@devwithbobby/loops 0.1.11 → 0.1.13
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 +1 -24
- package/dist/client/index.d.ts +122 -52
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +15 -26
- package/dist/component/convex.config.d.ts +1 -1
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/convex.config.js +0 -1
- package/dist/component/lib.d.ts +237 -29
- package/dist/component/lib.d.ts.map +1 -1
- package/dist/component/lib.js +47 -133
- package/dist/component/schema.d.ts +66 -1
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/tables/contacts.d.ts +123 -1
- package/dist/component/tables/contacts.d.ts.map +1 -1
- package/dist/component/tables/emailOperations.d.ts +151 -1
- package/dist/component/tables/emailOperations.d.ts.map +1 -1
- package/dist/component/tables/emailOperations.js +1 -6
- package/dist/component/validators.d.ts +20 -3
- package/dist/component/validators.d.ts.map +1 -1
- package/dist/utils.d.ts +186 -3
- package/dist/utils.d.ts.map +1 -1
- package/package.json +101 -101
- package/src/client/index.ts +56 -57
- package/src/component/convex.config.ts +0 -1
- package/src/component/lib.ts +146 -219
- package/src/component/tables/contacts.ts +0 -1
- package/src/component/tables/emailOperations.ts +1 -7
- package/src/component/validators.ts +0 -1
package/src/client/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ export class Loops {
|
|
|
32
32
|
public readonly options?: {
|
|
33
33
|
apiKey?: string;
|
|
34
34
|
};
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
constructor(
|
|
37
37
|
component: LoopsComponent,
|
|
38
38
|
options?: {
|
|
@@ -43,26 +43,26 @@ export class Loops {
|
|
|
43
43
|
throw new Error(
|
|
44
44
|
"Loops component reference is required. " +
|
|
45
45
|
"Make sure the component is mounted in your convex.config.ts and use: " +
|
|
46
|
-
"new Loops(components.loops)"
|
|
46
|
+
"new Loops(components.loops)",
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
if (!component.lib) {
|
|
51
51
|
throw new Error(
|
|
52
52
|
"Invalid component reference. " +
|
|
53
53
|
"The component may not be properly mounted. " +
|
|
54
54
|
"Ensure the component is correctly mounted in convex.config.ts: " +
|
|
55
|
-
"app.use(loops);"
|
|
55
|
+
"app.use(loops);",
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
this.component = component;
|
|
60
60
|
this.options = options;
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
const apiKey = options?.apiKey ?? process.env.LOOPS_API_KEY;
|
|
63
63
|
if (!apiKey) {
|
|
64
64
|
throw new Error(
|
|
65
|
-
"Loops API key is required. Set LOOPS_API_KEY in your Convex environment variables."
|
|
65
|
+
"Loops API key is required. Set LOOPS_API_KEY in your Convex environment variables.",
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -87,7 +87,7 @@ export class Loops {
|
|
|
87
87
|
throw new Error(
|
|
88
88
|
"Loops component is not initialized. " +
|
|
89
89
|
"Make sure to pass components.loops to the Loops constructor: " +
|
|
90
|
-
"new Loops(components.loops)"
|
|
90
|
+
"new Loops(components.loops)",
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
if (!this.component.lib) {
|
|
@@ -95,7 +95,7 @@ export class Loops {
|
|
|
95
95
|
"Invalid component reference. " +
|
|
96
96
|
"The component may not be properly mounted. " +
|
|
97
97
|
"Ensure the component is correctly mounted in convex.config.ts: " +
|
|
98
|
-
"app.use(loops);"
|
|
98
|
+
"app.use(loops);",
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
return ctx.runAction((this.component.lib as any).addContact, {
|
|
@@ -124,7 +124,10 @@ export class Loops {
|
|
|
124
124
|
/**
|
|
125
125
|
* Send a transactional email using a transactional ID
|
|
126
126
|
*/
|
|
127
|
-
async sendTransactional(
|
|
127
|
+
async sendTransactional(
|
|
128
|
+
ctx: RunActionCtx,
|
|
129
|
+
options: TransactionalEmailOptions,
|
|
130
|
+
) {
|
|
128
131
|
return ctx.runAction((this.component.lib as any).sendTransactional, {
|
|
129
132
|
apiKey: this.apiKey,
|
|
130
133
|
...options,
|
|
@@ -198,7 +201,34 @@ export class Loops {
|
|
|
198
201
|
subscribed?: boolean;
|
|
199
202
|
},
|
|
200
203
|
) {
|
|
201
|
-
return ctx.runQuery(
|
|
204
|
+
return ctx.runQuery(
|
|
205
|
+
(this.component.lib as any).countContacts,
|
|
206
|
+
options ?? {},
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* List contacts with pagination and optional filters
|
|
212
|
+
* Returns actual contact data, not just a count
|
|
213
|
+
* This queries the component's local database, not Loops API
|
|
214
|
+
*/
|
|
215
|
+
async listContacts(
|
|
216
|
+
ctx: RunQueryCtx,
|
|
217
|
+
options?: {
|
|
218
|
+
userGroup?: string;
|
|
219
|
+
source?: string;
|
|
220
|
+
subscribed?: boolean;
|
|
221
|
+
limit?: number;
|
|
222
|
+
offset?: number;
|
|
223
|
+
},
|
|
224
|
+
) {
|
|
225
|
+
return ctx.runQuery((this.component.lib as any).listContacts, {
|
|
226
|
+
userGroup: options?.userGroup,
|
|
227
|
+
source: options?.source,
|
|
228
|
+
subscribed: options?.subscribed,
|
|
229
|
+
limit: options?.limit ?? 100,
|
|
230
|
+
offset: options?.offset ?? 0,
|
|
231
|
+
});
|
|
202
232
|
}
|
|
203
233
|
|
|
204
234
|
/**
|
|
@@ -274,7 +304,10 @@ export class Loops {
|
|
|
274
304
|
maxEmails: number;
|
|
275
305
|
},
|
|
276
306
|
) {
|
|
277
|
-
return ctx.runQuery(
|
|
307
|
+
return ctx.runQuery(
|
|
308
|
+
(this.component.lib as any).checkRecipientRateLimit,
|
|
309
|
+
options,
|
|
310
|
+
);
|
|
278
311
|
}
|
|
279
312
|
|
|
280
313
|
/**
|
|
@@ -288,7 +321,10 @@ export class Loops {
|
|
|
288
321
|
maxEmails: number;
|
|
289
322
|
},
|
|
290
323
|
) {
|
|
291
|
-
return ctx.runQuery(
|
|
324
|
+
return ctx.runQuery(
|
|
325
|
+
(this.component.lib as any).checkActorRateLimit,
|
|
326
|
+
options,
|
|
327
|
+
);
|
|
292
328
|
}
|
|
293
329
|
|
|
294
330
|
/**
|
|
@@ -301,7 +337,10 @@ export class Loops {
|
|
|
301
337
|
maxEmails: number;
|
|
302
338
|
},
|
|
303
339
|
) {
|
|
304
|
-
return ctx.runQuery(
|
|
340
|
+
return ctx.runQuery(
|
|
341
|
+
(this.component.lib as any).checkGlobalRateLimit,
|
|
342
|
+
options,
|
|
343
|
+
);
|
|
305
344
|
}
|
|
306
345
|
|
|
307
346
|
/**
|
|
@@ -314,37 +353,14 @@ export class Loops {
|
|
|
314
353
|
});
|
|
315
354
|
}
|
|
316
355
|
|
|
317
|
-
/**
|
|
318
|
-
* Send a campaign to contacts
|
|
319
|
-
* Campaigns are one-time email sends to a segment or list of contacts
|
|
320
|
-
*/
|
|
321
|
-
async sendCampaign(
|
|
322
|
-
ctx: RunActionCtx,
|
|
323
|
-
options: {
|
|
324
|
-
campaignId: string;
|
|
325
|
-
emails?: string[];
|
|
326
|
-
transactionalId?: string;
|
|
327
|
-
dataVariables?: Record<string, any>;
|
|
328
|
-
audienceFilters?: {
|
|
329
|
-
userGroup?: string;
|
|
330
|
-
source?: string;
|
|
331
|
-
};
|
|
332
|
-
},
|
|
333
|
-
) {
|
|
334
|
-
return ctx.runAction((this.component.lib as any).sendCampaign, {
|
|
335
|
-
apiKey: this.apiKey,
|
|
336
|
-
...options,
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
356
|
/**
|
|
341
357
|
* Trigger a loop for a contact
|
|
342
358
|
* Loops are automated email sequences that can be triggered by events
|
|
343
|
-
*
|
|
359
|
+
*
|
|
344
360
|
* Note: Loops.so doesn't have a direct loop trigger endpoint.
|
|
345
361
|
* Loops are triggered through events. Make sure your loop is configured
|
|
346
362
|
* in the Loops dashboard to listen for events.
|
|
347
|
-
*
|
|
363
|
+
*
|
|
348
364
|
* @param options.eventName - Optional event name. If not provided, uses `loop_{loopId}`
|
|
349
365
|
*/
|
|
350
366
|
async triggerLoop(
|
|
@@ -366,7 +382,7 @@ export class Loops {
|
|
|
366
382
|
* For easy re-exporting.
|
|
367
383
|
* Apps can do
|
|
368
384
|
* ```ts
|
|
369
|
-
* export const { addContact, sendTransactional, sendEvent,
|
|
385
|
+
* export const { addContact, sendTransactional, sendEvent, triggerLoop } = loops.api();
|
|
370
386
|
* ```
|
|
371
387
|
*/
|
|
372
388
|
api() {
|
|
@@ -429,23 +445,6 @@ export class Loops {
|
|
|
429
445
|
return await this.deleteContact(ctx, args.email);
|
|
430
446
|
},
|
|
431
447
|
}),
|
|
432
|
-
sendCampaign: actionGeneric({
|
|
433
|
-
args: {
|
|
434
|
-
campaignId: v.string(),
|
|
435
|
-
emails: v.optional(v.array(v.string())),
|
|
436
|
-
transactionalId: v.optional(v.string()),
|
|
437
|
-
dataVariables: v.optional(v.any()),
|
|
438
|
-
audienceFilters: v.optional(
|
|
439
|
-
v.object({
|
|
440
|
-
userGroup: v.optional(v.string()),
|
|
441
|
-
source: v.optional(v.string()),
|
|
442
|
-
}),
|
|
443
|
-
),
|
|
444
|
-
},
|
|
445
|
-
handler: async (ctx, args) => {
|
|
446
|
-
return await this.sendCampaign(ctx, args);
|
|
447
|
-
},
|
|
448
|
-
}),
|
|
449
448
|
triggerLoop: actionGeneric({
|
|
450
449
|
args: {
|
|
451
450
|
loopId: v.string(),
|
|
@@ -13,7 +13,6 @@ const component = defineComponent("loops");
|
|
|
13
13
|
listContacts: api.lib.listContacts,
|
|
14
14
|
sendTransactional: api.lib.sendTransactional,
|
|
15
15
|
sendEvent: api.lib.sendEvent,
|
|
16
|
-
sendCampaign: api.lib.sendCampaign,
|
|
17
16
|
triggerLoop: api.lib.triggerLoop,
|
|
18
17
|
deleteContact: api.lib.deleteContact,
|
|
19
18
|
detectRecipientSpam: api.lib.detectRecipientSpam,
|