@stripe-sdk/core 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -261
- package/dist/client/index.d.mts +0 -4
- package/dist/client/index.d.ts +0 -4
- package/dist/client/index.js +70 -11
- package/dist/client/index.mjs +71 -12
- package/dist/{index-D8rM_YD4.d.mts → index-BKDJf1Hz.d.mts} +1 -27
- package/dist/{index-D8rM_YD4.d.ts → index-BKDJf1Hz.d.ts} +1 -27
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +601 -231
- package/dist/index.mjs +602 -232
- package/dist/next/index.d.mts +55 -32
- package/dist/next/index.d.ts +55 -32
- package/dist/next/index.js +362 -143
- package/dist/next/index.mjs +362 -143
- package/dist/server/index.d.mts +61 -21
- package/dist/server/index.d.ts +61 -21
- package/dist/server/index.js +546 -237
- package/dist/server/index.mjs +546 -237
- package/dist/server/webhooks/index.d.mts +1 -1
- package/dist/server/webhooks/index.d.ts +1 -1
- package/dist/server/webhooks/index.js +19 -7
- package/dist/server/webhooks/index.mjs +19 -7
- package/package.json +8 -5
- package/dist/client/index.js.map +0 -1
- package/dist/client/index.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/next/index.js.map +0 -1
- package/dist/next/index.mjs.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/server/index.mjs.map +0 -1
- package/dist/server/webhooks/index.js.map +0 -1
- package/dist/server/webhooks/index.mjs.map +0 -1
package/dist/next/index.js
CHANGED
|
@@ -59,6 +59,9 @@ function createWebhookHandler(config) {
|
|
|
59
59
|
function createNextWebhookHandler(config) {
|
|
60
60
|
const handler = createWebhookHandler(config);
|
|
61
61
|
return async function POST(request) {
|
|
62
|
+
if (request.method !== "POST") {
|
|
63
|
+
return new Response(null, { status: 405 });
|
|
64
|
+
}
|
|
62
65
|
try {
|
|
63
66
|
const contentLength = request.headers.get("content-length");
|
|
64
67
|
if (contentLength && parseInt(contentLength, 10) > MAX_BODY_SIZE) {
|
|
@@ -68,6 +71,12 @@ function createNextWebhookHandler(config) {
|
|
|
68
71
|
});
|
|
69
72
|
}
|
|
70
73
|
const body = await request.text();
|
|
74
|
+
if (body.length > MAX_BODY_SIZE) {
|
|
75
|
+
return new Response(JSON.stringify({ error: "Webhook body too large" }), {
|
|
76
|
+
status: 413,
|
|
77
|
+
headers: { "Content-Type": "application/json" }
|
|
78
|
+
});
|
|
79
|
+
}
|
|
71
80
|
const signature = request.headers.get("stripe-signature");
|
|
72
81
|
if (!signature) {
|
|
73
82
|
return new Response(JSON.stringify({ error: "Missing stripe-signature header" }), {
|
|
@@ -81,8 +90,8 @@ function createNextWebhookHandler(config) {
|
|
|
81
90
|
headers: { "Content-Type": "application/json" }
|
|
82
91
|
});
|
|
83
92
|
} catch (error) {
|
|
84
|
-
|
|
85
|
-
return new Response(JSON.stringify({ error:
|
|
93
|
+
console.error("[@stripe-sdk/core] Webhook error:", error instanceof Error ? error.message : "Unknown error");
|
|
94
|
+
return new Response(JSON.stringify({ error: "Webhook processing failed" }), {
|
|
86
95
|
status: 400,
|
|
87
96
|
headers: { "Content-Type": "application/json" }
|
|
88
97
|
});
|
|
@@ -106,8 +115,8 @@ function createPagesWebhookHandler(webhookConfig) {
|
|
|
106
115
|
const result = await handler(body, signature);
|
|
107
116
|
res.status(200).json(result);
|
|
108
117
|
} catch (error) {
|
|
109
|
-
|
|
110
|
-
res.status(400).json({ error:
|
|
118
|
+
console.error("[@stripe-sdk/core] Webhook error:", error instanceof Error ? error.message : "Unknown error");
|
|
119
|
+
res.status(400).json({ error: "Webhook processing failed" });
|
|
111
120
|
}
|
|
112
121
|
};
|
|
113
122
|
}
|
|
@@ -135,28 +144,42 @@ function getRawBody(req) {
|
|
|
135
144
|
}
|
|
136
145
|
const chunks = [];
|
|
137
146
|
let totalLength = 0;
|
|
147
|
+
let rejected = false;
|
|
138
148
|
req.on("data", (chunk) => {
|
|
149
|
+
if (rejected) return;
|
|
139
150
|
const buf = Buffer.from(chunk);
|
|
140
151
|
totalLength += buf.length;
|
|
141
152
|
if (totalLength > MAX_BODY_SIZE) {
|
|
153
|
+
rejected = true;
|
|
142
154
|
reject(new Error("Webhook body too large"));
|
|
143
155
|
return;
|
|
144
156
|
}
|
|
145
157
|
chunks.push(buf);
|
|
146
158
|
});
|
|
147
|
-
req.on("end", () =>
|
|
159
|
+
req.on("end", () => {
|
|
160
|
+
if (!rejected) resolve(Buffer.concat(chunks).toString("utf8"));
|
|
161
|
+
});
|
|
148
162
|
req.on("error", reject);
|
|
149
163
|
});
|
|
150
164
|
}
|
|
151
165
|
|
|
152
166
|
// src/utils/errors.ts
|
|
167
|
+
var SAFE_ERROR_MESSAGES = {
|
|
168
|
+
card_declined: "Your card was declined.",
|
|
169
|
+
expired_card: "Your card has expired.",
|
|
170
|
+
incorrect_cvc: "Incorrect security code.",
|
|
171
|
+
processing_error: "An error occurred while processing your card.",
|
|
172
|
+
incorrect_number: "The card number is incorrect.",
|
|
173
|
+
insufficient_funds: "Insufficient funds."
|
|
174
|
+
};
|
|
153
175
|
function handleStripeError(error) {
|
|
154
176
|
if (error?.type) {
|
|
155
177
|
const stripeError = error;
|
|
178
|
+
const safeMessage = stripeError.code && SAFE_ERROR_MESSAGES[stripeError.code] || getSafeMessage(stripeError.type);
|
|
156
179
|
return {
|
|
157
180
|
data: null,
|
|
158
181
|
error: {
|
|
159
|
-
message:
|
|
182
|
+
message: safeMessage,
|
|
160
183
|
type: stripeError.type,
|
|
161
184
|
code: stripeError.code,
|
|
162
185
|
statusCode: stripeError.statusCode
|
|
@@ -166,72 +189,196 @@ function handleStripeError(error) {
|
|
|
166
189
|
return {
|
|
167
190
|
data: null,
|
|
168
191
|
error: {
|
|
169
|
-
message:
|
|
192
|
+
message: "An unexpected error occurred",
|
|
170
193
|
type: "sdk_error"
|
|
171
194
|
}
|
|
172
195
|
};
|
|
173
196
|
}
|
|
197
|
+
function getSafeMessage(type) {
|
|
198
|
+
switch (type) {
|
|
199
|
+
case "card_error":
|
|
200
|
+
return "A card error occurred.";
|
|
201
|
+
case "invalid_request_error":
|
|
202
|
+
return "Invalid request. Please check your input.";
|
|
203
|
+
case "authentication_error":
|
|
204
|
+
return "Authentication failed.";
|
|
205
|
+
case "rate_limit_error":
|
|
206
|
+
return "Too many requests. Please try again later.";
|
|
207
|
+
case "api_error":
|
|
208
|
+
return "A payment processing error occurred. Please try again.";
|
|
209
|
+
default:
|
|
210
|
+
return "An unexpected error occurred.";
|
|
211
|
+
}
|
|
212
|
+
}
|
|
174
213
|
function success(data) {
|
|
175
214
|
return { data, error: null };
|
|
176
215
|
}
|
|
177
216
|
|
|
217
|
+
// src/utils/validators.ts
|
|
218
|
+
var STRIPE_ID_PREFIXES = {
|
|
219
|
+
customer: "cus_",
|
|
220
|
+
paymentIntent: "pi_",
|
|
221
|
+
paymentMethod: "pm_",
|
|
222
|
+
subscription: "sub_",
|
|
223
|
+
invoice: "in_",
|
|
224
|
+
invoiceItem: "ii_",
|
|
225
|
+
product: "prod_",
|
|
226
|
+
price: "price_",
|
|
227
|
+
coupon: "",
|
|
228
|
+
// coupons can have custom IDs
|
|
229
|
+
promotionCode: "promo_",
|
|
230
|
+
refund: "re_",
|
|
231
|
+
dispute: "dp_",
|
|
232
|
+
account: "acct_",
|
|
233
|
+
transfer: "tr_",
|
|
234
|
+
payout: "po_",
|
|
235
|
+
setupIntent: "seti_",
|
|
236
|
+
session: "cs_",
|
|
237
|
+
paymentLink: "plink_"
|
|
238
|
+
};
|
|
239
|
+
function validateStripeId(id, type) {
|
|
240
|
+
if (!id || typeof id !== "string") {
|
|
241
|
+
throw new Error(`${type} ID is required and must be a non-empty string`);
|
|
242
|
+
}
|
|
243
|
+
const prefix = STRIPE_ID_PREFIXES[type];
|
|
244
|
+
if (prefix && !id.startsWith(prefix)) {
|
|
245
|
+
throw new Error(`Invalid ${type} ID: expected prefix "${prefix}"`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function validateAmount(amount, label = "amount") {
|
|
249
|
+
if (typeof amount !== "number" || !Number.isFinite(amount)) {
|
|
250
|
+
throw new Error(`${label} must be a finite number`);
|
|
251
|
+
}
|
|
252
|
+
if (!Number.isInteger(amount)) {
|
|
253
|
+
throw new Error(`${label} must be an integer (amount in smallest currency unit)`);
|
|
254
|
+
}
|
|
255
|
+
if (amount < 0) {
|
|
256
|
+
throw new Error(`${label} must not be negative`);
|
|
257
|
+
}
|
|
258
|
+
if (amount > 99999999) {
|
|
259
|
+
throw new Error(`${label} exceeds maximum allowed value (99999999)`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function validateCurrency(currency) {
|
|
263
|
+
if (!currency || typeof currency !== "string") {
|
|
264
|
+
throw new Error("Currency is required");
|
|
265
|
+
}
|
|
266
|
+
const normalized = currency.trim().toLowerCase();
|
|
267
|
+
if (!/^[a-z]{3}$/.test(normalized)) {
|
|
268
|
+
throw new Error("Currency must be a valid 3-letter ISO 4217 code");
|
|
269
|
+
}
|
|
270
|
+
return normalized;
|
|
271
|
+
}
|
|
272
|
+
function validateUrl(url, label = "URL") {
|
|
273
|
+
if (!url || typeof url !== "string") {
|
|
274
|
+
throw new Error(`${label} is required`);
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
const parsed = new URL(url);
|
|
278
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
279
|
+
throw new Error(`${label} must use http or https protocol`);
|
|
280
|
+
}
|
|
281
|
+
} catch (e) {
|
|
282
|
+
if (e instanceof Error && e.message.includes("protocol")) throw e;
|
|
283
|
+
throw new Error(`${label} must be a valid URL`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function validateMetadata(metadata) {
|
|
287
|
+
const keys = Object.keys(metadata);
|
|
288
|
+
if (keys.length > 50) {
|
|
289
|
+
throw new Error("Metadata cannot have more than 50 keys");
|
|
290
|
+
}
|
|
291
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
292
|
+
if (key.length > 40) {
|
|
293
|
+
throw new Error(`Metadata key "${key}" exceeds 40 characters`);
|
|
294
|
+
}
|
|
295
|
+
if (typeof value !== "string") {
|
|
296
|
+
throw new Error(`Metadata value for key "${key}" must be a string`);
|
|
297
|
+
}
|
|
298
|
+
if (value.length > 500) {
|
|
299
|
+
throw new Error(`Metadata value for key "${key}" exceeds 500 characters`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
178
304
|
// src/server/payments/index.ts
|
|
179
|
-
async function createPaymentIntent(input) {
|
|
305
|
+
async function createPaymentIntent(input, options) {
|
|
180
306
|
try {
|
|
307
|
+
validateAmount(input.amount);
|
|
308
|
+
const currency = validateCurrency(input.currency);
|
|
309
|
+
if (input.customerId) validateStripeId(input.customerId, "customer");
|
|
310
|
+
if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
|
|
311
|
+
if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
|
|
312
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
181
313
|
const stripe = getStripe();
|
|
182
|
-
const paymentIntent = await stripe.paymentIntents.create(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
314
|
+
const paymentIntent = await stripe.paymentIntents.create(
|
|
315
|
+
{
|
|
316
|
+
amount: input.amount,
|
|
317
|
+
currency,
|
|
318
|
+
customer: input.customerId,
|
|
319
|
+
payment_method: input.paymentMethodId,
|
|
320
|
+
metadata: input.metadata,
|
|
321
|
+
description: input.description,
|
|
322
|
+
receipt_email: input.receiptEmail,
|
|
323
|
+
setup_future_usage: input.setupFutureUsage,
|
|
324
|
+
automatic_payment_methods: input.automaticPaymentMethods === false || input.paymentMethodId ? void 0 : { enabled: true },
|
|
325
|
+
return_url: input.returnUrl
|
|
326
|
+
},
|
|
327
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
328
|
+
);
|
|
194
329
|
return success(paymentIntent);
|
|
195
330
|
} catch (error) {
|
|
196
331
|
return handleStripeError(error);
|
|
197
332
|
}
|
|
198
333
|
}
|
|
199
|
-
async function createCheckoutSession(input) {
|
|
334
|
+
async function createCheckoutSession(input, options) {
|
|
200
335
|
try {
|
|
336
|
+
validateUrl(input.successUrl, "successUrl");
|
|
337
|
+
validateUrl(input.cancelUrl, "cancelUrl");
|
|
338
|
+
if (input.customerId) validateStripeId(input.customerId, "customer");
|
|
339
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
201
340
|
const stripe = getStripe();
|
|
202
|
-
const session = await stripe.checkout.sessions.create(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
341
|
+
const session = await stripe.checkout.sessions.create(
|
|
342
|
+
{
|
|
343
|
+
mode: input.mode,
|
|
344
|
+
line_items: input.lineItems.map((item) => ({
|
|
345
|
+
price: item.priceId,
|
|
346
|
+
quantity: item.quantity
|
|
347
|
+
})),
|
|
348
|
+
success_url: input.successUrl,
|
|
349
|
+
cancel_url: input.cancelUrl,
|
|
350
|
+
customer: input.customerId,
|
|
351
|
+
customer_email: input.customerEmail,
|
|
352
|
+
metadata: input.metadata,
|
|
353
|
+
allow_promotion_codes: input.allowPromotionCodes,
|
|
354
|
+
shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0,
|
|
355
|
+
billing_address_collection: input.billingAddressCollection,
|
|
356
|
+
subscription_data: input.trialPeriodDays ? { trial_period_days: input.trialPeriodDays } : void 0,
|
|
357
|
+
tax_id_collection: input.taxIdCollection ? { enabled: true } : void 0,
|
|
358
|
+
automatic_tax: input.automaticTax ? { enabled: true } : void 0,
|
|
359
|
+
locale: input.locale
|
|
360
|
+
},
|
|
361
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
362
|
+
);
|
|
221
363
|
return success(session);
|
|
222
364
|
} catch (error) {
|
|
223
365
|
return handleStripeError(error);
|
|
224
366
|
}
|
|
225
367
|
}
|
|
226
|
-
async function createSetupIntent(input) {
|
|
368
|
+
async function createSetupIntent(input, options) {
|
|
227
369
|
try {
|
|
370
|
+
if (input.customerId) validateStripeId(input.customerId, "customer");
|
|
371
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
228
372
|
const stripe = getStripe();
|
|
229
|
-
const setupIntent = await stripe.setupIntents.create(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
373
|
+
const setupIntent = await stripe.setupIntents.create(
|
|
374
|
+
{
|
|
375
|
+
customer: input.customerId,
|
|
376
|
+
payment_method_types: input.paymentMethodTypes,
|
|
377
|
+
usage: input.usage,
|
|
378
|
+
metadata: input.metadata
|
|
379
|
+
},
|
|
380
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
381
|
+
);
|
|
235
382
|
return success(setupIntent);
|
|
236
383
|
} catch (error) {
|
|
237
384
|
return handleStripeError(error);
|
|
@@ -239,39 +386,49 @@ async function createSetupIntent(input) {
|
|
|
239
386
|
}
|
|
240
387
|
|
|
241
388
|
// src/server/customers/index.ts
|
|
242
|
-
async function createCustomer(input) {
|
|
389
|
+
async function createCustomer(input, options) {
|
|
243
390
|
try {
|
|
391
|
+
if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
|
|
392
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
244
393
|
const stripe = getStripe();
|
|
245
|
-
const customer = await stripe.customers.create(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
394
|
+
const customer = await stripe.customers.create(
|
|
395
|
+
{
|
|
396
|
+
email: input.email,
|
|
397
|
+
name: input.name,
|
|
398
|
+
phone: input.phone,
|
|
399
|
+
description: input.description,
|
|
400
|
+
metadata: input.metadata,
|
|
401
|
+
payment_method: input.paymentMethodId,
|
|
402
|
+
invoice_settings: input.paymentMethodId ? { default_payment_method: input.paymentMethodId } : void 0,
|
|
403
|
+
address: input.address ? {
|
|
404
|
+
line1: input.address.line1,
|
|
405
|
+
line2: input.address.line2,
|
|
406
|
+
city: input.address.city,
|
|
407
|
+
state: input.address.state,
|
|
408
|
+
postal_code: input.address.postalCode,
|
|
409
|
+
country: input.address.country
|
|
410
|
+
} : void 0
|
|
411
|
+
},
|
|
412
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
413
|
+
);
|
|
262
414
|
return success(customer);
|
|
263
415
|
} catch (error) {
|
|
264
416
|
return handleStripeError(error);
|
|
265
417
|
}
|
|
266
418
|
}
|
|
267
|
-
async function createPortalSession(input) {
|
|
419
|
+
async function createPortalSession(input, options) {
|
|
268
420
|
try {
|
|
421
|
+
validateStripeId(input.customerId, "customer");
|
|
422
|
+
if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
|
|
269
423
|
const stripe = getStripe();
|
|
270
|
-
const session = await stripe.billingPortal.sessions.create(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
424
|
+
const session = await stripe.billingPortal.sessions.create(
|
|
425
|
+
{
|
|
426
|
+
customer: input.customerId,
|
|
427
|
+
return_url: input.returnUrl,
|
|
428
|
+
configuration: input.configuration
|
|
429
|
+
},
|
|
430
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
431
|
+
);
|
|
275
432
|
return success(session);
|
|
276
433
|
} catch (error) {
|
|
277
434
|
return handleStripeError(error);
|
|
@@ -279,23 +436,28 @@ async function createPortalSession(input) {
|
|
|
279
436
|
}
|
|
280
437
|
|
|
281
438
|
// src/server/subscriptions/index.ts
|
|
282
|
-
async function createSubscription(input) {
|
|
439
|
+
async function createSubscription(input, options) {
|
|
283
440
|
try {
|
|
441
|
+
validateStripeId(input.customerId, "customer");
|
|
442
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
284
443
|
const stripe = getStripe();
|
|
285
444
|
const items = input.items ? input.items.map((item) => ({ price: item.priceId, quantity: item.quantity })) : [{ price: input.priceId, quantity: input.quantity ?? 1 }];
|
|
286
|
-
const subscription = await stripe.subscriptions.create(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
445
|
+
const subscription = await stripe.subscriptions.create(
|
|
446
|
+
{
|
|
447
|
+
customer: input.customerId,
|
|
448
|
+
items,
|
|
449
|
+
metadata: input.metadata,
|
|
450
|
+
trial_period_days: input.trialPeriodDays,
|
|
451
|
+
coupon: input.couponId,
|
|
452
|
+
promotion_code: input.promotionCodeId,
|
|
453
|
+
payment_behavior: input.paymentBehavior ?? "default_incomplete",
|
|
454
|
+
cancel_at_period_end: input.cancelAtPeriodEnd,
|
|
455
|
+
billing_cycle_anchor: input.billingCycleAnchor,
|
|
456
|
+
proration_behavior: input.prorationBehavior,
|
|
457
|
+
expand: ["latest_invoice.payment_intent"]
|
|
458
|
+
},
|
|
459
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
460
|
+
);
|
|
299
461
|
return success(subscription);
|
|
300
462
|
} catch (error) {
|
|
301
463
|
return handleStripeError(error);
|
|
@@ -303,6 +465,7 @@ async function createSubscription(input) {
|
|
|
303
465
|
}
|
|
304
466
|
async function cancelSubscription(input) {
|
|
305
467
|
try {
|
|
468
|
+
validateStripeId(input.subscriptionId, "subscription");
|
|
306
469
|
const stripe = getStripe();
|
|
307
470
|
if (input.cancelAtPeriodEnd) {
|
|
308
471
|
const subscription2 = await stripe.subscriptions.update(input.subscriptionId, {
|
|
@@ -327,6 +490,7 @@ async function cancelSubscription(input) {
|
|
|
327
490
|
}
|
|
328
491
|
async function resumeSubscription(subscriptionId) {
|
|
329
492
|
try {
|
|
493
|
+
validateStripeId(subscriptionId, "subscription");
|
|
330
494
|
const stripe = getStripe();
|
|
331
495
|
const subscription = await stripe.subscriptions.update(subscriptionId, {
|
|
332
496
|
cancel_at_period_end: false
|
|
@@ -338,113 +502,168 @@ async function resumeSubscription(subscriptionId) {
|
|
|
338
502
|
}
|
|
339
503
|
|
|
340
504
|
// src/next/index.ts
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
},
|
|
345
|
-
createCheckoutSession: async (input) => {
|
|
346
|
-
return createCheckoutSession(input);
|
|
347
|
-
},
|
|
348
|
-
createSetupIntent: async (input) => {
|
|
349
|
-
return createSetupIntent(input);
|
|
350
|
-
},
|
|
351
|
-
createCustomer: async (input) => {
|
|
352
|
-
return createCustomer(input);
|
|
353
|
-
},
|
|
354
|
-
createPortalSession: async (input) => {
|
|
355
|
-
return createPortalSession(input);
|
|
356
|
-
},
|
|
357
|
-
createSubscription: async (input) => {
|
|
358
|
-
return createSubscription(input);
|
|
359
|
-
},
|
|
360
|
-
cancelSubscription: async (input) => {
|
|
361
|
-
return cancelSubscription(input);
|
|
362
|
-
},
|
|
363
|
-
resumeSubscription: async (subscriptionId) => {
|
|
364
|
-
return resumeSubscription(subscriptionId);
|
|
505
|
+
function createActions(config) {
|
|
506
|
+
if (typeof config?.authorize !== "function") {
|
|
507
|
+
throw new Error("[@stripe-sdk/core] createActions requires an authorize callback");
|
|
365
508
|
}
|
|
366
|
-
|
|
509
|
+
async function checkAuth() {
|
|
510
|
+
const result = await config.authorize();
|
|
511
|
+
if (result === false) {
|
|
512
|
+
throw new Error("Unauthorized");
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
createPaymentIntent: async (input) => {
|
|
517
|
+
await checkAuth();
|
|
518
|
+
return createPaymentIntent(input);
|
|
519
|
+
},
|
|
520
|
+
createCheckoutSession: async (input) => {
|
|
521
|
+
await checkAuth();
|
|
522
|
+
return createCheckoutSession(input);
|
|
523
|
+
},
|
|
524
|
+
createSetupIntent: async (input) => {
|
|
525
|
+
await checkAuth();
|
|
526
|
+
return createSetupIntent(input);
|
|
527
|
+
},
|
|
528
|
+
createCustomer: async (input) => {
|
|
529
|
+
await checkAuth();
|
|
530
|
+
return createCustomer(input);
|
|
531
|
+
},
|
|
532
|
+
createPortalSession: async (input) => {
|
|
533
|
+
await checkAuth();
|
|
534
|
+
return createPortalSession(input);
|
|
535
|
+
},
|
|
536
|
+
createSubscription: async (input) => {
|
|
537
|
+
await checkAuth();
|
|
538
|
+
return createSubscription(input);
|
|
539
|
+
},
|
|
540
|
+
cancelSubscription: async (input) => {
|
|
541
|
+
await checkAuth();
|
|
542
|
+
return cancelSubscription(input);
|
|
543
|
+
},
|
|
544
|
+
resumeSubscription: async (subscriptionId) => {
|
|
545
|
+
await checkAuth();
|
|
546
|
+
return resumeSubscription(subscriptionId);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function errorResponse(message, status) {
|
|
551
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
552
|
+
status,
|
|
553
|
+
headers: { "Content-Type": "application/json" }
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
function validateRouteOptions(options) {
|
|
557
|
+
if (typeof options?.authorize !== "function") {
|
|
558
|
+
throw new Error("[@stripe-sdk/core] Route helpers require an authorize callback");
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function ensureJsonContentType(request) {
|
|
562
|
+
const contentType = request.headers.get("content-type");
|
|
563
|
+
if (!contentType?.includes("application/json")) {
|
|
564
|
+
return errorResponse("Content-Type must be application/json", 415);
|
|
565
|
+
}
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
async function parseJsonBody(request) {
|
|
569
|
+
try {
|
|
570
|
+
const data = await request.json();
|
|
571
|
+
return { data };
|
|
572
|
+
} catch {
|
|
573
|
+
return { error: errorResponse("Invalid JSON in request body", 400) };
|
|
574
|
+
}
|
|
575
|
+
}
|
|
367
576
|
function createPaymentIntentRoute(options) {
|
|
577
|
+
validateRouteOptions(options);
|
|
368
578
|
return async function POST(request) {
|
|
369
579
|
try {
|
|
370
|
-
|
|
371
|
-
if (
|
|
580
|
+
const ctError = ensureJsonContentType(request);
|
|
581
|
+
if (ctError) return ctError;
|
|
582
|
+
const authResult = await options.authorize(request);
|
|
583
|
+
if (authResult === false) return errorResponse("Unauthorized", 401);
|
|
584
|
+
const parsed = await parseJsonBody(request);
|
|
585
|
+
if ("error" in parsed) return parsed.error;
|
|
586
|
+
let input = parsed.data;
|
|
587
|
+
if (options.beforeCreate) {
|
|
372
588
|
input = await options.beforeCreate(input, request);
|
|
373
589
|
}
|
|
374
590
|
const result = await createPaymentIntent(input);
|
|
375
591
|
if (result.error) {
|
|
376
|
-
return
|
|
377
|
-
status: 400,
|
|
378
|
-
headers: { "Content-Type": "application/json" }
|
|
379
|
-
});
|
|
592
|
+
return errorResponse(result.error.message, 400);
|
|
380
593
|
}
|
|
381
594
|
return new Response(
|
|
382
595
|
JSON.stringify({ clientSecret: result.data.client_secret, id: result.data.id }),
|
|
383
596
|
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
384
597
|
);
|
|
385
598
|
} catch (error) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
);
|
|
599
|
+
const message = error instanceof Error && error.message === "Unauthorized" ? "Unauthorized" : "Internal error";
|
|
600
|
+
const status = message === "Unauthorized" ? 401 : 500;
|
|
601
|
+
return errorResponse(message, status);
|
|
390
602
|
}
|
|
391
603
|
};
|
|
392
604
|
}
|
|
393
605
|
function createCheckoutSessionRoute(options) {
|
|
606
|
+
validateRouteOptions(options);
|
|
394
607
|
return async function POST(request) {
|
|
395
608
|
try {
|
|
396
|
-
|
|
397
|
-
if (
|
|
609
|
+
const ctError = ensureJsonContentType(request);
|
|
610
|
+
if (ctError) return ctError;
|
|
611
|
+
const authResult = await options.authorize(request);
|
|
612
|
+
if (authResult === false) return errorResponse("Unauthorized", 401);
|
|
613
|
+
const parsed = await parseJsonBody(request);
|
|
614
|
+
if ("error" in parsed) return parsed.error;
|
|
615
|
+
let input = parsed.data;
|
|
616
|
+
if (options.beforeCreate) {
|
|
398
617
|
input = await options.beforeCreate(input, request);
|
|
399
618
|
}
|
|
400
619
|
const result = await createCheckoutSession(input);
|
|
401
620
|
if (result.error) {
|
|
402
|
-
return
|
|
403
|
-
status: 400,
|
|
404
|
-
headers: { "Content-Type": "application/json" }
|
|
405
|
-
});
|
|
621
|
+
return errorResponse(result.error.message, 400);
|
|
406
622
|
}
|
|
407
623
|
return new Response(
|
|
408
624
|
JSON.stringify({ sessionId: result.data.id, url: result.data.url }),
|
|
409
625
|
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
410
626
|
);
|
|
411
627
|
} catch (error) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
);
|
|
628
|
+
const message = error instanceof Error && error.message === "Unauthorized" ? "Unauthorized" : "Internal error";
|
|
629
|
+
const status = message === "Unauthorized" ? 401 : 500;
|
|
630
|
+
return errorResponse(message, status);
|
|
416
631
|
}
|
|
417
632
|
};
|
|
418
633
|
}
|
|
419
|
-
function createPortalSessionRoute() {
|
|
634
|
+
function createPortalSessionRoute(options) {
|
|
635
|
+
validateRouteOptions(options);
|
|
420
636
|
return async function POST(request) {
|
|
421
637
|
try {
|
|
422
|
-
const
|
|
638
|
+
const ctError = ensureJsonContentType(request);
|
|
639
|
+
if (ctError) return ctError;
|
|
640
|
+
const authResult = await options.authorize(request);
|
|
641
|
+
if (authResult === false) return errorResponse("Unauthorized", 401);
|
|
642
|
+
const parsed = await parseJsonBody(request);
|
|
643
|
+
if ("error" in parsed) return parsed.error;
|
|
644
|
+
let input = parsed.data;
|
|
645
|
+
if (options.beforeCreate) {
|
|
646
|
+
input = await options.beforeCreate(input, request);
|
|
647
|
+
}
|
|
423
648
|
const result = await createPortalSession(input);
|
|
424
649
|
if (result.error) {
|
|
425
|
-
return
|
|
426
|
-
status: 400,
|
|
427
|
-
headers: { "Content-Type": "application/json" }
|
|
428
|
-
});
|
|
650
|
+
return errorResponse(result.error.message, 400);
|
|
429
651
|
}
|
|
430
652
|
return new Response(
|
|
431
653
|
JSON.stringify({ url: result.data.url }),
|
|
432
654
|
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
433
655
|
);
|
|
434
656
|
} catch (error) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
);
|
|
657
|
+
const message = error instanceof Error && error.message === "Unauthorized" ? "Unauthorized" : "Internal error";
|
|
658
|
+
const status = message === "Unauthorized" ? 401 : 500;
|
|
659
|
+
return errorResponse(message, status);
|
|
439
660
|
}
|
|
440
661
|
};
|
|
441
662
|
}
|
|
442
663
|
|
|
443
|
-
exports.
|
|
664
|
+
exports.createActions = createActions;
|
|
444
665
|
exports.createCheckoutSessionRoute = createCheckoutSessionRoute;
|
|
445
666
|
exports.createNextWebhookHandler = createNextWebhookHandler;
|
|
446
667
|
exports.createPagesWebhookHandler = createPagesWebhookHandler;
|
|
447
668
|
exports.createPaymentIntentRoute = createPaymentIntentRoute;
|
|
448
669
|
exports.createPortalSessionRoute = createPortalSessionRoute;
|
|
449
|
-
//# sourceMappingURL=index.js.map
|
|
450
|
-
//# sourceMappingURL=index.js.map
|