@delightstack/stripe 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/client/billing.client.svelte.d.ts +154 -0
- package/dist/client/billing.client.svelte.d.ts.map +1 -0
- package/dist/client/billing.client.svelte.js +279 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/server/billing.config.d.ts +189 -0
- package/dist/server/billing.config.d.ts.map +1 -0
- package/dist/server/billing.config.js +37 -0
- package/dist/server/billing.handler.d.ts +46 -0
- package/dist/server/billing.handler.d.ts.map +1 -0
- package/dist/server/billing.handler.js +73 -0
- package/dist/server/billing.meter.d.ts +41 -0
- package/dist/server/billing.meter.d.ts.map +1 -0
- package/dist/server/billing.meter.js +55 -0
- package/dist/server/billing.products.d.ts +24 -0
- package/dist/server/billing.products.d.ts.map +1 -0
- package/dist/server/billing.products.js +124 -0
- package/dist/server/billing.routes.d.ts +8 -0
- package/dist/server/billing.routes.d.ts.map +1 -0
- package/dist/server/billing.routes.js +441 -0
- package/dist/server/billing.stripe.d.ts +34 -0
- package/dist/server/billing.stripe.d.ts.map +1 -0
- package/dist/server/billing.stripe.js +135 -0
- package/dist/server/billing.sync.d.ts +29 -0
- package/dist/server/billing.sync.d.ts.map +1 -0
- package/dist/server/billing.sync.js +122 -0
- package/dist/server/billing.webhook.d.ts +10 -0
- package/dist/server/billing.webhook.d.ts.map +1 -0
- package/dist/server/billing.webhook.js +222 -0
- package/dist/server/billing.webhook.register.d.ts +12 -0
- package/dist/server/billing.webhook.register.d.ts.map +1 -0
- package/dist/server/billing.webhook.register.js +57 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +8 -0
- package/dist/sveltekit/guards.d.ts +29 -0
- package/dist/sveltekit/guards.d.ts.map +1 -0
- package/dist/sveltekit/guards.js +57 -0
- package/dist/sveltekit/index.d.ts +2 -0
- package/dist/sveltekit/index.d.ts.map +1 -0
- package/dist/sveltekit/index.js +1 -0
- package/dist/types/billing.type.d.ts +61 -0
- package/dist/types/billing.type.d.ts.map +1 -0
- package/dist/types/billing.type.js +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/webhook.type.d.ts +22 -0
- package/dist/types/webhook.type.d.ts.map +1 -0
- package/dist/types/webhook.type.js +2 -0
- package/package.json +91 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import type { RequestEvent } from '@sveltejs/kit';
|
|
2
|
+
/**
|
|
3
|
+
* A plan definition that maps to a Stripe Product + Price.
|
|
4
|
+
* Defined in code, synced to Stripe.
|
|
5
|
+
*/
|
|
6
|
+
export interface PlanDefinition {
|
|
7
|
+
/** Unique plan identifier (used in code, stored as Stripe product metadata) */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Human-readable name (synced to Stripe product name) */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Plan description (synced to Stripe product description) */
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Stripe lookup_key for the price. Allows price migration without code changes. */
|
|
14
|
+
lookup_key: string;
|
|
15
|
+
/** Price amount in smallest currency unit (e.g. 999 = $9.99) */
|
|
16
|
+
amount: number;
|
|
17
|
+
/** Currency code (lowercase) @default 'usd' */
|
|
18
|
+
currency?: string;
|
|
19
|
+
/** Billing interval */
|
|
20
|
+
interval: 'month' | 'year' | 'week' | 'day';
|
|
21
|
+
/** Number of intervals between billings @default 1 */
|
|
22
|
+
interval_count?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Entitlement names this plan grants.
|
|
25
|
+
* Maps to the auth package's entitlements array.
|
|
26
|
+
* @example ['premium', 'video-uploads']
|
|
27
|
+
*/
|
|
28
|
+
entitlements?: string[];
|
|
29
|
+
/** Trial period in days @default undefined (no trial) */
|
|
30
|
+
trial_days?: number;
|
|
31
|
+
/** Whether this plan is archived (hidden from new subscriptions) */
|
|
32
|
+
archived?: boolean;
|
|
33
|
+
/** Additional Stripe product metadata */
|
|
34
|
+
metadata?: Record<string, string>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A usage meter definition for billing based on consumption.
|
|
38
|
+
* Maps to Stripe Billing Meters.
|
|
39
|
+
*/
|
|
40
|
+
export interface MeterDefinition {
|
|
41
|
+
/** Unique meter identifier */
|
|
42
|
+
id: string;
|
|
43
|
+
/** Human-readable display name */
|
|
44
|
+
display_name: string;
|
|
45
|
+
/** Event name used in meter event API */
|
|
46
|
+
event_name: string;
|
|
47
|
+
/** Aggregation formula */
|
|
48
|
+
aggregation: 'sum' | 'count' | 'max' | 'last';
|
|
49
|
+
/** Value key in the event payload @default 'value' */
|
|
50
|
+
value_key?: string;
|
|
51
|
+
}
|
|
52
|
+
/** Minimal RPC interface for the auth server (avoids hard dependency) */
|
|
53
|
+
export interface AuthServerRpc {
|
|
54
|
+
updateOrg(id: string, data: {
|
|
55
|
+
plan?: number;
|
|
56
|
+
json?: string;
|
|
57
|
+
}): unknown;
|
|
58
|
+
/**
|
|
59
|
+
* Optional read of the org record. When provided, the billing package
|
|
60
|
+
* read-modify-writes the org's `json` metadata instead of overwriting it.
|
|
61
|
+
*/
|
|
62
|
+
getOrg?(id: string): {
|
|
63
|
+
json?: string | null;
|
|
64
|
+
} | null | undefined | Promise<{
|
|
65
|
+
json?: string | null;
|
|
66
|
+
} | null | undefined>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Store used to deduplicate Stripe webhook events by event ID.
|
|
70
|
+
* Provide a durable implementation (e.g. Durable Object storage) for
|
|
71
|
+
* multi-isolate deployments. Defaults to an in-memory store with a TTL/cap.
|
|
72
|
+
*/
|
|
73
|
+
export interface WebhookEventStore {
|
|
74
|
+
/** Returns true if the given Stripe event ID was already processed */
|
|
75
|
+
has(event_id: string): boolean | Promise<boolean>;
|
|
76
|
+
/** Marks the given Stripe event ID as processed */
|
|
77
|
+
add(event_id: string): void | Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
/** Minimal RPC interface for the websocket server (avoids hard dependency) */
|
|
80
|
+
export interface WebsocketRpc {
|
|
81
|
+
broadcast(message: Record<string, unknown>): void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Configuration for the billing/stripe integration.
|
|
85
|
+
* Pass to `defineBillingConfig()` to fill in defaults.
|
|
86
|
+
*/
|
|
87
|
+
export interface BillingConfig<E extends string = string> {
|
|
88
|
+
/** Stripe secret key (sk_live_... or sk_test_...) */
|
|
89
|
+
secret_key: string;
|
|
90
|
+
/** Stripe publishable key (pk_live_... or pk_test_...) */
|
|
91
|
+
publishable_key: string;
|
|
92
|
+
/**
|
|
93
|
+
* Stripe webhook signing secret. If omitted, webhooks are
|
|
94
|
+
* auto-registered and the secret is derived from the registration.
|
|
95
|
+
* Provide this to use a manually configured webhook.
|
|
96
|
+
*/
|
|
97
|
+
webhook_secret?: string;
|
|
98
|
+
/** Whether the app is in dev mode @default false */
|
|
99
|
+
dev?: boolean;
|
|
100
|
+
/** Base path for billing API routes @default '/api/billing' */
|
|
101
|
+
base_path?: string;
|
|
102
|
+
/** Plan definitions — products and prices defined in code */
|
|
103
|
+
plans?: PlanDefinition[];
|
|
104
|
+
/** Usage meter definitions */
|
|
105
|
+
meters?: MeterDefinition[];
|
|
106
|
+
/**
|
|
107
|
+
* Entitlement names that correspond to the auth package's entitlements array.
|
|
108
|
+
* Array index = bit position. Must match the auth config's entitlements array.
|
|
109
|
+
* Used to map plan entitlements to the auth system's bitwise encoding.
|
|
110
|
+
* @example ['premium', 'video-uploads', 'extra-usage']
|
|
111
|
+
*/
|
|
112
|
+
entitlements?: readonly E[];
|
|
113
|
+
/**
|
|
114
|
+
* Whether billing is scoped to orgs or users.
|
|
115
|
+
* - 'org': Stripe customer = org. Subscription managed by org owner.
|
|
116
|
+
* - 'user': Stripe customer = user. Each user manages their own subscription.
|
|
117
|
+
* @default 'org'
|
|
118
|
+
*/
|
|
119
|
+
billing_scope?: 'org' | 'user';
|
|
120
|
+
/**
|
|
121
|
+
* The public URL of the app (used for webhook registration and Billing Portal return URL).
|
|
122
|
+
* If omitted, derived from the first request's origin.
|
|
123
|
+
*/
|
|
124
|
+
app_url?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Additional origins that a client-provided `return_url` may point to
|
|
127
|
+
* (for Billing Portal and Checkout). The app's own origin is always allowed.
|
|
128
|
+
* Any other origin is rejected to prevent open-redirect/phishing.
|
|
129
|
+
* @example ['https://app.example.com']
|
|
130
|
+
*/
|
|
131
|
+
allowed_return_origins?: string[];
|
|
132
|
+
/**
|
|
133
|
+
* Store used to deduplicate Stripe webhook events (idempotency).
|
|
134
|
+
* Defaults to an in-memory store (per-isolate, 24h TTL, capped size).
|
|
135
|
+
* Provide a durable implementation for multi-isolate deployments.
|
|
136
|
+
*/
|
|
137
|
+
webhook_event_store?: WebhookEventStore;
|
|
138
|
+
/**
|
|
139
|
+
* Billing Portal configuration.
|
|
140
|
+
* @default { enabled: true }
|
|
141
|
+
*/
|
|
142
|
+
portal?: {
|
|
143
|
+
/** Enable the Stripe Billing Portal @default true */
|
|
144
|
+
enabled?: boolean;
|
|
145
|
+
};
|
|
146
|
+
/** Lifecycle hooks for billing events */
|
|
147
|
+
hooks?: {
|
|
148
|
+
/** Called after a subscription is created, updated, canceled, or deleted */
|
|
149
|
+
onSubscriptionChange?: (ctx: {
|
|
150
|
+
customer_id: string;
|
|
151
|
+
subscription_id: string;
|
|
152
|
+
status: string;
|
|
153
|
+
plan_id: string | null;
|
|
154
|
+
entitlements: string[];
|
|
155
|
+
event: RequestEvent;
|
|
156
|
+
}) => void | Promise<void>;
|
|
157
|
+
/** Called after a payment succeeds. `amount` is an integer in the smallest currency unit (cents). */
|
|
158
|
+
onPaymentSuccess?: (ctx: {
|
|
159
|
+
customer_id: string;
|
|
160
|
+
/** Integer amount in the smallest currency unit (e.g. cents) */
|
|
161
|
+
amount: number;
|
|
162
|
+
currency: string;
|
|
163
|
+
invoice_id: string;
|
|
164
|
+
}) => void | Promise<void>;
|
|
165
|
+
/** Called after a payment fails. `amount` is an integer in the smallest currency unit (cents). */
|
|
166
|
+
onPaymentFailed?: (ctx: {
|
|
167
|
+
customer_id: string;
|
|
168
|
+
/** Integer amount in the smallest currency unit (e.g. cents) */
|
|
169
|
+
amount: number;
|
|
170
|
+
currency: string;
|
|
171
|
+
invoice_id: string;
|
|
172
|
+
}) => void | Promise<void>;
|
|
173
|
+
/** Called when a customer is created in Stripe */
|
|
174
|
+
onCustomerCreated?: (ctx: {
|
|
175
|
+
customer_id: string;
|
|
176
|
+
org_id?: string;
|
|
177
|
+
user_id?: string;
|
|
178
|
+
}) => void | Promise<void>;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/** Resolved billing config with all defaults filled in */
|
|
182
|
+
export interface ResolvedBillingConfig<E extends string = string> extends BillingConfig<E> {
|
|
183
|
+
base_path: string;
|
|
184
|
+
billing_scope: 'org' | 'user';
|
|
185
|
+
portal: Required<NonNullable<BillingConfig['portal']>>;
|
|
186
|
+
}
|
|
187
|
+
/** Creates a billing config with sensible defaults */
|
|
188
|
+
export declare function defineBillingConfig<const E extends string>(config: BillingConfig<E>): ResolvedBillingConfig<E>;
|
|
189
|
+
//# sourceMappingURL=billing.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.config.d.ts","sourceRoot":"","sources":["../../src/server/billing.config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Creates a billing config with sensible defaults */
|
|
2
|
+
export function defineBillingConfig(config) {
|
|
3
|
+
if (!config.secret_key?.startsWith('sk_')) {
|
|
4
|
+
throw new Error('Billing config: secret_key must be a valid Stripe secret key (sk_...)');
|
|
5
|
+
}
|
|
6
|
+
if (!config.publishable_key?.startsWith('pk_')) {
|
|
7
|
+
throw new Error('Billing config: publishable_key must be a valid Stripe publishable key (pk_...)');
|
|
8
|
+
}
|
|
9
|
+
// Validate plan definitions
|
|
10
|
+
if (config.plans) {
|
|
11
|
+
const ids = new Set();
|
|
12
|
+
const keys = new Set();
|
|
13
|
+
for (const plan of config.plans) {
|
|
14
|
+
if (ids.has(plan.id)) {
|
|
15
|
+
throw new Error(`Billing config: duplicate plan id '${plan.id}'`);
|
|
16
|
+
}
|
|
17
|
+
if (keys.has(plan.lookup_key)) {
|
|
18
|
+
throw new Error(`Billing config: duplicate lookup_key '${plan.lookup_key}'`);
|
|
19
|
+
}
|
|
20
|
+
ids.add(plan.id);
|
|
21
|
+
keys.add(plan.lookup_key);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Validate entitlements limit
|
|
25
|
+
if (config.entitlements && config.entitlements.length > 32) {
|
|
26
|
+
throw new Error(`Billing config: entitlements array exceeds 32 entries (got ${config.entitlements.length}). ` +
|
|
27
|
+
'Bitwise encoding uses a 32-bit integer.');
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
...config,
|
|
31
|
+
base_path: config.base_path ?? '/api/billing',
|
|
32
|
+
billing_scope: config.billing_scope ?? 'org',
|
|
33
|
+
portal: {
|
|
34
|
+
enabled: config.portal?.enabled ?? true,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Handle, RequestEvent } from '@sveltejs/kit';
|
|
2
|
+
import type { BillingConfig, AuthServerRpc, WebsocketRpc } from './billing.config';
|
|
3
|
+
/** Options for `createBillingHandle()` */
|
|
4
|
+
export interface BillingHandleOptions<Config extends BillingConfig = BillingConfig> {
|
|
5
|
+
/** The billing configuration (pass result of `defineBillingConfig()` or raw config) */
|
|
6
|
+
config: Config;
|
|
7
|
+
/**
|
|
8
|
+
* Get the auth server for entitlement updates.
|
|
9
|
+
* Return undefined if not using auth integration.
|
|
10
|
+
*/
|
|
11
|
+
getAuthServer?: (event: RequestEvent) => AuthServerRpc | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Get the WebSocket server for real-time billing events.
|
|
14
|
+
* Return undefined if not using WebSocket integration.
|
|
15
|
+
*/
|
|
16
|
+
getWebsocket?: (event: RequestEvent) => WebsocketRpc | undefined;
|
|
17
|
+
/** Whether the app is building (static build step) @default false */
|
|
18
|
+
building?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Sync product/price/meter definitions to Stripe on first request.
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
sync_on_startup?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a SvelteKit Handle for billing.
|
|
27
|
+
* Composable with SvelteKit's `sequence()`.
|
|
28
|
+
*
|
|
29
|
+
* Routes handled:
|
|
30
|
+
* - POST /api/billing/webhook Stripe webhook endpoint
|
|
31
|
+
* - GET /api/billing/subscription Get current subscription
|
|
32
|
+
* - POST /api/billing/subscription Create/update subscription
|
|
33
|
+
* - DELETE /api/billing/subscription Cancel subscription
|
|
34
|
+
* - GET /api/billing/invoice List invoices
|
|
35
|
+
* - GET /api/billing/payment-method List payment methods
|
|
36
|
+
* - POST /api/billing/payment-method Add payment method (create setup session)
|
|
37
|
+
* - PATCH /api/billing/payment-method/:id Set default payment method
|
|
38
|
+
* - DELETE /api/billing/payment-method/:id Remove payment method
|
|
39
|
+
* - POST /api/billing/portal Create Billing Portal session
|
|
40
|
+
* - POST /api/billing/checkout Create Checkout session
|
|
41
|
+
* - GET /api/billing/plan List available plans
|
|
42
|
+
* - POST /api/billing/sync Force subscription sync
|
|
43
|
+
* - GET /api/billing/config Get client-safe config
|
|
44
|
+
*/
|
|
45
|
+
export declare function createBillingHandle<Config extends BillingConfig>(options: BillingHandleOptions<Config>): Handle;
|
|
46
|
+
//# sourceMappingURL=billing.handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.handler.d.ts","sourceRoot":"","sources":["../../src/server/billing.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EACX,aAAa,EAEb,aAAa,EACb,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAO1B,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB,CAAC,MAAM,SAAS,aAAa,GAAG,aAAa;IACjF,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,aAAa,GAAG,SAAS,CAAC;IAEnE;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,YAAY,GAAG,SAAS,CAAC;IAEjE,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,SAAS,aAAa,EAC/D,OAAO,EAAE,oBAAoB,CAAC,MAAM,CAAC,GACnC,MAAM,CAqDR"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { DelightError } from '@delightstack/utilities';
|
|
2
|
+
import { defineBillingConfig } from './billing.config';
|
|
3
|
+
import { handleBillingRoute } from './billing.routes';
|
|
4
|
+
import { handleWebhook } from './billing.webhook';
|
|
5
|
+
import { syncAll } from './billing.products';
|
|
6
|
+
/**
|
|
7
|
+
* Creates a SvelteKit Handle for billing.
|
|
8
|
+
* Composable with SvelteKit's `sequence()`.
|
|
9
|
+
*
|
|
10
|
+
* Routes handled:
|
|
11
|
+
* - POST /api/billing/webhook Stripe webhook endpoint
|
|
12
|
+
* - GET /api/billing/subscription Get current subscription
|
|
13
|
+
* - POST /api/billing/subscription Create/update subscription
|
|
14
|
+
* - DELETE /api/billing/subscription Cancel subscription
|
|
15
|
+
* - GET /api/billing/invoice List invoices
|
|
16
|
+
* - GET /api/billing/payment-method List payment methods
|
|
17
|
+
* - POST /api/billing/payment-method Add payment method (create setup session)
|
|
18
|
+
* - PATCH /api/billing/payment-method/:id Set default payment method
|
|
19
|
+
* - DELETE /api/billing/payment-method/:id Remove payment method
|
|
20
|
+
* - POST /api/billing/portal Create Billing Portal session
|
|
21
|
+
* - POST /api/billing/checkout Create Checkout session
|
|
22
|
+
* - GET /api/billing/plan List available plans
|
|
23
|
+
* - POST /api/billing/sync Force subscription sync
|
|
24
|
+
* - GET /api/billing/config Get client-safe config
|
|
25
|
+
*/
|
|
26
|
+
export function createBillingHandle(options) {
|
|
27
|
+
const config = defineBillingConfig(options.config);
|
|
28
|
+
let product_sync_started = false;
|
|
29
|
+
return async ({ event, resolve }) => {
|
|
30
|
+
if (options.building)
|
|
31
|
+
return resolve(event);
|
|
32
|
+
// Trigger product sync once on first request (non-blocking)
|
|
33
|
+
if (options.sync_on_startup && !product_sync_started) {
|
|
34
|
+
product_sync_started = true;
|
|
35
|
+
syncAll(config).catch((err) => {
|
|
36
|
+
console.error('[@delightstack/stripe] Product sync failed:', err);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const pathname = event.url.pathname;
|
|
40
|
+
const base_path = config.base_path;
|
|
41
|
+
if (!pathname.startsWith(base_path)) {
|
|
42
|
+
return resolve(event);
|
|
43
|
+
}
|
|
44
|
+
const route_path = pathname.slice(base_path.length) || '/';
|
|
45
|
+
const method = event.request.method;
|
|
46
|
+
// Webhook route does NOT require auth (Stripe sends it)
|
|
47
|
+
if (route_path === '/webhook' && method === 'POST') {
|
|
48
|
+
try {
|
|
49
|
+
return await handleWebhook(event, config, {
|
|
50
|
+
getAuthServer: options.getAuthServer,
|
|
51
|
+
getWebsocket: options.getWebsocket,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return DelightError.from(error).toResponse();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// All other routes require authentication
|
|
59
|
+
const locals = event.locals;
|
|
60
|
+
if (!locals.session) {
|
|
61
|
+
return DelightError.unauthorized('Authentication required').toResponse();
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return await handleBillingRoute(event, config, route_path, method, {
|
|
65
|
+
getAuthServer: options.getAuthServer,
|
|
66
|
+
getWebsocket: options.getWebsocket,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return DelightError.from(error).toResponse();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ResolvedBillingConfig } from './billing.config';
|
|
2
|
+
/**
|
|
3
|
+
* Reports a usage event to a Stripe Billing Meter.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* await reportMeterEvent(config, {
|
|
8
|
+
* meter_id: 'ai-tokens',
|
|
9
|
+
* customer_id: 'cus_xxx',
|
|
10
|
+
* value: result.usage.total_tokens,
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function reportMeterEvent(config: ResolvedBillingConfig, options: {
|
|
15
|
+
/** The meter ID (matches MeterDefinition.id from config) */
|
|
16
|
+
meter_id: string;
|
|
17
|
+
/** The Stripe customer ID to attribute the usage to */
|
|
18
|
+
customer_id: string;
|
|
19
|
+
/** The usage value to report */
|
|
20
|
+
value: number;
|
|
21
|
+
/** Unix timestamp in seconds @default now */
|
|
22
|
+
timestamp?: number;
|
|
23
|
+
/** Idempotency key to prevent duplicate events */
|
|
24
|
+
idempotency_key?: string;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a helper function bound to a specific meter and config.
|
|
28
|
+
* Designed for integration with the AI package.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // In your Durable Object:
|
|
33
|
+
* const reportTokenUsage = createMeterReporter(billingConfig, 'ai-tokens');
|
|
34
|
+
*
|
|
35
|
+
* // After each AI completion:
|
|
36
|
+
* const result = await ai.complete(options);
|
|
37
|
+
* await reportTokenUsage(customer_id, result.usage.total_tokens);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function createMeterReporter(config: ResolvedBillingConfig, meter_id: string): (customer_id: string, value: number, idempotency_key?: string) => Promise<void>;
|
|
41
|
+
//# sourceMappingURL=billing.meter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.meter.d.ts","sourceRoot":"","sources":["../../src/server/billing.meter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAI9D;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE;IACR,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB,GACC,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,IAEjF,aAAa,MAAM,EACnB,OAAO,MAAM,EACb,kBAAkB,MAAM,KACtB,OAAO,CAAC,IAAI,CAAC,CAShB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getStripe, stripeCall } from './billing.stripe';
|
|
2
|
+
import { DelightError } from '@delightstack/utilities';
|
|
3
|
+
/**
|
|
4
|
+
* Reports a usage event to a Stripe Billing Meter.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* await reportMeterEvent(config, {
|
|
9
|
+
* meter_id: 'ai-tokens',
|
|
10
|
+
* customer_id: 'cus_xxx',
|
|
11
|
+
* value: result.usage.total_tokens,
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export async function reportMeterEvent(config, options) {
|
|
16
|
+
const meter_def = config.meters?.find((m) => m.id === options.meter_id);
|
|
17
|
+
if (!meter_def) {
|
|
18
|
+
throw DelightError.badRequest(`Unknown meter: ${options.meter_id}`);
|
|
19
|
+
}
|
|
20
|
+
const stripe = getStripe(config);
|
|
21
|
+
await stripeCall(() => stripe.billing.meterEvents.create({
|
|
22
|
+
event_name: meter_def.event_name,
|
|
23
|
+
payload: {
|
|
24
|
+
stripe_customer_id: options.customer_id,
|
|
25
|
+
[meter_def.value_key ?? 'value']: String(options.value),
|
|
26
|
+
},
|
|
27
|
+
timestamp: options.timestamp ?? Math.floor(Date.now() / 1000),
|
|
28
|
+
}, options.idempotency_key ? { idempotencyKey: options.idempotency_key } : undefined));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a helper function bound to a specific meter and config.
|
|
32
|
+
* Designed for integration with the AI package.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* // In your Durable Object:
|
|
37
|
+
* const reportTokenUsage = createMeterReporter(billingConfig, 'ai-tokens');
|
|
38
|
+
*
|
|
39
|
+
* // After each AI completion:
|
|
40
|
+
* const result = await ai.complete(options);
|
|
41
|
+
* await reportTokenUsage(customer_id, result.usage.total_tokens);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function createMeterReporter(config, meter_id) {
|
|
45
|
+
return async (customer_id, value, idempotency_key) => {
|
|
46
|
+
if (value <= 0)
|
|
47
|
+
return; // Skip zero/negative usage
|
|
48
|
+
await reportMeterEvent(config, {
|
|
49
|
+
meter_id,
|
|
50
|
+
customer_id,
|
|
51
|
+
value,
|
|
52
|
+
idempotency_key,
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ResolvedBillingConfig } from './billing.config';
|
|
2
|
+
/**
|
|
3
|
+
* Syncs plan definitions to Stripe products and prices.
|
|
4
|
+
* Uses lookup_keys so that prices can be updated without changing code references.
|
|
5
|
+
* Idempotent — safe to call on every startup.
|
|
6
|
+
*
|
|
7
|
+
* Strategy:
|
|
8
|
+
* - Products are matched by metadata.plan_id
|
|
9
|
+
* - Prices are matched by lookup_key (Stripe's built-in mechanism)
|
|
10
|
+
* - Existing resources are updated; missing ones are created
|
|
11
|
+
* - Nothing is deleted (archived plans stay in Stripe)
|
|
12
|
+
*/
|
|
13
|
+
export declare function syncProducts(config: ResolvedBillingConfig): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Syncs meter definitions to Stripe Billing Meters.
|
|
16
|
+
* Idempotent — creates meters that do not exist.
|
|
17
|
+
*/
|
|
18
|
+
export declare function syncMeters(config: ResolvedBillingConfig): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Run a full sync of products, prices, and meters.
|
|
21
|
+
* Called automatically on first request if `sync_on_startup` is enabled.
|
|
22
|
+
*/
|
|
23
|
+
export declare function syncAll(config: ResolvedBillingConfig): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=billing.products.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.products.d.ts","sourceRoot":"","sources":["../../src/server/billing.products.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAO9D;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsF/E;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B7E;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { getStripe, stripeCall } from './billing.stripe';
|
|
2
|
+
/** Track whether sync has been performed this lifecycle */
|
|
3
|
+
let products_synced = false;
|
|
4
|
+
let meters_synced = false;
|
|
5
|
+
/**
|
|
6
|
+
* Syncs plan definitions to Stripe products and prices.
|
|
7
|
+
* Uses lookup_keys so that prices can be updated without changing code references.
|
|
8
|
+
* Idempotent — safe to call on every startup.
|
|
9
|
+
*
|
|
10
|
+
* Strategy:
|
|
11
|
+
* - Products are matched by metadata.plan_id
|
|
12
|
+
* - Prices are matched by lookup_key (Stripe's built-in mechanism)
|
|
13
|
+
* - Existing resources are updated; missing ones are created
|
|
14
|
+
* - Nothing is deleted (archived plans stay in Stripe)
|
|
15
|
+
*/
|
|
16
|
+
export async function syncProducts(config) {
|
|
17
|
+
if (products_synced || !config.plans?.length)
|
|
18
|
+
return;
|
|
19
|
+
products_synced = true;
|
|
20
|
+
const stripe = getStripe(config);
|
|
21
|
+
for (const plan of config.plans) {
|
|
22
|
+
// 1. Ensure product exists
|
|
23
|
+
let product;
|
|
24
|
+
// Search by metadata.plan_id
|
|
25
|
+
const products = await stripeCall(() => stripe.products.search({
|
|
26
|
+
query: `metadata['plan_id']:'${plan.id}'`,
|
|
27
|
+
}));
|
|
28
|
+
product = products.data[0];
|
|
29
|
+
if (!product) {
|
|
30
|
+
// Create new product
|
|
31
|
+
product = await stripeCall(() => stripe.products.create({
|
|
32
|
+
name: plan.name,
|
|
33
|
+
description: plan.description,
|
|
34
|
+
metadata: { plan_id: plan.id, ...plan.metadata },
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// Update existing product
|
|
39
|
+
await stripeCall(() => stripe.products.update(product.id, {
|
|
40
|
+
name: plan.name,
|
|
41
|
+
description: plan.description,
|
|
42
|
+
active: !plan.archived,
|
|
43
|
+
metadata: { plan_id: plan.id, ...plan.metadata },
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
// 2. Ensure price exists with the correct lookup_key
|
|
47
|
+
const prices = await stripeCall(() => stripe.prices.list({ lookup_keys: [plan.lookup_key], limit: 1 }));
|
|
48
|
+
if (!prices.data.length) {
|
|
49
|
+
// Create price with lookup_key
|
|
50
|
+
await stripeCall(() => stripe.prices.create({
|
|
51
|
+
product: product.id,
|
|
52
|
+
unit_amount: plan.amount,
|
|
53
|
+
currency: plan.currency ?? 'usd',
|
|
54
|
+
recurring: {
|
|
55
|
+
interval: plan.interval,
|
|
56
|
+
interval_count: plan.interval_count ?? 1,
|
|
57
|
+
},
|
|
58
|
+
lookup_key: plan.lookup_key,
|
|
59
|
+
transfer_lookup_key: true,
|
|
60
|
+
metadata: { plan_id: plan.id },
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// If price exists but amount/interval changed, create new price
|
|
65
|
+
// and transfer the lookup_key
|
|
66
|
+
const existing_price = prices.data[0];
|
|
67
|
+
if (existing_price.unit_amount !== plan.amount ||
|
|
68
|
+
existing_price.recurring?.interval !== plan.interval ||
|
|
69
|
+
(existing_price.recurring?.interval_count ?? 1) !== (plan.interval_count ?? 1)) {
|
|
70
|
+
await stripeCall(() => stripe.prices.create({
|
|
71
|
+
product: product.id,
|
|
72
|
+
unit_amount: plan.amount,
|
|
73
|
+
currency: plan.currency ?? 'usd',
|
|
74
|
+
recurring: {
|
|
75
|
+
interval: plan.interval,
|
|
76
|
+
interval_count: plan.interval_count ?? 1,
|
|
77
|
+
},
|
|
78
|
+
lookup_key: plan.lookup_key,
|
|
79
|
+
transfer_lookup_key: true,
|
|
80
|
+
metadata: { plan_id: plan.id },
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Syncs meter definitions to Stripe Billing Meters.
|
|
88
|
+
* Idempotent — creates meters that do not exist.
|
|
89
|
+
*/
|
|
90
|
+
export async function syncMeters(config) {
|
|
91
|
+
if (meters_synced || !config.meters?.length)
|
|
92
|
+
return;
|
|
93
|
+
meters_synced = true;
|
|
94
|
+
const stripe = getStripe(config);
|
|
95
|
+
// List existing meters
|
|
96
|
+
const existing = await stripeCall(() => stripe.billing.meters.list({ limit: 100 }));
|
|
97
|
+
for (const meter of config.meters) {
|
|
98
|
+
const found = existing.data.find((m) => m.event_name === meter.event_name);
|
|
99
|
+
if (!found) {
|
|
100
|
+
await stripeCall(() => stripe.billing.meters.create({
|
|
101
|
+
display_name: meter.display_name,
|
|
102
|
+
event_name: meter.event_name,
|
|
103
|
+
default_aggregation: {
|
|
104
|
+
formula: meter.aggregation,
|
|
105
|
+
},
|
|
106
|
+
customer_mapping: {
|
|
107
|
+
type: 'by_id',
|
|
108
|
+
event_payload_key: 'stripe_customer_id',
|
|
109
|
+
},
|
|
110
|
+
value_settings: {
|
|
111
|
+
event_payload_key: meter.value_key ?? 'value',
|
|
112
|
+
},
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Run a full sync of products, prices, and meters.
|
|
119
|
+
* Called automatically on first request if `sync_on_startup` is enabled.
|
|
120
|
+
*/
|
|
121
|
+
export async function syncAll(config) {
|
|
122
|
+
await syncProducts(config);
|
|
123
|
+
await syncMeters(config);
|
|
124
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RequestEvent } from '@sveltejs/kit';
|
|
2
|
+
import type { ResolvedBillingConfig, AuthServerRpc, WebsocketRpc } from './billing.config';
|
|
3
|
+
export interface RouteContext {
|
|
4
|
+
getAuthServer?: (event: RequestEvent) => AuthServerRpc | undefined;
|
|
5
|
+
getWebsocket?: (event: RequestEvent) => WebsocketRpc | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function handleBillingRoute(event: RequestEvent, config: ResolvedBillingConfig, route_path: string, method: string, ctx: RouteContext): Promise<Response>;
|
|
8
|
+
//# sourceMappingURL=billing.routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.routes.d.ts","sourceRoot":"","sources":["../../src/server/billing.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EACX,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAa1B,MAAM,WAAW,YAAY;IAC5B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,aAAa,GAAG,SAAS,CAAC;IACnE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,YAAY,GAAG,SAAS,CAAC;CACjE;AAoLD,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,qBAAqB,EAC7B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,YAAY,GACf,OAAO,CAAC,QAAQ,CAAC,CA+XnB"}
|