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