@devwithbobby/loops 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,14 +2,13 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@devwithbobby/loops.svg)](https://www.npmjs.com/package/@devwithbobby/loops)
4
4
 
5
- A Convex component for integrating with [Loops.so](https://loops.so) email marketing platform. Send transactional emails, manage contacts, trigger campaigns and loops, and monitor email operations with built-in spam detection and rate limiting.
5
+ A Convex component for integrating with [Loops.so](https://loops.so) email marketing platform. Send transactional emails, manage contacts, trigger loops, and monitor email operations with built-in spam detection and rate limiting.
6
6
 
7
7
  ## Features
8
8
 
9
9
  - ✅ **Contact Management** - Create, update, find, and delete contacts
10
10
  - ✅ **Transactional Emails** - Send one-off emails with templates
11
11
  - ✅ **Events** - Trigger email workflows based on events
12
- - ✅ **Campaigns** - Send campaigns to audiences or specific contacts
13
12
  - ✅ **Loops** - Trigger automated email sequences
14
13
  - ✅ **Monitoring** - Track all email operations with spam detection
15
14
  - ✅ **Rate Limiting** - Built-in rate limiting queries for abuse prevention
@@ -201,26 +200,6 @@ await loops.sendEvent(ctx, {
201
200
  });
202
201
  ```
203
202
 
204
- #### Send Campaign
205
-
206
- ```typescript
207
- // Send to specific emails
208
- await loops.sendCampaign(ctx, {
209
- campaignId: "campaign-id-from-loops",
210
- emails: ["user1@example.com", "user2@example.com"],
211
- dataVariables: { discount: "20%" },
212
- });
213
-
214
- // Send to audience
215
- await loops.sendCampaign(ctx, {
216
- campaignId: "campaign-id-from-loops",
217
- audienceFilters: {
218
- userGroup: "premium",
219
- source: "webapp",
220
- },
221
- });
222
- ```
223
-
224
203
  #### Trigger Loop (Automated Sequence)
225
204
 
226
205
  ```typescript
@@ -354,7 +333,6 @@ export const {
354
333
  updateContact,
355
334
  sendTransactional,
356
335
  sendEvent,
357
- sendCampaign,
358
336
  triggerLoop,
359
337
  countContacts,
360
338
  // ... all other functions
@@ -488,7 +466,6 @@ This component implements the following Loops.so API endpoints:
488
466
  - ✅ Count Contacts (custom implementation)
489
467
  - ✅ Send Transactional Email
490
468
  - ✅ Send Event
491
- - ✅ Send Campaign
492
469
  - ✅ Trigger Loop
493
470
 
494
471
  ## Contributing
@@ -32,41 +32,41 @@ export declare class Loops {
32
32
  /**
33
33
  * Add or update a contact in Loops
34
34
  */
35
- addContact(ctx: RunActionCtx, contact: ContactData): Promise<FunctionReturnType<Action>>;
35
+ addContact(ctx: RunActionCtx, contact: ContactData): Promise<any>;
36
36
  /**
37
37
  * Update an existing contact in Loops
38
38
  */
39
39
  updateContact(ctx: RunActionCtx, email: string, updates: Partial<ContactData> & {
40
40
  dataVariables?: Record<string, any>;
41
- }): Promise<FunctionReturnType<Action>>;
41
+ }): Promise<any>;
42
42
  /**
43
43
  * Send a transactional email using a transactional ID
44
44
  */
45
- sendTransactional(ctx: RunActionCtx, options: TransactionalEmailOptions): Promise<FunctionReturnType<Action>>;
45
+ sendTransactional(ctx: RunActionCtx, options: TransactionalEmailOptions): Promise<any>;
46
46
  /**
47
47
  * Send an event to Loops to trigger email workflows
48
48
  */
49
- sendEvent(ctx: RunActionCtx, options: EventOptions): Promise<FunctionReturnType<Action>>;
49
+ sendEvent(ctx: RunActionCtx, options: EventOptions): Promise<any>;
50
50
  /**
51
51
  * Find a contact by email
52
52
  * Retrieves contact information from Loops
53
53
  */
54
- findContact(ctx: RunActionCtx, email: string): Promise<FunctionReturnType<Action>>;
54
+ findContact(ctx: RunActionCtx, email: string): Promise<any>;
55
55
  /**
56
56
  * Batch create contacts
57
57
  * Create multiple contacts in a single API call
58
58
  */
59
- batchCreateContacts(ctx: RunActionCtx, contacts: ContactData[]): Promise<FunctionReturnType<Action>>;
59
+ batchCreateContacts(ctx: RunActionCtx, contacts: ContactData[]): Promise<any>;
60
60
  /**
61
61
  * Unsubscribe a contact
62
62
  * Unsubscribes a contact from receiving emails (they remain in the system)
63
63
  */
64
- unsubscribeContact(ctx: RunActionCtx, email: string): Promise<FunctionReturnType<Action>>;
64
+ unsubscribeContact(ctx: RunActionCtx, email: string): Promise<any>;
65
65
  /**
66
66
  * Resubscribe a contact
67
67
  * Resubscribes a previously unsubscribed contact
68
68
  */
69
- resubscribeContact(ctx: RunActionCtx, email: string): Promise<FunctionReturnType<Action>>;
69
+ resubscribeContact(ctx: RunActionCtx, email: string): Promise<any>;
70
70
  /**
71
71
  * Count contacts in the database
72
72
  * Can filter by audience criteria (userGroup, source, subscribed status)
@@ -76,34 +76,46 @@ export declare class Loops {
76
76
  userGroup?: string;
77
77
  source?: string;
78
78
  subscribed?: boolean;
79
- }): Promise<FunctionReturnType<Query>>;
79
+ }): Promise<any>;
80
+ /**
81
+ * List contacts with pagination and optional filters
82
+ * Returns actual contact data, not just a count
83
+ * This queries the component's local database, not Loops API
84
+ */
85
+ listContacts(ctx: RunQueryCtx, options?: {
86
+ userGroup?: string;
87
+ source?: string;
88
+ subscribed?: boolean;
89
+ limit?: number;
90
+ offset?: number;
91
+ }): Promise<any>;
80
92
  /**
81
93
  * Detect spam patterns: emails sent to the same recipient too frequently
82
94
  */
83
95
  detectRecipientSpam(ctx: RunQueryCtx, options?: {
84
96
  timeWindowMs?: number;
85
97
  maxEmailsPerRecipient?: number;
86
- }): Promise<FunctionReturnType<Query>>;
98
+ }): Promise<any>;
87
99
  /**
88
100
  * Detect spam patterns: emails sent by the same actor/user too frequently
89
101
  */
90
102
  detectActorSpam(ctx: RunQueryCtx, options?: {
91
103
  timeWindowMs?: number;
92
104
  maxEmailsPerActor?: number;
93
- }): Promise<FunctionReturnType<Query>>;
105
+ }): Promise<any>;
94
106
  /**
95
107
  * Get email operation statistics for monitoring
96
108
  */
