@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/types.d.ts
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export type
|
|
4
|
-
|
|
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
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,
|
|
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 {
|
|
2
|
-
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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.
|
|
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": "./
|
|
42
|
+
"default": "./dist/component/convex.config.js"
|
|
43
43
|
},
|
|
44
|
-
"./
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
|
|
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
|
},
|
package/src/client/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|