@devwithbobby/loops 0.1.12 → 0.1.14

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 (41) hide show
  1. package/dist/client/index.d.ts +305 -44
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +21 -32
  4. package/dist/component/convex.config.d.ts +1 -1
  5. package/dist/component/convex.config.d.ts.map +1 -1
  6. package/dist/component/convex.config.js +1 -1
  7. package/dist/component/helpers.d.ts +7 -0
  8. package/dist/component/helpers.d.ts.map +1 -0
  9. package/dist/component/helpers.js +30 -0
  10. package/dist/component/http.d.ts +3 -0
  11. package/dist/component/http.d.ts.map +1 -0
  12. package/dist/component/http.js +268 -0
  13. package/dist/component/lib.d.ts +237 -22
  14. package/dist/component/lib.d.ts.map +1 -1
  15. package/dist/component/lib.js +91 -143
  16. package/dist/component/schema.d.ts +66 -1
  17. package/dist/component/schema.d.ts.map +1 -1
  18. package/dist/component/tables/contacts.d.ts +123 -1
  19. package/dist/component/tables/contacts.d.ts.map +1 -1
  20. package/dist/component/tables/emailOperations.d.ts +151 -1
  21. package/dist/component/tables/emailOperations.d.ts.map +1 -1
  22. package/dist/component/tables/emailOperations.js +1 -6
  23. package/dist/component/validators.d.ts +20 -3
  24. package/dist/component/validators.d.ts.map +1 -1
  25. package/dist/types.d.ts +97 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +2 -0
  28. package/dist/utils.d.ts +186 -3
  29. package/dist/utils.d.ts.map +1 -1
  30. package/package.json +101 -101
  31. package/src/client/index.ts +40 -52
  32. package/src/component/_generated/api.d.ts +3 -11
  33. package/src/component/convex.config.ts +7 -2
  34. package/src/component/helpers.ts +44 -0
  35. package/src/component/http.ts +304 -0
  36. package/src/component/lib.ts +189 -204
  37. package/src/component/tables/contacts.ts +0 -1
  38. package/src/component/tables/emailOperations.ts +1 -7
  39. package/src/component/validators.ts +0 -1
  40. package/src/types.ts +168 -0
  41. package/src/client/types.ts +0 -64
@@ -1,26 +1,8 @@
1
1
  import { z } from "zod";
2
+ import { internalLib } from "../types";
2
3
  import { za, zm, zq } from "../utils.js";
3
- import { internal } from "./_generated/api";
4
+ import { loopsFetch, sanitizeLoopsError } from "./helpers";
4
5
  import { contactValidator } from "./validators.js";
5
- const LOOPS_API_BASE_URL = "https://app.loops.so/api/v1";
6
- /**
7
- * Sanitize error messages to avoid leaking sensitive information
8
- */
9
- const sanitizeError = (status, errorText) => {
10
- if (status === 401 || status === 403) {
11
- return new Error("Authentication failed. Please check your API key.");
12
- }
13
- if (status === 404) {
14
- return new Error("Resource not found.");
15
- }
16
- if (status === 429) {
17
- return new Error("Rate limit exceeded. Please try again later.");
18
- }
19
- if (status >= 500) {
20
- return new Error("Loops service error. Please try again later.");
21
- }
22
- return new Error(`Loops API error (${status}). Please try again.`);
23
- };
24
6
  /**
25
7
  * Internal mutation to store/update a contact in the database
26
8
  */
@@ -111,21 +93,14 @@ export const logEmailOperation = zm({
111
93
  email: args.email,
112
94
  timestamp: Date.now(),
113
95
  success: args.success,
96
+ actorId: args.actorId,
97
+ transactionalId: args.transactionalId,
98
+ campaignId: args.campaignId,
99
+ loopId: args.loopId,
100
+ eventName: args.eventName,
101
+ messageId: args.messageId,
102
+ metadata: args.metadata,
114
103
  };
115
- if (args.actorId)
116
- operationData.actorId = args.actorId;
117
- if (args.transactionalId)
118
- operationData.transactionalId = args.transactionalId;
119
- if (args.campaignId)
120
- operationData.campaignId = args.campaignId;
121
- if (args.loopId)
122
- operationData.loopId = args.loopId;
123
- if (args.eventName)
124
- operationData.eventName = args.eventName;
125
- if (args.messageId)
126
- operationData.messageId = args.messageId;
127
- if (args.metadata)
128
- operationData.metadata = args.metadata;
129
104
  await ctx.db.insert("emailOperations", operationData);
130
105
  },
