@nextsparkjs/core 0.1.0-beta.127 → 0.1.0-beta.128

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 (91) hide show
  1. package/dist/components/billing/ManageBillingButton.d.ts +3 -3
  2. package/dist/lib/api/rate-limit.d.ts.map +1 -1
  3. package/dist/lib/api/rate-limit.js +9 -6
  4. package/dist/lib/billing/config-types.d.ts +2 -5
  5. package/dist/lib/billing/config-types.d.ts.map +1 -1
  6. package/dist/lib/billing/gateways/factory.d.ts +13 -2
  7. package/dist/lib/billing/gateways/factory.d.ts.map +1 -1
  8. package/dist/lib/billing/gateways/factory.js +13 -6
  9. package/dist/lib/billing/gateways/interface.d.ts +19 -1
  10. package/dist/lib/billing/gateways/interface.d.ts.map +1 -1
  11. package/dist/lib/billing/gateways/polar.d.ts +8 -1
  12. package/dist/lib/billing/gateways/polar.d.ts.map +1 -1
  13. package/dist/lib/billing/gateways/polar.js +25 -0
  14. package/dist/lib/billing/gateways/stripe.d.ts +8 -26
  15. package/dist/lib/billing/gateways/stripe.d.ts.map +1 -1
  16. package/dist/lib/billing/gateways/stripe.js +41 -44
  17. package/dist/lib/billing/gateways/types.d.ts +11 -0
  18. package/dist/lib/billing/gateways/types.d.ts.map +1 -1
  19. package/dist/lib/billing/jobs.d.ts +1 -1
  20. package/dist/lib/billing/polar-webhook.d.ts +38 -0
  21. package/dist/lib/billing/polar-webhook.d.ts.map +1 -0
  22. package/dist/lib/billing/polar-webhook.js +0 -0
  23. package/dist/lib/billing/schema.d.ts +1 -2
  24. package/dist/lib/billing/schema.d.ts.map +1 -1
  25. package/dist/lib/billing/schema.js +1 -1
  26. package/dist/lib/billing/stripe-webhook.d.ts +48 -0
  27. package/dist/lib/billing/stripe-webhook.d.ts.map +1 -0
  28. package/dist/lib/billing/stripe-webhook.js +316 -0
  29. package/dist/lib/billing/types.d.ts +6 -2
  30. package/dist/lib/billing/types.d.ts.map +1 -1
  31. package/dist/lib/rate-limit-redis.d.ts +2 -2
  32. package/dist/lib/rate-limit-redis.d.ts.map +1 -1
  33. package/dist/lib/rate-limit-redis.js +22 -4
  34. package/dist/lib/selectors/core-selectors.d.ts +2 -2
  35. package/dist/lib/selectors/domains/superadmin.selectors.d.ts +2 -2
  36. package/dist/lib/selectors/domains/superadmin.selectors.js +2 -2
  37. package/dist/lib/selectors/selectors.d.ts +4 -4
  38. package/dist/lib/services/invoice.service.d.ts +3 -3
  39. package/dist/lib/services/invoice.service.js +2 -2
  40. package/dist/lib/services/membership.service.d.ts.map +1 -1
  41. package/dist/lib/services/membership.service.js +29 -0
  42. package/dist/lib/services/plan.service.d.ts +0 -3
  43. package/dist/lib/services/plan.service.d.ts.map +1 -1
  44. package/dist/lib/services/plan.service.js +3 -9
  45. package/dist/lib/services/subscription.service.d.ts +5 -5
  46. package/dist/lib/services/subscription.service.d.ts.map +1 -1
  47. package/dist/lib/services/subscription.service.js +54 -41
  48. package/dist/migrations/001_better_auth_and_functions.sql +5 -11
  49. package/dist/migrations/008_team_members_table.sql +27 -23
  50. package/dist/styles/classes.json +1 -1
  51. package/dist/templates/app/api/auth/[...all]/route.ts +35 -0
  52. package/dist/templates/app/api/health/route.ts +43 -23
  53. package/dist/templates/app/api/internal/user-metadata/route.ts +10 -0
  54. package/dist/templates/app/api/superadmin/subscriptions/route.ts +5 -0
  55. package/dist/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -0
  56. package/dist/templates/app/api/v1/billing/cancel/route.ts +8 -10
  57. package/dist/templates/app/api/v1/billing/change-plan/route.ts +2 -2
  58. package/dist/templates/app/api/v1/billing/checkout/route.ts +6 -8
  59. package/dist/templates/app/api/v1/billing/portal/route.ts +5 -5
  60. package/dist/templates/app/api/v1/billing/presets.ts +1 -1
  61. package/dist/templates/app/api/v1/billing/webhooks/polar/route.ts +83 -6
  62. package/dist/templates/app/api/v1/billing/webhooks/stripe/route.ts +18 -421
  63. package/dist/templates/app/layout.tsx +14 -5
  64. package/dist/templates/app/superadmin/subscriptions/page.tsx +16 -14
  65. package/dist/templates/app/superadmin/teams/[teamId]/page.tsx +18 -15
  66. package/dist/templates/contents/themes/starter/tests/cypress/src/features/SuperadminPOM.ts +2 -2
  67. package/dist/templates/lib/billing/polar-webhook-extensions.ts +23 -0
  68. package/dist/templates/lib/billing/stripe-webhook-extensions.ts +23 -0
  69. package/migrations/001_better_auth_and_functions.sql +5 -11
  70. package/migrations/008_team_members_table.sql +27 -23
  71. package/package.json +10 -2
  72. package/scripts/build/registry/generators/billing-registry.mjs +1 -2
  73. package/templates/app/api/auth/[...all]/route.ts +35 -0
  74. package/templates/app/api/health/route.ts +43 -23
  75. package/templates/app/api/internal/user-metadata/route.ts +10 -0
  76. package/templates/app/api/superadmin/subscriptions/route.ts +5 -0
  77. package/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -0
  78. package/templates/app/api/v1/billing/cancel/route.ts +8 -10
  79. package/templates/app/api/v1/billing/change-plan/route.ts +2 -2
  80. package/templates/app/api/v1/billing/checkout/route.ts +6 -8
  81. package/templates/app/api/v1/billing/portal/route.ts +5 -5
  82. package/templates/app/api/v1/billing/presets.ts +1 -1
  83. package/templates/app/api/v1/billing/webhooks/polar/route.ts +83 -6
  84. package/templates/app/api/v1/billing/webhooks/stripe/route.ts +18 -421
  85. package/templates/app/layout.tsx +14 -5
  86. package/templates/app/superadmin/subscriptions/page.tsx +16 -14
  87. package/templates/app/superadmin/teams/[teamId]/page.tsx +18 -15
  88. package/templates/contents/themes/starter/tests/cypress/src/features/SuperadminPOM.ts +2 -2
  89. package/templates/lib/billing/polar-webhook-extensions.ts +23 -0
  90. package/templates/lib/billing/stripe-webhook-extensions.ts +23 -0
  91. package/tests/jest/__mocks__/@nextsparkjs/registries/billing-registry.ts +7 -8
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Core Stripe Webhook Handler
3
+ *
4
+ * Provides handleStripeWebhook() — a reusable function that handles the full
5
+ * Stripe subscription lifecycle. Themes/projects call this from their route file
6
+ * and can extend it with onOneTimePaymentCompleted for their custom one-time purchases.
7
+ *
8
+ * Usage in route.ts:
9
+ * import { handleStripeWebhook } from '@nextsparkjs/core/lib/billing/stripe-webhook'
10
+ * export async function POST(request: NextRequest) {
11
+ * return handleStripeWebhook(request)
12
+ * }
13
+ *
14
+ * With theme extension:
15
+ * export async function POST(request: NextRequest) {
16
+ * return handleStripeWebhook(request, {
17
+ * onOneTimePaymentCompleted: async (session, { teamId, userId }) => {
18
+ * // theme-specific one-time payment logic
19
+ * }
20
+ * })
21
+ * }
22
+ */
23
+ import { NextRequest } from 'next/server';
24
+ import type { OneTimePaymentContext } from './types';
25
+ export type { OneTimePaymentContext };
26
+ /**
27
+ * Provider-agnostic representation of a Stripe checkout session.
28
+ * Avoids leaking `Stripe.Checkout.Session` SDK type to project code.
29
+ */
30
+ export interface StripeSessionData {
31
+ id: string;
32
+ amountTotal: number | null;
33
+ currency: string | null;
34
+ customerId: string | null;
35
+ subscriptionId: string | null;
36
+ metadata: Record<string, string>;
37
+ clientReferenceId: string | null;
38
+ }
39
+ export interface StripeWebhookExtensions {
40
+ /**
41
+ * Called when a Stripe checkout.session.completed event fires for a session
42
+ * that is NOT a subscription checkout (no planSlug in metadata).
43
+ * Use this for credit packs, one-time purchases, etc.
44
+ */
45
+ onOneTimePaymentCompleted?: (session: StripeSessionData, context: OneTimePaymentContext) => Promise<void>;
46
+ }
47
+ export declare function handleStripeWebhook(request: NextRequest, extensions?: StripeWebhookExtensions): Promise<Response>;
48
+ //# sourceMappingURL=stripe-webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripe-webhook.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/stripe-webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAKzC,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEnE,YAAY,EAAE,qBAAqB,EAAE,CAAA;AAErC;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,CAC1B,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,uBAAuB,GACnC,OAAO,CAAC,QAAQ,CAAC,CAsEnB"}
@@ -0,0 +1,316 @@
1
+ import { getBillingGateway } from "./gateways/factory.js";
2
+ import { BILLING_REGISTRY } from "@nextsparkjs/registries/billing-registry";
3
+ import { query, queryOne } from "../db.js";
4
+ async function handleStripeWebhook(request, extensions) {
5
+ const payload = await request.text();
6
+ const signature = request.headers.get("stripe-signature");
7
+ if (!signature) {
8
+ return Response.json({ error: "No signature provided" }, { status: 400 });
9
+ }
10
+ let event;
11
+ try {
12
+ const verified = getBillingGateway().verifyWebhookSignature(payload, signature);
13
+ event = { id: verified.id, type: verified.type, data: verified.data };
14
+ } catch (error) {
15
+ console.error("[stripe-webhook] Signature verification failed:", error);
16
+ return Response.json({ error: "Invalid signature" }, { status: 400 });
17
+ }
18
+ const eventId = event.id;
19
+ const existing = await queryOne(
20
+ `SELECT id FROM "billing_events" WHERE metadata->>'stripeEventId' = $1`,
21
+ [eventId]
22
+ );
23
+ if (existing) {
24
+ console.log(`[stripe-webhook] Event ${eventId} already processed, skipping`);
25
+ return Response.json({ received: true, status: "duplicate" });
26
+ }
27
+ try {
28
+ console.log(`[stripe-webhook] Processing event type: ${event.type}`);
29
+ switch (event.type) {
30
+ case "checkout.session.completed":
31
+ await handleCheckoutCompleted(event.data.object, extensions);
32
+ break;
33
+ case "invoice.paid":
34
+ await handleInvoicePaid(event.data.object);
35
+ break;
36
+ case "invoice.payment_failed":
37
+ await handlePaymentFailed(event.data.object);
38
+ break;
39
+ case "customer.subscription.updated":
40
+ await handleSubscriptionUpdated(event.data.object);
41
+ break;
42
+ case "customer.subscription.deleted":
43
+ await handleSubscriptionDeleted(event.data.object);
44
+ break;
45
+ default:
46
+ console.log(`[stripe-webhook] Unhandled event type: ${event.type}`);
47
+ }
48
+ return Response.json({ received: true });
49
+ } catch (error) {
50
+ console.error("[stripe-webhook] Handler error:", error);
51
+ return Response.json({ error: "Handler failed" }, { status: 500 });
52
+ }
53
+ }
54
+ async function handleCheckoutCompleted(session, extensions) {
55
+ var _a, _b, _c, _d, _e;
56
+ const teamId = ((_a = session.metadata) == null ? void 0 : _a.teamId) || session.client_reference_id;
57
+ if (!teamId) {
58
+ console.warn("[stripe-webhook] checkout.session.completed has no teamId in metadata \u2014 skipping (likely a test/synthetic event)");
59
+ return;
60
+ }
61
+ const planSlug = (_b = session.metadata) == null ? void 0 : _b.planSlug;
62
+ const userId = ((_c = session.metadata) == null ? void 0 : _c.userId) || "system";
63
+ if (!planSlug) {
64
+ if (extensions == null ? void 0 : extensions.onOneTimePaymentCompleted) {
65
+ console.log(`[stripe-webhook] One-time payment for team ${teamId}, delegating to theme extension`);
66
+ const sessionData = {
67
+ id: session.id,
68
+ amountTotal: session.amount_total,
69
+ currency: session.currency,
70
+ customerId: typeof session.customer === "string" ? session.customer : ((_d = session.customer) == null ? void 0 : _d.id) ?? null,
71
+ subscriptionId: typeof session.subscription === "string" ? session.subscription : null,
72
+ metadata: session.metadata ?? {},
73
+ clientReferenceId: session.client_reference_id ?? null
74
+ };
75
+ await extensions.onOneTimePaymentCompleted(sessionData, { teamId, userId });
76
+ } else {
77
+ console.log(`[stripe-webhook] One-time payment for team ${teamId} \u2014 no handler registered, skipping`);
78
+ }
79
+ return;
80
+ }
81
+ const subscriptionId = session.subscription;
82
+ const customerId = session.customer;
83
+ const billingPeriod = ((_e = session.metadata) == null ? void 0 : _e.billingPeriod) || "monthly";
84
+ console.log(`[stripe-webhook] Checkout completed for team ${teamId}, plan: ${planSlug}`);
85
+ let planId = null;
86
+ const planResult = await queryOne(
87
+ `SELECT id FROM plans WHERE slug = $1 LIMIT 1`,
88
+ [planSlug]
89
+ );
90
+ planId = (planResult == null ? void 0 : planResult.id) || null;
91
+ if (!planId) {
92
+ console.warn(`[stripe-webhook] Plan ${planSlug} not found in database, keeping current plan`);
93
+ }
94
+ if (planId) {
95
+ await query(
96
+ `UPDATE subscriptions
97
+ SET "externalSubscriptionId" = $1,
98
+ "externalCustomerId" = $2,
99
+ "paymentProvider" = 'stripe',
100
+ "planId" = $3,
101
+ "billingInterval" = $4,
102
+ status = 'active',
103
+ "updatedAt" = NOW()
104
+ WHERE "teamId" = $5
105
+ AND status IN ('active', 'trialing', 'past_due')`,
106
+ [subscriptionId, customerId, planId, billingPeriod, teamId]
107
+ );
108
+ } else {
109
+ await query(
110
+ `UPDATE subscriptions
111
+ SET "externalSubscriptionId" = $1,
112
+ "externalCustomerId" = $2,
113
+ "paymentProvider" = 'stripe',
114
+ status = 'active',
115
+ "updatedAt" = NOW()
116
+ WHERE "teamId" = $3
117
+ AND status IN ('active', 'trialing', 'past_due')`,
118
+ [subscriptionId, customerId, teamId]
119
+ );
120
+ }
121
+ await logBillingEvent({
122
+ teamId,
123
+ type: "payment",
124
+ status: "succeeded",
125
+ amount: session.amount_total || 0,
126
+ currency: session.currency || "usd",
127
+ stripeEventId: session.id
128
+ });
129
+ }
130
+ async function handleInvoicePaid(invoice) {
131
+ var _a, _b, _c;
132
+ const expandedInvoice = invoice;
133
+ const subscriptionId = typeof expandedInvoice.subscription === "string" ? expandedInvoice.subscription : (_a = expandedInvoice.subscription) == null ? void 0 : _a.id;
134
+ if (!subscriptionId) {
135
+ console.log("[stripe-webhook] Invoice has no subscription ID, skipping");
136
+ return;
137
+ }
138
+ console.log(`[stripe-webhook] Invoice paid for subscription ${subscriptionId}`);
139
+ if ((_c = (_b = invoice.lines) == null ? void 0 : _b.data) == null ? void 0 : _c[0]) {
140
+ const line = invoice.lines.data[0];
141
+ await query(
142
+ `UPDATE subscriptions
143
+ SET status = 'active',
144
+ "currentPeriodStart" = to_timestamp($1),
145
+ "currentPeriodEnd" = to_timestamp($2),
146
+ "updatedAt" = NOW()
147
+ WHERE "externalSubscriptionId" = $3`,
148
+ [line.period.start, line.period.end, subscriptionId]
149
+ );
150
+ } else {
151
+ await query(
152
+ `UPDATE subscriptions
153
+ SET status = 'active',
154
+ "updatedAt" = NOW()
155
+ WHERE "externalSubscriptionId" = $1`,
156
+ [subscriptionId]
157
+ );
158
+ }
159
+ await syncInvoiceToDatabase(invoice, "paid");
160
+ }
161
+ async function handlePaymentFailed(invoice) {
162
+ var _a;
163
+ const expandedInvoice = invoice;
164
+ const subscriptionId = typeof expandedInvoice.subscription === "string" ? expandedInvoice.subscription : (_a = expandedInvoice.subscription) == null ? void 0 : _a.id;
165
+ if (!subscriptionId) {
166
+ console.log("[stripe-webhook] Invoice has no subscription ID, skipping");
167
+ return;
168
+ }
169
+ console.log(`[stripe-webhook] Payment failed for subscription ${subscriptionId}`);
170
+ await query(
171
+ `UPDATE subscriptions
172
+ SET status = 'past_due',
173
+ "updatedAt" = NOW()
174
+ WHERE "externalSubscriptionId" = $1`,
175
+ [subscriptionId]
176
+ );
177
+ await syncInvoiceToDatabase(invoice, "failed");
178
+ }
179
+ async function handleSubscriptionUpdated(subscription) {
180
+ var _a;
181
+ const statusMap = {
182
+ trialing: "trialing",
183
+ active: "active",
184
+ past_due: "past_due",
185
+ canceled: "canceled",
186
+ unpaid: "past_due",
187
+ incomplete: "past_due",
188
+ incomplete_expired: "expired",
189
+ paused: "paused"
190
+ };
191
+ const ourStatus = statusMap[subscription.status] || "active";
192
+ console.log(
193
+ `[stripe-webhook] Subscription updated ${subscription.id}, status: ${subscription.status} -> ${ourStatus}`
194
+ );
195
+ const expandedSubscription = subscription;
196
+ const periodEnd = expandedSubscription.current_period_end ?? null;
197
+ const priceId = (_a = subscription.items.data[0]) == null ? void 0 : _a.price.id;
198
+ let paramIdx = 1;
199
+ const setClauses = [
200
+ `status = $${paramIdx++}`,
201
+ `"cancelAtPeriodEnd" = $${paramIdx++}`
202
+ ];
203
+ const params = [
204
+ ourStatus,
205
+ subscription.cancel_at_period_end
206
+ ];
207
+ if (periodEnd !== null) {
208
+ setClauses.push(`"currentPeriodEnd" = to_timestamp($${paramIdx++})`);
209
+ params.push(periodEnd);
210
+ }
211
+ setClauses.push(`"updatedAt" = NOW()`);
212
+ if (priceId) {
213
+ const planConfig = BILLING_REGISTRY.plans.find(
214
+ (p) => {
215
+ var _a2, _b;
216
+ return ((_a2 = p.providerPriceIds) == null ? void 0 : _a2.monthly) === priceId || ((_b = p.providerPriceIds) == null ? void 0 : _b.yearly) === priceId;
217
+ }
218
+ );
219
+ if (planConfig) {
220
+ const planResult = await queryOne(
221
+ `SELECT id FROM plans WHERE slug = $1 LIMIT 1`,
222
+ [planConfig.slug]
223
+ );
224
+ if (planResult) {
225
+ setClauses.push(`"planId" = $${paramIdx++}`);
226
+ params.push(planResult.id);
227
+ }
228
+ }
229
+ }
230
+ const subIdIdx = paramIdx++;
231
+ params.push(subscription.id);
232
+ await query(
233
+ `UPDATE subscriptions
234
+ SET ${setClauses.join(", ")}
235
+ WHERE "externalSubscriptionId" = $${subIdIdx}`,
236
+ params
237
+ );
238
+ }
239
+ async function handleSubscriptionDeleted(subscription) {
240
+ console.log(`[stripe-webhook] Subscription deleted ${subscription.id}`);
241
+ await query(
242
+ `UPDATE subscriptions
243
+ SET status = 'canceled',
244
+ "canceledAt" = NOW(),
245
+ "updatedAt" = NOW()
246
+ WHERE "externalSubscriptionId" = $1`,
247
+ [subscription.id]
248
+ );
249
+ }
250
+ async function logBillingEvent(params) {
251
+ const sub = await queryOne(
252
+ `SELECT id FROM subscriptions WHERE "teamId" = $1 LIMIT 1`,
253
+ [params.teamId]
254
+ );
255
+ if (!sub) {
256
+ console.warn(`[stripe-webhook] No subscription found for team ${params.teamId}, cannot log billing event`);
257
+ return;
258
+ }
259
+ await query(
260
+ `INSERT INTO "billing_events" ("subscriptionId", type, status, amount, currency, metadata)
261
+ VALUES ($1, $2, $3, $4, $5, $6)`,
262
+ [
263
+ sub.id,
264
+ params.type,
265
+ params.status,
266
+ params.amount,
267
+ params.currency,
268
+ JSON.stringify({ stripeEventId: params.stripeEventId })
269
+ ]
270
+ );
271
+ }
272
+ async function syncInvoiceToDatabase(invoice, status) {
273
+ var _a;
274
+ const expandedInvoice = invoice;
275
+ const subscriptionId = typeof expandedInvoice.subscription === "string" ? expandedInvoice.subscription : (_a = expandedInvoice.subscription) == null ? void 0 : _a.id;
276
+ if (!subscriptionId) {
277
+ console.warn("[stripe-webhook] Invoice has no subscription, cannot sync to invoices table");
278
+ return;
279
+ }
280
+ const subResult = await query(
281
+ `SELECT "teamId" FROM subscriptions WHERE "externalSubscriptionId" = $1`,
282
+ [subscriptionId]
283
+ );
284
+ if (!subResult.rows[0]) {
285
+ console.warn(`[stripe-webhook] No subscription found for ${subscriptionId}, cannot sync invoice`);
286
+ return;
287
+ }
288
+ const teamId = subResult.rows[0].teamId;
289
+ const invoiceNumber = invoice.number || invoice.id;
290
+ const amountInDollars = invoice.total / 100;
291
+ await query(
292
+ `INSERT INTO invoices (
293
+ id, "teamId", "invoiceNumber", date, amount, currency, status, "pdfUrl", description
294
+ ) VALUES (
295
+ gen_random_uuid()::text, $1, $2, to_timestamp($3), $4, $5, $6::invoice_status, $7, $8
296
+ )
297
+ ON CONFLICT ("teamId", "invoiceNumber") DO UPDATE SET
298
+ status = EXCLUDED.status,
299
+ "pdfUrl" = EXCLUDED."pdfUrl",
300
+ "updatedAt" = NOW()`,
301
+ [
302
+ teamId,
303
+ invoiceNumber,
304
+ invoice.created,
305
+ amountInDollars,
306
+ invoice.currency.toUpperCase(),
307
+ status,
308
+ invoice.invoice_pdf || invoice.hosted_invoice_url || null,
309
+ invoice.description || `Invoice ${invoiceNumber}`
310
+ ]
311
+ );
312
+ console.log(`[stripe-webhook] Invoice ${invoiceNumber} synced for team ${teamId} with status ${status}`);
313
+ }
314
+ export {
315
+ handleStripeWebhook
316
+ };
@@ -25,7 +25,7 @@ export interface Plan {
25
25
  updatedAt: Date;
26
26
  }