97
109
  getEmailStats(ctx: RunQueryCtx, options?: {
98
110
  timeWindowMs?: number;
99
- }): Promise<FunctionReturnType<Query>>;
111
+ }): Promise<any>;
100
112
  /**
101
113
  * Detect rapid-fire email sending patterns
102
114
  */
103
115
  detectRapidFirePatterns(ctx: RunQueryCtx, options?: {
104
116
  timeWindowMs?: number;
105
117
  minEmailsInWindow?: number;
106
- }): Promise<FunctionReturnType<Query>>;
118
+ }): Promise<any>;
107
119
  /**
108
120
  * Check if an email can be sent to a recipient based on rate limits
109
121
  */
@@ -111,7 +123,7 @@ export declare class Loops {
111
123
  email: string;
112
124
  timeWindowMs: number;
113
125
  maxEmails: number;
114
- }): Promise<FunctionReturnType<Query>>;
126
+ }): Promise<any>;
115
127
  /**
116
128
  * Check if an actor/user can send more emails based on rate limits
117
129
  */
@@ -119,32 +131,18 @@ export declare class Loops {
119
131
  actorId: string;
120
132
  timeWindowMs: number;
121
133
  maxEmails: number;
122
- }): Promise<FunctionReturnType<Query>>;
134
+ }): Promise<any>;
123
135
  /**
124
136
  * Check global email sending rate limit
125
137
  */
126
138
  checkGlobalRateLimit(ctx: RunQueryCtx, options: {
127
139
  timeWindowMs: number;
128
140
  maxEmails: number;
129
- }): Promise<FunctionReturnType<Query>>;
141
+ }): Promise<any>;
130
142
  /**
131
143
  * Delete a contact from Loops
132
144
  */
