convex-flutterwave 0.0.1

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 (52) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +504 -0
  3. package/dist/client/_generated/_ignore.d.ts +1 -0
  4. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  5. package/dist/client/_generated/_ignore.js +3 -0
  6. package/dist/client/_generated/_ignore.js.map +1 -0
  7. package/dist/client/index.d.ts +192 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +364 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/component/_generated/api.d.ts +34 -0
  12. package/dist/component/_generated/api.d.ts.map +1 -0
  13. package/dist/component/_generated/api.js +31 -0
  14. package/dist/component/_generated/api.js.map +1 -0
  15. package/dist/component/_generated/component.d.ts +141 -0
  16. package/dist/component/_generated/component.d.ts.map +1 -0
  17. package/dist/component/_generated/component.js +11 -0
  18. package/dist/component/_generated/component.js.map +1 -0
  19. package/dist/component/_generated/dataModel.d.ts +46 -0
  20. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  21. package/dist/component/_generated/dataModel.js +11 -0
  22. package/dist/component/_generated/dataModel.js.map +1 -0
  23. package/dist/component/_generated/server.d.ts +133 -0
  24. package/dist/component/_generated/server.d.ts.map +1 -0
  25. package/dist/component/_generated/server.js +80 -0
  26. package/dist/component/_generated/server.js.map +1 -0
  27. package/dist/component/convex.config.d.ts +3 -0
  28. package/dist/component/convex.config.d.ts.map +1 -0
  29. package/dist/component/convex.config.js +4 -0
  30. package/dist/component/convex.config.js.map +1 -0
  31. package/dist/component/lib.d.ts +117 -0
  32. package/dist/component/lib.d.ts.map +1 -0
  33. package/dist/component/lib.js +223 -0
  34. package/dist/component/lib.js.map +1 -0
  35. package/dist/component/schema.d.ts +73 -0
  36. package/dist/component/schema.d.ts.map +1 -0
  37. package/dist/component/schema.js +43 -0
  38. package/dist/component/schema.js.map +1 -0
  39. package/package.json +106 -0
  40. package/src/client/_generated/_ignore.ts +1 -0
  41. package/src/client/index.ts +565 -0
  42. package/src/client/setup.test.ts +26 -0
  43. package/src/component/_generated/api.ts +50 -0
  44. package/src/component/_generated/component.ts +183 -0
  45. package/src/component/_generated/dataModel.ts +60 -0
  46. package/src/component/_generated/server.ts +169 -0
  47. package/src/component/convex.config.ts +5 -0
  48. package/src/component/lib.test.ts +110 -0
  49. package/src/component/lib.ts +251 -0
  50. package/src/component/schema.ts +50 -0
  51. package/src/component/setup.test.ts +11 -0
  52. package/src/test.ts +18 -0