27
27
  export type SubscriptionStatus = 'trialing' | 'active' | 'past_due' | 'canceled' | 'paused' | 'expired';
28
- export type PaymentProvider = 'stripe' | 'polar' | 'paddle' | 'lemonsqueezy';
28
+ export type PaymentProvider = 'stripe' | 'polar';
29
29
  export type BillingInterval = 'monthly' | 'yearly';
30
30
  export interface Subscription {
31
31
  id: string;
@@ -88,7 +88,7 @@ export interface BillingEvent {
88
88
  }
89
89
  export type InvoiceStatus = 'pending' | 'paid' | 'failed' | 'refunded';
90
90
  /**
91
- * Invoice from Stripe synced to local database
91
+ * Invoice synced from payment provider to local database
92
92
  */
93
93
  export interface Invoice {
94
94
  id: string;
@@ -133,6 +133,10 @@ export interface TeamUsageSummary {
133
133
  byUser: UserUsageSummary[];
134
134
  topConsumers: TopConsumer[];
135
135
  }
136
+ export interface OneTimePaymentContext {
137
+ teamId: string;
138
+ userId: string;
139
+ }
136
140
  export interface CanPerformActionResult {
137
141
  allowed: boolean;
138
142
  reason?: 'no_permission' | 'feature_not_in_plan' | 'quota_exceeded';
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/types.ts"],"names":[],"mappings":"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"}
@@ -19,12 +19,12 @@ export interface RateLimitCheckResult {
19
19
  /**
20
20
  * Rate limit tiers available for API endpoints
21
21
  */
22
- export type RateLimitTier = 'auth' | 'api' | 'strict' | 'read' | 'write';
22
+ export type RateLimitTier = 'auth' | 'api' | 'strict' | 'read' | 'write' | 'webhook';
23
23
  /**
24
24
  * Check rate limit for a given identifier
25
25
  *
26
26
  * @param identifier - Unique identifier (e.g., IP address, user ID, or combination)
27
- * @param type - Rate limit tier: 'auth' (5/15min), 'api' (100/1min), 'strict' (10/1hr), 'read' (200/1min), 'write' (50/1min)
27
+ * @param type - Rate limit tier: 'auth' (5/15min), 'api' (100/1min), 'strict' (10/1hr), 'read' (200/1min), 'write' (50/1min), 'webhook' (500/1hr)
28
28
  * @returns Promise with success status, remaining requests, and reset timestamp
29
29
  */
30
30
  export declare function checkRateLimit(identifier: string, type?: RateLimitTier): Promise<RateLimitCheckResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit-redis.d.ts","sourceRoot":"","sources":["../../src/lib/rate-limit-redis.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgIH,eAAO,MAAM,eAAe,KAAO,CAAA;AACnC,eAAO,MAAM,cAAc,KAAO,CAAA;AAClC,eAAO,MAAM,iBAAiB,KAAO,CAAA;AAErC,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;AAaxE;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAqB,GAC1B,OAAO,CAAC,oBAAoB,CAAC,CA+C/B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAG1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAexF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,oBAAoB,GAAG,QAAQ,CAe9E"}
1
+ {"version":3,"file":"rate-limit-redis.d.ts","sourceRoot":"","sources":["../../src/lib/rate-limit-redis.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA2IH,eAAO,MAAM,eAAe,KAAO,CAAA;AACnC,eAAO,MAAM,cAAc,KAAO,CAAA;AAClC,eAAO,MAAM,iBAAiB,KAAO,CAAA;AAErC,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;AAcpF;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAqB,GAC1B,OAAO,CAAC,oBAAoB,CAAC,CAuD/B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAG1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAexF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,oBAAoB,GAAG,QAAQ,CAe9E"}
@@ -2,12 +2,14 @@ let Redis = null;
2
2
  let Ratelimit = null;
3
3
  let modulesLoaded = false;
4
4
  let loadError = null;
5
+ let redisUnconfiguredLogged = false;
5
6
  let redis = null;
6
7
  let authRateLimiterInstance = null;
7
8
  let apiRateLimiterInstance = null;
8
9
  let strictRateLimiterInstance = null;
9
10
  let readRateLimiterInstance = null;
10
11
  let writeRateLimiterInstance = null;
12
+ let webhookRateLimiterInstance = null;
11
13
  async function loadUpstashModules() {
12
14
  if (modulesLoaded) return !loadError;
13
15
  try {
@@ -57,13 +59,20 @@ async function loadUpstashModules() {
57
59
  prefix: "ratelimit:write",
58
60
  ephemeralCache: /* @__PURE__ */ new Map()
59
61
  });
62
+ webhookRateLimiterInstance = new Ratelimit({
63
+ redis,
64
+ limiter: Ratelimit.slidingWindow(500, "1 h"),
65
+ analytics: true,
66
+ prefix: "ratelimit:webhook",
67
+ ephemeralCache: /* @__PURE__ */ new Map()
68
+ });
60
69
  }
61
70
  modulesLoaded = true;
62
71
  return true;
63
72
  } catch (error) {
64
73
  loadError = error;
65
74
  modulesLoaded = true;
66
- if (process.env.NODE_ENV === "development") {
75
+ if (process.env.NODE_ENV !== "production") {
67
76
  console.warn("[RateLimit] Upstash modules not available, using fallback:", error.message);
68
77
  }
69
78
  return false;
@@ -77,7 +86,8 @@ const DEFAULT_TIER_LIMITS = {
77
86
  api: 100,
78
87
  strict: 10,
79
88
  read: 200,
80
- write: 50
89
+ write: 50,
90
+ webhook: 500
81
91
  };
82
92
  async function checkRateLimit(identifier, type = "api") {
83
93
  await loadUpstashModules();
@@ -86,11 +96,19 @@ async function checkRateLimit(identifier, type = "api") {
86
96
  api: apiRateLimiterInstance,
87
97
  strict: strictRateLimiterInstance,
88
98
  read: readRateLimiterInstance,
89
- write: writeRateLimiterInstance
99
+ write: writeRateLimiterInstance,
100
+ webhook: webhookRateLimiterInstance
90
101
  };
91
102
  const limiter = limiterMap[type];
92
103
  if (!limiter) {
93
- console.warn("[RateLimit] FALLBACK MODE: Rate limiting disabled - Redis unavailable. Identifier:", identifier, "Tier:", type);
104
+ if (!redisUnconfiguredLogged) {
105
+ redisUnconfiguredLogged = true;
106
+ console.error(
107
+ "[RateLimit] CRITICAL: Rate limiting is DISABLED (Redis unavailable).",
108
+ "Set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN to enable distributed rate limiting.",
109
+ "All requests are currently allowed through without limit enforcement."
110
+ );
111
+ }
94
112
  return {
95
113
  success: true,
96
114
  remaining: DEFAULT_TIER_LIMITS[type],
@@ -1091,7 +1091,7 @@ export declare const CORE_SELECTORS: {
1091
1091
  readonly plan: "superadmin-team-plan";
1092
1092
  readonly status: "superadmin-team-sub-status";
1093
1093
  readonly period: "superadmin-team-sub-period";
1094
- readonly stripeLink: "superadmin-team-stripe-link";
1094
+ readonly providerLink: "superadmin-team-provider-link";
1095
1095
  };
1096
1096
  readonly billingHistory: {
1097
1097
  readonly container: "superadmin-team-billing";
@@ -1130,7 +1130,7 @@ export declare const CORE_SELECTORS: {
1130
1130
  readonly element: "superadmin-subscriptions-table";
1131
1131
  readonly row: "superadmin-subscriptions-row-{id}";
1132
1132
  readonly viewTeamButton: "superadmin-subscriptions-view-team-{id}";
1133
- readonly stripeLink: "superadmin-subscriptions-stripe-{id}";
1133
+ readonly providerLink: "superadmin-subscriptions-provider-{id}";
1134
1134
  };
1135
1135
  readonly pagination: {
1136
1136
  readonly container: "superadmin-subscriptions-pagination";
@@ -211,7 +211,7 @@ export declare const SUPERADMIN_SELECTORS: {
211
211
  readonly plan: "superadmin-team-plan";
212
212
  readonly status: "superadmin-team-sub-status";
213
213
  readonly period: "superadmin-team-sub-period";
214
- readonly stripeLink: "superadmin-team-stripe-link";
214
+ readonly providerLink: "superadmin-team-provider-link";
215
215
  };
216
216
  readonly billingHistory: {
217
217
  readonly container: "superadmin-team-billing";
@@ -250,7 +250,7 @@ export declare const SUPERADMIN_SELECTORS: {
250
250
  readonly element: "superadmin-subscriptions-table";
251
251
  readonly row: "superadmin-subscriptions-row-{id}";
252
252
  readonly viewTeamButton: "superadmin-subscriptions-view-team-{id}";
253
- readonly stripeLink: "superadmin-subscriptions-stripe-{id}";
253
+ readonly providerLink: "superadmin-subscriptions-provider-{id}";
254
254
  };
255
255
  readonly pagination: {
256
256
  readonly container: "superadmin-subscriptions-pagination";
@@ -168,7 +168,7 @@ const SUPERADMIN_SELECTORS = {
168
168
  plan: "superadmin-team-plan",
169
169
  status: "superadmin-team-sub-status",
170
170
  period: "superadmin-team-sub-period",
171
- stripeLink: "superadmin-team-stripe-link"
171
+ providerLink: "superadmin-team-provider-link"
172
172
  },
173
173
  billingHistory: {
174
174
  container: "superadmin-team-billing",
@@ -210,7 +210,7 @@ const SUPERADMIN_SELECTORS = {
210
210
  element: "superadmin-subscriptions-table",
211
211
  row: "superadmin-subscriptions-row-{id}",
212
212
  viewTeamButton: "superadmin-subscriptions-view-team-{id}",
213
- stripeLink: "superadmin-subscriptions-stripe-{id}"
213
+ providerLink: "superadmin-subscriptions-provider-{id}"
214
214
  },
215
215
  pagination: {
216
216
  container: "superadmin-subscriptions-pagination",
@@ -1090,7 +1090,7 @@ export declare const SELECTORS: {
1090
1090
  readonly plan: "superadmin-team-plan";
1091
1091
  readonly status: "superadmin-team-sub-status";
1092
1092
  readonly period: "superadmin-team-sub-period";
1093
- readonly stripeLink: "superadmin-team-stripe-link";
1093
+ readonly providerLink: "superadmin-team-provider-link";
1094
1094
  };
1095
1095
  readonly billingHistory: {
1096
1096
  readonly container: "superadmin-team-billing";
@@ -1129,7 +1129,7 @@ export declare const SELECTORS: {
1129
1129
  readonly element: "superadmin-subscriptions-table";
1130
1130
  readonly row: "superadmin-subscriptions-row-{id}";
1131
1131
  readonly viewTeamButton: "superadmin-subscriptions-view-team-{id}";
1132
- readonly stripeLink: "superadmin-subscriptions-stripe-{id}";
1132
+ readonly providerLink: "superadmin-subscriptions-provider-{id}";
1133
1133
  };
1134
1134
  readonly pagination: {
1135
1135
  readonly container: "superadmin-subscriptions-pagination";
@@ -2671,7 +2671,7 @@ declare const _default: {
2671
2671
  readonly plan: "superadmin-team-plan";
2672
2672
  readonly status: "superadmin-team-sub-status";
2673
2673
  readonly period: "superadmin-team-sub-period";
2674
- readonly stripeLink: "superadmin-team-stripe-link";
2674
+ readonly providerLink: "superadmin-team-provider-link";
2675
2675
  };
2676
2676
  readonly billingHistory: {
2677
2677
  readonly container: "superadmin-team-billing";
@@ -2710,7 +2710,7 @@ declare const _default: {
2710
2710
  readonly element: "superadmin-subscriptions-table";
2711
2711
  readonly row: "superadmin-subscriptions-row-{id}";
2712
2712
  readonly viewTeamButton: "superadmin-subscriptions-view-team-{id}";
2713
- readonly stripeLink: "superadmin-subscriptions-stripe-{id}";
2713
+ readonly providerLink: "superadmin-subscriptions-provider-{id}";
2714
2714
  };
2715
2715
  readonly pagination: {
2716
2716
  readonly container: "superadmin-subscriptions-pagination";
@@ -2,7 +2,7 @@
2
2
  * Invoice Service
3
3
  *
4
4
  * Provides invoice management functions for billing operations.
5
- * Invoices are synced from Stripe and stored locally for fast access.
5
+ * Invoices are synced from the payment provider and stored locally for fast access.
6
6
  *
7
7
  * @module InvoiceService
8
8
  */
@@ -180,11 +180,11 @@ export declare class InvoiceService {
180
180
  * Update invoice PDF URL
181
181
  *
182
182
  * @param id - Invoice ID
183
- * @param pdfUrl - PDF URL from Stripe
183
+ * @param pdfUrl - PDF URL from payment provider
184
184
  * @returns Updated invoice
185
185
  *
186
186
  * @example
187
- * await InvoiceService.updatePdfUrl('inv-123', 'https://stripe.com/...')
187
+ * await InvoiceService.updatePdfUrl('inv-123', 'https://example.com/invoice.pdf')
188
188
  */
189
189
  static updatePdfUrl(id: string, pdfUrl: string): Promise<Invoice>;
190
190
  /**
@@ -348,11 +348,11 @@ class InvoiceService {
348
348
  * Update invoice PDF URL
349
349
  *
350
350
  * @param id - Invoice ID
351
- * @param pdfUrl - PDF URL from Stripe
351
+ * @param pdfUrl - PDF URL from payment provider
352
352
  * @returns Updated invoice
353
353
  *
354
354
  * @example
355
- * await InvoiceService.updatePdfUrl('inv-123', 'https://stripe.com/...')
355
+ * await InvoiceService.updatePdfUrl('inv-123', 'https://example.com/invoice.pdf')
356
356
  */
357
357
  static async updatePdfUrl(id, pdfUrl) {
358
358
  if (!id || id.trim() === "") {
@@ -1 +1 @@
1
- {"version":3,"file":"membership.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/membership.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EAEZ,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EACnB,MAAM,sBAAsB,CAAA;AAM7B;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,kBAAkB;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,UAAU,EAAE,CAAA;IAClC,QAAQ,CAAC,YAAY,EAAE,sBAAsB,GAAG,IAAI,CAAA;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;gBAE/B,IAAI,EAAE,kBAAkB;IAWpC;;;;;;;;;;OAUG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIvC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI9B;;;;;;;;;;OAUG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO;IAKpC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO;IAI9C;;;;;;;;;;OAUG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIpC;;;;;;;;;;;;OAYG;IACH,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,MAAU,GACpB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAmB1C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GACpC,YAAY;CAmDhB;AAMD,qBAAa,iBAAiB;IAC5B;;;;;;;;;;;;;;;;;;OAkBG;WACU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkEzE;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAiBlC;;;;;;;;OAQG;mBACkB,cAAc;CAyCpC"}
1
+ {"version":3,"file":"membership.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/membership.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EACnB,MAAM,sBAAsB,CAAA;AAM7B;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,kBAAkB;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,UAAU,EAAE,CAAA;IAClC,QAAQ,CAAC,YAAY,EAAE,sBAAsB,GAAG,IAAI,CAAA;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;gBAE/B,IAAI,EAAE,kBAAkB;IAWpC;;;;;;;;;;OAUG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIvC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI9B;;;;;;;;;;OAUG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO;IAKpC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO;IAI9C;;;;;;;;;;OAUG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIpC;;;;;;;;;;;;OAYG;IACH,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,MAAU,GACpB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAmB1C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GACpC,YAAY;CA0EhB;AAMD,qBAAa,iBAAiB;IAC5B;;;;;;;;;;;;;;;;;;OAkBG;WACU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkEzE;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAiBlC;;;;;;;;OAQG;mBACkB,cAAc;CAyCpC"}