133
- deleteContact(ctx: RunActionCtx, email: string): Promise<FunctionReturnType<Action>>;
134
- /**
135
- * Send a campaign to contacts
136
- * Campaigns are one-time email sends to a segment or list of contacts
137
- */
138
- sendCampaign(ctx: RunActionCtx, options: {
139
- campaignId: string;
140
- emails?: string[];
141
- transactionalId?: string;
142
- dataVariables?: Record<string, any>;
143
- audienceFilters?: {
144
- userGroup?: string;
145
- source?: string;
146
- };
147
- }): Promise<FunctionReturnType<Action>>;
145
+ deleteContact(ctx: RunActionCtx, email: string): Promise<any>;
148
146
  /**
149
147
  * Trigger a loop for a contact
150
148
  * Loops are automated email sequences that can be triggered by events
@@ -160,34 +158,106 @@ export declare class Loops {
160
158
  email: string;
161
159
  dataVariables?: Record<string, any>;
162
160
  eventName?: string;
163
- }): Promise<FunctionReturnType<Action>>;
161
+ }): Promise<any>;
164
162
  /**
165
163
  * For easy re-exporting.
166
164
  * Apps can do
167
165
  * ```ts
168
- * export const { addContact, sendTransactional, sendEvent, sendCampaign, triggerLoop } = loops.api();
166
+ * export const { addContact, sendTransactional, sendEvent, triggerLoop } = loops.api();
169
167
  * ```
170
168
  */
171
169
  api(): {
172
- addContact: any;
173
- updateContact: any;
174
- sendTransactional: any;
175
- sendEvent: any;
176
- deleteContact: any;
177
- sendCampaign: any;
178
- triggerLoop: any;
179
- findContact: any;
180
- batchCreateContacts: any;
181
- unsubscribeContact: any;
182
- resubscribeContact: any;
183
- countContacts: any;
184
- detectRecipientSpam: any;
185
- detectActorSpam: any;
186
- getEmailStats: any;
187
- detectRapidFirePatterns: any;
188
- checkRecipientRateLimit: any;
189
- checkActorRateLimit: any;
190
- checkGlobalRateLimit: any;
170
+ addContact: import("convex/server").RegisteredAction<"public", {
171
+ firstName?: string | undefined;
172
+ lastName?: string | undefined;
173
+ userId?: string | undefined;
174
+ source?: string | undefined;
175
+ subscribed?: boolean | undefined;
176
+ userGroup?: string | undefined;
177
+ email: string;
178
+ }, Promise<any>>;
179
+ updateContact: import("convex/server").RegisteredAction<"public", {
180
+ firstName?: string | undefined;
181
+ lastName?: string | undefined;
182
+ userId?: string | undefined;
183
+ source?: string | undefined;
184
+ subscribed?: boolean | undefined;
185
+ userGroup?: string | undefined;
186
+ dataVariables?: any;
187
+ email: string;
188
+ }, Promise<any>>;
189
+ sendTransactional: import("convex/server").RegisteredAction<"public", {
190
+ dataVariables?: any;
191
+ email: string;
192
+ transactionalId: string;
193
+ }, Promise<any>>;
194
+ sendEvent: import("convex/server").RegisteredAction<"public", {
195
+ eventProperties?: any;
196
+ email: string;
197
+ eventName: string;
198
+ }, Promise<any>>;
199
+ deleteContact: import("convex/server").RegisteredAction<"public", {
200
+ email: string;
201
+ }, Promise<any>>;
202
+ triggerLoop: import("convex/server").RegisteredAction<"public", {
203
+ dataVariables?: any;
204
+ email: string;
205
+ loopId: string;
206
+ }, Promise<any>>;
207
+ findContact: import("convex/server").RegisteredAction<"public", {
208
+ email: string;
209
+ }, Promise<any>>;
210
+ batchCreateContacts: import("convex/server").RegisteredAction<"public", {
211
+ contacts: {
212
+ firstName?: string | undefined;
213
+ lastName?: string | undefined;
214
+ userId?: string | undefined;
215
+ source?: string | undefined;
216
+ subscribed?: boolean | undefined;
217
+ userGroup?: string | undefined;
218
+ email: string;
219
+ }[];
220
+ }, Promise<any>>;
221
+ unsubscribeContact: import("convex/server").RegisteredAction<"public", {
222
+ email: string;
223
+ }, Promise<any>>;
224
+ resubscribeContact: import("convex/server").RegisteredAction<"public", {
225
+ email: string;
226
+ }, Promise<any>>;
227
+ countContacts: import("convex/server").RegisteredQuery<"public", {
228
+ source?: string | undefined;
229
+ subscribed?: boolean | undefined;
230
+ userGroup?: string | undefined;
231
+ }, Promise<any>>;
232
+ detectRecipientSpam: import("convex/server").RegisteredQuery<"public", {
233
+ timeWindowMs?: number | undefined;
234
+ maxEmailsPerRecipient?: number | undefined;
235
+ }, Promise<any>>;
236
+ detectActorSpam: import("convex/server").RegisteredQuery<"public", {
237
+ timeWindowMs?: number | undefined;
238
+ maxEmailsPerActor?: number | undefined;
239
+ }, Promise<any>>;
240
+ getEmailStats: import("convex/server").RegisteredQuery<"public", {
241
+ timeWindowMs?: number | undefined;
242
+ }, Promise<any>>;
243
+ detectRapidFirePatterns: import("convex/server").RegisteredQuery<"public", {
244
+ timeWindowMs?: number | undefined;
245
+ minEmailsInWindow?: number | undefined;
246
+ }, Promise<any>>;
247
+ checkRecipientRateLimit: import("convex/server").RegisteredQuery<"public", {
248
+ email: string;
249
+ timeWindowMs: number;
250
+ maxEmails: number;
251
+ }, Promise<any>>;
252
+ checkActorRateLimit: import("convex/server").RegisteredQuery<"public", {
253
+ actorId: string;
254
+ timeWindowMs: number;
255
+ maxEmails: number;
256
+ }, Promise<any>>;
257
+ checkGlobalRateLimit: import("convex/server").RegisteredQuery<"public", {
258
+ timeWindowMs: number;
259
+ maxEmails: number;
260
+ }, Promise<any>>;
191
261
  };
