@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.
- package/dist/components/billing/ManageBillingButton.d.ts +3 -3
- package/dist/lib/api/rate-limit.d.ts.map +1 -1
- package/dist/lib/api/rate-limit.js +9 -6
- package/dist/lib/billing/config-types.d.ts +2 -5
- package/dist/lib/billing/config-types.d.ts.map +1 -1
- package/dist/lib/billing/gateways/factory.d.ts +13 -2
- package/dist/lib/billing/gateways/factory.d.ts.map +1 -1
- package/dist/lib/billing/gateways/factory.js +13 -6
- package/dist/lib/billing/gateways/interface.d.ts +19 -1
- package/dist/lib/billing/gateways/interface.d.ts.map +1 -1
- package/dist/lib/billing/gateways/polar.d.ts +8 -1
- package/dist/lib/billing/gateways/polar.d.ts.map +1 -1
- package/dist/lib/billing/gateways/polar.js +25 -0
- package/dist/lib/billing/gateways/stripe.d.ts +8 -26
- package/dist/lib/billing/gateways/stripe.d.ts.map +1 -1
- package/dist/lib/billing/gateways/stripe.js +41 -44
- package/dist/lib/billing/gateways/types.d.ts +11 -0
- package/dist/lib/billing/gateways/types.d.ts.map +1 -1
- package/dist/lib/billing/jobs.d.ts +1 -1
- package/dist/lib/billing/polar-webhook.d.ts +38 -0
- package/dist/lib/billing/polar-webhook.d.ts.map +1 -0
- package/dist/lib/billing/polar-webhook.js +0 -0
- package/dist/lib/billing/schema.d.ts +1 -2
- package/dist/lib/billing/schema.d.ts.map +1 -1
- package/dist/lib/billing/schema.js +1 -1
- package/dist/lib/billing/stripe-webhook.d.ts +48 -0
- package/dist/lib/billing/stripe-webhook.d.ts.map +1 -0
- package/dist/lib/billing/stripe-webhook.js +316 -0
- package/dist/lib/billing/types.d.ts +6 -2
- package/dist/lib/billing/types.d.ts.map +1 -1
- package/dist/lib/rate-limit-redis.d.ts +2 -2
- package/dist/lib/rate-limit-redis.d.ts.map +1 -1
- package/dist/lib/rate-limit-redis.js +22 -4
- package/dist/lib/selectors/core-selectors.d.ts +2 -2
- package/dist/lib/selectors/domains/superadmin.selectors.d.ts +2 -2
- package/dist/lib/selectors/domains/superadmin.selectors.js +2 -2
- package/dist/lib/selectors/selectors.d.ts +4 -4
- package/dist/lib/services/invoice.service.d.ts +3 -3
- package/dist/lib/services/invoice.service.js +2 -2
- package/dist/lib/services/membership.service.d.ts.map +1 -1
- package/dist/lib/services/membership.service.js +29 -0
- package/dist/lib/services/plan.service.d.ts +0 -3
- package/dist/lib/services/plan.service.d.ts.map +1 -1
- package/dist/lib/services/plan.service.js +3 -9
- package/dist/lib/services/subscription.service.d.ts +5 -5
- package/dist/lib/services/subscription.service.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.js +54 -41
- package/dist/migrations/001_better_auth_and_functions.sql +5 -11
- package/dist/migrations/008_team_members_table.sql +27 -23
- package/dist/styles/classes.json +1 -1
- package/dist/templates/app/api/auth/[...all]/route.ts +35 -0
- package/dist/templates/app/api/health/route.ts +43 -23
- package/dist/templates/app/api/internal/user-metadata/route.ts +10 -0
- package/dist/templates/app/api/superadmin/subscriptions/route.ts +5 -0
- package/dist/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -0
- package/dist/templates/app/api/v1/billing/cancel/route.ts +8 -10
- package/dist/templates/app/api/v1/billing/change-plan/route.ts +2 -2
- package/dist/templates/app/api/v1/billing/checkout/route.ts +6 -8
- package/dist/templates/app/api/v1/billing/portal/route.ts +5 -5
- package/dist/templates/app/api/v1/billing/presets.ts +1 -1
- package/dist/templates/app/api/v1/billing/webhooks/polar/route.ts +83 -6
- package/dist/templates/app/api/v1/billing/webhooks/stripe/route.ts +18 -421
- package/dist/templates/app/layout.tsx +14 -5
- package/dist/templates/app/superadmin/subscriptions/page.tsx +16 -14
- package/dist/templates/app/superadmin/teams/[teamId]/page.tsx +18 -15
- package/dist/templates/contents/themes/starter/tests/cypress/src/features/SuperadminPOM.ts +2 -2
- package/dist/templates/lib/billing/polar-webhook-extensions.ts +23 -0
- package/dist/templates/lib/billing/stripe-webhook-extensions.ts +23 -0
- package/migrations/001_better_auth_and_functions.sql +5 -11
- package/migrations/008_team_members_table.sql +27 -23
- package/package.json +10 -2
- package/scripts/build/registry/generators/billing-registry.mjs +1 -2
- package/templates/app/api/auth/[...all]/route.ts +35 -0
- package/templates/app/api/health/route.ts +43 -23
- package/templates/app/api/internal/user-metadata/route.ts +10 -0
- package/templates/app/api/superadmin/subscriptions/route.ts +5 -0
- package/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -0
- package/templates/app/api/v1/billing/cancel/route.ts +8 -10
- package/templates/app/api/v1/billing/change-plan/route.ts +2 -2
- package/templates/app/api/v1/billing/checkout/route.ts +6 -8
- package/templates/app/api/v1/billing/portal/route.ts +5 -5
- package/templates/app/api/v1/billing/presets.ts +1 -1
- package/templates/app/api/v1/billing/webhooks/polar/route.ts +83 -6
- package/templates/app/api/v1/billing/webhooks/stripe/route.ts +18 -421
- package/templates/app/layout.tsx +14 -5
- package/templates/app/superadmin/subscriptions/page.tsx +16 -14
- package/templates/app/superadmin/teams/[teamId]/page.tsx +18 -15
- package/templates/contents/themes/starter/tests/cypress/src/features/SuperadminPOM.ts +2 -2
- package/templates/lib/billing/polar-webhook-extensions.ts +23 -0
- package/templates/lib/billing/stripe-webhook-extensions.ts +23 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/billing-registry.ts +7 -8
|
@@ -2,10 +2,10 @@ interface ManageBillingButtonProps {
|
|
|
2
2
|
className?: string;
|
|
3
3
|
}
|
|
4
4
|
/**
|
|
5
|
-
* ManageBillingButton - Redirect to
|
|
5
|
+
* ManageBillingButton - Redirect to Billing Management Portal
|
|
6
6
|
*
|
|
7
|
-
* Button that opens
|
|
8
|
-
* Only visible for subscriptions with an external
|
|
7
|
+
* Button that opens the payment provider's hosted billing portal for subscription management.
|
|
8
|
+
* Only visible for subscriptions with an external customer ID.
|
|
9
9
|
*
|
|
10
10
|
* Features:
|
|
11
11
|
* - Update payment method
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/lib/api/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAa,EACpB,QAAQ,GAAE,MAAc,GACvB,eAAe,CAyCjB;AAED;;;GAGG;AACH,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAqB,GAC1B,OAAO,CAAC,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/lib/api/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAa,EACpB,QAAQ,GAAE,MAAc,GACvB,eAAe,CAyCjB;AAED;;;GAGG;AACH,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAqB,GAC1B,OAAO,CAAC,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwCpD;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAwB5G;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,IAAI,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,YAAY,GAAG,IAAI,CAkCrB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,YAAY,CASd;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,OAAO,EAAE,EAC/C,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,IAEtD,SAAS,WAAW,EAAE,GAAG,MAAM,CAAC,KAAG,OAAO,CAAC,YAAY,CAAC,CAsCvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,IAAI,CAaP;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,KAAK,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CASD;AAED;;GAEG;AACH,wBAAgB,sBAAsB;;;;;EAErC;AAoGD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,EACnD,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,EACpE,IAAI,GAAE,aAAqB,IAEb,SAAS,WAAW,EAAE,GAAG,MAAM,CAAC,KAAG,OAAO,CAAC,YAAY,CAAC,CAkCvE"}
|
|
@@ -46,7 +46,8 @@ async function checkDistributedRateLimit(identifier, type = "api") {
|
|
|
46
46
|
api: 100,
|
|
47
47
|
strict: 10,
|
|
48
48
|
read: 200,
|
|
49
|
-
write: 50
|
|
49
|
+
write: 50,
|
|
50
|
+
webhook: 500
|
|
50
51
|
};
|
|
51
52
|
return {
|
|
52
53
|
allowed: result2.success,
|
|
@@ -65,8 +66,10 @@ async function checkDistributedRateLimit(identifier, type = "api") {
|
|
|
65
66
|
// 10 requests per hour
|
|
66
67
|
read: { limit: 200, windowMs: 60 * 1e3 },
|
|
67
68
|
// 200 requests per minute
|
|
68
|
-
write: { limit: 50, windowMs: 60 * 1e3 }
|
|
69
|
+
write: { limit: 50, windowMs: 60 * 1e3 },
|
|
69
70
|
// 50 requests per minute
|
|
71
|
+
webhook: { limit: 500, windowMs: 60 * 60 * 1e3 }
|
|
72
|
+
// 500 requests per hour
|
|
70
73
|
};
|
|
71
74
|
const config = limits[type];
|
|
72
75
|
const result = checkRateLimit(`${type}:${identifier}`, config.limit, config.windowMs);
|
|
@@ -200,15 +203,15 @@ function getRateLimitCacheStats() {
|
|
|
200
203
|
return rateLimitCache.getStats();
|
|
201
204
|
}
|
|
202
205
|
function getClientIp(request) {
|
|
206
|
+
const cfIp = request.headers.get("cf-connecting-ip");
|
|
207
|
+
if (cfIp) return cfIp;
|
|
203
208
|
const forwardedFor = request.headers.get("x-forwarded-for");
|
|
204
209
|
if (forwardedFor) {
|
|
205
|
-
const ips = forwardedFor.split(",").map((ip) => ip.trim());
|
|
206
|
-
if (ips
|
|
210
|
+
const ips = forwardedFor.split(",").map((ip) => ip.trim()).filter(Boolean);
|
|
211
|
+
if (ips.length > 0) return ips[ips.length - 1];
|
|
207
212
|
}
|
|
208
213
|
const realIp = request.headers.get("x-real-ip");
|
|
209
214
|
if (realIp) return realIp;
|
|
210
|
-
const cfIp = request.headers.get("cf-connecting-ip");
|
|
211
|
-
if (cfIp) return cfIp;
|
|
212
215
|
const trueClientIp = request.headers.get("true-client-ip");
|
|
213
216
|
if (trueClientIp) return trueClientIp;
|
|
214
217
|
return "unknown";
|
|
@@ -37,10 +37,7 @@ export interface PlanDefinition {
|
|
|
37
37
|
features: string[];
|
|
38
38
|
/** Map of limitSlug -> value (-1 means unlimited) */
|
|
39
39
|
limits: Record<string, number>;
|
|
40
|
-
/**
|
|
41
|
-
stripePriceIdMonthly?: string | null;
|
|
42
|
-
stripePriceIdYearly?: string | null;
|
|
43
|
-
/** Generic price IDs for any payment provider (checked first, falls back to stripe-specific) */
|
|
40
|
+
/** Price IDs for the configured payment provider (monthly and yearly) */
|
|
44
41
|
providerPriceIds?: {
|
|
45
42
|
monthly?: string | null;
|
|
46
43
|
yearly?: string | null;
|
|
@@ -64,7 +61,7 @@ export interface ActionMappings {
|
|
|
64
61
|
limits: Record<string, string>;
|
|
65
62
|
}
|
|
66
63
|
export interface BillingConfig {
|
|
67
|
-
/** Payment provider: stripe,
|
|
64
|
+
/** Payment provider: stripe, polar */
|
|
68
65
|
provider: PaymentProvider;
|
|
69
66
|
/** Default currency (ISO 4217) */
|
|
70
67
|
currency: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-types.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/config-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAMxE,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,qCAAqC;IACrC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAA;IACjC,sCAAsC;IACtC,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAA;CACtD;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,QAAQ,CAAA;IACd,UAAU,CAAC,EAAE,cAAc,CAAA;IAC3B,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,
|
|
1
|
+
{"version":3,"file":"config-types.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/config-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAMxE,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,qCAAqC;IACrC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAA;IACjC,sCAAsC;IACtC,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAA;CACtD;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,QAAQ,CAAA;IACd,UAAU,CAAC,EAAE,cAAc,CAAA;IAC3B,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,yEAAyE;IACzE,gBAAgB,CAAC,EAAE;QACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KACvB,CAAA;CACF;AAMD,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAMD,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,QAAQ,EAAE,eAAe,CAAA;IAEzB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAA;IAEhB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAA;IAEnB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;IAE3C,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAEvC,uBAAuB;IACvB,KAAK,EAAE,cAAc,EAAE,CAAA;IAEvB,uCAAuC;IACvC,cAAc,EAAE,cAAc,CAAA;CAC/B"}
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Billing Gateway Factory
|
|
3
3
|
*
|
|
4
4
|
* Returns the configured BillingGateway implementation based on the
|
|
5
|
-
* provider setting in the billing registry.
|
|
6
|
-
* provider SDKs (Stripe, Polar, etc.) are only imported when needed.
|
|
5
|
+
* provider setting in the billing registry.
|
|
7
6
|
*
|
|
8
7
|
* Usage:
|
|
9
8
|
* import { getBillingGateway } from '@nextsparkjs/core/lib/billing/gateways/factory'
|
|
@@ -17,6 +16,18 @@ import type { BillingGateway } from './interface';
|
|
|
17
16
|
* Provider is determined by BILLING_REGISTRY.config.provider (from billing.config.ts).
|
|
18
17
|
*/
|
|
19
18
|
export declare function getBillingGateway(): BillingGateway;
|
|
19
|
+
/**
|
|
20
|
+
* Get resource hint domains for the configured billing provider.
|
|
21
|
+
* Use in <head> for performance optimization.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // In layout.tsx:
|
|
25
|
+
* const { preconnect, dnsPrefetch } = getBillingResourceHints()
|
|
26
|
+
*/
|
|
27
|
+
export declare function getBillingResourceHints(): {
|
|
28
|
+
preconnect: string[];
|
|
29
|
+
dnsPrefetch: string[];
|
|
30
|
+
};
|
|
20
31
|
/**
|
|
21
32
|
* Reset the cached gateway instance.
|
|
22
33
|
* Useful for testing or when billing config changes at runtime.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/factory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAIjD;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAuBlD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAMzF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { BILLING_REGISTRY } from "@nextsparkjs/registries/billing-registry";
|
|
2
|
+
import { StripeGateway } from "./stripe.js";
|
|
3
|
+
import { PolarGateway } from "./polar.js";
|
|
2
4
|
let gatewayInstance = null;
|
|
3
5
|
function getBillingGateway() {
|
|
4
6
|
if (!gatewayInstance) {
|
|
5
7
|
const provider = BILLING_REGISTRY.provider;
|
|
6
8
|
switch (provider) {
|
|
7
|
-
case "stripe":
|
|
8
|
-
const { StripeGateway } = require("./stripe");
|
|
9
|
+
case "stripe":
|
|
9
10
|
gatewayInstance = new StripeGateway();
|
|
10
11
|
break;
|
|
11
|
-
|
|
12
|
-
case "polar": {
|
|
13
|
-
const { PolarGateway } = require("./polar");
|
|
12
|
+
case "polar":
|
|
14
13
|
gatewayInstance = new PolarGateway();
|
|
15
14
|
break;
|
|
16
|
-
}
|
|
17
15
|
// Future providers:
|
|
18
16
|
// case 'paddle': { ... }
|
|
19
17
|
// case 'lemonsqueezy': { ... }
|
|
18
|
+
// case 'mercadopago': { ... }
|
|
20
19
|
default:
|
|
21
20
|
throw new Error(
|
|
22
21
|
`Unsupported billing provider: "${provider}". Supported providers: stripe, polar. Check your billing.config.ts provider setting.`
|
|
@@ -25,10 +24,18 @@ function getBillingGateway() {
|
|
|
25
24
|
}
|
|
26
25
|
return gatewayInstance;
|
|
27
26
|
}
|
|
27
|
+
function getBillingResourceHints() {
|
|
28
|
+
try {
|
|
29
|
+
return getBillingGateway().getResourceHintDomains();
|
|
30
|
+
} catch {
|
|
31
|
+
return { preconnect: [], dnsPrefetch: [] };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
28
34
|
function resetBillingGateway() {
|
|
29
35
|
gatewayInstance = null;
|
|
30
36
|
}
|
|
31
37
|
export {
|
|
32
38
|
getBillingGateway,
|
|
39
|
+
getBillingResourceHints,
|
|
33
40
|
resetBillingGateway
|
|
34
41
|
};
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Consumers interact with this interface via the factory (getBillingGateway()),
|
|
6
6
|
* making provider switching a configuration change rather than a code change.
|
|
7
7
|
*/
|
|
8
|
-
import type { CheckoutSessionResult, PortalSessionResult, SubscriptionResult, CustomerResult, WebhookEventResult, CreateCheckoutParams, CreatePortalParams, CreateCustomerParams, UpdateSubscriptionParams } from './types';
|
|
8
|
+
import type { CheckoutSessionResult, PortalSessionResult, SubscriptionResult, CustomerResult, WebhookEventResult, CreateCheckoutParams, CreatePortalParams, CreateCustomerParams, UpdateSubscriptionParams, CreateOneTimeCheckoutParams } from './types';
|
|
9
9
|
export interface BillingGateway {
|
|
10
10
|
createCheckoutSession(params: CreateCheckoutParams): Promise<CheckoutSessionResult>;
|
|
11
|
+
createOneTimeCheckout(params: CreateOneTimeCheckoutParams): Promise<CheckoutSessionResult>;
|
|
11
12
|
createPortalSession(params: CreatePortalParams): Promise<PortalSessionResult>;
|
|
12
13
|
getCustomer(customerId: string): Promise<CustomerResult>;
|
|
13
14
|
createCustomer(params: CreateCustomerParams): Promise<CustomerResult>;
|
|
@@ -15,6 +16,23 @@ export interface BillingGateway {
|
|
|
15
16
|
cancelSubscriptionAtPeriodEnd(subscriptionId: string): Promise<SubscriptionResult>;
|
|
16
17
|
cancelSubscriptionImmediately(subscriptionId: string): Promise<SubscriptionResult>;
|
|
17
18
|
reactivateSubscription(subscriptionId: string): Promise<SubscriptionResult>;
|
|
19
|
+
/** Get the human-readable provider name (e.g., "Stripe", "Polar") */
|
|
20
|
+
getProviderName(): string;
|
|
21
|
+
/**
|
|
22
|
+
* Get resource hint domains for the <head>.
|
|
23
|
+
* - preconnect: domains loaded immediately on page render (DNS + TCP + TLS)
|
|
24
|
+
* - dnsPrefetch: domains used later after user interaction (DNS only)
|
|
25
|
+
*
|
|
26
|
+
* Note: preconnect sockets expire after ~10s, so only use for resources
|
|
27
|
+
* loaded during initial render. Use dnsPrefetch for domains used after
|
|
28
|
+
* user interaction (e.g., API calls on form submit).
|
|
29
|
+
*/
|
|
30
|
+
getResourceHintDomains(): {
|
|
31
|
+
preconnect: string[];
|
|
32
|
+
dnsPrefetch: string[];
|
|
33
|
+
};
|
|
34
|
+
/** Get the provider dashboard URL for a subscription (e.g., Stripe Dashboard, Polar Dashboard) */
|
|
35
|
+
getSubscriptionDashboardUrl(externalSubscriptionId: string | null | undefined): string | null;
|
|
18
36
|
verifyWebhookSignature(payload: string | Buffer, signatureOrHeaders: string | Record<string, string>): WebhookEventResult;
|
|
19
37
|
}
|
|
20
38
|
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,cAAc;IAE7B,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACnF,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC1F,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAG7E,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IACxD,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IAGrE,sBAAsB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACrF,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAClF,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAClF,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAG3E,qEAAqE;IACrE,eAAe,IAAI,MAAM,CAAA;IAEzB;;;;;;;;OAQG;IACH,sBAAsB,IAAI;QACxB,UAAU,EAAE,MAAM,EAAE,CAAA;QACpB,WAAW,EAAE,MAAM,EAAE,CAAA;KACtB,CAAA;IAED,kGAAkG;IAClG,2BAA2B,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAAA;IAG7F,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,kBAAkB,CAAA;CAC1H"}
|
|
@@ -23,13 +23,14 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { Polar } from '@polar-sh/sdk';
|
|
25
25
|
import type { BillingGateway } from './interface';
|
|
26
|
-
import type { CheckoutSessionResult, PortalSessionResult, SubscriptionResult, CustomerResult, WebhookEventResult, CreateCheckoutParams, CreatePortalParams, CreateCustomerParams, UpdateSubscriptionParams } from './types';
|
|
26
|
+
import type { CheckoutSessionResult, PortalSessionResult, SubscriptionResult, CustomerResult, WebhookEventResult, CreateCheckoutParams, CreatePortalParams, CreateCustomerParams, UpdateSubscriptionParams, CreateOneTimeCheckoutParams } from './types';
|
|
27
27
|
/**
|
|
28
28
|
* Polar.sh implementation of the BillingGateway interface.
|
|
29
29
|
* Maps Polar SDK types to provider-agnostic result types.
|
|
30
30
|
*/
|
|
31
31
|
export declare class PolarGateway implements BillingGateway {
|
|
32
32
|
createCheckoutSession(params: CreateCheckoutParams): Promise<CheckoutSessionResult>;
|
|
33
|
+
createOneTimeCheckout(params: CreateOneTimeCheckoutParams): Promise<CheckoutSessionResult>;
|
|
33
34
|
createPortalSession(params: CreatePortalParams): Promise<PortalSessionResult>;
|
|
34
35
|
verifyWebhookSignature(payload: string | Buffer, signatureOrHeaders: string | Record<string, string>): WebhookEventResult;
|
|
35
36
|
getCustomer(customerId: string): Promise<CustomerResult>;
|
|
@@ -37,6 +38,12 @@ export declare class PolarGateway implements BillingGateway {
|
|
|
37
38
|
updateSubscriptionPlan(params: UpdateSubscriptionParams): Promise<SubscriptionResult>;
|
|
38
39
|
cancelSubscriptionAtPeriodEnd(subscriptionId: string): Promise<SubscriptionResult>;
|
|
39
40
|
cancelSubscriptionImmediately(subscriptionId: string): Promise<SubscriptionResult>;
|
|
41
|
+
getProviderName(): string;
|
|
42
|
+
getResourceHintDomains(): {
|
|
43
|
+
preconnect: string[];
|
|
44
|
+
dnsPrefetch: string[];
|
|
45
|
+
};
|
|
46
|
+
getSubscriptionDashboardUrl(externalSubscriptionId: string | null | undefined): string | null;
|
|
40
47
|
reactivateSubscription(subscriptionId: string): Promise<SubscriptionResult>;
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"polar.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/polar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAKrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"polar.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/polar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAKrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,SAAS,CAAA;AAiBhB;;;GAGG;AACH,qBAAa,YAAa,YAAW,cAAc;IAC3C,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA0BnF,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAoB1F,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAcnF,sBAAsB,CACpB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClD,kBAAkB;IA4Bf,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAUxD,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAsBrE,sBAAsB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAkBrF,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiBlF,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAaxF,eAAe,IAAI,MAAM;IAIzB,sBAAsB,IAAI;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IAMzE,2BAA2B,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI;IAOvF,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAelF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAExC"}
|
|
@@ -34,6 +34,21 @@ class PolarGateway {
|
|
|
34
34
|
url: result.url ?? null
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
async createOneTimeCheckout(params) {
|
|
38
|
+
const { teamId, priceId, successUrl, cancelUrl, customerEmail, customerId, metadata } = params;
|
|
39
|
+
const checkoutParams = {
|
|
40
|
+
products: [priceId],
|
|
41
|
+
successUrl,
|
|
42
|
+
metadata: { teamId, ...metadata },
|
|
43
|
+
allowTrial: false,
|
|
44
|
+
// one-time purchases should never start a trial
|
|
45
|
+
...cancelUrl && { returnUrl: cancelUrl },
|
|
46
|
+
...customerEmail && { customerEmail },
|
|
47
|
+
...customerId && { customerId }
|
|
48
|
+
};
|
|
49
|
+
const result = await getPolar().checkouts.create(checkoutParams);
|
|
50
|
+
return { id: result.id, url: result.url ?? null };
|
|
51
|
+
}
|
|
37
52
|
async createPortalSession(params) {
|
|
38
53
|
const { customerId, returnUrl } = params;
|
|
39
54
|
const result = await getPolar().customerSessions.create({
|
|
@@ -127,6 +142,16 @@ class PolarGateway {
|
|
|
127
142
|
cancelAtPeriodEnd: false
|
|
128
143
|
};
|
|
129
144
|
}
|
|
145
|
+
getProviderName() {
|
|
146
|
+
return "Polar";
|
|
147
|
+
}
|
|
148
|
+
getResourceHintDomains() {
|
|
149
|
+
return { preconnect: [], dnsPrefetch: [] };
|
|
150
|
+
}
|
|
151
|
+
getSubscriptionDashboardUrl(externalSubscriptionId) {
|
|
152
|
+
if (!externalSubscriptionId) return null;
|
|
153
|
+
return "https://polar.sh/dashboard/sales/subscriptions";
|
|
154
|
+
}
|
|
130
155
|
async reactivateSubscription(subscriptionId) {
|
|
131
156
|
const result = await getPolar().subscriptions.update({
|
|
132
157
|
id: subscriptionId,
|
|
@@ -6,16 +6,15 @@
|
|
|
6
6
|
*
|
|
7
7
|
* P2: Stripe Integration
|
|
8
8
|
*/
|
|
9
|
-
import Stripe from 'stripe';
|
|
10
9
|
import type { BillingGateway } from './interface';
|
|
11
|
-
import type { CheckoutSessionResult, PortalSessionResult, SubscriptionResult, CustomerResult, WebhookEventResult, CreateCheckoutParams, CreatePortalParams, CreateCustomerParams, UpdateSubscriptionParams } from './types';
|
|
12
|
-
export type { CreateCheckoutParams, CreatePortalParams, UpdateSubscriptionParams } from './types';
|
|
10
|
+
import type { CheckoutSessionResult, PortalSessionResult, SubscriptionResult, CustomerResult, WebhookEventResult, CreateCheckoutParams, CreatePortalParams, CreateCustomerParams, UpdateSubscriptionParams, CreateOneTimeCheckoutParams } from './types';
|
|
13
11
|
/**
|
|
14
12
|
* Stripe implementation of the BillingGateway interface.
|
|
15
13
|
* Maps Stripe SDK types to provider-agnostic result types.
|
|
16
14
|
*/
|
|
17
15
|
export declare class StripeGateway implements BillingGateway {
|
|
18
16
|
createCheckoutSession(params: CreateCheckoutParams): Promise<CheckoutSessionResult>;
|
|
17
|
+
createOneTimeCheckout(params: CreateOneTimeCheckoutParams): Promise<CheckoutSessionResult>;
|
|
19
18
|
createPortalSession(params: CreatePortalParams): Promise<PortalSessionResult>;
|
|
20
19
|
verifyWebhookSignature(payload: string | Buffer, signatureOrHeaders: string | Record<string, string>): WebhookEventResult;
|
|
21
20
|
getCustomer(customerId: string): Promise<CustomerResult>;
|
|
@@ -23,29 +22,12 @@ export declare class StripeGateway implements BillingGateway {
|
|
|
23
22
|
updateSubscriptionPlan(params: UpdateSubscriptionParams): Promise<SubscriptionResult>;
|
|
24
23
|
cancelSubscriptionAtPeriodEnd(subscriptionId: string): Promise<SubscriptionResult>;
|
|
25
24
|
cancelSubscriptionImmediately(subscriptionId: string): Promise<SubscriptionResult>;
|
|
25
|
+
getProviderName(): string;
|
|
26
|
+
getResourceHintDomains(): {
|
|
27
|
+
preconnect: string[];
|
|
28
|
+
dnsPrefetch: string[];
|
|
29
|
+
};
|
|
30
|
+
getSubscriptionDashboardUrl(externalSubscriptionId: string | null | undefined): string | null;
|
|
26
31
|
reactivateSubscription(subscriptionId: string): Promise<SubscriptionResult>;
|
|
27
32
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Get raw Stripe instance for advanced usage (webhook handlers that need Stripe.Event types).
|
|
30
|
-
* Prefer using getBillingGateway() for all other operations.
|
|
31
|
-
*/
|
|
32
|
-
export declare function getStripeInstance(): Stripe;
|
|
33
|
-
/** @deprecated Use getBillingGateway().createCheckoutSession() instead */
|
|
34
|
-
export declare function createCheckoutSession(params: CreateCheckoutParams): Promise<CheckoutSessionResult>;
|
|
35
|
-
/** @deprecated Use getBillingGateway().createPortalSession() instead */
|
|
36
|
-
export declare function createPortalSession(params: CreatePortalParams): Promise<PortalSessionResult>;
|
|
37
|
-
/** @deprecated Use getBillingGateway().verifyWebhookSignature() instead */
|
|
38
|
-
export declare function verifyWebhookSignature(payload: string | Buffer, signatureOrHeaders: string | Record<string, string>): WebhookEventResult;
|
|
39
|
-
/** @deprecated Use getBillingGateway().getCustomer() instead */
|
|
40
|
-
export declare function getCustomer(customerId: string): Promise<CustomerResult>;
|
|
41
|
-
/** @deprecated Use getBillingGateway().createCustomer() instead */
|
|
42
|
-
export declare function createCustomer(params: CreateCustomerParams): Promise<CustomerResult>;
|
|
43
|
-
/** @deprecated Use getBillingGateway().cancelSubscriptionAtPeriodEnd() instead */
|
|
44
|
-
export declare function cancelSubscriptionAtPeriodEnd(subscriptionId: string): Promise<SubscriptionResult>;
|
|
45
|
-
/** @deprecated Use getBillingGateway().cancelSubscriptionImmediately() instead */
|
|
46
|
-
export declare function cancelSubscriptionImmediately(subscriptionId: string): Promise<SubscriptionResult>;
|
|
47
|
-
/** @deprecated Use getBillingGateway().reactivateSubscription() instead */
|
|
48
|
-
export declare function reactivateSubscription(subscriptionId: string): Promise<SubscriptionResult>;
|
|
49
|
-
/** @deprecated Use getBillingGateway().updateSubscriptionPlan() instead */
|
|
50
|
-
export declare function updateSubscriptionPlan(params: UpdateSubscriptionParams): Promise<SubscriptionResult>;
|
|
51
33
|
//# sourceMappingURL=stripe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/stripe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/stripe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,SAAS,CAAA;AAkBhB;;;GAGG;AACH,qBAAa,aAAc,YAAW,cAAc;IAC5C,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA2CnF,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAuB1F,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAQnF,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,kBAAkB;IAiBnH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAYxD,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IASrE,sBAAsB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA2BrF,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAWlF,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IASxF,eAAe,IAAI,MAAM;IAIzB,sBAAsB,IAAI;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IASzE,2BAA2B,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI;IAOvF,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAUlF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Stripe from "stripe";
|
|
2
2
|
import { BILLING_REGISTRY } from "@nextsparkjs/registries/billing-registry";
|
|
3
|
+
import { PlanService } from "../../services/plan.service.js";
|
|
3
4
|
let stripeInstance = null;
|
|
4
5
|
function getStripe() {
|
|
5
6
|
if (!stripeInstance) {
|
|
@@ -20,9 +21,9 @@ class StripeGateway {
|
|
|
20
21
|
if (!planConfig) {
|
|
21
22
|
throw new Error(`Plan ${planSlug} not found in BILLING_REGISTRY`);
|
|
22
23
|
}
|
|
23
|
-
const priceId =
|
|
24
|
+
const priceId = PlanService.getPriceId(planSlug, billingPeriod);
|
|
24
25
|
if (!priceId) {
|
|
25
|
-
throw new Error(`No
|
|
26
|
+
throw new Error(`No price ID configured for ${planSlug} ${billingPeriod}`);
|
|
26
27
|
}
|
|
27
28
|
const sessionParams = {
|
|
28
29
|
mode: "subscription",
|
|
@@ -46,6 +47,25 @@ class StripeGateway {
|
|
|
46
47
|
const session = await getStripe().checkout.sessions.create(sessionParams);
|
|
47
48
|
return { id: session.id, url: session.url };
|
|
48
49
|
}
|
|
50
|
+
async createOneTimeCheckout(params) {
|
|
51
|
+
const { teamId, priceId, quantity = 1, successUrl, cancelUrl, customerEmail, customerId, metadata } = params;
|
|
52
|
+
const sessionParams = {
|
|
53
|
+
mode: "payment",
|
|
54
|
+
payment_method_types: ["card"],
|
|
55
|
+
line_items: [{ price: priceId, quantity }],
|
|
56
|
+
success_url: successUrl,
|
|
57
|
+
cancel_url: cancelUrl,
|
|
58
|
+
metadata: { teamId, ...metadata },
|
|
59
|
+
client_reference_id: teamId
|
|
60
|
+
};
|
|
61
|
+
if (customerId) {
|
|
62
|
+
sessionParams.customer = customerId;
|
|
63
|
+
} else if (customerEmail) {
|
|
64
|
+
sessionParams.customer_email = customerEmail;
|
|
65
|
+
}
|
|
66
|
+
const session = await getStripe().checkout.sessions.create(sessionParams);
|
|
67
|
+
return { id: session.id, url: session.url };
|
|
68
|
+
}
|
|
49
69
|
async createPortalSession(params) {
|
|
50
70
|
const session = await getStripe().billingPortal.sessions.create({
|
|
51
71
|
customer: params.customerId,
|
|
@@ -125,6 +145,24 @@ class StripeGateway {
|
|
|
125
145
|
cancelAtPeriodEnd: canceled.cancel_at_period_end
|
|
126
146
|
};
|
|
127
147
|
}
|
|
148
|
+
getProviderName() {
|
|
149
|
+
return "Stripe";
|
|
150
|
+
}
|
|
151
|
+
getResourceHintDomains() {
|
|
152
|
+
return {
|
|
153
|
+
// js.stripe.com: Stripe.js SDK loaded on page render
|
|
154
|
+
preconnect: ["https://js.stripe.com"],
|
|
155
|
+
// api.stripe.com: called by Stripe.js after user fills payment form (too late for preconnect)
|
|
156
|
+
dnsPrefetch: ["https://api.stripe.com"]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
getSubscriptionDashboardUrl(externalSubscriptionId) {
|
|
160
|
+
var _a;
|
|
161
|
+
if (!externalSubscriptionId) return null;
|
|
162
|
+
const isLive = (_a = process.env.STRIPE_SECRET_KEY) == null ? void 0 : _a.startsWith("sk_live");
|
|
163
|
+
const prefix = isLive ? "" : "test/";
|
|
164
|
+
return `https://dashboard.stripe.com/${prefix}subscriptions/${externalSubscriptionId}`;
|
|
165
|
+
}
|
|
128
166
|
async reactivateSubscription(subscriptionId) {
|
|
129
167
|
const updated = await getStripe().subscriptions.update(subscriptionId, {
|
|
130
168
|
cancel_at_period_end: false
|
|
@@ -136,47 +174,6 @@ class StripeGateway {
|
|
|
136
174
|
};
|
|
137
175
|
}
|
|
138
176
|
}
|
|
139
|
-
function getStripeInstance() {
|
|
140
|
-
return getStripe();
|
|
141
|
-
}
|
|
142
|
-
const _defaultGateway = new StripeGateway();
|
|
143
|
-
async function createCheckoutSession(params) {
|
|
144
|
-
return _defaultGateway.createCheckoutSession(params);
|
|
145
|
-
}
|
|
146
|
-
async function createPortalSession(params) {
|
|
147
|
-
return _defaultGateway.createPortalSession(params);
|
|
148
|
-
}
|
|
149
|
-
function verifyWebhookSignature(payload, signatureOrHeaders) {
|
|
150
|
-
return _defaultGateway.verifyWebhookSignature(payload, signatureOrHeaders);
|
|
151
|
-
}
|
|
152
|
-
async function getCustomer(customerId) {
|
|
153
|
-
return _defaultGateway.getCustomer(customerId);
|
|
154
|
-
}
|
|
155
|
-
async function createCustomer(params) {
|
|
156
|
-
return _defaultGateway.createCustomer(params);
|
|
157
|
-
}
|
|
158
|
-
async function cancelSubscriptionAtPeriodEnd(subscriptionId) {
|
|
159
|
-
return _defaultGateway.cancelSubscriptionAtPeriodEnd(subscriptionId);
|
|
160
|
-
}
|
|
161
|
-
async function cancelSubscriptionImmediately(subscriptionId) {
|
|
162
|
-
return _defaultGateway.cancelSubscriptionImmediately(subscriptionId);
|
|
163
|
-
}
|
|
164
|
-
async function reactivateSubscription(subscriptionId) {
|
|
165
|
-
return _defaultGateway.reactivateSubscription(subscriptionId);
|
|
166
|
-
}
|
|
167
|
-
async function updateSubscriptionPlan(params) {
|
|
168
|
-
return _defaultGateway.updateSubscriptionPlan(params);
|
|
169
|
-
}
|
|
170
177
|
export {
|
|
171
|
-
StripeGateway
|
|
172
|
-
cancelSubscriptionAtPeriodEnd,
|
|
173
|
-
cancelSubscriptionImmediately,
|
|
174
|
-
createCheckoutSession,
|
|
175
|
-
createCustomer,
|
|
176
|
-
createPortalSession,
|
|
177
|
-
getCustomer,
|
|
178
|
-
getStripeInstance,
|
|
179
|
-
reactivateSubscription,
|
|
180
|
-
updateSubscriptionPlan,
|
|
181
|
-
verifyWebhookSignature
|
|
178
|
+
StripeGateway
|
|
182
179
|
};
|
|
@@ -47,6 +47,17 @@ export interface CreateCustomerParams {
|
|
|
47
47
|
export interface UpdateSubscriptionParams {
|
|
48
48
|
subscriptionId: string;
|
|
49
49
|
newPriceId: string;
|
|
50
|
+
/** Proration behavior when changing plans. Default: 'create_prorations' */
|
|
50
51
|
prorationBehavior?: 'create_prorations' | 'none' | 'always_invoice';
|
|
51
52
|
}
|
|
53
|
+
export interface CreateOneTimeCheckoutParams {
|
|
54
|
+
teamId: string;
|
|
55
|
+
priceId: string;
|
|
56
|
+
quantity?: number;
|
|
57
|
+
successUrl: string;
|
|
58
|
+
cancelUrl: string;
|
|
59
|
+
customerEmail?: string;
|
|
60
|
+
customerId?: string;
|
|
61
|
+
metadata?: Record<string, string>;
|
|
62
|
+
}
|
|
52
63
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAA;CACZ;AAMD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAMD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAMD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAMD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,SAAS,GAAG,QAAQ,CAAA;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,gBAAgB,CAAA;CACpE"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/billing/gateways/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAA;CACZ;AAMD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAMD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAMD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAMD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,SAAS,GAAG,QAAQ,CAAA;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,gBAAgB,CAAA;CACpE;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC"}
|
|
@@ -14,7 +14,7 @@ export interface JobResult {
|
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Expire trials that have passed their trial end date
|
|
17
|
-
* Trial -> Expired (if no payment method) or Active (if payment processed by
|
|
17
|
+
* Trial -> Expired (if no payment method) or Active (if payment processed by provider)
|
|
18
18
|
*/
|
|
19
19
|
export declare function expireTrials(): Promise<JobResult>;
|
|
20
20
|
/**
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polar.sh Webhook Types
|
|
3
|
+
*
|
|
4
|
+
* Exports extension interfaces for the Polar webhook handler.
|
|
5
|
+
* Projects override lib/billing/polar-webhook-extensions.ts to handle
|
|
6
|
+
* one-time payment events (credit packs, LTD purchases, upsells, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Usage in lib/billing/polar-webhook-extensions.ts:
|
|
9
|
+
* import type { PolarWebhookExtensions } from '@nextsparkjs/core/lib/billing/polar-webhook'
|
|
10
|
+
*
|
|
11
|
+
* export const polarWebhookExtensions: PolarWebhookExtensions = {
|
|
12
|
+
* onOneTimePaymentCompleted: async (order, context) => {
|
|
13
|
+
* if (order.metadata?.type === 'credit_pack') {
|
|
14
|
+
* await handleCreditPackPurchase(order, context)
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
import type { OneTimePaymentContext } from './types';
|
|
20
|
+
export type { OneTimePaymentContext };
|
|
21
|
+
export interface PolarOrderData {
|
|
22
|
+
id: string;
|
|
23
|
+
amount: number;
|
|
24
|
+
currency: string;
|
|
25
|
+
metadata: Record<string, string>;
|
|
26
|
+
customerId?: string;
|
|
27
|
+
externalCustomerId?: string;
|
|
28
|
+
productId?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface PolarWebhookExtensions {
|
|
31
|
+
/**
|
|
32
|
+
* Called when a Polar order.paid event fires for an order with no subscriptionId
|
|
33
|
+
* (i.e. a one-time purchase, not a recurring subscription payment).
|
|
34
|
+
* Use this for credit packs, one-time purchases, etc.
|
|
35
|
+
*/
|
|
36
|
+
onOneTimePaymentCompleted?: (order: PolarOrderData, context: OneTimePaymentContext) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=polar-webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polar-webhook.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/polar-webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEpD,YAAY,EAAE,qBAAqB,EAAE,CAAA;AAErC,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,CAC1B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB"}
|
|
File without changes
|
|
@@ -25,8 +25,7 @@ export declare const subscriptionStatusSchema: z.ZodEnum<{
|
|
|
25
25
|
}>;
|
|
26
26
|
export declare const paymentProviderSchema: z.ZodEnum<{
|
|
27
27
|
stripe: "stripe";
|
|
28
|
-
|
|
29
|
-
lemonsqueezy: "lemonsqueezy";
|
|
28
|
+
polar: "polar";
|
|
30
29
|
}>;
|
|
31
30
|
export declare const billingEventTypeSchema: z.ZodEnum<{
|
|
32
31
|
payment: "payment";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,eAAO,MAAM,cAAc;;;;EAAyC,CAAA;AAEpE,eAAO,MAAM,oBAAoB;;;;EAA8C,CAAA;AAE/E,eAAO,MAAM,wBAAwB;;;;;;;EAOnC,CAAA;AAEF,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/billing/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,eAAO,MAAM,cAAc;;;;EAAyC,CAAA;AAEpE,eAAO,MAAM,oBAAoB;;;;EAA8C,CAAA;AAE/E,eAAO,MAAM,wBAAwB;;;;;;;EAOnC,CAAA;AAEF,eAAO,MAAM,qBAAqB;;;EAA8B,CAAA;AAEhE,eAAO,MAAM,sBAAsB;;;;;EAAqD,CAAA;AAExF,eAAO,MAAM,wBAAwB;;;;EAA6C,CAAA;AAMlF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;iBAc3B,CAAA;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;iBAA6B,CAAA;AAM1D,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;iBAQnC,CAAA;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;iBAInC,CAAA;AAMF,eAAO,MAAM,gBAAgB;;;;;;;iBAO3B,CAAA;AAMF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;iBAUnC,CAAA;AAMF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC9D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC9D,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAC9E,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAC9E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC9D,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAA"}
|
|
@@ -9,7 +9,7 @@ const subscriptionStatusSchema = z.enum([
|
|
|
9
9
|
"paused",
|
|
10
10
|
"expired"
|
|
11
11
|
]);
|
|
12
|
-
const paymentProviderSchema = z.enum(["stripe", "
|
|
12
|
+
const paymentProviderSchema = z.enum(["stripe", "polar"]);
|
|
13
13
|
const billingEventTypeSchema = z.enum(["payment", "refund", "invoice", "credit"]);
|
|
14
14
|
const billingEventStatusSchema = z.enum(["pending", "succeeded", "failed"]);
|
|
15
15
|
const createPlanSchema = z.object({
|