payweave 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/dist/_tsup-dts-rollup.d.ts +19470 -0
  4. package/dist/chunk-4R5OGOCC.js +94 -0
  5. package/dist/chunk-4R5OGOCC.js.map +1 -0
  6. package/dist/chunk-535Q3GUN.js +175 -0
  7. package/dist/chunk-535Q3GUN.js.map +1 -0
  8. package/dist/chunk-67NRYGRC.js +192 -0
  9. package/dist/chunk-67NRYGRC.js.map +1 -0
  10. package/dist/chunk-CGQ73I4I.js +568 -0
  11. package/dist/chunk-CGQ73I4I.js.map +1 -0
  12. package/dist/chunk-CJEYDHY6.js +18 -0
  13. package/dist/chunk-CJEYDHY6.js.map +1 -0
  14. package/dist/chunk-CR63JAAS.js +3 -0
  15. package/dist/chunk-CR63JAAS.js.map +1 -0
  16. package/dist/chunk-E633MKVX.js +1507 -0
  17. package/dist/chunk-E633MKVX.js.map +1 -0
  18. package/dist/chunk-FBPOCXRZ.js +1135 -0
  19. package/dist/chunk-FBPOCXRZ.js.map +1 -0
  20. package/dist/chunk-HTRGMZFH.js +267 -0
  21. package/dist/chunk-HTRGMZFH.js.map +1 -0
  22. package/dist/chunk-IUVGM3K7.js +765 -0
  23. package/dist/chunk-IUVGM3K7.js.map +1 -0
  24. package/dist/chunk-JD4OZHRI.js +326 -0
  25. package/dist/chunk-JD4OZHRI.js.map +1 -0
  26. package/dist/chunk-NV3MZF7L.js +139 -0
  27. package/dist/chunk-NV3MZF7L.js.map +1 -0
  28. package/dist/chunk-NXQBP35U.js +13 -0
  29. package/dist/chunk-NXQBP35U.js.map +1 -0
  30. package/dist/chunk-QJHXDZYC.js +412 -0
  31. package/dist/chunk-QJHXDZYC.js.map +1 -0
  32. package/dist/chunk-TWZK62TZ.js +83 -0
  33. package/dist/chunk-TWZK62TZ.js.map +1 -0
  34. package/dist/cli/index.js +35381 -0
  35. package/dist/core/index.d.ts +85 -0
  36. package/dist/core/index.js +6 -0
  37. package/dist/core/index.js.map +1 -0
  38. package/dist/db/drizzle/index.d.ts +6 -0
  39. package/dist/db/drizzle/index.js +1532 -0
  40. package/dist/db/drizzle/index.js.map +1 -0
  41. package/dist/db/index.d.ts +43 -0
  42. package/dist/db/index.js +3 -0
  43. package/dist/db/index.js.map +1 -0
  44. package/dist/db/mongodb/index.d.ts +3 -0
  45. package/dist/db/mongodb/index.js +934 -0
  46. package/dist/db/mongodb/index.js.map +1 -0
  47. package/dist/db/mysql/index.d.ts +1 -0
  48. package/dist/db/mysql/index.js +12 -0
  49. package/dist/db/mysql/index.js.map +1 -0
  50. package/dist/db/postgres/index.d.ts +5 -0
  51. package/dist/db/postgres/index.js +791 -0
  52. package/dist/db/postgres/index.js.map +1 -0
  53. package/dist/db/prisma/index.d.ts +1 -0
  54. package/dist/db/prisma/index.js +12 -0
  55. package/dist/db/prisma/index.js.map +1 -0
  56. package/dist/db/sqlite/index.d.ts +5 -0
  57. package/dist/db/sqlite/index.js +750 -0
  58. package/dist/db/sqlite/index.js.map +1 -0
  59. package/dist/express/index.d.ts +1 -0
  60. package/dist/express/index.js +3 -0
  61. package/dist/express/index.js.map +1 -0
  62. package/dist/fastify/index.d.ts +1 -0
  63. package/dist/fastify/index.js +3 -0
  64. package/dist/fastify/index.js.map +1 -0
  65. package/dist/flutterwave/index.d.ts +27 -0
  66. package/dist/flutterwave/index.js +9 -0
  67. package/dist/flutterwave/index.js.map +1 -0
  68. package/dist/index.d.ts +85 -0
  69. package/dist/index.js +3677 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/next/index.d.ts +1 -0
  72. package/dist/next/index.js +3 -0
  73. package/dist/next/index.js.map +1 -0
  74. package/dist/paystack/index.d.ts +33 -0
  75. package/dist/paystack/index.js +9 -0
  76. package/dist/paystack/index.js.map +1 -0
  77. package/dist/products/index.d.ts +22 -0
  78. package/dist/products/index.js +7 -0
  79. package/dist/products/index.js.map +1 -0
  80. package/dist/testing/index.d.ts +11 -0
  81. package/dist/testing/index.js +69 -0
  82. package/dist/testing/index.js.map +1 -0
  83. package/dist/unified/index.d.ts +41 -0
  84. package/dist/unified/index.js +6 -0
  85. package/dist/unified/index.js.map +1 -0
  86. package/dist/webhooks/index.d.ts +8 -0
  87. package/dist/webhooks/index.js +8 -0
  88. package/dist/webhooks/index.js.map +1 -0
  89. package/package.json +164 -0
