@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.
@@ -10,12 +10,16 @@ var Stripe__default = /*#__PURE__*/_interopDefault(Stripe);
10
10
  var stripeInstance = null;
11
11
  var currentConfig = null;
12
12
  function initStripe(config) {
13
+ if (stripeInstance) {
14
+ console.warn("[@stripe-sdk/core] Stripe is already initialized. Re-initializing with new config.");
15
+ }
13
16
  currentConfig = config;
14
17
  stripeInstance = new Stripe__default.default(config.secretKey, {
15
18
  apiVersion: config.apiVersion ?? "2025-01-27.acacia",
19
+ maxNetworkRetries: config.maxNetworkRetries ?? 2,
16
20
  appInfo: config.appInfo ?? {
17
21
  name: "@stripe-sdk/core",
18
- version: "1.0.0"
22
+ version: "1.0.1"
19
23
  }
20
24
  });
21
25
  return stripeInstance;
@@ -34,17 +38,27 @@ function getConfig() {
34
38
  "[@stripe-sdk/core] Stripe not initialized. Call initStripe({ secretKey, publishableKey }) first."
35
39
  );
36
40
  }
37
- return currentConfig;
41
+ const { secretKey: _sk, ...safeConfig } = currentConfig;
42
+ return safeConfig;
38
43
  }
39
44
 
40
45
  // src/utils/errors.ts
