@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.
- package/dist/client/index.d.ts +305 -44
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +21 -32
- 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 +1 -1
- package/dist/component/helpers.d.ts +7 -0
- package/dist/component/helpers.d.ts.map +1 -0
- package/dist/component/helpers.js +30 -0
- package/dist/component/http.d.ts +3 -0
- package/dist/component/http.d.ts.map +1 -0
- package/dist/component/http.js +268 -0
- package/dist/component/lib.d.ts +237 -22
- package/dist/component/lib.d.ts.map +1 -1
- package/dist/component/lib.js +91 -143
- 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/types.d.ts +97 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- 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 +40 -52
- package/src/component/_generated/api.d.ts +3 -11
- package/src/component/convex.config.ts +7 -2
- package/src/component/helpers.ts +44 -0
- package/src/component/http.ts +304 -0
- package/src/component/lib.ts +189 -204
- 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/types.ts +168 -0
- package/src/client/types.ts +0 -64
package/dist/client/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Mounts } from "../component/_generated/api
|
|
2
|
-
import type { RunActionCtx, RunQueryCtx, UseApi } from "
|
|
1
|
+
import type { Mounts } from "../component/_generated/api";
|
|
2
|
+
import type { RunActionCtx, RunQueryCtx, UseApi } from "../types";
|
|
3
3
|
export type LoopsComponent = UseApi<Mounts>;
|
|
4
4
|
export interface ContactData {
|
|
5
5
|
email: string;
|
|
@@ -13,18 +13,18 @@ export interface ContactData {
|
|
|
13
13
|
export interface TransactionalEmailOptions {
|
|
14
14
|
transactionalId: string;
|
|
15
15
|
email: string;
|
|
16
|
-
dataVariables?: Record<string,
|
|
16
|
+
dataVariables?: Record<string, unknown>;
|
|
17
17
|
}
|
|
18
18
|
export interface EventOptions {
|
|
19
19
|
email: string;
|
|
20
20
|
eventName: string;
|
|
21
|
-
eventProperties?: Record<string,
|
|
21
|
+
eventProperties?: Record<string, unknown>;
|
|
22
22
|
}
|
|
23
23
|
export declare class Loops {
|
|
24
|
-
private readonly component;
|
|
25
24
|
readonly options?: {
|
|
26
25
|
apiKey?: string;
|
|
27
26
|
};
|
|
27
|
+
private readonly lib;
|
|
28
28
|
constructor(component: LoopsComponent, options?: {
|
|
29
29
|
apiKey?: string;
|
|
30
30
|
});
|
|
@@ -32,41 +32,77 @@ export declare class Loops {
|
|
|
32
32
|
/**
|
|
33
33
|
* Add or update a contact in Loops
|
|
34
34
|
*/
|
|
35
|
-
addContact(ctx: RunActionCtx, contact: ContactData): Promise<
|
|
35
|
+
addContact(ctx: RunActionCtx, contact: ContactData): Promise<{
|
|
36
|
+
success: boolean;
|
|
37
|
+
id?: string | undefined;
|
|
38
|
+
}>;
|
|
36
39
|
/**
|
|
37
40
|
* Update an existing contact in Loops
|
|
38
41
|
*/
|
|
39
42
|
updateContact(ctx: RunActionCtx, email: string, updates: Partial<ContactData> & {
|
|
40
|
-
dataVariables?: Record<string,
|
|
41
|
-
}): Promise<
|
|
43
|
+
dataVariables?: Record<string, unknown>;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
success: boolean;
|
|
46
|
+
}>;
|
|
42
47
|
/**
|
|
43
48
|
* Send a transactional email using a transactional ID
|
|
44
49
|
*/
|
|
45
|
-
sendTransactional(ctx: RunActionCtx, options: TransactionalEmailOptions): Promise<
|
|
50
|
+
sendTransactional(ctx: RunActionCtx, options: TransactionalEmailOptions): Promise<{
|
|
51
|
+
success: boolean;
|
|
52
|
+
messageId?: string | undefined;
|
|
53
|
+
}>;
|
|
46
54
|
/**
|
|
47
55
|
* Send an event to Loops to trigger email workflows
|
|
48
56
|
*/
|
|
49
|
-
sendEvent(ctx: RunActionCtx, options: EventOptions): Promise<
|
|
57
|
+
sendEvent(ctx: RunActionCtx, options: EventOptions): Promise<{
|
|
58
|
+
success: boolean;
|
|
59
|
+
}>;
|
|
50
60
|
/**
|
|
51
61
|
* Find a contact by email
|
|
52
62
|
* Retrieves contact information from Loops
|
|
53
63
|
*/
|
|
54
|
-
findContact(ctx: RunActionCtx, email: string): Promise<
|
|
64
|
+
findContact(ctx: RunActionCtx, email: string): Promise<{
|
|
65
|
+
success: boolean;
|
|
66
|
+
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;
|
|
77
|
+
}>;
|
|
55
78
|
/**
|
|
56
79
|
* Batch create contacts
|
|
57
80
|
* Create multiple contacts in a single API call
|
|
58
81
|
*/
|
|
59
|
-
batchCreateContacts(ctx: RunActionCtx, contacts: ContactData[]): Promise<
|
|
82
|
+
batchCreateContacts(ctx: RunActionCtx, contacts: ContactData[]): Promise<{
|
|
83
|
+
success: boolean;
|
|
84
|
+
created?: number | undefined;
|
|
85
|
+
failed?: number | undefined;
|
|
86
|
+
results?: {
|
|
87
|
+
email: string;
|
|
88
|
+
success: boolean;
|
|
89
|
+
error?: string | undefined;
|
|
90
|
+
}[] | undefined;
|
|
91
|
+
}>;
|
|
60
92
|
/**
|
|
61
93
|
* Unsubscribe a contact
|
|
62
94
|
* Unsubscribes a contact from receiving emails (they remain in the system)
|
|
63
95
|
*/
|
|
64
|
-
unsubscribeContact(ctx: RunActionCtx, email: string): Promise<
|
|
96
|
+
unsubscribeContact(ctx: RunActionCtx, email: string): Promise<{
|
|
97
|
+
success: boolean;
|
|
98
|
+
}>;
|
|
65
99
|
/**
|
|
66
100
|
* Resubscribe a contact
|
|
67
101
|
* Resubscribes a previously unsubscribed contact
|
|
68
102
|
*/
|
|
69
|
-
resubscribeContact(ctx: RunActionCtx, email: string): Promise<
|
|
103
|
+
resubscribeContact(ctx: RunActionCtx, email: string): Promise<{
|
|
104
|
+
success: boolean;
|
|
105
|
+
}>;
|
|
70
106
|
/**
|
|
71
107
|
* Count contacts in the database
|
|
72
108
|
* Can filter by audience criteria (userGroup, source, subscribed status)
|
|
@@ -76,7 +112,7 @@ export declare class Loops {
|
|
|
76
112
|
userGroup?: string;
|
|
77
113
|
source?: string;
|
|
78
114
|
subscribed?: boolean;
|
|
79
|
-
}): Promise<
|
|
115
|
+
}): Promise<number>;
|
|
80
116
|
/**
|
|
81
117
|
* List contacts with pagination and optional filters
|
|
82
118
|
* Returns actual contact data, not just a count
|
|
@@ -88,34 +124,78 @@ export declare class Loops {
|
|
|
88
124
|
subscribed?: boolean;
|
|
89
125
|
limit?: number;
|
|
90
126
|
offset?: number;
|
|
91
|
-
}): Promise<
|
|
127
|
+
}): Promise<{
|
|
128
|
+
contacts: {
|
|
129
|
+
_id: string;
|
|
130
|
+
email: string;
|
|
131
|
+
subscribed: boolean;
|
|
132
|
+
createdAt: number;
|
|
133
|
+
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;
|
|
142
|
+
limit: number;
|
|
143
|
+
offset: number;
|
|
144
|
+
hasMore: boolean;
|
|
145
|
+
}>;
|
|
92
146
|
/**
|
|
93
147
|
* Detect spam patterns: emails sent to the same recipient too frequently
|
|
94
148
|
*/
|
|
95
149
|
detectRecipientSpam(ctx: RunQueryCtx, options?: {
|
|
96
150
|
timeWindowMs?: number;
|
|
97
151
|
maxEmailsPerRecipient?: number;
|
|
98
|
-
}): Promise<
|
|
152
|
+
}): Promise<{
|
|
153
|
+
[x: string]: any;
|
|
154
|
+
email: string;
|
|
155
|
+
count: number;
|
|
156
|
+
timeWindowMs: number;
|
|
157
|
+
}[]>;
|
|
99
158
|
/**
|
|
100
159
|
* Detect spam patterns: emails sent by the same actor/user too frequently
|
|
101
160
|
*/
|
|
102
161
|
detectActorSpam(ctx: RunQueryCtx, options?: {
|
|
103
162
|
timeWindowMs?: number;
|
|
104
163
|
maxEmailsPerActor?: number;
|
|
105
|
-
}): Promise<
|
|
164
|
+
}): Promise<{
|
|
165
|
+
actorId: string;
|
|
166
|
+
count: number;
|
|
167
|
+
timeWindowMs: number;
|
|
168
|
+
}[]>;
|
|
106
169
|
/**
|
|
107
170
|
* Get email operation statistics for monitoring
|
|
108
171
|
*/
|
|
109
172
|
getEmailStats(ctx: RunQueryCtx, options?: {
|
|
110
173
|
timeWindowMs?: number;
|
|
111
|
-
}): Promise<
|
|
174
|
+
}): Promise<{
|
|
175
|
+
[x: string]: any;
|
|
176
|
+
totalOperations: number;
|
|
177
|
+
successfulOperations: number;
|
|
178
|
+
failedOperations: number;
|
|
179
|
+
operationsByType: {
|
|
180
|
+
[x: string]: number;
|
|
181
|
+
};
|
|
182
|
+
uniqueRecipients: number;
|
|
183
|
+
uniqueActors: number;
|
|
184
|
+
}>;
|
|
112
185
|
/**
|
|
113
186
|
* Detect rapid-fire email sending patterns
|
|
114
187
|
*/
|
|
115
188
|
detectRapidFirePatterns(ctx: RunQueryCtx, options?: {
|
|
116
189
|
timeWindowMs?: number;
|
|
117
190
|
minEmailsInWindow?: number;
|
|
118
|
-
}): Promise<
|
|
191
|
+
}): Promise<{
|
|
192
|
+
count: number;
|
|
193
|
+
timeWindowMs: number;
|
|
194
|
+
firstTimestamp: number;
|
|
195
|
+
lastTimestamp: number;
|
|
196
|
+
email?: string | undefined;
|
|
197
|
+
actorId?: string | undefined;
|
|
198
|
+
}[]>;
|
|
119
199
|
/**
|
|
120
200
|
* Check if an email can be sent to a recipient based on rate limits
|
|
121
201
|
*/
|
|
@@ -123,7 +203,14 @@ export declare class Loops {
|
|
|
123
203
|
email: string;
|
|
124
204
|
timeWindowMs: number;
|
|
125
205
|
maxEmails: number;
|
|
126
|
-
}): Promise<
|
|
206
|
+
}): Promise<{
|
|
207
|
+
[x: string]: any;
|
|
208
|
+
allowed: boolean;
|
|
209
|
+
count: number;
|
|
210
|
+
limit: number;
|
|
211
|
+
timeWindowMs: number;
|
|
212
|
+
retryAfter?: number | undefined;
|
|
213
|
+
}>;
|
|
127
214
|
/**
|
|
128
215
|
* Check if an actor/user can send more emails based on rate limits
|
|
129
216
|
*/
|
|
@@ -131,18 +218,31 @@ export declare class Loops {
|
|
|
131
218
|
actorId: string;
|
|
132
219
|
timeWindowMs: number;
|
|
133
220
|
maxEmails: number;
|
|
134
|
-
}): Promise<
|
|
221
|
+
}): Promise<{
|
|
222
|
+
allowed: boolean;
|
|
223
|
+
count: number;
|
|
224
|
+
limit: number;
|
|
225
|
+
timeWindowMs: number;
|
|
226
|
+
retryAfter?: number | undefined;
|
|
227
|
+
}>;
|
|
135
228
|
/**
|
|
136
229
|
* Check global email sending rate limit
|
|
137
230
|
*/
|
|
138
231
|
checkGlobalRateLimit(ctx: RunQueryCtx, options: {
|
|
139
232
|
timeWindowMs: number;
|
|
140
233
|
maxEmails: number;
|
|
141
|
-
}): Promise<
|
|
234
|
+
}): Promise<{
|
|
235
|
+
allowed: boolean;
|
|
236
|
+
count: number;
|
|
237
|
+
limit: number;
|
|
238
|
+
timeWindowMs: number;
|
|
239
|
+
}>;
|
|
142
240
|
/**
|
|
143
241
|
* Delete a contact from Loops
|
|
144
242
|
*/
|
|
145
|
-
deleteContact(ctx: RunActionCtx, email: string): Promise<
|
|
243
|
+
deleteContact(ctx: RunActionCtx, email: string): Promise<{
|
|
244
|
+
success: boolean;
|
|
245
|
+
}>;
|
|
146
246
|
/**
|
|
147
247
|
* Trigger a loop for a contact
|
|
148
248
|
* Loops are automated email sequences that can be triggered by events
|
|
@@ -156,9 +256,12 @@ export declare class Loops {
|
|
|
156
256
|
triggerLoop(ctx: RunActionCtx, options: {
|
|
157
257
|
loopId: string;
|
|
158
258
|
email: string;
|
|
159
|
-
dataVariables?: Record<string,
|
|
259
|
+
dataVariables?: Record<string, unknown>;
|
|
160
260
|
eventName?: string;
|
|
161
|
-
}): Promise<
|
|
261
|
+
}): Promise<{
|
|
262
|
+
success: boolean;
|
|
263
|
+
warning?: string | undefined;
|
|
264
|
+
}>;
|
|
162
265
|
/**
|
|
163
266
|
* For easy re-exporting.
|
|
164
267
|
* Apps can do
|
|
@@ -167,24 +270,182 @@ export declare class Loops {
|
|
|
167
270
|
* ```
|
|
168
271
|
*/
|
|
169
272
|
api(): {
|
|
170
|
-
addContact:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
273
|
+
addContact: import("convex/server").RegisteredAction<"public", {
|
|
274
|
+
firstName?: string | undefined;
|
|
275
|
+
lastName?: string | undefined;
|
|
276
|
+
userId?: string | undefined;
|
|
277
|
+
source?: string | undefined;
|
|
278
|
+
subscribed?: boolean | undefined;
|
|
279
|
+
userGroup?: string | undefined;
|
|
280
|
+
email: string;
|
|
281
|
+
}, Promise<{
|
|
282
|
+
success: boolean;
|
|
283
|
+
id?: string | undefined;
|
|
284
|
+
}>>;
|
|
285
|
+
updateContact: import("convex/server").RegisteredAction<"public", {
|
|
286
|
+
firstName?: string | undefined;
|
|
287
|
+
lastName?: string | undefined;
|
|
288
|
+
userId?: string | undefined;
|
|
289
|
+
source?: string | undefined;
|
|
290
|
+
subscribed?: boolean | undefined;
|
|
291
|
+
userGroup?: string | undefined;
|
|
292
|
+
dataVariables?: any;
|
|
293
|
+
email: string;
|
|
294
|
+
}, Promise<{
|
|
295
|
+
success: boolean;
|
|
296
|
+
}>>;
|
|
297
|
+
sendTransactional: import("convex/server").RegisteredAction<"public", {
|
|
298
|
+
dataVariables?: any;
|
|
299
|
+
email: string;
|
|
300
|
+
transactionalId: string;
|
|
301
|
+
}, Promise<{
|
|
302
|
+
success: boolean;
|
|
303
|
+
messageId?: string | undefined;
|
|
304
|
+
}>>;
|
|
305
|
+
sendEvent: import("convex/server").RegisteredAction<"public", {
|
|
306
|
+
eventProperties?: any;
|
|
307
|
+
email: string;
|
|
308
|
+
eventName: string;
|
|
309
|
+
}, Promise<{
|
|
310
|
+
success: boolean;
|
|
311
|
+
}>>;
|
|
312
|
+
deleteContact: import("convex/server").RegisteredAction<"public", {
|
|
313
|
+
email: string;
|
|
314
|
+
}, Promise<{
|
|
315
|
+
success: boolean;
|
|
316
|
+
}>>;
|
|
317
|
+
triggerLoop: import("convex/server").RegisteredAction<"public", {
|
|
318
|
+
dataVariables?: any;
|
|
319
|
+
email: string;
|
|
320
|
+
loopId: string;
|
|
321
|
+
}, Promise<{
|
|
322
|
+
success: boolean;
|
|
323
|
+
warning?: string | undefined;
|
|
324
|
+
}>>;
|
|
325
|
+
findContact: import("convex/server").RegisteredAction<"public", {
|
|
326
|
+
email: string;
|
|
327
|
+
}, Promise<{
|
|
328
|
+
success: boolean;
|
|
329
|
+
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;
|
|
340
|
+
}>>;
|
|
341
|
+
batchCreateContacts: import("convex/server").RegisteredAction<"public", {
|
|
342
|
+
contacts: {
|
|
343
|
+
firstName?: string | undefined;
|
|
344
|
+
lastName?: string | undefined;
|
|
345
|
+
userId?: string | undefined;
|
|
346
|
+
source?: string | undefined;
|
|
347
|
+
subscribed?: boolean | undefined;
|
|
348
|
+
userGroup?: string | undefined;
|
|
349
|
+
email: string;
|
|
350
|
+
}[];
|
|
351
|
+
}, Promise<{
|
|
352
|
+
success: boolean;
|
|
353
|
+
created?: number | undefined;
|
|
354
|
+
failed?: number | undefined;
|
|
355
|
+
results?: {
|
|
356
|
+
email: string;
|
|
357
|
+
success: boolean;
|
|
358
|
+
error?: string | undefined;
|
|
359
|
+
}[] | undefined;
|
|
360
|
+
}>>;
|
|
361
|
+
unsubscribeContact: import("convex/server").RegisteredAction<"public", {
|
|
362
|
+
email: string;
|
|
363
|
+
}, Promise<{
|
|
364
|
+
success: boolean;
|
|
365
|
+
}>>;
|
|
366
|
+
resubscribeContact: import("convex/server").RegisteredAction<"public", {
|
|
367
|
+
email: string;
|
|
368
|
+
}, Promise<{
|
|
369
|
+
success: boolean;
|
|
370
|
+
}>>;
|
|
371
|
+
countContacts: import("convex/server").RegisteredQuery<"public", {
|
|
372
|
+
source?: string | undefined;
|
|
373
|
+
subscribed?: boolean | undefined;
|
|
374
|
+
userGroup?: string | undefined;
|
|
375
|
+
}, Promise<number>>;
|
|
376
|
+
detectRecipientSpam: import("convex/server").RegisteredQuery<"public", {
|
|
377
|
+
timeWindowMs?: number | undefined;
|
|
378
|
+
maxEmailsPerRecipient?: number | undefined;
|
|
379
|
+
}, Promise<{
|
|
380
|
+
[x: string]: any;
|
|
381
|
+
email: string;
|
|
382
|
+
count: number;
|
|
383
|
+
timeWindowMs: number;
|
|
384
|
+
}[]>>;
|
|
385
|
+
detectActorSpam: import("convex/server").RegisteredQuery<"public", {
|
|
386
|
+
timeWindowMs?: number | undefined;
|
|
387
|
+
maxEmailsPerActor?: number | undefined;
|
|
388
|
+
}, Promise<{
|
|
389
|
+
actorId: string;
|
|
390
|
+
count: number;
|
|
391
|
+
timeWindowMs: number;
|
|
392
|
+
}[]>>;
|
|
393
|
+
getEmailStats: import("convex/server").RegisteredQuery<"public", {
|
|
394
|
+
timeWindowMs?: number | undefined;
|
|
395
|
+
}, Promise<{
|
|
396
|
+
[x: string]: any;
|
|
397
|
+
totalOperations: number;
|
|
398
|
+
successfulOperations: number;
|
|
399
|
+
failedOperations: number;
|
|
400
|
+
operationsByType: {
|
|
401
|
+
[x: string]: number;
|
|
402
|
+
};
|
|
403
|
+
uniqueRecipients: number;
|
|
404
|
+
uniqueActors: number;
|
|
405
|
+
}>>;
|
|
406
|
+
detectRapidFirePatterns: import("convex/server").RegisteredQuery<"public", {
|
|
407
|
+
timeWindowMs?: number | undefined;
|
|
408
|
+
minEmailsInWindow?: number | undefined;
|
|
409
|
+
}, Promise<{
|
|
410
|
+
count: number;
|
|
411
|
+
timeWindowMs: number;
|
|
412
|
+
firstTimestamp: number;
|
|
413
|
+
lastTimestamp: number;
|
|
414
|
+
email?: string | undefined;
|
|
415
|
+
actorId?: string | undefined;
|
|
416
|
+
}[]>>;
|
|
417
|
+
checkRecipientRateLimit: import("convex/server").RegisteredQuery<"public", {
|
|
418
|
+
email: string;
|
|
419
|
+
timeWindowMs: number;
|
|
420
|
+
maxEmails: number;
|
|
421
|
+
}, Promise<{
|
|
422
|
+
[x: string]: any;
|
|
423
|
+
allowed: boolean;
|
|
424
|
+
count: number;
|
|
425
|
+
limit: number;
|
|
426
|
+
timeWindowMs: number;
|
|
427
|
+
retryAfter?: number | undefined;
|
|
428
|
+
}>>;
|
|
429
|
+
checkActorRateLimit: import("convex/server").RegisteredQuery<"public", {
|
|
430
|
+
actorId: string;
|
|
431
|
+
timeWindowMs: number;
|
|
432
|
+
maxEmails: number;
|
|
433
|
+
}, Promise<{
|
|
434
|
+
allowed: boolean;
|
|
435
|
+
count: number;
|
|
436
|
+
limit: number;
|
|
437
|
+
timeWindowMs: number;
|
|
438
|
+
retryAfter?: number | undefined;
|
|
439
|
+
}>>;
|
|
440
|
+
checkGlobalRateLimit: import("convex/server").RegisteredQuery<"public", {
|
|
441
|
+
timeWindowMs: number;
|
|
442
|
+
maxEmails: number;
|
|
443
|
+
}, Promise<{
|
|
444
|
+
allowed: boolean;
|
|
445
|
+
count: number;
|
|
446
|
+
limit: number;
|
|
447
|
+
timeWindowMs: number;
|
|
448
|
+
}>>;
|
|
188
449
|
};
|
|
189
450
|
}
|
|
190
451
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
|
package/dist/client/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { actionGeneric, queryGeneric } from "convex/server";
|
|
2
2
|
import { v } from "convex/values";
|
|
3
3
|
export class Loops {
|
|
4
|
-
component;
|
|
5
4
|
options;
|
|
5
|
+
lib;
|
|
6
6
|
constructor(component, options) {
|
|
7
7
|
if (!component) {
|
|
8
8
|
throw new Error("Loops component reference is required. " +
|
|
@@ -15,7 +15,7 @@ export class Loops {
|
|
|
15
15
|
"Ensure the component is correctly mounted in convex.config.ts: " +
|
|
16
16
|
"app.use(loops);");
|
|
17
17
|
}
|
|
18
|
-
this.
|
|
18
|
+
this.lib = component.lib;
|
|
19
19
|
this.options = options;
|
|
20
20
|
const apiKey = options?.apiKey ?? process.env.LOOPS_API_KEY;
|
|
21
21
|
if (!apiKey) {
|
|
@@ -33,18 +33,7 @@ export class Loops {
|
|
|
33
33
|
* Add or update a contact in Loops
|
|
34
34
|
*/
|
|
35
35
|
async addContact(ctx, contact) {
|
|
36
|
-
|
|
37
|
-
throw new Error("Loops component is not initialized. " +
|
|
38
|
-
"Make sure to pass components.loops to the Loops constructor: " +
|
|
39
|
-
"new Loops(components.loops)");
|
|
40
|
-
}
|
|
41
|
-
if (!this.component.lib) {
|
|
42
|
-
throw new Error("Invalid component reference. " +
|
|
43
|
-
"The component may not be properly mounted. " +
|
|
44
|
-
"Ensure the component is correctly mounted in convex.config.ts: " +
|
|
45
|
-
"app.use(loops);");
|
|
46
|
-
}
|
|
47
|
-
return ctx.runAction(this.component.lib.addContact, {
|
|
36
|
+
return ctx.runAction(this.lib.addContact, {
|
|
48
37
|
apiKey: this.apiKey,
|
|
49
38
|
contact,
|
|
50
39
|
});
|
|
@@ -53,7 +42,7 @@ export class Loops {
|
|
|
53
42
|
* Update an existing contact in Loops
|
|
54
43
|
*/
|
|
55
44
|
async updateContact(ctx, email, updates) {
|
|
56
|
-
return ctx.runAction(this.
|
|
45
|
+
return ctx.runAction(this.lib.updateContact, {
|
|
57
46
|
apiKey: this.apiKey,
|
|
58
47
|
email,
|
|
59
48
|
...updates,
|
|
@@ -63,7 +52,7 @@ export class Loops {
|
|
|
63
52
|
* Send a transactional email using a transactional ID
|
|
64
53
|
*/
|
|
65
54
|
async sendTransactional(ctx, options) {
|
|
66
|
-
return ctx.runAction(this.
|
|
55
|
+
return ctx.runAction(this.lib.sendTransactional, {
|
|
67
56
|
apiKey: this.apiKey,
|
|
68
57
|
...options,
|
|
69
58
|
});
|
|
@@ -72,7 +61,7 @@ export class Loops {
|
|
|
72
61
|
* Send an event to Loops to trigger email workflows
|
|
73
62
|
*/
|
|
74
63
|
async sendEvent(ctx, options) {
|
|
75
|
-
return ctx.runAction(this.
|
|
64
|
+
return ctx.runAction(this.lib.sendEvent, {
|
|
76
65
|
apiKey: this.apiKey,
|
|
77
66
|
...options,
|
|
78
67
|
});
|
|
@@ -82,7 +71,7 @@ export class Loops {
|
|
|
82
71
|
* Retrieves contact information from Loops
|
|
83
72
|
*/
|
|
84
73
|
async findContact(ctx, email) {
|
|
85
|
-
return ctx.runAction(this.
|
|
74
|
+
return ctx.runAction(this.lib.findContact, {
|
|
86
75
|
apiKey: this.apiKey,
|
|
87
76
|
email,
|
|
88
77
|
});
|
|
@@ -92,7 +81,7 @@ export class Loops {
|
|
|
92
81
|
* Create multiple contacts in a single API call
|
|
93
82
|
*/
|
|
94
83
|
async batchCreateContacts(ctx, contacts) {
|
|
95
|
-
return ctx.runAction(this.
|
|
84
|
+
return ctx.runAction(this.lib.batchCreateContacts, {
|
|
96
85
|
apiKey: this.apiKey,
|
|
97
86
|
contacts,
|
|
98
87
|
});
|
|
@@ -102,7 +91,7 @@ export class Loops {
|
|
|
102
91
|
* Unsubscribes a contact from receiving emails (they remain in the system)
|
|
103
92
|
*/
|
|
104
93
|
async unsubscribeContact(ctx, email) {
|
|
105
|
-
return ctx.runAction(this.
|
|
94
|
+
return ctx.runAction(this.lib.unsubscribeContact, {
|
|
106
95
|
apiKey: this.apiKey,
|
|
107
96
|
email,
|
|
108
97
|
});
|
|
@@ -112,7 +101,7 @@ export class Loops {
|
|
|
112
101
|
* Resubscribes a previously unsubscribed contact
|
|
113
102
|
*/
|
|
114
103
|
async resubscribeContact(ctx, email) {
|
|
115
|
-
return ctx.runAction(this.
|
|
104
|
+
return ctx.runAction(this.lib.resubscribeContact, {
|
|
116
105
|
apiKey: this.apiKey,
|
|
117
106
|
email,
|
|
118
107
|
});
|
|
@@ -123,7 +112,7 @@ export class Loops {
|
|
|
123
112
|
* This queries the component's local database, not Loops API
|
|
124
113
|
*/
|
|
125
114
|
async countContacts(ctx, options) {
|
|
126
|
-
return ctx.runQuery(this.
|
|
115
|
+
return ctx.runQuery(this.lib.countContacts, options ?? {});
|
|
127
116
|
}
|
|
128
117
|
/**
|
|
129
118
|
* List contacts with pagination and optional filters
|
|
@@ -131,7 +120,7 @@ export class Loops {
|
|
|
131
120
|
* This queries the component's local database, not Loops API
|
|
132
121
|
*/
|
|
133
122
|
async listContacts(ctx, options) {
|
|
134
|
-
return ctx.runQuery(this.
|
|
123
|
+
return ctx.runQuery(this.lib.listContacts, {
|
|
135
124
|
userGroup: options?.userGroup,
|
|
136
125
|
source: options?.source,
|
|
137
126
|
subscribed: options?.subscribed,
|
|
@@ -143,7 +132,7 @@ export class Loops {
|
|
|
143
132
|
* Detect spam patterns: emails sent to the same recipient too frequently
|
|
144
133
|
*/
|
|
145
134
|
async detectRecipientSpam(ctx, options) {
|
|
146
|
-
return ctx.runQuery(this.
|
|
135
|
+
return ctx.runQuery(this.lib.detectRecipientSpam, {
|
|
147
136
|
timeWindowMs: options?.timeWindowMs ?? 3600000,
|
|
148
137
|
maxEmailsPerRecipient: options?.maxEmailsPerRecipient ?? 10,
|
|
149
138
|
});
|
|
@@ -152,7 +141,7 @@ export class Loops {
|
|
|
152
141
|
* Detect spam patterns: emails sent by the same actor/user too frequently
|
|
153
142
|
*/
|
|
154
143
|
async detectActorSpam(ctx, options) {
|
|
155
|
-
return ctx.runQuery(this.
|
|
144
|
+
return ctx.runQuery(this.lib.detectActorSpam, {
|
|
156
145
|
timeWindowMs: options?.timeWindowMs ?? 3600000,
|
|
157
146
|
maxEmailsPerActor: options?.maxEmailsPerActor ?? 100,
|
|
158
147
|
});
|
|
@@ -161,7 +150,7 @@ export class Loops {
|
|
|
161
150
|
* Get email operation statistics for monitoring
|
|
162
151
|
*/
|
|
163
152
|
async getEmailStats(ctx, options) {
|
|
164
|
-
return ctx.runQuery(this.
|
|
153
|
+
return ctx.runQuery(this.lib.getEmailStats, {
|
|
165
154
|
timeWindowMs: options?.timeWindowMs ?? 86400000,
|
|
166
155
|
});
|
|
167
156
|
}
|
|
@@ -169,7 +158,7 @@ export class Loops {
|
|
|
169
158
|
* Detect rapid-fire email sending patterns
|
|
170
159
|
*/
|
|
171
160
|
async detectRapidFirePatterns(ctx, options) {
|
|
172
|
-
return ctx.runQuery(this.
|
|
161
|
+
return ctx.runQuery(this.lib.detectRapidFirePatterns, {
|
|
173
162
|
timeWindowMs: options?.timeWindowMs ?? 60000,
|
|
174
163
|
minEmailsInWindow: options?.minEmailsInWindow ?? 5,
|
|
175
164
|
});
|
|
@@ -178,25 +167,25 @@ export class Loops {
|
|
|
178
167
|
* Check if an email can be sent to a recipient based on rate limits
|
|
179
168
|
*/
|
|
180
169
|
async checkRecipientRateLimit(ctx, options) {
|
|
181
|
-
return ctx.runQuery(this.
|
|
170
|
+
return ctx.runQuery(this.lib.checkRecipientRateLimit, options);
|
|
182
171
|
}
|
|
183
172
|
/**
|
|
184
173
|
* Check if an actor/user can send more emails based on rate limits
|
|
185
174
|
*/
|
|
186
175
|
async checkActorRateLimit(ctx, options) {
|
|
187
|
-
return ctx.runQuery(this.
|
|
176
|
+
return ctx.runQuery(this.lib.checkActorRateLimit, options);
|
|
188
177
|
}
|
|
189
178
|
/**
|
|
190
179
|
* Check global email sending rate limit
|
|
191
180
|
*/
|
|
192
181
|
async checkGlobalRateLimit(ctx, options) {
|
|
193
|
-
return ctx.runQuery(this.
|
|
182
|
+
return ctx.runQuery(this.lib.checkGlobalRateLimit, options);
|
|
194
183
|
}
|
|
195
184
|
/**
|
|
196
185
|
* Delete a contact from Loops
|
|
197
186
|
*/
|
|
198
187
|
async deleteContact(ctx, email) {
|
|
199
|
-
return ctx.runAction(this.
|
|
188
|
+
return ctx.runAction(this.lib.deleteContact, {
|
|
200
189
|
apiKey: this.apiKey,
|
|
201
190
|
email,
|
|
202
191
|
});
|
|
@@ -212,7 +201,7 @@ export class Loops {
|
|
|
212
201
|
* @param options.eventName - Optional event name. If not provided, uses `loop_{loopId}`
|
|
213
202
|
*/
|
|
214
203
|
async triggerLoop(ctx, options) {
|
|
215
|
-
return ctx.runAction(this.
|
|
204
|
+
return ctx.runAction(this.lib.triggerLoop, {
|
|
216
205
|
apiKey: this.apiKey,
|
|
217
206
|
...options,
|
|
218
207
|
});
|