@devwithbobby/loops 0.1.19 → 0.2.0
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 +47 -12
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +42 -4
- package/dist/component/_generated/api.d.ts +185 -1
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/component.d.ts +12 -5
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/_generated/dataModel.d.ts +1 -1
- package/dist/component/aggregates.d.ts +42 -0
- package/dist/component/aggregates.d.ts.map +1 -0
- package/dist/component/aggregates.js +54 -0
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/convex.config.js +2 -0
- package/dist/component/helpers.d.ts.map +1 -1
- package/dist/component/http.js +1 -1
- package/dist/component/lib.d.ts +66 -17
- package/dist/component/lib.d.ts.map +1 -1
- package/dist/component/lib.js +194 -73
- package/dist/component/schema.d.ts +2 -2
- package/dist/component/tables/contacts.d.ts.map +1 -1
- package/dist/component/tables/emailOperations.d.ts +4 -4
- package/dist/component/tables/emailOperations.d.ts.map +1 -1
- package/dist/test.d.ts +2 -2
- package/dist/types.d.ts +249 -62
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -2
- package/dist/utils.d.ts +6 -6
- package/package.json +15 -9
- package/src/client/index.ts +52 -6
- package/src/component/_generated/api.ts +190 -1
- package/src/component/_generated/component.ts +10 -5
- package/src/component/_generated/dataModel.ts +1 -1
- package/src/component/aggregates.ts +89 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/http.ts +1 -1
- package/src/component/lib.ts +226 -89
- package/src/types.ts +20 -122
package/dist/component/http.js
CHANGED
|
@@ -82,7 +82,7 @@ http.route({
|
|
|
82
82
|
source: url.searchParams.get("source") ?? undefined,
|
|
83
83
|
subscribed: booleanFromQuery(url.searchParams.get("subscribed")),
|
|
84
84
|
limit: numberFromQuery(url.searchParams.get("limit"), 100),
|
|
85
|
-
|
|
85
|
+
cursor: url.searchParams.get("cursor") ?? null,
|
|
86
86
|
});
|
|
87
87
|
return jsonResponse(data);
|
|
88
88
|
}
|
package/dist/component/lib.d.ts
CHANGED
|
@@ -36,9 +36,15 @@ export declare const logEmailOperation: import("convex/server").RegisteredMutati
|
|
|
36
36
|
* Count contacts in the database
|
|
37
37
|
* Can filter by audience criteria (userGroup, source, subscribed status)
|
|
38
38
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* For userGroup-only filtering, uses efficient O(log n) aggregate counting.
|
|
40
|
+
* For other filters (source, subscribed), uses indexed queries with a read limit.
|
|
41
|
+
*
|
|
42
|
+
* IMPORTANT: Before using this with existing data, run the backfillContactAggregate
|
|
43
|
+
* mutation to populate the aggregate with existing contacts.
|
|
44
|
+
*
|
|
45
|
+
* NOTE: When filtering by source or subscribed, counts are capped at MAX_COUNT_LIMIT
|
|
46
|
+
* to avoid query read limit errors. For exact counts with large datasets, use
|
|
47
|
+
* userGroup-only filtering which uses efficient aggregate counting.
|
|
42
48
|
*/
|
|
43
49
|
export declare const countContacts: import("convex/server").RegisteredQuery<"public", {
|
|
44
50
|
userGroup?: string | undefined;
|
|
@@ -46,19 +52,22 @@ export declare const countContacts: import("convex/server").RegisteredQuery<"pub
|
|
|
46
52
|
subscribed?: boolean | undefined;
|
|
47
53
|
}, Promise<number>>;
|
|
48
54
|
/**
|
|
49
|
-
* List contacts from the database with pagination
|
|
55
|
+
* List contacts from the database with cursor-based pagination
|
|
50
56
|
* Can filter by audience criteria (userGroup, source, subscribed status)
|
|
51
57
|
* Returns actual contact data, not just a count
|
|
52
58
|
*
|
|
59
|
+
* Uses cursor-based pagination for efficient querying - only reads documents
|
|
60
|
+
* from the cursor position forward, not all preceding documents.
|
|
61
|
+
*
|
|
53
62
|
* Note: When multiple filters are provided, only one index can be used.
|
|
54
|
-
* Additional filters are applied in-memory
|
|
63
|
+
* Additional filters are applied in-memory after fetching.
|
|
55
64
|
*/
|
|
56
65
|
export declare const listContacts: import("convex/server").RegisteredQuery<"public", {
|
|
57
66
|
limit: number;
|
|
58
|
-
offset: number;
|
|
59
67
|
userGroup?: string | undefined;
|
|
60
68
|
source?: string | undefined;
|
|
61
69
|
subscribed?: boolean | undefined;
|
|
70
|
+
cursor?: string | null | undefined;
|
|
62
71
|
}, Promise<{
|
|
63
72
|
contacts: {
|
|
64
73
|
_id: string;
|
|
@@ -73,10 +82,8 @@ export declare const listContacts: import("convex/server").RegisteredQuery<"publ
|
|
|
73
82
|
userGroup?: string | undefined;
|
|
74
83
|
loopsContactId?: string | undefined;
|
|
75
84
|
}[];
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
offset: number;
|
|
79
|
-
hasMore: boolean;
|
|
85
|
+
continueCursor: string | null;
|
|
86
|
+
isDone: boolean;
|
|
80
87
|
}>>;
|
|
81
88
|
/**
|
|
82
89
|
* Add or update a contact in Loops
|
|
@@ -242,7 +249,10 @@ export declare const resubscribeContact: import("convex/server").RegisteredActio
|
|
|
242
249
|
}>>;
|
|
243
250
|
/**
|
|
244
251
|
* Check for spam patterns: too many emails to the same recipient in a time window
|
|
245
|
-
* Returns email addresses that received too many emails
|
|
252
|
+
* Returns email addresses that received too many emails.
|
|
253
|
+
*
|
|
254
|
+
* NOTE: Analysis is limited to the most recent MAX_SPAM_DETECTION_LIMIT operations
|
|
255
|
+
* in the time window to avoid query read limit errors.
|
|
246
256
|
*/
|
|
247
257
|
export declare const detectRecipientSpam: import("convex/server").RegisteredQuery<"public", {
|
|
248
258
|
timeWindowMs: number;
|
|
@@ -255,7 +265,10 @@ export declare const detectRecipientSpam: import("convex/server").RegisteredQuer
|
|
|
255
265
|
}[]>>;
|
|
256
266
|
/**
|
|
257
267
|
* Check for spam patterns: too many emails from the same actor/user
|
|
258
|
-
* Returns actor IDs that sent too many emails
|
|
268
|
+
* Returns actor IDs that sent too many emails.
|
|
269
|
+
*
|
|
270
|
+
* NOTE: Analysis is limited to the most recent MAX_SPAM_DETECTION_LIMIT operations
|
|
271
|
+
* in the time window to avoid query read limit errors.
|
|
259
272
|
*/
|
|
260
273
|
export declare const detectActorSpam: import("convex/server").RegisteredQuery<"public", {
|
|
261
274
|
timeWindowMs: number;
|
|
@@ -266,7 +279,11 @@ export declare const detectActorSpam: import("convex/server").RegisteredQuery<"p
|
|
|
266
279
|
timeWindowMs: number;
|
|
267
280
|
}[]>>;
|
|
268
281
|
/**
|
|
269
|
-
* Get recent email operation statistics for monitoring
|
|
282
|
+
* Get recent email operation statistics for monitoring.
|
|
283
|
+
*
|
|
284
|
+
* NOTE: Statistics are calculated from the most recent MAX_SPAM_DETECTION_LIMIT
|
|
285
|
+
* operations in the time window to avoid query read limit errors. For high-volume
|
|
286
|
+
* applications, consider using scheduled jobs with pagination for exact statistics.
|
|
270
287
|
*/
|
|
271
288
|
export declare const getEmailStats: import("convex/server").RegisteredQuery<"public", {
|
|
272
289
|
timeWindowMs: number;
|
|
@@ -281,7 +298,10 @@ export declare const getEmailStats: import("convex/server").RegisteredQuery<"pub
|
|
|
281
298
|
}>>;
|
|
282
299
|
/**
|
|
283
300
|
* Detect rapid-fire email sending patterns (multiple emails sent in quick succession)
|
|
284
|
-
* Returns suspicious patterns indicating potential spam
|
|
301
|
+
* Returns suspicious patterns indicating potential spam.
|
|
302
|
+
*
|
|
303
|
+
* NOTE: Analysis is limited to the most recent MAX_SPAM_DETECTION_LIMIT operations
|
|
304
|
+
* in the time window to avoid query read limit errors.
|
|
285
305
|
*/
|
|
286
306
|
export declare const detectRapidFirePatterns: import("convex/server").RegisteredQuery<"public", {
|
|
287
307
|
timeWindowMs: number;
|
|
@@ -296,7 +316,10 @@ export declare const detectRapidFirePatterns: import("convex/server").Registered
|
|
|
296
316
|
}[]>>;
|
|
297
317
|
/**
|
|
298
318
|
* Rate limiting: Check if an email can be sent to a recipient
|
|
299
|
-
* Based on recent email operations in the database
|
|
319
|
+
* Based on recent email operations in the database.
|
|
320
|
+
*
|
|
321
|
+
* Uses efficient .take() query - only reads the minimum number of documents
|
|
322
|
+
* needed to determine if the rate limit is exceeded.
|
|
300
323
|
*/
|
|
301
324
|
export declare const checkRecipientRateLimit: import("convex/server").RegisteredQuery<"public", {
|
|
302
325
|
email: string;
|
|
@@ -312,7 +335,10 @@ export declare const checkRecipientRateLimit: import("convex/server").Registered
|
|
|
312
335
|
}>>;
|
|
313
336
|
/**
|
|
314
337
|
* Rate limiting: Check if an actor/user can send more emails
|
|
315
|
-
* Based on recent email operations in the database
|
|
338
|
+
* Based on recent email operations in the database.
|
|
339
|
+
*
|
|
340
|
+
* Uses efficient .take() query - only reads the minimum number of documents
|
|
341
|
+
* needed to determine if the rate limit is exceeded.
|
|
316
342
|
*/
|
|
317
343
|
export declare const checkActorRateLimit: import("convex/server").RegisteredQuery<"public", {
|
|
318
344
|
actorId: string;
|
|
@@ -327,7 +353,10 @@ export declare const checkActorRateLimit: import("convex/server").RegisteredQuer
|
|
|
327
353
|
}>>;
|
|
328
354
|
/**
|
|
329
355
|
* Rate limiting: Check global email sending rate
|
|
330
|
-
* Checks total email operations across all senders
|
|
356
|
+
* Checks total email operations across all senders.
|
|
357
|
+
*
|
|
358
|
+
* Uses efficient .take() query - only reads the minimum number of documents
|
|
359
|
+
* needed to determine if the rate limit is exceeded.
|
|
331
360
|
*/
|
|
332
361
|
export declare const checkGlobalRateLimit: import("convex/server").RegisteredQuery<"public", {
|
|
333
362
|
timeWindowMs: number;
|
|
@@ -338,4 +367,24 @@ export declare const checkGlobalRateLimit: import("convex/server").RegisteredQue
|
|
|
338
367
|
limit: number;
|
|
339
368
|
timeWindowMs: number;
|
|
340
369
|
}>>;
|
|
370
|
+
/**
|
|
371
|
+
* Backfill the contact aggregate with existing contacts.
|
|
372
|
+
* Run this mutation after upgrading to a version with aggregate support.
|
|
373
|
+
*
|
|
374
|
+
* This processes contacts in batches to avoid timeout issues with large datasets.
|
|
375
|
+
* Call repeatedly with the returned cursor until isDone is true.
|
|
376
|
+
*
|
|
377
|
+
* Usage:
|
|
378
|
+
* 1. First call with clear: true to reset the aggregate
|
|
379
|
+
* 2. Subsequent calls with the returned cursor until isDone is true
|
|
380
|
+
*/
|
|
381
|
+
export declare const backfillContactAggregate: import("convex/server").RegisteredMutation<"public", {
|
|
382
|
+
batchSize: number;
|
|
383
|
+
cursor?: string | null | undefined;
|
|
384
|
+
clear?: boolean | undefined;
|
|
385
|
+
}, Promise<{
|
|
386
|
+
processed: number;
|
|
387
|
+
cursor: string | null;
|
|
388
|
+
isDone: boolean;
|
|
389
|
+
}>>;
|
|
341
390
|
//# sourceMappingURL=lib.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../src/component/lib.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../src/component/lib.ts"],"names":[],"mappings":"AAkBA;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;iBA2DvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;;iBAiBxB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;iBAkC5B,CAAC;AAUH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa;;;;mBA8DxB,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;GAgGvB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;GA+GrB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;GAgDxB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;GAiD5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;GAyCpB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;GA0BxB,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW;;;;;;;;;GA4DtB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;GA4DtB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;GA8D9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;GA2B7B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;GA2B7B,CAAC;AASH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;KA8C9B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;KA4C1B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;GAkDxB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;KAsGlC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;GAiDlC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;GA+C9B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;GAiC/B,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;GAsCnC,CAAC"}
|