@convex-dev/workos-authkit 0.1.6 → 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.
- package/README.md +23 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +24 -5
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +604 -6
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +18 -7
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/backfill.d.ts +60 -0
- package/dist/component/backfill.d.ts.map +1 -0
- package/dist/component/backfill.js +171 -0
- package/dist/component/backfill.js.map +1 -0
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/convex.config.js +2 -0
- package/dist/component/convex.config.js.map +1 -1
- package/dist/component/lib.d.ts +27 -10
- package/dist/component/lib.d.ts.map +1 -1
- package/dist/component/lib.js +93 -80
- package/dist/component/lib.js.map +1 -1
- package/dist/component/schema.d.ts +7 -2
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +3 -0
- package/dist/component/schema.js.map +1 -1
- package/package.json +36 -34
- package/src/client/index.ts +24 -5
- package/src/component/_generated/api.ts +535 -6
- package/src/component/_generated/component.ts +25 -12
- package/src/component/backfill.test.ts +335 -0
- package/src/component/backfill.ts +217 -0
- package/src/component/convex.config.ts +2 -0
- package/src/component/lib.ts +103 -81
- package/src/component/schema.ts +3 -0
- package/src/test.ts +4 -0
package/src/component/lib.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { v } from "convex/values";
|
|
1
|
+
import { type Infer, v } from "convex/values";
|
|
2
2
|
import {
|
|
3
3
|
internalAction,
|
|
4
4
|
internalMutation,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
mutation,
|
|
7
7
|
query,
|
|
8
8
|
} from "./_generated/server.js";
|
|
9
|
+
import type { MutationCtx } from "./_generated/server.js";
|
|
9
10
|
import { components, internal } from "./_generated/api.js";
|
|
10
11
|
import { omit, withoutSystemFields } from "convex-helpers";
|
|
11
12
|
import { WorkOS, type Event as WorkOSEvent } from "@workos-inc/node";
|
|
@@ -18,7 +19,7 @@ const eventWorkpool = new Workpool(components.eventWorkpool, {
|
|
|
18
19
|
maxParallelism: 1,
|
|
19
20
|
});
|
|
20
21
|
|
|
21
|
-
const vEvent = v.object({
|
|
22
|
+
export const vEvent = v.object({
|
|
22
23
|
id: v.string(),
|
|
23
24
|
createdAt: v.string(),
|
|
24
25
|
event: v.string(),
|
|
@@ -26,24 +27,109 @@ const vEvent = v.object({
|
|
|
26
27
|
context: v.optional(v.record(v.string(), v.any())),
|
|
27
28
|
});
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
async function processEventHandler(
|
|
31
|
+
ctx: MutationCtx,
|
|
32
|
+
args: {
|
|
33
|
+
event: Infer<typeof vEvent>;
|
|
34
|
+
logLevel?: "DEBUG";
|
|
35
|
+
onEventHandle?: string;
|
|
36
|
+
}
|
|
37
|
+
) {
|
|
38
|
+
if (args.logLevel === "DEBUG") {
|
|
39
|
+
console.log("processing event", args.event);
|
|
40
|
+
}
|
|
41
|
+
const dbEvent = await ctx.db
|
|
42
|
+
.query("events")
|
|
43
|
+
.withIndex("eventId", (q) => q.eq("eventId", args.event.id))
|
|
44
|
+
.unique();
|
|
45
|
+
if (dbEvent) {
|
|
46
|
+
console.log("event already processed", args.event.id);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
await ctx.db.insert("events", {
|
|
50
|
+
eventId: args.event.id,
|
|
51
|
+
event: args.event.event,
|
|
52
|
+
updatedAt: args.event.data.updatedAt as string | undefined,
|
|
53
|
+
});
|
|
54
|
+
const event = args.event as WorkOSEvent;
|
|
55
|
+
switch (event.event) {
|
|
56
|
+
case "user.created": {
|
|
57
|
+
const data = omit(event.data, ["object"]);
|
|
58
|
+
const existingUser = await ctx.db
|
|
59
|
+
.query("users")
|
|
60
|
+
.withIndex("id", (q) => q.eq("id", data.id))
|
|
61
|
+
.unique();
|
|
62
|
+
if (existingUser) {
|
|
63
|
+
console.warn("user already exists", data.id);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
await ctx.db.insert("users", data);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case "user.updated": {
|
|
70
|
+
const data = omit(event.data, ["object"]);
|
|
71
|
+
const user = await ctx.db
|
|
72
|
+
.query("users")
|
|
73
|
+
.withIndex("id", (q) => q.eq("id", data.id))
|
|
74
|
+
.unique();
|
|
75
|
+
if (!user) {
|
|
76
|
+
console.error("user not found", data.id);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (user.updatedAt >= data.updatedAt) {
|
|
80
|
+
console.warn(`user already updated for event ${event.id}, skipping`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
await ctx.db.patch(user._id, data);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "user.deleted": {
|
|
87
|
+
const data = omit(event.data, ["object"]);
|
|
88
|
+
const user = await ctx.db
|
|
89
|
+
.query("users")
|
|
90
|
+
.withIndex("id", (q) => q.eq("id", data.id))
|
|
91
|
+
.unique();
|
|
92
|
+
if (!user) {
|
|
93
|
+
console.warn("user not found", data.id);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
await ctx.db.delete(user._id);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (args.onEventHandle) {
|
|
101
|
+
await ctx.runMutation(args.onEventHandle as FunctionHandle<"mutation">, {
|
|
102
|
+
event: args.event.event,
|
|
103
|
+
data: args.event.data,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const onWebhookEvent = mutation({
|
|
30
109
|
args: {
|
|
31
110
|
apiKey: v.string(),
|
|
32
|
-
|
|
33
|
-
event: v.string(),
|
|
34
|
-
updatedAt: v.optional(v.string()),
|
|
111
|
+
event: vEvent,
|
|
35
112
|
onEventHandle: v.optional(v.string()),
|
|
36
113
|
eventTypes: v.optional(v.array(v.string())),
|
|
37
114
|
logLevel: v.optional(v.literal("DEBUG")),
|
|
38
115
|
},
|
|
116
|
+
returns: v.null(),
|
|
39
117
|
handler: async (ctx, args) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
118
|
+
const isCreateEvent = args.event.event.endsWith(".created");
|
|
119
|
+
|
|
120
|
+
if (isCreateEvent) {
|
|
121
|
+
// Process create events immediately
|
|
122
|
+
await processEventHandler(ctx, args);
|
|
123
|
+
} else {
|
|
124
|
+
// Enqueue update/delete events to workpool
|
|
125
|
+
await eventWorkpool.enqueueAction(ctx, internal.lib.updateEvents, {
|
|
126
|
+
apiKey: args.apiKey,
|
|
127
|
+
onEventHandle: args.onEventHandle,
|
|
128
|
+
eventTypes: args.eventTypes,
|
|
129
|
+
logLevel: args.logLevel,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
47
133
|
},
|
|
48
134
|
});
|
|
49
135
|
|
|
@@ -67,6 +153,9 @@ export const updateEvents = internalAction({
|
|
|
67
153
|
logLevel: v.optional(v.literal("DEBUG")),
|
|
68
154
|
},
|
|
69
155
|
handler: async (ctx, args) => {
|
|
156
|
+
// Cancel other pending workpool jobs since this run will
|
|
157
|
+
// process all available events from the WorkOS API.
|
|
158
|
+
await eventWorkpool.cancelAll(ctx);
|
|
70
159
|
const workos = new WorkOS(args.apiKey);
|
|
71
160
|
const cursor = await ctx.runQuery(internal.lib.getCursor);
|
|
72
161
|
let nextCursor = cursor ?? undefined;
|
|
@@ -107,74 +196,7 @@ export const processEvent = internalMutation({
|
|
|
107
196
|
onEventHandle: v.optional(v.string()),
|
|
108
197
|
},
|
|
109
198
|
handler: async (ctx, args) => {
|
|
110
|
-
|
|
111
|
-
console.log("processing event", args.event);
|
|
112
|
-
}
|
|
113
|
-
const dbEvent = await ctx.db
|
|
114
|
-
.query("events")
|
|
115
|
-
.withIndex("eventId", (q) => q.eq("eventId", args.event.id))
|
|
116
|
-
.unique();
|
|
117
|
-
if (dbEvent) {
|
|
118
|
-
console.log("event already processed", args.event.id);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
await ctx.db.insert("events", {
|
|
122
|
-
eventId: args.event.id,
|
|
123
|
-
event: args.event.event,
|
|
124
|
-
updatedAt: args.event.data.updatedAt,
|
|
125
|
-
});
|
|
126
|
-
const event = args.event as WorkOSEvent;
|
|
127
|
-
switch (event.event) {
|
|
128
|
-
case "user.created": {
|
|
129
|
-
const data = omit(event.data, ["object"]);
|
|
130
|
-
const existingUser = await ctx.db
|
|
131
|
-
.query("users")
|
|
132
|
-
.withIndex("id", (q) => q.eq("id", data.id))
|
|
133
|
-
.unique();
|
|
134
|
-
if (existingUser) {
|
|
135
|
-
console.warn("user already exists", data.id);
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
await ctx.db.insert("users", data);
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
case "user.updated": {
|
|
142
|
-
const data = omit(event.data, ["object"]);
|
|
143
|
-
const user = await ctx.db
|
|
144
|
-
.query("users")
|
|
145
|
-
.withIndex("id", (q) => q.eq("id", data.id))
|
|
146
|
-
.unique();
|
|
147
|
-
if (!user) {
|
|
148
|
-
console.error("user not found", data.id);
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
if (user.updatedAt >= data.updatedAt) {
|
|
152
|
-
console.warn(`user already updated for event ${event.id}, skipping`);
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
await ctx.db.patch(user._id, data);
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
case "user.deleted": {
|
|
159
|
-
const data = omit(event.data, ["object"]);
|
|
160
|
-
const user = await ctx.db
|
|
161
|
-
.query("users")
|
|
162
|
-
.withIndex("id", (q) => q.eq("id", data.id))
|
|
163
|
-
.unique();
|
|
164
|
-
if (!user) {
|
|
165
|
-
console.warn("user not found", data.id);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
await ctx.db.delete(user._id);
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (args.onEventHandle) {
|
|
173
|
-
await ctx.runMutation(args.onEventHandle as FunctionHandle<"mutation">, {
|
|
174
|
-
event: args.event.event,
|
|
175
|
-
data: args.event.data,
|
|
176
|
-
});
|
|
177
|
-
}
|
|
199
|
+
await processEventHandler(ctx, args);
|
|
178
200
|
},
|
|
179
201
|
});
|
|
180
202
|
|
package/src/component/schema.ts
CHANGED
package/src/test.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { TestConvex } from "convex-test";
|
|
2
2
|
import type { GenericSchema, SchemaDefinition } from "convex/server";
|
|
3
|
+
import workpool from "@convex-dev/workpool/test";
|
|
4
|
+
import workflow from "@convex-dev/workflow/test";
|
|
3
5
|
import schema from "./component/schema.js";
|
|
4
6
|
const modules = import.meta.glob("./component/**/*.ts");
|
|
5
7
|
|
|
@@ -13,5 +15,7 @@ function register(
|
|
|
13
15
|
name: string = "workOSAuthKit"
|
|
14
16
|
) {
|
|
15
17
|
t.registerComponent(name, schema, modules);
|
|
18
|
+
workpool.register(t, `${name}/eventWorkpool`);
|
|
19
|
+
workflow.register(t, `${name}/backfillWorkflow`);
|
|
16
20
|
}
|
|
17
21
|
export default { register, schema, modules };
|