@devlider001/washlab-backend 1.0.4 → 1.0.5

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 (73) hide show
  1. package/convex/_generated/api.d.ts +2 -0
  2. package/convex/audit.d.ts +39 -0
  3. package/convex/notifications.d.ts +170 -0
  4. package/convex/schema.d.ts +51 -0
  5. package/dist/convex/admin.d.ts +377 -0
  6. package/dist/convex/admin.d.ts.map +1 -0
  7. package/dist/convex/admin.js +959 -0
  8. package/dist/convex/admin.js.map +1 -0
  9. package/dist/convex/analytics.d.ts +87 -0
  10. package/dist/convex/analytics.d.ts.map +1 -0
  11. package/dist/convex/analytics.js +361 -0
  12. package/dist/convex/analytics.js.map +1 -0
  13. package/dist/convex/attendants.d.ts +140 -0
  14. package/dist/convex/attendants.d.ts.map +1 -0
  15. package/dist/convex/attendants.js +337 -0
  16. package/dist/convex/attendants.js.map +1 -0
  17. package/dist/convex/audit.d.ts +158 -0
  18. package/dist/convex/audit.d.ts.map +1 -0
  19. package/dist/convex/audit.js +184 -0
  20. package/dist/convex/audit.js.map +1 -0
  21. package/dist/convex/clerk.d.ts +53 -0
  22. package/dist/convex/clerk.d.ts.map +1 -0
  23. package/dist/convex/clerk.js +316 -0
  24. package/dist/convex/clerk.js.map +1 -0
  25. package/dist/convex/customers.d.ts +224 -0
  26. package/dist/convex/customers.d.ts.map +1 -0
  27. package/dist/convex/customers.js +504 -0
  28. package/dist/convex/customers.js.map +1 -0
  29. package/dist/convex/http.d.ts +3 -0
  30. package/dist/convex/http.d.ts.map +1 -0
  31. package/dist/convex/http.js +115 -0
  32. package/dist/convex/http.js.map +1 -0
  33. package/dist/convex/lib/audit.d.ts +36 -0
  34. package/dist/convex/lib/audit.d.ts.map +1 -0
  35. package/dist/convex/lib/audit.js +59 -0
  36. package/dist/convex/lib/audit.js.map +1 -0
  37. package/dist/convex/lib/auth.d.ts +96 -0
  38. package/dist/convex/lib/auth.d.ts.map +1 -0
  39. package/dist/convex/lib/auth.js +94 -0
  40. package/dist/convex/lib/auth.js.map +1 -0
  41. package/dist/convex/lib/utils.d.ts +38 -0
  42. package/dist/convex/lib/utils.d.ts.map +1 -0
  43. package/dist/convex/lib/utils.js +71 -0
  44. package/dist/convex/lib/utils.js.map +1 -0
  45. package/dist/convex/loyalty.d.ts +82 -0
  46. package/dist/convex/loyalty.d.ts.map +1 -0
  47. package/dist/convex/loyalty.js +286 -0
  48. package/dist/convex/loyalty.js.map +1 -0
  49. package/dist/convex/orders.d.ts +326 -0
  50. package/dist/convex/orders.d.ts.map +1 -0
  51. package/dist/convex/orders.js +570 -0
  52. package/dist/convex/orders.js.map +1 -0
  53. package/dist/convex/payments.d.ts +134 -0
  54. package/dist/convex/payments.d.ts.map +1 -0
  55. package/dist/convex/payments.js +360 -0
  56. package/dist/convex/payments.js.map +1 -0
  57. package/dist/convex/resources.d.ts +119 -0
  58. package/dist/convex/resources.d.ts.map +1 -0
  59. package/dist/convex/resources.js +283 -0
  60. package/dist/convex/resources.js.map +1 -0
  61. package/dist/convex/schema.d.ts +450 -0
  62. package/dist/convex/schema.d.ts.map +1 -0
  63. package/dist/convex/schema.js +347 -0
  64. package/dist/convex/schema.js.map +1 -0
  65. package/dist/convex/vouchers.d.ts +187 -0
  66. package/dist/convex/vouchers.d.ts.map +1 -0
  67. package/dist/convex/vouchers.js +464 -0
  68. package/dist/convex/vouchers.js.map +1 -0
  69. package/dist/src/index.d.ts +9 -0
  70. package/dist/src/index.d.ts.map +1 -0
  71. package/dist/src/index.js +9 -0
  72. package/dist/src/index.js.map +1 -0
  73. package/package.json +3 -3
