@devwithbobby/loops 0.1.17 → 0.1.19

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 (49) hide show
  1. package/README.md +46 -23
  2. package/dist/client/index.d.ts +105 -85
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +26 -7
  5. package/dist/component/_generated/api.d.ts +44 -0
  6. package/dist/component/_generated/api.d.ts.map +1 -0
  7. package/{src → dist}/component/_generated/api.js +10 -3
  8. package/dist/component/_generated/component.d.ts +259 -0
  9. package/dist/component/_generated/component.d.ts.map +1 -0
  10. package/dist/component/_generated/component.js +9 -0
  11. package/dist/component/_generated/dataModel.d.ts +46 -0
  12. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  13. package/dist/component/_generated/dataModel.js +10 -0
  14. package/{src → dist}/component/_generated/server.d.ts +10 -38
  15. package/dist/component/_generated/server.d.ts.map +1 -0
  16. package/{src → dist}/component/_generated/server.js +9 -22
  17. package/dist/component/convex.config.d.ts.map +1 -1
  18. package/dist/component/convex.config.js +0 -22
  19. package/dist/component/helpers.d.ts +1 -1
  20. package/dist/component/helpers.d.ts.map +1 -1
  21. package/dist/component/helpers.js +1 -2
  22. package/dist/component/http.d.ts.map +1 -1
  23. package/dist/component/http.js +0 -1
  24. package/dist/component/lib.d.ts +7 -0
  25. package/dist/component/lib.d.ts.map +1 -1
  26. package/dist/component/lib.js +62 -20
  27. package/dist/component/schema.d.ts +2 -2
  28. package/dist/component/tables/contacts.d.ts.map +1 -1
  29. package/dist/component/tables/emailOperations.d.ts +4 -4
  30. package/dist/component/tables/emailOperations.d.ts.map +1 -1
  31. package/dist/test.d.ts +83 -0
  32. package/dist/test.d.ts.map +1 -0
  33. package/dist/test.js +16 -0
  34. package/dist/utils.d.ts +6 -6
  35. package/package.json +15 -9
  36. package/src/client/index.ts +31 -14
  37. package/src/component/_generated/api.ts +60 -0
  38. package/src/component/_generated/component.ts +323 -0
  39. package/src/component/_generated/{dataModel.d.ts → dataModel.ts} +1 -1
  40. package/src/component/_generated/server.ts +161 -0
  41. package/src/component/convex.config.ts +0 -27
  42. package/src/component/helpers.ts +2 -2
  43. package/src/component/http.ts +0 -4
  44. package/src/component/lib.ts +69 -20
  45. package/src/test.ts +27 -0
  46. package/dist/client/types.d.ts +0 -24
  47. package/dist/client/types.d.ts.map +0 -1
  48. package/dist/client/types.js +0 -0
  49. package/src/component/_generated/api.d.ts +0 -47
