@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/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Stripe from 'stripe';
|
|
2
|
-
import { createContext, useContext, useMemo, useState, useCallback } from 'react';
|
|
2
|
+
import { createContext, useContext, useMemo, useRef, useState, useCallback } from 'react';
|
|
3
3
|
import { loadStripe } from '@stripe/stripe-js';
|
|
4
4
|
import { Elements, useStripe, useElements, LinkAuthenticationElement, PaymentElement } from '@stripe/react-stripe-js';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -8,12 +8,16 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
8
8
|
var stripeInstance = null;
|
|
9
9
|
var currentConfig = null;
|
|
10
10
|
function initStripe(config) {
|
|
11
|
+
if (stripeInstance) {
|
|
12
|
+
console.warn("[@stripe-sdk/core] Stripe is already initialized. Re-initializing with new config.");
|
|
13
|
+
}
|
|
11
14
|
currentConfig = config;
|
|
12
15
|
stripeInstance = new Stripe(config.secretKey, {
|
|
13
16
|
apiVersion: config.apiVersion ?? "2025-01-27.acacia",
|
|
17
|
+
maxNetworkRetries: config.maxNetworkRetries ?? 2,
|
|
14
18
|
appInfo: config.appInfo ?? {
|
|
15
19
|
name: "@stripe-sdk/core",
|
|
16
|
-
version: "1.0.
|
|
20
|
+
version: "1.0.1"
|
|
17
21
|
}
|
|
18
22
|
});
|
|
19
23
|
return stripeInstance;
|
|
@@ -32,17 +36,27 @@ function getConfig() {
|
|
|
32
36
|
"[@stripe-sdk/core] Stripe not initialized. Call initStripe({ secretKey, publishableKey }) first."
|
|
33
37
|
);
|
|
34
38
|
}
|
|
35
|
-
|
|
39
|
+
const { secretKey: _sk, ...safeConfig } = currentConfig;
|
|
40
|
+
return safeConfig;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
// src/utils/errors.ts
|
|
44
|
+
var SAFE_ERROR_MESSAGES = {
|
|
45
|
+
card_declined: "Your card was declined.",
|
|
46
|
+
expired_card: "Your card has expired.",
|
|
47
|
+
incorrect_cvc: "Incorrect security code.",
|
|
48
|
+
processing_error: "An error occurred while processing your card.",
|
|
49
|
+
incorrect_number: "The card number is incorrect.",
|
|
50
|
+
insufficient_funds: "Insufficient funds."
|
|
51
|
+
};
|
|
39
52
|
function handleStripeError(error) {
|
|
40
53
|
if (error?.type) {
|
|
41
54
|
const stripeError = error;
|
|
55
|
+
const safeMessage = stripeError.code && SAFE_ERROR_MESSAGES[stripeError.code] || getSafeMessage(stripeError.type);
|
|
42
56
|
return {
|
|
43
57
|
data: null,
|
|
44
58
|
error: {
|
|
45
|
-
message:
|
|
59
|
+
message: safeMessage,
|
|
46
60
|
type: stripeError.type,
|
|
47
61
|
code: stripeError.code,
|
|
48
62
|
statusCode: stripeError.statusCode
|
|
@@ -52,31 +66,147 @@ function handleStripeError(error) {
|
|
|
52
66
|
return {
|
|
53
67
|
data: null,
|
|
54
68
|
error: {
|
|
55
|
-
message:
|
|
69
|
+
message: "An unexpected error occurred",
|
|
56
70
|
type: "sdk_error"
|
|
57
71
|
}
|
|
58
72
|
};
|
|
59
73
|
}
|
|
74
|
+
function getSafeMessage(type) {
|
|
75
|
+
switch (type) {
|
|
76
|
+
case "card_error":
|
|
77
|
+
return "A card error occurred.";
|
|
78
|
+
case "invalid_request_error":
|
|
79
|
+
return "Invalid request. Please check your input.";
|
|
80
|
+
case "authentication_error":
|
|
81
|
+
return "Authentication failed.";
|
|
82
|
+
case "rate_limit_error":
|
|
83
|
+
return "Too many requests. Please try again later.";
|
|
84
|
+
case "api_error":
|
|
85
|
+
return "A payment processing error occurred. Please try again.";
|
|
86
|
+
default:
|
|
87
|
+
return "An unexpected error occurred.";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
60
90
|
function success(data) {
|
|
61
91
|
return { data, error: null };
|
|
62
92
|
}
|
|
63
93
|
|
|
94
|
+
// src/utils/validators.ts
|
|
95
|
+
var STRIPE_ID_PREFIXES = {
|
|
96
|
+
customer: "cus_",
|
|
97
|
+
paymentIntent: "pi_",
|
|
98
|
+
paymentMethod: "pm_",
|
|
99
|
+
subscription: "sub_",
|
|
100
|
+
invoice: "in_",
|
|
101
|
+
invoiceItem: "ii_",
|
|
102
|
+
product: "prod_",
|
|
103
|
+
price: "price_",
|
|
104
|
+
coupon: "",
|
|
105
|
+
// coupons can have custom IDs
|
|
106
|
+
promotionCode: "promo_",
|
|
107
|
+
refund: "re_",
|
|
108
|
+
dispute: "dp_",
|
|
109
|
+
account: "acct_",
|
|
110
|
+
transfer: "tr_",
|
|
111
|
+
payout: "po_",
|
|
112
|
+
setupIntent: "seti_",
|
|
113
|
+
session: "cs_",
|
|
114
|
+
paymentLink: "plink_"
|
|
115
|
+
};
|
|
116
|
+
function validateStripeId(id, type) {
|
|
117
|
+
if (!id || typeof id !== "string") {
|
|
118
|
+
throw new Error(`${type} ID is required and must be a non-empty string`);
|
|
119
|
+
}
|
|
120
|
+
const prefix = STRIPE_ID_PREFIXES[type];
|
|
121
|
+
if (prefix && !id.startsWith(prefix)) {
|
|
122
|
+
throw new Error(`Invalid ${type} ID: expected prefix "${prefix}"`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function validateAmount(amount, label = "amount") {
|
|
126
|
+
if (typeof amount !== "number" || !Number.isFinite(amount)) {
|
|
127
|
+
throw new Error(`${label} must be a finite number`);
|
|
128
|
+
}
|
|
129
|
+
if (!Number.isInteger(amount)) {
|
|
130
|
+
throw new Error(`${label} must be an integer (amount in smallest currency unit)`);
|
|
131
|
+
}
|
|
132
|
+
if (amount < 0) {
|
|
133
|
+
throw new Error(`${label} must not be negative`);
|
|
134
|
+
}
|
|
135
|
+
if (amount > 99999999) {
|
|
136
|
+
throw new Error(`${label} exceeds maximum allowed value (99999999)`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function validateCurrency(currency) {
|
|
140
|
+
if (!currency || typeof currency !== "string") {
|
|
141
|
+
throw new Error("Currency is required");
|
|
142
|
+
}
|
|
143
|
+
const normalized = currency.trim().toLowerCase();
|
|
144
|
+
if (!/^[a-z]{3}$/.test(normalized)) {
|
|
145
|
+
throw new Error("Currency must be a valid 3-letter ISO 4217 code");
|
|
146
|
+
}
|
|
147
|
+
return normalized;
|
|
148
|
+
}
|
|
149
|
+
function validateUrl(url, label = "URL") {
|
|
150
|
+
if (!url || typeof url !== "string") {
|
|
151
|
+
throw new Error(`${label} is required`);
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const parsed = new URL(url);
|
|
155
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
156
|
+
throw new Error(`${label} must use http or https protocol`);
|
|
157
|
+
}
|
|
158
|
+
} catch (e) {
|
|
159
|
+
if (e instanceof Error && e.message.includes("protocol")) throw e;
|
|
160
|
+
throw new Error(`${label} must be a valid URL`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function validateMetadata(metadata) {
|
|
164
|
+
const keys = Object.keys(metadata);
|
|
165
|
+
if (keys.length > 50) {
|
|
166
|
+
throw new Error("Metadata cannot have more than 50 keys");
|
|
167
|
+
}
|
|
168
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
169
|
+
if (key.length > 40) {
|
|
170
|
+
throw new Error(`Metadata key "${key}" exceeds 40 characters`);
|
|
171
|
+
}
|
|
172
|
+
if (typeof value !== "string") {
|
|
173
|
+
throw new Error(`Metadata value for key "${key}" must be a string`);
|
|
174
|
+
}
|
|
175
|
+
if (value.length > 500) {
|
|
176
|
+
throw new Error(`Metadata value for key "${key}" exceeds 500 characters`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function sanitizeLimit(limit, defaultLimit = 10) {
|
|
181
|
+
if (limit === void 0) return defaultLimit;
|
|
182
|
+
return Math.min(Math.max(Math.floor(limit), 1), 100);
|
|
183
|
+
}
|
|
184
|
+
|
|
64
185
|
// src/server/payments/index.ts
|
|
65
|
-
async function createPaymentIntent(input) {
|
|
186
|
+
async function createPaymentIntent(input, options) {
|
|
66
187
|
try {
|
|
188
|
+
validateAmount(input.amount);
|
|
189
|
+
const currency = validateCurrency(input.currency);
|
|
190
|
+
if (input.customerId) validateStripeId(input.customerId, "customer");
|
|
191
|
+
if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
|
|
192
|
+
if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
|
|
193
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
67
194
|
const stripe = getStripe();
|
|
68
|
-
const paymentIntent = await stripe.paymentIntents.create(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
195
|
+
const paymentIntent = await stripe.paymentIntents.create(
|
|
196
|
+
{
|
|
197
|
+
amount: input.amount,
|
|
198
|
+
currency,
|
|
199
|
+
customer: input.customerId,
|
|
200
|
+
payment_method: input.paymentMethodId,
|
|
201
|
+
metadata: input.metadata,
|
|
202
|
+
description: input.description,
|
|
203
|
+
receipt_email: input.receiptEmail,
|
|
204
|
+
setup_future_usage: input.setupFutureUsage,
|
|
205
|
+
automatic_payment_methods: input.automaticPaymentMethods === false || input.paymentMethodId ? void 0 : { enabled: true },
|
|
206
|
+
return_url: input.returnUrl
|
|
207
|
+
},
|
|
208
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
209
|
+
);
|
|
80
210
|
return success(paymentIntent);
|
|
81
211
|
} catch (error) {
|
|
82
212
|
return handleStripeError(error);
|
|
@@ -84,6 +214,7 @@ async function createPaymentIntent(input) {
|
|
|
84
214
|
}
|
|
85
215
|
async function retrievePaymentIntent(paymentIntentId) {
|
|
86
216
|
try {
|
|
217
|
+
validateStripeId(paymentIntentId, "paymentIntent");
|
|
87
218
|
const stripe = getStripe();
|
|
88
219
|
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
|
|
89
220
|
return success(paymentIntent);
|
|
@@ -93,6 +224,9 @@ async function retrievePaymentIntent(paymentIntentId) {
|
|
|
93
224
|
}
|
|
94
225
|
async function confirmPaymentIntent(input) {
|
|
95
226
|
try {
|
|
227
|
+
validateStripeId(input.paymentIntentId, "paymentIntent");
|
|
228
|
+
if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
|
|
229
|
+
if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
|
|
96
230
|
const stripe = getStripe();
|
|
97
231
|
const paymentIntent = await stripe.paymentIntents.confirm(input.paymentIntentId, {
|
|
98
232
|
payment_method: input.paymentMethodId,
|
|
@@ -105,6 +239,7 @@ async function confirmPaymentIntent(input) {
|
|
|
105
239
|
}
|
|
106
240
|
async function cancelPaymentIntent(paymentIntentId) {
|
|
107
241
|
try {
|
|
242
|
+
validateStripeId(paymentIntentId, "paymentIntent");
|
|
108
243
|
const stripe = getStripe();
|
|
109
244
|
const paymentIntent = await stripe.paymentIntents.cancel(paymentIntentId);
|
|
110
245
|
return success(paymentIntent);
|
|
@@ -114,9 +249,10 @@ async function cancelPaymentIntent(paymentIntentId) {
|
|
|
114
249
|
}
|
|
115
250
|
async function listPaymentIntents(input) {
|
|
116
251
|
try {
|
|
252
|
+
if (input?.customerId) validateStripeId(input.customerId, "customer");
|
|
117
253
|
const stripe = getStripe();
|
|
118
254
|
const paymentIntents = await stripe.paymentIntents.list({
|
|
119
|
-
limit: input?.limit
|
|
255
|
+
limit: sanitizeLimit(input?.limit),
|
|
120
256
|
starting_after: input?.startingAfter,
|
|
121
257
|
ending_before: input?.endingBefore,
|
|
122
258
|
customer: input?.customerId
|
|
@@ -126,28 +262,35 @@ async function listPaymentIntents(input) {
|
|
|
126
262
|
return handleStripeError(error);
|
|
127
263
|
}
|
|
128
264
|
}
|
|
129
|
-
async function createCheckoutSession(input) {
|
|
265
|
+
async function createCheckoutSession(input, options) {
|
|
130
266
|
try {
|
|
267
|
+
validateUrl(input.successUrl, "successUrl");
|
|
268
|
+
validateUrl(input.cancelUrl, "cancelUrl");
|
|
269
|
+
if (input.customerId) validateStripeId(input.customerId, "customer");
|
|
270
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
131
271
|
const stripe = getStripe();
|
|
132
|
-
const session = await stripe.checkout.sessions.create(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
272
|
+
const session = await stripe.checkout.sessions.create(
|
|
273
|
+
{
|
|
274
|
+
mode: input.mode,
|
|
275
|
+
line_items: input.lineItems.map((item) => ({
|
|
276
|
+
price: item.priceId,
|
|
277
|
+
quantity: item.quantity
|
|
278
|
+
})),
|
|
279
|
+
success_url: input.successUrl,
|
|
280
|
+
cancel_url: input.cancelUrl,
|
|
281
|
+
customer: input.customerId,
|
|
282
|
+
customer_email: input.customerEmail,
|
|
283
|
+
metadata: input.metadata,
|
|
284
|
+
allow_promotion_codes: input.allowPromotionCodes,
|
|
285
|
+
shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0,
|
|
286
|
+
billing_address_collection: input.billingAddressCollection,
|
|
287
|
+
subscription_data: input.trialPeriodDays ? { trial_period_days: input.trialPeriodDays } : void 0,
|
|
288
|
+
tax_id_collection: input.taxIdCollection ? { enabled: true } : void 0,
|
|
289
|
+
automatic_tax: input.automaticTax ? { enabled: true } : void 0,
|
|
290
|
+
locale: input.locale
|
|
291
|
+
},
|
|
292
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
293
|
+
);
|
|
151
294
|
return success(session);
|
|
152
295
|
} catch (error) {
|
|
153
296
|
return handleStripeError(error);
|
|
@@ -155,6 +298,7 @@ async function createCheckoutSession(input) {
|
|
|
155
298
|
}
|
|
156
299
|
async function retrieveCheckoutSession(sessionId) {
|
|
157
300
|
try {
|
|
301
|
+
validateStripeId(sessionId, "session");
|
|
158
302
|
const stripe = getStripe();
|
|
159
303
|
const session = await stripe.checkout.sessions.retrieve(sessionId, {
|
|
160
304
|
expand: ["line_items", "payment_intent", "subscription"]
|
|
@@ -168,7 +312,7 @@ async function listCheckoutSessions(input) {
|
|
|
168
312
|
try {
|
|
169
313
|
const stripe = getStripe();
|
|
170
314
|
const sessions = await stripe.checkout.sessions.list({
|
|
171
|
-
limit: input?.limit
|
|
315
|
+
limit: sanitizeLimit(input?.limit),
|
|
172
316
|
starting_after: input?.startingAfter,
|
|
173
317
|
ending_before: input?.endingBefore
|
|
174
318
|
});
|
|
@@ -177,29 +321,36 @@ async function listCheckoutSessions(input) {
|
|
|
177
321
|
return handleStripeError(error);
|
|
178
322
|
}
|
|
179
323
|
}
|
|
180
|
-
async function createPaymentLink(input) {
|
|
324
|
+
async function createPaymentLink(input, options) {
|
|
181
325
|
try {
|
|
326
|
+
if (input.afterCompletion?.redirectUrl) {
|
|
327
|
+
validateUrl(input.afterCompletion.redirectUrl, "afterCompletion.redirectUrl");
|
|
328
|
+
}
|
|
329
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
182
330
|
const stripe = getStripe();
|
|
183
|
-
const paymentLink = await stripe.paymentLinks.create(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
331
|
+
const paymentLink = await stripe.paymentLinks.create(
|
|
332
|
+
{
|
|
333
|
+
line_items: input.lineItems.map((item) => ({
|
|
334
|
+
price: item.priceId,
|
|
335
|
+
quantity: item.quantity,
|
|
336
|
+
adjustable_quantity: item.adjustableQuantity ? {
|
|
337
|
+
enabled: item.adjustableQuantity.enabled,
|
|
338
|
+
minimum: item.adjustableQuantity.minimum,
|
|
339
|
+
maximum: item.adjustableQuantity.maximum
|
|
340
|
+
} : void 0
|
|
341
|
+
})),
|
|
342
|
+
metadata: input.metadata,
|
|
343
|
+
after_completion: input.afterCompletion ? {
|
|
344
|
+
type: input.afterCompletion.type,
|
|
345
|
+
redirect: input.afterCompletion.redirectUrl ? { url: input.afterCompletion.redirectUrl } : void 0
|
|
346
|
+
} : void 0,
|
|
347
|
+
allow_promotion_codes: input.allowPromotionCodes,
|
|
348
|
+
automatic_tax: input.automaticTax ? { enabled: true } : void 0,
|
|
349
|
+
billing_address_collection: input.billingAddressCollection,
|
|
350
|
+
shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0
|
|
351
|
+
},
|
|
352
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
353
|
+
);
|
|
203
354
|
return success(paymentLink);
|
|
204
355
|
} catch (error) {
|
|
205
356
|
return handleStripeError(error);
|
|
@@ -207,6 +358,7 @@ async function createPaymentLink(input) {
|
|
|
207
358
|
}
|
|
208
359
|
async function retrievePaymentLink(paymentLinkId) {
|
|
209
360
|
try {
|
|
361
|
+
validateStripeId(paymentLinkId, "paymentLink");
|
|
210
362
|
const stripe = getStripe();
|
|
211
363
|
const paymentLink = await stripe.paymentLinks.retrieve(paymentLinkId);
|
|
212
364
|
return success(paymentLink);
|
|
@@ -214,15 +366,20 @@ async function retrievePaymentLink(paymentLinkId) {
|
|
|
214
366
|
return handleStripeError(error);
|
|
215
367
|
}
|
|
216
368
|
}
|
|
217
|
-
async function createSetupIntent(input) {
|
|
369
|
+
async function createSetupIntent(input, options) {
|
|
218
370
|
try {
|
|
371
|
+
if (input.customerId) validateStripeId(input.customerId, "customer");
|
|
372
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
219
373
|
const stripe = getStripe();
|
|
220
|
-
const setupIntent = await stripe.setupIntents.create(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
374
|
+
const setupIntent = await stripe.setupIntents.create(
|
|
375
|
+
{
|
|
376
|
+
customer: input.customerId,
|
|
377
|
+
payment_method_types: input.paymentMethodTypes,
|
|
378
|
+
usage: input.usage,
|
|
379
|
+
metadata: input.metadata
|
|
380
|
+
},
|
|
381
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
382
|
+
);
|
|
226
383
|
return success(setupIntent);
|
|
227
384
|
} catch (error) {
|
|
228
385
|
return handleStripeError(error);
|
|
@@ -230,6 +387,7 @@ async function createSetupIntent(input) {
|
|
|
230
387
|
}
|
|
231
388
|
async function retrieveSetupIntent(setupIntentId) {
|
|
232
389
|
try {
|
|
390
|
+
validateStripeId(setupIntentId, "setupIntent");
|
|
233
391
|
const stripe = getStripe();
|
|
234
392
|
const setupIntent = await stripe.setupIntents.retrieve(setupIntentId);
|
|
235
393
|
return success(setupIntent);
|
|
@@ -239,6 +397,7 @@ async function retrieveSetupIntent(setupIntentId) {
|
|
|
239
397
|
}
|
|
240
398
|
async function listPaymentMethods(customerId, type) {
|
|
241
399
|
try {
|
|
400
|
+
validateStripeId(customerId, "customer");
|
|
242
401
|
const stripe = getStripe();
|
|
243
402
|
const paymentMethods = await stripe.paymentMethods.list({
|
|
244
403
|
customer: customerId,
|
|
@@ -251,6 +410,8 @@ async function listPaymentMethods(customerId, type) {
|
|
|
251
410
|
}
|
|
252
411
|
async function attachPaymentMethod(paymentMethodId, customerId) {
|
|
253
412
|
try {
|
|
413
|
+
validateStripeId(paymentMethodId, "paymentMethod");
|
|
414
|
+
validateStripeId(customerId, "customer");
|
|
254
415
|
const stripe = getStripe();
|
|
255
416
|
const paymentMethod = await stripe.paymentMethods.attach(paymentMethodId, {
|
|
256
417
|
customer: customerId
|
|
@@ -262,6 +423,7 @@ async function attachPaymentMethod(paymentMethodId, customerId) {
|
|
|
262
423
|
}
|
|
263
424
|
async function detachPaymentMethod(paymentMethodId) {
|
|
264
425
|
try {
|
|
426
|
+
validateStripeId(paymentMethodId, "paymentMethod");
|
|
265
427
|
const stripe = getStripe();
|
|
266
428
|
const paymentMethod = await stripe.paymentMethods.detach(paymentMethodId);
|
|
267
429
|
return success(paymentMethod);
|
|
@@ -271,26 +433,31 @@ async function detachPaymentMethod(paymentMethodId) {
|
|
|
271
433
|
}
|
|
272
434
|
|
|
273
435
|
// src/server/customers/index.ts
|
|
274
|
-
async function createCustomer(input) {
|
|
436
|
+
async function createCustomer(input, options) {
|
|
275
437
|
try {
|
|
438
|
+
if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
|
|
439
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
276
440
|
const stripe = getStripe();
|
|
277
|
-
const customer = await stripe.customers.create(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
441
|
+
const customer = await stripe.customers.create(
|
|
442
|
+
{
|
|
443
|
+
email: input.email,
|
|
444
|
+
name: input.name,
|
|
445
|
+
phone: input.phone,
|
|
446
|
+
description: input.description,
|
|
447
|
+
metadata: input.metadata,
|
|
448
|
+
payment_method: input.paymentMethodId,
|
|
449
|
+
invoice_settings: input.paymentMethodId ? { default_payment_method: input.paymentMethodId } : void 0,
|
|
450
|
+
address: input.address ? {
|
|
451
|
+
line1: input.address.line1,
|
|
452
|
+
line2: input.address.line2,
|
|
453
|
+
city: input.address.city,
|
|
454
|
+
state: input.address.state,
|
|
455
|
+
postal_code: input.address.postalCode,
|
|
456
|
+
country: input.address.country
|
|
457
|
+
} : void 0
|
|
458
|
+
},
|
|
459
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
460
|
+
);
|
|
294
461
|
return success(customer);
|
|
295
462
|
} catch (error) {
|
|
296
463
|
return handleStripeError(error);
|
|
@@ -298,6 +465,7 @@ async function createCustomer(input) {
|
|
|
298
465
|
}
|
|
299
466
|
async function retrieveCustomer(customerId) {
|
|
300
467
|
try {
|
|
468
|
+
validateStripeId(customerId, "customer");
|
|
301
469
|
const stripe = getStripe();
|
|
302
470
|
const customer = await stripe.customers.retrieve(customerId, {
|
|
303
471
|
expand: ["subscriptions", "sources"]
|
|
@@ -315,6 +483,9 @@ async function retrieveCustomer(customerId) {
|
|
|
315
483
|
}
|
|
316
484
|
async function updateCustomer(input) {
|
|
317
485
|
try {
|
|
486
|
+
validateStripeId(input.customerId, "customer");
|
|
487
|
+
if (input.defaultPaymentMethodId) validateStripeId(input.defaultPaymentMethodId, "paymentMethod");
|
|
488
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
318
489
|
const stripe = getStripe();
|
|
319
490
|
const customer = await stripe.customers.update(input.customerId, {
|
|
320
491
|
email: input.email,
|
|
@@ -339,6 +510,7 @@ async function updateCustomer(input) {
|
|
|
339
510
|
}
|
|
340
511
|
async function deleteCustomer(customerId) {
|
|
341
512
|
try {
|
|
513
|
+
validateStripeId(customerId, "customer");
|
|
342
514
|
const stripe = getStripe();
|
|
343
515
|
const deleted = await stripe.customers.del(customerId);
|
|
344
516
|
return success(deleted);
|
|
@@ -350,7 +522,7 @@ async function listCustomers(input) {
|
|
|
350
522
|
try {
|
|
351
523
|
const stripe = getStripe();
|
|
352
524
|
const customers = await stripe.customers.list({
|
|
353
|
-
limit: input?.limit
|
|
525
|
+
limit: sanitizeLimit(input?.limit),
|
|
354
526
|
starting_after: input?.startingAfter,
|
|
355
527
|
ending_before: input?.endingBefore,
|
|
356
528
|
email: input?.email
|
|
@@ -360,26 +532,42 @@ async function listCustomers(input) {
|
|
|
360
532
|
return handleStripeError(error);
|
|
361
533
|
}
|
|
362
534
|
}
|
|
363
|
-
async function searchCustomers(
|
|
535
|
+
async function searchCustomers(input) {
|
|
364
536
|
try {
|
|
537
|
+
const clauses = [];
|
|
538
|
+
if (input.email) clauses.push(`email:"${input.email.replace(/"/g, "")}"`);
|
|
539
|
+
if (input.name) clauses.push(`name:"${input.name.replace(/"/g, "")}"`);
|
|
540
|
+
if (input.phone) clauses.push(`phone:"${input.phone.replace(/"/g, "")}"`);
|
|
541
|
+
if (clauses.length === 0) {
|
|
542
|
+
return {
|
|
543
|
+
data: null,
|
|
544
|
+
error: { message: "At least one search field (email, name, phone) is required", type: "invalid_request_error" }
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const query = clauses.join(" AND ");
|
|
365
548
|
const stripe = getStripe();
|
|
366
549
|
const customers = await stripe.customers.search({
|
|
367
550
|
query,
|
|
368
|
-
limit: limit
|
|
551
|
+
limit: sanitizeLimit(input.limit)
|
|
369
552
|
});
|
|
370
553
|
return success(customers);
|
|
371
554
|
} catch (error) {
|
|
372
555
|
return handleStripeError(error);
|
|
373
556
|
}
|
|
374
557
|
}
|
|
375
|
-
async function createPortalSession(input) {
|
|
558
|
+
async function createPortalSession(input, options) {
|
|
376
559
|
try {
|
|
560
|
+
validateStripeId(input.customerId, "customer");
|
|
561
|
+
if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
|
|
377
562
|
const stripe = getStripe();
|
|
378
|
-
const session = await stripe.billingPortal.sessions.create(
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
563
|
+
const session = await stripe.billingPortal.sessions.create(
|
|
564
|
+
{
|
|
565
|
+
customer: input.customerId,
|
|
566
|
+
return_url: input.returnUrl,
|
|
567
|
+
configuration: input.configuration
|
|
568
|
+
},
|
|
569
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
570
|
+
);
|
|
383
571
|
return success(session);
|
|
384
572
|
} catch (error) {
|
|
385
573
|
return handleStripeError(error);
|
|
@@ -387,23 +575,28 @@ async function createPortalSession(input) {
|
|
|
387
575
|
}
|
|
388
576
|
|
|
389
577
|
// src/server/subscriptions/index.ts
|
|
390
|
-
async function createSubscription(input) {
|
|
578
|
+
async function createSubscription(input, options) {
|
|
391
579
|
try {
|
|
580
|
+
validateStripeId(input.customerId, "customer");
|
|
581
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
392
582
|
const stripe = getStripe();
|
|
393
583
|
const items = input.items ? input.items.map((item) => ({ price: item.priceId, quantity: item.quantity })) : [{ price: input.priceId, quantity: input.quantity ?? 1 }];
|
|
394
|
-
const subscription = await stripe.subscriptions.create(
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
584
|
+
const subscription = await stripe.subscriptions.create(
|
|
585
|
+
{
|
|
586
|
+
customer: input.customerId,
|
|
587
|
+
items,
|
|
588
|
+
metadata: input.metadata,
|
|
589
|
+
trial_period_days: input.trialPeriodDays,
|
|
590
|
+
coupon: input.couponId,
|
|
591
|
+
promotion_code: input.promotionCodeId,
|
|
592
|
+
payment_behavior: input.paymentBehavior ?? "default_incomplete",
|
|
593
|
+
cancel_at_period_end: input.cancelAtPeriodEnd,
|
|
594
|
+
billing_cycle_anchor: input.billingCycleAnchor,
|
|
595
|
+
proration_behavior: input.prorationBehavior,
|
|
596
|
+
expand: ["latest_invoice.payment_intent"]
|
|
597
|
+
},
|
|
598
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
599
|
+
);
|
|
407
600
|
return success(subscription);
|
|
408
601
|
} catch (error) {
|
|
409
602
|
return handleStripeError(error);
|
|
@@ -411,6 +604,7 @@ async function createSubscription(input) {
|
|
|
411
604
|
}
|
|
412
605
|
async function retrieveSubscription(subscriptionId) {
|
|
413
606
|
try {
|
|
607
|
+
validateStripeId(subscriptionId, "subscription");
|
|
414
608
|
const stripe = getStripe();
|
|
415
609
|
const subscription = await stripe.subscriptions.retrieve(subscriptionId, {
|
|
416
610
|
expand: ["latest_invoice.payment_intent", "default_payment_method"]
|
|
@@ -422,6 +616,8 @@ async function retrieveSubscription(subscriptionId) {
|
|
|
422
616
|
}
|
|
423
617
|
async function updateSubscription(input) {
|
|
424
618
|
try {
|
|
619
|
+
validateStripeId(input.subscriptionId, "subscription");
|
|
620
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
425
621
|
const stripe = getStripe();
|
|
426
622
|
const params = {
|
|
427
623
|
metadata: input.metadata,
|
|
@@ -444,6 +640,7 @@ async function updateSubscription(input) {
|
|
|
444
640
|
}
|
|
445
641
|
async function cancelSubscription(input) {
|
|
446
642
|
try {
|
|
643
|
+
validateStripeId(input.subscriptionId, "subscription");
|
|
447
644
|
const stripe = getStripe();
|
|
448
645
|
if (input.cancelAtPeriodEnd) {
|
|
449
646
|
const subscription2 = await stripe.subscriptions.update(input.subscriptionId, {
|
|
@@ -468,6 +665,7 @@ async function cancelSubscription(input) {
|
|
|
468
665
|
}
|
|
469
666
|
async function resumeSubscription(subscriptionId) {
|
|
470
667
|
try {
|
|
668
|
+
validateStripeId(subscriptionId, "subscription");
|
|
471
669
|
const stripe = getStripe();
|
|
472
670
|
const subscription = await stripe.subscriptions.update(subscriptionId, {
|
|
473
671
|
cancel_at_period_end: false
|
|
@@ -479,9 +677,10 @@ async function resumeSubscription(subscriptionId) {
|
|
|
479
677
|
}
|
|
480
678
|
async function listSubscriptions(input) {
|
|
481
679
|
try {
|
|
680
|
+
if (input?.customerId) validateStripeId(input.customerId, "customer");
|
|
482
681
|
const stripe = getStripe();
|
|
483
682
|
const subscriptions = await stripe.subscriptions.list({
|
|
484
|
-
limit: input?.limit
|
|
683
|
+
limit: sanitizeLimit(input?.limit),
|
|
485
684
|
starting_after: input?.startingAfter,
|
|
486
685
|
ending_before: input?.endingBefore,
|
|
487
686
|
customer: input?.customerId,
|
|
@@ -494,24 +693,32 @@ async function listSubscriptions(input) {
|
|
|
494
693
|
}
|
|
495
694
|
|
|
496
695
|
// src/server/products/index.ts
|
|
497
|
-
async function createProduct(input) {
|
|
696
|
+
async function createProduct(input, options) {
|
|
498
697
|
try {
|
|
698
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
699
|
+
if (input.defaultPriceData) {
|
|
700
|
+
validateAmount(input.defaultPriceData.unitAmount, "unitAmount");
|
|
701
|
+
validateCurrency(input.defaultPriceData.currency);
|
|
702
|
+
}
|
|
499
703
|
const stripe = getStripe();
|
|
500
|
-
const product = await stripe.products.create(
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
704
|
+
const product = await stripe.products.create(
|
|
705
|
+
{
|
|
706
|
+
name: input.name,
|
|
707
|
+
description: input.description,
|
|
708
|
+
images: input.images,
|
|
709
|
+
metadata: input.metadata,
|
|
710
|
+
active: input.active,
|
|
711
|
+
default_price_data: input.defaultPriceData ? {
|
|
712
|
+
unit_amount: input.defaultPriceData.unitAmount,
|
|
713
|
+
currency: input.defaultPriceData.currency,
|
|
714
|
+
recurring: input.defaultPriceData.recurring ? {
|
|
715
|
+
interval: input.defaultPriceData.recurring.interval,
|
|
716
|
+
interval_count: input.defaultPriceData.recurring.intervalCount
|
|
717
|
+
} : void 0
|
|
512
718
|
} : void 0
|
|
513
|
-
}
|
|
514
|
-
|
|
719
|
+
},
|
|
720
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
721
|
+
);
|
|
515
722
|
return success(product);
|
|
516
723
|
} catch (error) {
|
|
517
724
|
return handleStripeError(error);
|
|
@@ -519,6 +726,7 @@ async function createProduct(input) {
|
|
|
519
726
|
}
|
|
520
727
|
async function retrieveProduct(productId) {
|
|
521
728
|
try {
|
|
729
|
+
validateStripeId(productId, "product");
|
|
522
730
|
const stripe = getStripe();
|
|
523
731
|
const product = await stripe.products.retrieve(productId);
|
|
524
732
|
return success(product);
|
|
@@ -528,6 +736,8 @@ async function retrieveProduct(productId) {
|
|
|
528
736
|
}
|
|
529
737
|
async function updateProduct(input) {
|
|
530
738
|
try {
|
|
739
|
+
validateStripeId(input.productId, "product");
|
|
740
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
531
741
|
const stripe = getStripe();
|
|
532
742
|
const product = await stripe.products.update(input.productId, {
|
|
533
743
|
name: input.name,
|
|
@@ -543,6 +753,7 @@ async function updateProduct(input) {
|
|
|
543
753
|
}
|
|
544
754
|
async function archiveProduct(productId) {
|
|
545
755
|
try {
|
|
756
|
+
validateStripeId(productId, "product");
|
|
546
757
|
const stripe = getStripe();
|
|
547
758
|
const product = await stripe.products.update(productId, { active: false });
|
|
548
759
|
return success(product);
|
|
@@ -554,7 +765,7 @@ async function listProducts(input) {
|
|
|
554
765
|
try {
|
|
555
766
|
const stripe = getStripe();
|
|
556
767
|
const products = await stripe.products.list({
|
|
557
|
-
limit: input?.limit
|
|
768
|
+
limit: sanitizeLimit(input?.limit),
|
|
558
769
|
starting_after: input?.startingAfter,
|
|
559
770
|
ending_before: input?.endingBefore,
|
|
560
771
|
active: input?.active
|
|
@@ -564,8 +775,12 @@ async function listProducts(input) {
|
|
|
564
775
|
return handleStripeError(error);
|
|
565
776
|
}
|
|
566
777
|
}
|
|
567
|
-
async function createPrice(input) {
|
|
778
|
+
async function createPrice(input, options) {
|
|
568
779
|
try {
|
|
780
|
+
validateStripeId(input.productId, "product");
|
|
781
|
+
validateCurrency(input.currency);
|
|
782
|
+
if (input.unitAmount !== void 0) validateAmount(input.unitAmount, "unitAmount");
|
|
783
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
569
784
|
const stripe = getStripe();
|
|
570
785
|
const params = {
|
|
571
786
|
product: input.productId,
|
|
@@ -593,7 +808,10 @@ async function createPrice(input) {
|
|
|
593
808
|
} else {
|
|
594
809
|
params.unit_amount = input.unitAmount;
|
|
595
810
|
}
|
|
596
|
-
const price = await stripe.prices.create(
|
|
811
|
+
const price = await stripe.prices.create(
|
|
812
|
+
params,
|
|
813
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
814
|
+
);
|
|
597
815
|
return success(price);
|
|
598
816
|
} catch (error) {
|
|
599
817
|
return handleStripeError(error);
|
|
@@ -601,6 +819,7 @@ async function createPrice(input) {
|
|
|
601
819
|
}
|
|
602
820
|
async function retrievePrice(priceId) {
|
|
603
821
|
try {
|
|
822
|
+
validateStripeId(priceId, "price");
|
|
604
823
|
const stripe = getStripe();
|
|
605
824
|
const price = await stripe.prices.retrieve(priceId);
|
|
606
825
|
return success(price);
|
|
@@ -610,9 +829,10 @@ async function retrievePrice(priceId) {
|
|
|
610
829
|
}
|
|
611
830
|
async function listPrices(input) {
|
|
612
831
|
try {
|
|
832
|
+
if (input?.productId) validateStripeId(input.productId, "product");
|
|
613
833
|
const stripe = getStripe();
|
|
614
834
|
const prices = await stripe.prices.list({
|
|
615
|
-
limit: input?.limit
|
|
835
|
+
limit: sanitizeLimit(input?.limit),
|
|
616
836
|
starting_after: input?.startingAfter,
|
|
617
837
|
ending_before: input?.endingBefore,
|
|
618
838
|
product: input?.productId,
|
|
@@ -626,6 +846,7 @@ async function listPrices(input) {
|
|
|
626
846
|
}
|
|
627
847
|
async function archivePrice(priceId) {
|
|
628
848
|
try {
|
|
849
|
+
validateStripeId(priceId, "price");
|
|
629
850
|
const stripe = getStripe();
|
|
630
851
|
const price = await stripe.prices.update(priceId, { active: false });
|
|
631
852
|
return success(price);
|
|
@@ -635,17 +856,22 @@ async function archivePrice(priceId) {
|
|
|
635
856
|
}
|
|
636
857
|
|
|
637
858
|
// src/server/invoices/index.ts
|
|
638
|
-
async function createInvoice(input) {
|
|
859
|
+
async function createInvoice(input, options) {
|
|
639
860
|
try {
|
|
861
|
+
validateStripeId(input.customerId, "customer");
|
|
862
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
640
863
|
const stripe = getStripe();
|
|
641
|
-
const invoice = await stripe.invoices.create(
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
864
|
+
const invoice = await stripe.invoices.create(
|
|
865
|
+
{
|
|
866
|
+
customer: input.customerId,
|
|
867
|
+
collection_method: input.collectionMethod ?? "charge_automatically",
|
|
868
|
+
days_until_due: input.daysUntilDue,
|
|
869
|
+
metadata: input.metadata,
|
|
870
|
+
description: input.description,
|
|
871
|
+
auto_advance: input.autoAdvance
|
|
872
|
+
},
|
|
873
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
874
|
+
);
|
|
649
875
|
return success(invoice);
|
|
650
876
|
} catch (error) {
|
|
651
877
|
return handleStripeError(error);
|
|
@@ -653,6 +879,7 @@ async function createInvoice(input) {
|
|
|
653
879
|
}
|
|
654
880
|
async function retrieveInvoice(invoiceId) {
|
|
655
881
|
try {
|
|
882
|
+
validateStripeId(invoiceId, "invoice");
|
|
656
883
|
const stripe = getStripe();
|
|
657
884
|
const invoice = await stripe.invoices.retrieve(invoiceId);
|
|
658
885
|
return success(invoice);
|
|
@@ -662,6 +889,7 @@ async function retrieveInvoice(invoiceId) {
|
|
|
662
889
|
}
|
|
663
890
|
async function finalizeInvoice(invoiceId) {
|
|
664
891
|
try {
|
|
892
|
+
validateStripeId(invoiceId, "invoice");
|
|
665
893
|
const stripe = getStripe();
|
|
666
894
|
const invoice = await stripe.invoices.finalizeInvoice(invoiceId);
|
|
667
895
|
return success(invoice);
|
|
@@ -671,6 +899,7 @@ async function finalizeInvoice(invoiceId) {
|
|
|
671
899
|
}
|
|
672
900
|
async function sendInvoice(invoiceId) {
|
|
673
901
|
try {
|
|
902
|
+
validateStripeId(invoiceId, "invoice");
|
|
674
903
|
const stripe = getStripe();
|
|
675
904
|
const invoice = await stripe.invoices.sendInvoice(invoiceId);
|
|
676
905
|
return success(invoice);
|
|
@@ -680,6 +909,7 @@ async function sendInvoice(invoiceId) {
|
|
|
680
909
|
}
|
|
681
910
|
async function payInvoice(invoiceId) {
|
|
682
911
|
try {
|
|
912
|
+
validateStripeId(invoiceId, "invoice");
|
|
683
913
|
const stripe = getStripe();
|
|
684
914
|
const invoice = await stripe.invoices.pay(invoiceId);
|
|
685
915
|
return success(invoice);
|
|
@@ -689,6 +919,7 @@ async function payInvoice(invoiceId) {
|
|
|
689
919
|
}
|
|
690
920
|
async function voidInvoice(invoiceId) {
|
|
691
921
|
try {
|
|
922
|
+
validateStripeId(invoiceId, "invoice");
|
|
692
923
|
const stripe = getStripe();
|
|
693
924
|
const invoice = await stripe.invoices.voidInvoice(invoiceId);
|
|
694
925
|
return success(invoice);
|
|
@@ -698,9 +929,10 @@ async function voidInvoice(invoiceId) {
|
|
|
698
929
|
}
|
|
699
930
|
async function listInvoices(input) {
|
|
700
931
|
try {
|
|
932
|
+
if (input?.customerId) validateStripeId(input.customerId, "customer");
|
|
701
933
|
const stripe = getStripe();
|
|
702
934
|
const invoices = await stripe.invoices.list({
|
|
703
|
-
limit: input?.limit
|
|
935
|
+
limit: sanitizeLimit(input?.limit),
|
|
704
936
|
starting_after: input?.startingAfter,
|
|
705
937
|
ending_before: input?.endingBefore,
|
|
706
938
|
customer: input?.customerId,
|
|
@@ -713,6 +945,8 @@ async function listInvoices(input) {
|
|
|
713
945
|
}
|
|
714
946
|
async function getUpcomingInvoice(customerId, subscriptionId) {
|
|
715
947
|
try {
|
|
948
|
+
validateStripeId(customerId, "customer");
|
|
949
|
+
if (subscriptionId) validateStripeId(subscriptionId, "subscription");
|
|
716
950
|
const stripe = getStripe();
|
|
717
951
|
const invoice = await stripe.invoices.retrieveUpcoming({
|
|
718
952
|
customer: customerId,
|
|
@@ -723,19 +957,28 @@ async function getUpcomingInvoice(customerId, subscriptionId) {
|
|
|
723
957
|
return handleStripeError(error);
|
|
724
958
|
}
|
|
725
959
|
}
|
|
726
|
-
async function createInvoiceItem(input) {
|
|
960
|
+
async function createInvoiceItem(input, options) {
|
|
727
961
|
try {
|
|
962
|
+
validateStripeId(input.customerId, "customer");
|
|
963
|
+
if (input.invoiceId) validateStripeId(input.invoiceId, "invoice");
|
|
964
|
+
if (input.priceId) validateStripeId(input.priceId, "price");
|
|
965
|
+
if (input.amount !== void 0) validateAmount(input.amount, "invoice item amount");
|
|
966
|
+
if (input.currency) validateCurrency(input.currency);
|
|
967
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
728
968
|
const stripe = getStripe();
|
|
729
|
-
const invoiceItem = await stripe.invoiceItems.create(
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
969
|
+
const invoiceItem = await stripe.invoiceItems.create(
|
|
970
|
+
{
|
|
971
|
+
customer: input.customerId,
|
|
972
|
+
invoice: input.invoiceId,
|
|
973
|
+
price: input.priceId,
|
|
974
|
+
amount: input.amount,
|
|
975
|
+
currency: input.currency,
|
|
976
|
+
description: input.description,
|
|
977
|
+
quantity: input.quantity,
|
|
978
|
+
metadata: input.metadata
|
|
979
|
+
},
|
|
980
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
981
|
+
);
|
|
739
982
|
return success(invoiceItem);
|
|
740
983
|
} catch (error) {
|
|
741
984
|
return handleStripeError(error);
|
|
@@ -743,16 +986,22 @@ async function createInvoiceItem(input) {
|
|
|
743
986
|
}
|
|
744
987
|
|
|
745
988
|
// src/server/refunds/index.ts
|
|
746
|
-
async function createRefund(input) {
|
|
989
|
+
async function createRefund(input, options) {
|
|
747
990
|
try {
|
|
991
|
+
if (input.paymentIntentId) validateStripeId(input.paymentIntentId, "paymentIntent");
|
|
992
|
+
if (input.amount !== void 0) validateAmount(input.amount, "refund amount");
|
|
993
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
748
994
|
const stripe = getStripe();
|
|
749
|
-
const refund = await stripe.refunds.create(
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
995
|
+
const refund = await stripe.refunds.create(
|
|
996
|
+
{
|
|
997
|
+
payment_intent: input.paymentIntentId,
|
|
998
|
+
charge: input.chargeId,
|
|
999
|
+
amount: input.amount,
|
|
1000
|
+
reason: input.reason,
|
|
1001
|
+
metadata: input.metadata
|
|
1002
|
+
},
|
|
1003
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
1004
|
+
);
|
|
756
1005
|
return success(refund);
|
|
757
1006
|
} catch (error) {
|
|
758
1007
|
return handleStripeError(error);
|
|
@@ -760,6 +1009,7 @@ async function createRefund(input) {
|
|
|
760
1009
|
}
|
|
761
1010
|
async function retrieveRefund(refundId) {
|
|
762
1011
|
try {
|
|
1012
|
+
validateStripeId(refundId, "refund");
|
|
763
1013
|
const stripe = getStripe();
|
|
764
1014
|
const refund = await stripe.refunds.retrieve(refundId);
|
|
765
1015
|
return success(refund);
|
|
@@ -769,9 +1019,10 @@ async function retrieveRefund(refundId) {
|
|
|
769
1019
|
}
|
|
770
1020
|
async function listRefunds(input) {
|
|
771
1021
|
try {
|
|
1022
|
+
if (input?.paymentIntentId) validateStripeId(input.paymentIntentId, "paymentIntent");
|
|
772
1023
|
const stripe = getStripe();
|
|
773
1024
|
const refunds = await stripe.refunds.list({
|
|
774
|
-
limit: input?.limit
|
|
1025
|
+
limit: sanitizeLimit(input?.limit),
|
|
775
1026
|
starting_after: input?.startingAfter,
|
|
776
1027
|
ending_before: input?.endingBefore,
|
|
777
1028
|
payment_intent: input?.paymentIntentId,
|
|
@@ -784,6 +1035,7 @@ async function listRefunds(input) {
|
|
|
784
1035
|
}
|
|
785
1036
|
async function retrieveDispute(disputeId) {
|
|
786
1037
|
try {
|
|
1038
|
+
validateStripeId(disputeId, "dispute");
|
|
787
1039
|
const stripe = getStripe();
|
|
788
1040
|
const dispute = await stripe.disputes.retrieve(disputeId);
|
|
789
1041
|
return success(dispute);
|
|
@@ -793,6 +1045,8 @@ async function retrieveDispute(disputeId) {
|
|
|
793
1045
|
}
|
|
794
1046
|
async function updateDispute(input) {
|
|
795
1047
|
try {
|
|
1048
|
+
validateStripeId(input.disputeId, "dispute");
|
|
1049
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
796
1050
|
const stripe = getStripe();
|
|
797
1051
|
const dispute = await stripe.disputes.update(input.disputeId, {
|
|
798
1052
|
evidence: input.evidence ? {
|
|
@@ -814,6 +1068,7 @@ async function updateDispute(input) {
|
|
|
814
1068
|
}
|
|
815
1069
|
async function closeDispute(disputeId) {
|
|
816
1070
|
try {
|
|
1071
|
+
validateStripeId(disputeId, "dispute");
|
|
817
1072
|
const stripe = getStripe();
|
|
818
1073
|
const dispute = await stripe.disputes.close(disputeId);
|
|
819
1074
|
return success(dispute);
|
|
@@ -825,7 +1080,7 @@ async function listDisputes(input) {
|
|
|
825
1080
|
try {
|
|
826
1081
|
const stripe = getStripe();
|
|
827
1082
|
const disputes = await stripe.disputes.list({
|
|
828
|
-
limit: input?.limit
|
|
1083
|
+
limit: sanitizeLimit(input?.limit),
|
|
829
1084
|
starting_after: input?.startingAfter,
|
|
830
1085
|
ending_before: input?.endingBefore
|
|
831
1086
|
});
|
|
@@ -836,17 +1091,21 @@ async function listDisputes(input) {
|
|
|
836
1091
|
}
|
|
837
1092
|
|
|
838
1093
|
// src/server/connect/index.ts
|
|
839
|
-
async function createConnectAccount(input) {
|
|
1094
|
+
async function createConnectAccount(input, options) {
|
|
840
1095
|
try {
|
|
1096
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
841
1097
|
const stripe = getStripe();
|
|
842
|
-
const account = await stripe.accounts.create(
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1098
|
+
const account = await stripe.accounts.create(
|
|
1099
|
+
{
|
|
1100
|
+
type: input.type,
|
|
1101
|
+
country: input.country,
|
|
1102
|
+
email: input.email,
|
|
1103
|
+
capabilities: input.capabilities,
|
|
1104
|
+
business_type: input.businessType,
|
|
1105
|
+
metadata: input.metadata
|
|
1106
|
+
},
|
|
1107
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
1108
|
+
);
|
|
850
1109
|
return success(account);
|
|
851
1110
|
} catch (error) {
|
|
852
1111
|
return handleStripeError(error);
|
|
@@ -854,6 +1113,7 @@ async function createConnectAccount(input) {
|
|
|
854
1113
|
}
|
|
855
1114
|
async function retrieveConnectAccount(accountId) {
|
|
856
1115
|
try {
|
|
1116
|
+
validateStripeId(accountId, "account");
|
|
857
1117
|
const stripe = getStripe();
|
|
858
1118
|
const account = await stripe.accounts.retrieve(accountId);
|
|
859
1119
|
return success(account);
|
|
@@ -863,6 +1123,7 @@ async function retrieveConnectAccount(accountId) {
|
|
|
863
1123
|
}
|
|
864
1124
|
async function deleteConnectAccount(accountId) {
|
|
865
1125
|
try {
|
|
1126
|
+
validateStripeId(accountId, "account");
|
|
866
1127
|
const stripe = getStripe();
|
|
867
1128
|
const deleted = await stripe.accounts.del(accountId);
|
|
868
1129
|
return success(deleted);
|
|
@@ -874,7 +1135,7 @@ async function listConnectAccounts(input) {
|
|
|
874
1135
|
try {
|
|
875
1136
|
const stripe = getStripe();
|
|
876
1137
|
const accounts = await stripe.accounts.list({
|
|
877
|
-
limit: input?.limit
|
|
1138
|
+
limit: sanitizeLimit(input?.limit),
|
|
878
1139
|
starting_after: input?.startingAfter,
|
|
879
1140
|
ending_before: input?.endingBefore
|
|
880
1141
|
});
|
|
@@ -885,6 +1146,9 @@ async function listConnectAccounts(input) {
|
|
|
885
1146
|
}
|
|
886
1147
|
async function createAccountLink(input) {
|
|
887
1148
|
try {
|
|
1149
|
+
validateStripeId(input.accountId, "account");
|
|
1150
|
+
validateUrl(input.refreshUrl, "refreshUrl");
|
|
1151
|
+
validateUrl(input.returnUrl, "returnUrl");
|
|
888
1152
|
const stripe = getStripe();
|
|
889
1153
|
const accountLink = await stripe.accountLinks.create({
|
|
890
1154
|
account: input.accountId,
|
|
@@ -897,17 +1161,24 @@ async function createAccountLink(input) {
|
|
|
897
1161
|
return handleStripeError(error);
|
|
898
1162
|
}
|
|
899
1163
|
}
|
|
900
|
-
async function createTransfer(input) {
|
|
1164
|
+
async function createTransfer(input, options) {
|
|
901
1165
|
try {
|
|
1166
|
+
validateAmount(input.amount, "transfer amount");
|
|
1167
|
+
validateCurrency(input.currency);
|
|
1168
|
+
validateStripeId(input.destinationAccountId, "account");
|
|
1169
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
902
1170
|
const stripe = getStripe();
|
|
903
|
-
const transfer = await stripe.transfers.create(
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1171
|
+
const transfer = await stripe.transfers.create(
|
|
1172
|
+
{
|
|
1173
|
+
amount: input.amount,
|
|
1174
|
+
currency: input.currency,
|
|
1175
|
+
destination: input.destinationAccountId,
|
|
1176
|
+
description: input.description,
|
|
1177
|
+
metadata: input.metadata,
|
|
1178
|
+
source_transaction: input.sourceTransaction
|
|
1179
|
+
},
|
|
1180
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
1181
|
+
);
|
|
911
1182
|
return success(transfer);
|
|
912
1183
|
} catch (error) {
|
|
913
1184
|
return handleStripeError(error);
|
|
@@ -915,9 +1186,10 @@ async function createTransfer(input) {
|
|
|
915
1186
|
}
|
|
916
1187
|
async function listTransfers(input) {
|
|
917
1188
|
try {
|
|
1189
|
+
if (input?.destinationAccountId) validateStripeId(input.destinationAccountId, "account");
|
|
918
1190
|
const stripe = getStripe();
|
|
919
1191
|
const transfers = await stripe.transfers.list({
|
|
920
|
-
limit: input?.limit
|
|
1192
|
+
limit: sanitizeLimit(input?.limit),
|
|
921
1193
|
starting_after: input?.startingAfter,
|
|
922
1194
|
ending_before: input?.endingBefore,
|
|
923
1195
|
destination: input?.destinationAccountId
|
|
@@ -927,14 +1199,20 @@ async function listTransfers(input) {
|
|
|
927
1199
|
return handleStripeError(error);
|
|
928
1200
|
}
|
|
929
1201
|
}
|
|
930
|
-
async function createPayout(amount, currency, metadata) {
|
|
1202
|
+
async function createPayout(amount, currency, metadata, options) {
|
|
931
1203
|
try {
|
|
1204
|
+
validateAmount(amount, "payout amount");
|
|
1205
|
+
const normalizedCurrency = validateCurrency(currency);
|
|
1206
|
+
if (metadata) validateMetadata(metadata);
|
|
932
1207
|
const stripe = getStripe();
|
|
933
|
-
const payout = await stripe.payouts.create(
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1208
|
+
const payout = await stripe.payouts.create(
|
|
1209
|
+
{
|
|
1210
|
+
amount,
|
|
1211
|
+
currency: normalizedCurrency,
|
|
1212
|
+
metadata
|
|
1213
|
+
},
|
|
1214
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
1215
|
+
);
|
|
938
1216
|
return success(payout);
|
|
939
1217
|
} catch (error) {
|
|
940
1218
|
return handleStripeError(error);
|
|
@@ -944,7 +1222,7 @@ async function listPayouts(input) {
|
|
|
944
1222
|
try {
|
|
945
1223
|
const stripe = getStripe();
|
|
946
1224
|
const payouts = await stripe.payouts.list({
|
|
947
|
-
limit: input?.limit
|
|
1225
|
+
limit: sanitizeLimit(input?.limit),
|
|
948
1226
|
starting_after: input?.startingAfter,
|
|
949
1227
|
ending_before: input?.endingBefore,
|
|
950
1228
|
status: input?.status
|
|
@@ -967,7 +1245,7 @@ async function listBalanceTransactions(input) {
|
|
|
967
1245
|
try {
|
|
968
1246
|
const stripe = getStripe();
|
|
969
1247
|
const transactions = await stripe.balanceTransactions.list({
|
|
970
|
-
limit: input?.limit
|
|
1248
|
+
limit: sanitizeLimit(input?.limit),
|
|
971
1249
|
starting_after: input?.startingAfter,
|
|
972
1250
|
ending_before: input?.endingBefore,
|
|
973
1251
|
type: input?.type
|
|
@@ -979,20 +1257,26 @@ async function listBalanceTransactions(input) {
|
|
|
979
1257
|
}
|
|
980
1258
|
|
|
981
1259
|
// src/server/coupons/index.ts
|
|
982
|
-
async function createCoupon(input) {
|
|
1260
|
+
async function createCoupon(input, options) {
|
|
983
1261
|
try {
|
|
1262
|
+
if (input.amountOff !== void 0) validateAmount(input.amountOff, "amountOff");
|
|
1263
|
+
if (input.currency) validateCurrency(input.currency);
|
|
1264
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
984
1265
|
const stripe = getStripe();
|
|
985
|
-
const coupon = await stripe.coupons.create(
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1266
|
+
const coupon = await stripe.coupons.create(
|
|
1267
|
+
{
|
|
1268
|
+
percent_off: input.percentOff,
|
|
1269
|
+
amount_off: input.amountOff,
|
|
1270
|
+
currency: input.currency,
|
|
1271
|
+
duration: input.duration,
|
|
1272
|
+
duration_in_months: input.durationInMonths,
|
|
1273
|
+
max_redemptions: input.maxRedemptions,
|
|
1274
|
+
redeem_by: input.redeemBy,
|
|
1275
|
+
name: input.name,
|
|
1276
|
+
metadata: input.metadata
|
|
1277
|
+
},
|
|
1278
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
1279
|
+
);
|
|
996
1280
|
return success(coupon);
|
|
997
1281
|
} catch (error) {
|
|
998
1282
|
return handleStripeError(error);
|
|
@@ -1000,6 +1284,7 @@ async function createCoupon(input) {
|
|
|
1000
1284
|
}
|
|
1001
1285
|
async function retrieveCoupon(couponId) {
|
|
1002
1286
|
try {
|
|
1287
|
+
validateStripeId(couponId, "coupon");
|
|
1003
1288
|
const stripe = getStripe();
|
|
1004
1289
|
const coupon = await stripe.coupons.retrieve(couponId);
|
|
1005
1290
|
return success(coupon);
|
|
@@ -1009,6 +1294,7 @@ async function retrieveCoupon(couponId) {
|
|
|
1009
1294
|
}
|
|
1010
1295
|
async function deleteCoupon(couponId) {
|
|
1011
1296
|
try {
|
|
1297
|
+
validateStripeId(couponId, "coupon");
|
|
1012
1298
|
const stripe = getStripe();
|
|
1013
1299
|
const deleted = await stripe.coupons.del(couponId);
|
|
1014
1300
|
return success(deleted);
|
|
@@ -1020,7 +1306,7 @@ async function listCoupons(input) {
|
|
|
1020
1306
|
try {
|
|
1021
1307
|
const stripe = getStripe();
|
|
1022
1308
|
const coupons = await stripe.coupons.list({
|
|
1023
|
-
limit: input?.limit
|
|
1309
|
+
limit: sanitizeLimit(input?.limit),
|
|
1024
1310
|
starting_after: input?.startingAfter,
|
|
1025
1311
|
ending_before: input?.endingBefore
|
|
1026
1312
|
});
|
|
@@ -1029,22 +1315,32 @@ async function listCoupons(input) {
|
|
|
1029
1315
|
return handleStripeError(error);
|
|
1030
1316
|
}
|
|
1031
1317
|
}
|
|
1032
|
-
async function createPromotionCode(input) {
|
|
1318
|
+
async function createPromotionCode(input, options) {
|
|
1033
1319
|
try {
|
|
1320
|
+
if (input.metadata) validateMetadata(input.metadata);
|
|
1321
|
+
if (input.restrictions?.minimumAmountCurrency) {
|
|
1322
|
+
validateCurrency(input.restrictions.minimumAmountCurrency);
|
|
1323
|
+
}
|
|
1324
|
+
if (input.restrictions?.minimumAmount !== void 0) {
|
|
1325
|
+
validateAmount(input.restrictions.minimumAmount, "minimumAmount");
|
|
1326
|
+
}
|
|
1034
1327
|
const stripe = getStripe();
|
|
1035
|
-
const promotionCode = await stripe.promotionCodes.create(
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1328
|
+
const promotionCode = await stripe.promotionCodes.create(
|
|
1329
|
+
{
|
|
1330
|
+
coupon: input.couponId,
|
|
1331
|
+
code: input.code,
|
|
1332
|
+
active: input.active,
|
|
1333
|
+
max_redemptions: input.maxRedemptions,
|
|
1334
|
+
expires_at: input.expiresAt,
|
|
1335
|
+
metadata: input.metadata,
|
|
1336
|
+
restrictions: input.restrictions ? {
|
|
1337
|
+
first_time_transaction: input.restrictions.firstTimeTransaction,
|
|
1338
|
+
minimum_amount: input.restrictions.minimumAmount,
|
|
1339
|
+
minimum_amount_currency: input.restrictions.minimumAmountCurrency
|
|
1340
|
+
} : void 0
|
|
1341
|
+
},
|
|
1342
|
+
options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
|
|
1343
|
+
);
|
|
1048
1344
|
return success(promotionCode);
|
|
1049
1345
|
} catch (error) {
|
|
1050
1346
|
return handleStripeError(error);
|
|
@@ -1052,6 +1348,7 @@ async function createPromotionCode(input) {
|
|
|
1052
1348
|
}
|
|
1053
1349
|
async function retrievePromotionCode(promotionCodeId) {
|
|
1054
1350
|
try {
|
|
1351
|
+
validateStripeId(promotionCodeId, "promotionCode");
|
|
1055
1352
|
const stripe = getStripe();
|
|
1056
1353
|
const promotionCode = await stripe.promotionCodes.retrieve(promotionCodeId);
|
|
1057
1354
|
return success(promotionCode);
|
|
@@ -1063,7 +1360,7 @@ async function listPromotionCodes(input) {
|
|
|
1063
1360
|
try {
|
|
1064
1361
|
const stripe = getStripe();
|
|
1065
1362
|
const promotionCodes = await stripe.promotionCodes.list({
|
|
1066
|
-
limit: input?.limit
|
|
1363
|
+
limit: sanitizeLimit(input?.limit),
|
|
1067
1364
|
starting_after: input?.startingAfter,
|
|
1068
1365
|
ending_before: input?.endingBefore,
|
|
1069
1366
|
coupon: input?.couponId,
|
|
@@ -1117,6 +1414,9 @@ function createWebhookHandler(config) {
|
|
|
1117
1414
|
function createNextWebhookHandler(config) {
|
|
1118
1415
|
const handler = createWebhookHandler(config);
|
|
1119
1416
|
return async function POST(request) {
|
|
1417
|
+
if (request.method !== "POST") {
|
|
1418
|
+
return new Response(null, { status: 405 });
|
|
1419
|
+
}
|
|
1120
1420
|
try {
|
|
1121
1421
|
const contentLength = request.headers.get("content-length");
|
|
1122
1422
|
if (contentLength && parseInt(contentLength, 10) > MAX_BODY_SIZE) {
|
|
@@ -1126,6 +1426,12 @@ function createNextWebhookHandler(config) {
|
|
|
1126
1426
|
});
|
|
1127
1427
|
}
|
|
1128
1428
|
const body = await request.text();
|
|
1429
|
+
if (body.length > MAX_BODY_SIZE) {
|
|
1430
|
+
return new Response(JSON.stringify({ error: "Webhook body too large" }), {
|
|
1431
|
+
status: 413,
|
|
1432
|
+
headers: { "Content-Type": "application/json" }
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1129
1435
|
const signature = request.headers.get("stripe-signature");
|
|
1130
1436
|
if (!signature) {
|
|
1131
1437
|
return new Response(JSON.stringify({ error: "Missing stripe-signature header" }), {
|
|
@@ -1139,8 +1445,8 @@ function createNextWebhookHandler(config) {
|
|
|
1139
1445
|
headers: { "Content-Type": "application/json" }
|
|
1140
1446
|
});
|
|
1141
1447
|
} catch (error) {
|
|
1142
|
-
|
|
1143
|
-
return new Response(JSON.stringify({ error:
|
|
1448
|
+
console.error("[@stripe-sdk/core] Webhook error:", error instanceof Error ? error.message : "Unknown error");
|
|
1449
|
+
return new Response(JSON.stringify({ error: "Webhook processing failed" }), {
|
|
1144
1450
|
status: 400,
|
|
1145
1451
|
headers: { "Content-Type": "application/json" }
|
|
1146
1452
|
});
|
|
@@ -1164,8 +1470,8 @@ function createPagesWebhookHandler(webhookConfig) {
|
|
|
1164
1470
|
const result = await handler(body, signature);
|
|
1165
1471
|
res.status(200).json(result);
|
|
1166
1472
|
} catch (error) {
|
|
1167
|
-
|
|
1168
|
-
res.status(400).json({ error:
|
|
1473
|
+
console.error("[@stripe-sdk/core] Webhook error:", error instanceof Error ? error.message : "Unknown error");
|
|
1474
|
+
res.status(400).json({ error: "Webhook processing failed" });
|
|
1169
1475
|
}
|
|
1170
1476
|
};
|
|
1171
1477
|
}
|
|
@@ -1193,16 +1499,21 @@ function getRawBody(req) {
|
|
|
1193
1499
|
}
|
|
1194
1500
|
const chunks = [];
|
|
1195
1501
|
let totalLength = 0;
|
|
1502
|
+
let rejected = false;
|
|
1196
1503
|
req.on("data", (chunk) => {
|
|
1504
|
+
if (rejected) return;
|
|
1197
1505
|
const buf = Buffer.from(chunk);
|
|
1198
1506
|
totalLength += buf.length;
|
|
1199
1507
|
if (totalLength > MAX_BODY_SIZE) {
|
|
1508
|
+
rejected = true;
|
|
1200
1509
|
reject(new Error("Webhook body too large"));
|
|
1201
1510
|
return;
|
|
1202
1511
|
}
|
|
1203
1512
|
chunks.push(buf);
|
|
1204
1513
|
});
|
|
1205
|
-
req.on("end", () =>
|
|
1514
|
+
req.on("end", () => {
|
|
1515
|
+
if (!rejected) resolve(Buffer.concat(chunks).toString("utf8"));
|
|
1516
|
+
});
|
|
1206
1517
|
req.on("error", reject);
|
|
1207
1518
|
});
|
|
1208
1519
|
}
|
|
@@ -1214,12 +1525,26 @@ function useStripeConfig() {
|
|
|
1214
1525
|
}
|
|
1215
1526
|
return context;
|
|
1216
1527
|
}
|
|
1528
|
+
function validatePublishableKey(key) {
|
|
1529
|
+
if (!key || typeof key !== "string") {
|
|
1530
|
+
throw new Error("StripeProvider requires a publishableKey");
|
|
1531
|
+
}
|
|
1532
|
+
if (key.startsWith("sk_")) {
|
|
1533
|
+
throw new Error(
|
|
1534
|
+
"StripeProvider received a secret key (sk_*). Use a publishable key (pk_*) instead. Secret keys must NEVER be used on the client side."
|
|
1535
|
+
);
|
|
1536
|
+
}
|
|
1537
|
+
if (!key.startsWith("pk_")) {
|
|
1538
|
+
throw new Error('StripeProvider requires a publishable key starting with "pk_"');
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1217
1541
|
function StripeProvider({
|
|
1218
1542
|
publishableKey,
|
|
1219
1543
|
children,
|
|
1220
1544
|
options,
|
|
1221
1545
|
locale
|
|
1222
1546
|
}) {
|
|
1547
|
+
validatePublishableKey(publishableKey);
|
|
1223
1548
|
const stripePromise = useMemo(
|
|
1224
1549
|
() => loadStripe(publishableKey, locale ? { locale } : void 0),
|
|
1225
1550
|
[publishableKey, locale]
|
|
@@ -1234,6 +1559,10 @@ function StripeElementsProvider({
|
|
|
1234
1559
|
locale,
|
|
1235
1560
|
loader = "auto"
|
|
1236
1561
|
}) {
|
|
1562
|
+
validatePublishableKey(publishableKey);
|
|
1563
|
+
if (!clientSecret || typeof clientSecret !== "string") {
|
|
1564
|
+
throw new Error("StripeElementsProvider requires a clientSecret");
|
|
1565
|
+
}
|
|
1237
1566
|
const stripePromise = useMemo(
|
|
1238
1567
|
() => loadStripe(publishableKey, locale ? { locale } : void 0),
|
|
1239
1568
|
[publishableKey, locale]
|
|
@@ -1248,9 +1577,21 @@ function StripeElementsProvider({
|
|
|
1248
1577
|
);
|
|
1249
1578
|
return /* @__PURE__ */ jsx(StripeContext.Provider, { value: { publishableKey }, children: /* @__PURE__ */ jsx(Elements, { stripe: stripePromise, options, children }) });
|
|
1250
1579
|
}
|
|
1580
|
+
function validateReturnUrl(url) {
|
|
1581
|
+
try {
|
|
1582
|
+
const parsed = new URL(url);
|
|
1583
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
1584
|
+
throw new Error("returnUrl must use http or https protocol");
|
|
1585
|
+
}
|
|
1586
|
+
} catch {
|
|
1587
|
+
throw new Error("returnUrl must be a valid URL");
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1251
1590
|
function usePayment(options) {
|
|
1252
1591
|
const stripe = useStripe();
|
|
1253
1592
|
const elements = useElements();
|
|
1593
|
+
const optionsRef = useRef(options);
|
|
1594
|
+
optionsRef.current = options;
|
|
1254
1595
|
const [state, setState] = useState({
|
|
1255
1596
|
isProcessing: false,
|
|
1256
1597
|
isSuccess: false,
|
|
@@ -1262,28 +1603,32 @@ function usePayment(options) {
|
|
|
1262
1603
|
setState((s) => ({ ...s, error: "Stripe not loaded yet" }));
|
|
1263
1604
|
return { success: false, error: "Stripe not loaded yet" };
|
|
1264
1605
|
}
|
|
1606
|
+
const returnUrl = overrides?.returnUrl ?? optionsRef.current?.returnUrl ?? (typeof window !== "undefined" ? window.location.href : "");
|
|
1607
|
+
if (returnUrl && returnUrl !== window.location.href) {
|
|
1608
|
+
validateReturnUrl(returnUrl);
|
|
1609
|
+
}
|
|
1265
1610
|
setState({ isProcessing: true, isSuccess: false, error: null, paymentIntentId: null });
|
|
1266
1611
|
const { error, paymentIntent } = await stripe.confirmPayment({
|
|
1267
1612
|
elements,
|
|
1268
1613
|
confirmParams: {
|
|
1269
|
-
return_url:
|
|
1614
|
+
return_url: returnUrl
|
|
1270
1615
|
},
|
|
1271
1616
|
redirect: "if_required"
|
|
1272
1617
|
});
|
|
1273
1618
|
if (error) {
|
|
1274
1619
|
const message = error.message ?? "Payment failed";
|
|
1275
1620
|
setState({ isProcessing: false, isSuccess: false, error: message, paymentIntentId: null });
|
|
1276
|
-
|
|
1621
|
+
optionsRef.current?.onError?.(message);
|
|
1277
1622
|
return { success: false, error: message };
|
|
1278
1623
|
}
|
|
1279
1624
|
if (paymentIntent?.status === "succeeded") {
|
|
1280
1625
|
setState({ isProcessing: false, isSuccess: true, error: null, paymentIntentId: paymentIntent.id });
|
|
1281
|
-
|
|
1626
|
+
optionsRef.current?.onSuccess?.(paymentIntent.id);
|
|
1282
1627
|
return { success: true, paymentIntentId: paymentIntent.id };
|
|
1283
1628
|
}
|
|
1284
1629
|
setState({ isProcessing: false, isSuccess: false, error: null, paymentIntentId: paymentIntent?.id ?? null });
|
|
1285
1630
|
return { success: false, status: paymentIntent?.status };
|
|
1286
|
-
}, [stripe, elements
|
|
1631
|
+
}, [stripe, elements]);
|
|
1287
1632
|
const reset = useCallback(() => {
|
|
1288
1633
|
setState({ isProcessing: false, isSuccess: false, error: null, paymentIntentId: null });
|
|
1289
1634
|
}, []);
|
|
@@ -1294,9 +1639,21 @@ function usePayment(options) {
|
|
|
1294
1639
|
isReady: !!stripe && !!elements
|
|
1295
1640
|
};
|
|
1296
1641
|
}
|
|
1642
|
+
function validateReturnUrl2(url) {
|
|
1643
|
+
try {
|
|
1644
|
+
const parsed = new URL(url);
|
|
1645
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
1646
|
+
throw new Error("returnUrl must use http or https protocol");
|
|
1647
|
+
}
|
|
1648
|
+
} catch {
|
|
1649
|
+
throw new Error("returnUrl must be a valid URL");
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1297
1652
|
function useSetupIntent(options) {
|
|
1298
1653
|
const stripe = useStripe();
|
|
1299
1654
|
const elements = useElements();
|
|
1655
|
+
const optionsRef = useRef(options);
|
|
1656
|
+
optionsRef.current = options;
|
|
1300
1657
|
const [state, setState] = useState({
|
|
1301
1658
|
isProcessing: false,
|
|
1302
1659
|
isSuccess: false,
|
|
@@ -1309,29 +1666,33 @@ function useSetupIntent(options) {
|
|
|
1309
1666
|
setState((s) => ({ ...s, error: "Stripe not loaded yet" }));
|
|
1310
1667
|
return { success: false, error: "Stripe not loaded yet" };
|
|
1311
1668
|
}
|
|
1669
|
+
const returnUrl = overrides?.returnUrl ?? optionsRef.current?.returnUrl ?? (typeof window !== "undefined" ? window.location.href : "");
|
|
1670
|
+
if (returnUrl && returnUrl !== window.location.href) {
|
|
1671
|
+
validateReturnUrl2(returnUrl);
|
|
1672
|
+
}
|
|
1312
1673
|
setState({ isProcessing: true, isSuccess: false, error: null, setupIntentId: null, paymentMethodId: null });
|
|
1313
1674
|
const { error, setupIntent } = await stripe.confirmSetup({
|
|
1314
1675
|
elements,
|
|
1315
1676
|
confirmParams: {
|
|
1316
|
-
return_url:
|
|
1677
|
+
return_url: returnUrl
|
|
1317
1678
|
},
|
|
1318
1679
|
redirect: "if_required"
|
|
1319
1680
|
});
|
|
1320
1681
|
if (error) {
|
|
1321
1682
|
const message = error.message ?? "Setup failed";
|
|
1322
1683
|
setState({ isProcessing: false, isSuccess: false, error: message, setupIntentId: null, paymentMethodId: null });
|
|
1323
|
-
|
|
1684
|
+
optionsRef.current?.onError?.(message);
|
|
1324
1685
|
return { success: false, error: message };
|
|
1325
1686
|
}
|
|
1326
1687
|
if (setupIntent?.status === "succeeded") {
|
|
1327
1688
|
const pmId = typeof setupIntent.payment_method === "string" ? setupIntent.payment_method : setupIntent.payment_method?.id ?? null;
|
|
1328
1689
|
setState({ isProcessing: false, isSuccess: true, error: null, setupIntentId: setupIntent.id, paymentMethodId: pmId });
|
|
1329
|
-
if (pmId)
|
|
1690
|
+
if (pmId) optionsRef.current?.onSuccess?.(setupIntent.id, pmId);
|
|
1330
1691
|
return { success: true, setupIntentId: setupIntent.id, paymentMethodId: pmId };
|
|
1331
1692
|
}
|
|
1332
1693
|
setState({ isProcessing: false, isSuccess: false, error: null, setupIntentId: setupIntent?.id ?? null, paymentMethodId: null });
|
|
1333
1694
|
return { success: false, status: setupIntent?.status };
|
|
1334
|
-
}, [stripe, elements
|
|
1695
|
+
}, [stripe, elements]);
|
|
1335
1696
|
const reset = useCallback(() => {
|
|
1336
1697
|
setState({ isProcessing: false, isSuccess: false, error: null, setupIntentId: null, paymentMethodId: null });
|
|
1337
1698
|
}, []);
|
|
@@ -1342,6 +1703,14 @@ function useSetupIntent(options) {
|
|
|
1342
1703
|
isReady: !!stripe && !!elements
|
|
1343
1704
|
};
|
|
1344
1705
|
}
|
|
1706
|
+
function isValidStripeUrl(url) {
|
|
1707
|
+
try {
|
|
1708
|
+
const parsed = new URL(url);
|
|
1709
|
+
return parsed.hostname.endsWith(".stripe.com") && parsed.protocol === "https:";
|
|
1710
|
+
} catch {
|
|
1711
|
+
return false;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1345
1714
|
function useCheckout(options) {
|
|
1346
1715
|
const [state, setState] = useState({
|
|
1347
1716
|
isLoading: false,
|
|
@@ -1368,8 +1737,11 @@ function useCheckout(options) {
|
|
|
1368
1737
|
options.onError?.(message);
|
|
1369
1738
|
return { success: false, error: message };
|
|
1370
1739
|
}
|
|
1371
|
-
}, [options]);
|
|
1740
|
+
}, [options.publishableKey, options.onError]);
|
|
1372
1741
|
const redirectToPortal = useCallback((portalUrl) => {
|
|
1742
|
+
if (!isValidStripeUrl(portalUrl)) {
|
|
1743
|
+
throw new Error("Invalid portal URL: must be a valid stripe.com HTTPS URL");
|
|
1744
|
+
}
|
|
1373
1745
|
window.location.href = portalUrl;
|
|
1374
1746
|
}, []);
|
|
1375
1747
|
return {
|
|
@@ -1704,5 +2076,3 @@ function SubscriptionManager({
|
|
|
1704
2076
|
}
|
|
1705
2077
|
|
|
1706
2078
|
export { CheckoutForm, PricingTable, SetupForm, StripeElementsProvider, StripeProvider, SubscriptionManager, archivePrice, archiveProduct, attachPaymentMethod, cancelPaymentIntent, cancelSubscription, closeDispute, confirmPaymentIntent, createAccountLink, createCheckoutSession, createConnectAccount, createCoupon, createCustomer, createInvoice, createInvoiceItem, createNextWebhookHandler, createPagesWebhookHandler, createPaymentIntent, createPaymentLink, createPayout, createPortalSession, createPrice, createProduct, createPromotionCode, createRefund, createSetupIntent, createSubscription, createTransfer, createWebhookHandler, deleteConnectAccount, deleteCoupon, deleteCustomer, detachPaymentMethod, finalizeInvoice, getBalance, getConfig, getStripe, getUpcomingInvoice, initStripe, listBalanceTransactions, listCheckoutSessions, listConnectAccounts, listCoupons, listCustomers, listDisputes, listInvoices, listPaymentIntents, listPaymentMethods, listPayouts, listPrices, listProducts, listPromotionCodes, listRefunds, listSubscriptions, listTransfers, payInvoice, resumeSubscription, retrieveCheckoutSession, retrieveConnectAccount, retrieveCoupon, retrieveCustomer, retrieveDispute, retrieveInvoice, retrievePaymentIntent, retrievePaymentLink, retrievePrice, retrieveProduct, retrievePromotionCode, retrieveRefund, retrieveSetupIntent, retrieveSubscription, searchCustomers, sendInvoice, updateCustomer, updateDispute, updateProduct, updateSubscription, useCheckout, usePayment, useSetupIntent, useStripeConfig, voidInvoice };
|
|
1707
|
-
//# sourceMappingURL=index.mjs.map
|
|
1708
|
-
//# sourceMappingURL=index.mjs.map
|