131
106
  });
@@ -244,7 +219,12 @@ export const listContacts = zq({
244
219
  // Sort by createdAt (newest first)
245
220
  allContacts.sort((a, b) => b.createdAt - a.createdAt);
246
221
  const total = allContacts.length;
247
- const paginatedContacts = allContacts.slice(args.offset, args.offset + args.limit);
222
+ const paginatedContacts = allContacts
223
+ .slice(args.offset, args.offset + args.limit)
224
+ .map((contact) => ({
225
+ ...contact,
226
+ subscribed: contact.subscribed ?? true, // Ensure subscribed is always boolean
227
+ }));
248
228
  const hasMore = args.offset + args.limit < total;
249
229
  return {
250
230
  contacts: paginatedContacts,
@@ -270,36 +250,22 @@ export const addContact = za({
270
250
  id: z.string().optional(),
271
251
  }),
272
252
  handler: async (ctx, args) => {
273
- const response = await fetch(`${LOOPS_API_BASE_URL}/contacts/create`, {
253
+ const createResponse = await loopsFetch(args.apiKey, "/contacts/create", {
274
254
  method: "POST",
275
- headers: {
276
- Authorization: `Bearer ${args.apiKey}`,
277
- "Content-Type": "application/json",
278
- },
279
- body: JSON.stringify(args.contact),
255
+ json: args.contact,
280
256
  });
281
- if (!response.ok) {
282
- const errorText = await response.text();
283
- if (response.status === 409) {
257
+ if (!createResponse.ok) {
258
+ const errorText = await createResponse.text();
259
+ if (createResponse.status === 409) {
284
260
  console.log(`Contact ${args.contact.email} already exists, updating instead`);
285
- const findResponse = await fetch(`${LOOPS_API_BASE_URL}/contacts/find?email=${encodeURIComponent(args.contact.email)}`, {
286
- method: "GET",
287
- headers: {
288
- Authorization: `Bearer ${args.apiKey}`,
289
- "Content-Type": "application/json",
290
- },
291
- });
261
+ const findResponse = await loopsFetch(args.apiKey, `/contacts/find?email=${encodeURIComponent(args.contact.email)}`, { method: "GET" });
292
262
  if (!findResponse.ok) {
293
263
  const findErrorText = await findResponse.text();
294
264
  console.error(`Failed to find existing contact [${findResponse.status}]:`, findErrorText);
295
265
  }
296
- const updateResponse = await fetch(`${LOOPS_API_BASE_URL}/contacts/update`, {
266
+ const updateResponse = await loopsFetch(args.apiKey, "/contacts/update", {
297
267
  method: "PUT",
298
- headers: {
299
- Authorization: `Bearer ${args.apiKey}`,
300
- "Content-Type": "application/json",
301
- },
302
- body: JSON.stringify({
268
+ json: {
303
269
  email: args.contact.email,
304
270
  firstName: args.contact.firstName,
305
271
  lastName: args.contact.lastName,
@@ -307,12 +273,12 @@ export const addContact = za({
307
273
  source: args.contact.source,
308
274
  subscribed: args.contact.subscribed,
309
275
  userGroup: args.contact.userGroup,
310
- }),
276
+ },
311
277
  });
312
278
  if (!updateResponse.ok) {
313
279
  const updateErrorText = await updateResponse.text();
314
280
  console.error(`Loops API error [${updateResponse.status}]:`, updateErrorText);
315
- throw sanitizeError(updateResponse.status, updateErrorText);
281
+ throw sanitizeLoopsError(updateResponse.status, updateErrorText);
316
282
  }
317
283
  // Get contact ID if available
318
284
  let contactId;
@@ -321,7 +287,7 @@ export const addContact = za({
321
287
  contactId = findData.id;
322
288
  }
323
289
  // Store/update in our database
324
- await ctx.runMutation((internal.lib).storeContact, {
290
+ await ctx.runMutation(internalLib.storeContact, {
325
291
  email: args.contact.email,
326
292
  firstName: args.contact.firstName,
327
293
  lastName: args.contact.lastName,
@@ -336,13 +302,12 @@ export const addContact = za({
336
302
  id: contactId,
337
303
  };
338
304
  }
339
- // For other errors, throw as normal
340
- console.error(`Loops API error [${response.status}]:`, errorText);
341
- throw sanitizeError(response.status, errorText);
305
+ console.error(`Loops API error [${createResponse.status}]:`, errorText);
306
+ throw sanitizeLoopsError(createResponse.status, errorText);
342
307
  }
343
308
  // Contact was created successfully
344
- const data = (await response.json());
345
- await ctx.runMutation((internal.lib).storeContact, {
309
+ const data = (await createResponse.json());
310
+ await ctx.runMutation(internalLib.storeContact, {
346
311
  email: args.contact.email,
347
312
  firstName: args.contact.firstName,
348
313
  lastName: args.contact.lastName,
@@ -377,13 +342,9 @@ export const updateContact = za({
377
342
  success: z.boolean(),
378
343
  }),
379
344
  handler: async (ctx, args) => {
380
- const response = await fetch(`${LOOPS_API_BASE_URL}/contacts/update`, {
345
+ const response = await loopsFetch(args.apiKey, "/contacts/update", {
381
346
  method: "PUT",
382
- headers: {
383
- Authorization: `Bearer ${args.apiKey}`,
384
- "Content-Type": "application/json",
385
- },
386
- body: JSON.stringify({
347
+ json: {
387
348
  email: args.email,
388
349
  dataVariables: args.dataVariables,
389
350
  firstName: args.firstName,
@@ -392,14 +353,14 @@ export const updateContact = za({
392
353
  source: args.source,
393
354
  subscribed: args.subscribed,
394
355
  userGroup: args.userGroup,
395
- }),
356
+ },
396
357
  });
397
358
  if (!response.ok) {
398
359
  const errorText = await response.text();
399
360
  console.error(`Loops API error [${response.status}]:`, errorText);
400
- throw sanitizeError(response.status, errorText);
361
+ throw sanitizeLoopsError(response.status, errorText);
401
362
  }
402
- await ctx.runMutation((internal.lib).storeContact, {
363
+ await ctx.runMutation(internalLib.storeContact, {
403
364
  email: args.email,
404
365
  firstName: args.firstName,
405
366
  lastName: args.lastName,
@@ -426,31 +387,27 @@ export const sendTransactional = za({
426
387
  messageId: z.string().optional(),
427
388
  }),
428
389
  handler: async (ctx, args) => {
429
- const response = await fetch(`${LOOPS_API_BASE_URL}/transactional`, {
390
+ const response = await loopsFetch(args.apiKey, "/transactional", {
430
391
  method: "POST",
431
- headers: {
432
- Authorization: `Bearer ${args.apiKey}`,
433
- "Content-Type": "application/json",
434
- },
435
- body: JSON.stringify({
392
+ json: {
436
393
  transactionalId: args.transactionalId,
437
394
  email: args.email,
438
395
  dataVariables: args.dataVariables,
439
- }),
396
+ },
440
397
  });
441
398
  if (!response.ok) {
442
399
  const errorText = await response.text();
443
400
  console.error(`Loops API error [${response.status}]:`, errorText);
444
- await ctx.runMutation((internal.lib).logEmailOperation, {
401
+ await ctx.runMutation(internalLib.logEmailOperation, {
445
402
  operationType: "transactional",
446
403
  email: args.email,
447
404
  success: false,
448
405
  transactionalId: args.transactionalId,
449
406
  });
450
- throw sanitizeError(response.status, errorText);
407
+ throw sanitizeLoopsError(response.status, errorText);
451
408
  }
452
409
  const data = (await response.json());
453
- await ctx.runMutation((internal.lib).logEmailOperation, {
410
+ await ctx.runMutation(internalLib.logEmailOperation, {
454
411
  operationType: "transactional",
455
412
  email: args.email,
456
413
  success: true,
@@ -476,23 +433,19 @@ export const sendEvent = za({
476
433
  returns: z.object({
477
434
  success: z.boolean(),
478
435
  }),
479
- handler: async (ctx, args) => {
480
- const response = await fetch(`${LOOPS_API_BASE_URL}/events/send`, {
436
+ handler: async (_ctx, args) => {
437
+ const response = await loopsFetch(args.apiKey, "/events/send", {
481
438
  method: "POST",
482
- headers: {
483
- Authorization: `Bearer ${args.apiKey}`,
484
- "Content-Type": "application/json",
485
- },
486
- body: JSON.stringify({
439
+ json: {
487
440
  email: args.email,
488
441
  eventName: args.eventName,
489
442
  eventProperties: args.eventProperties,
490
- }),
443
+ },
491
444
  });
492
445
  if (!response.ok) {
493
446
  const errorText = await response.text();
494
447
  console.error(`Loops API error [${response.status}]:`, errorText);
495
- throw sanitizeError(response.status, errorText);
448
+ throw sanitizeLoopsError(response.status, errorText);
496
449
  }
497
450
  return { success: true };
498
451
  },
@@ -509,20 +462,16 @@ export const deleteContact = za({
509
462
  success: z.boolean(),
510
463
  }),
511
464
  handler: async (ctx, args) => {
512
- const response = await fetch(`${LOOPS_API_BASE_URL}/contacts/delete`, {
465
+ const response = await loopsFetch(args.apiKey, "/contacts/delete", {
513
466
  method: "POST",
514
- headers: {
515
- Authorization: `Bearer ${args.apiKey}`,
516
- "Content-Type": "application/json",
517
- },
518
- body: JSON.stringify({ email: args.email }),
467
+ json: { email: args.email },
519
468
  });
520
469
  if (!response.ok) {
521
470
  const errorText = await response.text();
522
471
  console.error(`Loops API error [${response.status}]:`, errorText);
523
- throw sanitizeError(response.status, errorText);
472
+ throw sanitizeLoopsError(response.status, errorText);
524
473
  }
525
- await ctx.runMutation((internal.lib).removeContact, {
474
+ await ctx.runMutation(internalLib.removeContact, {
526
475
  email: args.email,
527
476
  });
528
477
  return { success: true };
@@ -563,7 +512,7 @@ export const triggerLoop = za({
563
512
  const eventName = args.eventName || `loop_${args.loopId}`;
564
513
  try {
565
514
  // Send event to trigger the loop
566
- await ctx.runAction((internal.lib).sendEvent, {
515
+ await ctx.runAction(internalLib.sendEvent, {
567
516
  apiKey: args.apiKey,
568
517
  email: args.email,
569
518
  eventName,
@@ -573,7 +522,7 @@ export const triggerLoop = za({
573
522
  },
574
523
  });
575
524
  // Log as loop operation
576
- await ctx.runMutation((internal.lib).logEmailOperation, {
525
+ await ctx.runMutation(internalLib.logEmailOperation, {
577
526
  operationType: "loop",
578
527
  email: args.email,
579
528
  success: true,
@@ -587,13 +536,15 @@ export const triggerLoop = za({
587
536
  }
588
537
  catch (error) {
589
538
  // Log failed loop operation
590
- await ctx.runMutation((internal.lib).logEmailOperation, {
539
+ await ctx.runMutation(internalLib.logEmailOperation, {
591
540
  operationType: "loop",
592
541
  email: args.email,
593
542
  success: false,
594
543
  loopId: args.loopId,
595
544
  eventName,
596
- metadata: { error: error instanceof Error ? error.message : String(error) },
545
+ metadata: {
546
+ error: error instanceof Error ? error.message : String(error),
547
+ },
597
548
  });
598
549
  throw error;
599
550
  }
@@ -625,28 +576,25 @@ export const findContact = za({
625
576
  })
626
577
  .optional(),
627
578
  }),
628
- handler: async (ctx, args) => {
629
- const response = await fetch(`${LOOPS_API_BASE_URL}/contacts/find?email=${encodeURIComponent(args.email)}`, {
630
- method: "GET",
631
- headers: {
632
- Authorization: `Bearer ${args.apiKey}`,
633
- "Content-Type": "application/json",
634
- },
635
- });
579
+ handler: async (_ctx, args) => {
580
+ const response = await loopsFetch(args.apiKey, `/contacts/find?email=${encodeURIComponent(args.email)}`, { method: "GET" });
636
581
  if (!response.ok) {
637
582
  if (response.status === 404) {
638
583
  return { success: false, contact: undefined };
639
584
  }
640
585
  const errorText = await response.text();
641
586
  console.error(`Loops API error [${response.status}]:`, errorText);
642
- throw sanitizeError(response.status, errorText);
587
+ throw sanitizeLoopsError(response.status, errorText);
643
588
  }
644
589
  const data = (await response.json());
645
590
  // Handle case where Loops returns an array instead of a single object
646
591
  let contact = Array.isArray(data) ? data[0] : data;
647
592
  // Convert null values to undefined for optional fields (Zod handles undefined but not null in optional())
648
593
  if (contact) {
649
- contact = Object.fromEntries(Object.entries(contact).map(([key, value]) => [key, value === null ? undefined : value]));
594
+ contact = Object.fromEntries(Object.entries(contact).map(([key, value]) => [
595
+ key,
596
+ value === null ? undefined : value,
597
+ ]));
650
598
  }
651
599
  return {
652
600
  success: true,
@@ -668,11 +616,13 @@ export const batchCreateContacts = za({
668
616
  success: z.boolean(),
669
617
  created: z.number().optional(),
670
618
  failed: z.number().optional(),
671
- results: z.array(z.object({
619
+ results: z
620
+ .array(z.object({
672
621
  email: z.string(),
673
622
  success: z.boolean(),
674
623
  error: z.string().optional(),
675
- })).optional(),
624
+ }))
625
+ .optional(),
676
626
  }),
677
627
  handler: async (ctx, args) => {
678
628
  let created = 0;
@@ -682,7 +632,7 @@ export const batchCreateContacts = za({
682
632
  for (const contact of args.contacts) {
683
633
  try {
684
634
  // Use the addContact function which handles create/update logic
685
- const result = await ctx.runAction((internal.lib).addContact, {
635
+ const result = await ctx.runAction(internalLib.addContact, {
686
636
  apiKey: args.apiKey,
687
637
  contact,
688
638
  });
@@ -695,7 +645,7 @@ export const batchCreateContacts = za({
695
645
  results.push({
696
646
  email: contact.email,
697
647
  success: false,
698
- error: "Unknown error"
648
+ error: "Unknown error",
699
649
  });
700
650
  }
701
651
  }
@@ -729,20 +679,16 @@ export const unsubscribeContact = za({
729
679
  success: z.boolean(),
730
680
  }),
731
681
  handler: async (ctx, args) => {
732
- const response = await fetch(`${LOOPS_API_BASE_URL}/contacts/unsubscribe`, {
682
+ const response = await loopsFetch(args.apiKey, "/contacts/unsubscribe", {
733
683
  method: "POST",
734
- headers: {
735
- Authorization: `Bearer ${args.apiKey}`,
736
- "Content-Type": "application/json",
737
- },
738
- body: JSON.stringify({ email: args.email }),
684
+ json: { email: args.email },
739
685
  });
740
686
  if (!response.ok) {
741
687
  const errorText = await response.text();
742
688
  console.error(`Loops API error [${response.status}]:`, errorText);
743
- throw sanitizeError(response.status, errorText);
689
+ throw sanitizeLoopsError(response.status, errorText);
744
690
  }
745
- await ctx.runMutation((internal.lib).storeContact, {
691
+ await ctx.runMutation(internalLib.storeContact, {
746
692
  email: args.email,
747
693
  subscribed: false,
748
694
  });
@@ -762,20 +708,16 @@ export const resubscribeContact = za({
762
708
  success: z.boolean(),
763
709
  }),
764
710
  handler: async (ctx, args) => {
765
- const response = await fetch(`${LOOPS_API_BASE_URL}/contacts/resubscribe`, {
711
+ const response = await loopsFetch(args.apiKey, "/contacts/resubscribe", {
766
712
  method: "POST",
767
- headers: {
768
- Authorization: `Bearer ${args.apiKey}`,
769
- "Content-Type": "application/json",
770
- },
771
- body: JSON.stringify({ email: args.email }),
713
+ json: { email: args.email },
772
714
  });
773
715
  if (!response.ok) {
774
716
  const errorText = await response.text();
775
717
  console.error(`Loops API error [${response.status}]:`, errorText);
776
- throw sanitizeError(response.status, errorText);
718
+ throw sanitizeLoopsError(response.status, errorText);
777
719
  }
778
- await ctx.runMutation((internal.lib).storeContact, {
720
+ await ctx.runMutation(internalLib.storeContact, {
779
721
  email: args.email,
780
722
  subscribed: true,
781
723
  });
@@ -791,11 +733,13 @@ export const detectRecipientSpam = zq({
791
733
  timeWindowMs: z.number().default(3600000),
792
734
  maxEmailsPerRecipient: z.number().default(10),
793
735
  }),
794
- returns: z.array(z.object({
736
+ returns: z.array(z
737
+ .object({
795
738
  email: z.string(),
796
739
  count: z.number(),
797
740
  timeWindowMs: z.number(),
798
- })),
741
+ })
742
+ .catchall(z.any())),
799
743
  handler: async (ctx, args) => {
800
744
  const cutoffTime = Date.now() - args.timeWindowMs;
801
745
  const operations = await ctx.db
@@ -867,14 +811,16 @@ export const getEmailStats = zq({
867
811
  args: z.object({
868
812
  timeWindowMs: z.number().default(86400000),
869
813
  }),
870
- returns: z.object({
814
+ returns: z
815
+ .object({
871
816
  totalOperations: z.number(),
872
817
  successfulOperations: z.number(),
873
818
  failedOperations: z.number(),
874
819
  operationsByType: z.record(z.string(), z.number()),
875
820
  uniqueRecipients: z.number(),
876
821
  uniqueActors: z.number(),
877
- }),
822
+ })
823
+ .catchall(z.any()),
878
824
  handler: async (ctx, args) => {
879
825
  const cutoffTime = Date.now() - args.timeWindowMs;
880
826
  const operations = await ctx.db
@@ -937,7 +883,7 @@ export const detectRapidFirePatterns = zq({
937
883
  if (!emailGroups.has(op.email)) {
938
884
  emailGroups.set(op.email, []);
939
885
  }
940
- emailGroups.get(op.email).push(op);
886
+ emailGroups.get(op.email)?.push(op);
941
887
  }
942
888
  }
943
889
  for (const [email, ops] of emailGroups.entries()) {
@@ -965,7 +911,7 @@ export const detectRapidFirePatterns = zq({
965
911
  if (!actorGroups.has(op.actorId)) {
966
912
  actorGroups.set(op.actorId, []);
967
913
  }
968
- actorGroups.get(op.actorId).push(op);
914
+ actorGroups.get(op.actorId)?.push(op);
969
915
  }
970
916
  }
971
917
  for (const [actorId, ops] of actorGroups.entries()) {
@@ -1000,13 +946,15 @@ export const checkRecipientRateLimit = zq({
1000
946
  timeWindowMs: z.number(),
1001
947
  maxEmails: z.number(),
1002
948
  }),
1003
- returns: z.object({
949
+ returns: z
950
+ .object({
1004
951
  allowed: z.boolean(),
1005
952
  count: z.number(),
1006
953
  limit: z.number(),
1007
954
  timeWindowMs: z.number(),
1008
955
  retryAfter: z.number().optional(),
1009
- }),
956
+ })
957
+ .catchall(z.any()),
1010
958
  handler: async (ctx, args) => {
1011
959
  const cutoffTime = Date.now() - args.timeWindowMs;
1012
960
  const operations = await ctx.db
@@ -1,3 +1,68 @@
1
- declare const _default: any;
1
+ declare const _default: import("convex/server").SchemaDefinition<{
2
+ contacts: import("convex/server").TableDefinition<import("convex/values").VObject<{
3
+ firstName?: string | undefined;
4
+ lastName?: string | undefined;
5
+ userId?: string | undefined;
6
+ source?: string | undefined;
7
+ subscribed?: boolean | undefined;
8
+ userGroup?: string | undefined;
9
+ loopsContactId?: string | undefined;
10
+ email: string;
11
+ createdAt: number;
12
+ updatedAt: number;
13
+ }, import("zodvex").ConvexValidatorFromZodFieldsAuto<{
14
+ email: import("zod").ZodString;
15
+ firstName: import("zod").ZodOptional<import("zod").ZodString>;
16
+ lastName: import("zod").ZodOptional<import("zod").ZodString>;
17
+ userId: import("zod").ZodOptional<import("zod").ZodString>;
18
+ source: import("zod").ZodOptional<import("zod").ZodString>;
19
+ subscribed: import("zod").ZodDefault<import("zod").ZodBoolean>;
20
+ userGroup: import("zod").ZodOptional<import("zod").ZodString>;
21
+ loopsContactId: import("zod").ZodOptional<import("zod").ZodString>;
22
+ createdAt: import("zod").ZodNumber;
23
+ updatedAt: import("zod").ZodNumber;
24
+ }>, "required", "email" | "firstName" | "lastName" | "userId" | "source" | "subscribed" | "userGroup" | "loopsContactId" | "createdAt" | "updatedAt">, {
25
+ email: ["email", "_creationTime"];
26
+ userId: ["userId", "_creationTime"];
27
+ userGroup: ["userGroup", "_creationTime"];
28
+ source: ["source", "_creationTime"];
29
+ subscribed: ["subscribed", "_creationTime"];
30
+ }, {}, {}>;
31
+ emailOperations: import("convex/server").TableDefinition<import("convex/values").VObject<{
32
+ actorId?: string | undefined;
33
+ transactionalId?: string | undefined;
34
+ campaignId?: string | undefined;
35
+ loopId?: string | undefined;
36
+ eventName?: string | undefined;
37
+ messageId?: string | undefined;
38
+ metadata?: Record<string, any> | undefined;
39
+ email: string;
40
+ success: boolean;
41
+ operationType: "transactional" | "event" | "campaign" | "loop";
42
+ timestamp: number;
43
+ }, import("zodvex").ConvexValidatorFromZodFieldsAuto<{
44
+ operationType: import("zod").ZodEnum<{
45
+ transactional: "transactional";
46
+ event: "event";
47
+ campaign: "campaign";
48
+ loop: "loop";
49
+ }>;
50
+ email: import("zod").ZodString;
51
+ actorId: import("zod").ZodOptional<import("zod").ZodString>;
52
+ transactionalId: import("zod").ZodOptional<import("zod").ZodString>;
53
+ campaignId: import("zod").ZodOptional<import("zod").ZodString>;
54
+ loopId: import("zod").ZodOptional<import("zod").ZodString>;
55
+ eventName: import("zod").ZodOptional<import("zod").ZodString>;
56
+ timestamp: import("zod").ZodNumber;
57
+ success: import("zod").ZodBoolean;
58
+ messageId: import("zod").ZodOptional<import("zod").ZodString>;
59
+ metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
60
+ }>, "required", "email" | "success" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "metadata" | `metadata.${string}`>, {
61
+ email: ["email", "timestamp", "_creationTime"];
62
+ actorId: ["actorId", "timestamp", "_creationTime"];
63
+ operationType: ["operationType", "timestamp", "_creationTime"];
64
+ timestamp: ["timestamp", "_creationTime"];
65
+ }, {}, {}>;
66
+ }, true>;
2
67
  export default _default;
3
68
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":";AAIA,wBAYG"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,wBAYG"}