package/dist/index.js ADDED
@@ -0,0 +1,3677 @@
1
+ import './chunk-CR63JAAS.js';
2
+ import { PaystackClient } from './chunk-E633MKVX.js';
3
+ export { PaystackClient } from './chunk-E633MKVX.js';
4
+ import { FlutterwaveClient } from './chunk-FBPOCXRZ.js';
5
+ export { FlutterwaveClient } from './chunk-FBPOCXRZ.js';
6
+ import { defineProvider, STRIPE_BASE_URL, stripeProviderConfigSchema, readHeader, inferEnvironment, HttpClient, STRIPE_API_VERSION, resolvePayweaveConfig, SDK_VERSION, oauthClientCredentials, bearer } from './chunk-IUVGM3K7.js';
7
+ export { SDK_VERSION as VERSION } from './chunk-IUVGM3K7.js';
8
+ export { feature, plan } from './chunk-535Q3GUN.js';
9
+ import { createPaystackUnified, createFlutterwaveUnified } from './chunk-JD4OZHRI.js';
10
+ import './chunk-TWZK62TZ.js';
11
+ import { verifyStripe, subscribe, constructEvent, resolvePlanGroup, BILLING_CAPABLE_PROVIDERS } from './chunk-CGQ73I4I.js';
12
+ import './chunk-4R5OGOCC.js';
13
+ import { verifyPaystack } from './chunk-NXQBP35U.js';
14
+ import { verifyFlutterwaveV4, verifyFlutterwaveV3 } from './chunk-CJEYDHY6.js';
15
+ import { toUnifiedEventType, UNIFIED_CAPABILITY_MATRIX, assertUnifiedCapability } from './chunk-67NRYGRC.js';
16
+ import { PayweaveConfigError, PayweaveValidationError, PayweaveWebhookVerificationError, PayweaveProviderError, PayweaveError } from './chunk-HTRGMZFH.js';
17
+ export { PayweaveAuthError, PayweaveConfigError, PayweaveError, PayweaveNetworkError, PayweaveNotFoundError, PayweaveProviderError, PayweaveRateLimitError, PayweaveValidationError, PayweaveWebhookVerificationError } from './chunk-HTRGMZFH.js';
18
+ import { z } from 'zod';
19
+ import { createHash } from 'crypto';
20
+
21
+ // src/webhooks/dispatch.ts
22
+ var SIGNATURE_HEADER_TABLE = [
23
+ { headerName: "x-paystack-signature", provider: "paystack" },
24
+ { headerName: "verif-hash", provider: "flutterwave", flutterwaveVersion: "v3" },
25
+ { headerName: "flutterwave-signature", provider: "flutterwave", flutterwaveVersion: "v4" },
26
+ { headerName: "stripe-signature", provider: "stripe" }
27
+ ];
28
+ var KNOWN_HEADER_NAMES = SIGNATURE_HEADER_TABLE.map((spec) => spec.headerName).join(", ");
29
+ function detectSignatureHeader(headers) {
30
+ const found = [];
31
+ for (const spec of SIGNATURE_HEADER_TABLE) {
32
+ const value = readHeader(headers, spec.headerName);
33
+ if (value !== void 0) found.push({ spec, value });
34
+ }
35
+ const [only, ...rest] = found;
36
+ if (only === void 0) {
37
+ throw new PayweaveWebhookVerificationError(
38
+ `No known webhook signature header on the request \u2014 expected exactly one of: ${KNOWN_HEADER_NAMES}.`,
39
+ { provider: "unknown", isRetryable: false }
40
+ );
41
+ }
42
+ if (rest.length > 0) {
43
+ const names = found.map((f) => f.spec.headerName).join(", ");
44
+ throw new PayweaveWebhookVerificationError(
45
+ `Multiple known webhook signature headers on one request (${names}) \u2014 ambiguous and likely forged; rejecting.`,
46
+ { provider: "unknown", isRetryable: false }
47
+ );
48
+ }
49
+ return only;
50
+ }
51
+ function requireConfigured(resolved, spec) {
52
+ const entry = resolved.providerConfigs[spec.provider];
53
+ if (entry === void 0) {
54
+ throw new PayweaveWebhookVerificationError(
55
+ `Received a "${spec.headerName}" header but ${spec.provider} is not configured on this client (configured: ${resolved.providers.join(", ")}) \u2014 failing closed.`,
56
+ { provider: spec.provider, isRetryable: false }
57
+ );
58
+ }
59
+ if (spec.provider === "flutterwave") {
60
+ const configuredVersion = entry.version === "v4" ? "v4" : "v3";
61
+ if (spec.flutterwaveVersion !== configuredVersion) {
62
+ throw new PayweaveWebhookVerificationError(
63
+ `Received the Flutterwave ${spec.flutterwaveVersion} signature header ("${spec.headerName}") but this client is configured for Flutterwave ${configuredVersion} \u2014 a client verifies webhooks only with its own version's scheme; failing closed.`,
64
+ { provider: "flutterwave", isRetryable: false }
65
+ );
66
+ }
67
+ }
68
+ return entry;
69
+ }
70
+ function verifyDetected(entry, spec, input) {
71
+ if (spec.provider === "paystack") {
72
+ const secret = entry.webhookSecret ?? entry.secretKey;
73
+ if (!secret) {
74
+ throw new PayweaveConfigError("Missing Paystack secret key for webhook verification.", {
75
+ provider: "paystack"
76
+ });
77
+ }
78
+ return verifyPaystack(input.rawBody, readHeader(input.headers, spec.headerName), secret);
79
+ }
80
+ if (spec.provider === "flutterwave") {
81
+ if (!entry.webhookSecret) {
82
+ throw new PayweaveConfigError(
83
+ "Flutterwave webhook verification requires `webhookSecret` (the dashboard secret hash).",
84
+ { provider: "flutterwave" }
85
+ );
86
+ }
87
+ if (spec.flutterwaveVersion === "v4") {
88
+ return verifyFlutterwaveV4(
89
+ input.rawBody,
90
+ readHeader(input.headers, spec.headerName),
91
+ entry.webhookSecret
92
+ );
93
+ }
94
+ return verifyFlutterwaveV3(readHeader(input.headers, spec.headerName), entry.webhookSecret);
95
+ }
96
+ if (!entry.webhookSecret) {
97
+ throw new PayweaveConfigError(
98
+ "Stripe webhook verification requires `webhookSecret` (the endpoint signing secret, `whsec_*`).",
99
+ { provider: "stripe" }
100
+ );
101
+ }
102
+ return verifyStripe(input.rawBody, readHeader(input.headers, spec.headerName), entry.webhookSecret);
103
+ }
104
+ function createWebhookDispatch(resolved, billing) {
105
+ function dispatch(headers) {
106
+ const { spec } = detectSignatureHeader(headers);
107
+ return { spec, entry: requireConfigured(resolved, spec) };
108
+ }
109
+ function verify(input) {
110
+ const { spec, entry } = dispatch(input.headers);
111
+ return verifyDetected(entry, spec, input);
112
+ }
113
+ return {
114
+ verify,
115
+ verifyOrThrow(input) {
116
+ const { spec, entry } = dispatch(input.headers);
117
+ if (!verifyDetected(entry, spec, input)) {
118
+ throw new PayweaveWebhookVerificationError("Webhook signature verification failed.", {
119
+ provider: spec.provider,
120
+ isRetryable: false
121
+ });
122
+ }
123
+ },
124
+ constructEvent(input) {
125
+ const { spec, entry } = dispatch(input.headers);
126
+ const version = spec.provider === "flutterwave" ? entry.version === "v4" ? "v4" : "v3" : void 0;
127
+ return constructEvent({
128
+ rawBody: input.rawBody,
129
+ headers: input.headers,
130
+ provider: spec.provider,
131
+ version,
132
+ verify: (i) => verifyDetected(entry, spec, i),
133
+ logger: entry.logger,
134
+ billing
135
+ });
136
+ }
137
+ };
138
+ }
139
+
140
+ // src/stripe/form-encoding.ts
141
+ var STRIPE_FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
142
+ function isPlainObject(value) {
143
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
144
+ const proto = Object.getPrototypeOf(value);
145
+ return proto === Object.prototype || proto === null;
146
+ }
147
+ function describe(value) {
148
+ if (typeof value === "number") return `non-finite number ${String(value)}`;
149
+ if (value instanceof Date) return "Date (pass a Unix timestamp in seconds instead)";
150
+ return `unsupported value of type ${typeof value}`;
151
+ }
152
+ function unsupported(path, value) {
153
+ return new PayweaveValidationError(
154
+ `Cannot form-encode "${path}" for Stripe: ${describe(value)}.`,
155
+ { provider: "stripe" }
156
+ );
157
+ }
158
+ function appendPairs(pairs, key, value) {
159
+ if (value === void 0 || value === null) return;
160
+ switch (typeof value) {
161
+ case "string":
162
+ pairs.push(`${key}=${encodeURIComponent(value)}`);
163
+ return;
164
+ case "boolean":
165
+ pairs.push(`${key}=${value ? "true" : "false"}`);
166
+ return;
167
+ case "number":
168
+ if (!Number.isFinite(value)) throw unsupported(key, value);
169
+ pairs.push(`${key}=${encodeURIComponent(String(value))}`);
170
+ return;
171
+ }
172
+ if (Array.isArray(value)) {
173
+ for (let i = 0; i < value.length; i += 1) {
174
+ appendPairs(pairs, `${key}[${i}]`, value[i]);
175
+ }
176
+ return;
177
+ }
178
+ if (isPlainObject(value)) {
179
+ for (const [childKey, childValue] of Object.entries(value)) {
180
+ appendPairs(pairs, `${key}[${encodeURIComponent(childKey)}]`, childValue);
181
+ }
182
+ return;
183
+ }
184
+ throw unsupported(key, value);
185
+ }
186
+ function encodeStripeForm(body) {
187
+ if (!isPlainObject(body)) {
188
+ throw new PayweaveValidationError(
189
+ "Stripe request bodies must be plain objects (validated by the request schema before encoding).",
190
+ { provider: "stripe" }
191
+ );
192
+ }
193
+ const pairs = [];
194
+ for (const [key, value] of Object.entries(body)) {
195
+ appendPairs(pairs, encodeURIComponent(key), value);
196
+ }
197
+ return { contentType: STRIPE_FORM_CONTENT_TYPE, body: pairs.join("&") };
198
+ }
199
+
200
+ // src/stripe/http-options.ts
201
+ function stripeAuth(opts) {
202
+ const version = opts.apiVersion ?? STRIPE_API_VERSION;
203
+ return {
204
+ async applyAuth(init) {
205
+ init.headers.set("Authorization", `Bearer ${opts.secretKey}`);
206
+ init.headers.set("Stripe-Version", version);
207
+ if (opts.accountId !== void 0) {
208
+ init.headers.set("Stripe-Account", opts.accountId);
209
+ }
210
+ }
211
+ };
212
+ }
213
+ function stripeHttpOptions(resolved) {
214
+ if (resolved.provider !== "stripe") {
215
+ throw new PayweaveConfigError(
216
+ `stripeHttpOptions received a "${resolved.provider}" config \u2014 expected provider "stripe".`,
217
+ { provider: "stripe" }
218
+ );
219
+ }
220
+ if (resolved.secretKey === void 0) {
221
+ throw new PayweaveConfigError("Stripe config resolved without a secretKey.", {
222
+ provider: "stripe"
223
+ });
224
+ }
225
+ return {
226
+ baseUrl: resolved.baseUrl,
227
+ provider: "stripe",
228
+ auth: stripeAuth({
229
+ secretKey: resolved.secretKey,
230
+ apiVersion: resolved.apiVersion,
231
+ accountId: resolved.accountId
232
+ }),
233
+ bodyEncoder: encodeStripeForm,
234
+ timeoutMs: resolved.timeoutMs,
235
+ maxRetries: resolved.maxRetries,
236
+ fetch: resolved.fetch,
237
+ logger: resolved.logger
238
+ };
239
+ }
240
+ function parseRequest(schema, input) {
241
+ try {
242
+ return schema.parse(input);
243
+ } catch (err) {
244
+ if (err instanceof z.ZodError) {
245
+ const detail = err.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
246
+ throw new PayweaveValidationError(`stripe request validation failed \u2014 ${detail}`, {
247
+ provider: "stripe",
248
+ cause: err
249
+ });
250
+ }
251
+ throw err;
252
+ }
253
+ }
254
+ var metadataSchema = z.record(
255
+ z.string(),
256
+ z.union([z.string(), z.number(), z.boolean()])
257
+ );
258
+ var createdRange = z.object({
259
+ gt: z.number().int().optional(),
260
+ gte: z.number().int().optional(),
261
+ lt: z.number().int().optional(),
262
+ lte: z.number().int().optional()
263
+ });
264
+ var listCursorFields = {
265
+ /** Page size, 1–100 (Stripe default 10). */
266
+ limit: z.number().int().min(1).max(100).optional(),
267
+ /** Cursor: object id — return items AFTER this id (next page). */
268
+ starting_after: z.string().optional(),
269
+ /** Cursor: object id — return items BEFORE this id (previous page). */
270
+ ending_before: z.string().optional()
271
+ };
272
+ var stripeList = (item) => z.looseObject({
273
+ object: z.string(),
274
+ data: z.array(item),
275
+ has_more: z.boolean(),
276
+ url: z.string().optional()
277
+ });
278
+ async function* iterateStripeList(fetchPage) {
279
+ let startingAfter;
280
+ for (; ; ) {
281
+ const page = await fetchPage(startingAfter);
282
+ for (const item of page.data) yield item;
283
+ const last = page.data[page.data.length - 1];
284
+ if (!page.has_more || last === void 0) return;
285
+ startingAfter = last.id;
286
+ }
287
+ }
288
+ function flattenQuery(query) {
289
+ const out = {};
290
+ for (const [key, value] of Object.entries(query)) {
291
+ if (value === void 0 || value === null) continue;
292
+ if (typeof value === "object" && !Array.isArray(value)) {
293
+ for (const [childKey, childValue] of Object.entries(value)) {
294
+ if (childValue === void 0 || childValue === null) continue;
295
+ out[`${key}[${childKey}]`] = childValue;
296
+ }
297
+ continue;
298
+ }
299
+ out[key] = value;
300
+ }
301
+ return out;
302
+ }
303
+ function requireId(value, what) {
304
+ return parseRequest(z.string().min(1, `${what} id must be a non-empty string`), value);
305
+ }
306
+ var stripeSearchResult = (item) => z.looseObject({
307
+ object: z.string(),
308
+ data: z.array(item),
309
+ has_more: z.boolean(),
310
+ next_page: z.string().nullable().optional(),
311
+ url: z.string().optional(),
312
+ total_count: z.number().optional()
313
+ });
314
+ async function* iterateStripeSearch(fetchPage) {
315
+ let page;
316
+ for (; ; ) {
317
+ const result = await fetchPage(page);
318
+ for (const item of result.data) yield item;
319
+ if (!result.has_more || result.next_page == null) return;
320
+ page = result.next_page;
321
+ }
322
+ }
323
+ var productData = z.object({
324
+ /** Product name — required by Stripe when creating a product inline. */
325
+ name: z.string(),
326
+ description: z.string().optional(),
327
+ images: z.array(z.string()).optional(),
328
+ metadata: metadataSchema.optional(),
329
+ tax_code: z.string().optional()
330
+ });
331
+ var recurring = z.object({
332
+ interval: z.enum(["day", "week", "month", "year"]),
333
+ interval_count: z.number().int().optional()
334
+ });
335
+ var priceData = z.object({
336
+ /** Three-letter ISO currency code, lowercase (e.g. `usd`). */
337
+ currency: z.string(),
338
+ /** Amount in the smallest currency unit (minor units) — integer, unchanged. */
339
+ unit_amount: z.number().int().nonnegative().optional(),
340
+ /** Decimal string alternative to `unit_amount` (e.g. fractional cents). */
341
+ unit_amount_decimal: z.string().optional(),
342
+ /** Existing Product id (`prod_*`) the price belongs to. */
343
+ product: z.string().optional(),
344
+ /** Inline Product creation (alternative to `product`). */
345
+ product_data: productData.optional(),
346
+ /** Present only for `subscription` mode line items. */
347
+ recurring: recurring.optional(),
348
+ tax_behavior: z.enum(["inclusive", "exclusive", "unspecified"]).optional()
349
+ });
350
+ var lineItemInput = z.object({
351
+ /** Saved Price (or Plan) id (`price_*`). Alternative to `price_data`. */
352
+ price: z.string().optional(),
353
+ /** Inline price definition. Alternative to `price`. */
354
+ price_data: priceData.optional(),
355
+ quantity: z.number().int().optional(),
356
+ /** Let the customer adjust the quantity in Checkout. */
357
+ adjustable_quantity: z.object({
358
+ enabled: z.boolean(),
359
+ minimum: z.number().int().optional(),
360
+ maximum: z.number().int().optional()
361
+ }).optional(),
362
+ /** Tax Rate ids applied to this line item. */
363
+ tax_rates: z.array(z.string()).optional(),
364
+ metadata: metadataSchema.optional()
365
+ });
366
+ var paymentIntentData = z.object({
367
+ capture_method: z.enum(["automatic", "automatic_async", "manual"]).optional(),
368
+ setup_future_usage: z.enum(["on_session", "off_session"]).optional(),
369
+ statement_descriptor: z.string().optional(),
370
+ statement_descriptor_suffix: z.string().optional(),
371
+ receipt_email: z.string().optional(),
372
+ metadata: metadataSchema.optional()
373
+ });
374
+ var sessionCreateReq = z.object({
375
+ /** Session mode — determines what the session sets up. Required. */
376
+ mode: z.enum(["payment", "setup", "subscription"]),
377
+ /** Items being purchased. Required for `payment`/`subscription` modes. */
378
+ line_items: z.array(lineItemInput).optional(),
379
+ /** Redirect target after a successful session (hosted page). */
380
+ success_url: z.string().optional(),
381
+ /** Redirect target when the customer cancels (hosted page). */
382
+ cancel_url: z.string().optional(),
383
+ /** Return target for embedded UI modes. */
384
+ return_url: z.string().optional(),
385
+ /** Checkout UI surface (see the JSDoc above for version-pinned values). */
386
+ ui_mode: z.enum(["hosted_page", "embedded_page", "elements"]).optional(),
387
+ /** Your internal reference for this session (≤200 chars). */
388
+ client_reference_id: z.string().max(200).optional(),
389
+ /** Existing Customer id (`cus_*`) to prefill. */
390
+ customer: z.string().optional(),
391
+ /** Email to prefill when no `customer` is given (≤800 chars). */
392
+ customer_email: z.string().max(800).optional(),
393
+ customer_creation: z.enum(["always", "if_required"]).optional(),
394
+ /** Three-letter ISO currency code — required in some `setup`-mode cases. */
395
+ currency: z.string().optional(),
396
+ /** Payment method types to accept (e.g. `["card"]`). Provider-validated. */
397
+ payment_method_types: z.array(z.string()).optional(),
398
+ metadata: metadataSchema.optional(),
399
+ /** Unix timestamp — 30 minutes to 24 hours after creation. */
400
+ expires_at: z.number().int().optional(),
401
+ payment_intent_data: paymentIntentData.optional(),
402
+ billing_address_collection: z.enum(["auto", "required"]).optional(),
403
+ allow_promotion_codes: z.boolean().optional()
404
+ });
405
+ var checkoutSession = z.looseObject({
406
+ id: z.string(),
407
+ object: z.string().optional(),
408
+ /** `open` | `complete` | `expired` (normalization is the unified layer's job). */
409
+ status: z.string().nullable().optional(),
410
+ /** `paid` | `unpaid` | `no_payment_required`. */
411
+ payment_status: z.string().optional(),
412
+ mode: z.string().optional(),
413
+ /** Hosted checkout URL — null once the session is no longer open. */
414
+ url: z.string().nullable().optional(),
415
+ client_reference_id: z.string().nullable().optional(),
416
+ /** Customer id string, or an expanded object — kept unknown. */
417
+ customer: z.unknown().optional(),
418
+ customer_email: z.string().nullable().optional(),
419
+ /** PaymentIntent id string, or an expanded object — kept unknown. */
420
+ payment_intent: z.unknown().optional(),
421
+ /** Integer minor units. */
422
+ amount_subtotal: z.number().nullable().optional(),
423
+ /** Integer minor units. */
424
+ amount_total: z.number().nullable().optional(),
425
+ currency: z.string().nullable().optional(),
426
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
427
+ success_url: z.string().nullable().optional(),
428
+ cancel_url: z.string().nullable().optional(),
429
+ created: z.number().optional(),
430
+ expires_at: z.number().optional(),
431
+ livemode: z.boolean().optional()
432
+ });
433
+ var sessionListQuery = z.object({
434
+ ...listCursorFields,
435
+ /** Filter by Customer id. */
436
+ customer: z.string().optional(),
437
+ /** Filter by customer email (`customer_details[email]`, ≤800 chars). */
438
+ customer_details: z.object({ email: z.string().max(800) }).optional(),
439
+ /** Filter by PaymentIntent id. */
440
+ payment_intent: z.string().optional(),
441
+ /** Filter by Payment Link id. */
442
+ payment_link: z.string().optional(),
443
+ /** Filter by Subscription id. */
444
+ subscription: z.string().optional(),
445
+ status: z.enum(["open", "complete", "expired"]).optional(),
446
+ /** Creation-date window (Unix timestamps). */
447
+ created: createdRange.optional()
448
+ });
449
+ var sessionLineItem = z.looseObject({
450
+ id: z.string(),
451
+ object: z.string().optional(),
452
+ amount_discount: z.number().optional(),
453
+ amount_subtotal: z.number().optional(),
454
+ amount_tax: z.number().optional(),
455
+ amount_total: z.number().optional(),
456
+ currency: z.string().optional(),
457
+ description: z.string().nullable().optional(),
458
+ /** The Price object backing this item — kept loose. */
459
+ price: z.looseObject({}).nullable().optional(),
460
+ quantity: z.number().nullable().optional()
461
+ });
462
+ var lineItemsQuery = z.object({ ...listCursorFields });
463
+
464
+ // src/stripe/resources/checkout-sessions.ts
465
+ var sessionListRes = stripeList(checkoutSession);
466
+ var lineItemListRes = stripeList(sessionLineItem);
467
+ var CheckoutSessions = class {
468
+ constructor(http) {
469
+ this.http = http;
470
+ }
471
+ http;
472
+ /**
473
+ * Create a Checkout Session. `session.url` is the hosted checkout page to
474
+ * redirect the customer to. Amounts (`price_data.unit_amount`) are integer
475
+ * minor units, sent to Stripe unchanged. Pass `idempotencyKey` to make the
476
+ * POST safely replayable (and retry-eligible).
477
+ *
478
+ * Docs: https://docs.stripe.com/api/checkout/sessions/create
479
+ *
480
+ * @example
481
+ * const session = await payweave.stripe.checkout.sessions.create({
482
+ * mode: "payment",
483
+ * line_items: [{ price: "price_123", quantity: 2 }],
484
+ * success_url: "https://example.com/success",
485
+ * cancel_url: "https://example.com/cancel",
486
+ * }, { idempotencyKey: "order-8123-checkout" });
487
+ * console.log(session.url);
488
+ */
489
+ async create(input, opts = {}) {
490
+ const body = parseRequest(sessionCreateReq, input);
491
+ return this.http.request({
492
+ method: "POST",
493
+ path: "/v1/checkout/sessions",
494
+ body,
495
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
496
+ schema: checkoutSession
497
+ });
498
+ }
499
+ /**
500
+ * Retrieve a Checkout Session by id (`cs_*`). A 404 for an unknown id
501
+ * surfaces as {@link PayweaveNotFoundError}. Note `session.url` is null once
502
+ * the session is no longer open.
503
+ *
504
+ * Docs: https://docs.stripe.com/api/checkout/sessions/retrieve
505
+ *
506
+ * @example
507
+ * const session = await payweave.stripe.checkout.sessions.retrieve("cs_test_123");
508
+ * if (session.payment_status === "paid") { }
509
+ */
510
+ async retrieve(id) {
511
+ const sessionId = requireId(id, "checkout session");
512
+ return this.http.request({
513
+ method: "GET",
514
+ path: `/v1/checkout/sessions/${encodeURIComponent(sessionId)}`,
515
+ schema: checkoutSession
516
+ });
517
+ }
518
+ /**
519
+ * List Checkout Sessions (newest first). Cursor pagination: `limit` +
520
+ * `starting_after`/`ending_before`; nested filters (`created`,
521
+ * `customer_details`) become bracket query keys.
522
+ *
523
+ * Docs: https://docs.stripe.com/api/checkout/sessions/list
524
+ *
525
+ * @example
526
+ * const page = await payweave.stripe.checkout.sessions.list({ status: "complete", limit: 50 });
527
+ * console.log(page.data.length, page.has_more);
528
+ */
529
+ async list(query = {}) {
530
+ const q = parseRequest(sessionListQuery, query);
531
+ return this.http.request({
532
+ method: "GET",
533
+ path: "/v1/checkout/sessions",
534
+ query: flattenQuery(q),
535
+ schema: sessionListRes
536
+ });
537
+ }
538
+ /**
539
+ * Async iterator over ALL sessions matching `query`, transparently following
540
+ * `has_more` with `starting_after = <last id>`.
541
+ *
542
+ * Docs: https://docs.stripe.com/api/checkout/sessions/list
543
+ *
544
+ * @example
545
+ * for await (const session of payweave.stripe.checkout.sessions.iterate({ status: "open" })) {
546
+ * console.log(session.id);
547
+ * }
548
+ */
549
+ async *iterate(query = {}) {
550
+ const base = parseRequest(sessionListQuery, query);
551
+ yield* iterateStripeList(
552
+ (startingAfter) => this.http.request({
553
+ method: "GET",
554
+ path: "/v1/checkout/sessions",
555
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
556
+ schema: sessionListRes
557
+ })
558
+ );
559
+ }
560
+ /**
561
+ * Expire an OPEN Checkout Session so it can no longer be paid — Stripe
562
+ * errors when the session is not `open` (surfaced as
563
+ * {@link PayweaveValidationError} on the 400). Returns the session with
564
+ * `status: "expired"`.
565
+ *
566
+ * Docs: https://docs.stripe.com/api/checkout/sessions/expire
567
+ *
568
+ * @example
569
+ * const expired = await payweave.stripe.checkout.sessions.expire("cs_test_123");
570
+ * console.log(expired.status); // "expired"
571
+ */
572
+ async expire(id) {
573
+ const sessionId = requireId(id, "checkout session");
574
+ return this.http.request({
575
+ method: "POST",
576
+ path: `/v1/checkout/sessions/${encodeURIComponent(sessionId)}/expire`,
577
+ schema: checkoutSession
578
+ });
579
+ }
580
+ /**
581
+ * List a session's line items (cursor-paginated; `amount_*` are integer
582
+ * minor units).
583
+ *
584
+ * Docs: https://docs.stripe.com/api/checkout/sessions/line_items
585
+ *
586
+ * @example
587
+ * const items = await payweave.stripe.checkout.sessions.lineItems("cs_test_123", { limit: 20 });
588
+ * console.log(items.data[0]?.amount_total);
589
+ */
590
+ async lineItems(id, query = {}) {
591
+ const sessionId = requireId(id, "checkout session");
592
+ const q = parseRequest(lineItemsQuery, query);
593
+ return this.http.request({
594
+ method: "GET",
595
+ path: `/v1/checkout/sessions/${encodeURIComponent(sessionId)}/line_items`,
596
+ query: flattenQuery(q),
597
+ schema: lineItemListRes
598
+ });
599
+ }
600
+ /**
601
+ * Async iterator over ALL line items of a session, following `has_more`
602
+ * with `starting_after = <last id>` — line items are themselves a paginated
603
+ * list (PW-602 work order).
604
+ *
605
+ * Docs: https://docs.stripe.com/api/checkout/sessions/line_items
606
+ *
607
+ * @example
608
+ * for await (const item of payweave.stripe.checkout.sessions.iterateLineItems("cs_test_123")) {
609
+ * console.log(item.description, item.quantity);
610
+ * }
611
+ */
612
+ async *iterateLineItems(id, query = {}) {
613
+ const sessionId = requireId(id, "checkout session");
614
+ const base = parseRequest(lineItemsQuery, query);
615
+ yield* iterateStripeList(
616
+ (startingAfter) => this.http.request({
617
+ method: "GET",
618
+ path: `/v1/checkout/sessions/${encodeURIComponent(sessionId)}/line_items`,
619
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
620
+ schema: lineItemListRes
621
+ })
622
+ );
623
+ }
624
+ };
625
+ var addressInput = z.object({
626
+ city: z.string().optional(),
627
+ /** Two-letter country code (ISO 3166-1 alpha-2). */
628
+ country: z.string().optional(),
629
+ line1: z.string().optional(),
630
+ line2: z.string().optional(),
631
+ postal_code: z.string().optional(),
632
+ /** State/county/province/region (ISO 3166-2 recommended). */
633
+ state: z.string().optional()
634
+ });
635
+ var cashBalanceInput = z.object({
636
+ settings: z.object({
637
+ reconciliation_mode: z.enum(["automatic", "manual", "merchant_default"]).optional()
638
+ }).optional()
639
+ });
640
+ var invoiceSettingsInput = z.object({
641
+ /** Up to 4 custom fields shown on invoices. */
642
+ custom_fields: z.array(
643
+ z.object({
644
+ /** ≤40 chars. */
645
+ name: z.string().max(40),
646
+ /** ≤140 chars. */
647
+ value: z.string().max(140)
648
+ })
649
+ ).optional(),
650
+ default_payment_method: z.string().optional(),
651
+ footer: z.string().optional(),
652
+ rendering_options: z.object({
653
+ amount_tax_display: z.enum(["exclude_tax", "include_inclusive_tax"]).optional(),
654
+ template: z.string().optional()
655
+ }).optional()
656
+ });
657
+ var shippingInput = z.object({
658
+ address: addressInput,
659
+ name: z.string(),
660
+ phone: z.string().optional()
661
+ });
662
+ var customerSharedFields = {
663
+ /** Required when calculating taxes. */
664
+ address: addressInput.optional(),
665
+ /** Integer MINOR units — a credit/debit applied to future invoices. */
666
+ balance: z.number().int().optional(),
667
+ /** ≤150 chars. */
668
+ business_name: z.string().max(150).optional(),
669
+ cash_balance: cashBalanceInput.optional(),
670
+ description: z.string().optional(),
671
+ /** ≤512 chars. */
672
+ email: z.string().max(512).optional(),
673
+ /** ≤150 chars. */
674
+ individual_name: z.string().max(150).optional(),
675
+ /** 3–12 uppercase letters or numbers (provider-validated). */
676
+ invoice_prefix: z.string().optional(),
677
+ invoice_settings: invoiceSettingsInput.optional(),
678
+ metadata: metadataSchema.optional(),
679
+ /** ≤256 chars. */
680
+ name: z.string().max(256).optional(),
681
+ next_invoice_sequence: z.number().int().optional(),
682
+ /** ≤20 chars. */
683
+ phone: z.string().max(20).optional(),
684
+ preferred_locales: z.array(z.string()).optional(),
685
+ shipping: shippingInput.optional(),
686
+ /** Payment source id; on update it becomes the new default source. */
687
+ source: z.string().optional(),
688
+ tax_exempt: z.enum(["none", "exempt", "reverse"]).optional()
689
+ };
690
+ var customerCreateReq = z.object({
691
+ ...customerSharedFields,
692
+ /** PaymentMethod id (`pm_*`) to attach to the new customer. */
693
+ payment_method: z.string().optional(),
694
+ /** Tax details — recommended when calculating taxes. */
695
+ tax: z.object({
696
+ ip_address: z.string().optional(),
697
+ /** Create documents `deferred` (default) | `immediately`. */
698
+ validate_location: z.enum(["deferred", "immediately"]).optional()
699
+ }).optional(),
700
+ /**
701
+ * The customer's tax IDs. `type` is a country-specific code (e.g. `eu_vat`,
702
+ * `us_ein`) — 100+ documented values, provider-validated (kept `string`).
703
+ */
704
+ tax_id_data: z.array(z.object({ type: z.string(), value: z.string() })).optional(),
705
+ /** Test clock id to attach (test mode). */
706
+ test_clock: z.string().optional()
707
+ });
708
+ var customerUpdateReq = z.object({
709
+ ...customerSharedFields,
710
+ /** Payment source id to make the customer's new default (≤500 chars). */
711
+ default_source: z.string().max(500).optional(),
712
+ /** Tax details — recommended when calculating taxes. */
713
+ tax: z.object({
714
+ ip_address: z.string().optional(),
715
+ /** Update documents `auto` (default) | `deferred` | `immediately`. */
716
+ validate_location: z.enum(["auto", "deferred", "immediately"]).optional()
717
+ }).optional()
718
+ });
719
+ var customerListQuery = z.object({
720
+ ...listCursorFields,
721
+ /** Creation-date window (Unix timestamps). */
722
+ created: createdRange.optional(),
723
+ /** Case-sensitive exact-match filter on email (≤512 chars). */
724
+ email: z.string().max(512).optional(),
725
+ /** Filter by test clock id. */
726
+ test_clock: z.string().optional()
727
+ });
728
+ var searchReqFields = {
729
+ /** Search query string, e.g. `name:'Jane' AND metadata['foo']:'bar'`. */
730
+ query: z.string().min(1, "search query must be a non-empty string"),
731
+ /** Page size, 1–100 (Stripe default 10). */
732
+ limit: z.number().int().min(1).max(100).optional(),
733
+ /** Pagination token from the previous page's `next_page` — omit initially. */
734
+ page: z.string().optional()
735
+ };
736
+ var customerSearchReq = z.object({ ...searchReqFields });
737
+ var customer = z.looseObject({
738
+ id: z.string(),
739
+ object: z.string().optional(),
740
+ address: z.looseObject({}).nullable().optional(),
741
+ /** Integer minor units. */
742
+ balance: z.number().optional(),
743
+ created: z.number().optional(),
744
+ currency: z.string().nullable().optional(),
745
+ /** Source id string, or an expanded object — kept unknown. */
746
+ default_source: z.unknown().optional(),
747
+ delinquent: z.boolean().nullable().optional(),
748
+ description: z.string().nullable().optional(),
749
+ email: z.string().nullable().optional(),
750
+ invoice_prefix: z.string().nullable().optional(),
751
+ invoice_settings: z.looseObject({}).optional(),
752
+ livemode: z.boolean().optional(),
753
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
754
+ name: z.string().nullable().optional(),
755
+ next_invoice_sequence: z.number().optional(),
756
+ phone: z.string().nullable().optional(),
757
+ preferred_locales: z.array(z.string()).nullable().optional(),
758
+ shipping: z.looseObject({}).nullable().optional(),
759
+ /** `none` | `exempt` | `reverse`. */
760
+ tax_exempt: z.string().nullable().optional(),
761
+ /** Test clock id string, or an expanded object — kept unknown. */
762
+ test_clock: z.unknown().optional(),
763
+ /**
764
+ * `true` only on the reduced stub `retrieve` returns for a DELETED customer
765
+ * (https://docs.stripe.com/api/customers/retrieve — verified 2026-07-12:
766
+ * deleted customers stay retrievable "to be able to track their history").
767
+ */
768
+ deleted: z.boolean().optional()
769
+ });
770
+ var deletedCustomer = z.looseObject({
771
+ id: z.string(),
772
+ object: z.string().optional(),
773
+ deleted: z.boolean()
774
+ });
775
+
776
+ // src/stripe/resources/customers.ts
777
+ var customerListRes = stripeList(customer);
778
+ var customerSearchRes = stripeSearchResult(customer);
779
+ function bodyIfNonEmpty(body) {
780
+ return Object.keys(body).length > 0 ? { body } : {};
781
+ }
782
+ var Customers = class {
783
+ constructor(http) {
784
+ this.http = http;
785
+ }
786
+ http;
787
+ /**
788
+ * Create a Customer. Every field is optional — Stripe allows an empty
789
+ * customer. `metadata` maps go to the wire as bracket pairs
790
+ * (`metadata[pwv_reference]=...`). Pass `idempotencyKey` to make the POST
791
+ * safely replayable (and retry-eligible).
792
+ *
793
+ * Docs: https://docs.stripe.com/api/customers/create
794
+ *
795
+ * @example
796
+ * const cus = await payweave.stripe.customers.create({
797
+ * email: "jenny.rosen@example.com",
798
+ * name: "Jenny Rosen",
799
+ * metadata: { pwv_reference: "pwv_ref_0001" },
800
+ * }, { idempotencyKey: "signup-8123-customer" });
801
+ * console.log(cus.id);
802
+ */
803
+ async create(input = {}, opts = {}) {
804
+ const body = parseRequest(customerCreateReq, input);
805
+ return this.http.request({
806
+ method: "POST",
807
+ path: "/v1/customers",
808
+ ...bodyIfNonEmpty(body),
809
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
810
+ schema: customer
811
+ });
812
+ }
813
+ /**
814
+ * Retrieve a Customer by id (`cus_*`). A 404 for an unknown id surfaces as
815
+ * {@link PayweaveNotFoundError}. DELETED customers stay retrievable (to
816
+ * track history) and come back as a reduced stub with `deleted: true` —
817
+ * check that flag before using other fields.
818
+ *
819
+ * Docs: https://docs.stripe.com/api/customers/retrieve
820
+ *
821
+ * @example
822
+ * const cus = await payweave.stripe.customers.retrieve("cus_123");
823
+ * if (!cus.deleted) console.log(cus.email);
824
+ */
825
+ async retrieve(id) {
826
+ const customerId = requireId(id, "customer");
827
+ return this.http.request({
828
+ method: "GET",
829
+ path: `/v1/customers/${encodeURIComponent(customerId)}`,
830
+ schema: customer
831
+ });
832
+ }
833
+ /**
834
+ * Update a Customer. Fields not provided remain unchanged; unset an
835
+ * individual `metadata` key by posting an empty string value for it. Pass
836
+ * `idempotencyKey` to make the POST safely replayable (and retry-eligible).
837
+ *
838
+ * Docs: https://docs.stripe.com/api/customers/update
839
+ *
840
+ * @example
841
+ * const cus = await payweave.stripe.customers.update("cus_123", {
842
+ * metadata: { pwv_reference: "pwv_ref_0001", legacy_id: "" }, // "" unsets
843
+ * });
844
+ */
845
+ async update(id, input = {}, opts = {}) {
846
+ const customerId = requireId(id, "customer");
847
+ const body = parseRequest(customerUpdateReq, input);
848
+ return this.http.request({
849
+ method: "POST",
850
+ path: `/v1/customers/${encodeURIComponent(customerId)}`,
851
+ ...bodyIfNonEmpty(body),
852
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
853
+ schema: customer
854
+ });
855
+ }
856
+ /**
857
+ * PERMANENTLY delete a Customer — cannot be undone. Immediately cancels
858
+ * any active subscriptions, removes all stored payment details, and blocks
859
+ * further operations on the customer. Returns the deletion stub
860
+ * `{ id, object: "customer", deleted: true }`; the customer remains
861
+ * retrievable afterwards (as a deleted stub) for history.
862
+ *
863
+ * Docs: https://docs.stripe.com/api/customers/delete
864
+ *
865
+ * @example
866
+ * const gone = await payweave.stripe.customers.delete("cus_123");
867
+ * console.log(gone.deleted); // true
868
+ */
869
+ async delete(id) {
870
+ const customerId = requireId(id, "customer");
871
+ return this.http.request({
872
+ method: "DELETE",
873
+ path: `/v1/customers/${encodeURIComponent(customerId)}`,
874
+ schema: deletedCustomer
875
+ });
876
+ }
877
+ /**
878
+ * List Customers (newest first). Cursor pagination: `limit` +
879
+ * `starting_after`/`ending_before`; the `created` window becomes bracket
880
+ * query keys (`created[gte]`).
881
+ *
882
+ * Docs: https://docs.stripe.com/api/customers/list
883
+ *
884
+ * @example
885
+ * const page = await payweave.stripe.customers.list({ email: "jenny.rosen@example.com" });
886
+ * console.log(page.data.length, page.has_more);
887
+ */
888
+ async list(query = {}) {
889
+ const q = parseRequest(customerListQuery, query);
890
+ return this.http.request({
891
+ method: "GET",
892
+ path: "/v1/customers",
893
+ query: flattenQuery(q),
894
+ schema: customerListRes
895
+ });
896
+ }
897
+ /**
898
+ * Async iterator over ALL Customers matching `query`, transparently
899
+ * following `has_more` with `starting_after = <last id>`.
900
+ *
901
+ * Docs: https://docs.stripe.com/api/customers/list
902
+ *
903
+ * @example
904
+ * for await (const cus of payweave.stripe.customers.iterate({ email: "a@example.com" })) {
905
+ * console.log(cus.id);
906
+ * }
907
+ */
908
+ async *iterate(query = {}) {
909
+ const base = parseRequest(customerListQuery, query);
910
+ yield* iterateStripeList(
911
+ (startingAfter) => this.http.request({
912
+ method: "GET",
913
+ path: "/v1/customers",
914
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
915
+ schema: customerListRes
916
+ })
917
+ );
918
+ }
919
+ /**
920
+ * Search Customers with Stripe's search query language (e.g.
921
+ * `name:'Jane Doe' AND metadata['foo']:'bar'`). Pagination is TOKEN-based:
922
+ * pass the previous page's `next_page` as `page` (never `starting_after`).
923
+ * Search is eventually consistent (typically <1 minute; up to an hour
924
+ * during outages) — don't use it in read-after-write flows.
925
+ *
926
+ * Docs: https://docs.stripe.com/api/customers/search
927
+ *
928
+ * @example
929
+ * const found = await payweave.stripe.customers.search({
930
+ * query: "metadata['pwv_reference']:'pwv_ref_0001'",
931
+ * });
932
+ * console.log(found.data[0]?.id, found.next_page);
933
+ */
934
+ async search(input) {
935
+ const q = parseRequest(customerSearchReq, input);
936
+ return this.http.request({
937
+ method: "GET",
938
+ path: "/v1/customers/search",
939
+ query: flattenQuery(q),
940
+ schema: customerSearchRes
941
+ });
942
+ }
943
+ /**
944
+ * Async iterator over ALL Customers matching a search query, transparently
945
+ * following `has_more` with `page = <next_page token>` — search pagination
946
+ * differs from list pagination (https://docs.stripe.com/api/pagination/search).
947
+ *
948
+ * Docs: https://docs.stripe.com/api/customers/search
949
+ *
950
+ * @example
951
+ * for await (const cus of payweave.stripe.customers.iterateSearch({
952
+ * query: "email:'jenny.rosen@example.com'",
953
+ * })) {
954
+ * console.log(cus.id);
955
+ * }
956
+ */
957
+ async *iterateSearch(input) {
958
+ const base = parseRequest(customerSearchReq, input);
959
+ yield* iterateStripeSearch(
960
+ (page) => this.http.request({
961
+ method: "GET",
962
+ path: "/v1/customers/search",
963
+ query: flattenQuery({ ...base, page }),
964
+ schema: customerSearchRes
965
+ })
966
+ );
967
+ }
968
+ };
969
+ var automaticPaymentMethods = z.object({
970
+ enabled: z.boolean(),
971
+ allow_redirects: z.enum(["always", "never"]).optional()
972
+ });
973
+ var paymentIntentCreateReq = z.object({
974
+ /** Positive integer in the smallest currency unit (minor units) — unchanged. */
975
+ amount: z.number().int().positive(),
976
+ /** Three-letter ISO currency code, lowercase. Required. */
977
+ currency: z.string(),
978
+ automatic_payment_methods: automaticPaymentMethods.optional(),
979
+ /** `true` = create + confirm in one call. Defaults to false. */
980
+ confirm: z.boolean().optional(),
981
+ /** Customer id (`cus_*`) this intent belongs to. */
982
+ customer: z.string().optional(),
983
+ description: z.string().optional(),
984
+ metadata: metadataSchema.optional(),
985
+ /** PaymentMethod id (`pm_*`) to attach. */
986
+ payment_method: z.string().optional(),
987
+ /** Payment method types to accept (e.g. `["card", "link"]`). */
988
+ payment_method_types: z.array(z.string()).optional(),
989
+ receipt_email: z.string().optional(),
990
+ /** `automatic` | `automatic_async` (default) | `manual`. */
991
+ capture_method: z.enum(["automatic", "automatic_async", "manual"]).optional(),
992
+ confirmation_method: z.enum(["automatic", "manual"]).optional(),
993
+ setup_future_usage: z.enum(["on_session", "off_session"]).optional(),
994
+ /** ≤22 chars — statement text for non-card charges. */
995
+ statement_descriptor: z.string().max(22).optional(),
996
+ /** ≤22 chars — suffix appended to the account descriptor for card charges. */
997
+ statement_descriptor_suffix: z.string().max(22).optional(),
998
+ /** Redirect URL after off-page authentication (use with `confirm: true`). */
999
+ return_url: z.string().optional(),
1000
+ /** Customer is not in the checkout flow (docs type: boolean or string). */
1001
+ off_session: z.union([z.boolean(), z.string()]).optional(),
1002
+ /** Transaction-group identifier for Connect. */
1003
+ transfer_group: z.string().optional(),
1004
+ /** Connect application fee, integer minor units. */
1005
+ application_fee_amount: z.number().int().optional()
1006
+ });
1007
+ var paymentIntentConfirmReq = z.object({
1008
+ /** PaymentMethod id (`pm_*`) to use for this confirmation attempt. */
1009
+ payment_method: z.string().optional(),
1010
+ /** Redirect URL after authentication for redirect-based methods. */
1011
+ return_url: z.string().optional(),
1012
+ receipt_email: z.string().optional(),
1013
+ setup_future_usage: z.enum(["on_session", "off_session"]).optional(),
1014
+ capture_method: z.enum(["automatic", "automatic_async", "manual"]).optional(),
1015
+ /** Customer is not in the checkout flow (docs type: boolean or string). */
1016
+ off_session: z.union([z.boolean(), z.string()]).optional(),
1017
+ /** ConfirmationToken id capturing client-collected payment details. */
1018
+ confirmation_token: z.string().optional(),
1019
+ /** Fail (instead of returning `requires_action`) when an action is needed. */
1020
+ error_on_requires_action: z.boolean().optional(),
1021
+ /** Mandate id to use for this confirmation. */
1022
+ mandate: z.string().optional()
1023
+ });
1024
+ var paymentIntentCaptureReq = z.object({
1025
+ /** Integer minor units to capture; defaults to full `amount_capturable`. */
1026
+ amount_to_capture: z.number().int().positive().optional(),
1027
+ /** Connect application fee, integer minor units. */
1028
+ application_fee_amount: z.number().int().optional(),
1029
+ /** Default true. `false` retains uncaptured funds (multicapture accounts). */
1030
+ final_capture: z.boolean().optional(),
1031
+ metadata: metadataSchema.optional(),
1032
+ /** ≤22 chars — statement text for non-card charges. */
1033
+ statement_descriptor: z.string().max(22).optional(),
1034
+ /** ≤22 chars — suffix appended to the account descriptor for card charges. */
1035
+ statement_descriptor_suffix: z.string().max(22).optional()
1036
+ });
1037
+ var paymentIntentCancelReq = z.object({
1038
+ cancellation_reason: z.enum(["duplicate", "fraudulent", "requested_by_customer", "abandoned"]).optional()
1039
+ });
1040
+ var paymentIntentListQuery = z.object({
1041
+ ...listCursorFields,
1042
+ /** Filter by Customer id. */
1043
+ customer: z.string().optional(),
1044
+ /** Creation-date window (Unix timestamps). */
1045
+ created: createdRange.optional()
1046
+ });
1047
+ var paymentIntent = z.looseObject({
1048
+ id: z.string(),
1049
+ object: z.string().optional(),
1050
+ amount: z.number().optional(),
1051
+ amount_capturable: z.number().optional(),
1052
+ amount_received: z.number().optional(),
1053
+ currency: z.string().optional(),
1054
+ /**
1055
+ * `requires_payment_method` | `requires_confirmation` | `requires_action` |
1056
+ * `processing` | `requires_capture` | `canceled` | `succeeded` —
1057
+ * normalization is the unified layer's job.
1058
+ */
1059
+ status: z.string().optional(),
1060
+ client_secret: z.string().nullable().optional(),
1061
+ capture_method: z.string().optional(),
1062
+ confirmation_method: z.string().optional(),
1063
+ /** Customer id string, or an expanded object — kept unknown. */
1064
+ customer: z.unknown().optional(),
1065
+ description: z.string().nullable().optional(),
1066
+ /** Latest Charge id string, or an expanded object — kept unknown. */
1067
+ latest_charge: z.unknown().optional(),
1068
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
1069
+ /** PaymentMethod id string, or an expanded object — kept unknown. */
1070
+ payment_method: z.unknown().optional(),
1071
+ receipt_email: z.string().nullable().optional(),
1072
+ /** Client-side action required to continue — kept loose. */
1073
+ next_action: z.looseObject({}).nullable().optional(),
1074
+ cancellation_reason: z.string().nullable().optional(),
1075
+ canceled_at: z.number().nullable().optional(),
1076
+ created: z.number().optional(),
1077
+ livemode: z.boolean().optional()
1078
+ });
1079
+
1080
+ // src/stripe/resources/payment-intents.ts
1081
+ var paymentIntentListRes = stripeList(paymentIntent);
1082
+ function bodyIfNonEmpty2(body) {
1083
+ return Object.keys(body).length > 0 ? { body } : {};
1084
+ }
1085
+ var PaymentIntents = class {
1086
+ constructor(http) {
1087
+ this.http = http;
1088
+ }
1089
+ http;
1090
+ /**
1091
+ * Create a PaymentIntent. `amount` is a positive integer in MINOR units
1092
+ * (e.g. 2000 = $20.00) and is sent to Stripe unchanged. Pass
1093
+ * `idempotencyKey` to make the POST safely replayable (and retry-eligible).
1094
+ *
1095
+ * Docs: https://docs.stripe.com/api/payment_intents/create
1096
+ *
1097
+ * @example
1098
+ * const pi = await payweave.stripe.paymentIntents.create({
1099
+ * amount: 2000,
1100
+ * currency: "usd",
1101
+ * automatic_payment_methods: { enabled: true },
1102
+ * }, { idempotencyKey: "order-8123-intent" });
1103
+ * console.log(pi.client_secret);
1104
+ */
1105
+ async create(input, opts = {}) {
1106
+ const body = parseRequest(paymentIntentCreateReq, input);
1107
+ return this.http.request({
1108
+ method: "POST",
1109
+ path: "/v1/payment_intents",
1110
+ body,
1111
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1112
+ schema: paymentIntent
1113
+ });
1114
+ }
1115
+ /**
1116
+ * Retrieve a PaymentIntent by id (`pi_*`). A 404 for an unknown id surfaces
1117
+ * as {@link PayweaveNotFoundError}.
1118
+ *
1119
+ * Docs: https://docs.stripe.com/api/payment_intents/retrieve
1120
+ *
1121
+ * @example
1122
+ * const pi = await payweave.stripe.paymentIntents.retrieve("pi_123");
1123
+ * if (pi.status === "succeeded") { }
1124
+ */
1125
+ async retrieve(id) {
1126
+ const intentId = requireId(id, "payment intent");
1127
+ return this.http.request({
1128
+ method: "GET",
1129
+ path: `/v1/payment_intents/${encodeURIComponent(intentId)}`,
1130
+ schema: paymentIntent
1131
+ });
1132
+ }
1133
+ /**
1134
+ * Confirm a PaymentIntent (attempt payment with the attached/provided
1135
+ * payment method). On success the status moves to `succeeded` — or
1136
+ * `requires_capture` when `capture_method` is `manual`, or
1137
+ * `requires_action` when authentication is needed. Pass `idempotencyKey`
1138
+ * to make the POST safely replayable (and retry-eligible).
1139
+ *
1140
+ * Docs: https://docs.stripe.com/api/payment_intents/confirm
1141
+ *
1142
+ * @example
1143
+ * const pi = await payweave.stripe.paymentIntents.confirm("pi_123", {
1144
+ * payment_method: "pm_card_visa",
1145
+ * return_url: "https://example.com/return",
1146
+ * }, { idempotencyKey: "order-8123-confirm" });
1147
+ */
1148
+ async confirm(id, input = {}, opts = {}) {
1149
+ const intentId = requireId(id, "payment intent");
1150
+ const body = parseRequest(paymentIntentConfirmReq, input);
1151
+ return this.http.request({
1152
+ method: "POST",
1153
+ path: `/v1/payment_intents/${encodeURIComponent(intentId)}/confirm`,
1154
+ ...bodyIfNonEmpty2(body),
1155
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1156
+ schema: paymentIntent
1157
+ });
1158
+ }
1159
+ /**
1160
+ * Capture the funds of a `requires_capture` PaymentIntent (manual capture
1161
+ * flow — uncaptured intents cancel after 7 days by default).
1162
+ * `amount_to_capture` is integer minor units and defaults to the full
1163
+ * `amount_capturable`. Pass `idempotencyKey` to make the POST safely
1164
+ * replayable (and retry-eligible).
1165
+ *
1166
+ * Docs: https://docs.stripe.com/api/payment_intents/capture
1167
+ *
1168
+ * @example
1169
+ * const pi = await payweave.stripe.paymentIntents.capture("pi_123", {
1170
+ * amount_to_capture: 1500,
1171
+ * }, { idempotencyKey: "order-8123-capture" });
1172
+ * console.log(pi.status); // "succeeded"
1173
+ */
1174
+ async capture(id, input = {}, opts = {}) {
1175
+ const intentId = requireId(id, "payment intent");
1176
+ const body = parseRequest(paymentIntentCaptureReq, input);
1177
+ return this.http.request({
1178
+ method: "POST",
1179
+ path: `/v1/payment_intents/${encodeURIComponent(intentId)}/capture`,
1180
+ ...bodyIfNonEmpty2(body),
1181
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1182
+ schema: paymentIntent
1183
+ });
1184
+ }
1185
+ /**
1186
+ * Cancel a PaymentIntent. Valid only for statuses
1187
+ * `requires_payment_method`, `requires_capture`, `requires_confirmation`,
1188
+ * `requires_action` and (rarely) `processing` — Stripe errors otherwise
1189
+ * (surfaced as {@link PayweaveValidationError} on the 400). For
1190
+ * `requires_capture` intents the remaining `amount_capturable` is
1191
+ * automatically refunded.
1192
+ *
1193
+ * Docs: https://docs.stripe.com/api/payment_intents/cancel
1194
+ *
1195
+ * @example
1196
+ * const pi = await payweave.stripe.paymentIntents.cancel("pi_123", {
1197
+ * cancellation_reason: "requested_by_customer",
1198
+ * });
1199
+ * console.log(pi.status); // "canceled"
1200
+ */
1201
+ async cancel(id, input = {}) {
1202
+ const intentId = requireId(id, "payment intent");
1203
+ const body = parseRequest(paymentIntentCancelReq, input);
1204
+ return this.http.request({
1205
+ method: "POST",
1206
+ path: `/v1/payment_intents/${encodeURIComponent(intentId)}/cancel`,
1207
+ ...bodyIfNonEmpty2(body),
1208
+ schema: paymentIntent
1209
+ });
1210
+ }
1211
+ /**
1212
+ * List PaymentIntents (newest first). Cursor pagination: `limit` +
1213
+ * `starting_after`/`ending_before`; the `created` window becomes bracket
1214
+ * query keys (`created[gte]`).
1215
+ *
1216
+ * Docs: https://docs.stripe.com/api/payment_intents/list
1217
+ *
1218
+ * @example
1219
+ * const page = await payweave.stripe.paymentIntents.list({ customer: "cus_123", limit: 50 });
1220
+ * console.log(page.data.length, page.has_more);
1221
+ */
1222
+ async list(query = {}) {
1223
+ const q = parseRequest(paymentIntentListQuery, query);
1224
+ return this.http.request({
1225
+ method: "GET",
1226
+ path: "/v1/payment_intents",
1227
+ query: flattenQuery(q),
1228
+ schema: paymentIntentListRes
1229
+ });
1230
+ }
1231
+ /**
1232
+ * Async iterator over ALL PaymentIntents matching `query`, transparently
1233
+ * following `has_more` with `starting_after = <last id>`.
1234
+ *
1235
+ * Docs: https://docs.stripe.com/api/payment_intents/list
1236
+ *
1237
+ * @example
1238
+ * for await (const pi of payweave.stripe.paymentIntents.iterate({ customer: "cus_123" })) {
1239
+ * console.log(pi.id, pi.status);
1240
+ * }
1241
+ */
1242
+ async *iterate(query = {}) {
1243
+ const base = parseRequest(paymentIntentListQuery, query);
1244
+ yield* iterateStripeList(
1245
+ (startingAfter) => this.http.request({
1246
+ method: "GET",
1247
+ path: "/v1/payment_intents",
1248
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
1249
+ schema: paymentIntentListRes
1250
+ })
1251
+ );
1252
+ }
1253
+ };
1254
+ var customUnitAmountInput = z.object({
1255
+ /** Pass `true` to enable — otherwise omit the whole object. */
1256
+ enabled: z.boolean(),
1257
+ maximum: z.number().int().optional(),
1258
+ minimum: z.number().int().optional(),
1259
+ preset: z.number().int().optional()
1260
+ });
1261
+ var recurringInput = z.object({
1262
+ interval: z.enum(["day", "week", "month", "year"]),
1263
+ /** Intervals between billings — max 3 years (36 months, 156 weeks). */
1264
+ interval_count: z.number().int().optional(),
1265
+ /** Defaults to `licensed`. */
1266
+ usage_type: z.enum(["licensed", "metered"]).optional(),
1267
+ /** Billing Meter id tracking usage for a metered price. */
1268
+ meter: z.string().optional()
1269
+ });
1270
+ var tierInput = z.object({
1271
+ /** Upper bound of this tier — `"inf"` for the fallback tier. Required. */
1272
+ up_to: z.union([z.literal("inf"), z.number().int()]),
1273
+ /** Flat amount for the whole tier, integer minor units. */
1274
+ flat_amount: z.number().int().optional(),
1275
+ /** Decimal-string alternative to `flat_amount` (only one of the two). */
1276
+ flat_amount_decimal: z.string().optional(),
1277
+ /** Per-unit amount, integer minor units. */
1278
+ unit_amount: z.number().int().optional(),
1279
+ /** Decimal-string alternative to `unit_amount` (only one of the two). */
1280
+ unit_amount_decimal: z.string().optional()
1281
+ });
1282
+ var productDataInput = z.object({
1283
+ /** Displayable product name. Required. */
1284
+ name: z.string(),
1285
+ /** Defaults to true. */
1286
+ active: z.boolean().optional(),
1287
+ metadata: metadataSchema.optional(),
1288
+ /** ≤22 chars; may not include `<`, `>`, `\`, `"`, `'`. */
1289
+ statement_descriptor: z.string().max(22).optional(),
1290
+ /** Tax code id — recommended when calculating taxes. */
1291
+ tax_code: z.string().optional(),
1292
+ tax_details: z.object({
1293
+ tax_code: z.string().optional(),
1294
+ /** Tax location id — required/optional/unsupported per tax code. */
1295
+ performance_location: z.string().optional()
1296
+ }).optional(),
1297
+ /** ≤12 chars. */
1298
+ unit_label: z.string().max(12).optional()
1299
+ });
1300
+ var priceCreateReq = z.object({
1301
+ /** Three-letter ISO currency code, lowercase. Required. */
1302
+ currency: z.string(),
1303
+ /** Integer minor units (or 0 for a free price). */
1304
+ unit_amount: z.number().int().nonnegative().optional(),
1305
+ /** Decimal string alternative to `unit_amount` (≤12 decimal places). */
1306
+ unit_amount_decimal: z.string().optional(),
1307
+ custom_unit_amount: customUnitAmountInput.optional(),
1308
+ /** Usable for new purchases. Defaults to true; `false` = archived. */
1309
+ active: z.boolean().optional(),
1310
+ /** Defaults to `per_unit`. */
1311
+ billing_scheme: z.enum(["per_unit", "tiered"]).optional(),
1312
+ /** Stable retrieval key (≤200 chars) — PW-803's price identifier. */
1313
+ lookup_key: z.string().max(200).optional(),
1314
+ /** Atomically move `lookup_key` off the price currently holding it. */
1315
+ transfer_lookup_key: z.boolean().optional(),
1316
+ metadata: metadataSchema.optional(),
1317
+ /** Internal description, hidden from customers. */
1318
+ nickname: z.string().optional(),
1319
+ /** Existing Product id (`prod_*`). Alternative to `product_data`. */
1320
+ product: z.string().optional(),
1321
+ /** Inline Product creation. Alternative to `product`. */
1322
+ product_data: productDataInput.optional(),
1323
+ recurring: recurringInput.optional(),
1324
+ /** Cannot be changed after being set to `inclusive`/`exclusive`. */
1325
+ tax_behavior: z.enum(["inclusive", "exclusive", "unspecified"]).optional(),
1326
+ /** Required when `billing_scheme=tiered`. */
1327
+ tiers: z.array(tierInput).optional(),
1328
+ /** Required when `billing_scheme=tiered`. */
1329
+ tiers_mode: z.enum(["graduated", "volume"]).optional(),
1330
+ /** Transform reported quantity before billing — cannot combine with tiers. */
1331
+ transform_quantity: z.object({
1332
+ divide_by: z.number().int(),
1333
+ round: z.enum(["up", "down"])
1334
+ }).optional()
1335
+ });
1336
+ var priceUpdateReq = z.object({
1337
+ /** `false` archives the price for new purchases (PW-803 price rotation). */
1338
+ active: z.boolean().optional(),
1339
+ /** Stable retrieval key (≤200 chars). */
1340
+ lookup_key: z.string().max(200).optional(),
1341
+ /** Atomically move `lookup_key` off the price currently holding it. */
1342
+ transfer_lookup_key: z.boolean().optional(),
1343
+ metadata: metadataSchema.optional(),
1344
+ /** Internal description, hidden from customers. */
1345
+ nickname: z.string().optional(),
1346
+ /** Cannot be changed after being set to `inclusive`/`exclusive`. */
1347
+ tax_behavior: z.enum(["inclusive", "exclusive", "unspecified"]).optional()
1348
+ });
1349
+ var priceListQuery = z.object({
1350
+ ...listCursorFields,
1351
+ /** Only active (or only archived) prices. */
1352
+ active: z.boolean().optional(),
1353
+ /** Creation-date window (Unix timestamps). */
1354
+ created: createdRange.optional(),
1355
+ /** Filter by currency code. */
1356
+ currency: z.string().optional(),
1357
+ /** Only prices with these lookup_keys (up to 10). */
1358
+ lookup_keys: z.array(z.string()).optional(),
1359
+ /** Filter by Product id. */
1360
+ product: z.string().optional(),
1361
+ /** Filter by recurring components. */
1362
+ recurring: z.object({
1363
+ interval: z.enum(["day", "week", "month", "year"]).optional(),
1364
+ /** Filter by the price's Billing Meter id. */
1365
+ meter: z.string().optional(),
1366
+ usage_type: z.enum(["licensed", "metered"]).optional()
1367
+ }).optional(),
1368
+ type: z.enum(["one_time", "recurring"]).optional()
1369
+ });
1370
+ var priceSearchReq = z.object({ ...searchReqFields });
1371
+ var price = z.looseObject({
1372
+ id: z.string(),
1373
+ object: z.string().optional(),
1374
+ active: z.boolean().optional(),
1375
+ /** `per_unit` | `tiered`. */
1376
+ billing_scheme: z.string().optional(),
1377
+ created: z.number().optional(),
1378
+ currency: z.string().optional(),
1379
+ custom_unit_amount: z.looseObject({}).nullable().optional(),
1380
+ livemode: z.boolean().optional(),
1381
+ lookup_key: z.string().nullable().optional(),
1382
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
1383
+ nickname: z.string().nullable().optional(),
1384
+ /** Product id string, or an expanded object — kept unknown. */
1385
+ product: z.unknown().optional(),
1386
+ recurring: z.looseObject({
1387
+ interval: z.string().optional(),
1388
+ interval_count: z.number().nullable().optional(),
1389
+ trial_period_days: z.number().nullable().optional(),
1390
+ usage_type: z.string().optional(),
1391
+ meter: z.string().nullable().optional()
1392
+ }).nullable().optional(),
1393
+ tax_behavior: z.string().nullable().optional(),
1394
+ /** `graduated` | `volume` — null unless tiered. */
1395
+ tiers_mode: z.string().nullable().optional(),
1396
+ transform_quantity: z.looseObject({}).nullable().optional(),
1397
+ /** `one_time` | `recurring`. */
1398
+ type: z.string().optional(),
1399
+ /** Integer minor units — null for tiered/custom-amount prices. */
1400
+ unit_amount: z.number().nullable().optional(),
1401
+ unit_amount_decimal: z.string().nullable().optional()
1402
+ });
1403
+
1404
+ // src/stripe/resources/prices.ts
1405
+ var priceListRes = stripeList(price);
1406
+ var priceSearchRes = stripeSearchResult(price);
1407
+ function bodyIfNonEmpty3(body) {
1408
+ return Object.keys(body).length > 0 ? { body } : {};
1409
+ }
1410
+ var Prices = class {
1411
+ constructor(http) {
1412
+ this.http = http;
1413
+ }
1414
+ http;
1415
+ /**
1416
+ * Create a Price. `unit_amount` is integer MINOR units (e.g. 1500 = $15.00)
1417
+ * and is sent to Stripe unchanged; `recurring` makes it a subscription
1418
+ * price; `lookup_key` (+ `transfer_lookup_key`) gives it a stable
1419
+ * identifier that survives price rotation. Amount, currency, product and
1420
+ * recurring are IMMUTABLE afterwards. Pass `idempotencyKey` to make the
1421
+ * POST safely replayable (and retry-eligible).
1422
+ *
1423
+ * Docs: https://docs.stripe.com/api/prices/create
1424
+ *
1425
+ * @example
1426
+ * const pr = await payweave.stripe.prices.create({
1427
+ * currency: "usd",
1428
+ * unit_amount: 1500,
1429
+ * product: "prod_123",
1430
+ * recurring: { interval: "month" },
1431
+ * lookup_key: "pro-monthly",
1432
+ * }, { idempotencyKey: "push-pro-monthly-v2" });
1433
+ * console.log(pr.id);
1434
+ */
1435
+ async create(input, opts = {}) {
1436
+ const body = parseRequest(priceCreateReq, input);
1437
+ return this.http.request({
1438
+ method: "POST",
1439
+ path: "/v1/prices",
1440
+ body,
1441
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1442
+ schema: price
1443
+ });
1444
+ }
1445
+ /**
1446
+ * Retrieve a Price by id (`price_*`). A 404 for an unknown id surfaces as
1447
+ * {@link PayweaveNotFoundError}.
1448
+ *
1449
+ * Docs: https://docs.stripe.com/api/prices/retrieve
1450
+ *
1451
+ * @example
1452
+ * const pr = await payweave.stripe.prices.retrieve("price_123");
1453
+ * console.log(pr.unit_amount, pr.currency);
1454
+ */
1455
+ async retrieve(id) {
1456
+ const priceId = requireId(id, "price");
1457
+ return this.http.request({
1458
+ method: "GET",
1459
+ path: `/v1/prices/${encodeURIComponent(priceId)}`,
1460
+ schema: price
1461
+ });
1462
+ }
1463
+ /**
1464
+ * Update a Price. ONLY `active`, `lookup_key`/`transfer_lookup_key`,
1465
+ * `metadata`, `nickname` and `tax_behavior` (until set) are updatable —
1466
+ * amount/currency/product/recurring are immutable, and prices cannot be
1467
+ * deleted: rotate by creating a new Price and archiving this one with
1468
+ * `active: false` (PW-803's price-change flow). Pass `idempotencyKey` to
1469
+ * make the POST safely replayable (and retry-eligible).
1470
+ *
1471
+ * Docs: https://docs.stripe.com/api/prices/update
1472
+ *
1473
+ * @example
1474
+ * const archived = await payweave.stripe.prices.update("price_123", {
1475
+ * active: false,
1476
+ * });
1477
+ * console.log(archived.active); // false
1478
+ */
1479
+ async update(id, input = {}, opts = {}) {
1480
+ const priceId = requireId(id, "price");
1481
+ const body = parseRequest(priceUpdateReq, input);
1482
+ return this.http.request({
1483
+ method: "POST",
1484
+ path: `/v1/prices/${encodeURIComponent(priceId)}`,
1485
+ ...bodyIfNonEmpty3(body),
1486
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1487
+ schema: price
1488
+ });
1489
+ }
1490
+ /**
1491
+ * List Prices (newest first). Cursor pagination: `limit` +
1492
+ * `starting_after`/`ending_before`; `created`/`recurring` become bracket
1493
+ * query keys (`recurring[interval]`) and `lookup_keys` explicit indices
1494
+ * (`lookup_keys[0]=...`).
1495
+ *
1496
+ * Docs: https://docs.stripe.com/api/prices/list
1497
+ *
1498
+ * @example
1499
+ * const page = await payweave.stripe.prices.list({ product: "prod_123", active: true });
1500
+ * console.log(page.data.length, page.has_more);
1501
+ */
1502
+ async list(query = {}) {
1503
+ const { lookup_keys, ...rest } = parseRequest(priceListQuery, query);
1504
+ const q = flattenQuery(rest);
1505
+ lookup_keys?.forEach((key, i) => {
1506
+ q[`lookup_keys[${i}]`] = key;
1507
+ });
1508
+ return this.http.request({
1509
+ method: "GET",
1510
+ path: "/v1/prices",
1511
+ query: q,
1512
+ schema: priceListRes
1513
+ });
1514
+ }
1515
+ /**
1516
+ * Async iterator over ALL Prices matching `query`, transparently following
1517
+ * `has_more` with `starting_after = <last id>`.
1518
+ *
1519
+ * Docs: https://docs.stripe.com/api/prices/list
1520
+ *
1521
+ * @example
1522
+ * for await (const pr of payweave.stripe.prices.iterate({ product: "prod_123" })) {
1523
+ * console.log(pr.id, pr.unit_amount);
1524
+ * }
1525
+ */
1526
+ async *iterate(query = {}) {
1527
+ const { lookup_keys, ...base } = parseRequest(priceListQuery, query);
1528
+ const lookupPairs = {};
1529
+ lookup_keys?.forEach((key, i) => {
1530
+ lookupPairs[`lookup_keys[${i}]`] = key;
1531
+ });
1532
+ yield* iterateStripeList(
1533
+ (startingAfter) => this.http.request({
1534
+ method: "GET",
1535
+ path: "/v1/prices",
1536
+ query: {
1537
+ ...flattenQuery({ ...base, starting_after: startingAfter }),
1538
+ ...lookupPairs
1539
+ },
1540
+ schema: priceListRes
1541
+ })
1542
+ );
1543
+ }
1544
+ /**
1545
+ * Search Prices with Stripe's search query language (e.g.
1546
+ * `active:'true' AND lookup_key:'pro-monthly'`). Pagination is TOKEN-based:
1547
+ * pass the previous page's `next_page` as `page` (never `starting_after`).
1548
+ * Search is eventually consistent — don't use it in read-after-write flows.
1549
+ *
1550
+ * Docs: https://docs.stripe.com/api/prices/search
1551
+ *
1552
+ * @example
1553
+ * const found = await payweave.stripe.prices.search({
1554
+ * query: "metadata['pwv_reference']:'pwv_plan_pro'",
1555
+ * });
1556
+ * console.log(found.data[0]?.id, found.next_page);
1557
+ */
1558
+ async search(input) {
1559
+ const q = parseRequest(priceSearchReq, input);
1560
+ return this.http.request({
1561
+ method: "GET",
1562
+ path: "/v1/prices/search",
1563
+ query: flattenQuery(q),
1564
+ schema: priceSearchRes
1565
+ });
1566
+ }
1567
+ /**
1568
+ * Async iterator over ALL Prices matching a search query, transparently
1569
+ * following `has_more` with `page = <next_page token>` — search pagination
1570
+ * differs from list pagination (https://docs.stripe.com/api/pagination/search).
1571
+ *
1572
+ * Docs: https://docs.stripe.com/api/prices/search
1573
+ *
1574
+ * @example
1575
+ * for await (const pr of payweave.stripe.prices.iterateSearch({
1576
+ * query: "type:'recurring'",
1577
+ * })) {
1578
+ * console.log(pr.id);
1579
+ * }
1580
+ */
1581
+ async *iterateSearch(input) {
1582
+ const base = parseRequest(priceSearchReq, input);
1583
+ yield* iterateStripeSearch(
1584
+ (page) => this.http.request({
1585
+ method: "GET",
1586
+ path: "/v1/prices/search",
1587
+ query: flattenQuery({ ...base, page }),
1588
+ schema: priceSearchRes
1589
+ })
1590
+ );
1591
+ }
1592
+ };
1593
+ var marketingFeatureInput = z.object({
1594
+ /** ≤80 chars. */
1595
+ name: z.string().max(80)
1596
+ });
1597
+ var packageDimensionsInput = z.object({
1598
+ /** Inches, ≤2 decimal places. */
1599
+ height: z.number(),
1600
+ /** Inches, ≤2 decimal places. */
1601
+ length: z.number(),
1602
+ /** Ounces, ≤2 decimal places. */
1603
+ weight: z.number(),
1604
+ /** Inches, ≤2 decimal places. */
1605
+ width: z.number()
1606
+ });
1607
+ var taxDetailsInput = z.object({
1608
+ tax_code: z.string().optional(),
1609
+ /** Tax location id — required/optional/unsupported depending on tax code. */
1610
+ performance_location: z.string().optional()
1611
+ });
1612
+ var customUnitAmountInput2 = z.object({
1613
+ /** Pass `true` to enable — otherwise omit the whole object. */
1614
+ enabled: z.boolean(),
1615
+ maximum: z.number().int().optional(),
1616
+ minimum: z.number().int().optional(),
1617
+ preset: z.number().int().optional()
1618
+ });
1619
+ var defaultPriceDataInput = z.object({
1620
+ /** Three-letter ISO currency code, lowercase. Required. */
1621
+ currency: z.string(),
1622
+ /** Integer minor units (or 0 for a free price). */
1623
+ unit_amount: z.number().int().nonnegative().optional(),
1624
+ /** Decimal string alternative to `unit_amount` (≤12 decimal places). */
1625
+ unit_amount_decimal: z.string().optional(),
1626
+ custom_unit_amount: customUnitAmountInput2.optional(),
1627
+ metadata: metadataSchema.optional(),
1628
+ recurring: z.object({
1629
+ interval: z.enum(["day", "week", "month", "year"]),
1630
+ /** Intervals between billings — max 3 years (36 months, 156 weeks). */
1631
+ interval_count: z.number().int().optional()
1632
+ }).optional(),
1633
+ /** Cannot be changed after being set to `inclusive`/`exclusive`. */
1634
+ tax_behavior: z.enum(["inclusive", "exclusive", "unspecified"]).optional()
1635
+ });
1636
+ var productSharedFields = {
1637
+ /** Available for purchase. Defaults to true; `false` = archived. */
1638
+ active: z.boolean().optional(),
1639
+ description: z.string().optional(),
1640
+ /** Up to 8 image URLs. */
1641
+ images: z.array(z.string()).optional(),
1642
+ /** Up to 15 marketing features (pricing tables). */
1643
+ marketing_features: z.array(marketingFeatureInput).optional(),
1644
+ metadata: metadataSchema.optional(),
1645
+ package_dimensions: packageDimensionsInput.optional(),
1646
+ /** Whether the product is shipped (physical goods). */
1647
+ shippable: z.boolean().optional(),
1648
+ /** ≤22 chars, `type=service` subscriptions only. */
1649
+ statement_descriptor: z.string().max(22).optional(),
1650
+ /** Tax code id — recommended when calculating taxes. */
1651
+ tax_code: z.string().optional(),
1652
+ tax_details: taxDetailsInput.optional(),
1653
+ /** ≤12 chars, `type=service` only. */
1654
+ unit_label: z.string().max(12).optional(),
1655
+ /** Publicly-accessible webpage for the product. */
1656
+ url: z.string().optional()
1657
+ };
1658
+ var productCreateReq = z.object({
1659
+ /** Displayable product name. Required. */
1660
+ name: z.string(),
1661
+ ...productSharedFields,
1662
+ /** Custom unique id (`prod_*` generated when omitted). */
1663
+ id: z.string().optional(),
1664
+ /** Create the product's default Price in the same call. */
1665
+ default_price_data: defaultPriceDataInput.optional()
1666
+ });
1667
+ var productUpdateReq = z.object({
1668
+ ...productSharedFields,
1669
+ /** Existing Price id (`price_*`) to make the default for this product. */
1670
+ default_price: z.string().optional(),
1671
+ name: z.string().optional()
1672
+ });
1673
+ var productListQuery = z.object({
1674
+ ...listCursorFields,
1675
+ /** Only active (or only archived) products. */
1676
+ active: z.boolean().optional(),
1677
+ /** Creation-date window (Unix timestamps). */
1678
+ created: createdRange.optional(),
1679
+ /** Only these product ids — cannot combine with the cursor params. */
1680
+ ids: z.array(z.string()).optional(),
1681
+ /** Only shippable (physical) products. */
1682
+ shippable: z.boolean().optional(),
1683
+ /** Only products with this url. */
1684
+ url: z.string().optional()
1685
+ });
1686
+ var productSearchReq = z.object({ ...searchReqFields });
1687
+ var product = z.looseObject({
1688
+ id: z.string(),
1689
+ object: z.string().optional(),
1690
+ active: z.boolean().optional(),
1691
+ created: z.number().optional(),
1692
+ /** Price id string, or an expanded object — kept unknown. */
1693
+ default_price: z.unknown().optional(),
1694
+ description: z.string().nullable().optional(),
1695
+ images: z.array(z.string()).optional(),
1696
+ marketing_features: z.array(z.looseObject({})).optional(),
1697
+ livemode: z.boolean().optional(),
1698
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
1699
+ name: z.string().optional(),
1700
+ package_dimensions: z.looseObject({}).nullable().optional(),
1701
+ shippable: z.boolean().nullable().optional(),
1702
+ statement_descriptor: z.string().nullable().optional(),
1703
+ /** Tax code id string, or an expanded object — kept unknown. */
1704
+ tax_code: z.unknown().optional(),
1705
+ unit_label: z.string().nullable().optional(),
1706
+ updated: z.number().optional(),
1707
+ url: z.string().nullable().optional()
1708
+ });
1709
+ var deletedProduct = z.looseObject({
1710
+ id: z.string(),
1711
+ object: z.string().optional(),
1712
+ deleted: z.boolean()
1713
+ });
1714
+
1715
+ // src/stripe/resources/products.ts
1716
+ var productListRes = stripeList(product);
1717
+ var productSearchRes = stripeSearchResult(product);
1718
+ function bodyIfNonEmpty4(body) {
1719
+ return Object.keys(body).length > 0 ? { body } : {};
1720
+ }
1721
+ var Products = class {
1722
+ constructor(http) {
1723
+ this.http = http;
1724
+ }
1725
+ http;
1726
+ /**
1727
+ * Create a Product. `default_price_data` creates the product's default
1728
+ * Price in the same call — its `unit_amount` is integer MINOR units, sent
1729
+ * to Stripe unchanged. Pass `idempotencyKey` to make the POST safely
1730
+ * replayable (and retry-eligible).
1731
+ *
1732
+ * Docs: https://docs.stripe.com/api/products/create
1733
+ *
1734
+ * @example
1735
+ * const prod = await payweave.stripe.products.create({
1736
+ * name: "Pro Plan",
1737
+ * metadata: { pwv_reference: "pwv_plan_pro" },
1738
+ * default_price_data: {
1739
+ * currency: "usd",
1740
+ * unit_amount: 1500, // $15.00 in minor units
1741
+ * recurring: { interval: "month" },
1742
+ * },
1743
+ * }, { idempotencyKey: "push-pro-plan-v1" });
1744
+ * console.log(prod.id, prod.default_price);
1745
+ */
1746
+ async create(input, opts = {}) {
1747
+ const body = parseRequest(productCreateReq, input);
1748
+ return this.http.request({
1749
+ method: "POST",
1750
+ path: "/v1/products",
1751
+ body,
1752
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1753
+ schema: product
1754
+ });
1755
+ }
1756
+ /**
1757
+ * Retrieve a Product by id (`prod_*`). A 404 for an unknown id surfaces as
1758
+ * {@link PayweaveNotFoundError}.
1759
+ *
1760
+ * Docs: https://docs.stripe.com/api/products/retrieve
1761
+ *
1762
+ * @example
1763
+ * const prod = await payweave.stripe.products.retrieve("prod_123");
1764
+ * console.log(prod.name, prod.active);
1765
+ */
1766
+ async retrieve(id) {
1767
+ const productId = requireId(id, "product");
1768
+ return this.http.request({
1769
+ method: "GET",
1770
+ path: `/v1/products/${encodeURIComponent(productId)}`,
1771
+ schema: product
1772
+ });
1773
+ }
1774
+ /**
1775
+ * Update a Product. Fields not provided remain unchanged. `active: false`
1776
+ * ARCHIVES the product (no new purchases) — the sync-flow alternative to
1777
+ * deletion, since products with prices cannot be deleted (PW-803 relies on
1778
+ * this). Pass `idempotencyKey` to make the POST safely replayable (and
1779
+ * retry-eligible).
1780
+ *
1781
+ * Docs: https://docs.stripe.com/api/products/update
1782
+ *
1783
+ * @example
1784
+ * const archived = await payweave.stripe.products.update("prod_123", { active: false });
1785
+ * console.log(archived.active); // false
1786
+ */
1787
+ async update(id, input = {}, opts = {}) {
1788
+ const productId = requireId(id, "product");
1789
+ const body = parseRequest(productUpdateReq, input);
1790
+ return this.http.request({
1791
+ method: "POST",
1792
+ path: `/v1/products/${encodeURIComponent(productId)}`,
1793
+ ...bodyIfNonEmpty4(body),
1794
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
1795
+ schema: product
1796
+ });
1797
+ }
1798
+ /**
1799
+ * Delete a Product. Only succeeds when the product has NO prices attached
1800
+ * (and, for `type=good`, no SKUs) — otherwise Stripe rejects with a 400
1801
+ * (surfaced as {@link PayweaveValidationError}). Sync flows should archive
1802
+ * with `update(id, { active: false })` instead. Returns the deletion stub
1803
+ * `{ id, object: "product", deleted: true }`.
1804
+ *
1805
+ * Docs: https://docs.stripe.com/api/products/delete
1806
+ *
1807
+ * @example
1808
+ * const gone = await payweave.stripe.products.delete("prod_123");
1809
+ * console.log(gone.deleted); // true
1810
+ */
1811
+ async delete(id) {
1812
+ const productId = requireId(id, "product");
1813
+ return this.http.request({
1814
+ method: "DELETE",
1815
+ path: `/v1/products/${encodeURIComponent(productId)}`,
1816
+ schema: deletedProduct
1817
+ });
1818
+ }
1819
+ /**
1820
+ * List Products (newest first). Cursor pagination: `limit` +
1821
+ * `starting_after`/`ending_before`; `created` becomes bracket query keys
1822
+ * and `ids` explicit indices (`ids[0]=...` — cannot combine `ids` with the
1823
+ * cursor params).
1824
+ *
1825
+ * Docs: https://docs.stripe.com/api/products/list
1826
+ *
1827
+ * @example
1828
+ * const page = await payweave.stripe.products.list({ active: true, limit: 50 });
1829
+ * console.log(page.data.length, page.has_more);
1830
+ */
1831
+ async list(query = {}) {
1832
+ const { ids, ...rest } = parseRequest(productListQuery, query);
1833
+ const q = flattenQuery(rest);
1834
+ ids?.forEach((id, i) => {
1835
+ q[`ids[${i}]`] = id;
1836
+ });
1837
+ return this.http.request({
1838
+ method: "GET",
1839
+ path: "/v1/products",
1840
+ query: q,
1841
+ schema: productListRes
1842
+ });
1843
+ }
1844
+ /**
1845
+ * Async iterator over ALL Products matching `query`, transparently
1846
+ * following `has_more` with `starting_after = <last id>` (providers.md
1847
+ * §3.1). `ids` is not supported here — Stripe forbids combining it with
1848
+ * cursors; use {@link Products.list}.
1849
+ *
1850
+ * Docs: https://docs.stripe.com/api/products/list
1851
+ *
1852
+ * @example
1853
+ * for await (const prod of payweave.stripe.products.iterate({ active: true })) {
1854
+ * console.log(prod.id, prod.name);
1855
+ * }
1856
+ */
1857
+ async *iterate(query = {}) {
1858
+ const base = parseRequest(productListQuery, query);
1859
+ yield* iterateStripeList(
1860
+ (startingAfter) => this.http.request({
1861
+ method: "GET",
1862
+ path: "/v1/products",
1863
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
1864
+ schema: productListRes
1865
+ })
1866
+ );
1867
+ }
1868
+ /**
1869
+ * Search Products with Stripe's search query language (e.g.
1870
+ * `active:'true' AND metadata['order_id']:'6735'`). Pagination is
1871
+ * TOKEN-based: pass the previous page's `next_page` as `page` (never
1872
+ * `starting_after`). Search is eventually consistent — don't use it in
1873
+ * read-after-write flows.
1874
+ *
1875
+ * Docs: https://docs.stripe.com/api/products/search
1876
+ *
1877
+ * @example
1878
+ * const found = await payweave.stripe.products.search({
1879
+ * query: "metadata['pwv_reference']:'pwv_plan_pro'",
1880
+ * });
1881
+ * console.log(found.data[0]?.id, found.has_more);
1882
+ */
1883
+ async search(input) {
1884
+ const q = parseRequest(productSearchReq, input);
1885
+ return this.http.request({
1886
+ method: "GET",
1887
+ path: "/v1/products/search",
1888
+ query: flattenQuery(q),
1889
+ schema: productSearchRes
1890
+ });
1891
+ }
1892
+ /**
1893
+ * Async iterator over ALL Products matching a search query, transparently
1894
+ * following `has_more` with `page = <next_page token>` — search pagination
1895
+ * differs from list pagination (https://docs.stripe.com/api/pagination/search).
1896
+ *
1897
+ * Docs: https://docs.stripe.com/api/products/search
1898
+ *
1899
+ * @example
1900
+ * for await (const prod of payweave.stripe.products.iterateSearch({
1901
+ * query: "active:'true'",
1902
+ * })) {
1903
+ * console.log(prod.id);
1904
+ * }
1905
+ */
1906
+ async *iterateSearch(input) {
1907
+ const base = parseRequest(productSearchReq, input);
1908
+ yield* iterateStripeSearch(
1909
+ (page) => this.http.request({
1910
+ method: "GET",
1911
+ path: "/v1/products/search",
1912
+ query: flattenQuery({ ...base, page }),
1913
+ schema: productSearchRes
1914
+ })
1915
+ );
1916
+ }
1917
+ };
1918
+ var refundCreateReq = z.object({
1919
+ /**
1920
+ * Positive integer in the smallest currency unit (minor units) — "can
1921
+ * refund only up to the remaining, unrefunded amount of the charge".
1922
+ * Omit to refund in full.
1923
+ */
1924
+ amount: z.number().int().positive().optional(),
1925
+ /** The identifier of the charge to refund (`ch_*`). */
1926
+ charge: z.string().optional(),
1927
+ /**
1928
+ * The identifier of the PaymentIntent to refund (`pi_*`) — the path the
1929
+ * unified layer uses (providers.md §3.3: refunds go against the payment
1930
+ * intent).
1931
+ */
1932
+ payment_intent: z.string().optional(),
1933
+ /**
1934
+ * Reason for the refund. If set: `duplicate` | `fraudulent` |
1935
+ * `requested_by_customer`.
1936
+ */
1937
+ reason: z.enum(["duplicate", "fraudulent", "requested_by_customer"]).optional(),
1938
+ /**
1939
+ * For payment methods without native refund support (e.g. Konbini,
1940
+ * PromptPay) — customer email to receive refund instructions.
1941
+ */
1942
+ instructions_email: z.string().optional(),
1943
+ metadata: metadataSchema.optional(),
1944
+ /**
1945
+ * Origin of the refund. `customer_balance` refunds from a Customer
1946
+ * Balance instead of a Charge/PaymentIntent — when provided, a
1947
+ * Charge/PaymentIntent identifier is not required.
1948
+ */
1949
+ origin: z.enum(["customer_balance"]).optional(),
1950
+ /**
1951
+ * Whether the application fee should be refunded too (refundable only by
1952
+ * the application that created the charge — Connect).
1953
+ */
1954
+ refund_application_fee: z.boolean().optional(),
1955
+ /**
1956
+ * Whether the transfer should be reversed when refunding (reversible only
1957
+ * by the application that created the charge — Connect).
1958
+ */
1959
+ reverse_transfer: z.boolean().optional()
1960
+ }).refine(
1961
+ (v) => v.charge !== void 0 || v.payment_intent !== void 0 || v.origin !== void 0,
1962
+ {
1963
+ message: "one of charge, payment_intent, or origin is required (https://docs.stripe.com/api/refunds/create)"
1964
+ }
1965
+ );
1966
+ var refundUpdateReq = z.object({
1967
+ metadata: metadataSchema.optional()
1968
+ });
1969
+ var refundListQuery = z.object({
1970
+ ...listCursorFields,
1971
+ /** Only return refunds for this Charge id. */
1972
+ charge: z.string().optional(),
1973
+ /** Only return refunds for this PaymentIntent id. */
1974
+ payment_intent: z.string().optional(),
1975
+ /** Creation-date window (Unix timestamps). */
1976
+ created: createdRange.optional()
1977
+ });
1978
+ var refund = z.looseObject({
1979
+ id: z.string(),
1980
+ object: z.string().optional(),
1981
+ amount: z.number().optional(),
1982
+ /** Balance transaction id string, or an expanded object — kept unknown. */
1983
+ balance_transaction: z.unknown().optional(),
1984
+ /** Charge id string, or an expanded object — kept unknown. */
1985
+ charge: z.unknown().optional(),
1986
+ created: z.number().optional(),
1987
+ currency: z.string().optional(),
1988
+ /** Non-card refunds only. */
1989
+ description: z.string().nullable().optional(),
1990
+ /** Transaction-specific details — child hashes deliberately untyped. */
1991
+ destination_details: z.looseObject({}).nullable().optional(),
1992
+ /** Balance transaction reversing the initial one after a failed refund. */
1993
+ failure_balance_transaction: z.unknown().optional(),
1994
+ /**
1995
+ * `lost_or_stolen_card` | `expired_or_canceled_card` |
1996
+ * `charge_for_pending_refund_disputed` | `insufficient_funds` | `declined` |
1997
+ * `merchant_request` | `unknown` — kept loose (drift logs, never throws).
1998
+ */
1999
+ failure_reason: z.string().nullable().optional(),
2000
+ instructions_email: z.string().nullable().optional(),
2001
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
2002
+ /** Present when status is `requires_action` — child shape kept loose. */
2003
+ next_action: z.looseObject({}).nullable().optional(),
2004
+ /** PaymentIntent id string, or an expanded object — kept unknown. */
2005
+ payment_intent: z.unknown().optional(),
2006
+ /** `processing` | `insufficient_funds` | `charge_pending` — kept loose. */
2007
+ pending_reason: z.string().nullable().optional(),
2008
+ /**
2009
+ * `duplicate` | `fraudulent` | `requested_by_customer` or Stripe-generated
2010
+ * `expired_uncaptured_charge` — kept loose.
2011
+ */
2012
+ reason: z.string().nullable().optional(),
2013
+ receipt_number: z.string().nullable().optional(),
2014
+ /** Transfer reversal id string, or an expanded object — kept unknown. */
2015
+ source_transfer_reversal: z.unknown().optional(),
2016
+ /**
2017
+ * `pending` | `requires_action` | `succeeded` | `failed` | `canceled` —
2018
+ * normalization is the unified layer's job.
2019
+ */
2020
+ status: z.string().nullable().optional(),
2021
+ /** Transfer reversal id string, or an expanded object — kept unknown. */
2022
+ transfer_reversal: z.unknown().optional()
2023
+ });
2024
+
2025
+ // src/stripe/resources/refunds.ts
2026
+ var refundListRes = stripeList(refund);
2027
+ function bodyIfNonEmpty5(body) {
2028
+ return Object.keys(body).length > 0 ? { body } : {};
2029
+ }
2030
+ var Refunds = class {
2031
+ constructor(http) {
2032
+ this.http = http;
2033
+ }
2034
+ http;
2035
+ /**
2036
+ * Create a refund. Target either a `charge` or a `payment_intent` (the
2037
+ * unified layer refunds against the payment intent — providers.md §3.3);
2038
+ * one of the two is required unless `origin: "customer_balance"`. `amount`
2039
+ * is integer MINOR units and defaults to the full remaining unrefunded
2040
+ * amount. Stripe errors if the target is already fully refunded (surfaced
2041
+ * as {@link PayweaveValidationError} with providerCode
2042
+ * `charge_already_refunded` on the 400).
2043
+ *
2044
+ * Money-moving POST: never auto-retried bare — pass `idempotencyKey` to
2045
+ * make it safely replayable (and retry-eligible).
2046
+ *
2047
+ * Docs: https://docs.stripe.com/api/refunds/create
2048
+ *
2049
+ * @example
2050
+ * const re = await payweave.stripe.refunds.create({
2051
+ * payment_intent: "pi_123",
2052
+ * amount: 500, // partial refund, minor units
2053
+ * reason: "requested_by_customer",
2054
+ * }, { idempotencyKey: "order-8123-refund" });
2055
+ * console.log(re.status); // "succeeded" | "pending" | ...
2056
+ */
2057
+ async create(input, opts = {}) {
2058
+ const body = parseRequest(refundCreateReq, input);
2059
+ return this.http.request({
2060
+ method: "POST",
2061
+ path: "/v1/refunds",
2062
+ body,
2063
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
2064
+ schema: refund
2065
+ });
2066
+ }
2067
+ /**
2068
+ * Retrieve a refund by id (`re_*`). A 404 for an unknown id surfaces as
2069
+ * {@link PayweaveNotFoundError}.
2070
+ *
2071
+ * Docs: https://docs.stripe.com/api/refunds/retrieve
2072
+ *
2073
+ * @example
2074
+ * const re = await payweave.stripe.refunds.retrieve("re_123");
2075
+ * if (re.status === "succeeded") { }
2076
+ */
2077
+ async retrieve(id) {
2078
+ const refundId = requireId(id, "refund");
2079
+ return this.http.request({
2080
+ method: "GET",
2081
+ path: `/v1/refunds/${encodeURIComponent(refundId)}`,
2082
+ schema: refund
2083
+ });
2084
+ }
2085
+ /**
2086
+ * Update a refund. `metadata` is the ONLY updatable field; unset individual
2087
+ * keys by posting an empty string value.
2088
+ *
2089
+ * Docs: https://docs.stripe.com/api/refunds/update
2090
+ *
2091
+ * @example
2092
+ * const re = await payweave.stripe.refunds.update("re_123", {
2093
+ * metadata: { order_id: "6735" },
2094
+ * });
2095
+ */
2096
+ async update(id, input = {}) {
2097
+ const refundId = requireId(id, "refund");
2098
+ const body = parseRequest(refundUpdateReq, input);
2099
+ return this.http.request({
2100
+ method: "POST",
2101
+ path: `/v1/refunds/${encodeURIComponent(refundId)}`,
2102
+ ...bodyIfNonEmpty5(body),
2103
+ schema: refund
2104
+ });
2105
+ }
2106
+ /**
2107
+ * Cancel a refund. ONLY valid while the refund's status is
2108
+ * `requires_action` — "you can't cancel refunds in other states" (only
2109
+ * refunds for payment methods that require customer action ever enter that
2110
+ * state); Stripe raises an error otherwise (surfaced as
2111
+ * {@link PayweaveValidationError} on the 400). Takes no body parameters.
2112
+ *
2113
+ * Docs: https://docs.stripe.com/api/refunds/cancel
2114
+ *
2115
+ * @example
2116
+ * const re = await payweave.stripe.refunds.cancel("re_123");
2117
+ * console.log(re.status); // "canceled"
2118
+ */
2119
+ async cancel(id) {
2120
+ const refundId = requireId(id, "refund");
2121
+ return this.http.request({
2122
+ method: "POST",
2123
+ path: `/v1/refunds/${encodeURIComponent(refundId)}/cancel`,
2124
+ schema: refund
2125
+ });
2126
+ }
2127
+ /**
2128
+ * List refunds (newest first). Filter by `charge` or `payment_intent`;
2129
+ * cursor pagination via `limit` + `starting_after`/`ending_before`; the
2130
+ * `created` window becomes bracket query keys (`created[gte]`).
2131
+ *
2132
+ * Docs: https://docs.stripe.com/api/refunds/list
2133
+ *
2134
+ * @example
2135
+ * const page = await payweave.stripe.refunds.list({ payment_intent: "pi_123", limit: 50 });
2136
+ * console.log(page.data.length, page.has_more);
2137
+ */
2138
+ async list(query = {}) {
2139
+ const q = parseRequest(refundListQuery, query);
2140
+ return this.http.request({
2141
+ method: "GET",
2142
+ path: "/v1/refunds",
2143
+ query: flattenQuery(q),
2144
+ schema: refundListRes
2145
+ });
2146
+ }
2147
+ /**
2148
+ * Async iterator over ALL refunds matching `query`, transparently following
2149
+ * `has_more` with `starting_after = <last id>`.
2150
+ *
2151
+ * Docs: https://docs.stripe.com/api/refunds/list
2152
+ *
2153
+ * @example
2154
+ * for await (const re of payweave.stripe.refunds.iterate({ charge: "ch_123" })) {
2155
+ * console.log(re.id, re.status);
2156
+ * }
2157
+ */
2158
+ async *iterate(query = {}) {
2159
+ const base = parseRequest(refundListQuery, query);
2160
+ yield* iterateStripeList(
2161
+ (startingAfter) => this.http.request({
2162
+ method: "GET",
2163
+ path: "/v1/refunds",
2164
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
2165
+ schema: refundListRes
2166
+ })
2167
+ );
2168
+ }
2169
+ };
2170
+ var recurring2 = z.object({
2171
+ interval: z.enum(["day", "week", "month", "year"]),
2172
+ interval_count: z.number().int().optional()
2173
+ });
2174
+ var subscriptionItemPriceData = z.object({
2175
+ /** Three-letter ISO currency code, lowercase (e.g. `usd`). Required. */
2176
+ currency: z.string(),
2177
+ /** Existing Product id (`prod_*`) this price belongs to. Required. */
2178
+ product: z.string(),
2179
+ /** Billing frequency. Required. */
2180
+ recurring: recurring2,
2181
+ tax_behavior: z.enum(["exclusive", "inclusive", "unspecified"]).optional(),
2182
+ /** Amount in the smallest currency unit (minor units) — integer, unchanged. */
2183
+ unit_amount: z.number().int().nonnegative().optional(),
2184
+ /** Decimal string alternative to `unit_amount` (≤12 decimal places). */
2185
+ unit_amount_decimal: z.string().optional()
2186
+ });
2187
+ var discountParam = z.object({
2188
+ /** Coupon id to create a new discount from. */
2189
+ coupon: z.string().optional(),
2190
+ /** Existing Discount id to reuse. */
2191
+ discount: z.string().optional(),
2192
+ /** Promotion code id to create a new discount from. */
2193
+ promotion_code: z.string().optional()
2194
+ });
2195
+ var itemBillingThresholds = z.object({
2196
+ usage_gte: z.number().int()
2197
+ });
2198
+ var paymentBehavior = z.enum([
2199
+ "allow_incomplete",
2200
+ "default_incomplete",
2201
+ "error_if_incomplete",
2202
+ "pending_if_incomplete"
2203
+ ]);
2204
+ var prorationBehavior = z.enum(["always_invoice", "create_prorations", "none"]);
2205
+ var subscriptionItemCreateReq = z.object({
2206
+ /** Subscription id (`sub_*`) to add the item to. Required. */
2207
+ subscription: z.string().min(1),
2208
+ /** Saved Price id (`price_*`). Alternative to `price_data`. */
2209
+ price: z.string().optional(),
2210
+ /** Inline price definition. Alternative to `price`. */
2211
+ price_data: subscriptionItemPriceData.optional(),
2212
+ quantity: z.number().int().nonnegative().optional(),
2213
+ metadata: metadataSchema.optional(),
2214
+ billing_thresholds: itemBillingThresholds.optional(),
2215
+ /** Coupons/promotion codes to redeem into discounts for this item. */
2216
+ discounts: z.array(discountParam).optional(),
2217
+ payment_behavior: paymentBehavior.optional(),
2218
+ proration_behavior: prorationBehavior.optional(),
2219
+ /** Unix timestamp — prorate as though the update happened at this time. */
2220
+ proration_date: z.number().int().optional(),
2221
+ /** Tax Rate ids overriding the subscription's `default_tax_rates`. */
2222
+ tax_rates: z.array(z.string()).optional()
2223
+ });
2224
+ var subscriptionItemUpdateReq = z.object({
2225
+ /** Saved Price id (`price_*`). Alternative to `price_data`. */
2226
+ price: z.string().optional(),
2227
+ /** Inline price definition. Alternative to `price`. */
2228
+ price_data: subscriptionItemPriceData.optional(),
2229
+ quantity: z.number().int().nonnegative().optional(),
2230
+ metadata: metadataSchema.optional(),
2231
+ billing_thresholds: itemBillingThresholds.optional(),
2232
+ /** Coupons/promotion codes to redeem into discounts for this item. */
2233
+ discounts: z.array(discountParam).optional(),
2234
+ /** Customer is not in the flow — attempt payment immediately off-session. */
2235
+ off_session: z.boolean().optional(),
2236
+ payment_behavior: paymentBehavior.optional(),
2237
+ proration_behavior: prorationBehavior.optional(),
2238
+ /** Unix timestamp — prorate as though the update happened at this time. */
2239
+ proration_date: z.number().int().optional(),
2240
+ /** Tax Rate ids overriding the subscription's `default_tax_rates`. */
2241
+ tax_rates: z.array(z.string()).optional()
2242
+ });
2243
+ var subscriptionItemDeleteReq = z.object({
2244
+ /** Delete all usage for the item — only when the price's `usage_type` is `metered`. */
2245
+ clear_usage: z.boolean().optional(),
2246
+ payment_behavior: paymentBehavior.optional(),
2247
+ proration_behavior: prorationBehavior.optional(),
2248
+ /** Unix timestamp — prorate as though the update happened at this time. */
2249
+ proration_date: z.number().int().optional()
2250
+ });
2251
+ var subscriptionItemListQuery = z.object({
2252
+ ...listCursorFields,
2253
+ /** Subscription id (`sub_*`) whose items to list. Required. */
2254
+ subscription: z.string().min(1)
2255
+ });
2256
+ var subscriptionItem = z.looseObject({
2257
+ id: z.string(),
2258
+ object: z.string().optional(),
2259
+ /** Parent subscription id (`sub_*`). */
2260
+ subscription: z.string().optional(),
2261
+ /** The Price the customer is subscribed to — kept loose beyond its id. */
2262
+ price: z.looseObject({ id: z.string().optional() }).nullable().optional(),
2263
+ quantity: z.number().nullable().optional(),
2264
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
2265
+ created: z.number().optional(),
2266
+ /** Start of the item's current billing period (Unix timestamp). */
2267
+ current_period_start: z.number().optional(),
2268
+ /** End of the item's current billing period (Unix timestamp). */
2269
+ current_period_end: z.number().optional(),
2270
+ /** Time period the item has been billed for — nullable, expandable. */
2271
+ billed_until: z.unknown().optional(),
2272
+ billing_thresholds: z.looseObject({}).nullable().optional(),
2273
+ /** Discount ids (or expanded objects) — kept unknown. */
2274
+ discounts: z.unknown().optional(),
2275
+ /** Tax Rate objects applied to this item — kept unknown. */
2276
+ tax_rates: z.unknown().optional()
2277
+ });
2278
+ var subscriptionItemDeleted = z.looseObject({
2279
+ id: z.string(),
2280
+ object: z.string().optional(),
2281
+ deleted: z.boolean().optional()
2282
+ });
2283
+
2284
+ // src/stripe/resources/subscription-items.ts
2285
+ var subscriptionItemListRes = stripeList(subscriptionItem);
2286
+ function bodyIfNonEmpty6(body) {
2287
+ return Object.keys(body).length > 0 ? { body } : {};
2288
+ }
2289
+ var SubscriptionItems = class {
2290
+ constructor(http) {
2291
+ this.http = http;
2292
+ }
2293
+ http;
2294
+ /**
2295
+ * Add a new item (price) to an existing subscription. Prorations follow
2296
+ * `proration_behavior` (default `create_prorations`). Pass `idempotencyKey`
2297
+ * to make the POST safely replayable (and retry-eligible).
2298
+ *
2299
+ * Docs: https://docs.stripe.com/api/subscription_items/create
2300
+ *
2301
+ * @example
2302
+ * const item = await payweave.stripe.subscriptionItems.create({
2303
+ * subscription: "sub_123",
2304
+ * price: "price_123",
2305
+ * quantity: 2,
2306
+ * }, { idempotencyKey: "sub_123-addon-seat" });
2307
+ * console.log(item.id, item.current_period_end);
2308
+ */
2309
+ async create(input, opts = {}) {
2310
+ const body = parseRequest(subscriptionItemCreateReq, input);
2311
+ return this.http.request({
2312
+ method: "POST",
2313
+ path: "/v1/subscription_items",
2314
+ body,
2315
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
2316
+ schema: subscriptionItem
2317
+ });
2318
+ }
2319
+ /**
2320
+ * Retrieve a subscription item by id (`si_*`). A 404 for an unknown id
2321
+ * surfaces as {@link PayweaveNotFoundError}.
2322
+ *
2323
+ * Docs: https://docs.stripe.com/api/subscription_items/retrieve
2324
+ *
2325
+ * @example
2326
+ * const item = await payweave.stripe.subscriptionItems.retrieve("si_123");
2327
+ * console.log(item.price?.id, item.quantity);
2328
+ */
2329
+ async retrieve(id) {
2330
+ const itemId = requireId(id, "subscription item");
2331
+ return this.http.request({
2332
+ method: "GET",
2333
+ path: `/v1/subscription_items/${encodeURIComponent(itemId)}`,
2334
+ schema: subscriptionItem
2335
+ });
2336
+ }
2337
+ /**
2338
+ * Update a subscription item — switch its `price`, change `quantity`, etc.
2339
+ * Proration parameters (`proration_behavior`, `proration_date`) are passed
2340
+ * through exactly as documented. Pass `idempotencyKey` to make the POST
2341
+ * safely replayable (and retry-eligible).
2342
+ *
2343
+ * Docs: https://docs.stripe.com/api/subscription_items/update
2344
+ *
2345
+ * @example
2346
+ * const item = await payweave.stripe.subscriptionItems.update("si_123", {
2347
+ * quantity: 5,
2348
+ * proration_behavior: "create_prorations",
2349
+ * });
2350
+ */
2351
+ async update(id, input = {}, opts = {}) {
2352
+ const itemId = requireId(id, "subscription item");
2353
+ const body = parseRequest(subscriptionItemUpdateReq, input);
2354
+ return this.http.request({
2355
+ method: "POST",
2356
+ path: `/v1/subscription_items/${encodeURIComponent(itemId)}`,
2357
+ ...bodyIfNonEmpty6(body),
2358
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
2359
+ schema: subscriptionItem
2360
+ });
2361
+ }
2362
+ /**
2363
+ * Delete an item from its subscription — removing a price the customer was
2364
+ * subscribed to. Optional form params ride the DELETE (`clear_usage` only
2365
+ * for metered prices; prorations per `proration_behavior`). Returns the
2366
+ * `{ id, object, deleted: true }` acknowledgement. A subscription cannot
2367
+ * lose its last item this way — Stripe rejects that with a 400
2368
+ * (surfaced as {@link PayweaveValidationError}); cancel the subscription
2369
+ * instead.
2370
+ *
2371
+ * Docs: https://docs.stripe.com/api/subscription_items/delete
2372
+ *
2373
+ * @example
2374
+ * const gone = await payweave.stripe.subscriptionItems.delete("si_123", {
2375
+ * proration_behavior: "none",
2376
+ * });
2377
+ * console.log(gone.deleted); // true
2378
+ */
2379
+ async delete(id, input = {}) {
2380
+ const itemId = requireId(id, "subscription item");
2381
+ const body = parseRequest(subscriptionItemDeleteReq, input);
2382
+ return this.http.request({
2383
+ method: "DELETE",
2384
+ path: `/v1/subscription_items/${encodeURIComponent(itemId)}`,
2385
+ ...bodyIfNonEmpty6(body),
2386
+ schema: subscriptionItemDeleted
2387
+ });
2388
+ }
2389
+ /**
2390
+ * List the items of ONE subscription — `subscription` is required by the
2391
+ * API. Cursor pagination: `limit` + `starting_after`/`ending_before`.
2392
+ *
2393
+ * Docs: https://docs.stripe.com/api/subscription_items/list
2394
+ *
2395
+ * @example
2396
+ * const page = await payweave.stripe.subscriptionItems.list({
2397
+ * subscription: "sub_123",
2398
+ * limit: 10,
2399
+ * });
2400
+ * console.log(page.data.length, page.has_more);
2401
+ */
2402
+ async list(query) {
2403
+ const q = parseRequest(subscriptionItemListQuery, query);
2404
+ return this.http.request({
2405
+ method: "GET",
2406
+ path: "/v1/subscription_items",
2407
+ query: flattenQuery(q),
2408
+ schema: subscriptionItemListRes
2409
+ });
2410
+ }
2411
+ /**
2412
+ * Async iterator over ALL items of a subscription, transparently following
2413
+ * `has_more` with `starting_after = <last id>`.
2414
+ *
2415
+ * Docs: https://docs.stripe.com/api/subscription_items/list
2416
+ *
2417
+ * @example
2418
+ * for await (const item of payweave.stripe.subscriptionItems.iterate({ subscription: "sub_123" })) {
2419
+ * console.log(item.id, item.price?.id);
2420
+ * }
2421
+ */
2422
+ async *iterate(query) {
2423
+ const base = parseRequest(subscriptionItemListQuery, query);
2424
+ yield* iterateStripeList(
2425
+ (startingAfter) => this.http.request({
2426
+ method: "GET",
2427
+ path: "/v1/subscription_items",
2428
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
2429
+ schema: subscriptionItemListRes
2430
+ })
2431
+ );
2432
+ }
2433
+ };
2434
+ var createItemParam = z.object({
2435
+ /** Saved Price id (`price_*`). Alternative to `price_data`. */
2436
+ price: z.string().optional(),
2437
+ /** Inline price definition (recurring required). Alternative to `price`. */
2438
+ price_data: subscriptionItemPriceData.optional(),
2439
+ quantity: z.number().int().nonnegative().optional(),
2440
+ metadata: metadataSchema.optional(),
2441
+ billing_thresholds: itemBillingThresholds.optional(),
2442
+ /** Coupons/promotion codes to redeem into discounts for this item. */
2443
+ discounts: z.array(discountParam).optional(),
2444
+ /** Tax Rate ids overriding the subscription's `default_tax_rates`. */
2445
+ tax_rates: z.array(z.string()).optional()
2446
+ });
2447
+ var updateItemParam = z.object({
2448
+ /** Existing SubscriptionItem id (`si_*`) to update. */
2449
+ id: z.string().optional(),
2450
+ /** Saved Price id (`price_*`). Alternative to `price_data`. */
2451
+ price: z.string().optional(),
2452
+ /** Inline price definition (recurring required). Alternative to `price`. */
2453
+ price_data: subscriptionItemPriceData.optional(),
2454
+ quantity: z.number().int().nonnegative().optional(),
2455
+ metadata: metadataSchema.optional(),
2456
+ /** Set to `true` to delete the specified item. */
2457
+ deleted: z.boolean().optional(),
2458
+ /** Delete all usage for the item (metered prices). */
2459
+ clear_usage: z.boolean().optional(),
2460
+ billing_thresholds: itemBillingThresholds.optional(),
2461
+ /** Coupons/promotion codes to redeem into discounts for this item. */
2462
+ discounts: z.array(discountParam).optional(),
2463
+ /** Tax Rate ids overriding the subscription's `default_tax_rates`. */
2464
+ tax_rates: z.array(z.string()).optional()
2465
+ });
2466
+ var cancelAt = z.union([
2467
+ z.number().int(),
2468
+ z.enum(["max_billed_until", "max_period_end", "min_period_end"])
2469
+ ]);
2470
+ var cancellationDetails = z.object({
2471
+ /** Additional comments about why the user canceled. */
2472
+ comment: z.string().optional(),
2473
+ /** The customer-submitted reason for cancellation. */
2474
+ feedback: z.enum([
2475
+ "customer_service",
2476
+ "low_quality",
2477
+ "missing_features",
2478
+ "other",
2479
+ "switched_service",
2480
+ "too_complex",
2481
+ "too_expensive",
2482
+ "unused"
2483
+ ]).optional()
2484
+ });
2485
+ var trialEnd = z.union([z.literal("now"), z.number().int()]);
2486
+ var subscriptionCreateReq = z.object({
2487
+ /**
2488
+ * Customer id (`cus_*`) to subscribe. Stripe requires a customer (the
2489
+ * unverified `customer_account` alternative is untyped in this P0 subset).
2490
+ */
2491
+ customer: z.string().optional(),
2492
+ /** Items being subscribed to — up to 20, each with an attached price. Required. */
2493
+ items: z.array(createItemParam).max(20),
2494
+ /** Past Unix timestamp to backdate the subscription's start date to. */
2495
+ backdate_start_date: z.number().int().optional(),
2496
+ /** Future Unix timestamp anchoring the billing cycle (first full invoice). */
2497
+ billing_cycle_anchor: z.number().int().optional(),
2498
+ /** Unix timestamp or symbolic value at which to auto-cancel. */
2499
+ cancel_at: cancelAt.optional(),
2500
+ /** Cancel at the end of the current period instead of immediately. Default false. */
2501
+ cancel_at_period_end: z.boolean().optional(),
2502
+ collection_method: z.enum(["charge_automatically", "send_invoice"]).optional(),
2503
+ /** Three-letter ISO currency code, lowercase. */
2504
+ currency: z.string().optional(),
2505
+ /** Days until invoices are due — `send_invoice` collection only. */
2506
+ days_until_due: z.number().int().optional(),
2507
+ /** PaymentMethod id (`pm_*`) used as this subscription's default. */
2508
+ default_payment_method: z.string().optional(),
2509
+ /** Source id used as this subscription's default payment source. */
2510
+ default_source: z.string().optional(),
2511
+ /** Tax Rate ids applied by default to the subscription's items. */
2512
+ default_tax_rates: z.array(z.string()).optional(),
2513
+ /** ≤500 chars, displayable to customers. */
2514
+ description: z.string().max(500).optional(),
2515
+ /** Coupons/promotion codes to redeem into discounts for the subscription. */
2516
+ discounts: z.array(discountParam).optional(),
2517
+ metadata: metadataSchema.optional(),
2518
+ /** Customer is not in the checkout flow. Default false. */
2519
+ off_session: z.boolean().optional(),
2520
+ payment_behavior: z.enum(["allow_incomplete", "default_incomplete", "error_if_incomplete"]).optional(),
2521
+ /** Invoice-pending-items schedule between billing cycles. */
2522
+ pending_invoice_item_interval: z.object({
2523
+ interval: z.enum(["day", "month", "week", "year"]),
2524
+ interval_count: z.number().int().optional()
2525
+ }).optional(),
2526
+ proration_behavior: z.enum(["create_prorations", "none"]).optional(),
2527
+ /** Unix timestamp or `"now"` — when the trial ends. */
2528
+ trial_end: trialEnd.optional(),
2529
+ /** Use the price's/plan's trial period. Default false. */
2530
+ trial_from_plan: z.boolean().optional(),
2531
+ /** Trial length in days (alternative to `trial_end`). */
2532
+ trial_period_days: z.number().int().optional(),
2533
+ /** What happens at trial end when no payment method is present. */
2534
+ trial_settings: z.object({
2535
+ end_behavior: z.object({
2536
+ missing_payment_method: z.enum(["cancel", "create_invoice", "pause"])
2537
+ })
2538
+ }).optional()
2539
+ });
2540
+ var pauseCollection = z.union([
2541
+ z.object({
2542
+ behavior: z.enum(["keep_as_draft", "mark_uncollectible", "void"]),
2543
+ /** Unix timestamp at which collection automatically resumes. */
2544
+ resumes_at: z.number().int().optional()
2545
+ }),
2546
+ z.literal("")
2547
+ ]);
2548
+ var subscriptionUpdateReq = z.object({
2549
+ /** Item changes: update by `id`, add by `price`, remove with `deleted: true`. */
2550
+ items: z.array(updateItemParam).optional(),
2551
+ /** Unix timestamp or symbolic value at which to auto-cancel. */
2552
+ cancel_at: cancelAt.optional(),
2553
+ /** `true` = cancel when the current period ends; `false` = clear a pending one. */
2554
+ cancel_at_period_end: z.boolean().optional(),
2555
+ cancellation_details: cancellationDetails.optional(),
2556
+ /** `now` resets the billing cycle anchor; `unchanged` keeps it. */
2557
+ billing_cycle_anchor: z.enum(["now", "unchanged"]).optional(),
2558
+ collection_method: z.enum(["charge_automatically", "send_invoice"]).optional(),
2559
+ /** Days until invoices are due — `send_invoice` collection only. */
2560
+ days_until_due: z.number().int().optional(),
2561
+ /** PaymentMethod id (`pm_*`) used as this subscription's default. */
2562
+ default_payment_method: z.string().optional(),
2563
+ /** ≤500 chars, displayable to customers. */
2564
+ description: z.string().max(500).optional(),
2565
+ /** Coupons/promotion codes to redeem into discounts for the subscription. */
2566
+ discounts: z.array(discountParam).optional(),
2567
+ metadata: metadataSchema.optional(),
2568
+ /** Customer is not in the checkout flow. Default false. */
2569
+ off_session: z.boolean().optional(),
2570
+ /** Pause payment collection (subscription stays `active`); `""` unsets. */
2571
+ pause_collection: pauseCollection.optional(),
2572
+ payment_behavior: z.enum([
2573
+ "allow_incomplete",
2574
+ "default_incomplete",
2575
+ "error_if_incomplete",
2576
+ "pending_if_incomplete"
2577
+ ]).optional(),
2578
+ proration_behavior: z.enum(["always_invoice", "create_prorations", "none"]).optional(),
2579
+ /** Unix timestamp — prorate as though the update happened at this time. */
2580
+ proration_date: z.number().int().optional(),
2581
+ /** Unix timestamp or `"now"` — when the trial ends. */
2582
+ trial_end: trialEnd.optional()
2583
+ });
2584
+ var subscriptionCancelReq = z.object({
2585
+ cancellation_details: cancellationDetails.optional(),
2586
+ /** Generate a final invoice for un-invoiced metered usage and pending prorations. Default false. */
2587
+ invoice_now: z.boolean().optional(),
2588
+ /** Credit remaining unused time until the period end via a proration item. Default false. */
2589
+ prorate: z.boolean().optional()
2590
+ });
2591
+ var subscriptionResumeReq = z.object({
2592
+ /** `now` resets the anchor and starts a new period; `unchanged` keeps it. Default `now`. */
2593
+ billing_cycle_anchor: z.enum(["now", "unchanged"]).optional(),
2594
+ proration_behavior: z.enum(["always_invoice", "create_prorations", "none"]).optional(),
2595
+ /** Unix timestamp — prorate as though resumed at this time. */
2596
+ proration_date: z.number().int().optional()
2597
+ });
2598
+ var subscriptionListQuery = z.object({
2599
+ ...listCursorFields,
2600
+ /** Filter by Customer id. */
2601
+ customer: z.string().optional(),
2602
+ /** Filter by recurring Price id. */
2603
+ price: z.string().optional(),
2604
+ /**
2605
+ * Status filter. Documented special values (verified 2026-07-12):
2606
+ * `canceled` (includes deleted customers' subscriptions), `ended` (canceled
2607
+ * + expired due to incomplete payment), `all`; omitted = all non-canceled
2608
+ * subscriptions. Kept as an open string — the docs page does not enumerate
2609
+ * a closed value set for this filter (conservative); Stripe
2610
+ * validates server-side.
2611
+ */
2612
+ status: z.string().optional(),
2613
+ collection_method: z.enum(["charge_automatically", "send_invoice"]).optional(),
2614
+ /** Creation-date window (Unix timestamps). */
2615
+ created: createdRange.optional(),
2616
+ /** Current-period-start window (Unix timestamps). */
2617
+ current_period_start: createdRange.optional(),
2618
+ /** Current-period-end window (Unix timestamps). */
2619
+ current_period_end: createdRange.optional()
2620
+ });
2621
+ var subscription = z.looseObject({
2622
+ id: z.string(),
2623
+ object: z.string().optional(),
2624
+ /**
2625
+ * `incomplete` | `incomplete_expired` | `trialing` | `active` | `past_due`
2626
+ * | `canceled` | `unpaid` | `paused` — normalization is the unified layer's
2627
+ * job.
2628
+ */
2629
+ status: z.string().optional(),
2630
+ /** Customer id string, or an expanded object — kept unknown. */
2631
+ customer: z.unknown().optional(),
2632
+ /** Embedded (paginated) list of the subscription's items. */
2633
+ items: stripeList(subscriptionItem).optional(),
2634
+ currency: z.string().optional(),
2635
+ collection_method: z.string().optional(),
2636
+ /** Unix timestamp at which the subscription will auto-cancel. */
2637
+ cancel_at: z.number().nullable().optional(),
2638
+ /** Whether the subscription cancels when the current period ends. */
2639
+ cancel_at_period_end: z.boolean().optional(),
2640
+ /** When the cancellation was requested (Unix timestamp). */
2641
+ canceled_at: z.number().nullable().optional(),
2642
+ /** `{ reason, feedback, comment }` — kept loose. */
2643
+ cancellation_details: z.looseObject({}).nullable().optional(),
2644
+ created: z.number().optional(),
2645
+ /** Start of the subscription (may differ from `created` when backdated). */
2646
+ start_date: z.number().optional(),
2647
+ /** Anchor aligning future billing cycle dates (Unix timestamp). */
2648
+ billing_cycle_anchor: z.number().optional(),
2649
+ trial_start: z.number().nullable().optional(),
2650
+ trial_end: z.number().nullable().optional(),
2651
+ /** When the subscription ended (Unix timestamp). */
2652
+ ended_at: z.number().nullable().optional(),
2653
+ /** Latest Invoice id string, or an expanded object — kept unknown. */
2654
+ latest_invoice: z.unknown().optional(),
2655
+ /** Default PaymentMethod id string, or an expanded object — kept unknown. */
2656
+ default_payment_method: z.unknown().optional(),
2657
+ days_until_due: z.number().nullable().optional(),
2658
+ /** Payment-collection pause state — `{ behavior, resumes_at }`, kept loose. */
2659
+ pause_collection: z.looseObject({}).nullable().optional(),
2660
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
2661
+ description: z.string().nullable().optional(),
2662
+ livemode: z.boolean().optional()
2663
+ });
2664
+
2665
+ // src/stripe/resources/subscriptions.ts
2666
+ var subscriptionListRes = stripeList(subscription);
2667
+ function bodyIfNonEmpty7(body) {
2668
+ return Object.keys(body).length > 0 ? { body } : {};
2669
+ }
2670
+ var Subscriptions = class {
2671
+ constructor(http) {
2672
+ this.http = http;
2673
+ }
2674
+ http;
2675
+ /**
2676
+ * Create a subscription for an existing customer — the first invoice is
2677
+ * attempted immediately unless a trial or `billing_cycle_anchor` defers it.
2678
+ * `items` (up to 20, each with a `price` or inline `price_data`) is
2679
+ * required. Pass `idempotencyKey` to make the POST safely replayable (and
2680
+ * retry-eligible).
2681
+ *
2682
+ * Docs: https://docs.stripe.com/api/subscriptions/create
2683
+ *
2684
+ * @example
2685
+ * const sub = await payweave.stripe.subscriptions.create({
2686
+ * customer: "cus_123",
2687
+ * items: [{ price: "price_123", quantity: 1 }],
2688
+ * metadata: { pwv_plan: "pro" },
2689
+ * }, { idempotencyKey: "sub-cus_123-pro" });
2690
+ * console.log(sub.status, sub.items?.data[0]?.current_period_end);
2691
+ */
2692
+ async create(input, opts = {}) {
2693
+ const body = parseRequest(subscriptionCreateReq, input);
2694
+ return this.http.request({
2695
+ method: "POST",
2696
+ path: "/v1/subscriptions",
2697
+ body,
2698
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
2699
+ schema: subscription
2700
+ });
2701
+ }
2702
+ /**
2703
+ * Retrieve a subscription by id (`sub_*`). A 404 for an unknown id surfaces
2704
+ * as {@link PayweaveNotFoundError}. Period boundaries live on the embedded
2705
+ * items (`sub.items.data[].current_period_start/end`) on the SDK's pinned
2706
+ * API version.
2707
+ *
2708
+ * Docs: https://docs.stripe.com/api/subscriptions/retrieve
2709
+ *
2710
+ * @example
2711
+ * const sub = await payweave.stripe.subscriptions.retrieve("sub_123");
2712
+ * if (sub.status === "active") { }
2713
+ */
2714
+ async retrieve(id) {
2715
+ const subscriptionId = requireId(id, "subscription");
2716
+ return this.http.request({
2717
+ method: "GET",
2718
+ path: `/v1/subscriptions/${encodeURIComponent(subscriptionId)}`,
2719
+ schema: subscription
2720
+ });
2721
+ }
2722
+ /**
2723
+ * Update a subscription: change items/quantities (proration per
2724
+ * `proration_behavior`), schedule an END-OF-PERIOD cancellation with
2725
+ * `cancel_at_period_end: true` (or clear one with `false`), pause payment
2726
+ * collection with `pause_collection` (unset with `""` to resume
2727
+ * collection), etc. For IMMEDIATE cancellation use {@link cancel} instead.
2728
+ * Pass `idempotencyKey` to make the POST safely replayable (and
2729
+ * retry-eligible).
2730
+ *
2731
+ * Docs: https://docs.stripe.com/api/subscriptions/update
2732
+ *
2733
+ * @example
2734
+ * // Cancel when the current billing period ends — NOT immediate:
2735
+ * const sub = await payweave.stripe.subscriptions.update("sub_123", {
2736
+ * cancel_at_period_end: true,
2737
+ * });
2738
+ * console.log(sub.status, sub.cancel_at_period_end); // "active", true
2739
+ */
2740
+ async update(id, input = {}, opts = {}) {
2741
+ const subscriptionId = requireId(id, "subscription");
2742
+ const body = parseRequest(subscriptionUpdateReq, input);
2743
+ return this.http.request({
2744
+ method: "POST",
2745
+ path: `/v1/subscriptions/${encodeURIComponent(subscriptionId)}`,
2746
+ ...bodyIfNonEmpty7(body),
2747
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
2748
+ schema: subscription
2749
+ });
2750
+ }
2751
+ /**
2752
+ * Cancel a subscription IMMEDIATELY (`DELETE /v1/subscriptions/{id}`) —
2753
+ * the customer is not charged again, and pending prorations are dropped
2754
+ * unless `invoice_now`/`prorate` say otherwise. To cancel at the END of the
2755
+ * current period instead, use
2756
+ * `update(id, { cancel_at_period_end: true })` — the two shapes are
2757
+ * distinct on Stripe and PW-805's state machine relies on that.
2758
+ *
2759
+ * Docs: https://docs.stripe.com/api/subscriptions/cancel
2760
+ *
2761
+ * @example
2762
+ * const sub = await payweave.stripe.subscriptions.cancel("sub_123", {
2763
+ * invoice_now: true,
2764
+ * prorate: true,
2765
+ * cancellation_details: { feedback: "too_expensive" },
2766
+ * });
2767
+ * console.log(sub.status); // "canceled"
2768
+ */
2769
+ async cancel(id, input = {}) {
2770
+ const subscriptionId = requireId(id, "subscription");
2771
+ const body = parseRequest(subscriptionCancelReq, input);
2772
+ return this.http.request({
2773
+ method: "DELETE",
2774
+ path: `/v1/subscriptions/${encodeURIComponent(subscriptionId)}`,
2775
+ ...bodyIfNonEmpty7(body),
2776
+ schema: subscription
2777
+ });
2778
+ }
2779
+ /**
2780
+ * Resume a subscription whose STATUS is `paused` (e.g. a trial that ended
2781
+ * with `trial_settings.end_behavior.missing_payment_method: "pause"`) —
2782
+ * only available under `charge_automatically` collection. Not for paused
2783
+ * payment COLLECTION: unset that via
2784
+ * `update(id, { pause_collection: "" })`. `billing_cycle_anchor` defaults
2785
+ * to `now` (resets the cycle; no prorations); `unchanged` keeps the anchor
2786
+ * and prorates per `proration_behavior`. Pass `idempotencyKey` to make the
2787
+ * POST safely replayable (and retry-eligible).
2788
+ *
2789
+ * Docs: https://docs.stripe.com/api/subscriptions/resume
2790
+ *
2791
+ * @example
2792
+ * const sub = await payweave.stripe.subscriptions.resume("sub_123", {
2793
+ * billing_cycle_anchor: "now",
2794
+ * });
2795
+ * console.log(sub.status); // "active"
2796
+ */
2797
+ async resume(id, input = {}, opts = {}) {
2798
+ const subscriptionId = requireId(id, "subscription");
2799
+ const body = parseRequest(subscriptionResumeReq, input);
2800
+ return this.http.request({
2801
+ method: "POST",
2802
+ path: `/v1/subscriptions/${encodeURIComponent(subscriptionId)}/resume`,
2803
+ ...bodyIfNonEmpty7(body),
2804
+ ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
2805
+ schema: subscription
2806
+ });
2807
+ }
2808
+ /**
2809
+ * List subscriptions. By default only non-canceled subscriptions are
2810
+ * returned — pass `status: "canceled"`, `"ended"`, or `"all"` to widen.
2811
+ * Filters are query params; range filters become bracket keys
2812
+ * (`current_period_end[gte]`).
2813
+ *
2814
+ * Docs: https://docs.stripe.com/api/subscriptions/list
2815
+ *
2816
+ * @example
2817
+ * const page = await payweave.stripe.subscriptions.list({
2818
+ * customer: "cus_123",
2819
+ * status: "all",
2820
+ * limit: 50,
2821
+ * });
2822
+ * console.log(page.data.length, page.has_more);
2823
+ */
2824
+ async list(query = {}) {
2825
+ const q = parseRequest(subscriptionListQuery, query);
2826
+ return this.http.request({
2827
+ method: "GET",
2828
+ path: "/v1/subscriptions",
2829
+ query: flattenQuery(q),
2830
+ schema: subscriptionListRes
2831
+ });
2832
+ }
2833
+ /**
2834
+ * Async iterator over ALL subscriptions matching `query`, transparently
2835
+ * following `has_more` with `starting_after = <last id>`.
2836
+ *
2837
+ * Docs: https://docs.stripe.com/api/subscriptions/list
2838
+ *
2839
+ * @example
2840
+ * for await (const sub of payweave.stripe.subscriptions.iterate({ customer: "cus_123" })) {
2841
+ * console.log(sub.id, sub.status);
2842
+ * }
2843
+ */
2844
+ async *iterate(query = {}) {
2845
+ const base = parseRequest(subscriptionListQuery, query);
2846
+ yield* iterateStripeList(
2847
+ (startingAfter) => this.http.request({
2848
+ method: "GET",
2849
+ path: "/v1/subscriptions",
2850
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
2851
+ schema: subscriptionListRes
2852
+ })
2853
+ );
2854
+ }
2855
+ };
2856
+ var enabledEvents = z.array(z.string()).min(1);
2857
+ var webhookEndpointCreateReq = z.object({
2858
+ /** The URL of the webhook endpoint. Required. */
2859
+ url: z.string(),
2860
+ /**
2861
+ * The list of events to enable for this endpoint; `["*"]` enables all
2862
+ * events except those that require explicit selection. Required. Encodes as
2863
+ * `enabled_events[0]=...`.
2864
+ */
2865
+ enabled_events: enabledEvents,
2866
+ /**
2867
+ * Events sent to this endpoint are rendered with this Stripe version
2868
+ * instead of the account default.
2869
+ */
2870
+ api_version: z.string().optional(),
2871
+ /**
2872
+ * `true` = receive events from connected accounts; `false` (default) = from
2873
+ * your own account.
2874
+ */
2875
+ connect: z.boolean().optional(),
2876
+ /** Optional description of what the webhook is used for. */
2877
+ description: z.string().optional(),
2878
+ metadata: metadataSchema.optional()
2879
+ });
2880
+ var webhookEndpointUpdateReq = z.object({
2881
+ /** Optional description of what the webhook is used for. */
2882
+ description: z.string().optional(),
2883
+ /** Disable the webhook endpoint if set to true. */
2884
+ disabled: z.boolean().optional(),
2885
+ /** Replacement list of enabled events (`["*"]` = all). */
2886
+ enabled_events: enabledEvents.optional(),
2887
+ metadata: metadataSchema.optional(),
2888
+ /** The URL of the webhook endpoint. */
2889
+ url: z.string().optional()
2890
+ });
2891
+ var webhookEndpointListQuery = z.object({
2892
+ ...listCursorFields
2893
+ });
2894
+ var webhookEndpoint = z.looseObject({
2895
+ id: z.string(),
2896
+ object: z.string().optional(),
2897
+ /** API version events are rendered as for this endpoint. */
2898
+ api_version: z.string().nullable().optional(),
2899
+ /** ID of the associated Connect application. */
2900
+ application: z.string().nullable().optional(),
2901
+ created: z.number().optional(),
2902
+ description: z.string().nullable().optional(),
2903
+ /** `["*"]` indicates all events (except explicit-selection ones). */
2904
+ enabled_events: z.array(z.string()).optional(),
2905
+ livemode: z.boolean().optional(),
2906
+ metadata: z.record(z.string(), z.string()).nullable().optional(),
2907
+ /**
2908
+ * The endpoint's signing secret (`whsec_*`), used to verify webhook
2909
+ * signatures. ⚠️ "Only returned at creation"
2910
+ * (https://docs.stripe.com/api/webhook_endpoints/object — verified
2911
+ * 2026-07-12) — capture it from the `create` response or it is gone;
2912
+ * retrieve/update/list never include it. Store it as the provider config's
2913
+ * `webhookSecret`; core `redact` masks it from all logs.
2914
+ */
2915
+ secret: z.string().optional(),
2916
+ /** `enabled` | `disabled` — kept loose (drift logs, never throws). */
2917
+ status: z.string().optional(),
2918
+ url: z.string().optional()
2919
+ });
2920
+ var webhookEndpointDeleted = z.looseObject({
2921
+ id: z.string(),
2922
+ object: z.string().optional(),
2923
+ deleted: z.boolean().optional()
2924
+ });
2925
+
2926
+ // src/stripe/resources/webhook-endpoints.ts
2927
+ var webhookEndpointListRes = stripeList(webhookEndpoint);
2928
+ function bodyIfNonEmpty8(body) {
2929
+ return Object.keys(body).length > 0 ? { body } : {};
2930
+ }
2931
+ var WebhookEndpoints = class {
2932
+ constructor(http) {
2933
+ this.http = http;
2934
+ }
2935
+ http;
2936
+ /**
2937
+ * Create a webhook endpoint. `url` and `enabled_events` are required;
2938
+ * `enabled_events` bracket-encodes as `enabled_events[0]=...` and `["*"]`
2939
+ * enables all events (except those requiring explicit selection).
2940
+ *
2941
+ * ⚠️ The response is the ONLY place the endpoint's `whsec_*` signing
2942
+ * `secret` is ever returned ("Only returned at creation") — persist it
2943
+ * immediately (e.g. as the `stripe.webhookSecret` config) or it cannot be
2944
+ * recovered; retrieve/update/list responses never include it.
2945
+ *
2946
+ * Docs: https://docs.stripe.com/api/webhook_endpoints/create
2947
+ *
2948
+ * @example
2949
+ * const we = await payweave.stripe.webhookEndpoints.create({
2950
+ * url: "https://example.com/payweave/webhooks",
2951
+ * enabled_events: ["checkout.session.completed", "payment_intent.succeeded"],
2952
+ * });
2953
+ * const signingSecret = we.secret; // whsec_* — shown ONCE, store it now
2954
+ */
2955
+ async create(input) {
2956
+ const body = parseRequest(webhookEndpointCreateReq, input);
2957
+ return this.http.request({
2958
+ method: "POST",
2959
+ path: "/v1/webhook_endpoints",
2960
+ body,
2961
+ schema: webhookEndpoint
2962
+ });
2963
+ }
2964
+ /**
2965
+ * Retrieve a webhook endpoint by id (`we_*`). The response does NOT include
2966
+ * the signing `secret` (create-only). A 404 for an unknown id surfaces as
2967
+ * {@link PayweaveNotFoundError}.
2968
+ *
2969
+ * Docs: https://docs.stripe.com/api/webhook_endpoints/retrieve
2970
+ *
2971
+ * @example
2972
+ * const we = await payweave.stripe.webhookEndpoints.retrieve("we_123");
2973
+ * console.log(we.status, we.enabled_events);
2974
+ */
2975
+ async retrieve(id) {
2976
+ const endpointId = requireId(id, "webhook endpoint");
2977
+ return this.http.request({
2978
+ method: "GET",
2979
+ path: `/v1/webhook_endpoints/${encodeURIComponent(endpointId)}`,
2980
+ schema: webhookEndpoint
2981
+ });
2982
+ }
2983
+ /**
2984
+ * Update a webhook endpoint (`description`, `enabled_events`, `url`,
2985
+ * `metadata`, or `disabled: true` to disable it). The response does NOT
2986
+ * include the signing `secret` (create-only).
2987
+ *
2988
+ * Docs: https://docs.stripe.com/api/webhook_endpoints/update
2989
+ *
2990
+ * @example
2991
+ * const we = await payweave.stripe.webhookEndpoints.update("we_123", {
2992
+ * disabled: true,
2993
+ * });
2994
+ * console.log(we.status); // "disabled"
2995
+ */
2996
+ async update(id, input = {}) {
2997
+ const endpointId = requireId(id, "webhook endpoint");
2998
+ const body = parseRequest(webhookEndpointUpdateReq, input);
2999
+ return this.http.request({
3000
+ method: "POST",
3001
+ path: `/v1/webhook_endpoints/${encodeURIComponent(endpointId)}`,
3002
+ ...bodyIfNonEmpty8(body),
3003
+ schema: webhookEndpoint
3004
+ });
3005
+ }
3006
+ /**
3007
+ * Delete a webhook endpoint. Returns `{ id, object, deleted: true }`;
3008
+ * deleting an already-deleted endpoint raises a Stripe error (404 →
3009
+ * {@link PayweaveNotFoundError}). `payweave listen` calls this on
3010
+ * teardown.
3011
+ *
3012
+ * Docs: https://docs.stripe.com/api/webhook_endpoints/delete
3013
+ *
3014
+ * @example
3015
+ * const gone = await payweave.stripe.webhookEndpoints.delete("we_123");
3016
+ * console.log(gone.deleted); // true
3017
+ */
3018
+ async delete(id) {
3019
+ const endpointId = requireId(id, "webhook endpoint");
3020
+ return this.http.request({
3021
+ method: "DELETE",
3022
+ path: `/v1/webhook_endpoints/${encodeURIComponent(endpointId)}`,
3023
+ schema: webhookEndpointDeleted
3024
+ });
3025
+ }
3026
+ /**
3027
+ * List webhook endpoints. Cursor pagination only (`limit` +
3028
+ * `starting_after`/`ending_before`) — no other documented filters.
3029
+ * Responses never include signing secrets.
3030
+ *
3031
+ * Docs: https://docs.stripe.com/api/webhook_endpoints/list
3032
+ *
3033
+ * @example
3034
+ * const page = await payweave.stripe.webhookEndpoints.list({ limit: 20 });
3035
+ * console.log(page.data.map((we) => we.url));
3036
+ */
3037
+ async list(query = {}) {
3038
+ const q = parseRequest(webhookEndpointListQuery, query);
3039
+ return this.http.request({
3040
+ method: "GET",
3041
+ path: "/v1/webhook_endpoints",
3042
+ query: flattenQuery(q),
3043
+ schema: webhookEndpointListRes
3044
+ });
3045
+ }
3046
+ /**
3047
+ * Async iterator over ALL webhook endpoints, transparently following
3048
+ * `has_more` with `starting_after = <last id>`.
3049
+ *
3050
+ * Docs: https://docs.stripe.com/api/webhook_endpoints/list
3051
+ *
3052
+ * @example
3053
+ * for await (const we of payweave.stripe.webhookEndpoints.iterate()) {
3054
+ * console.log(we.id, we.url, we.status);
3055
+ * }
3056
+ */
3057
+ async *iterate(query = {}) {
3058
+ const base = parseRequest(webhookEndpointListQuery, query);
3059
+ yield* iterateStripeList(
3060
+ (startingAfter) => this.http.request({
3061
+ method: "GET",
3062
+ path: "/v1/webhook_endpoints",
3063
+ query: flattenQuery({ ...base, starting_after: startingAfter }),
3064
+ schema: webhookEndpointListRes
3065
+ })
3066
+ );
3067
+ }
3068
+ };
3069
+
3070
+ // src/stripe/client.ts
3071
+ var StripeClient = class {
3072
+ /** Shared HTTP client every Stripe resource is constructed with. */
3073
+ http;
3074
+ /** Checkout namespace (`payweave.stripe.checkout.sessions.create(...)`). */
3075
+ checkout;
3076
+ /** PaymentIntents: create, retrieve, confirm, capture, cancel, list/iterate. */
3077
+ paymentIntents;
3078
+ /** Customers: create, retrieve, update, delete, list/iterate, search/iterateSearch. */
3079
+ customers;
3080
+ /** Products: create, retrieve, update, delete, list/iterate, search/iterateSearch. */
3081
+ products;
3082
+ /** Prices: create, retrieve, update, list/iterate, search/iterateSearch (no delete — prices are archived). */
3083
+ prices;
3084
+ /** Subscriptions: create, retrieve, update, cancel, resume, list/iterate. */
3085
+ subscriptions;
3086
+ /** SubscriptionItems: create, retrieve, update, delete, list/iterate. */
3087
+ subscriptionItems;
3088
+ /** Refunds: create (idempotencyKey), retrieve, update, cancel, list/iterate. */
3089
+ refunds;
3090
+ /** WebhookEndpoints: create (secret shown ONCE), retrieve, update, delete, list/iterate. */
3091
+ webhookEndpoints;
3092
+ constructor(http) {
3093
+ this.http = http;
3094
+ this.checkout = { sessions: new CheckoutSessions(this.http) };
3095
+ this.paymentIntents = new PaymentIntents(this.http);
3096
+ this.customers = new Customers(this.http);
3097
+ this.products = new Products(this.http);
3098
+ this.prices = new Prices(this.http);
3099
+ this.subscriptions = new Subscriptions(this.http);
3100
+ this.subscriptionItems = new SubscriptionItems(this.http);
3101
+ this.refunds = new Refunds(this.http);
3102
+ this.webhookEndpoints = new WebhookEndpoints(this.http);
3103
+ }
3104
+ };
3105
+ function stripeHttp(cfg) {
3106
+ return new HttpClient(stripeHttpOptions(cfg));
3107
+ }
3108
+ defineProvider({
3109
+ id: "stripe",
3110
+ configKey: "stripe",
3111
+ configSchema: stripeProviderConfigSchema,
3112
+ environments: {
3113
+ // One host for both — Stripe's environment is key-derived, not host-derived.
3114
+ test: { baseUrl: STRIPE_BASE_URL },
3115
+ live: { baseUrl: STRIPE_BASE_URL }
3116
+ },
3117
+ inferEnvironment: (secretKey) => {
3118
+ try {
3119
+ return inferEnvironment("stripe", secretKey);
3120
+ } catch {
3121
+ return null;
3122
+ }
3123
+ },
3124
+ createHttp: stripeHttp,
3125
+ webhooks: {
3126
+ signatureHeader: "stripe-signature",
3127
+ verify: ({ rawBody, headers, secret }) => verifyStripe(rawBody, readHeader(headers, "stripe-signature"), secret),
3128
+ parse: (rawBody) => {
3129
+ const root = JSON.parse(rawBody);
3130
+ return {
3131
+ type: typeof root.type === "string" ? root.type : "unknown",
3132
+ data: root.data,
3133
+ raw: root,
3134
+ ...typeof root.id === "string" ? { id: root.id } : {}
3135
+ };
3136
+ },
3137
+ toUnified: (e) => ({
3138
+ provider: "stripe",
3139
+ type: e.type,
3140
+ unifiedType: toUnifiedEventType("stripe", void 0, e.type, e.data),
3141
+ data: e.data,
3142
+ raw: e.raw
3143
+ })
3144
+ }
3145
+ });
3146
+ function isBillingCapableProvider(provider) {
3147
+ return BILLING_CAPABLE_PROVIDERS.includes(provider);
3148
+ }
3149
+ function stableStringify(value) {
3150
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
3151
+ if (value !== null && typeof value === "object") {
3152
+ const entries = Object.entries(value).sort(
3153
+ ([a], [b]) => a < b ? -1 : a > b ? 1 : 0
3154
+ );
3155
+ return `{${entries.map(([key, val]) => `${JSON.stringify(key)}:${stableStringify(val)}`).join(",")}}`;
3156
+ }
3157
+ return JSON.stringify(value);
3158
+ }
3159
+ function planPriceHash(plan2) {
3160
+ const price2 = plan2.price;
3161
+ const payload = price2 ? { amount: price2.amount, currency: price2.currency, interval: price2.interval } : null;
3162
+ return createHash("sha256").update(stableStringify(payload)).digest("hex");
3163
+ }
3164
+ function planPaystackHash(plan2) {
3165
+ const price2 = plan2.price;
3166
+ const payload = {
3167
+ name: plan2.name ?? null,
3168
+ price: price2 ? { amount: price2.amount, currency: price2.currency, interval: price2.interval } : null
3169
+ };
3170
+ return createHash("sha256").update(stableStringify(payload)).digest("hex");
3171
+ }
3172
+ function buildFeatures(plan2) {
3173
+ const out = {};
3174
+ for (const inclusion of plan2.includes) {
3175
+ out[inclusion.featureId] = inclusion.type === "boolean" ? { type: "boolean" } : { type: "metered", limit: inclusion.limit, reset: inclusion.reset };
3176
+ }
3177
+ return out;
3178
+ }
3179
+ async function findStripeProduct(stripe, planId) {
3180
+ const found = await stripe.products.search({ query: `metadata['pwv_plan']:'${planId}'` });
3181
+ return found.data[0];
3182
+ }
3183
+ async function findStripePrice(stripe, planId, hash) {
3184
+ const found = await stripe.prices.search({
3185
+ query: `metadata['pwv_plan']:'${planId}' AND metadata['pwv_hash']:'${hash}'`
3186
+ });
3187
+ return found.data[0];
3188
+ }
3189
+ async function syncStripe(stripe, plan2, existingVersion) {
3190
+ const price2 = plan2.price;
3191
+ if (!price2) throw new PayweaveConfigError(`plan "${plan2.id}" has no price to sync to stripe.`);
3192
+ const priceHash = planPriceHash(plan2);
3193
+ const prevRefs = existingVersion?.providerRefs.stripe;
3194
+ const prevProductId = prevRefs?.productId;
3195
+ const prevPriceId = prevRefs?.priceId;
3196
+ const nameChanged = (existingVersion?.name ?? null) !== (plan2.name ?? null);
3197
+ const priceChanged = prevRefs?.hash !== priceHash;
3198
+ if (prevProductId !== void 0 && prevPriceId !== void 0 && !nameChanged && !priceChanged) {
3199
+ return { refs: { productId: prevProductId, priceId: prevPriceId, hash: priceHash }, action: "unchanged" };
3200
+ }
3201
+ let created = false;
3202
+ let adopted = false;
3203
+ let productId = prevProductId;
3204
+ if (productId === void 0) {
3205
+ const found = await findStripeProduct(stripe, plan2.id);
3206
+ if (found) {
3207
+ productId = found.id;
3208
+ adopted = true;
3209
+ } else {
3210
+ const createdProduct = await stripe.products.create(
3211
+ { name: plan2.name ?? plan2.id, metadata: { pwv_plan: plan2.id } },
3212
+ { idempotencyKey: `pwv-push-product-${plan2.id}` }
3213
+ );
3214
+ productId = createdProduct.id;
3215
+ created = true;
3216
+ }
3217
+ } else if (nameChanged) {
3218
+ await stripe.products.update(productId, {
3219
+ name: plan2.name ?? plan2.id,
3220
+ metadata: { pwv_plan: plan2.id }
3221
+ });
3222
+ }
3223
+ let priceId = prevPriceId;
3224
+ if (priceId === void 0 || priceChanged) {
3225
+ const foundPrice = await findStripePrice(stripe, plan2.id, priceHash);
3226
+ if (foundPrice) {
3227
+ priceId = foundPrice.id;
3228
+ adopted = true;
3229
+ } else {
3230
+ const createdPrice = await stripe.prices.create(
3231
+ {
3232
+ currency: price2.currency.toLowerCase(),
3233
+ unit_amount: price2.amount,
3234
+ recurring: { interval: price2.interval },
3235
+ product: productId,
3236
+ metadata: { pwv_plan: plan2.id, pwv_hash: priceHash }
3237
+ },
3238
+ { idempotencyKey: `pwv-push-price-${plan2.id}-${priceHash}` }
3239
+ );
3240
+ priceId = createdPrice.id;
3241
+ created = true;
3242
+ }
3243
+ if (prevPriceId !== void 0 && prevPriceId !== priceId) {
3244
+ await stripe.prices.update(prevPriceId, { active: false });
3245
+ }
3246
+ }
3247
+ return {
3248
+ refs: { productId, priceId, hash: priceHash },
3249
+ action: adopted ? "adopted" : created ? "created" : "unchanged"
3250
+ };
3251
+ }
3252
+ var PAYSTACK_INTERVAL = {
3253
+ month: "monthly",
3254
+ year: "annually"
3255
+ };
3256
+ function encodePaystackTag(tag) {
3257
+ return JSON.stringify(tag);
3258
+ }
3259
+ function decodePaystackTag(description) {
3260
+ if (description === null || description === void 0) return void 0;
3261
+ try {
3262
+ const parsed = JSON.parse(description);
3263
+ if (parsed !== null && typeof parsed === "object" && typeof parsed.pwv_plan === "string" && typeof parsed.pwv_hash === "string") {
3264
+ return parsed;
3265
+ }
3266
+ } catch {
3267
+ }
3268
+ return void 0;
3269
+ }
3270
+ async function findAdoptablePaystackPlan(paystack, planId, hash) {
3271
+ for await (const candidate of paystack.plans.iterate()) {
3272
+ const tag = decodePaystackTag(candidate.description ?? void 0);
3273
+ if (tag?.pwv_plan === planId && tag.pwv_hash === hash) {
3274
+ const code = candidate.plan_code;
3275
+ if (code !== void 0) return code;
3276
+ }
3277
+ }
3278
+ return void 0;
3279
+ }
3280
+ async function syncPaystack(paystack, plan2, existingVersion) {
3281
+ const price2 = plan2.price;
3282
+ if (!price2) throw new PayweaveConfigError(`plan "${plan2.id}" has no price to sync to paystack.`);
3283
+ const hash = planPaystackHash(plan2);
3284
+ const prevRefs = existingVersion?.providerRefs.paystack;
3285
+ const prevPlanCode = prevRefs?.planCode;
3286
+ if (prevPlanCode !== void 0 && prevRefs?.hash === hash) {
3287
+ return { refs: { planCode: prevPlanCode, hash }, action: "unchanged" };
3288
+ }
3289
+ const adoptedCode = await findAdoptablePaystackPlan(paystack, plan2.id, hash);
3290
+ if (adoptedCode !== void 0) {
3291
+ return { refs: { planCode: adoptedCode, hash }, action: "adopted" };
3292
+ }
3293
+ const created = await paystack.plans.create({
3294
+ name: plan2.name ?? plan2.id,
3295
+ amount: price2.amount,
3296
+ interval: PAYSTACK_INTERVAL[price2.interval],
3297
+ currency: price2.currency,
3298
+ description: encodePaystackTag({ pwv_plan: plan2.id, pwv_hash: hash })
3299
+ });
3300
+ const planCode = created.data.plan_code;
3301
+ if (planCode === void 0) {
3302
+ throw new PayweaveProviderError("paystack created a plan without a plan_code", {
3303
+ provider: "paystack"
3304
+ });
3305
+ }
3306
+ return { refs: { planCode, hash }, action: "created" };
3307
+ }
3308
+ async function pushPlanToProvider(ctx, provider, plan2, existingVersion) {
3309
+ if (provider === "stripe") {
3310
+ if (!ctx.stripe) throw new PayweaveConfigError("stripe is not configured on this client.");
3311
+ return syncStripe(ctx.stripe, plan2, existingVersion);
3312
+ }
3313
+ if (provider === "paystack") {
3314
+ if (!ctx.paystack) throw new PayweaveConfigError("paystack is not configured on this client.");
3315
+ return syncPaystack(ctx.paystack, plan2, existingVersion);
3316
+ }
3317
+ throw new PayweaveConfigError(
3318
+ `payweave.sync() does not support pushing plans to "${provider}" yet \u2014 its payment-plan mapping is deferred pending further API verification; billing-capable providers: ${BILLING_CAPABLE_PROVIDERS.join(", ")}.`
3319
+ );
3320
+ }
3321
+ function planVersionInput(plan2, providerRefs) {
3322
+ return {
3323
+ planId: plan2.id,
3324
+ group: resolvePlanGroup(plan2),
3325
+ isDefault: plan2.default,
3326
+ name: plan2.name ?? null,
3327
+ priceMinor: plan2.price?.amount ?? null,
3328
+ priceCurrency: plan2.price?.currency ?? null,
3329
+ priceInterval: plan2.price?.interval ?? null,
3330
+ features: buildFeatures(plan2),
3331
+ providerRefs
3332
+ };
3333
+ }
3334
+ async function sync(ctx) {
3335
+ const database = ctx.database;
3336
+ if (!database) {
3337
+ throw new PayweaveConfigError(
3338
+ "payweave.sync() needs a database \u2014 pass a payweave/db/* adapter to createPayweave()."
3339
+ );
3340
+ }
3341
+ const products = ctx.products;
3342
+ if (!products) {
3343
+ throw new PayweaveConfigError(
3344
+ "payweave.sync() needs products \u2014 pass a `products` array to createPayweave()."
3345
+ );
3346
+ }
3347
+ const billingProviders = ctx.providers.filter(isBillingCapableProvider);
3348
+ const skippedProviders = ctx.providers.filter((provider) => !isBillingCapableProvider(provider));
3349
+ const plans = [];
3350
+ for (const plan2 of products) {
3351
+ const existingVersion = await database.plans.getActiveVersion(plan2.id);
3352
+ const providerRefs = {};
3353
+ const providerActions = {};
3354
+ if (plan2.price !== void 0) {
3355
+ for (const provider of billingProviders) {
3356
+ const result = await pushPlanToProvider(ctx, provider, plan2, existingVersion);
3357
+ providerRefs[provider] = result.refs;
3358
+ providerActions[provider] = result.action;
3359
+ }
3360
+ }
3361
+ const pushed = await database.plans.pushVersion(planVersionInput(plan2, providerRefs));
3362
+ plans.push({
3363
+ planId: plan2.id,
3364
+ version: pushed.version,
3365
+ versionChanged: existingVersion === null || existingVersion.version !== pushed.version,
3366
+ providers: providerActions
3367
+ });
3368
+ }
3369
+ return { plans, skippedProviders };
3370
+ }
3371
+
3372
+ // src/products/usage.ts
3373
+ function requireDatabase(ctx, method) {
3374
+ if (!ctx.database) {
3375
+ throw new PayweaveConfigError(
3376
+ `payweave.${method}() needs a database \u2014 pass a payweave/db/* adapter to createPayweave().`
3377
+ );
3378
+ }
3379
+ return ctx.database;
3380
+ }
3381
+ function assertPositiveSafeInteger(value, name) {
3382
+ if (!Number.isSafeInteger(value) || value <= 0) {
3383
+ throw new PayweaveValidationError(`${name} must be a positive safe integer \u2014 got ${value}`);
3384
+ }
3385
+ }
3386
+ async function resolveFeatureContext(ctx, database, customerId, featureId) {
3387
+ const products = ctx.products ?? [];
3388
+ let type;
3389
+ let group;
3390
+ for (const p of products) {
3391
+ const inc = p.includes.find((i) => i.featureId === featureId);
3392
+ if (inc) {
3393
+ type = inc.type;
3394
+ group = resolvePlanGroup(p);
3395
+ break;
3396
+ }
3397
+ }
3398
+ if (type === void 0 || group === void 0) {
3399
+ throw new PayweaveValidationError(
3400
+ `unknown feature "${featureId}" \u2014 configure it in \`products\`.`
3401
+ );
3402
+ }
3403
+ let customerRow = await database.customers.getByExternalId(customerId);
3404
+ if (customerRow === null) {
3405
+ customerRow = await database.customers.upsert({ externalId: customerId });
3406
+ }
3407
+ const subscription2 = await database.subscriptions.getActive(customerRow.id, group);
3408
+ if (subscription2) {
3409
+ const plan2 = products.find((p) => p.id === subscription2.planId);
3410
+ if (!plan2) {
3411
+ throw new PayweaveValidationError(
3412
+ `customer's active subscription references plan "${subscription2.planId}", which is no longer in \`products\` \u2014 was it renamed or removed?`
3413
+ );
3414
+ }
3415
+ const inclusion2 = plan2.includes.find((i) => i.featureId === featureId);
3416
+ return { group, type, plan: plan2, inclusion: inclusion2, subscription: subscription2, customerRow };
3417
+ }
3418
+ const defaultPlan = products.find((p) => p.default && resolvePlanGroup(p) === group);
3419
+ if (!defaultPlan) {
3420
+ throw new PayweaveConfigError(
3421
+ `group "${group}" has no default plan \u2014 check()/report() need one to answer for a customer with no active subscription in that group.`
3422
+ );
3423
+ }
3424
+ const inclusion = defaultPlan.includes.find((i) => i.featureId === featureId);
3425
+ return { group, type, plan: defaultPlan, inclusion, subscription: null, customerRow };
3426
+ }
3427
+ async function buildMeteredInit(database, resolved, inclusion, now) {
3428
+ const isPaid = resolved.plan.price !== void 0;
3429
+ const anchor = isPaid && resolved.subscription ? resolved.subscription.currentPeriodStart : now;
3430
+ const planVersion = resolved.subscription ? resolved.subscription.planVersion : (await database.plans.getActiveVersion(resolved.plan.id))?.version ?? 1;
3431
+ return {
3432
+ limit: inclusion.limit,
3433
+ resetInterval: inclusion.reset,
3434
+ anchor,
3435
+ planId: resolved.plan.id,
3436
+ planVersion
3437
+ };
3438
+ }
3439
+ async function check(ctx, input) {
3440
+ const database = requireDatabase(ctx, "check");
3441
+ const resolved = await resolveFeatureContext(ctx, database, input.customerId, input.featureId);
3442
+ if (resolved.type === "boolean") {
3443
+ return {
3444
+ allowed: resolved.inclusion !== void 0,
3445
+ balance: null,
3446
+ limit: null,
3447
+ resetsAt: null,
3448
+ planId: resolved.plan.id
3449
+ };
3450
+ }
3451
+ if (!resolved.inclusion) {
3452
+ return { allowed: false, balance: null, limit: null, resetsAt: null, planId: resolved.plan.id };
3453
+ }
3454
+ const inclusion = resolved.inclusion;
3455
+ const now = /* @__PURE__ */ new Date();
3456
+ const init = await buildMeteredInit(database, resolved, inclusion, now);
3457
+ const conditional = input.consume === true;
3458
+ const amount = conditional ? 1 : 0;
3459
+ const result = await database.balances.consume({
3460
+ customerId: resolved.customerRow.id,
3461
+ featureId: input.featureId,
3462
+ group: resolved.group,
3463
+ amount,
3464
+ conditional,
3465
+ init,
3466
+ now
3467
+ });
3468
+ const balance = result.limit - result.used;
3469
+ return {
3470
+ allowed: conditional ? result.applied : balance > 0,
3471
+ balance,
3472
+ limit: result.limit,
3473
+ resetsAt: result.periodEnd,
3474
+ planId: resolved.plan.id
3475
+ };
3476
+ }
3477
+ async function report(ctx, input) {
3478
+ const database = requireDatabase(ctx, "report");
3479
+ const amount = input.amount ?? 1;
3480
+ assertPositiveSafeInteger(amount, "amount");
3481
+ const resolved = await resolveFeatureContext(ctx, database, input.customerId, input.featureId);
3482
+ if (resolved.type === "boolean") {
3483
+ throw new PayweaveValidationError(
3484
+ `report() only accepts metered features \u2014 "${input.featureId}" is a boolean feature.`
3485
+ );
3486
+ }
3487
+ if (!resolved.inclusion) {
3488
+ throw new PayweaveValidationError(
3489
+ `report(): feature "${input.featureId}" is not included in customer "${input.customerId}"'s current plan "${resolved.plan.id}" \u2014 call check() first, which answers { allowed: false } for a plan lacking a feature.`
3490
+ );
3491
+ }
3492
+ const inclusion = resolved.inclusion;
3493
+ const now = /* @__PURE__ */ new Date();
3494
+ const init = await buildMeteredInit(database, resolved, inclusion, now);
3495
+ const result = await database.balances.consume({
3496
+ customerId: resolved.customerRow.id,
3497
+ featureId: input.featureId,
3498
+ group: resolved.group,
3499
+ amount,
3500
+ conditional: false,
3501
+ init,
3502
+ now
3503
+ });
3504
+ return { balance: result.limit - result.used, resetsAt: result.periodEnd };
3505
+ }
3506
+
3507
+ // src/index.ts
3508
+ function buildAuth(resolved) {
3509
+ if (resolved.provider === "flutterwave" && resolved.version === "v4") {
3510
+ if (!resolved.clientId || !resolved.clientSecret || !resolved.tokenUrl) {
3511
+ throw new PayweaveConfigError("Flutterwave v4 requires clientId, clientSecret, and a token URL.", {
3512
+ provider: "flutterwave"
3513
+ });
3514
+ }
3515
+ return oauthClientCredentials({
3516
+ clientId: resolved.clientId,
3517
+ clientSecret: resolved.clientSecret,
3518
+ tokenUrl: resolved.tokenUrl,
3519
+ ...resolved.fetch ? { fetch: resolved.fetch } : {},
3520
+ ...resolved.logger ? { logger: resolved.logger } : {}
3521
+ });
3522
+ }
3523
+ if (!resolved.secretKey) {
3524
+ throw new PayweaveConfigError(`Missing secret key for ${resolved.provider}.`, {
3525
+ provider: resolved.provider
3526
+ });
3527
+ }
3528
+ return bearer(resolved.secretKey);
3529
+ }
3530
+ function buildHttpClient(resolved) {
3531
+ return new HttpClient({
3532
+ baseUrl: resolved.baseUrl,
3533
+ auth: buildAuth(resolved),
3534
+ provider: resolved.provider,
3535
+ version: resolved.version,
3536
+ timeoutMs: resolved.timeoutMs,
3537
+ maxRetries: resolved.maxRetries,
3538
+ fetch: resolved.fetch,
3539
+ logger: resolved.logger,
3540
+ userAgent: `payweave/${SDK_VERSION} (${resolved.provider})`
3541
+ });
3542
+ }
3543
+ function stripeUnifiedNamespace() {
3544
+ const notImplemented = (op) => Promise.reject(
3545
+ new PayweaveError(
3546
+ `stripe unified "${op}" is supported in principle but not implemented yet \u2014 the resource endpoints landed, but the unified mapping (\`src/unified/stripe.ts\`) has not. Use the per-call \`provider\` override to route to another configured provider, or call the Surface A \`payweave.stripe.*\` resources directly.`,
3547
+ { provider: "stripe", isRetryable: false }
3548
+ )
3549
+ );
3550
+ const capabilityGap = (op) => {
3551
+ try {
3552
+ assertUnifiedCapability("stripe", op);
3553
+ } catch (err) {
3554
+ return Promise.reject(err);
3555
+ }
3556
+ return Promise.reject(new PayweaveError(`${op} is not supported on stripe.`, { provider: "stripe" }));
3557
+ };
3558
+ return {
3559
+ checkout: { create: () => notImplemented("checkout.create") },
3560
+ verify: () => notImplemented("verify"),
3561
+ refunds: { create: () => notImplemented("refunds.create") },
3562
+ transfers: { create: () => capabilityGap("transfers.create") },
3563
+ banks: {
3564
+ list: () => capabilityGap("banks.list"),
3565
+ resolveAccount: () => capabilityGap("banks.resolveAccount")
3566
+ }
3567
+ };
3568
+ }
3569
+ function createPayweave(config) {
3570
+ const resolved = resolvePayweaveConfig(config);
3571
+ const surfaces = {};
3572
+ const unifiedByProvider = {};
3573
+ for (const key of resolved.providers) {
3574
+ const entry = resolved.providerConfigs[key];
3575
+ if (entry === void 0) continue;
3576
+ if (key === "paystack") {
3577
+ const http = buildHttpClient(entry);
3578
+ surfaces.paystack = new PaystackClient(http);
3579
+ unifiedByProvider.paystack = createPaystackUnified(http);
3580
+ } else if (key === "flutterwave") {
3581
+ const http = buildHttpClient(entry);
3582
+ const version = entry.version === "v4" ? "v4" : "v3";
3583
+ surfaces.flutterwave = new FlutterwaveClient(http, version, entry.encryptionKey);
3584
+ unifiedByProvider.flutterwave = createFlutterwaveUnified(http, version);
3585
+ } else {
3586
+ surfaces.stripe = new StripeClient(new HttpClient(stripeHttpOptions(entry)));
3587
+ unifiedByProvider.stripe = stripeUnifiedNamespace();
3588
+ }
3589
+ }
3590
+ const routeTo = (override) => {
3591
+ const key = override ?? resolved.defaultProvider;
3592
+ const ns = unifiedByProvider[key];
3593
+ if (ns === void 0) {
3594
+ throw new PayweaveConfigError(
3595
+ `provider "${key}" is not configured on this client \u2014 configured: ${resolved.providers.join(", ")}.`,
3596
+ { provider: key }
3597
+ );
3598
+ }
3599
+ return ns;
3600
+ };
3601
+ const guardedRoute = (op, override) => {
3602
+ const ns = routeTo(override);
3603
+ assertUnifiedCapability(override ?? resolved.defaultProvider, op);
3604
+ return ns;
3605
+ };
3606
+ const unified = {
3607
+ checkout: {
3608
+ create: ({ provider, ...input }) => guardedRoute("checkout.create", provider).checkout.create(input)
3609
+ },
3610
+ verify: ({ provider, ...input }) => guardedRoute("verify", provider).verify(input),
3611
+ refunds: {
3612
+ create: ({ provider, ...input }) => guardedRoute("refunds.create", provider).refunds.create(input)
3613
+ },
3614
+ transfers: {
3615
+ create: ({ provider, ...input }) => guardedRoute("transfers.create", provider).transfers.create(input)
3616
+ },
3617
+ banks: {
3618
+ list: ({ provider, ...input }) => guardedRoute("banks.list", provider).banks.list(input),
3619
+ resolveAccount: ({ provider, ...input }) => guardedRoute("banks.resolveAccount", provider).banks.resolveAccount(input)
3620
+ }
3621
+ };
3622
+ function capabilities(provider) {
3623
+ if (provider !== void 0) {
3624
+ if (!resolved.providers.includes(provider)) {
3625
+ throw new PayweaveConfigError(
3626
+ `provider "${provider}" is not configured on this client \u2014 configured: ${resolved.providers.join(", ")}.`,
3627
+ { provider }
3628
+ );
3629
+ }
3630
+ return UNIFIED_CAPABILITY_MATRIX[provider];
3631
+ }
3632
+ const out = {};
3633
+ for (const key of resolved.providers) out[key] = UNIFIED_CAPABILITY_MATRIX[key];
3634
+ return out;
3635
+ }
3636
+ const billingContext = {
3637
+ database: resolved.database,
3638
+ products: resolved.products,
3639
+ providers: resolved.providers,
3640
+ defaultProvider: resolved.defaultProvider,
3641
+ stripe: surfaces.stripe,
3642
+ paystack: surfaces.paystack
3643
+ };
3644
+ const client = {
3645
+ providers: resolved.providers,
3646
+ defaultProvider: resolved.defaultProvider,
3647
+ environment: resolved.environment,
3648
+ // Multi-provider header dispatch: the
3649
+ // provider is detected from the signature header NAME, then verified with
3650
+ // that provider's existing timing-safe verifier — fail closed on
3651
+ // unconfigured/ambiguous/unknown headers. `billingContext` (below) is
3652
+ // threaded through so every constructed event's `.apply()` can
3653
+ // reach the database — the same object the billing surface below uses.
3654
+ webhooks: createWebhookDispatch(resolved, billingContext),
3655
+ checkout: unified.checkout,
3656
+ verify: unified.verify,
3657
+ refunds: unified.refunds,
3658
+ transfers: unified.transfers,
3659
+ banks: unified.banks,
3660
+ capabilities,
3661
+ // See `PayweaveClientBase.database`'s doc comment.
3662
+ database: resolved.database,
3663
+ products: resolved.products,
3664
+ subscribe: (input) => subscribe(billingContext, input),
3665
+ // BillingSync push.
3666
+ sync: () => sync(billingContext),
3667
+ // metered usage (real implementations, not stubs).
3668
+ check: (input) => check(billingContext, input),
3669
+ report: (input) => report(billingContext, input),
3670
+ ...surfaces
3671
+ };
3672
+ return Object.freeze(client);
3673
+ }
3674
+
3675
+ export { StripeClient, createPayweave };
3676
+ //# sourceMappingURL=index.js.map
3677
+ //# sourceMappingURL=index.js.map