Skip to content

Commit bd001bb

Browse files
auth cleanup
1 parent be96b09 commit bd001bb

3 files changed

Lines changed: 17 additions & 11 deletions

File tree

demos/react-convex-todolist/convex/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default defineSchema({
77
lists: defineTable({
88
created_at: v.string(),
99
name: v.string(),
10-
owner_id: v.string(),
10+
owner_id: v.id('users'),
1111
notes: v.optional(v.string()),
1212
priority: v.optional(v.number()),
1313
tags: v.optional(v.array(v.string())),

demos/react-convex-todolist/convex/todos.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ const findTodoByUuid = async (params: { db: DatabaseReader; uuid: string }) => {
1919
.first();
2020
};
2121

22+
/**
23+
* Public todo mutations use `list_uuid` from the local-first client and resolve
24+
* the Convex `list_id` server-side after checking list ownership. This keeps
25+
* callers from directly assigning a todo to an arbitrary Convex list document.
26+
*/
27+
const publicTodoValidator = schema.tables.todos.validator.omit('list_id');
28+
2229
/**
2330
* Create a todo record given its record data.
2431
* The `list_id` is resolved here on the backend.
2532
*/
2633
export const create = mutation({
2734
// This does not include an `id` field. The local uuid is presented in the `uuid` field
28-
args: schema.tables.todos.validator.omit('list_id'),
35+
args: publicTodoValidator,
2936
handler: async (ctx, args) => {
3037
const { db } = ctx;
3138
const ownerId = await requireOwnerId(ctx);
@@ -48,7 +55,7 @@ export const create = mutation({
4855
*/
4956
export const update = mutation({
5057
// The uuid is required, every other field is an optional patch
51-
args: v.object({ uuid: v.string() }).extend(schema.tables.todos.validator.partial().fields),
58+
args: v.object({ uuid: v.string() }).extend(publicTodoValidator.partial().fields),
5259
handler: async (ctx, { uuid, ...fields }) => {
5360
const { db } = ctx;
5461
const ownerId = await requireOwnerId(ctx);
@@ -62,16 +69,17 @@ export const update = mutation({
6269
}
6370
assertListOwner(currentList, ownerId);
6471

72+
const patch: Partial<typeof matching> = fields;
6573
if (fields.list_uuid !== undefined) {
6674
const nextList = await findListByUuid({ db, uuid: fields.list_uuid });
6775
if (!nextList) {
6876
throw mutationError(MUTATION_ERROR_CODES.NOT_FOUND, `No matching list found for uuid=${fields.list_uuid}`);
6977
}
7078
assertListOwner(nextList, ownerId);
71-
fields.list_id = nextList._id;
79+
patch.list_id = nextList._id;
7280
}
7381

74-
await db.patch(matching._id, fields);
82+
await db.patch(matching._id, patch);
7583
}
7684
});
7785

demos/react-convex-todolist/src/components/providers/SystemProvider.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useAuthToken } from '@convex-dev/auth/react';
55
import { CircularProgress } from '@mui/material';
66
import { PowerSyncContext } from '@powersync/react';
77
import { PowerSyncDatabase } from '@powersync/web';
8-
import { useConvex } from 'convex/react';
8+
import { useConvex, useConvexAuth } from 'convex/react';
99
import Logger from 'js-logger';
1010
import React, { Suspense } from 'react';
1111

@@ -31,26 +31,24 @@ export const useConnector = () => React.useContext(ConnectorContext);
3131

3232
const AuthAwareSystemProvider = ({ children }: { children: React.ReactNode }) => {
3333
const authToken = useAuthToken();
34+
const { isAuthenticated } = useConvexAuth();
3435
const convexClient = useConvex();
3536
const [connector] = React.useState(() => new DemoConnector({ convexClient }));
3637

3738
// Update connector with current auth token
3839
React.useEffect(() => {
39-
if (authToken) {
40-
console.log('[Convex] JWT token:', authToken);
41-
}
4240
connector.setAuthToken(authToken);
4341
}, [authToken, connector]);
4442

4543
React.useEffect(() => {
46-
if (authToken) {
44+
if (authToken && isAuthenticated) {
4745
// Connect PowerSync when authenticated
4846
powerSync.connect(connector);
4947
} else {
5048
// Disconnect PowerSync when not authenticated
5149
powerSync.disconnect();
5250
}
53-
}, [authToken, connector]);
51+
}, [authToken, connector, isAuthenticated]);
5452

5553
return (
5654
<Suspense fallback={<CircularProgress />}>

0 commit comments

Comments
 (0)