46
+ var SAFE_ERROR_MESSAGES = {
47
+ card_declined: "Your card was declined.",
48
+ expired_card: "Your card has expired.",
49
+ incorrect_cvc: "Incorrect security code.",
50
+ processing_error: "An error occurred while processing your card.",
51
+ incorrect_number: "The card number is incorrect.",
52
+ insufficient_funds: "Insufficient funds."
53
+ };
41
54
  function handleStripeError(error) {
42
55
  if (error?.type) {
43
56
  const stripeError = error;
57
+ const safeMessage = stripeError.code && SAFE_ERROR_MESSAGES[stripeError.code] || getSafeMessage(stripeError.type);
44
58
  return {
45
59
  data: null,
46
60
  error: {
47
- message: stripeError.message,
61
+ message: safeMessage,
48
62
  type: stripeError.type,
49
63
  code: stripeError.code,
50
64
  statusCode: stripeError.statusCode
@@ -54,31 +68,147 @@ function handleStripeError(error) {
54
68
  return {
55
69
  data: null,
56
70
  error: {
57
- message: error instanceof Error ? error.message : "An unknown error occurred",
71
+ message: "An unexpected error occurred",
58
72
  type: "sdk_error"
59
73
  }
60
74
  };
61
75
  }
76
+ function getSafeMessage(type) {
77
+ switch (type) {
78
+ case "card_error":
79
+ return "A card error occurred.";
80
+ case "invalid_request_error":
81
+ return "Invalid request. Please check your input.";
82
+ case "authentication_error":
83
+ return "Authentication failed.";
84
+ case "rate_limit_error":
85
+ return "Too many requests. Please try again later.";
86
+ case "api_error":
87
+ return "A payment processing error occurred. Please try again.";
88
+ default:
89
+ return "An unexpected error occurred.";
90
+ }
91
+ }
62
92
  function success(data) {
63
93
  return { data, error: null };
64
94
  }
65
95
 
96
+ // src/utils/validators.ts
97
+ var STRIPE_ID_PREFIXES = {
98
+ customer: "cus_",
99
+ paymentIntent: "pi_",
100
+ paymentMethod: "pm_",
101
+ subscription: "sub_",
102
+ invoice: "in_",
103
+ invoiceItem: "ii_",
104
+ product: "prod_",
105
+ price: "price_",
106
+ coupon: "",
107
+ // coupons can have custom IDs
108
+ promotionCode: "promo_",
109
+ refund: "re_",
110
+ dispute: "dp_",
111
+ account: "acct_",
112
+ transfer: "tr_",
113
+ payout: "po_",
114
+ setupIntent: "seti_",
115
+ session: "cs_",
116
+ paymentLink: "plink_"
117
+ };
118
+ function validateStripeId(id, type) {
119
+ if (!id || typeof id !== "string") {
120
+ throw new Error(`${type} ID is required and must be a non-empty string`);
121
+ }
122
+ const prefix = STRIPE_ID_PREFIXES[type];
123
+ if (prefix && !id.startsWith(prefix)) {
124
+ throw new Error(`Invalid ${type} ID: expected prefix "${prefix}"`);
125
+ }
126
+ }
127
+ function validateAmount(amount, label = "amount") {
128
+ if (typeof amount !== "number" || !Number.isFinite(amount)) {
129
+ throw new Error(`${label} must be a finite number`);
130
+ }
131
+ if (!Number.isInteger(amount)) {
132
+ throw new Error(`${label} must be an integer (amount in smallest currency unit)`);
133
+ }
134
+ if (amount < 0) {
135
+ throw new Error(`${label} must not be negative`);
136
+ }
137
+ if (amount > 99999999) {
138
+ throw new Error(`${label} exceeds maximum allowed value (99999999)`);
139
+ }
140
+ }
141
+ function validateCurrency(currency) {
142
+ if (!currency || typeof currency !== "string") {
143
+ throw new Error("Currency is required");
144
+ }
145
+ const normalized = currency.trim().toLowerCase();
146
+ if (!/^[a-z]{3}$/.test(normalized)) {
147
+ throw new Error("Currency must be a valid 3-letter ISO 4217 code");
148
+ }
149
+ return normalized;
150
+ }
151
+ function validateUrl(url, label = "URL") {
152
+ if (!url || typeof url !== "string") {
153
+ throw new Error(`${label} is required`);
154
+ }
155
+ try {
156
+ const parsed = new URL(url);
157
+ if (!["http:", "https:"].includes(parsed.protocol)) {
158
+ throw new Error(`${label} must use http or https protocol`);
159
+ }
160
+ } catch (e) {
161
+ if (e instanceof Error && e.message.includes("protocol")) throw e;
162
+ throw new Error(`${label} must be a valid URL`);
163
+ }
164
+ }
165
+ function validateMetadata(metadata) {
166
+ const keys = Object.keys(metadata);
167
+ if (keys.length > 50) {
168
+ throw new Error("Metadata cannot have more than 50 keys");
169
+ }
170
+ for (const [key, value] of Object.entries(metadata)) {
171
+ if (key.length > 40) {
172
+ throw new Error(`Metadata key "${key}" exceeds 40 characters`);
173
+ }
174
+ if (typeof value !== "string") {
175
+ throw new Error(`Metadata value for key "${key}" must be a string`);
176
+ }
177
+ if (value.length > 500) {
178
+ throw new Error(`Metadata value for key "${key}" exceeds 500 characters`);
179
+ }
180
+ }
181
+ }
182
+ function sanitizeLimit(limit, defaultLimit = 10) {
183
+ if (limit === void 0) return defaultLimit;
184
+ return Math.min(Math.max(Math.floor(limit), 1), 100);
185
+ }
186
+
66
187
  // src/server/payments/index.ts
67
- async function createPaymentIntent(input) {
68
- try {
69
- const stripe = getStripe();
70
- const paymentIntent = await stripe.paymentIntents.create({
71
- amount: input.amount,
72
- currency: input.currency,
73
- customer: input.customerId,
74
- payment_method: input.paymentMethodId,
75
- metadata: input.metadata,
76
- description: input.description,
77
- receipt_email: input.receiptEmail,
78
- setup_future_usage: input.setupFutureUsage,
79
- automatic_payment_methods: input.automaticPaymentMethods === false || input.paymentMethodId ? void 0 : { enabled: true },
80
- return_url: input.returnUrl
81
- });
188
+ async function createPaymentIntent(input, options) {
189
+ try {
190
+ validateAmount(input.amount);
191
+ const currency = validateCurrency(input.currency);
192
+ if (input.customerId) validateStripeId(input.customerId, "customer");
193
+ if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
194
+ if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
195
+ if (input.metadata) validateMetadata(input.metadata);
196
+ const stripe = getStripe();
197
+ const paymentIntent = await stripe.paymentIntents.create(
198
+ {
199
+ amount: input.amount,
200
+ currency,
201
+ customer: input.customerId,
202
+ payment_method: input.paymentMethodId,
203
+ metadata: input.metadata,
204
+ description: input.description,
205
+ receipt_email: input.receiptEmail,
206
+ setup_future_usage: input.setupFutureUsage,
207
+ automatic_payment_methods: input.automaticPaymentMethods === false || input.paymentMethodId ? void 0 : { enabled: true },
208
+ return_url: input.returnUrl
209
+ },
210
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
211
+ );
82
212
  return success(paymentIntent);
83
213
  } catch (error) {
84
214
  return handleStripeError(error);
@@ -86,6 +216,7 @@ async function createPaymentIntent(input) {
86
216
  }
87
217
  async function retrievePaymentIntent(paymentIntentId) {
88
218
  try {
219
+ validateStripeId(paymentIntentId, "paymentIntent");
89
220
  const stripe = getStripe();
90
221
  const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
91
222
  return success(paymentIntent);
@@ -95,6 +226,9 @@ async function retrievePaymentIntent(paymentIntentId) {
95
226
  }
96
227
  async function confirmPaymentIntent(input) {
97
228
  try {
229
+ validateStripeId(input.paymentIntentId, "paymentIntent");
230
+ if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
231
+ if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
98
232
  const stripe = getStripe();
99
233
  const paymentIntent = await stripe.paymentIntents.confirm(input.paymentIntentId, {
100
234
  payment_method: input.paymentMethodId,
@@ -107,6 +241,7 @@ async function confirmPaymentIntent(input) {
107
241
  }
108
242
  async function cancelPaymentIntent(paymentIntentId) {
109
243
  try {
244
+ validateStripeId(paymentIntentId, "paymentIntent");
110
245
  const stripe = getStripe();
111
246
  const paymentIntent = await stripe.paymentIntents.cancel(paymentIntentId);
112
247
  return success(paymentIntent);
@@ -116,9 +251,10 @@ async function cancelPaymentIntent(paymentIntentId) {
116
251
  }
117
252
  async function listPaymentIntents(input) {
118
253
  try {
254
+ if (input?.customerId) validateStripeId(input.customerId, "customer");
119
255
  const stripe = getStripe();
120
256
  const paymentIntents = await stripe.paymentIntents.list({
121
- limit: input?.limit ?? 10,
257
+ limit: sanitizeLimit(input?.limit),
122
258
  starting_after: input?.startingAfter,
123
259
  ending_before: input?.endingBefore,
124
260
  customer: input?.customerId
@@ -128,28 +264,35 @@ async function listPaymentIntents(input) {
128
264
  return handleStripeError(error);
129
265
  }
130
266
  }
131
- async function createCheckoutSession(input) {
132
- try {
133
- const stripe = getStripe();
134
- const session = await stripe.checkout.sessions.create({
135
- mode: input.mode,
136
- line_items: input.lineItems.map((item) => ({
137
- price: item.priceId,
138
- quantity: item.quantity
139
- })),
140
- success_url: input.successUrl,
141
- cancel_url: input.cancelUrl,
142
- customer: input.customerId,
143
- customer_email: input.customerEmail,
144
- metadata: input.metadata,
145
- allow_promotion_codes: input.allowPromotionCodes,
146
- shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0,
147
- billing_address_collection: input.billingAddressCollection,
148
- subscription_data: input.trialPeriodDays ? { trial_period_days: input.trialPeriodDays } : void 0,
149
- tax_id_collection: input.taxIdCollection ? { enabled: true } : void 0,
150
- automatic_tax: input.automaticTax ? { enabled: true } : void 0,
151
- locale: input.locale
152
- });
267
+ async function createCheckoutSession(input, options) {
268
+ try {
269
+ validateUrl(input.successUrl, "successUrl");
270
+ validateUrl(input.cancelUrl, "cancelUrl");
271
+ if (input.customerId) validateStripeId(input.customerId, "customer");
272
+ if (input.metadata) validateMetadata(input.metadata);
273
+ const stripe = getStripe();
274
+ const session = await stripe.checkout.sessions.create(
275
+ {
276
+ mode: input.mode,
277
+ line_items: input.lineItems.map((item) => ({
278
+ price: item.priceId,
279
+ quantity: item.quantity
280
+ })),
281
+ success_url: input.successUrl,
282
+ cancel_url: input.cancelUrl,
283
+ customer: input.customerId,
284
+ customer_email: input.customerEmail,
285
+ metadata: input.metadata,
286
+ allow_promotion_codes: input.allowPromotionCodes,
287
+ shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0,
288
+ billing_address_collection: input.billingAddressCollection,
289
+ subscription_data: input.trialPeriodDays ? { trial_period_days: input.trialPeriodDays } : void 0,
290
+ tax_id_collection: input.taxIdCollection ? { enabled: true } : void 0,
291
+ automatic_tax: input.automaticTax ? { enabled: true } : void 0,
292
+ locale: input.locale
293
+ },
294
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
295
+ );
153
296
  return success(session);
154
297
  } catch (error) {
155
298
  return handleStripeError(error);
@@ -157,6 +300,7 @@ async function createCheckoutSession(input) {
157
300
  }
158
301
  async function retrieveCheckoutSession(sessionId) {
159
302
  try {
303
+ validateStripeId(sessionId, "session");
160
304
  const stripe = getStripe();
161
305
  const session = await stripe.checkout.sessions.retrieve(sessionId, {
162
306
  expand: ["line_items", "payment_intent", "subscription"]
@@ -170,7 +314,7 @@ async function listCheckoutSessions(input) {
170
314
  try {
171
315
  const stripe = getStripe();
172
316
  const sessions = await stripe.checkout.sessions.list({
173
- limit: input?.limit ?? 10,
317
+ limit: sanitizeLimit(input?.limit),
174
318
  starting_after: input?.startingAfter,
175
319
  ending_before: input?.endingBefore
176
320
  });
@@ -179,29 +323,36 @@ async function listCheckoutSessions(input) {
179
323
  return handleStripeError(error);
180
324
  }
181
325
  }
182
- async function createPaymentLink(input) {
326
+ async function createPaymentLink(input, options) {
183
327
  try {
184
- const stripe = getStripe();
185
- const paymentLink = await stripe.paymentLinks.create({
186
- line_items: input.lineItems.map((item) => ({
187
- price: item.priceId,
188
- quantity: item.quantity,
189
- adjustable_quantity: item.adjustableQuantity ? {
190
- enabled: item.adjustableQuantity.enabled,
191
- minimum: item.adjustableQuantity.minimum,
192
- maximum: item.adjustableQuantity.maximum
193
- } : void 0
194
- })),
195
- metadata: input.metadata,
196
- after_completion: input.afterCompletion ? {
197
- type: input.afterCompletion.type,
198
- redirect: input.afterCompletion.redirectUrl ? { url: input.afterCompletion.redirectUrl } : void 0
199
- } : void 0,
200
- allow_promotion_codes: input.allowPromotionCodes,
201
- automatic_tax: input.automaticTax ? { enabled: true } : void 0,
202
- billing_address_collection: input.billingAddressCollection,
203
- shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0
204
- });
328
+ if (input.afterCompletion?.redirectUrl) {
329
+ validateUrl(input.afterCompletion.redirectUrl, "afterCompletion.redirectUrl");
330
+ }
331
+ if (input.metadata) validateMetadata(input.metadata);
332
+ const stripe = getStripe();
333
+ const paymentLink = await stripe.paymentLinks.create(
334
+ {
335
+ line_items: input.lineItems.map((item) => ({
336
+ price: item.priceId,
337
+ quantity: item.quantity,
338
+ adjustable_quantity: item.adjustableQuantity ? {
339
+ enabled: item.adjustableQuantity.enabled,
340
+ minimum: item.adjustableQuantity.minimum,
341
+ maximum: item.adjustableQuantity.maximum
342
+ } : void 0
343
+ })),
344
+ metadata: input.metadata,
345
+ after_completion: input.afterCompletion ? {
346
+ type: input.afterCompletion.type,
347
+ redirect: input.afterCompletion.redirectUrl ? { url: input.afterCompletion.redirectUrl } : void 0
348
+ } : void 0,
349
+ allow_promotion_codes: input.allowPromotionCodes,
350
+ automatic_tax: input.automaticTax ? { enabled: true } : void 0,
351
+ billing_address_collection: input.billingAddressCollection,
352
+ shipping_address_collection: input.shippingAddressCollection ? { allowed_countries: input.shippingAddressCollection.allowedCountries } : void 0
353
+ },
354
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
355
+ );
205
356
  return success(paymentLink);
206
357
  } catch (error) {
207
358
  return handleStripeError(error);
@@ -209,6 +360,7 @@ async function createPaymentLink(input) {
209
360
  }
210
361
  async function retrievePaymentLink(paymentLinkId) {
211
362
  try {
363
+ validateStripeId(paymentLinkId, "paymentLink");
212
364
  const stripe = getStripe();
213
365
  const paymentLink = await stripe.paymentLinks.retrieve(paymentLinkId);
214
366
  return success(paymentLink);
@@ -216,15 +368,20 @@ async function retrievePaymentLink(paymentLinkId) {
216
368
  return handleStripeError(error);
217
369
  }
218
370
  }
219
- async function createSetupIntent(input) {
371
+ async function createSetupIntent(input, options) {
220
372
  try {
373
+ if (input.customerId) validateStripeId(input.customerId, "customer");
374
+ if (input.metadata) validateMetadata(input.metadata);
221
375
  const stripe = getStripe();
222
- const setupIntent = await stripe.setupIntents.create({
223
- customer: input.customerId,
224
- payment_method_types: input.paymentMethodTypes,
225
- usage: input.usage,
226
- metadata: input.metadata
227
- });
376
+ const setupIntent = await stripe.setupIntents.create(
377
+ {
378
+ customer: input.customerId,
379
+ payment_method_types: input.paymentMethodTypes,
380
+ usage: input.usage,
381
+ metadata: input.metadata
382
+ },
383
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
384
+ );
228
385
  return success(setupIntent);
229
386
  } catch (error) {
230
387
  return handleStripeError(error);
@@ -232,6 +389,7 @@ async function createSetupIntent(input) {
232
389
  }
233
390
  async function retrieveSetupIntent(setupIntentId) {
234
391
  try {
392
+ validateStripeId(setupIntentId, "setupIntent");
235
393
  const stripe = getStripe();
236
394
  const setupIntent = await stripe.setupIntents.retrieve(setupIntentId);
237
395
  return success(setupIntent);
@@ -241,6 +399,7 @@ async function retrieveSetupIntent(setupIntentId) {
241
399
  }
242
400
  async function listPaymentMethods(customerId, type) {
243
401
  try {
402
+ validateStripeId(customerId, "customer");
244
403
  const stripe = getStripe();
245
404
  const paymentMethods = await stripe.paymentMethods.list({
246
405
  customer: customerId,
@@ -253,6 +412,8 @@ async function listPaymentMethods(customerId, type) {
253
412
  }
254
413
  async function attachPaymentMethod(paymentMethodId, customerId) {
255
414
  try {
415
+ validateStripeId(paymentMethodId, "paymentMethod");
416
+ validateStripeId(customerId, "customer");
256
417
  const stripe = getStripe();
257
418
  const paymentMethod = await stripe.paymentMethods.attach(paymentMethodId, {
258
419
  customer: customerId
@@ -264,6 +425,7 @@ async function attachPaymentMethod(paymentMethodId, customerId) {
264
425
  }
265
426
  async function detachPaymentMethod(paymentMethodId) {
266
427
  try {
428
+ validateStripeId(paymentMethodId, "paymentMethod");
267
429
  const stripe = getStripe();
268
430
  const paymentMethod = await stripe.paymentMethods.detach(paymentMethodId);
269
431
  return success(paymentMethod);
@@ -273,26 +435,31 @@ async function detachPaymentMethod(paymentMethodId) {
273
435
  }
274
436
 
275
437
  // src/server/customers/index.ts
276
- async function createCustomer(input) {
277
- try {
278
- const stripe = getStripe();
279
- const customer = await stripe.customers.create({
280
- email: input.email,
281
- name: input.name,
282
- phone: input.phone,
283
- description: input.description,
284
- metadata: input.metadata,
285
- payment_method: input.paymentMethodId,
286
- invoice_settings: input.paymentMethodId ? { default_payment_method: input.paymentMethodId } : void 0,
287
- address: input.address ? {
288
- line1: input.address.line1,
289
- line2: input.address.line2,
290
- city: input.address.city,
291
- state: input.address.state,
292
- postal_code: input.address.postalCode,
293
- country: input.address.country
294
- } : void 0
295
- });
438
+ async function createCustomer(input, options) {
439
+ try {
440
+ if (input.paymentMethodId) validateStripeId(input.paymentMethodId, "paymentMethod");
441
+ if (input.metadata) validateMetadata(input.metadata);
442
+ const stripe = getStripe();
443
+ const customer = await stripe.customers.create(
444
+ {
445
+ email: input.email,
446
+ name: input.name,
447
+ phone: input.phone,
448
+ description: input.description,
449
+ metadata: input.metadata,
450
+ payment_method: input.paymentMethodId,
451
+ invoice_settings: input.paymentMethodId ? { default_payment_method: input.paymentMethodId } : void 0,
452
+ address: input.address ? {
453
+ line1: input.address.line1,
454
+ line2: input.address.line2,
455
+ city: input.address.city,
456
+ state: input.address.state,
457
+ postal_code: input.address.postalCode,
458
+ country: input.address.country
459
+ } : void 0
460
+ },
461
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
462
+ );
296
463
  return success(customer);
297
464
  } catch (error) {
298
465
  return handleStripeError(error);
@@ -300,6 +467,7 @@ async function createCustomer(input) {
300
467
  }
301
468
  async function retrieveCustomer(customerId) {
302
469
  try {
470
+ validateStripeId(customerId, "customer");
303
471
  const stripe = getStripe();
304
472
  const customer = await stripe.customers.retrieve(customerId, {
305
473
  expand: ["subscriptions", "sources"]
@@ -317,6 +485,9 @@ async function retrieveCustomer(customerId) {
317
485
  }
318
486
  async function updateCustomer(input) {
319
487
  try {
488
+ validateStripeId(input.customerId, "customer");
489
+ if (input.defaultPaymentMethodId) validateStripeId(input.defaultPaymentMethodId, "paymentMethod");
490
+ if (input.metadata) validateMetadata(input.metadata);
320
491
  const stripe = getStripe();
321
492
  const customer = await stripe.customers.update(input.customerId, {
322
493
  email: input.email,
@@ -341,6 +512,7 @@ async function updateCustomer(input) {
341
512
  }
342
513
  async function deleteCustomer(customerId) {
343
514
  try {
515
+ validateStripeId(customerId, "customer");
344
516
  const stripe = getStripe();
345
517
  const deleted = await stripe.customers.del(customerId);
346
518
  return success(deleted);
@@ -352,7 +524,7 @@ async function listCustomers(input) {
352
524
  try {
353
525
  const stripe = getStripe();
354
526
  const customers = await stripe.customers.list({
355
- limit: input?.limit ?? 10,
527
+ limit: sanitizeLimit(input?.limit),
356
528
  starting_after: input?.startingAfter,
357
529
  ending_before: input?.endingBefore,
358
530
  email: input?.email
@@ -362,26 +534,42 @@ async function listCustomers(input) {
362
534
  return handleStripeError(error);
363
535
  }
364
536
  }
365
- async function searchCustomers(query, limit) {
537
+ async function searchCustomers(input) {
366
538
  try {
539
+ const clauses = [];
540
+ if (input.email) clauses.push(`email:"${input.email.replace(/"/g, "")}"`);
541
+ if (input.name) clauses.push(`name:"${input.name.replace(/"/g, "")}"`);
542
+ if (input.phone) clauses.push(`phone:"${input.phone.replace(/"/g, "")}"`);
543
+ if (clauses.length === 0) {
544
+ return {
545
+ data: null,
546
+ error: { message: "At least one search field (email, name, phone) is required", type: "invalid_request_error" }
547
+ };
548
+ }
549
+ const query = clauses.join(" AND ");
367
550
  const stripe = getStripe();
368
551
  const customers = await stripe.customers.search({
369
552
  query,
370
- limit: limit ?? 10
553
+ limit: sanitizeLimit(input.limit)
371
554
  });
372
555
  return success(customers);
373
556
  } catch (error) {
374
557
  return handleStripeError(error);
375
558
  }
376
559
  }
377
- async function createPortalSession(input) {
560
+ async function createPortalSession(input, options) {
378
561
  try {
562
+ validateStripeId(input.customerId, "customer");
563
+ if (input.returnUrl) validateUrl(input.returnUrl, "returnUrl");
379
564
  const stripe = getStripe();
380
- const session = await stripe.billingPortal.sessions.create({
381
- customer: input.customerId,
382
- return_url: input.returnUrl,
383
- configuration: input.configuration
384
- });
565
+ const session = await stripe.billingPortal.sessions.create(
566
+ {
567
+ customer: input.customerId,
568
+ return_url: input.returnUrl,
569
+ configuration: input.configuration
570
+ },
571
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
572
+ );
385
573
  return success(session);
386
574
  } catch (error) {
387
575
  return handleStripeError(error);
@@ -389,23 +577,28 @@ async function createPortalSession(input) {
389
577
  }
390
578
 
391
579
  // src/server/subscriptions/index.ts
392
- async function createSubscription(input) {
580
+ async function createSubscription(input, options) {
393
581
  try {
582
+ validateStripeId(input.customerId, "customer");
583
+ if (input.metadata) validateMetadata(input.metadata);
394
584
  const stripe = getStripe();
395
585
  const items = input.items ? input.items.map((item) => ({ price: item.priceId, quantity: item.quantity })) : [{ price: input.priceId, quantity: input.quantity ?? 1 }];
396
- const subscription = await stripe.subscriptions.create({
397
- customer: input.customerId,
398
- items,
399
- metadata: input.metadata,
400
- trial_period_days: input.trialPeriodDays,
401
- coupon: input.couponId,
402
- promotion_code: input.promotionCodeId,
403
- payment_behavior: input.paymentBehavior ?? "default_incomplete",
404
- cancel_at_period_end: input.cancelAtPeriodEnd,
405
- billing_cycle_anchor: input.billingCycleAnchor,
406
- proration_behavior: input.prorationBehavior,
407
- expand: ["latest_invoice.payment_intent"]
408
- });
586
+ const subscription = await stripe.subscriptions.create(
587
+ {
588
+ customer: input.customerId,
589
+ items,
590
+ metadata: input.metadata,
591
+ trial_period_days: input.trialPeriodDays,
592
+ coupon: input.couponId,
593
+ promotion_code: input.promotionCodeId,
594
+ payment_behavior: input.paymentBehavior ?? "default_incomplete",
595
+ cancel_at_period_end: input.cancelAtPeriodEnd,
596
+ billing_cycle_anchor: input.billingCycleAnchor,
597
+ proration_behavior: input.prorationBehavior,
598
+ expand: ["latest_invoice.payment_intent"]
599
+ },
600
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
601
+ );
409
602
  return success(subscription);
410
603
  } catch (error) {
411
604
  return handleStripeError(error);
@@ -413,6 +606,7 @@ async function createSubscription(input) {
413
606
  }
414
607
  async function retrieveSubscription(subscriptionId) {
415
608
  try {
609
+ validateStripeId(subscriptionId, "subscription");
416
610
  const stripe = getStripe();
417
611
  const subscription = await stripe.subscriptions.retrieve(subscriptionId, {
418
612
  expand: ["latest_invoice.payment_intent", "default_payment_method"]
@@ -424,6 +618,8 @@ async function retrieveSubscription(subscriptionId) {
424
618
  }
425
619
  async function updateSubscription(input) {
426
620
  try {
621
+ validateStripeId(input.subscriptionId, "subscription");
622
+ if (input.metadata) validateMetadata(input.metadata);
427
623
  const stripe = getStripe();
428
624
  const params = {
429
625
  metadata: input.metadata,
@@ -446,6 +642,7 @@ async function updateSubscription(input) {
446
642
  }
447
643
  async function cancelSubscription(input) {
448
644
  try {
645
+ validateStripeId(input.subscriptionId, "subscription");
449
646
  const stripe = getStripe();
450
647
  if (input.cancelAtPeriodEnd) {
451
648
  const subscription2 = await stripe.subscriptions.update(input.subscriptionId, {
@@ -470,6 +667,7 @@ async function cancelSubscription(input) {
470
667
  }
471
668
  async function resumeSubscription(subscriptionId) {
472
669
  try {
670
+ validateStripeId(subscriptionId, "subscription");
473
671
  const stripe = getStripe();
474
672
  const subscription = await stripe.subscriptions.update(subscriptionId, {
475
673
  cancel_at_period_end: false
@@ -481,9 +679,10 @@ async function resumeSubscription(subscriptionId) {
481
679
  }
482
680
  async function listSubscriptions(input) {
483
681
  try {
682
+ if (input?.customerId) validateStripeId(input.customerId, "customer");
484
683
  const stripe = getStripe();
485
684
  const subscriptions = await stripe.subscriptions.list({
486
- limit: input?.limit ?? 10,
685
+ limit: sanitizeLimit(input?.limit),
487
686
  starting_after: input?.startingAfter,
488
687
  ending_before: input?.endingBefore,
489
688
  customer: input?.customerId,
@@ -496,24 +695,32 @@ async function listSubscriptions(input) {
496
695
  }
497
696
 
498
697
  // src/server/products/index.ts
499
- async function createProduct(input) {
698
+ async function createProduct(input, options) {
500
699
  try {
700
+ if (input.metadata) validateMetadata(input.metadata);
701
+ if (input.defaultPriceData) {
702
+ validateAmount(input.defaultPriceData.unitAmount, "unitAmount");
703
+ validateCurrency(input.defaultPriceData.currency);
704
+ }
501
705
  const stripe = getStripe();
502
- const product = await stripe.products.create({
503
- name: input.name,
504
- description: input.description,
505
- images: input.images,
506
- metadata: input.metadata,
507
- active: input.active,
508
- default_price_data: input.defaultPriceData ? {
509
- unit_amount: input.defaultPriceData.unitAmount,
510
- currency: input.defaultPriceData.currency,
511
- recurring: input.defaultPriceData.recurring ? {
512
- interval: input.defaultPriceData.recurring.interval,
513
- interval_count: input.defaultPriceData.recurring.intervalCount
706
+ const product = await stripe.products.create(
707
+ {
708
+ name: input.name,
709
+ description: input.description,
710
+ images: input.images,
711
+ metadata: input.metadata,
712
+ active: input.active,
713
+ default_price_data: input.defaultPriceData ? {
714
+ unit_amount: input.defaultPriceData.unitAmount,
715
+ currency: input.defaultPriceData.currency,
716
+ recurring: input.defaultPriceData.recurring ? {
717
+ interval: input.defaultPriceData.recurring.interval,
718
+ interval_count: input.defaultPriceData.recurring.intervalCount
719
+ } : void 0
514
720
  } : void 0
515
- } : void 0
516
- });
721
+ },
722
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
723
+ );
517
724
  return success(product);
518
725
  } catch (error) {
519
726
  return handleStripeError(error);
@@ -521,6 +728,7 @@ async function createProduct(input) {
521
728
  }
522
729
  async function retrieveProduct(productId) {
523
730
  try {
731
+ validateStripeId(productId, "product");
524
732
  const stripe = getStripe();
525
733
  const product = await stripe.products.retrieve(productId);
526
734
  return success(product);
@@ -530,6 +738,8 @@ async function retrieveProduct(productId) {
530
738
  }
531
739
  async function updateProduct(input) {
532
740
  try {
741
+ validateStripeId(input.productId, "product");
742
+ if (input.metadata) validateMetadata(input.metadata);
533
743
  const stripe = getStripe();
534
744
  const product = await stripe.products.update(input.productId, {
535
745
  name: input.name,
@@ -545,6 +755,7 @@ async function updateProduct(input) {
545
755
  }
546
756
  async function archiveProduct(productId) {
547
757
  try {
758
+ validateStripeId(productId, "product");
548
759
  const stripe = getStripe();
549
760
  const product = await stripe.products.update(productId, { active: false });
550
761
  return success(product);
@@ -556,7 +767,7 @@ async function listProducts(input) {
556
767
  try {
557
768
  const stripe = getStripe();
558
769
  const products = await stripe.products.list({
559
- limit: input?.limit ?? 10,
770
+ limit: sanitizeLimit(input?.limit),
560
771
  starting_after: input?.startingAfter,
561
772
  ending_before: input?.endingBefore,
562
773
  active: input?.active
@@ -566,8 +777,12 @@ async function listProducts(input) {
566
777
  return handleStripeError(error);
567
778
  }
568
779
  }
569
- async function createPrice(input) {
780
+ async function createPrice(input, options) {
570
781
  try {
782
+ validateStripeId(input.productId, "product");
783
+ validateCurrency(input.currency);
784
+ if (input.unitAmount !== void 0) validateAmount(input.unitAmount, "unitAmount");
785
+ if (input.metadata) validateMetadata(input.metadata);
571
786
  const stripe = getStripe();
572
787
  const params = {
573
788
  product: input.productId,
@@ -595,7 +810,10 @@ async function createPrice(input) {
595
810
  } else {
596
811
  params.unit_amount = input.unitAmount;
597
812
  }
598
- const price = await stripe.prices.create(params);
813
+ const price = await stripe.prices.create(
814
+ params,
815
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
816
+ );
599
817
  return success(price);
600
818
  } catch (error) {
601
819
  return handleStripeError(error);
@@ -603,6 +821,7 @@ async function createPrice(input) {
603
821
  }
604
822
  async function retrievePrice(priceId) {
605
823
  try {
824
+ validateStripeId(priceId, "price");
606
825
  const stripe = getStripe();
607
826
  const price = await stripe.prices.retrieve(priceId);
608
827
  return success(price);
@@ -612,9 +831,10 @@ async function retrievePrice(priceId) {
612
831
  }
613
832
  async function listPrices(input) {
614
833
  try {
834
+ if (input?.productId) validateStripeId(input.productId, "product");
615
835
  const stripe = getStripe();
616
836
  const prices = await stripe.prices.list({
617
- limit: input?.limit ?? 10,
837
+ limit: sanitizeLimit(input?.limit),
618
838
  starting_after: input?.startingAfter,
619
839
  ending_before: input?.endingBefore,
620
840
  product: input?.productId,
@@ -628,6 +848,7 @@ async function listPrices(input) {
628
848
  }
629
849
  async function archivePrice(priceId) {
630
850
  try {
851
+ validateStripeId(priceId, "price");
631
852
  const stripe = getStripe();
632
853
  const price = await stripe.prices.update(priceId, { active: false });
633
854
  return success(price);
@@ -637,17 +858,22 @@ async function archivePrice(priceId) {
637
858
  }
638
859
 
639
860
  // src/server/invoices/index.ts
640
- async function createInvoice(input) {
641
- try {
642
- const stripe = getStripe();
643
- const invoice = await stripe.invoices.create({
644
- customer: input.customerId,
645
- collection_method: input.collectionMethod ?? "charge_automatically",
646
- days_until_due: input.daysUntilDue,
647
- metadata: input.metadata,
648
- description: input.description,
649
- auto_advance: input.autoAdvance
650
- });
861
+ async function createInvoice(input, options) {
862
+ try {
863
+ validateStripeId(input.customerId, "customer");
864
+ if (input.metadata) validateMetadata(input.metadata);
865
+ const stripe = getStripe();
866
+ const invoice = await stripe.invoices.create(
867
+ {
868
+ customer: input.customerId,
869
+ collection_method: input.collectionMethod ?? "charge_automatically",
870
+ days_until_due: input.daysUntilDue,
871
+ metadata: input.metadata,
872
+ description: input.description,
873
+ auto_advance: input.autoAdvance
874
+ },
875
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
876
+ );
651
877
  return success(invoice);
652
878
  } catch (error) {
653
879
  return handleStripeError(error);
@@ -655,6 +881,7 @@ async function createInvoice(input) {
655
881
  }
656
882
  async function retrieveInvoice(invoiceId) {
657
883
  try {
884
+ validateStripeId(invoiceId, "invoice");
658
885
  const stripe = getStripe();
659
886
  const invoice = await stripe.invoices.retrieve(invoiceId);
660
887
  return success(invoice);
@@ -664,6 +891,7 @@ async function retrieveInvoice(invoiceId) {
664
891
  }
665
892
  async function finalizeInvoice(invoiceId) {
666
893
  try {
894
+ validateStripeId(invoiceId, "invoice");
667
895
  const stripe = getStripe();
668
896
  const invoice = await stripe.invoices.finalizeInvoice(invoiceId);
669
897
  return success(invoice);
@@ -673,6 +901,7 @@ async function finalizeInvoice(invoiceId) {
673
901
  }
674
902
  async function sendInvoice(invoiceId) {
675
903
  try {
904
+ validateStripeId(invoiceId, "invoice");
676
905
  const stripe = getStripe();
677
906
  const invoice = await stripe.invoices.sendInvoice(invoiceId);
678
907
  return success(invoice);
@@ -682,6 +911,7 @@ async function sendInvoice(invoiceId) {
682
911
  }
683
912
  async function payInvoice(invoiceId) {
684
913
  try {
914
+ validateStripeId(invoiceId, "invoice");
685
915
  const stripe = getStripe();
686
916
  const invoice = await stripe.invoices.pay(invoiceId);
687
917
  return success(invoice);
@@ -691,6 +921,7 @@ async function payInvoice(invoiceId) {
691
921
  }
692
922
  async function voidInvoice(invoiceId) {
693
923
  try {
924
+ validateStripeId(invoiceId, "invoice");
694
925
  const stripe = getStripe();
695
926
  const invoice = await stripe.invoices.voidInvoice(invoiceId);
696
927
  return success(invoice);
@@ -700,9 +931,10 @@ async function voidInvoice(invoiceId) {
700
931
  }
701
932
  async function listInvoices(input) {
702
933
  try {
934
+ if (input?.customerId) validateStripeId(input.customerId, "customer");
703
935
  const stripe = getStripe();
704
936
  const invoices = await stripe.invoices.list({
705
- limit: input?.limit ?? 10,
937
+ limit: sanitizeLimit(input?.limit),
706
938
  starting_after: input?.startingAfter,
707
939
  ending_before: input?.endingBefore,
708
940
  customer: input?.customerId,
@@ -715,6 +947,8 @@ async function listInvoices(input) {
715
947
  }
716
948
  async function getUpcomingInvoice(customerId, subscriptionId) {
717
949
  try {
950
+ validateStripeId(customerId, "customer");
951
+ if (subscriptionId) validateStripeId(subscriptionId, "subscription");
718
952
  const stripe = getStripe();
719
953
  const invoice = await stripe.invoices.retrieveUpcoming({
720
954
  customer: customerId,
@@ -725,19 +959,28 @@ async function getUpcomingInvoice(customerId, subscriptionId) {
725
959
  return handleStripeError(error);
726
960
  }
727
961
  }
728
- async function createInvoiceItem(input) {
962
+ async function createInvoiceItem(input, options) {
729
963
  try {
964
+ validateStripeId(input.customerId, "customer");
965
+ if (input.invoiceId) validateStripeId(input.invoiceId, "invoice");
966
+ if (input.priceId) validateStripeId(input.priceId, "price");
967
+ if (input.amount !== void 0) validateAmount(input.amount, "invoice item amount");
968
+ if (input.currency) validateCurrency(input.currency);
969
+ if (input.metadata) validateMetadata(input.metadata);
730
970
  const stripe = getStripe();
731
- const invoiceItem = await stripe.invoiceItems.create({
732
- customer: input.customerId,
733
- invoice: input.invoiceId,
734
- price: input.priceId,
735
- amount: input.amount,
736
- currency: input.currency,
737
- description: input.description,
738
- quantity: input.quantity,
739
- metadata: input.metadata
740
- });
971
+ const invoiceItem = await stripe.invoiceItems.create(
972
+ {
973
+ customer: input.customerId,
974
+ invoice: input.invoiceId,
975
+ price: input.priceId,
976
+ amount: input.amount,
977
+ currency: input.currency,
978
+ description: input.description,
979
+ quantity: input.quantity,
980
+ metadata: input.metadata
981
+ },
982
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
983
+ );
741
984
  return success(invoiceItem);
742
985
  } catch (error) {
743
986
  return handleStripeError(error);
@@ -745,16 +988,22 @@ async function createInvoiceItem(input) {
745
988
  }
746
989
 
747
990
  // src/server/refunds/index.ts
748
- async function createRefund(input) {
749
- try {
750
- const stripe = getStripe();
751
- const refund = await stripe.refunds.create({
752
- payment_intent: input.paymentIntentId,
753
- charge: input.chargeId,
754
- amount: input.amount,
755
- reason: input.reason,
756
- metadata: input.metadata
757
- });
991
+ async function createRefund(input, options) {
992
+ try {
993
+ if (input.paymentIntentId) validateStripeId(input.paymentIntentId, "paymentIntent");
994
+ if (input.amount !== void 0) validateAmount(input.amount, "refund amount");
995
+ if (input.metadata) validateMetadata(input.metadata);
996
+ const stripe = getStripe();
997
+ const refund = await stripe.refunds.create(
998
+ {
999
+ payment_intent: input.paymentIntentId,
1000
+ charge: input.chargeId,
1001
+ amount: input.amount,
1002
+ reason: input.reason,
1003
+ metadata: input.metadata
1004
+ },
1005
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
1006
+ );
758
1007
  return success(refund);
759
1008
  } catch (error) {
760
1009
  return handleStripeError(error);
@@ -762,6 +1011,7 @@ async function createRefund(input) {
762
1011
  }
763
1012
  async function retrieveRefund(refundId) {
764
1013
  try {
1014
+ validateStripeId(refundId, "refund");
765
1015
  const stripe = getStripe();
766
1016
  const refund = await stripe.refunds.retrieve(refundId);
767
1017
  return success(refund);
@@ -771,9 +1021,10 @@ async function retrieveRefund(refundId) {
771
1021
  }
772
1022
  async function listRefunds(input) {
773
1023
  try {
1024
+ if (input?.paymentIntentId) validateStripeId(input.paymentIntentId, "paymentIntent");
774
1025
  const stripe = getStripe();
775
1026
  const refunds = await stripe.refunds.list({
776
- limit: input?.limit ?? 10,
1027
+ limit: sanitizeLimit(input?.limit),
777
1028
  starting_after: input?.startingAfter,
778
1029
  ending_before: input?.endingBefore,
779
1030
  payment_intent: input?.paymentIntentId,
@@ -786,6 +1037,7 @@ async function listRefunds(input) {
786
1037
  }
787
1038
  async function retrieveDispute(disputeId) {
788
1039
  try {
1040
+ validateStripeId(disputeId, "dispute");
789
1041
  const stripe = getStripe();
790
1042
  const dispute = await stripe.disputes.retrieve(disputeId);
791
1043
  return success(dispute);
@@ -795,6 +1047,8 @@ async function retrieveDispute(disputeId) {
795
1047
  }
796
1048
  async function updateDispute(input) {
797
1049
  try {
1050
+ validateStripeId(input.disputeId, "dispute");
1051
+ if (input.metadata) validateMetadata(input.metadata);
798
1052
  const stripe = getStripe();
799
1053
  const dispute = await stripe.disputes.update(input.disputeId, {
800
1054
  evidence: input.evidence ? {
@@ -816,6 +1070,7 @@ async function updateDispute(input) {
816
1070
  }
817
1071
  async function closeDispute(disputeId) {
818
1072
  try {
1073
+ validateStripeId(disputeId, "dispute");
819
1074
  const stripe = getStripe();
820
1075
  const dispute = await stripe.disputes.close(disputeId);
821
1076
  return success(dispute);
@@ -827,7 +1082,7 @@ async function listDisputes(input) {
827
1082
  try {
828
1083
  const stripe = getStripe();
829
1084
  const disputes = await stripe.disputes.list({
830
- limit: input?.limit ?? 10,
1085
+ limit: sanitizeLimit(input?.limit),
831
1086
  starting_after: input?.startingAfter,
832
1087
  ending_before: input?.endingBefore
833
1088
  });
@@ -838,17 +1093,21 @@ async function listDisputes(input) {
838
1093
  }
839
1094
 
840
1095
  // src/server/connect/index.ts
841
- async function createConnectAccount(input) {
842
- try {
843
- const stripe = getStripe();
844
- const account = await stripe.accounts.create({
845
- type: input.type,
846
- country: input.country,
847
- email: input.email,
848
- capabilities: input.capabilities,
849
- business_type: input.businessType,
850
- metadata: input.metadata
851
- });
1096
+ async function createConnectAccount(input, options) {
1097
+ try {
1098
+ if (input.metadata) validateMetadata(input.metadata);
1099
+ const stripe = getStripe();
1100
+ const account = await stripe.accounts.create(
1101
+ {
1102
+ type: input.type,
1103
+ country: input.country,
1104
+ email: input.email,
1105
+ capabilities: input.capabilities,
1106
+ business_type: input.businessType,
1107
+ metadata: input.metadata
1108
+ },
1109
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
1110
+ );
852
1111
  return success(account);
853
1112
  } catch (error) {
854
1113
  return handleStripeError(error);
@@ -856,6 +1115,7 @@ async function createConnectAccount(input) {
856
1115
  }
857
1116
  async function retrieveConnectAccount(accountId) {
858
1117
  try {
1118
+ validateStripeId(accountId, "account");
859
1119
  const stripe = getStripe();
860
1120
  const account = await stripe.accounts.retrieve(accountId);
861
1121
  return success(account);
@@ -865,6 +1125,7 @@ async function retrieveConnectAccount(accountId) {
865
1125
  }
866
1126
  async function deleteConnectAccount(accountId) {
867
1127
  try {
1128
+ validateStripeId(accountId, "account");
868
1129
  const stripe = getStripe();
869
1130
  const deleted = await stripe.accounts.del(accountId);
870
1131
  return success(deleted);
@@ -876,7 +1137,7 @@ async function listConnectAccounts(input) {
876
1137
  try {
877
1138
  const stripe = getStripe();
878
1139
  const accounts = await stripe.accounts.list({
879
- limit: input?.limit ?? 10,
1140
+ limit: sanitizeLimit(input?.limit),
880
1141
  starting_after: input?.startingAfter,
881
1142
  ending_before: input?.endingBefore
882
1143
  });
@@ -887,6 +1148,9 @@ async function listConnectAccounts(input) {
887
1148
  }
888
1149
  async function createAccountLink(input) {
889
1150
  try {
1151
+ validateStripeId(input.accountId, "account");
1152
+ validateUrl(input.refreshUrl, "refreshUrl");
1153
+ validateUrl(input.returnUrl, "returnUrl");
890
1154
  const stripe = getStripe();
891
1155
  const accountLink = await stripe.accountLinks.create({
892
1156
  account: input.accountId,
@@ -899,17 +1163,24 @@ async function createAccountLink(input) {
899
1163
  return handleStripeError(error);
900
1164
  }
901
1165
  }
902
- async function createTransfer(input) {
1166
+ async function createTransfer(input, options) {
903
1167
  try {
1168
+ validateAmount(input.amount, "transfer amount");
1169
+ validateCurrency(input.currency);
1170
+ validateStripeId(input.destinationAccountId, "account");
1171
+ if (input.metadata) validateMetadata(input.metadata);
904
1172
  const stripe = getStripe();
905
- const transfer = await stripe.transfers.create({
906
- amount: input.amount,
907
- currency: input.currency,
908
- destination: input.destinationAccountId,
909
- description: input.description,
910
- metadata: input.metadata,
911
- source_transaction: input.sourceTransaction
912
- });
1173
+ const transfer = await stripe.transfers.create(
1174
+ {
1175
+ amount: input.amount,
1176
+ currency: input.currency,
1177
+ destination: input.destinationAccountId,
1178
+ description: input.description,
1179
+ metadata: input.metadata,
1180
+ source_transaction: input.sourceTransaction
1181
+ },
1182
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
1183
+ );
913
1184
  return success(transfer);
914
1185
  } catch (error) {
915
1186
  return handleStripeError(error);
@@ -917,9 +1188,10 @@ async function createTransfer(input) {
917
1188
  }
918
1189
  async function listTransfers(input) {
919
1190
  try {
1191
+ if (input?.destinationAccountId) validateStripeId(input.destinationAccountId, "account");
920
1192
  const stripe = getStripe();
921
1193
  const transfers = await stripe.transfers.list({
922
- limit: input?.limit ?? 10,
1194
+ limit: sanitizeLimit(input?.limit),
923
1195
  starting_after: input?.startingAfter,
924
1196
  ending_before: input?.endingBefore,
925
1197
  destination: input?.destinationAccountId
@@ -929,14 +1201,20 @@ async function listTransfers(input) {
929
1201
  return handleStripeError(error);
930
1202
  }
931
1203
  }
932
- async function createPayout(amount, currency, metadata) {
1204
+ async function createPayout(amount, currency, metadata, options) {
933
1205
  try {
1206
+ validateAmount(amount, "payout amount");
1207
+ const normalizedCurrency = validateCurrency(currency);
1208
+ if (metadata) validateMetadata(metadata);
934
1209
  const stripe = getStripe();
935
- const payout = await stripe.payouts.create({
936
- amount,
937
- currency,
938
- metadata
939
- });
1210
+ const payout = await stripe.payouts.create(
1211
+ {
1212
+ amount,
1213
+ currency: normalizedCurrency,
1214
+ metadata
1215
+ },
1216
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
1217
+ );
940
1218
  return success(payout);
941
1219
  } catch (error) {
942
1220
  return handleStripeError(error);
@@ -946,7 +1224,7 @@ async function listPayouts(input) {
946
1224
  try {
947
1225
  const stripe = getStripe();
948
1226
  const payouts = await stripe.payouts.list({
949
- limit: input?.limit ?? 10,
1227
+ limit: sanitizeLimit(input?.limit),
950
1228
  starting_after: input?.startingAfter,
951
1229
  ending_before: input?.endingBefore,
952
1230
  status: input?.status
@@ -969,7 +1247,7 @@ async function listBalanceTransactions(input) {
969
1247
  try {
970
1248
  const stripe = getStripe();
971
1249
  const transactions = await stripe.balanceTransactions.list({
972
- limit: input?.limit ?? 10,
1250
+ limit: sanitizeLimit(input?.limit),
973
1251
  starting_after: input?.startingAfter,
974
1252
  ending_before: input?.endingBefore,
975
1253
  type: input?.type
@@ -981,20 +1259,26 @@ async function listBalanceTransactions(input) {
981
1259
  }
982
1260
 
983
1261
  // src/server/coupons/index.ts
984
- async function createCoupon(input) {
985
- try {
986
- const stripe = getStripe();
987
- const coupon = await stripe.coupons.create({
988
- percent_off: input.percentOff,
989
- amount_off: input.amountOff,
990
- currency: input.currency,
991
- duration: input.duration,
992
- duration_in_months: input.durationInMonths,
993
- max_redemptions: input.maxRedemptions,
994
- redeem_by: input.redeemBy,
995
- name: input.name,
996
- metadata: input.metadata
997
- });
1262
+ async function createCoupon(input, options) {
1263
+ try {
1264
+ if (input.amountOff !== void 0) validateAmount(input.amountOff, "amountOff");
1265
+ if (input.currency) validateCurrency(input.currency);
1266
+ if (input.metadata) validateMetadata(input.metadata);
1267
+ const stripe = getStripe();
1268
+ const coupon = await stripe.coupons.create(
1269
+ {
1270
+ percent_off: input.percentOff,
1271
+ amount_off: input.amountOff,
1272
+ currency: input.currency,
1273
+ duration: input.duration,
1274
+ duration_in_months: input.durationInMonths,
1275
+ max_redemptions: input.maxRedemptions,
1276
+ redeem_by: input.redeemBy,
1277
+ name: input.name,
1278
+ metadata: input.metadata
1279
+ },
1280
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
1281
+ );
998
1282
  return success(coupon);
999
1283
  } catch (error) {
1000
1284
  return handleStripeError(error);
@@ -1002,6 +1286,7 @@ async function createCoupon(input) {
1002
1286
  }
1003
1287
  async function retrieveCoupon(couponId) {
1004
1288
  try {
1289
+ validateStripeId(couponId, "coupon");
1005
1290
  const stripe = getStripe();
1006
1291
  const coupon = await stripe.coupons.retrieve(couponId);
1007
1292
  return success(coupon);
@@ -1011,6 +1296,7 @@ async function retrieveCoupon(couponId) {
1011
1296
  }
1012
1297
  async function deleteCoupon(couponId) {
1013
1298
  try {
1299
+ validateStripeId(couponId, "coupon");
1014
1300
  const stripe = getStripe();
1015
1301
  const deleted = await stripe.coupons.del(couponId);
1016
1302
  return success(deleted);
@@ -1022,7 +1308,7 @@ async function listCoupons(input) {
1022
1308
  try {
1023
1309
  const stripe = getStripe();
1024
1310
  const coupons = await stripe.coupons.list({
1025
- limit: input?.limit ?? 10,
1311
+ limit: sanitizeLimit(input?.limit),
1026
1312
  starting_after: input?.startingAfter,
1027
1313
  ending_before: input?.endingBefore
1028
1314
  });
@@ -1031,22 +1317,32 @@ async function listCoupons(input) {
1031
1317
  return handleStripeError(error);
1032
1318
  }
1033
1319
  }
1034
- async function createPromotionCode(input) {
1320
+ async function createPromotionCode(input, options) {
1035
1321
  try {
1322
+ if (input.metadata) validateMetadata(input.metadata);
1323
+ if (input.restrictions?.minimumAmountCurrency) {
1324
+ validateCurrency(input.restrictions.minimumAmountCurrency);
1325
+ }
1326
+ if (input.restrictions?.minimumAmount !== void 0) {
1327
+ validateAmount(input.restrictions.minimumAmount, "minimumAmount");
1328
+ }
1036
1329
  const stripe = getStripe();
1037
- const promotionCode = await stripe.promotionCodes.create({
1038
- coupon: input.couponId,
1039
- code: input.code,
1040
- active: input.active,
1041
- max_redemptions: input.maxRedemptions,
1042
- expires_at: input.expiresAt,
1043
- metadata: input.metadata,
1044
- restrictions: input.restrictions ? {
1045
- first_time_transaction: input.restrictions.firstTimeTransaction,
1046
- minimum_amount: input.restrictions.minimumAmount,
1047
- minimum_amount_currency: input.restrictions.minimumAmountCurrency
1048
- } : void 0
1049
- });
1330
+ const promotionCode = await stripe.promotionCodes.create(
1331
+ {
1332
+ coupon: input.couponId,
1333
+ code: input.code,
1334
+ active: input.active,
1335
+ max_redemptions: input.maxRedemptions,
1336
+ expires_at: input.expiresAt,
1337
+ metadata: input.metadata,
1338
+ restrictions: input.restrictions ? {
1339
+ first_time_transaction: input.restrictions.firstTimeTransaction,
1340
+ minimum_amount: input.restrictions.minimumAmount,
1341
+ minimum_amount_currency: input.restrictions.minimumAmountCurrency
1342
+ } : void 0
1343
+ },
1344
+ options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : void 0
1345
+ );
1050
1346
  return success(promotionCode);
1051
1347
  } catch (error) {
1052
1348
  return handleStripeError(error);
@@ -1054,6 +1350,7 @@ async function createPromotionCode(input) {
1054
1350
  }
1055
1351
  async function retrievePromotionCode(promotionCodeId) {
1056
1352
  try {
1353
+ validateStripeId(promotionCodeId, "promotionCode");
1057
1354
  const stripe = getStripe();
1058
1355
  const promotionCode = await stripe.promotionCodes.retrieve(promotionCodeId);
1059
1356
  return success(promotionCode);
@@ -1065,7 +1362,7 @@ async function listPromotionCodes(input) {
1065
1362
  try {
1066
1363
  const stripe = getStripe();
1067
1364
  const promotionCodes = await stripe.promotionCodes.list({
1068
- limit: input?.limit ?? 10,
1365
+ limit: sanitizeLimit(input?.limit),
1069
1366
  starting_after: input?.startingAfter,
1070
1367
  ending_before: input?.endingBefore,
1071
1368
  coupon: input?.couponId,
@@ -1119,6 +1416,9 @@ function createWebhookHandler(config) {
1119
1416
  function createNextWebhookHandler(config) {
1120
1417
  const handler = createWebhookHandler(config);
1121
1418
  return async function POST(request) {
1419
+ if (request.method !== "POST") {
1420
+ return new Response(null, { status: 405 });
1421
+ }
1122
1422
  try {
1123
1423
  const contentLength = request.headers.get("content-length");
1124
1424
  if (contentLength && parseInt(contentLength, 10) > MAX_BODY_SIZE) {
@@ -1128,6 +1428,12 @@ function createNextWebhookHandler(config) {
1128
1428
  });
1129
1429
  }
1130
1430
  const body = await request.text();
1431
+ if (body.length > MAX_BODY_SIZE) {
1432
+ return new Response(JSON.stringify({ error: "Webhook body too large" }), {
1433
+ status: 413,
1434
+ headers: { "Content-Type": "application/json" }
1435
+ });
1436
+ }
1131
1437
  const signature = request.headers.get("stripe-signature");
1132
1438
  if (!signature) {
1133
1439
  return new Response(JSON.stringify({ error: "Missing stripe-signature header" }), {
@@ -1141,8 +1447,8 @@ function createNextWebhookHandler(config) {
1141
1447
  headers: { "Content-Type": "application/json" }
1142
1448
  });
1143
1449
  } catch (error) {
1144
- const message = error instanceof Error ? error.message : "Webhook handler failed";
1145
- return new Response(JSON.stringify({ error: message }), {
1450
+ console.error("[@stripe-sdk/core] Webhook error:", error instanceof Error ? error.message : "Unknown error");
1451
+ return new Response(JSON.stringify({ error: "Webhook processing failed" }), {
1146
1452
  status: 400,
1147
1453
  headers: { "Content-Type": "application/json" }
1148
1454
  });
@@ -1166,8 +1472,8 @@ function createPagesWebhookHandler(webhookConfig) {
1166
1472
  const result = await handler(body, signature);
1167
1473
  res.status(200).json(result);
1168
1474
  } catch (error) {
1169
- const message = error instanceof Error ? error.message : "Webhook handler failed";
1170
- res.status(400).json({ error: message });
1475
+ console.error("[@stripe-sdk/core] Webhook error:", error instanceof Error ? error.message : "Unknown error");
1476
+ res.status(400).json({ error: "Webhook processing failed" });
1171
1477
  }
1172
1478
  };
1173
1479
  }
@@ -1195,16 +1501,21 @@ function getRawBody(req) {
1195
1501
  }
1196
1502
  const chunks = [];
1197
1503
  let totalLength = 0;
1504
+ let rejected = false;
1198
1505
  req.on("data", (chunk) => {
1506
+ if (rejected) return;
1199
1507
  const buf = Buffer.from(chunk);
1200
1508
  totalLength += buf.length;
1201
1509
  if (totalLength > MAX_BODY_SIZE) {
1510
+ rejected = true;
1202
1511
  reject(new Error("Webhook body too large"));
1203
1512
  return;
1204
1513
  }
1205
1514
  chunks.push(buf);
1206
1515
  });
1207
- req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
1516
+ req.on("end", () => {
1517
+ if (!rejected) resolve(Buffer.concat(chunks).toString("utf8"));
1518
+ });
1208
1519
  req.on("error", reject);
1209
1520
  });
1210
1521
  }
@@ -1286,5 +1597,3 @@ exports.updateDispute = updateDispute;
1286
1597
  exports.updateProduct = updateProduct;
1287
1598
  exports.updateSubscription = updateSubscription;
1288
1599
  exports.voidInvoice = voidInvoice;
1289
- //# sourceMappingURL=index.js.map
1290
- //# sourceMappingURL=index.js.map