@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.
Files changed (37) hide show
  1. package/dist/client/index.d.ts +47 -12
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +42 -4
  4. package/dist/component/_generated/api.d.ts +185 -1
  5. package/dist/component/_generated/api.d.ts.map +1 -1
  6. package/dist/component/_generated/component.d.ts +12 -5
  7. package/dist/component/_generated/component.d.ts.map +1 -1
  8. package/dist/component/_generated/dataModel.d.ts +1 -1
  9. package/dist/component/aggregates.d.ts +42 -0
  10. package/dist/component/aggregates.d.ts.map +1 -0
  11. package/dist/component/aggregates.js +54 -0
  12. package/dist/component/convex.config.d.ts.map +1 -1
  13. package/dist/component/convex.config.js +2 -0
  14. package/dist/component/helpers.d.ts.map +1 -1
  15. package/dist/component/http.js +1 -1
  16. package/dist/component/lib.d.ts +66 -17
  17. package/dist/component/lib.d.ts.map +1 -1
  18. package/dist/component/lib.js +194 -73
  19. package/dist/component/schema.d.ts +2 -2
  20. package/dist/component/tables/contacts.d.ts.map +1 -1
  21. package/dist/component/tables/emailOperations.d.ts +4 -4
  22. package/dist/component/tables/emailOperations.d.ts.map +1 -1
  23. package/dist/test.d.ts +2 -2
  24. package/dist/types.d.ts +249 -62
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/types.js +4 -2
  27. package/dist/utils.d.ts +6 -6
  28. package/package.json +15 -9
  29. package/src/client/index.ts +52 -6
  30. package/src/component/_generated/api.ts +190 -1
  31. package/src/component/_generated/component.ts +10 -5
  32. package/src/component/_generated/dataModel.ts +1 -1
  33. package/src/component/aggregates.ts +89 -0
  34. package/src/component/convex.config.ts +3 -0
  35. package/src/component/http.ts +1 -1
  36. package/src/component/lib.ts +226 -89
  37. package/src/types.ts +20 -122
package/dist/types.d.ts CHANGED
@@ -1,26 +1,7 @@
1
- import type { Expand, FunctionArgs, FunctionReference, FunctionReturnType, StorageActionWriter, StorageReader } from "convex/server";
2
- import type { GenericId } from "convex/values";
3
- export type RunQueryCtx = {
4
- runQuery: <Query extends FunctionReference<"query", "internal">>(query: Query, args: FunctionArgs<Query>) => Promise<FunctionReturnType<Query>>;
5
- };
6
- export type RunMutationCtx = RunQueryCtx & {
7
- runMutation: <Mutation extends FunctionReference<"mutation", "internal">>(mutation: Mutation, args: FunctionArgs<Mutation>) => Promise<FunctionReturnType<Mutation>>;
8
- };
9
- export type RunActionCtx = RunMutationCtx & {
10
- runAction<Action extends FunctionReference<"action", "internal">>(action: Action, args: FunctionArgs<Action>): Promise<FunctionReturnType<Action>>;
11
- };
12
- export type ActionCtx = RunActionCtx & {
13
- storage: StorageActionWriter;
14
- };
15
- export type QueryCtx = RunQueryCtx & {
16
- storage: StorageReader;
17
- };
18
- export type OpaqueIds<T> = T extends GenericId<infer _T> ? string : T extends (infer U)[] ? OpaqueIds<U>[] : T extends ArrayBuffer ? ArrayBuffer : T extends object ? {
19
- [K in keyof T]: OpaqueIds<T[K]>;
20
- } : T;
21
- export type UseApi<API> = Expand<{
22
- [mod in keyof API]: API[mod] extends FunctionReference<infer FType, "public", infer FArgs, infer FReturnType, infer FComponentPath> ? FunctionReference<FType, "internal", OpaqueIds<FArgs>, OpaqueIds<FReturnType>, FComponentPath> : UseApi<API[mod]>;
23
- }>;
1
+ import type { GenericActionCtx, GenericDataModel, GenericMutationCtx, GenericQueryCtx } from "convex/server";
2
+ export type RunQueryCtx = Pick<GenericQueryCtx<GenericDataModel>, "runQuery">;
3
+ export type RunMutationCtx = Pick<GenericMutationCtx<GenericDataModel>, "runQuery" | "runMutation">;
4
+ export type RunActionCtx = Pick<GenericActionCtx<GenericDataModel>, "runQuery" | "runMutation" | "runAction">;
24
5
  export type HeadersInitParam = ConstructorParameters<typeof Headers>[0];