@@ -0,0 +1,192 @@
1
+ import { httpActionGeneric } from "convex/server";
2
+ import type { GenericActionCtx, GenericDataModel } from "convex/server";
3
+ import type { ComponentApi } from "../component/_generated/component.js";
4
+ export type FlutterwaveOptions = {
5
+ secretKey: string;
6
+ webhookSecretHash: string;
7
+ };
8
+ export type FlutterwavePaymentOption = "card" | "account" | "banktransfer" | "ussd" | "nqr" | "mpesa" | "mobilemoneyghana" | "mobilemoneyuganda" | "mobilemoneyrwanda" | "mobilemoneyzambia" | "barter" | "credit" | "opay" | "fawrypay";
9
+ export type InitializeTransactionArgs = {
10
+ email: string;
11
+ amount: number;
12
+ currency?: string;
13
+ redirectUrl: string;
14
+ txRef?: string;
15
+ customerName?: string;
16
+ customerPhoneNumber?: string;
17
+ /** Restricts which payment methods Flutterwave's hosted page offers. Omit to offer everything enabled on your account. */
18
+ paymentOptions?: FlutterwavePaymentOption[];
19
+ /** Links this checkout to a payment plan, turning it into a subscription. See createPaymentPlan(). */
20
+ paymentPlan?: string;
21
+ metadata?: Record<string, unknown>;
22
+ };
23
+ export type InitializeTransactionResult = {
24
+ paymentLink: string;
25
+ txRef: string;
26
+ };
27
+ export type VerifyTransactionResult = {
28
+ status: string;
29
+ txRef: string;
30
+ flwRef?: string;
31
+ transactionId: string;
32
+ amount: number;
33
+ currency: string;
34
+ paymentType?: string;
35
+ narration?: string;
36
+ paidAt?: number;
37
+ customerEmail: string;
38
+ };
39
+ export type CreatePaymentPlanArgs = {
40
+ name: string;
41
+ amount: number;
42
+ interval: "hourly" | "daily" | "weekly" | "monthly" | "quarterly" | "yearly" | "bi-annually";
43
+ currency?: string;
44
+ duration?: number;
45
+ };
46
+ export type PaymentPlanResult = {
47
+ planId: string;
48
+ name: string;
49
+ amount: number;
50
+ interval: string;
51
+ currency: string;
52
+ duration?: number;
53
+ status: string;
54
+ };
55
+ export declare class Flutterwave {
56
+ private component;
57
+ private options;
58
+ webhookHandler: ReturnType<typeof httpActionGeneric>;
59
+ constructor(component: ComponentApi, options: FlutterwaveOptions);
60
+ initializeTransaction(ctx: GenericActionCtx<GenericDataModel>, args: InitializeTransactionArgs): Promise<InitializeTransactionResult>;
61
+ verifyTransaction(ctx: GenericActionCtx<GenericDataModel>, args: {
62
+ transactionId: string;
63
+ }): Promise<VerifyTransactionResult>;
64
+ cancelSubscription(ctx: GenericActionCtx<GenericDataModel>, args: {
65
+ subscriptionId: string;
66
+ customerEmail: string;
67
+ }): Promise<void>;
68
+ enableSubscription(ctx: GenericActionCtx<GenericDataModel>, args: {
69
+ subscriptionId: string;
70
+ customerEmail: string;
71
+ }): Promise<void>;
72
+ createPaymentPlan(ctx: GenericActionCtx<GenericDataModel>, args: CreatePaymentPlanArgs): Promise<PaymentPlanResult>;
73
+ listPaymentPlans(_ctx: GenericActionCtx<GenericDataModel>): Promise<PaymentPlanResult[]>;
74
+ /**
75
+ * Flutterwave has no "subscription created" webhook — a subscription is
76
+ * created implicitly the first time a customer pays through a checkout
77
+ * initialized with `paymentPlan`, and that charge webhook doesn't carry
78
+ * the subscription's own id (only the plan id). This reads the customer's
79
+ * subscriptions straight from Flutterwave's Subscriptions API and upserts
80
+ * them locally — call it after a plan-linked checkout returns, or from a
81
+ * manual "sync" action, as a reliable way to populate subscription state.
82
+ */
83
+ private fetchFlutterwaveSubscriptions;
84
+ syncCustomerSubscriptions(ctx: GenericActionCtx<GenericDataModel>, args: {
85
+ email: string;
86
+ }): Promise<number>;
87
+ /**
88
+ * Attributes every subscription on a given plan to one email, regardless
89
+ * of what Flutterwave itself has on file as that subscription's customer.
90
+ * This is unsafe to reach for by default — a real plan can have many
91
+ * subscribers — but it's exactly what's needed when Flutterwave's
92
+ * test-mode sandbox has substituted its own fixed customer identity for
93
+ * every subscription (see the README's Subscriptions section), making
94
+ * email-based sync unable to find anything at all. Reach for it only
95
+ * where you already know (or, in a single-developer test/demo context,
96
+ * can safely assume) there's one subscriber to claim — the example app
97
+ * uses it as a fallback for exactly that reason.
98
+ */
99
+ syncSubscriptionsByPlan(ctx: GenericActionCtx<GenericDataModel>, args: {
100
+ planId: string;
101
+ email: string;
102
+ }): Promise<number>;
103
+ getTransaction(ctx: RunQueryCtx, args: {
104
+ txRef: string;
105
+ }): Promise<{
106
+ _creationTime: number;
107
+ _id: string;
108
+ amount: number;
109
+ createdAt: number;
110
+ currency: string;
111
+ customerEmail: string;
112
+ flwRef?: string;
113
+ metadata?: string;
114
+ narration?: string;
115
+ paidAt?: number;
116
+ paymentType?: string;
117
+ status: "pending" | "successful" | "failed" | "cancelled";
118
+ transactionId?: string;
119
+ txRef: string;
120
+ updatedAt: number;
121
+ } | null>;
122
+ listTransactions(ctx: RunQueryCtx, args: {
123
+ customerEmail: string;
124
+ limit?: number;
125
+ }): Promise<{
126
+ _creationTime: number;
127
+ _id: string;
128
+ amount: number;
129
+ createdAt: number;
130
+ currency: string;
131
+ customerEmail: string;
132
+ flwRef?: string;
133
+ metadata?: string;
134
+ narration?: string;
135
+ paidAt?: number;
136
+ paymentType?: string;
137
+ status: "pending" | "successful" | "failed" | "cancelled";
138
+ transactionId?: string;
139
+ txRef: string;
140
+ updatedAt: number;
141
+ }[]>;
142
+ getSubscription(ctx: RunQueryCtx, args: {
143
+ subscriptionId: string;
144
+ }): Promise<{
145
+ _creationTime: number;
146
+ _id: string;
147
+ amount?: number;
148
+ createdAt: number;
149
+ customerEmail: string;
150
+ planId?: string;
151
+ status: "active" | "cancelled";
152
+ subscriptionId: string;
153
+ updatedAt: number;
154
+ } | null>;
155
+ listSubscriptions(ctx: RunQueryCtx, args: {
156
+ customerEmail: string;
157
+ }): Promise<{
158
+ _creationTime: number;
159
+ _id: string;
160
+ amount?: number;
161
+ createdAt: number;
162
+ customerEmail: string;
163
+ planId?: string;
164
+ status: "active" | "cancelled";
165
+ subscriptionId: string;
166
+ updatedAt: number;
167
+ }[]>;
168
+ hasActiveSubscription(ctx: RunQueryCtx, args: {
169
+ customerEmail: string;
170
+ }): Promise<boolean>;
171
+ listRecentEvents(ctx: RunQueryCtx, args?: {
172
+ limit?: number;
173
+ }): Promise<{
174
+ _creationTime: number;
175
+ _id: string;
176
+ eventId: string;
177
+ eventType: string;
178
+ payload: string;
179
+ receivedAt: number;
180
+ txRef?: string;
181
+ }[]>;
182
+ getStats(ctx: RunQueryCtx): Promise<{
183
+ events: number;
184
+ subscriptions: number;
185
+ transactions: number;
186
+ }>;
187
+ }
188
+ type RunQueryCtx = {
189
+ runQuery: GenericActionCtx<GenericDataModel>["runQuery"];
190
+ };
191
+ export {};
192
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,364 @@
1
+ import { httpActionGeneric } from "convex/server";
2
+ const FLUTTERWAVE_API_BASE = "https://api.flutterwave.com/v3";
3
+ // Flutterwave does not sign webhook payloads. Instead, it echoes back the
4
+ // secret hash you configured in the Dashboard, verbatim, in a `verif-hash`
5
+ // header — verification is a direct (constant-time) string comparison, not
6
+ // an HMAC digest of the request body. See:
7
+ // https://developer.flutterwave.com/docs/integration-guides/webhooks
8
+ function timingSafeEqual(a, b) {
9
+ if (a.length !== b.length)
10
+ return false;
11
+ let mismatch = 0;
12
+ for (let i = 0; i < a.length; i++) {
13
+ mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
14
+ }
15
+ return mismatch === 0;
16
+ }
17
+ export class Flutterwave {
18
+ component;
19
+ options;
20
+ webhookHandler;
21
+ constructor(component, options) {
22
+ this.component = component;
23
+ this.options = options;
24
+ const component_ = component;
25
+ const webhookSecretHash = options.webhookSecretHash;
26
+ this.webhookHandler = httpActionGeneric(async (ctx, request) => {
27
+ const rawBody = await request.text();
28
+ const signature = request.headers.get("verif-hash");
29
+ if (!signature) {
30
+ return new Response(JSON.stringify({ error: "Missing signature" }), {
31
+ status: 400,
32
+ headers: { "Content-Type": "application/json" },
33
+ });
34
+ }
35
+ if (!timingSafeEqual(webhookSecretHash, signature)) {
36
+ console.error("convex-flutterwave: webhook signature mismatch");
37
+ return new Response(JSON.stringify({ error: "Invalid signature" }), {
38
+ status: 401,
39
+ headers: { "Content-Type": "application/json" },
40
+ });
41
+ }
42
+ let event;
43
+ try {
44
+ event = JSON.parse(rawBody);
45
+ }
46
+ catch {
47
+ return new Response(JSON.stringify({ error: "Invalid JSON" }), {
48
+ status: 400,
49
+ headers: { "Content-Type": "application/json" },
50
+ });
51
+ }
52
+ const data = event.data ?? {};
53
+ const eventId = data.id !== undefined
54
+ ? `${event.event}:${data.id}`
55
+ : `${event.event}:${data.tx_ref ?? crypto.randomUUID()}`;
56
+ const { alreadyProcessed } = await ctx.runMutation(component_.lib.checkAndRecordEvent, {
57
+ eventId,
58
+ eventType: event.event,
59
+ txRef: data.tx_ref ?? undefined,
60
+ payload: rawBody,
61
+ });
62
+ if (alreadyProcessed) {
63
+ return new Response(JSON.stringify({ success: true, duplicate: true }), {
64
+ status: 200,
65
+ headers: { "Content-Type": "application/json" },
66
+ });
67
+ }
68
+ switch (event.event) {
69
+ case "charge.completed": {
70
+ const customer = data.customer;
71
+ const status = data.status === "successful" ? "successful" : "failed";
72
+ await ctx.runMutation(component_.lib.recordTransaction, {
73
+ txRef: data.tx_ref,
74
+ flwRef: data.flw_ref ?? undefined,
75
+ transactionId: data.id !== undefined ? String(data.id) : undefined,
76
+ customerEmail: customer?.email ?? "",
77
+ amount: data.amount,
78
+ currency: data.currency ?? "NGN",
79
+ status,
80
+ paymentType: data.payment_type ?? undefined,
81
+ narration: data.narration ?? undefined,
82
+ paidAt: data.created_at ? new Date(data.created_at).getTime() : undefined,
83
+ metadata: data.meta ? JSON.stringify(data.meta) : undefined,
84
+ });
85
+ break;
86
+ }
87
+ case "subscription.cancelled": {
88
+ const planId = data.plan ?? undefined;
89
+ const customer = data.customer;
90
+ if (data.id !== undefined) {
91
+ await ctx.runMutation(component_.lib.recordSubscriptionEvent, {
92
+ subscriptionId: String(data.id),
93
+ customerEmail: customer?.email ?? "",
94
+ planId,
95
+ amount: data.amount ?? undefined,
96
+ status: "cancelled",
97
+ });
98
+ }
99
+ break;
100
+ }
101
+ default:
102
+ break;
103
+ }
104
+ return new Response(JSON.stringify({ success: true }), {
105
+ status: 200,
106
+ headers: { "Content-Type": "application/json" },
107
+ });
108
+ });
109
+ }
110
+ async initializeTransaction(ctx, args) {
111
+ const txRef = args.txRef ?? crypto.randomUUID();
112
+ const res = await fetch(`${FLUTTERWAVE_API_BASE}/payments`, {
113
+ method: "POST",
114
+ headers: {
115
+ Authorization: `Bearer ${this.options.secretKey}`,
116
+ "Content-Type": "application/json",
117
+ },
118
+ body: JSON.stringify({
119
+ tx_ref: txRef,
120
+ amount: args.amount,
121
+ currency: args.currency ?? "NGN",
122
+ redirect_url: args.redirectUrl,
123
+ // Flutterwave requires payment_plan as a numeric id, not a string —
124
+ // this component's own PaymentPlanResult.planId is a string (for
125
+ // consistency with every other id in this API), so it's converted
126
+ // here. Sending it as a string doesn't error; Flutterwave just
127
+ // silently processes the charge as a normal one-time payment
128
+ // instead of linking it to the plan, so no subscription is created.
129
+ payment_plan: args.paymentPlan !== undefined ? Number(args.paymentPlan) : undefined,
130
+ payment_options: args.paymentOptions?.join(", "),
131
+ customer: {
132
+ email: args.email,
133
+ name: args.customerName,
134
+ phonenumber: args.customerPhoneNumber,
135
+ },
136
+ meta: args.metadata,
137
+ }),
138
+ });
139
+ const json = (await res.json());
140
+ if (json.status !== "success") {
141
+ throw new Error(json.message ?? "Failed to initialize Flutterwave transaction");
142
+ }
143
+ await ctx.runMutation(this.component.lib.recordTransaction, {
144
+ txRef,
145
+ customerEmail: args.email,
146
+ amount: args.amount,
147
+ currency: args.currency ?? "NGN",
148
+ status: "pending",
149
+ metadata: args.metadata ? JSON.stringify(args.metadata) : undefined,
150
+ });
151
+ return { paymentLink: json.data.link, txRef };
152
+ }
153
+ async verifyTransaction(ctx, args) {
154
+ const res = await fetch(`${FLUTTERWAVE_API_BASE}/transactions/${encodeURIComponent(args.transactionId)}/verify`, { headers: { Authorization: `Bearer ${this.options.secretKey}` } });
155
+ const json = (await res.json());
156
+ if (json.status !== "success") {
157
+ throw new Error(json.message ?? "Failed to verify Flutterwave transaction");
158
+ }
159
+ const data = json.data;
160
+ const status = data.status === "successful" ? "successful" : "failed";
161
+ await ctx.runMutation(this.component.lib.recordTransaction, {
162
+ txRef: data.tx_ref,
163
+ flwRef: data.flw_ref ?? undefined,
164
+ transactionId: String(data.id),
165
+ customerEmail: data.customer?.email ?? "",
166
+ amount: data.amount,
167
+ currency: data.currency,
168
+ status,
169
+ paymentType: data.payment_type ?? undefined,
170
+ narration: data.narration ?? undefined,
171
+ paidAt: data.created_at ? new Date(data.created_at).getTime() : undefined,
172
+ });
173
+ // recordTransaction keeps the email the transaction was first created
174
+ // under rather than whatever Flutterwave just echoed back (see its
175
+ // comment — test mode rewrites it). Read that back so callers — and
176
+ // anything they render, like a result screen — see the real address
177
+ // too, not just what's in the database.
178
+ const stored = await ctx.runQuery(this.component.lib.getTransaction, { txRef: data.tx_ref });
179
+ return {
180
+ status: data.status,
181
+ txRef: data.tx_ref,
182
+ flwRef: data.flw_ref ?? undefined,
183
+ transactionId: String(data.id),
184
+ amount: data.amount,
185
+ currency: data.currency,
186
+ paymentType: data.payment_type ?? undefined,
187
+ narration: data.narration ?? undefined,
188
+ paidAt: data.created_at ? new Date(data.created_at).getTime() : undefined,
189
+ customerEmail: stored?.customerEmail ?? data.customer?.email ?? "",
190
+ };
191
+ }
192
+ async cancelSubscription(ctx, args) {
193
+ const res = await fetch(`${FLUTTERWAVE_API_BASE}/subscriptions/${encodeURIComponent(args.subscriptionId)}/cancel`, { method: "PUT", headers: { Authorization: `Bearer ${this.options.secretKey}` } });
194
+ const json = (await res.json());
195
+ if (json.status !== "success") {
196
+ throw new Error(json.message ?? "Failed to cancel Flutterwave subscription");
197
+ }
198
+ await ctx.runMutation(this.component.lib.recordSubscriptionEvent, {
199
+ subscriptionId: args.subscriptionId,
200
+ customerEmail: args.customerEmail,
201
+ status: "cancelled",
202
+ });
203
+ }
204
+ async enableSubscription(ctx, args) {
205
+ const res = await fetch(`${FLUTTERWAVE_API_BASE}/subscriptions/${encodeURIComponent(args.subscriptionId)}/activate`, { method: "PUT", headers: { Authorization: `Bearer ${this.options.secretKey}` } });
206
+ const json = (await res.json());
207
+ if (json.status !== "success") {
208
+ throw new Error(json.message ?? "Failed to activate Flutterwave subscription");
209
+ }
210
+ await ctx.runMutation(this.component.lib.recordSubscriptionEvent, {
211
+ subscriptionId: args.subscriptionId,
212
+ customerEmail: args.customerEmail,
213
+ status: "active",
214
+ });
215
+ }
216
+ async createPaymentPlan(ctx, args) {
217
+ const res = await fetch(`${FLUTTERWAVE_API_BASE}/payment-plans`, {
218
+ method: "POST",
219
+ headers: {
220
+ Authorization: `Bearer ${this.options.secretKey}`,
221
+ "Content-Type": "application/json",
222
+ },
223
+ body: JSON.stringify({
224
+ name: args.name,
225
+ amount: args.amount,
226
+ interval: args.interval,
227
+ currency: args.currency ?? "NGN",
228
+ duration: args.duration,
229
+ }),
230
+ });
231
+ const json = (await res.json());
232
+ if (json.status !== "success") {
233
+ throw new Error(json.message ?? "Failed to create Flutterwave payment plan");
234
+ }
235
+ return {
236
+ planId: String(json.data.id),
237
+ name: json.data.name,
238
+ amount: json.data.amount,
239
+ interval: json.data.interval,
240
+ currency: json.data.currency,
241
+ duration: json.data.duration,
242
+ status: json.data.status,
243
+ };
244
+ }
245
+ async listPaymentPlans(_ctx) {
246
+ const res = await fetch(`${FLUTTERWAVE_API_BASE}/payment-plans`, {
247
+ headers: { Authorization: `Bearer ${this.options.secretKey}` },
248
+ });
249
+ const json = (await res.json());
250
+ if (json.status !== "success") {
251
+ throw new Error(json.message ?? "Failed to list Flutterwave payment plans");
252
+ }
253
+ return json.data.map((plan) => ({
254
+ planId: String(plan.id),
255
+ name: plan.name,
256
+ amount: plan.amount,
257
+ interval: plan.interval,
258
+ currency: plan.currency,
259
+ duration: plan.duration,
260
+ status: plan.status,
261
+ }));
262
+ }
263
+ /**
264
+ * Flutterwave has no "subscription created" webhook — a subscription is
265
+ * created implicitly the first time a customer pays through a checkout
266
+ * initialized with `paymentPlan`, and that charge webhook doesn't carry
267
+ * the subscription's own id (only the plan id). This reads the customer's
268
+ * subscriptions straight from Flutterwave's Subscriptions API and upserts
269
+ * them locally — call it after a plan-linked checkout returns, or from a
270
+ * manual "sync" action, as a reliable way to populate subscription state.
271
+ */
272
+ async fetchFlutterwaveSubscriptions(email) {
273
+ const url = email
274
+ ? `${FLUTTERWAVE_API_BASE}/subscriptions?email=${encodeURIComponent(email)}`
275
+ : `${FLUTTERWAVE_API_BASE}/subscriptions`;
276
+ const res = await fetch(url, { headers: { Authorization: `Bearer ${this.options.secretKey}` } });
277
+ return await res.json();
278
+ }
279
+ async syncCustomerSubscriptions(ctx, args) {
280
+ const json = await this.fetchFlutterwaveSubscriptions(args.email);
281
+ if (json.status !== "success") {
282
+ throw new Error(json.message ?? "Failed to fetch Flutterwave subscriptions");
283
+ }
284
+ let subscriptions = json.data ?? [];
285
+ // Flutterwave's ?email= filter matches against whatever email it has on
286
+ // file for the subscription — in test mode that's the same "ravesb_
287
+ // <hash>_" rewritten address seen elsewhere, not the real one, so
288
+ // filtering by the real email can come back empty even when a matching
289
+ // subscription exists. Fall back to an unfiltered list and match after
290
+ // stripping that rewrite, rather than trusting the filter alone.
291
+ if (subscriptions.length === 0) {
292
+ const all = await this.fetchFlutterwaveSubscriptions();
293
+ if (all.status === "success") {
294
+ subscriptions = (all.data ?? []).filter((sub) => sub.customer?.customer_email?.replace(/^ravesb_[0-9a-f]+_/i, "") === args.email);
295
+ }
296
+ }
297
+ for (const sub of subscriptions) {
298
+ await ctx.runMutation(this.component.lib.recordSubscriptionEvent, {
299
+ subscriptionId: String(sub.id),
300
+ // Use the email the caller queried by, not Flutterwave's own
301
+ // customer_email field — in test mode Flutterwave rewrites it (e.g.
302
+ // "ravesb_<hash>_real@email.com"), which would make the record
303
+ // unfindable by the email a merchant actually knows the customer as.
304
+ customerEmail: args.email,
305
+ planId: sub.plan !== undefined ? String(sub.plan) : undefined,
306
+ amount: sub.amount ?? undefined,
307
+ status: sub.status === "active" ? "active" : "cancelled",
308
+ });
309
+ }
310
+ return subscriptions.length;
311
+ }
312
+ /**
313
+ * Attributes every subscription on a given plan to one email, regardless
314
+ * of what Flutterwave itself has on file as that subscription's customer.
315
+ * This is unsafe to reach for by default — a real plan can have many
316
+ * subscribers — but it's exactly what's needed when Flutterwave's
317
+ * test-mode sandbox has substituted its own fixed customer identity for
318
+ * every subscription (see the README's Subscriptions section), making
319
+ * email-based sync unable to find anything at all. Reach for it only
320
+ * where you already know (or, in a single-developer test/demo context,
321
+ * can safely assume) there's one subscriber to claim — the example app
322
+ * uses it as a fallback for exactly that reason.
323
+ */
324
+ async syncSubscriptionsByPlan(ctx, args) {
325
+ const json = await this.fetchFlutterwaveSubscriptions();
326
+ if (json.status !== "success") {
327
+ throw new Error(json.message ?? "Failed to fetch Flutterwave subscriptions");
328
+ }
329
+ const planId = Number(args.planId);
330
+ const subscriptions = (json.data ?? []).filter((sub) => sub.plan === planId);
331
+ for (const sub of subscriptions) {
332
+ await ctx.runMutation(this.component.lib.recordSubscriptionEvent, {
333
+ subscriptionId: String(sub.id),
334
+ customerEmail: args.email,
335
+ planId: String(planId),
336
+ amount: sub.amount ?? undefined,
337
+ status: sub.status === "active" ? "active" : "cancelled",
338
+ });
339
+ }
340
+ return subscriptions.length;
341
+ }
342
+ async getTransaction(ctx, args) {
343
+ return await ctx.runQuery(this.component.lib.getTransaction, args);
344
+ }
345
+ async listTransactions(ctx, args) {
346
+ return await ctx.runQuery(this.component.lib.listTransactions, args);
347
+ }
348
+ async getSubscription(ctx, args) {
349
+ return await ctx.runQuery(this.component.lib.getSubscription, args);
350
+ }
351
+ async listSubscriptions(ctx, args) {
352
+ return await ctx.runQuery(this.component.lib.listSubscriptions, args);
353
+ }
354
+ async hasActiveSubscription(ctx, args) {
355
+ return await ctx.runQuery(this.component.lib.hasActiveSubscription, args);
356
+ }
357
+ async listRecentEvents(ctx, args) {
358
+ return await ctx.runQuery(this.component.lib.listRecentEvents, args ?? {});
359
+ }
360
+ async getStats(ctx) {
361
+ return await ctx.runQuery(this.component.lib.getStats, {});
362
+ }
363
+ }
364
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAIlD,MAAM,oBAAoB,GAAG,gCAAgC,CAAC;AA0E9D,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,2CAA2C;AAC3C,qEAAqE;AACrE,SAAS,eAAe,CAAC,CAAS,EAAE,CAAS;IAC3C,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,QAAQ,KAAK,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,OAAO,WAAW;IAIZ;IACA;IAJV,cAAc,CAAuC;IAErD,YACU,SAAuB,EACvB,OAA2B;QAD3B,cAAS,GAAT,SAAS,CAAc;QACvB,YAAO,GAAP,OAAO,CAAoB;QAEnC,MAAM,UAAU,GAAG,SAAS,CAAC;QAC7B,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QAEpD,IAAI,CAAC,cAAc,GAAG,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;YAC7D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAEpD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,eAAe,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAE,CAAC;gBACnD,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;gBAChE,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;YAED,IAAI,KAAuD,CAAC;YAC5D,IAAI,CAAC;gBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,EAAE;oBAC7D,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;YAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;YAC9B,MAAM,OAAO,GACX,IAAI,CAAC,EAAE,KAAK,SAAS;gBACnB,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,EAAE;gBAC7B,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,IAAK,IAAI,CAAC,MAAiB,IAAI,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;YAEzE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,mBAAmB,EAAE;gBACrF,OAAO;gBACP,SAAS,EAAE,KAAK,CAAC,KAAK;gBACtB,KAAK,EAAG,IAAI,CAAC,MAAiB,IAAI,SAAS;gBAC3C,OAAO,EAAE,OAAO;aACjB,CAAC,CAAC;YAEH,IAAI,gBAAgB,EAAE,CAAC;gBACrB,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE;oBACtE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;YAED,QAAQ,KAAK,CAAC,KAAK,EAAE,CAAC;gBACpB,KAAK,kBAAkB,CAAC,CAAC,CAAC;oBACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAA+C,CAAC;oBACtE,MAAM,MAAM,GAAI,IAAI,CAAC,MAAiB,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;oBAClF,MAAM,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,iBAAiB,EAAE;wBACtD,KAAK,EAAE,IAAI,CAAC,MAAgB;wBAC5B,MAAM,EAAG,IAAI,CAAC,OAAkB,IAAI,SAAS;wBAC7C,aAAa,EAAE,IAAI,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;wBAClE,aAAa,EAAG,QAAQ,EAAE,KAAgB,IAAI,EAAE;wBAChD,MAAM,EAAE,IAAI,CAAC,MAAgB;wBAC7B,QAAQ,EAAG,IAAI,CAAC,QAAmB,IAAI,KAAK;wBAC5C,MAAM;wBACN,WAAW,EAAG,IAAI,CAAC,YAAuB,IAAI,SAAS;wBACvD,SAAS,EAAG,IAAI,CAAC,SAAoB,IAAI,SAAS;wBAClD,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;wBACnF,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;qBAC5D,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;gBACD,KAAK,wBAAwB,CAAC,CAAC,CAAC;oBAC9B,MAAM,MAAM,GAAI,IAAI,CAAC,IAAe,IAAI,SAAS,CAAC;oBAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAA+C,CAAC;oBACtE,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;wBAC1B,MAAM,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,uBAAuB,EAAE;4BAC5D,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC/B,aAAa,EAAG,QAAQ,EAAE,KAAgB,IAAI,EAAE;4BAChD,MAAM;4BACN,MAAM,EAAG,IAAI,CAAC,MAAiB,IAAI,SAAS;4BAC5C,MAAM,EAAE,WAAW;yBACpB,CAAC,CAAC;oBACL,CAAC;oBACD,MAAM;gBACR,CAAC;gBACD;oBACE,MAAM;YACV,CAAC;YAED,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE;gBACrD,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,GAAuC,EACvC,IAA+B;QAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAEhD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAoB,WAAW,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;gBACjD,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK;gBAChC,YAAY,EAAE,IAAI,CAAC,WAAW;gBAC9B,oEAAoE;gBACpE,iEAAiE;gBACjE,kEAAkE;gBAClE,+DAA+D;gBAC/D,6DAA6D;gBAC7D,oEAAoE;gBACpE,YAAY,EAAE,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS;gBACnF,eAAe,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC;gBAChD,QAAQ,EAAE;oBACR,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,IAAI,EAAE,IAAI,CAAC,YAAY;oBACvB,WAAW,EAAE,IAAI,CAAC,mBAAmB;iBACtC;gBACD,IAAI,EAAE,IAAI,CAAC,QAAQ;aACpB,CAAC;SACH,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAI7B,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,8CAA8C,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,EAAE;YAC1D,KAAK;YACL,aAAa,EAAE,IAAI,CAAC,KAAK;YACzB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK;YAChC,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;SACpE,CAAC,CAAC;QAEH,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,GAAuC,EACvC,IAA+B;QAE/B,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,oBAAoB,iBAAiB,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,EACvF,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,CACnE,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAe7B,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,0CAA0C,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;QAEtE,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,EAAE;YAC1D,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,MAAM,EAAE,IAAI,CAAC,OAAO,IAAI,SAAS;YACjC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,MAAM;YACN,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,SAAS;YAC3C,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS;YACtC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;SAC1E,CAAC,CAAC;QAEH,sEAAsE;QACtE,mEAAmE;QACnE,oEAAoE;QACpE,oEAAoE;QACpE,wCAAwC;QACxC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAE7F,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,MAAM,EAAE,IAAI,CAAC,OAAO,IAAI,SAAS;YACjC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,SAAS;YAC3C,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS;YACtC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;YACzE,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;SACnE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,GAAuC,EACvC,IAAuD;QAEvD,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,oBAAoB,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,EACzF,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,CAClF,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyC,CAAC;QACxE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,2CAA2C,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,EAAE;YAChE,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,MAAM,EAAE,WAAW;SACpB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,GAAuC,EACvC,IAAuD;QAEvD,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,oBAAoB,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,EAC3F,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,CAClF,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyC,CAAC;QACxE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,6CAA6C,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,EAAE;YAChE,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,GAAuC,EACvC,IAA2B;QAE3B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAoB,gBAAgB,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;gBACjD,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK;gBAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC;SACH,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAY7B,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,2CAA2C,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YACpB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;YACxB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC5B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC5B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC5B,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;SACzB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,IAAwC;QAExC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAoB,gBAAgB,EAAE;YAC/D,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE;SAC/D,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAY7B,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,0CAA0C,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC9B,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,6BAA6B,CAAC,KAAc;QAWxD,MAAM,GAAG,GAAG,KAAK;YACf,CAAC,CAAC,GAAG,oBAAoB,wBAAwB,kBAAkB,CAAC,KAAK,CAAC,EAAE;YAC5E,CAAC,CAAC,GAAG,oBAAoB,gBAAgB,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACjG,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC7B,GAAuC,EACvC,IAAuB;QAEvB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,2CAA2C,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,aAAa,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAEpC,wEAAwE;QACxE,oEAAoE;QACpE,kEAAkE;QAClE,uEAAuE;QACvE,uEAAuE;QACvE,iEAAiE;QACjE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,6BAA6B,EAAE,CAAC;YACvD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,aAAa,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CACrC,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,CAClF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,EAAE;gBAChE,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9B,6DAA6D;gBAC7D,oEAAoE;gBACpE,+DAA+D;gBAC/D,qEAAqE;gBACrE,aAAa,EAAE,IAAI,CAAC,KAAK;gBACzB,MAAM,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;gBAC7D,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,SAAS;gBAC/B,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;aACzD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,aAAa,CAAC,MAAM,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,uBAAuB,CAC3B,GAAuC,EACvC,IAAuC;QAEvC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,6BAA6B,EAAE,CAAC;QACxD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,2CAA2C,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,aAAa,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QAE7E,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,EAAE;gBAChE,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9B,aAAa,EAAE,IAAI,CAAC,KAAK;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;gBACtB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,SAAS;gBAC/B,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;aACzD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,aAAa,CAAC,MAAM,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,GAAgB,EAAE,IAAuB;QAC5D,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,GAAgB,EAAE,IAA+C;QACtF,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,GAAgB,EAAE,IAAgC;QACtE,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAgB,EAAE,IAA+B;QACvE,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,GAAgB,EAAE,IAA+B;QAC3E,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,GAAgB,EAAE,IAAyB;QAChE,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAgB;QAC7B,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Generated `api` utility.
3
+ *
4
+ * THIS CODE IS AUTOMATICALLY GENERATED.
5
+ *
6
+ * To regenerate, run `npx convex dev`.
7
+ * @module
8
+ */
9
+ import type * as lib from "../lib.js";
10
+ import type { ApiFromModules, FilterApi, FunctionReference } from "convex/server";
11
+ declare const fullApi: ApiFromModules<{
12
+ lib: typeof lib;
13
+ }>;
14
+ /**
15
+ * A utility for referencing Convex functions in your app's public API.
16
+ *
17
+ * Usage:
18
+ * ```js
19
+ * const myFunctionReference = api.myModule.myFunction;
20
+ * ```
21
+ */
22
+ export declare const api: FilterApi<typeof fullApi, FunctionReference<any, "public">>;
23
+ /**
24
+ * A utility for referencing Convex functions in your app's internal API.
25
+ *
26
+ * Usage:
27
+ * ```js
28
+ * const myFunctionReference = internal.myModule.myFunction;
29
+ * ```
30
+ */
31
+ export declare const internal: FilterApi<typeof fullApi, FunctionReference<any, "internal">>;
32
+ export declare const components: {};
33
+ export {};
34
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,GAAG,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,QAAA,MAAM,OAAO,EAAE,cAAc,CAAC;IAC5B,GAAG,EAAE,OAAO,GAAG,CAAC;CACjB,CAAiB,CAAC;AAEnB;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,EAAE,SAAS,CACzB,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CACjB,CAAC;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,CAC9B,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CACnB,CAAC;AAElB,eAAO,MAAM,UAAU,EAAqC,EAAE,CAAC"}
@@ -0,0 +1,31 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `api` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+ import { anyApi, componentsGeneric } from "convex/server";
11
+ const fullApi = anyApi;
12
+ /**
13
+ * A utility for referencing Convex functions in your app's public API.
14
+ *
15
+ * Usage:
16
+ * ```js
17
+ * const myFunctionReference = api.myModule.myFunction;
18
+ * ```
19
+ */
20
+ export const api = anyApi;
21
+ /**
22
+ * A utility for referencing Convex functions in your app's internal API.
23
+ *
24
+ * Usage:
25
+ * ```js
26
+ * const myFunctionReference = internal.myModule.myFunction;
27
+ * ```
28
+ */
29
+ export const internal = anyApi;
30
+ export const components = componentsGeneric();
31
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB;;;;;;;GAOG;AASH,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,OAAO,GAER,MAAa,CAAC;AAEnB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAGZ,MAAa,CAAC;AAElB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAGjB,MAAa,CAAC;AAElB,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,EAAmB,CAAC"}