@convex-dev/workos-authkit 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +23 -0
  2. package/dist/client/index.d.ts +3 -0
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +24 -5
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/component/_generated/api.d.ts +592 -0
  7. package/dist/component/_generated/api.d.ts.map +1 -1
  8. package/dist/component/_generated/api.js.map +1 -1
  9. package/dist/component/_generated/component.d.ts +18 -7
  10. package/dist/component/_generated/component.d.ts.map +1 -1
  11. package/dist/component/backfill.d.ts +60 -0
  12. package/dist/component/backfill.d.ts.map +1 -0
  13. package/dist/component/backfill.js +171 -0
  14. package/dist/component/backfill.js.map +1 -0
  15. package/dist/component/convex.config.d.ts.map +1 -1
  16. package/dist/component/convex.config.js +2 -0
  17. package/dist/component/convex.config.js.map +1 -1
  18. package/dist/component/lib.d.ts +27 -10
  19. package/dist/component/lib.d.ts.map +1 -1
  20. package/dist/component/lib.js +93 -80
  21. package/dist/component/lib.js.map +1 -1
  22. package/dist/component/schema.d.ts +7 -2
  23. package/dist/component/schema.d.ts.map +1 -1
  24. package/dist/component/schema.js +3 -0
  25. package/dist/component/schema.js.map +1 -1
  26. package/package.json +10 -9
  27. package/src/client/index.ts +24 -5
  28. package/src/component/_generated/api.ts +518 -0
  29. package/src/component/_generated/component.ts +25 -12
  30. package/src/component/backfill.test.ts +335 -0
  31. package/src/component/backfill.ts +217 -0
  32. package/src/component/convex.config.ts +2 -0
  33. package/src/component/lib.ts +103 -81
  34. package/src/component/schema.ts +3 -0
  35. package/src/test.ts +4 -0