@@ -0,0 +1,504 @@
1
+ import { query, mutation } from "./_generated/server";
2
+ import { v } from "convex/values";
3
+ import { getClerkIdentity, getCurrentCustomer } from "./lib/auth";
4
+ import { createAuditLog } from "./lib/audit";
5
+ import { getCurrentTimestamp } from "./lib/utils";
6
+ /**
7
+ * Customer Functions
8
+ *
9
+ * Handles customer profile management, registration, and lookups.
10
+ * Customers can be guests (walk-in, no account) or registered (with Clerk account).
11
+ */
12
+ /**
13
+ * Get customer by phone number
14
+ * Used by POS for walk-in customer lookup
15
+ */
16
+ export const getByPhone = query({
17
+ args: {
18
+ phoneNumber: v.string(),
19
+ },
20
+ handler: async (ctx, args) => {
21
+ const user = await ctx.db
22
+ .query("users")
23
+ .withIndex("by_phone", (q) => q.eq("phoneNumber", args.phoneNumber))
24
+ .first();
25
+ if (!user || user.isDeleted) {
26
+ return null;
27
+ }
28
+ return user;
29
+ },
30
+ });
31
+ /**
32
+ * Get current customer profile (from authenticated Clerk session)
33
+ */
34
+ export const getProfile = query({
35
+ args: {},
36
+ handler: async (ctx) => {
37
+ const user = await getCurrentCustomer(ctx);
38
+ // Get order count for summary
39
+ const orders = await ctx.db
40
+ .query("orders")
41
+ .withIndex("by_customer", (q) => q.eq("customerId", user._id))
42
+ .collect();
43
+ const completedOrders = orders.filter((o) => !o.isDeleted && o.status === "completed").length;
44
+ return {
45
+ ...user,
46
+ orderCount: orders.length,
47
+ completedOrderCount: completedOrders,
48
+ };
49
+ },
50
+ });
51
+ /**
52
+ * Get customer order history - Paginated
53
+ * Supports usePaginatedQuery for infinite scroll
54
+ */
55
+ export const getOrders = query({
56
+ args: {
57
+ cursor: v.optional(v.string()),
58
+ numItems: v.optional(v.number()),
59
+ },
60
+ handler: async (ctx, args) => {
61
+ const user = await getCurrentCustomer(ctx);
62
+ const numItems = args.numItems ?? 20;
63
+ const result = await ctx.db
64
+ .query("orders")
65
+ .withIndex("by_customer", (q) => q.eq("customerId", user._id))
66
+ .order("desc")
67
+ .filter((q) => q.eq(q.field("isDeleted"), false))
68
+ .paginate({
69
+ cursor: args.cursor ?? null,
70
+ numItems,
71
+ });
72
+ return {
73
+ page: result.page,
74
+ isDone: result.isDone,
75
+ continueCursor: result.continueCursor,
76
+ };
77
+ },
78
+ });
79
+ /**
80
+ * Get customer loyalty points balance
81
+ */
82
+ export const getLoyaltyPoints = query({
83
+ args: {},
84
+ handler: async (ctx) => {
85
+ const user = await getCurrentCustomer(ctx);
86
+ const loyaltyPoints = await ctx.db
87
+ .query("loyaltyPoints")
88
+ .withIndex("by_customer", (q) => q.eq("customerId", user._id))
89
+ .first();
90
+ if (!loyaltyPoints || loyaltyPoints.isDeleted) {
91
+ return {
92
+ points: 0,
93
+ totalEarned: 0,
94
+ totalRedeemed: 0,
95
+ };
96
+ }
97
+ return {
98
+ points: loyaltyPoints.points,
99
+ totalEarned: loyaltyPoints.totalEarned,
100
+ totalRedeemed: loyaltyPoints.totalRedeemed,
101
+ lastEarnedAt: loyaltyPoints.lastEarnedAt,
102
+ lastRedeemedAt: loyaltyPoints.lastRedeemedAt,
103
+ };
104
+ },
105
+ });
106
+ /**
107
+ * Create guest customer (walk-in, no Clerk account)
108
+ * Used when creating walk-in orders at POS
109
+ */
110
+ export const createGuest = mutation({
111
+ args: {
112
+ name: v.string(),
113
+ phoneNumber: v.string(),
114
+ },
115
+ handler: async (ctx, args) => {
116
+ // Check if customer already exists
117
+ const existing = await ctx.db
118
+ .query("users")
119
+ .withIndex("by_phone", (q) => q.eq("phoneNumber", args.phoneNumber))
120
+ .first();
121
+ if (existing) {
122
+ if (!existing.isDeleted) {
123
+ return existing._id;
124
+ }
125
+ // If deleted, reactivate the account
126
+ await ctx.db.patch(existing._id, {
127
+ isDeleted: false,
128
+ name: args.name,
129
+ });
130
+ return existing._id;
131
+ }
132
+ // Create new guest customer
133
+ const userId = await ctx.db.insert("users", {
134
+ name: args.name,
135
+ phoneNumber: args.phoneNumber,
136
+ clerkUserId: undefined,
137
+ isRegistered: false,
138
+ isVerified: false,
139
+ status: "active",
140
+ createdAt: getCurrentTimestamp(),
141
+ isDeleted: false,
142
+ });
143
+ await createAuditLog({
144
+ ctx,
145
+ actorId: "system",
146
+ actorType: "admin",
147
+ actorRole: "system",
148
+ action: "customer.guest_created",
149
+ entityType: "user",
150
+ entityId: userId,
151
+ details: JSON.stringify({ phoneNumber: args.phoneNumber, name: args.name }),
152
+ });
153
+ return userId;
154
+ },
155
+ });
156
+ /**
157
+ * Register customer (link Clerk account to customer profile)
158
+ * Called after customer signs up via Clerk
159
+ */
160
+ export const register = mutation({
161
+ args: {
162
+ name: v.string(),
163
+ phoneNumber: v.string(),
164
+ email: v.optional(v.string()),
165
+ },
166
+ handler: async (ctx, args) => {
167
+ const identity = await getClerkIdentity(ctx);
168
+ const clerkUserId = identity.subject;
169
+ // Check if customer already exists with this Clerk ID
170
+ const existingByClerk = await ctx.db
171
+ .query("users")
172
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
173
+ .first();
174
+ if (existingByClerk && !existingByClerk.isDeleted) {
175
+ throw new Error("Customer account already registered");
176
+ }
177
+ // Check if guest customer exists with this phone number
178
+ const existingByPhone = await ctx.db
179
+ .query("users")
180
+ .withIndex("by_phone", (q) => q.eq("phoneNumber", args.phoneNumber))
181
+ .first();
182
+ let userId;
183
+ if (existingByPhone && !existingByPhone.isDeleted) {
184
+ // Update existing guest customer with Clerk ID
185
+ userId = existingByPhone._id;
186
+ await ctx.db.patch(userId, {
187
+ clerkUserId,
188
+ isRegistered: true,
189
+ isVerified: identity.emailVerified ?? false,
190
+ email: args.email ?? existingByPhone.email,
191
+ name: args.name,
192
+ lastLoginAt: getCurrentTimestamp(),
193
+ });
194
+ }
195
+ else if (existingByPhone && existingByPhone.isDeleted) {
196
+ // Reactivate deleted account
197
+ userId = existingByPhone._id;
198
+ await ctx.db.patch(userId, {
199
+ clerkUserId,
200
+ isRegistered: true,
201
+ isVerified: identity.emailVerified ?? false,
202
+ email: args.email,
203
+ name: args.name,
204
+ isDeleted: false,
205
+ lastLoginAt: getCurrentTimestamp(),
206
+ });
207
+ }
208
+ else {
209
+ // Create new registered customer
210
+ userId = await ctx.db.insert("users", {
211
+ name: args.name,
212
+ phoneNumber: args.phoneNumber,
213
+ email: args.email,
214
+ clerkUserId,
215
+ isRegistered: true,
216
+ isVerified: identity.emailVerified ?? false,
217
+ status: "active",
218
+ createdAt: getCurrentTimestamp(),
219
+ lastLoginAt: getCurrentTimestamp(),
220
+ isDeleted: false,
221
+ });
222
+ }
223
+ await createAuditLog({
224
+ ctx,
225
+ actorId: clerkUserId,
226
+ actorType: "customer",
227
+ actorRole: "customer",
228
+ action: "customer.registered",
229
+ entityType: "user",
230
+ entityId: userId,
231
+ details: JSON.stringify({ phoneNumber: args.phoneNumber, email: args.email }),
232
+ });
233
+ return userId;
234
+ },
235
+ });
236
+ /**
237
+ * Update customer profile
238
+ */
239
+ export const updateProfile = mutation({
240
+ args: {
241
+ name: v.optional(v.string()),
242
+ email: v.optional(v.string()),
243
+ preferredBranchId: v.optional(v.id("branches")),
244
+ },
245
+ handler: async (ctx, args) => {
246
+ const user = await getCurrentCustomer(ctx);
247
+ const identity = await getClerkIdentity(ctx);
248
+ const updates = {};
249
+ if (args.name !== undefined) {
250
+ updates.name = args.name;
251
+ }
252
+ if (args.email !== undefined) {
253
+ updates.email = args.email;
254
+ }
255
+ if (args.preferredBranchId !== undefined) {
256
+ // Verify branch exists
257
+ const branch = await ctx.db.get(args.preferredBranchId);
258
+ if (!branch || branch.isDeleted) {
259
+ throw new Error("Branch not found");
260
+ }
261
+ updates.preferredBranchId = args.preferredBranchId;
262
+ }
263
+ updates.lastLoginAt = getCurrentTimestamp();
264
+ await ctx.db.patch(user._id, updates);
265
+ await createAuditLog({
266
+ ctx,
267
+ actorId: identity.subject,
268
+ actorType: "customer",
269
+ actorRole: "customer",
270
+ action: "customer.profile_updated",
271
+ entityType: "user",
272
+ entityId: user._id,
273
+ details: JSON.stringify(updates),
274
+ });
275
+ return user._id;
276
+ },
277
+ });
278
+ /**
279
+ * Create test user (DEV ONLY)
280
+ *
281
+ * This mutation allows creating test users in development without requiring
282
+ * Clerk authentication. Useful for testing and development.
283
+ *
284
+ * WARNING: This should only be used in development environments.
285
+ * In production, users should be created via Clerk webhooks or the register mutation.
286
+ */
287
+ export const createTestUser = mutation({
288
+ args: {
289
+ name: v.string(),
290
+ phoneNumber: v.string(),
291
+ email: v.optional(v.string()),
292
+ clerkUserId: v.optional(v.string()), // Optional: can simulate Clerk user
293
+ isRegistered: v.optional(v.boolean()), // Default: true if clerkUserId provided
294
+ isVerified: v.optional(v.boolean()), // Default: false
295
+ },
296
+ handler: async (ctx, args) => {
297
+ // Check if customer already exists by phone
298
+ const existingByPhone = await ctx.db
299
+ .query("users")
300
+ .withIndex("by_phone", (q) => q.eq("phoneNumber", args.phoneNumber))
301
+ .first();
302
+ if (existingByPhone && !existingByPhone.isDeleted) {
303
+ throw new Error("Customer with this phone number already exists");
304
+ }
305
+ // Check if customer exists by Clerk ID (if provided)
306
+ if (args.clerkUserId) {
307
+ const existingByClerk = await ctx.db
308
+ .query("users")
309
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", args.clerkUserId))
310
+ .first();
311
+ if (existingByClerk && !existingByClerk.isDeleted) {
312
+ throw new Error("Customer with this Clerk ID already exists");
313
+ }
314
+ }
315
+ const now = getCurrentTimestamp();
316
+ const isRegistered = args.isRegistered ?? (args.clerkUserId !== undefined);
317
+ const isVerified = args.isVerified ?? false;
318
+ // If existing but deleted, reactivate
319
+ if (existingByPhone && existingByPhone.isDeleted) {
320
+ await ctx.db.patch(existingByPhone._id, {
321
+ name: args.name,
322
+ email: args.email,
323
+ clerkUserId: args.clerkUserId,
324
+ isRegistered,
325
+ isVerified,
326
+ isDeleted: false,
327
+ lastLoginAt: now,
328
+ });
329
+ await createAuditLog({
330
+ ctx,
331
+ actorId: args.clerkUserId || "system",
332
+ actorType: "admin",
333
+ actorRole: "system",
334
+ action: "customer.test_user_created",
335
+ entityType: "user",
336
+ entityId: existingByPhone._id,
337
+ details: JSON.stringify({
338
+ phoneNumber: args.phoneNumber,
339
+ email: args.email,
340
+ isTestUser: true
341
+ }),
342
+ });
343
+ return existingByPhone._id;
344
+ }
345
+ // Create new test user
346
+ const userId = await ctx.db.insert("users", {
347
+ name: args.name,
348
+ phoneNumber: args.phoneNumber,
349
+ email: args.email,
350
+ clerkUserId: args.clerkUserId,
351
+ isRegistered,
352
+ isVerified,
353
+ status: "active",
354
+ createdAt: now,
355
+ lastLoginAt: now,
356
+ isDeleted: false,
357
+ });
358
+ await createAuditLog({
359
+ ctx,
360
+ actorId: args.clerkUserId || "system",
361
+ actorType: "admin",
362
+ actorRole: "system",
363
+ action: "customer.test_user_created",
364
+ entityType: "user",
365
+ entityId: userId,
366
+ details: JSON.stringify({
367
+ phoneNumber: args.phoneNumber,
368
+ email: args.email,
369
+ isTestUser: true
370
+ }),
371
+ });
372
+ return userId;
373
+ },
374
+ });
375
+ /**
376
+ * Search customers by name or phone number
377
+ * Used by POS for customer lookup
378
+ */
379
+ export const search = query({
380
+ args: {
381
+ query: v.string(),
382
+ limit: v.optional(v.number()),
383
+ },
384
+ handler: async (ctx, args) => {
385
+ // Allow both attendants and admins
386
+ try {
387
+ const { getCurrentAttendant } = await import("./lib/auth");
388
+ await getCurrentAttendant(ctx);
389
+ }
390
+ catch {
391
+ const { getCurrentAdmin } = await import("./lib/auth");
392
+ await getCurrentAdmin(ctx);
393
+ }
394
+ const limit = args.limit ?? 20;
395
+ const searchQuery = args.query.toLowerCase().trim();
396
+ if (searchQuery.length < 2) {
397
+ return [];
398
+ }
399
+ // Get all customers
400
+ const allCustomers = await ctx.db
401
+ .query("users")
402
+ .filter((q) => q.eq(q.field("isDeleted"), false))
403
+ .collect();
404
+ // Filter by name or phone
405
+ const filtered = allCustomers.filter((c) => {
406
+ const nameMatch = c.name.toLowerCase().includes(searchQuery);
407
+ const phoneMatch = c.phoneNumber.includes(searchQuery);
408
+ return nameMatch || phoneMatch;
409
+ });
410
+ // Sort by relevance (exact phone match first, then name match)
411
+ const sorted = filtered.sort((a, b) => {
412
+ const aPhoneExact = a.phoneNumber === searchQuery;
413
+ const bPhoneExact = b.phoneNumber === searchQuery;
414
+ if (aPhoneExact && !bPhoneExact)
415
+ return -1;
416
+ if (!aPhoneExact && bPhoneExact)
417
+ return 1;
418
+ const aNameStarts = a.name.toLowerCase().startsWith(searchQuery);
419
+ const bNameStarts = b.name.toLowerCase().startsWith(searchQuery);
420
+ if (aNameStarts && !bNameStarts)
421
+ return -1;
422
+ if (!aNameStarts && bNameStarts)
423
+ return 1;
424
+ return a.name.localeCompare(b.name);
425
+ });
426
+ // Get order counts for each customer
427
+ const customersWithStats = await Promise.all(sorted.slice(0, limit).map(async (customer) => {
428
+ const orders = await ctx.db
429
+ .query("orders")
430
+ .withIndex("by_customer", (q) => q.eq("customerId", customer._id))
431
+ .collect();
432
+ const completedOrders = orders.filter((o) => !o.isDeleted && o.status === "completed").length;
433
+ const totalSpent = orders
434
+ .filter((o) => !o.isDeleted && o.paymentStatus === "paid")
435
+ .reduce((sum, o) => sum + o.finalPrice, 0);
436
+ // Get last order date
437
+ const lastOrder = orders
438
+ .filter((o) => !o.isDeleted)
439
+ .sort((a, b) => b.createdAt - a.createdAt)[0];
440
+ return {
441
+ ...customer,
442
+ orderCount: orders.filter((o) => !o.isDeleted).length,
443
+ completedOrderCount: completedOrders,
444
+ totalSpent: Math.round(totalSpent * 100) / 100,
445
+ lastOrderDate: lastOrder?.createdAt,
446
+ };
447
+ }));
448
+ return customersWithStats;
449
+ },
450
+ });
451
+ /**
452
+ * Get customer details with full order history
453
+ */
454
+ export const getDetails = query({
455
+ args: {
456
+ customerId: v.id("users"),
457
+ },
458
+ handler: async (ctx, args) => {
459
+ // Allow both attendants and admins
460
+ try {
461
+ const { getCurrentAttendant } = await import("./lib/auth");
462
+ await getCurrentAttendant(ctx);
463
+ }
464
+ catch {
465
+ const { getCurrentAdmin } = await import("./lib/auth");
466
+ await getCurrentAdmin(ctx);
467
+ }
468
+ const customer = await ctx.db.get(args.customerId);
469
+ if (!customer || customer.isDeleted) {
470
+ throw new Error("Customer not found");
471
+ }
472
+ // Get all orders
473
+ const orders = await ctx.db
474
+ .query("orders")
475
+ .withIndex("by_customer", (q) => q.eq("customerId", args.customerId))
476
+ .collect();
477
+ const activeOrders = orders.filter((o) => !o.isDeleted);
478
+ const completedOrders = activeOrders.filter((o) => o.status === "completed");
479
+ const totalSpent = activeOrders
480
+ .filter((o) => o.paymentStatus === "paid")
481
+ .reduce((sum, o) => sum + o.finalPrice, 0);
482
+ // Get loyalty points
483
+ const loyaltyPoints = await ctx.db
484
+ .query("loyaltyPoints")
485
+ .withIndex("by_customer", (q) => q.eq("customerId", args.customerId))
486
+ .first();
487
+ // Get last order
488
+ const lastOrder = activeOrders
489
+ .sort((a, b) => b.createdAt - a.createdAt)[0];
490
+ return {
491
+ ...customer,
492
+ orderCount: activeOrders.length,
493
+ completedOrderCount: completedOrders.length,
494
+ totalSpent: Math.round(totalSpent * 100) / 100,
495
+ averageOrderValue: activeOrders.length > 0
496
+ ? Math.round((totalSpent / activeOrders.length) * 100) / 100
497
+ : 0,
498
+ loyaltyPoints: loyaltyPoints?.points || 0,
499
+ lastOrderDate: lastOrder?.createdAt,
500
+ lastOrderNumber: lastOrder?.orderNumber,
501
+ };
502
+ },
503
+ });
504
+ //# sourceMappingURL=customers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customers.js","sourceRoot":"","sources":["../../convex/customers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const http: import("convex/server").HttpRouter;
2
+ export default http;
3
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../convex/http.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,IAAI,oCAAe,CAAA;AA0IzB,eAAe,IAAI,CAAA"}
@@ -0,0 +1,115 @@
1
+ import { httpRouter } from "convex/server";
2
+ import { httpAction } from "./_generated/server";
3
+ import { internal } from "./_generated/api";
4
+ const http = httpRouter();
5
+ /**
6
+ * Clerk Webhook Handler
7
+ *
8
+ * Handles webhook events from Clerk to keep user data in sync.
9
+ *
10
+ * Required Clerk webhook events:
11
+ * - user.created
12
+ * - user.updated
13
+ * - user.deleted
14
+ *
15
+ * Setup in Clerk Dashboard:
16
+ * 1. Go to Webhooks section
17
+ * 2. Add endpoint: https://your-deployment.convex.site/clerk-webhook
18
+ * 3. Subscribe to: user.created, user.updated, user.deleted
19
+ * 4. Copy the signing secret and set as CLERK_WEBHOOK_SECRET in Convex
20
+ */
21
+ http.route({
22
+ path: "/clerk-webhook",
23
+ method: "POST",
24
+ handler: httpAction(async (ctx, request) => {
25
+ // Verify webhook signature (optional but recommended)
26
+ const webhookSecret = process.env.CLERK_WEBHOOK_SECRET;
27
+ if (webhookSecret) {
28
+ const signature = request.headers.get("svix-signature");
29
+ if (!signature) {
30
+ return new Response("Missing signature", { status: 401 });
31
+ }
32
+ // Note: For production, implement proper signature verification
33
+ // using svix library or similar
34
+ }
35
+ try {
36
+ const event = await request.json();
37
+ // Handle different webhook event types
38
+ switch (event.type) {
39
+ case "user.created": {
40
+ const userData = event.data;
41
+ // Extract user information
42
+ const clerkUserId = userData.id;
43
+ const email = userData.email_addresses?.[0]?.email_address;
44
+ const phoneNumber = userData.phone_numbers?.[0]?.phone_number;
45
+ const firstName = userData.first_name || "";
46
+ const lastName = userData.last_name || "";
47
+ const name = `${firstName} ${lastName}`.trim() || email || phoneNumber || "User";
48
+ const emailVerified = userData.email_addresses?.[0]?.verification?.status === "verified";
49
+ // Determine user type from Clerk metadata or roles
50
+ // You can customize this based on your Clerk setup
51
+ const userType = userData.public_metadata?.userType ||
52
+ userData.private_metadata?.userType ||
53
+ "customer"; // Default to customer
54
+ // Sync user to database
55
+ await ctx.runMutation(internal.clerk.syncUserCreated, {
56
+ clerkUserId,
57
+ email,
58
+ phoneNumber,
59
+ name,
60
+ emailVerified,
61
+ userType,
62
+ });
63
+ break;
64
+ }
65
+ case "user.updated": {
66
+ const userData = event.data;
67
+ const clerkUserId = userData.id;
68
+ const email = userData.email_addresses?.[0]?.email_address;
69
+ const phoneNumber = userData.phone_numbers?.[0]?.phone_number;
70
+ const firstName = userData.first_name || "";
71
+ const lastName = userData.last_name || "";
72
+ const name = `${firstName} ${lastName}`.trim() || email || phoneNumber || "User";
73
+ const emailVerified = userData.email_addresses?.[0]?.verification?.status === "verified";
74
+ // Check if userType changed in metadata
75
+ const userType = userData.public_metadata?.userType ||
76
+ userData.private_metadata?.userType ||
77
+ undefined;
78
+ await ctx.runMutation(internal.clerk.syncUserUpdated, {
79
+ clerkUserId,
80
+ email,
81
+ phoneNumber,
82
+ name,
83
+ emailVerified,
84
+ userType,
85
+ });
86
+ break;
87
+ }
88
+ case "user.deleted": {
89
+ const userData = event.data;
90
+ const clerkUserId = userData.id;
91
+ await ctx.runMutation(internal.clerk.syncUserDeleted, {
92
+ clerkUserId,
93
+ });
94
+ break;
95
+ }
96
+ default:
97
+ // Ignore unknown event types
98
+ console.log(`Unknown webhook event type: ${event.type}`);
99
+ }
100
+ return new Response(JSON.stringify({ received: true }), {
101
+ status: 200,
102
+ headers: { "Content-Type": "application/json" },
103
+ });
104
+ }
105
+ catch (error) {
106
+ console.error("Webhook error:", error);
107
+ return new Response(JSON.stringify({ error: "Webhook processing failed" }), {
108
+ status: 500,
109
+ headers: { "Content-Type": "application/json" },
110
+ });
111
+ }
112
+ }),
113
+ });
114
+ export default http;
115
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../convex/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE3C,MAAM,IAAI,GAAG,UAAU,EAAE,CAAA;AAEzB;;;;;;;;;;;;;;;GAeG;AACH,IAAI,CAAC,KAAK,CAAC;IACT,IAAI,EAAE,gBAAgB;IACtB,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;QACzC,sDAAsD;QACtD,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAA;QACtD,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;YACvD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAC3D,CAAC;YACD,gEAAgE;YAChE,gCAAgC;QAClC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,EAG/B,CAAA;YAED,uCAAuC;YACvC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,cAAc,CAAC,CAAC,CAAC;oBACpB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAA;oBAE3B,2BAA2B;oBAC3B,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,CAAA;oBAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,CAAA;oBAC1D,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAA;oBAC7D,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAA;oBAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAA;oBACzC,MAAM,IAAI,GACR,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,WAAW,IAAI,MAAM,CAAA;oBACrE,MAAM,aAAa,GACjB,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,KAAK,UAAU,CAAA;oBAEpE,mDAAmD;oBACnD,mDAAmD;oBACnD,MAAM,QAAQ,GACZ,QAAQ,CAAC,eAAe,EAAE,QAAQ;wBAClC,QAAQ,CAAC,gBAAgB,EAAE,QAAQ;wBACnC,UAAU,CAAA,CAAC,sBAAsB;oBAEnC,wBAAwB;oBACxB,MAAM,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,EAAE;wBACpD,WAAW;wBACX,KAAK;wBACL,WAAW;wBACX,IAAI;wBACJ,aAAa;wBACb,QAAQ;qBACT,CAAC,CAAA;oBAEF,MAAK;gBACP,CAAC;gBAED,KAAK,cAAc,CAAC,CAAC,CAAC;oBACpB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAA;oBAC3B,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,CAAA;oBAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,CAAA;oBAC1D,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAA;oBAC7D,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAA;oBAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAA;oBACzC,MAAM,IAAI,GACR,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,WAAW,IAAI,MAAM,CAAA;oBACrE,MAAM,aAAa,GACjB,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,KAAK,UAAU,CAAA;oBAEpE,wCAAwC;oBACxC,MAAM,QAAQ,GACZ,QAAQ,CAAC,eAAe,EAAE,QAAQ;wBAClC,QAAQ,CAAC,gBAAgB,EAAE,QAAQ;wBACnC,SAAS,CAAA;oBAEX,MAAM,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,EAAE;wBACpD,WAAW;wBACX,KAAK;wBACL,WAAW;wBACX,IAAI;wBACJ,aAAa;wBACb,QAAQ;qBACT,CAAC,CAAA;oBAEF,MAAK;gBACP,CAAC;gBAED,KAAK,cAAc,CAAC,CAAC,CAAC;oBACpB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAA;oBAC3B,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,CAAA;oBAE/B,MAAM,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,EAAE;wBACpD,WAAW;qBACZ,CAAC,CAAA;oBAEF,MAAK;gBACP,CAAC;gBAED;oBACE,6BAA6B;oBAC7B,OAAO,CAAC,GAAG,CAAC,+BAA+B,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YAC5D,CAAC;YAED,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE;gBACtD,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;YACtC,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,EACtD;gBACE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CACF,CAAA;QACH,CAAC;IACH,CAAC,CAAC;CACH,CAAC,CAAA;AAEF,eAAe,IAAI,CAAA"}