25
6
  export interface ContactPayload {
26
7
  email: string;
@@ -54,44 +35,250 @@ export interface TriggerPayload {
54
35
  dataVariables?: Record<string, unknown>;
55
36
  eventName?: string;
56
37
  }
57
- export type InternalActionRef<Args extends Record<string, unknown> = Record<string, unknown>, Result = unknown> = FunctionReference<"action", "internal", Args, Result>;
58
- export type InternalMutationRef<Args extends Record<string, unknown> = Record<string, unknown>, Result = unknown> = FunctionReference<"mutation", "internal", Args, Result>;
59
- export type InternalQueryRef<Args extends Record<string, unknown> = Record<string, unknown>, Result = unknown> = FunctionReference<"query", "internal", Args, Result>;
60
- type AddContactArgs = {
61
- apiKey: string;
62
- contact: ContactPayload;
63
- };
64
- type AddContactResult = {
65
- success: boolean;
66
- id?: string;
38
+ export declare const internalLib: {
39
+ storeContact: import("convex/server").FunctionReference<"mutation", "public", {
40
+ email: string;
41
+ firstName?: string | undefined;
42
+ lastName?: string | undefined;
43
+ userId?: string | undefined;
44
+ source?: string | undefined;
45
+ subscribed?: boolean | undefined;
46
+ userGroup?: string | undefined;
47
+ loopsContactId?: string | undefined;
48
+ }, null, string | undefined>;
49
+ removeContact: import("convex/server").FunctionReference<"mutation", "public", {
50
+ email: string;
51
+ }, null, string | undefined>;
52
+ logEmailOperation: import("convex/server").FunctionReference<"mutation", "public", {
53
+ operationType: "transactional" | "event" | "campaign" | "loop";
54
+ email: string;
55
+ success: boolean;
56
+ actorId?: string | undefined;
57
+ transactionalId?: string | undefined;
58
+ campaignId?: string | undefined;
59
+ loopId?: string | undefined;
60
+ eventName?: string | undefined;
61
+ messageId?: string | undefined;
62
+ metadata?: Record<string, any> | undefined;
63
+ }, null, string | undefined>;
64
+ countContacts: import("convex/server").FunctionReference<"query", "public", {
65
+ userGroup?: string | undefined;
66
+ source?: string | undefined;
67
+ subscribed?: boolean | undefined;
68
+ }, number, string | undefined>;
69
+ listContacts: import("convex/server").FunctionReference<"query", "public", {
70
+ limit: number;
71
+ userGroup?: string | undefined;
72
+ source?: string | undefined;
73
+ subscribed?: boolean | undefined;
74
+ cursor?: string | null | undefined;
75
+ }, {
76
+ contacts: {
77
+ _id: string;
78
+ email: string;
79
+ subscribed: boolean;
80
+ createdAt: number;
81
+ updatedAt: number;
82
+ firstName?: string | undefined;
83
+ lastName?: string | undefined;
84
+ userId?: string | undefined;
85
+ source?: string | undefined;
86
+ userGroup?: string | undefined;
87
+ loopsContactId?: string | undefined;
88
+ }[];
89
+ continueCursor: string | null;
90
+ isDone: boolean;
91
+ }, string | undefined>;
92
+ addContact: import("convex/server").FunctionReference<"action", "public", {
93
+ apiKey: string;
94
+ contact: {
95
+ email: string;
96
+ firstName?: string | undefined;
97
+ lastName?: string | undefined;
98
+ userId?: string | undefined;
99
+ source?: string | undefined;
100
+ subscribed?: boolean | undefined;
101
+ userGroup?: string | undefined;
102
+ };
103
+ }, {
104
+ success: boolean;
105
+ id?: string | undefined;
106
+ }, string | undefined>;
107
+ updateContact: import("convex/server").FunctionReference<"action", "public", {
108
+ apiKey: string;
109
+ email: string;
110
+ dataVariables?: Record<string, any> | undefined;
111
+ firstName?: string | undefined;
112
+ lastName?: string | undefined;
113
+ userId?: string | undefined;
114
+ source?: string | undefined;
115
+ subscribed?: boolean | undefined;
116
+ userGroup?: string | undefined;
117
+ }, {
118
+ success: boolean;
119
+ }, string | undefined>;
120
+ sendTransactional: import("convex/server").FunctionReference<"action", "public", {
121
+ apiKey: string;
122
+ transactionalId: string;
123
+ email: string;
124
+ dataVariables?: Record<string, any> | undefined;
125
+ }, {
126
+ success: boolean;
127
+ messageId?: string | undefined;
128
+ }, string | undefined>;
129
+ sendEvent: import("convex/server").FunctionReference<"action", "public", {
130
+ apiKey: string;
131
+ email: string;
132
+ eventName: string;
133
+ eventProperties?: Record<string, any> | undefined;
134
+ }, {
135
+ success: boolean;
136
+ }, string | undefined>;
137
+ deleteContact: import("convex/server").FunctionReference<"action", "public", {
138
+ apiKey: string;
139
+ email: string;
140
+ }, {
141
+ success: boolean;
142
+ }, string | undefined>;
143
+ triggerLoop: import("convex/server").FunctionReference<"action", "public", {
144
+ apiKey: string;
145
+ loopId: string;
146
+ email: string;
147
+ dataVariables?: Record<string, any> | undefined;
148
+ eventName?: string | undefined;
149
+ }, {
150
+ success: boolean;
151
+ warning?: string | undefined;
152
+ }, string | undefined>;
153
+ findContact: import("convex/server").FunctionReference<"action", "public", {
154
+ apiKey: string;
155
+ email: string;
156
+ }, {
157
+ success: boolean;
158
+ contact?: {
159
+ id?: string | null | undefined;
160
+ email?: string | null | undefined;
161
+ firstName?: string | null | undefined;
162
+ lastName?: string | null | undefined;
163
+ source?: string | null | undefined;
164
+ subscribed?: boolean | null | undefined;
165
+ userGroup?: string | null | undefined;
166
+ userId?: string | null | undefined;
167
+ createdAt?: string | null | undefined;
168
+ } | undefined;
169
+ }, string | undefined>;
170
+ batchCreateContacts: import("convex/server").FunctionReference<"action", "public", {
171
+ apiKey: string;
172
+ contacts: {
173
+ email: string;
174
+ firstName?: string | undefined;
175
+ lastName?: string | undefined;
176
+ userId?: string | undefined;
177
+ source?: string | undefined;
178
+ subscribed?: boolean | undefined;
179
+ userGroup?: string | undefined;
180
+ }[];
181
+ }, {
182
+ success: boolean;
183
+ created?: number | undefined;
184
+ failed?: number | undefined;
185
+ results?: {
186
+ email: string;
187
+ success: boolean;
188
+ error?: string | undefined;
189
+ }[] | undefined;
190
+ }, string | undefined>;
191
+ unsubscribeContact: import("convex/server").FunctionReference<"action", "public", {
192
+ apiKey: string;
193
+ email: string;
194
+ }, {
195
+ success: boolean;
196
+ }, string | undefined>;
197
+ resubscribeContact: import("convex/server").FunctionReference<"action", "public", {
198
+ apiKey: string;
199
+ email: string;
200
+ }, {
201
+ success: boolean;
202
+ }, string | undefined>;
203
+ detectRecipientSpam: import("convex/server").FunctionReference<"query", "public", {
204
+ timeWindowMs: number;
205
+ maxEmailsPerRecipient: number;
206
+ }, {
207
+ [x: string]: any;
208
+ email: string;
209
+ count: number;
210
+ timeWindowMs: number;
211
+ }[], string | undefined>;
212
+ detectActorSpam: import("convex/server").FunctionReference<"query", "public", {
213
+ timeWindowMs: number;
214
+ maxEmailsPerActor: number;
215
+ }, {
216
+ actorId: string;
217
+ count: number;
218
+ timeWindowMs: number;
219
+ }[], string | undefined>;
220
+ getEmailStats: import("convex/server").FunctionReference<"query", "public", {
221
+ timeWindowMs: number;
222
+ }, {
223
+ [x: string]: any;
224
+ totalOperations: number;
225
+ successfulOperations: number;
226
+ failedOperations: number;
227
+ operationsByType: Record<string, number>;
228
+ uniqueRecipients: number;
229
+ uniqueActors: number;
230
+ }, string | undefined>;
231
+ detectRapidFirePatterns: import("convex/server").FunctionReference<"query", "public", {
232
+ timeWindowMs: number;
233
+ minEmailsInWindow: number;
234
+ }, {
235
+ count: number;
236
+ timeWindowMs: number;
237
+ firstTimestamp: number;
238
+ lastTimestamp: number;
239
+ email?: string | undefined;
240
+ actorId?: string | undefined;
241
+ }[], string | undefined>;
242
+ checkRecipientRateLimit: import("convex/server").FunctionReference<"query", "public", {
243
+ email: string;
244
+ timeWindowMs: number;
245
+ maxEmails: number;
246
+ }, {
247
+ [x: string]: any;
248
+ allowed: boolean;
249
+ count: number;
250
+ limit: number;
251
+ timeWindowMs: number;
252
+ retryAfter?: number | undefined;
253
+ }, string | undefined>;
254
+ checkActorRateLimit: import("convex/server").FunctionReference<"query", "public", {
255
+ actorId: string;
256
+ timeWindowMs: number;
257
+ maxEmails: number;
258
+ }, {
259
+ allowed: boolean;
260
+ count: number;
261
+ limit: number;
262
+ timeWindowMs: number;
263
+ retryAfter?: number | undefined;
264
+ }, string | undefined>;
265
+ checkGlobalRateLimit: import("convex/server").FunctionReference<"query", "public", {
266
+ timeWindowMs: number;
267
+ maxEmails: number;
268
+ }, {
269
+ allowed: boolean;
270
+ count: number;
271
+ limit: number;
272
+ timeWindowMs: number;
273
+ }, string | undefined>;
274
+ backfillContactAggregate: import("convex/server").FunctionReference<"mutation", "public", {
275
+ batchSize: number;
276
+ cursor?: string | null | undefined;
277
+ clear?: boolean | undefined;
278
+ }, {
279
+ processed: number;
280
+ cursor: string | null;
281
+ isDone: boolean;
282
+ }, string | undefined>;
67
283
  };
68
- export interface InternalActionLib {
69
- addContact: InternalActionRef<AddContactArgs, AddContactResult>;
70
- updateContact: InternalActionRef;
71
- findContact: InternalActionRef;
72
- deleteContact: InternalActionRef;
73
- sendTransactional: InternalActionRef;
74
- sendEvent: InternalActionRef;
75
- triggerLoop: InternalActionRef;
76
- batchCreateContacts: InternalActionRef;
77
- unsubscribeContact: InternalActionRef;
78
- resubscribeContact: InternalActionRef;
79
- storeContact: InternalMutationRef;
80
- removeContact: InternalMutationRef;
81
- logEmailOperation: InternalMutationRef;
82
- }
83
- export interface InternalQueryLib {
84
- countContacts: InternalQueryRef;
85
- listContacts: InternalQueryRef;
86
- detectRecipientSpam: InternalQueryRef;
87
- detectActorSpam: InternalQueryRef;
88
- getEmailStats: InternalQueryRef;
89
- detectRapidFirePatterns: InternalQueryRef;
90
- checkRecipientRateLimit: InternalQueryRef;
91
- checkActorRateLimit: InternalQueryRef;
92
- checkGlobalRateLimit: InternalQueryRef;
93
- }
94
- export type InternalLibReferences = InternalActionLib & InternalQueryLib;
95
- export declare const internalLib: InternalLibReferences;
96
- export {};
97
284
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,MAAM,EACN,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,MAAM,MAAM,WAAW,GAAG;IACzB,QAAQ,EAAE,CAAC,KAAK,SAAS,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC,EAC9D,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,KACrB,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IAC1C,WAAW,EAAE,CAAC,QAAQ,SAAS,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,EACvE,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC,KACxB,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG;IAC3C,SAAS,CAAC,MAAM,SAAS,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,EAC/D,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,GACxB,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG;IACtC,OAAO,EAAE,mBAAmB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG;IACpC,OAAO,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,EAAE,CAAC,GACrD,MAAM,GACN,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACpB,SAAS,CAAC,CAAC,CAAC,EAAE,GACd,CAAC,SAAS,WAAW,GACpB,WAAW,GACX,CAAC,SAAS,MAAM,GACf;KACC,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/B,GACA,CAAC,CAAC;AAER,MAAM,MAAM,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC;KAC/B,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,iBAAiB,CACrD,MAAM,KAAK,EACX,QAAQ,EACR,MAAM,KAAK,EACX,MAAM,WAAW,EACjB,MAAM,cAAc,CACpB,GACE,iBAAiB,CACjB,KAAK,EACL,UAAU,EACV,SAAS,CAAC,KAAK,CAAC,EAChB,SAAS,CAAC,WAAW,CAAC,EACtB,cAAc,CACd,GACA,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAExE,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAqB,SAAQ,OAAO,CAAC,cAAc,CAAC;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,iBAAiB,CAC5B,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,MAAM,GAAG,OAAO,IACb,iBAAiB,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAE1D,MAAM,MAAM,mBAAmB,CAC9B,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,MAAM,GAAG,OAAO,IACb,iBAAiB,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAE5D,MAAM,MAAM,gBAAgB,CAC3B,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,MAAM,GAAG,OAAO,IACb,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAEzD,KAAK,cAAc,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,CAAC;CACxB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,iBAAiB,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAChE,aAAa,EAAE,iBAAiB,CAAC;IACjC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,aAAa,EAAE,iBAAiB,CAAC;IACjC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,mBAAmB,EAAE,iBAAiB,CAAC;IACvC,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,YAAY,EAAE,mBAAmB,CAAC;IAClC,aAAa,EAAE,mBAAmB,CAAC;IACnC,iBAAiB,EAAE,mBAAmB,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAChC,aAAa,EAAE,gBAAgB,CAAC;IAChC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,mBAAmB,EAAE,gBAAgB,CAAC;IACtC,eAAe,EAAE,gBAAgB,CAAC;IAClC,aAAa,EAAE,gBAAgB,CAAC;IAChC,uBAAuB,EAAE,gBAAgB,CAAC;IAC1C,uBAAuB,EAAE,gBAAgB,CAAC;IAC1C,mBAAmB,EAAE,gBAAgB,CAAC;IACtC,oBAAoB,EAAE,gBAAgB,CAAC;CACvC;AAED,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEzE,eAAO,MAAM,WAAW,uBAEnB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,MAAM,eAAe,CAAC;AAIvB,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG,IAAI,CAChC,kBAAkB,CAAC,gBAAgB,CAAC,EACpC,UAAU,GAAG,aAAa,CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,IAAI,CAC9B,gBAAgB,CAAC,gBAAgB,CAAC,EAClC,UAAU,GAAG,aAAa,GAAG,WAAW,CACxC,CAAC;AAGF,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAGxE,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAqB,SAAQ,OAAO,CAAC,cAAc,CAAC;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAU,CAAC"}
package/dist/types.js CHANGED
@@ -1,2 +1,4 @@
1
- import { internal } from "./component/_generated/api";
2
- export const internalLib = internal.lib;
1
+ import { api } from "./component/_generated/api";
2
+ // Lib reference for component internals
3
+ // This is used internally by the component to call its own functions
4
+ export const internalLib = api.lib;
package/dist/utils.d.ts CHANGED
@@ -33,19 +33,19 @@ export declare const zq: <A extends import("zod").ZodType | Record<string, impor
33
33
  document: {
34
34
  _id: import("convex/values").GenericId<"emailOperations">;
35
35
  _creationTime: number;
36
- metadata?: Record<string, any> | undefined;
37
36
  actorId?: string | undefined;
38
37
  transactionalId?: string | undefined;
39
38
  campaignId?: string | undefined;
40
39
  loopId?: string | undefined;
41
40
  eventName?: string | undefined;
42
41
  messageId?: string | undefined;
42
+ metadata?: Record<string, any> | undefined;
43
43
  email: string;
44
44
  success: boolean;
45
45
  operationType: "transactional" | "event" | "campaign" | "loop";
46
46
  timestamp: number;
47
47
  };
48
- fieldPaths: ("email" | "success" | "metadata" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "_creationTime" | `metadata.${string}`) | "_id";
48
+ fieldPaths: ("email" | "success" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "metadata" | "_creationTime" | `metadata.${string}`) | "_id";
49
49
  indexes: {
50
50
  email: ["email", "timestamp", "_creationTime"];
51
51
  actorId: ["actorId", "timestamp", "_creationTime"];
@@ -95,19 +95,19 @@ export declare const zm: <A extends import("zod").ZodType | Record<string, impor
95
95
  document: {
96
96
  _id: import("convex/values").GenericId<"emailOperations">;
97
97
  _creationTime: number;
98
- metadata?: Record<string, any> | undefined;
99
98
  actorId?: string | undefined;
100
99
  transactionalId?: string | undefined;
101
100
  campaignId?: string | undefined;
102
101
  loopId?: string | undefined;
103
102
  eventName?: string | undefined;
104
103
  messageId?: string | undefined;
104
+ metadata?: Record<string, any> | undefined;
105
105
  email: string;
106
106
  success: boolean;
107
107
  operationType: "transactional" | "event" | "campaign" | "loop";
108
108
  timestamp: number;
109
109
  };
110
- fieldPaths: ("email" | "success" | "metadata" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "_creationTime" | `metadata.${string}`) | "_id";
110
+ fieldPaths: ("email" | "success" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "metadata" | "_creationTime" | `metadata.${string}`) | "_id";
111
111
  indexes: {
112
112
  email: ["email", "timestamp", "_creationTime"];
113
113
  actorId: ["actorId", "timestamp", "_creationTime"];
@@ -157,19 +157,19 @@ export declare const za: <A extends import("zod").ZodType | Record<string, impor
157
157
  document: {
158
158
  _id: import("convex/values").GenericId<"emailOperations">;
159
159
  _creationTime: number;
160
- metadata?: Record<string, any> | undefined;
161
160
  actorId?: string | undefined;
162
161
  transactionalId?: string | undefined;
163
162
  campaignId?: string | undefined;
164
163
  loopId?: string | undefined;
165
164
  eventName?: string | undefined;
166
165
  messageId?: string | undefined;
166
+ metadata?: Record<string, any> | undefined;
167
167
  email: string;
168
168
  success: boolean;
169
169
  operationType: "transactional" | "event" | "campaign" | "loop";
170
170
  timestamp: number;
171
171
  };
172
- fieldPaths: ("email" | "success" | "metadata" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "_creationTime" | `metadata.${string}`) | "_id";
172
+ fieldPaths: ("email" | "success" | "operationType" | "actorId" | "transactionalId" | "campaignId" | "loopId" | "eventName" | "timestamp" | "messageId" | "metadata" | "_creationTime" | `metadata.${string}`) | "_id";
173
173
  indexes: {
174
174
  email: ["email", "timestamp", "_creationTime"];
175
175
  actorId: ["actorId", "timestamp", "_creationTime"];
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@devwithbobby/loops",
3
- "version": "0.1.19",
3
+ "version": "0.2.0",
4
4
  "description": "Convex component for integrating with Loops.so email marketing platform",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
+ "main": "dist/client/index.js",
8
+ "types": "dist/client/index.d.ts",
7
9
  "keywords": [
8
10
  "convex",
9
11
  "component",
@@ -32,19 +34,22 @@
32
34
  "exports": {
33
35
  "./package.json": "./package.json",
34
36
  ".": {
35
- "@convex-dev/component-source": "./src/client/index.ts",
36
37
  "types": "./dist/client/index.d.ts",
37
38
  "default": "./dist/client/index.js"
38
39
  },
39
40
  "./convex.config": {
40
- "@convex-dev/component-source": "./src/component/convex.config.ts",
41
41
  "types": "./dist/component/convex.config.d.ts",
42
- "default": "./src/component/convex.config.ts"
42
+ "default": "./dist/component/convex.config.js"
43
43
  },
44
- "./component": {
45
- "@convex-dev/component-source": "./src/component/_generated/component.ts",
46
- "types": "./dist/component/_generated/component.d.ts",
47
- "default": "./dist/component/_generated/component.js"
44
+ "./convex.config.js": {
45
+ "types": "./dist/component/convex.config.d.ts",
46
+ "default": "./dist/component/convex.config.js"
47
+ },
48
+ "./_generated/component": {
49
+ "types": "./dist/component/_generated/component.d.ts"
50
+ },
51
+ "./_generated/component.js": {
52
+ "types": "./dist/component/_generated/component.d.ts"
48
53
  },
49
54
  "./test": "./src/test.ts"
50
55
  },
@@ -65,7 +70,7 @@
65
70
  "check": "biome check .",
66
71
  "check:fix": "biome check --write .",
67
72
  "typecheck": "tsc --noEmit",
68
- "attw": "attw $(npm pack -s) --exclude-entrypoints ./convex.config --profile esm-only",
73
+ "attw": "attw $(npm pack -s) --exclude-entrypoints ./convex.config ./test --profile esm-only --ignore-rules internal-resolution-error",
69
74
  "prepare": "npm run build || true",
70
75
  "changeset": "changeset",
71
76
  "ci:version": "changeset version && bun update",
@@ -77,6 +82,7 @@
77
82
  "release": "bun run preversion && npm version patch && npm publish"
78
83
  },
79
84
  "dependencies": {
85
+ "@convex-dev/aggregate": "^0.2.1",
80
86
  "zod": "^4.1.12",
81
87
  "zodvex": "^0.2.3"
82
88
  },
@@ -1,7 +1,7 @@
1
- import { actionGeneric, queryGeneric } from "convex/server";
1
+ import { actionGeneric, mutationGeneric, queryGeneric } from "convex/server";
2
2
  import { v } from "convex/values";
3
3
  import type { ComponentApi } from "../component/_generated/component.js";
4
- import type { RunActionCtx, RunQueryCtx } from "../types";
4
+ import type { RunActionCtx, RunMutationCtx, RunQueryCtx } from "../types";
5
5
 
6
6
  export type LoopsComponent = ComponentApi;
7
7
 
@@ -195,9 +195,12 @@ export class Loops {
195
195
  }
196
196
 
197
197
  /**
198
- * List contacts with pagination and optional filters
198
+ * List contacts with cursor-based pagination and optional filters
199
199
  * Returns actual contact data, not just a count
200
200
  * This queries the component's local database, not Loops API
201
+ *
202
+ * Uses cursor-based pagination for efficiency. Pass the `continueCursor`
203
+ * from the previous response as `cursor` to get the next page.
201
204
  */
202
205
  async listContacts(
203
206
  ctx: RunQueryCtx,
@@ -206,7 +209,7 @@ export class Loops {
206
209
  source?: string;
207
210
  subscribed?: boolean;
208
211
  limit?: number;
209
- offset?: number;
212
+ cursor?: string | null;
210
213
  },
211
214
  ) {
212
215
  return ctx.runQuery(this.lib.listContacts, {
@@ -214,7 +217,7 @@ export class Loops {
214
217
  source: options?.source,
215
218
  subscribed: options?.subscribed,
216
219
  limit: options?.limit ?? 100,
217
- offset: options?.offset ?? 0,
220
+ cursor: options?.cursor ?? null,
218
221
  });
219
222
  }
220
223
 
@@ -356,6 +359,39 @@ export class Loops {
356
359
  });
357
360
  }
358
361
 
362
+ /**
363
+ * Backfill the contact aggregate with existing contacts.
364
+ * Run this after upgrading to a version with aggregate support.
365
+ *
366
+ * This processes contacts in batches to avoid timeout issues with large datasets.
367
+ * Call repeatedly with the returned cursor until isDone is true.
368
+ *
369
+ * Usage:
370
+ * ```ts
371
+ * // First call - clear existing aggregate and start backfill
372
+ * let result = await loops.backfillContactAggregate(ctx, { clear: true });
373
+ *
374
+ * // Continue until done
375
+ * while (!result.isDone) {
376
+ * result = await loops.backfillContactAggregate(ctx, { cursor: result.cursor });
377
+ * }
378
+ * ```
379
+ */
380
+ async backfillContactAggregate(
381
+ ctx: RunMutationCtx,
382
+ options?: {
383
+ cursor?: string | null;
384
+ batchSize?: number;
385
+ clear?: boolean;
386
+ },
387
+ ) {
388
+ return ctx.runMutation(this.lib.backfillContactAggregate, {
389
+ cursor: options?.cursor ?? null,
390
+ batchSize: options?.batchSize ?? 100,
391
+ clear: options?.clear,
392
+ });
393
+ }
394
+
359
395
  /**
360
396
  * For easy re-exporting.
361
397
  * Apps can do
@@ -491,7 +527,7 @@ export class Loops {
491
527
  source: v.optional(v.string()),
492
528
  subscribed: v.optional(v.boolean()),
493
529
  limit: v.optional(v.number()),
494
- offset: v.optional(v.number()),
530
+ cursor: v.optional(v.union(v.string(), v.null())),
495
531
  },
496
532
  handler: async (ctx, args) => {
497
533
  return await this.listContacts(ctx, args);
@@ -561,6 +597,16 @@ export class Loops {
561
597
  return await this.checkGlobalRateLimit(ctx, args);
562
598
  },
563
599
  }),
600
+ backfillContactAggregate: mutationGeneric({
601
+ args: {
602
+ cursor: v.optional(v.union(v.string(), v.null())),
603
+ batchSize: v.optional(v.number()),
604
+ clear: v.optional(v.boolean()),
605
+ },
606
+ handler: async (ctx, args) => {
607
+ return await this.backfillContactAggregate(ctx, args);
608
+ },
609
+ }),
564
610
  };
565
611
  }
566
612
  }