@@ -19,16 +19,14 @@ import type { FunctionReference } from "convex/server";
19
19
  * ```
20
20
  */
21
21
  export type ComponentApi<Name extends string | undefined = string | undefined> = {
22
- lib: {
23
- enqueueWebhookEvent: FunctionReference<"mutation", "internal", {
22
+ backfill: {
23
+ startBackfill: FunctionReference<"mutation", "internal", {
24
24
  apiKey: string;
25
- event: string;
26
- eventId: string;
27
- eventTypes?: Array<string>;
28
25
  logLevel?: "DEBUG";
29
26
  onEventHandle?: string;
30
- updatedAt?: string;
31
- }, any, Name>;
27
+ }, null, Name>;
28
+ };
29
+ lib: {
32
30
  getAuthUser: FunctionReference<"query", "internal", {
33
31
  id: string;
34
32
  }, {
@@ -45,6 +43,19 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
45
43
  profilePictureUrl?: null | string;
46
44
  updatedAt: string;
47
45
  } | null, Name>;
46
+ onWebhookEvent: FunctionReference<"mutation", "internal", {
47
+ apiKey: string;
48
+ event: {
49
+ context?: Record<string, any>;
50
+ createdAt: string;
51
+ data: Record<string, any>;
52
+ event: string;
53
+ id: string;
54
+ };
55
+ eventTypes?: Array<string>;
56
+ logLevel?: "DEBUG";
57
+ onEventHandle?: string;
58
+ }, null, Name>;
48
59
  };
49
60
  };
50
61
  //# sourceMappingURL=component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../src/component/_generated/component.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,IAC3E;IACE,GAAG,EAAE;QACH,mBAAmB,EAAE,iBAAiB,CACpC,UAAU,EACV,UAAU,EACV;YACE,MAAM,EAAE,MAAM,CAAC;YACf,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,EAAE,MAAM,CAAC;YAChB,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,EACD,GAAG,EACH,IAAI,CACL,CAAC;QACF,WAAW,EAAE,iBAAiB,CAC5B,OAAO,EACP,UAAU,EACV;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,EACd;YACE,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,aAAa,EAAE,OAAO,CAAC;YACvB,UAAU,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAC3B,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAC1B,EAAE,EAAE,MAAM,CAAC;YACX,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YACzB,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAC7B,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC9B,iBAAiB,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAClC,SAAS,EAAE,MAAM,CAAC;SACnB,GAAG,IAAI,EACR,IAAI,CACL,CAAC;KACH,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../src/component/_generated/component.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,IAC3E;IACE,QAAQ,EAAE;QACR,aAAa,EAAE,iBAAiB,CAC9B,UAAU,EACV,UAAU,EACV;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,EAC9D,IAAI,EACJ,IAAI,CACL,CAAC;KACH,CAAC;IACF,GAAG,EAAE;QACH,WAAW,EAAE,iBAAiB,CAC5B,OAAO,EACP,UAAU,EACV;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,EACd;YACE,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,aAAa,EAAE,OAAO,CAAC;YACvB,UAAU,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAC3B,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAC1B,EAAE,EAAE,MAAM,CAAC;YACX,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YACzB,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAC7B,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC9B,iBAAiB,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;YAClC,SAAS,EAAE,MAAM,CAAC;SACnB,GAAG,IAAI,EACR,IAAI,CACL,CAAC;QACF,cAAc,EAAE,iBAAiB,CAC/B,UAAU,EACV,UAAU,EACV;YACE,MAAM,EAAE,MAAM,CAAC;YACf,KAAK,EAAE;gBACL,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBAC9B,SAAS,EAAE,MAAM,CAAC;gBAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBAC1B,KAAK,EAAE,MAAM,CAAC;gBACd,EAAE,EAAE,MAAM,CAAC;aACZ,CAAC;YACF,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,aAAa,CAAC,EAAE,MAAM,CAAC;SACxB,EACD,IAAI,EACJ,IAAI,CACL,CAAC;KACH,CAAC;CACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ export declare const getBackfillApiKey: import("convex/server").RegisteredQuery<"internal", {}, Promise<string | null>>;
2
+ /** Fetches one page of users from WorkOS and upserts them, returning only the cursor. */
3
+ export declare const processUsersPage: import("convex/server").RegisteredAction<"internal", {
4
+ logLevel?: "DEBUG" | undefined;
5
+ onEventHandle?: string | undefined;
6
+ after?: string | undefined;
7
+ }, Promise<{
8
+ nextCursor: string | undefined;
9
+ }>>;
10
+ export declare const upsertUsersPage: import("convex/server").RegisteredMutation<"internal", {
11
+ logLevel?: "DEBUG" | undefined;
12
+ onEventHandle?: string | undefined;
13
+ users: {
14
+ firstName?: string | null | undefined;
15
+ lastName?: string | null | undefined;
16
+ profilePictureUrl?: string | null | undefined;
17
+ lastSignInAt?: string | null | undefined;
18
+ externalId?: string | null | undefined;
19
+ locale?: string | null | undefined;
20
+ id: string;
21
+ updatedAt: string;
22
+ email: string;
23
+ emailVerified: boolean;
24
+ metadata: Record<string, any>;
25
+ createdAt: string;
26
+ }[];
27
+ }, Promise<null>>;
28
+ export declare const backfillBatch: import("convex/server").RegisteredMutation<"internal", {
29
+ fn: "You should not call this directly, call workflow.start instead";
30
+ args: {
31
+ logLevel?: "DEBUG" | undefined;
32
+ onEventHandle?: string | undefined;
33
+ after?: string | undefined;
34
+ };
35
+ }, {
36
+ cursor?: string | undefined;
37
+ done: boolean;
38
+ }>;
39
+ export declare const backfillOnComplete: import("convex/server").RegisteredMutation<"internal", {
40
+ result: {
41
+ kind: "success";
42
+ returnValue: any;
43
+ } | {
44
+ kind: "failed";
45
+ error: string;
46
+ } | {
47
+ kind: "canceled";
48
+ };
49
+ workflowId: string;
50
+ context: {
51
+ logLevel?: "DEBUG" | undefined;
52
+ onEventHandle?: string | undefined;
53
+ };
54
+ }, Promise<null>>;
55
+ export declare const startBackfill: import("convex/server").RegisteredMutation<"public", {
56
+ logLevel?: "DEBUG" | undefined;
57
+ onEventHandle?: string | undefined;
58
+ apiKey: string;
59
+ }, Promise<null>>;
60
+ //# sourceMappingURL=backfill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../src/component/backfill.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,iBAAiB,iFAO5B,CAAC;AAEH,yFAAyF;AACzF,eAAO,MAAM,gBAAgB;;;;;gBAYF,MAAM,GAAG,SAAS;GA0B3C,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;iBAqC1B,CAAC;AAIH,eAAO,MAAM,aAAa;;;;;;;;;;EAiCxB,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;iBA4C7B,CAAC;AAEH,eAAO,MAAM,aAAa;;;;iBAwBxB,CAAC"}
@@ -0,0 +1,171 @@
1
+ import { v } from "convex/values";
2
+ import { internalAction, internalMutation, internalQuery, mutation, } from "./_generated/server.js";
3
+ import { components, internal } from "./_generated/api.js";
4
+ import { WorkOS } from "@workos-inc/node";
5
+ import { WorkflowManager } from "@convex-dev/workflow";
6
+ import { vResultValidator } from "@convex-dev/workpool";
7
+ import schema from "./schema.js";
8
+ const workflow = new WorkflowManager(components.backfillWorkflow, {
9
+ workpoolOptions: { maxParallelism: 1 },
10
+ });
11
+ const vUser = schema.tables.users.validator;
12
+ export const getBackfillApiKey = internalQuery({
13
+ args: {},
14
+ returns: v.union(v.string(), v.null()),
15
+ handler: async (ctx) => {
16
+ const backfillState = await ctx.db.query("backfillState").unique();
17
+ return backfillState?.apiKey ?? null;
18
+ },
19
+ });
20
+ /** Fetches one page of users from WorkOS and upserts them, returning only the cursor. */
21
+ export const processUsersPage = internalAction({
22
+ args: {
23
+ after: v.optional(v.string()),
24
+ onEventHandle: v.optional(v.string()),
25
+ logLevel: v.optional(v.literal("DEBUG")),
26
+ },
27
+ returns: v.object({
28
+ nextCursor: v.optional(v.string()),
29
+ }),
30
+ handler: async (ctx, args) => {
31
+ const apiKey = await ctx.runQuery(internal.backfill.getBackfillApiKey, {});
32
+ if (!apiKey) {
33
+ throw new Error("Backfill API key not found");
34
+ }
35
+ const workos = new WorkOS(apiKey);
36
+ const { data, listMetadata } = await workos.userManagement.listUsers({
37
+ limit: 100,
38
+ after: args.after,
39
+ order: "asc",
40
+ });
41
+ const users = data.map(({ object: _object, ...rest }) => rest);
42
+ if (users.length > 0) {
43
+ await ctx.runMutation(internal.backfill.upsertUsersPage, {
44
+ users,
45
+ onEventHandle: args.onEventHandle,
46
+ logLevel: args.logLevel,
47
+ });
48
+ }
49
+ return {
50
+ nextCursor: listMetadata.after ?? undefined,
51
+ };
52
+ },
53
+ });
54
+ export const upsertUsersPage = internalMutation({
55
+ args: {
56
+ users: v.array(vUser),
57
+ onEventHandle: v.optional(v.string()),
58
+ logLevel: v.optional(v.literal("DEBUG")),
59
+ },
60
+ returns: v.null(),
61
+ handler: async (ctx, args) => {
62
+ const existingUsers = await Promise.all(args.users.map((user) => ctx.db
63
+ .query("users")
64
+ .withIndex("id", (q) => q.eq("id", user.id))
65
+ .unique()));
66
+ const newUsers = args.users.filter((_, i) => !existingUsers[i]);
67
+ if (args.logLevel === "DEBUG") {
68
+ console.log(`backfill: ${newUsers.length} new users out of ${args.users.length}`);
69
+ }
70
+ for (const user of newUsers) {
71
+ await ctx.db.insert("users", user);
72
+ if (args.onEventHandle) {
73
+ await ctx.runMutation(args.onEventHandle, { event: "user.created", data: { ...user, object: "user" } });
74
+ }
75
+ }
76
+ return null;
77
+ },
78
+ });
79
+ const MAX_PAGES_PER_BATCH = 50;
80
+ export const backfillBatch = workflow.define({
81
+ args: {
82
+ onEventHandle: v.optional(v.string()),
83
+ logLevel: v.optional(v.literal("DEBUG")),
84
+ after: v.optional(v.string()),
85
+ },
86
+ returns: v.object({
87
+ done: v.boolean(),
88
+ cursor: v.optional(v.string()),
89
+ }),
90
+ handler: async (step, args) => {
91
+ let cursor = args.after;
92
+ let pagesProcessed = 0;
93
+ while (pagesProcessed < MAX_PAGES_PER_BATCH) {
94
+ const result = await step.runAction(internal.backfill.processUsersPage, {
95
+ after: cursor,
96
+ onEventHandle: args.onEventHandle,
97
+ logLevel: args.logLevel,
98
+ });
99
+ cursor = result.nextCursor;
100
+ pagesProcessed++;
101
+ if (!cursor) {
102
+ return { done: true };
103
+ }
104
+ }
105
+ return { done: false, cursor };
106
+ },
107
+ });
108
+ export const backfillOnComplete = internalMutation({
109
+ args: {
110
+ workflowId: v.string(),
111
+ result: vResultValidator,
112
+ context: v.object({
113
+ onEventHandle: v.optional(v.string()),
114
+ logLevel: v.optional(v.literal("DEBUG")),
115
+ }),
116
+ },
117
+ returns: v.null(),
118
+ handler: async (ctx, args) => {
119
+ if (args.result.kind !== "success") {
120
+ console.error(`Backfill workflow ${args.result.kind}`, args.result);
121
+ const backfillState = await ctx.db.query("backfillState").unique();
122
+ if (backfillState) {
123
+ await ctx.db.delete(backfillState._id);
124
+ }
125
+ return null;
126
+ }
127
+ const returnValue = args.result.returnValue;
128
+ if (returnValue.done || !returnValue.cursor) {
129
+ const backfillState = await ctx.db.query("backfillState").unique();
130
+ if (backfillState) {
131
+ await ctx.db.delete(backfillState._id);
132
+ }
133
+ }
134
+ else {
135
+ await workflow.start(ctx, internal.backfill.backfillBatch, {
136
+ ...args.context,
137
+ after: returnValue.cursor,
138
+ }, {
139
+ onComplete: internal.backfill.backfillOnComplete,
140
+ context: args.context,
141
+ });
142
+ }
143
+ return null;
144
+ },
145
+ });
146
+ export const startBackfill = mutation({
147
+ args: {
148
+ apiKey: v.string(),
149
+ onEventHandle: v.optional(v.string()),
150
+ logLevel: v.optional(v.literal("DEBUG")),
151
+ },
152
+ returns: v.null(),
153
+ handler: async (ctx, args) => {
154
+ const existing = await ctx.db.query("backfillState").unique();
155
+ if (existing) {
156
+ console.warn("Backfill already in progress, skipping");
157
+ return null;
158
+ }
159
+ await ctx.db.insert("backfillState", { apiKey: args.apiKey });
160
+ const context = {
161
+ onEventHandle: args.onEventHandle,
162
+ logLevel: args.logLevel,
163
+ };
164
+ await workflow.start(ctx, internal.backfill.backfillBatch, context, {
165
+ onComplete: internal.backfill.backfillOnComplete,
166
+ context,
167
+ });
168
+ return null;
169
+ },
170
+ });
171
+ //# sourceMappingURL=backfill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill.js","sourceRoot":"","sources":["../../src/component/backfill.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,SAAS,kDAAmC,CAAC;AAInD,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,SAAS,kDAAmC,CAAC;AAKnD,eAAe,SAAS,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import { defineComponent } from "convex/server";
2
2
  import workpool from "@convex-dev/workpool/convex.config";
3
+ import workflow from "@convex-dev/workflow/convex.config";
3
4
  const component = defineComponent("workOSAuthKit");
4
5
  component.use(workpool, { name: "eventWorkpool" });
6
+ component.use(workflow, { name: "backfillWorkflow" });
5
7
  export default component;
6
8
  //# sourceMappingURL=convex.config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"convex.config.js","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,QAAQ,MAAM,oCAAoC,CAAC;AAE1D,MAAM,SAAS,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;AAEnD,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;AAEnD,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"convex.config.js","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,QAAQ,MAAM,oCAAoC,CAAC;AAC1D,OAAO,QAAQ,MAAM,oCAAoC,CAAC;AAE1D,MAAM,SAAS,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;AAEnD,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;AACnD,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAEtD,eAAe,SAAS,CAAC"}
@@ -1,17 +1,34 @@
1
- export declare const enqueueWebhookEvent: import("convex/server").RegisteredMutation<"public", {
2
- eventTypes?: string[] | undefined;
1
+ export declare const vEvent: import("convex/values").VObject<{
2
+ context?: Record<string, any> | undefined;
3
+ id: string;
4
+ event: string;
5
+ createdAt: string;
6
+ data: Record<string, any>;
7
+ }, {
8
+ id: import("convex/values").VString<string, "required">;
9
+ createdAt: import("convex/values").VString<string, "required">;
10
+ event: import("convex/values").VString<string, "required">;
11
+ data: import("convex/values").VRecord<Record<string, any>, import("convex/values").VString<string, "required">, import("convex/values").VAny<any, "required", string>, "required", string>;
12
+ context: import("convex/values").VRecord<Record<string, any> | undefined, import("convex/values").VString<string, "required">, import("convex/values").VAny<any, "required", string>, "optional", string>;
13
+ }, "required", "id" | "event" | "createdAt" | "context" | "data" | `context.${string}` | `data.${string}`>;
14
+ export declare const onWebhookEvent: import("convex/server").RegisteredMutation<"public", {
3
15
  logLevel?: "DEBUG" | undefined;
4
16
  onEventHandle?: string | undefined;
5
- updatedAt?: string | undefined;
17
+ eventTypes?: string[] | undefined;
6
18
  apiKey: string;
7
- event: string;
8
- eventId: string;
9
- }, Promise<void>>;
19
+ event: {
20
+ context?: Record<string, any> | undefined;
21
+ id: string;
22
+ event: string;
23
+ createdAt: string;
24
+ data: Record<string, any>;
25
+ };
26
+ }, Promise<null>>;
10
27
  export declare const getCursor: import("convex/server").RegisteredQuery<"internal", {}, Promise<string | undefined>>;
11
28
  export declare const updateEvents: import("convex/server").RegisteredAction<"internal", {
12
- eventTypes?: string[] | undefined;
13
29
  logLevel?: "DEBUG" | undefined;
14
30
  onEventHandle?: string | undefined;
31
+ eventTypes?: string[] | undefined;
15
32
  apiKey: string;
16
33
  }, Promise<void>>;
17
34
  export declare const processEvent: import("convex/server").RegisteredMutation<"internal", {
@@ -19,10 +36,10 @@ export declare const processEvent: import("convex/server").RegisteredMutation<"i
19
36
  onEventHandle?: string | undefined;
20
37
  event: {
21
38
  context?: Record<string, any> | undefined;
22
- event: string;
23
39
  id: string;
24
- data: Record<string, any>;
40
+ event: string;
25
41
  createdAt: string;
42
+ data: Record<string, any>;
26
43
  };
27
44
  }, Promise<void>>;
28
45
  export declare const getAuthUser: import("convex/server").RegisteredQuery<"public", {
@@ -34,8 +51,8 @@ export declare const getAuthUser: import("convex/server").RegisteredQuery<"publi
34
51
  lastSignInAt?: string | null | undefined;
35
52
  externalId?: string | null | undefined;
36
53
  locale?: string | null | undefined;
37
- updatedAt: string;
38
54
  id: string;
55
+ updatedAt: string;
39
56
  email: string;
40
57
  emailVerified: boolean;
41
58
  metadata: Record<string, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../src/component/lib.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,mBAAmB;;;;;;;;iBAmB9B,CAAC;AAEH,eAAO,MAAM,SAAS,sFAUpB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;iBAuCvB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;iBA4EvB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;UAYtB,CAAC"}
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../src/component/lib.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,MAAM;;;;;;;;;;;;0GAMjB,CAAC;AAgFH,eAAO,MAAM,cAAc;;;;;;;;;;;;iBA0BzB,CAAC;AAEH,eAAO,MAAM,SAAS,sFAUpB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;iBA0CvB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;iBASvB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;UAYtB,CAAC"}
@@ -9,31 +9,108 @@ import { parse } from "convex-helpers/validators";
9
9
  const eventWorkpool = new Workpool(components.eventWorkpool, {
10
10
  maxParallelism: 1,
11
11
  });
12
- const vEvent = v.object({
12
+ export const vEvent = v.object({
13
13
  id: v.string(),
14
14
  createdAt: v.string(),
15
15
  event: v.string(),
16
16
  data: v.record(v.string(), v.any()),
17
17
  context: v.optional(v.record(v.string(), v.any())),
18
18
  });
19
- export const enqueueWebhookEvent = mutation({
19
+ async function processEventHandler(ctx, args) {
20
+ if (args.logLevel === "DEBUG") {
21
+ console.log("processing event", args.event);
22
+ }
23
+ const dbEvent = await ctx.db
24
+ .query("events")
25
+ .withIndex("eventId", (q) => q.eq("eventId", args.event.id))
26
+ .unique();
27
+ if (dbEvent) {
28
+ console.log("event already processed", args.event.id);
29
+ return;
30
+ }
31
+ await ctx.db.insert("events", {
32
+ eventId: args.event.id,
33
+ event: args.event.event,
34
+ updatedAt: args.event.data.updatedAt,
35
+ });
36
+ const event = args.event;
37
+ switch (event.event) {
38
+ case "user.created": {
39
+ const data = omit(event.data, ["object"]);
40
+ const existingUser = await ctx.db
41
+ .query("users")
42
+ .withIndex("id", (q) => q.eq("id", data.id))
43
+ .unique();
44
+ if (existingUser) {
45
+ console.warn("user already exists", data.id);
46
+ return;
47
+ }
48
+ await ctx.db.insert("users", data);
49
+ break;
50
+ }
51
+ case "user.updated": {
52
+ const data = omit(event.data, ["object"]);
53
+ const user = await ctx.db
54
+ .query("users")
55
+ .withIndex("id", (q) => q.eq("id", data.id))
56
+ .unique();
57
+ if (!user) {
58
+ console.error("user not found", data.id);
59
+ return;
60
+ }
61
+ if (user.updatedAt >= data.updatedAt) {
62
+ console.warn(`user already updated for event ${event.id}, skipping`);
63
+ return;
64
+ }
65
+ await ctx.db.patch(user._id, data);
66
+ break;
67
+ }
68
+ case "user.deleted": {
69
+ const data = omit(event.data, ["object"]);
70
+ const user = await ctx.db
71
+ .query("users")
72
+ .withIndex("id", (q) => q.eq("id", data.id))
73
+ .unique();
74
+ if (!user) {
75
+ console.warn("user not found", data.id);
76
+ return;
77
+ }
78
+ await ctx.db.delete(user._id);
79
+ break;
80
+ }
81
+ }
82
+ if (args.onEventHandle) {
83
+ await ctx.runMutation(args.onEventHandle, {
84
+ event: args.event.event,
85
+ data: args.event.data,
86
+ });
87
+ }
88
+ }
89
+ export const onWebhookEvent = mutation({
20
90
  args: {
21
91
  apiKey: v.string(),
22
- eventId: v.string(),
23
- event: v.string(),
24
- updatedAt: v.optional(v.string()),
92
+ event: vEvent,
25
93
  onEventHandle: v.optional(v.string()),
26
94
  eventTypes: v.optional(v.array(v.string())),
27
95
  logLevel: v.optional(v.literal("DEBUG")),
28
96
  },
97
+ returns: v.null(),
29
98
  handler: async (ctx, args) => {
30
- await eventWorkpool.cancelAll(ctx);
31
- await eventWorkpool.enqueueAction(ctx, internal.lib.updateEvents, {
32
- apiKey: args.apiKey,
33
- onEventHandle: args.onEventHandle,
34
- eventTypes: args.eventTypes,
35
- logLevel: args.logLevel,
36
- });
99
+ const isCreateEvent = args.event.event.endsWith(".created");
100
+ if (isCreateEvent) {
101
+ // Process create events immediately
102
+ await processEventHandler(ctx, args);
103
+ }
104
+ else {
105
+ // Enqueue update/delete events to workpool
106
+ await eventWorkpool.enqueueAction(ctx, internal.lib.updateEvents, {
107
+ apiKey: args.apiKey,
108
+ onEventHandle: args.onEventHandle,
109
+ eventTypes: args.eventTypes,
110
+ logLevel: args.logLevel,
111
+ });
112
+ }
113
+ return null;
37
114
  },
38
115
  });
39
116
  export const getCursor = internalQuery({
@@ -55,6 +132,9 @@ export const updateEvents = internalAction({
55
132
  logLevel: v.optional(v.literal("DEBUG")),
56
133
  },
57
134
  handler: async (ctx, args) => {
135
+ // Cancel other pending workpool jobs since this run will
136
+ // process all available events from the WorkOS API.
137
+ await eventWorkpool.cancelAll(ctx);
58
138
  const workos = new WorkOS(args.apiKey);
59
139
  const cursor = await ctx.runQuery(internal.lib.getCursor);
60
140
  let nextCursor = cursor ?? undefined;
@@ -94,74 +174,7 @@ export const processEvent = internalMutation({
94
174
  onEventHandle: v.optional(v.string()),
95
175
  },
96
176
  handler: async (ctx, args) => {
97
- if (args.logLevel === "DEBUG") {
98
- console.log("processing event", args.event);
99
- }
100
- const dbEvent = await ctx.db
101
- .query("events")
102
- .withIndex("eventId", (q) => q.eq("eventId", args.event.id))
103
- .unique();
104
- if (dbEvent) {
105
- console.log("event already processed", args.event.id);
106
- return;
107
- }
108
- await ctx.db.insert("events", {
109
- eventId: args.event.id,
110
- event: args.event.event,
111
- updatedAt: args.event.data.updatedAt,
112
- });
113
- const event = args.event;
114
- switch (event.event) {
115
- case "user.created": {
116
- const data = omit(event.data, ["object"]);
117
- const existingUser = await ctx.db
118
- .query("users")
119
- .withIndex("id", (q) => q.eq("id", data.id))
120
- .unique();
121
- if (existingUser) {
122
- console.warn("user already exists", data.id);
123
- break;
124
- }
125
- await ctx.db.insert("users", data);
126
- break;
127
- }
128
- case "user.updated": {
129
- const data = omit(event.data, ["object"]);
130
- const user = await ctx.db
131
- .query("users")
132
- .withIndex("id", (q) => q.eq("id", data.id))
133
- .unique();
134
- if (!user) {
135
- console.error("user not found", data.id);
136
- break;
137
- }
138
- if (user.updatedAt >= data.updatedAt) {
139
- console.warn(`user already updated for event ${event.id}, skipping`);
140
- break;
141
- }
142
- await ctx.db.patch(user._id, data);
143
- break;
144
- }
145
- case "user.deleted": {
146
- const data = omit(event.data, ["object"]);
147
- const user = await ctx.db
148
- .query("users")
149
- .withIndex("id", (q) => q.eq("id", data.id))
150
- .unique();
151
- if (!user) {
152
- console.warn("user not found", data.id);
153
- break;
154
- }
155
- await ctx.db.delete(user._id);
156
- break;
157
- }
158
- }
159
- if (args.onEventHandle) {
160
- await ctx.runMutation(args.onEventHandle, {
161
- event: args.event.event,
162
- data: args.event.data,
163
- });
164
- }
177
+ await processEventHandler(ctx, args);
165
178
  },
166
179
  });
167
180
  export const getAuthUser = query({