192
262
  }
193
263
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
@@ -125,6 +125,20 @@ export class Loops {
125
125
  async countContacts(ctx, options) {
126
126
  return ctx.runQuery(this.component.lib.countContacts, options ?? {});
127
127
  }
128
+ /**
129
+ * List contacts with pagination and optional filters
130
+ * Returns actual contact data, not just a count
131
+ * This queries the component's local database, not Loops API
132
+ */
133
+ async listContacts(ctx, options) {
134
+ return ctx.runQuery(this.component.lib.listContacts, {
135
+ userGroup: options?.userGroup,
136
+ source: options?.source,
137
+ subscribed: options?.subscribed,
138
+ limit: options?.limit ?? 100,
139
+ offset: options?.offset ?? 0,
140
+ });
141
+ }
128
142
  /**
129
143
  * Detect spam patterns: emails sent to the same recipient too frequently
130
144
  */
@@ -187,16 +201,6 @@ export class Loops {
187
201
  email,
188
202
  });
189
203
  }
190
- /**
191
- * Send a campaign to contacts
192
- * Campaigns are one-time email sends to a segment or list of contacts
193
- */
194
- async sendCampaign(ctx, options) {
195
- return ctx.runAction(this.component.lib.sendCampaign, {
196
- apiKey: this.apiKey,
197
- ...options,
198
- });
199
- }
200
204
  /**
201
205
  * Trigger a loop for a contact
202
206
  * Loops are automated email sequences that can be triggered by events
@@ -217,7 +221,7 @@ export class Loops {
217
221
  * For easy re-exporting.
218
222
  * Apps can do
219
223
  * ```ts
220
- * export const { addContact, sendTransactional, sendEvent, sendCampaign, triggerLoop } = loops.api();
224
+ * export const { addContact, sendTransactional, sendEvent, triggerLoop } = loops.api();
221
225
  * ```
222
226
  */
223
227
  api() {
@@ -280,21 +284,6 @@ export class Loops {
280
284
  return await this.deleteContact(ctx, args.email);
281
285
  },
282
286
  }),
283
- sendCampaign: actionGeneric({
284
- args: {
285
- campaignId: v.string(),
286
- emails: v.optional(v.array(v.string())),
287
- transactionalId: v.optional(v.string()),
288
- dataVariables: v.optional(v.any()),
289
- audienceFilters: v.optional(v.object({
290
- userGroup: v.optional(v.string()),
291
- source: v.optional(v.string()),
292
- })),
293
- },
294
- handler: async (ctx, args) => {
295
- return await this.sendCampaign(ctx, args);
296
- },
297
- }),
298
287
  triggerLoop: actionGeneric({
299
288
  args: {
300
289
  loopId: v.string(),
@@ -1,3 +1,3 @@
1
- declare const component: any;
1
+ declare const component: import("convex/server").ComponentDefinition<any>;
2
2
  export default component;
3
3
  //# sourceMappingURL=convex.config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,SAAS,KAA2B,CAAC;AAwB3C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,SAAS,kDAA2B,CAAC;AAuB3C,eAAe,SAAS,CAAC"}
@@ -12,7 +12,6 @@ component.export(api, {
12
12
  listContacts: api.lib.listContacts,
13
13
  sendTransactional: api.lib.sendTransactional,
14
14
  sendEvent: api.lib.sendEvent,
15
- sendCampaign: api.lib.sendCampaign,
16
15
  triggerLoop: api.lib.triggerLoop,
17
16
  deleteContact: api.lib.deleteContact,
18
17
  detectRecipientSpam: api.lib.detectRecipientSpam,