package/README.md CHANGED
@@ -6,13 +6,13 @@ A Convex component for integrating with [Loops.so](https://loops.so) email marke
6
6
 
7
7
  ## Features
8
8
 
9
- - **Contact Management** - Create, update, find, and delete contacts
10
- - **Transactional Emails** - Send one-off emails with templates
11
- - **Events** - Trigger email workflows based on events
12
- - **Loops** - Trigger automated email sequences
13
- - **Monitoring** - Track all email operations with spam detection
14
- - **Rate Limiting** - Built-in rate limiting queries for abuse prevention
15
- - **Type-Safe** - Full TypeScript support with Zod validation
9
+ - **Contact Management** - Create, update, find, list, and delete contacts
10
+ - **Transactional Emails** - Send one-off emails with templates
11
+ - **Events** - Trigger email workflows based on events
12
+ - **Loops** - Trigger automated email sequences
13
+ - **Monitoring** - Track all email operations with spam detection
14
+ - **Rate Limiting** - Built-in rate limiting queries for abuse prevention
15
+ - **Type-Safe** - Full TypeScript support with Zod validation
16
16
 
17
17
  ## Installation
18
18
 
@@ -40,17 +40,17 @@ export default app;
40
40
 
41
41
  ### 2. Set Up Environment Variables
42
42
 
43
- **⚠️ IMPORTANT: Set your Loops API key before using the component.**
43
+ **IMPORTANT: Set your Loops API key before using the component.**
44
44
 
45
45
  ```bash
46
46
  npx convex env set LOOPS_API_KEY "your-loops-api-key-here"
47
47
  ```
48
48
 
49
49
  **Or via Convex Dashboard:**
50
- 1. Go to Settings Environment Variables
50
+ 1. Go to Settings -> Environment Variables
51
51
  2. Add `LOOPS_API_KEY` with your Loops.so API key
52
52
 
53
- Get your API key from [Loops.so Dashboard](https://app.loops.so/settings/api).
53
+ Get your API key from [Loops.so Dashboard](https://app.loops.so/settings?page=api).
54
54
 
55
55
  ### 3. Use the Component
56
56
 
@@ -135,6 +135,27 @@ await loops.updateContact(ctx, "user@example.com", {
135
135
  const contact = await loops.findContact(ctx, "user@example.com");
136
136
  ```
137
137
 
138
+ #### List Contacts
139
+
140
+ List contacts with pagination and optional filtering.
141
+
142
+ ```typescript
143
+ // Simple list with default limit (100)
144
+ const result = await loops.listContacts(ctx);
145
+
146
+ // List with filters and pagination
147
+ const result = await loops.listContacts(ctx, {
148
+ userGroup: "premium",
149
+ subscribed: true,
150
+ limit: 20,
151
+ offset: 0
152
+ });
153
+
154
+ console.log(result.contacts); // Array of contacts
155
+ console.log(result.total); // Total count matching filters
156
+ console.log(result.hasMore); // Boolean indicating if more pages exist
157
+ ```
158
+
138
159
  #### Delete Contact
139
160
 
140
161
  ```typescript
@@ -335,11 +356,12 @@ export const {
335
356
  sendEvent,
336
357
  triggerLoop,
337
358
  countContacts,
359
+ listContacts,
338
360
  // ... all other functions
339
361
  } = loops.api();
340
362
  ```
341
363
 
342
- **⚠️ Security Warning:** The `api()` helper exports functions without authentication. Always wrap these functions with auth checks in production:
364
+ **Security Warning:** The `api()` helper exports functions without authentication. Always wrap these functions with auth checks in production:
343
365
 
344
366
  ```typescript
345
367
  export const addContact = action({
@@ -392,12 +414,12 @@ npx convex env set LOOPS_API_KEY "your-api-key"
392
414
 
393
415
  **Via Dashboard:**
394
416
  1. Go to your Convex Dashboard
395
- 2. Navigate to Settings Environment Variables
417
+ 2. Navigate to Settings -> Environment Variables
396
418
  3. Add `LOOPS_API_KEY` with your Loops.so API key value
397
419
 
398
- Get your API key from [Loops.so Dashboard](https://app.loops.so/settings/api).
420
+ Get your API key from [Loops.so Dashboard](https://app.loops.so/settings?page=api).
399
421
 
400
- ⚠️ **Never** pass the API key directly in code or via function options in production. Always use environment variables.
422
+ **Never** pass the API key directly in code or via function options in production. Always use environment variables.
401
423
 
402
424
  ## Monitoring & Rate Limiting
403
425
 
@@ -458,15 +480,16 @@ example/ # Example app
458
480
 
459
481
  This component implements the following Loops.so API endpoints:
460
482
 
461
- - Create/Update Contact
462
- - Delete Contact
463
- - Find Contact
464
- - Batch Create Contacts
465
- - Unsubscribe/Resubscribe Contact
466
- - Count Contacts (custom implementation)
467
- - Send Transactional Email
468
- - Send Event
469
- - Trigger Loop
483
+ - Create/Update Contact
484
+ - Delete Contact
485
+ - Find Contact
486
+ - Batch Create Contacts
487
+ - Unsubscribe/Resubscribe Contact
488
+ - Count Contacts (custom implementation)
489
+ - List Contacts (custom implementation)
490
+ - Send Transactional Email
491
+ - Send Event
492
+ - Trigger Loop
470
493
 
471
494
  ## Contributing
472
495
 
@@ -1,6 +1,6 @@
1
- import type { Mounts } from "../component/_generated/api";
2
- import type { RunActionCtx, RunQueryCtx, UseApi } from "../types";
3
- export type LoopsComponent = UseApi<Mounts>;
1
+ import type { ComponentApi } from "../component/_generated/component.js";
2
+ import type { RunActionCtx, RunQueryCtx } from "../types";
3
+ export type LoopsComponent = ComponentApi;
4
4
  export interface ContactData {
5
5
  email: string;
6
6
  firstName?: string;
@@ -25,16 +25,21 @@ export declare class Loops {
25
25
  apiKey?: string;
26
26
  };
27
27
  private readonly lib;
28
+ private _apiKey?;
28
29
  constructor(component: LoopsComponent, options?: {
29
30
  apiKey?: string;
30
31
  });
31
- private readonly apiKey;
32
+ /**
33
+ * Get the API key, checking environment at call time (not constructor time).
34
+ * This allows the Loops client to be instantiated at module load time.
35
+ */
36
+ private get apiKey();
32
37
  /**
33
38
  * Add or update a contact in Loops
34
39
  */
35
40
  addContact(ctx: RunActionCtx, contact: ContactData): Promise<{
41
+ id?: string;
36
42
  success: boolean;
37
- id?: string | undefined;
38
43
  }>;
39
44
  /**
40
45
  * Update an existing contact in Loops
@@ -48,8 +53,8 @@ export declare class Loops {
48
53
  * Send a transactional email using a transactional ID
49
54
  */
50
55
  sendTransactional(ctx: RunActionCtx, options: TransactionalEmailOptions): Promise<{
56
+ messageId?: string;
51
57
  success: boolean;
52
- messageId?: string | undefined;
53
58
  }>;
54
59
  /**
55
60
  * Send an event to Loops to trigger email workflows
@@ -62,32 +67,32 @@ export declare class Loops {
62
67
  * Retrieves contact information from Loops
63
68
  */
64
69
  findContact(ctx: RunActionCtx, email: string): Promise<{
65
- success: boolean;
66
70
  contact?: {
67
- id?: string | null | undefined;
68
- email?: string | null | undefined;
69
- firstName?: string | null | undefined;
70
- lastName?: string | null | undefined;
71
- source?: string | null | undefined;
72
- subscribed?: boolean | null | undefined;
73
- userGroup?: string | null | undefined;
74
- userId?: string | null | undefined;
75
- createdAt?: string | null | undefined;
76
- } | undefined;
71
+ createdAt?: string | null;
72
+ email?: string | null;
73
+ firstName?: string | null;
74
+ id?: string | null;
75
+ lastName?: string | null;
76
+ source?: string | null;
77
+ subscribed?: boolean | null;
78
+ userGroup?: string | null;
79
+ userId?: string | null;
80
+ };
81
+ success: boolean;
77
82
  }>;
78
83
  /**
79
84
  * Batch create contacts
80
85
  * Create multiple contacts in a single API call
81
86
  */
82
87
  batchCreateContacts(ctx: RunActionCtx, contacts: ContactData[]): Promise<{
83
- success: boolean;
84
- created?: number | undefined;
85
- failed?: number | undefined;
86
- results?: {
88
+ created?: number;
89
+ failed?: number;
90
+ results?: Array<{
87
91
  email: string;
92
+ error?: string;
88
93
  success: boolean;
89
- error?: string | undefined;
90
- }[] | undefined;
94
+ }>;
95
+ success: boolean;
91
96
  }>;
92
97
  /**
93
98
  * Unsubscribe a contact
@@ -125,23 +130,23 @@ export declare class Loops {
125
130
  limit?: number;
126
131
  offset?: number;
127
132
  }): Promise<{
128
- contacts: {
133
+ contacts: Array<{
129
134
  _id: string;
135
+ createdAt: number;
130
136
  email: string;
137
+ firstName?: string;
138
+ lastName?: string;
139
+ loopsContactId?: string;
140
+ source?: string;
131
141
  subscribed: boolean;
132
- createdAt: number;
133
142
  updatedAt: number;
134
- firstName?: string | undefined;
135
- lastName?: string | undefined;
136
- userId?: string | undefined;
137
- source?: string | undefined;
138
- userGroup?: string | undefined;
139
- loopsContactId?: string | undefined;
140
- }[];
141
- total: number;
143
+ userGroup?: string;
144
+ userId?: string;
145
+ }>;
146
+ hasMore: boolean;
142
147
  limit: number;
143
148
  offset: number;
144
- hasMore: boolean;
149
+ total: number;
145
150
  }>;
146
151
  /**
147
152
  * Detect spam patterns: emails sent to the same recipient too frequently
@@ -150,9 +155,8 @@ export declare class Loops {
150
155
  timeWindowMs?: number;
151
156
  maxEmailsPerRecipient?: number;
152
157
  }): Promise<{
153
- [x: string]: any;
154
- email: string;
155
158
  count: number;
159
+ email: string;
156
160
  timeWindowMs: number;
157
161
  }[]>;
158
162
  /**
@@ -172,15 +176,12 @@ export declare class Loops {
172
176
  getEmailStats(ctx: RunQueryCtx, options?: {
173
177
  timeWindowMs?: number;
174
178
  }): Promise<{
175
- [x: string]: any;
176
- totalOperations: number;
177
- successfulOperations: number;
178
179
  failedOperations: number;
179
- operationsByType: {
180
- [x: string]: number;
181
- };
182
- uniqueRecipients: number;
180
+ operationsByType: Record<string, number>;
181
+ successfulOperations: number;
182
+ totalOperations: number;
183
183
  uniqueActors: number;
184
+ uniqueRecipients: number;
184
185
  }>;
185
186
  /**
186
187
  * Detect rapid-fire email sending patterns
@@ -189,12 +190,12 @@ export declare class Loops {
189
190
  timeWindowMs?: number;
190
191
  minEmailsInWindow?: number;
191
192
  }): Promise<{
193
+ actorId?: string;
192
194
  count: number;
193
- timeWindowMs: number;
195
+ email?: string;
194
196
  firstTimestamp: number;
195
197
  lastTimestamp: number;
196
- email?: string | undefined;
197
- actorId?: string | undefined;
198
+ timeWindowMs: number;
198
199
  }[]>;
199
200
  /**
200
201
  * Check if an email can be sent to a recipient based on rate limits
@@ -204,12 +205,11 @@ export declare class Loops {
204
205
  timeWindowMs: number;
205
206
  maxEmails: number;
206
207
  }): Promise<{
207
- [x: string]: any;
208
208
  allowed: boolean;
209
209
  count: number;
210
210
  limit: number;
211
+ retryAfter?: number;
211
212
  timeWindowMs: number;
212
- retryAfter?: number | undefined;
213
213
  }>;
214
214
  /**
215
215
  * Check if an actor/user can send more emails based on rate limits
@@ -222,8 +222,8 @@ export declare class Loops {
222
222
  allowed: boolean;
223
223
  count: number;
224
224
  limit: number;
225
+ retryAfter?: number;
225
226
  timeWindowMs: number;
226
- retryAfter?: number | undefined;
227
227
  }>;
228
228
  /**
229
229
  * Check global email sending rate limit
@@ -260,7 +260,7 @@ export declare class Loops {
260
260
  eventName?: string;
261
261
  }): Promise<{
262
262
  success: boolean;
263
- warning?: string | undefined;
263
+ warning?: string;
264
264
  }>;
265
265
  /**
266
266
  * For easy re-exporting.
@@ -279,8 +279,8 @@ export declare class Loops {
279
279
  userGroup?: string | undefined;
280
280
  email: string;
281
281
  }, Promise<{
282
+ id?: string;
282
283
  success: boolean;
283
- id?: string | undefined;
284
284
  }>>;
285
285
  updateContact: import("convex/server").RegisteredAction<"public", {
286
286
  firstName?: string | undefined;
@@ -299,8 +299,8 @@ export declare class Loops {
299
299
  email: string;
300
300
  transactionalId: string;
301
301
  }, Promise<{
302
+ messageId?: string;
302
303
  success: boolean;
303
- messageId?: string | undefined;
304
304
  }>>;
305
305
  sendEvent: import("convex/server").RegisteredAction<"public", {
306
306
  eventProperties?: any;
@@ -320,23 +320,23 @@ export declare class Loops {
320
320
  loopId: string;
321
321
  }, Promise<{
322
322
  success: boolean;
323
- warning?: string | undefined;
323
+ warning?: string;
324
324
  }>>;
325
325
  findContact: import("convex/server").RegisteredAction<"public", {
326
326
  email: string;
327
327
  }, Promise<{
328
- success: boolean;
329
328
  contact?: {
330
- id?: string | null | undefined;
331
- email?: string | null | undefined;
332
- firstName?: string | null | undefined;
333
- lastName?: string | null | undefined;
334
- source?: string | null | undefined;
335
- subscribed?: boolean | null | undefined;
336
- userGroup?: string | null | undefined;
337
- userId?: string | null | undefined;
338
- createdAt?: string | null | undefined;
339
- } | undefined;
329
+ createdAt?: string | null;
330
+ email?: string | null;
331
+ firstName?: string | null;
332
+ id?: string | null;
333
+ lastName?: string | null;
334
+ source?: string | null;
335
+ subscribed?: boolean | null;
336
+ userGroup?: string | null;
337
+ userId?: string | null;
338
+ };
339
+ success: boolean;
340
340
  }>>;
341
341
  batchCreateContacts: import("convex/server").RegisteredAction<"public", {
342
342
  contacts: {
@@ -349,14 +349,14 @@ export declare class Loops {
349
349
  email: string;
350
350
  }[];
351
351
  }, Promise<{
352
- success: boolean;
353
- created?: number | undefined;
354
- failed?: number | undefined;
355
- results?: {
352
+ created?: number;
353
+ failed?: number;
354
+ results?: Array<{
356
355
  email: string;
356
+ error?: string;
357
357
  success: boolean;
358
- error?: string | undefined;
359
- }[] | undefined;
358
+ }>;
359
+ success: boolean;
360
360
  }>>;
361
361
  unsubscribeContact: import("convex/server").RegisteredAction<"public", {
362
362
  email: string;
@@ -373,13 +373,37 @@ export declare class Loops {
373
373
  subscribed?: boolean | undefined;
374
374
  userGroup?: string | undefined;
375
375
  }, Promise<number>>;
376
+ listContacts: import("convex/server").RegisteredQuery<"public", {
377
+ source?: string | undefined;
378
+ subscribed?: boolean | undefined;
379
+ userGroup?: string | undefined;
380
+ limit?: number | undefined;
381
+ offset?: number | undefined;
382
+ }, Promise<{
383
+ contacts: Array<{
384
+ _id: string;
385
+ createdAt: number;
386
+ email: string;
387
+ firstName?: string;
388
+ lastName?: string;
389
+ loopsContactId?: string;
390
+ source?: string;
391
+ subscribed: boolean;
392
+ updatedAt: number;
393
+ userGroup?: string;
394
+ userId?: string;
395
+ }>;
396
+ hasMore: boolean;
397
+ limit: number;
398
+ offset: number;
399
+ total: number;
400
+ }>>;
376
401
  detectRecipientSpam: import("convex/server").RegisteredQuery<"public", {
377
402
  timeWindowMs?: number | undefined;
378
403
  maxEmailsPerRecipient?: number | undefined;
379
404
  }, Promise<{
380
- [x: string]: any;
381
- email: string;
382
405
  count: number;
406
+ email: string;
383
407
  timeWindowMs: number;
384
408
  }[]>>;
385
409
  detectActorSpam: import("convex/server").RegisteredQuery<"public", {
@@ -393,38 +417,34 @@ export declare class Loops {
393
417
  getEmailStats: import("convex/server").RegisteredQuery<"public", {
394
418
  timeWindowMs?: number | undefined;
395
419
  }, Promise<{
396
- [x: string]: any;
397
- totalOperations: number;
398
- successfulOperations: number;
399
420
  failedOperations: number;
400
- operationsByType: {
401
- [x: string]: number;
402
- };
403
- uniqueRecipients: number;
421
+ operationsByType: Record<string, number>;
422
+ successfulOperations: number;
423
+ totalOperations: number;
404
424
  uniqueActors: number;
425
+ uniqueRecipients: number;
405
426
  }>>;
406
427
  detectRapidFirePatterns: import("convex/server").RegisteredQuery<"public", {
407
428
  timeWindowMs?: number | undefined;
408
429
  minEmailsInWindow?: number | undefined;
409
430
  }, Promise<{
431
+ actorId?: string;
410
432
  count: number;
411
- timeWindowMs: number;
433
+ email?: string;
412
434
  firstTimestamp: number;
413
435
  lastTimestamp: number;
414
- email?: string | undefined;
415
- actorId?: string | undefined;
436
+ timeWindowMs: number;
416
437
  }[]>>;
417
438
  checkRecipientRateLimit: import("convex/server").RegisteredQuery<"public", {
418
439
  email: string;
419
440
  timeWindowMs: number;
420
441
  maxEmails: number;
421
442
  }, Promise<{
422
- [x: string]: any;
423
443
  allowed: boolean;
424
444
  count: number;
425
445
  limit: number;
446
+ retryAfter?: number;
426
447
  timeWindowMs: number;
427
- retryAfter?: number | undefined;
428
448
  }>>;
429
449
  checkActorRateLimit: import("convex/server").RegisteredQuery<"public", {
430
450
  actorId: string;
@@ -434,8 +454,8 @@ export declare class Loops {
434
454
  allowed: boolean;
435
455
  count: number;
436
456
  limit: number;
457
+ retryAfter?: number;
437
458
  timeWindowMs: number;
438
- retryAfter?: number | undefined;
439
459
  }>>;
440
460
  checkGlobalRateLimit: import("convex/server").RegisteredQuery<"public", {
441
461
  timeWindowMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { v } from "convex/values";
3
3
  export class Loops {
4
4
  options;
5
5
  lib;
6
+ _apiKey;
6
7
  constructor(component, options) {
7
8
  if (!component) {
8
9
  throw new Error("Loops component reference is required. " +
@@ -17,18 +18,24 @@ export class Loops {
17
18
  }
18
19
  this.lib = component.lib;
19
20
  this.options = options;
20
- const apiKey = options?.apiKey ?? process.env.LOOPS_API_KEY;
21
- if (!apiKey) {
22
- throw new Error("Loops API key is required. Set LOOPS_API_KEY in your Convex environment variables.");
23
- }
21
+ this._apiKey = options?.apiKey;
24
22
  if (options?.apiKey) {
25
23
  console.warn("API key passed directly via options. " +
26
24
  "For security, use LOOPS_API_KEY environment variable instead. " +
27
- "See ENV_SETUP.md for details.");
25
+ "See README.md for details.");
26
+ }
27
+ }
28
+ /**
29
+ * Get the API key, checking environment at call time (not constructor time).
30
+ * This allows the Loops client to be instantiated at module load time.
31
+ */
32
+ get apiKey() {
33
+ const key = this._apiKey ?? process.env.LOOPS_API_KEY;
34
+ if (!key) {
35
+ throw new Error("Loops API key is required. Set LOOPS_API_KEY in your Convex environment variables.");
28
36
  }
29
- this.apiKey = apiKey;
37
+ return key;
30
38
  }
31
- apiKey;
32
39
  /**
33
40
  * Add or update a contact in Loops
34
41
  */
@@ -333,6 +340,18 @@ export class Loops {
333
340
  return await this.countContacts(ctx, args);
334
341
  },
335
342
  }),
343
+ listContacts: queryGeneric({
344
+ args: {
345
+ userGroup: v.optional(v.string()),
346
+ source: v.optional(v.string()),
347
+ subscribed: v.optional(v.boolean()),
348
+ limit: v.optional(v.number()),
349
+ offset: v.optional(v.number()),
350
+ },
351
+ handler: async (ctx, args) => {
352
+ return await this.listContacts(ctx, args);
353
+ },
354
+ }),
336
355
  detectRecipientSpam: queryGeneric({
337
356
  args: {
338
357
  timeWindowMs: v.optional(v.number()),
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Generated `api` utility.
3
+ *
4
+ * THIS CODE IS AUTOMATICALLY GENERATED.
5
+ *
6
+ * To regenerate, run `npx convex dev`.
7
+ * @module
8
+ */
9
+ import type * as helpers from "../helpers.js";
10
+ import type * as http from "../http.js";
11
+ import type * as lib from "../lib.js";
12
+ import type * as tables_contacts from "../tables/contacts.js";
13
+ import type * as tables_emailOperations from "../tables/emailOperations.js";
14
+ import type * as validators from "../validators.js";
15
+ import type { ApiFromModules, FilterApi, FunctionReference } from "convex/server";
16
+ declare const fullApi: ApiFromModules<{
17
+ helpers: typeof helpers;
18
+ http: typeof http;
19
+ lib: typeof lib;
20
+ "tables/contacts": typeof tables_contacts;
21
+ "tables/emailOperations": typeof tables_emailOperations;
22
+ validators: typeof validators;
23
+ }>;
24
+ /**
25
+ * A utility for referencing Convex functions in your app's public API.
26
+ *
27
+ * Usage:
28
+ * ```js
29
+ * const myFunctionReference = api.myModule.myFunction;
30
+ * ```
31
+ */
32
+ export declare const api: FilterApi<typeof fullApi, FunctionReference<any, "public">>;
33
+ /**
34
+ * A utility for referencing Convex functions in your app's internal API.
35
+ *
36
+ * Usage:
37
+ * ```js
38
+ * const myFunctionReference = internal.myModule.myFunction;
39
+ * ```
40
+ */
41
+ export declare const internal: FilterApi<typeof fullApi, FunctionReference<any, "internal">>;
42
+ export declare const components: {};
43
+ export {};
44
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,KAAK,GAAG,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,KAAK,eAAe,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,KAAK,sBAAsB,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,QAAA,MAAM,OAAO,EAAE,cAAc,CAAC;IAC5B,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,GAAG,EAAE,OAAO,GAAG,CAAC;IAChB,iBAAiB,EAAE,OAAO,eAAe,CAAC;IAC1C,wBAAwB,EAAE,OAAO,sBAAsB,CAAC;IACxD,UAAU,EAAE,OAAO,UAAU,CAAC;CAC/B,CAAiB,CAAC;AAEnB;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,EAAE,SAAS,CACzB,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CACjB,CAAC;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,CAC9B,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CACnB,CAAC;AAElB,eAAO,MAAM,UAAU,EAAqC,EAAE,CAAC"}
@@ -7,11 +7,10 @@
7
7
  * To regenerate, run `npx convex dev`.
8
8
  * @module
9
9
  */
10
-
11
10
  import { anyApi, componentsGeneric } from "convex/server";
12
-
11
+ const fullApi = anyApi;
13
12
  /**
14
- * A utility for referencing Convex functions in your app's API.
13
+ * A utility for referencing Convex functions in your app's public API.
15
14
  *
16
15
  * Usage:
17
16
  * ```js
@@ -19,5 +18,13 @@ import { anyApi, componentsGeneric } from "convex/server";
19
18
  * ```
20
19
  */
21
20
  export const api = anyApi;
21
+ /**
22
+ * A utility for referencing Convex functions in your app's internal API.
23
+ *
24
+ * Usage:
25
+ * ```js
26
+ * const myFunctionReference = internal.myModule.myFunction;
27
+ * ```
28
+ */
22
29
  export const internal = anyApi;
23
30
  export const components = componentsGeneric();