@klappay/types 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  CHARGE_AMOUNT_MAX: () => CHARGE_AMOUNT_MAX,
28
28
  CHARGE_EXPIRES_IN_MAX_SECONDS: () => CHARGE_EXPIRES_IN_MAX_SECONDS,
29
29
  CHARGE_EXPIRES_IN_MIN_SECONDS: () => CHARGE_EXPIRES_IN_MIN_SECONDS,
30
+ CHARGE_SPLIT_RECIPIENTS_MAX: () => CHARGE_SPLIT_RECIPIENTS_MAX,
30
31
  CapabilitiesSchema: () => CapabilitiesSchema,
31
32
  ChargeSchema: () => ChargeSchema,
32
33
  ChargeStatusSchema: () => ChargeStatusSchema,
@@ -78,6 +79,7 @@ __export(index_exports, {
78
79
  SandboxTriggerSchema: () => SandboxTriggerSchema,
79
80
  SettlementStatusSchema: () => SettlementStatusSchema,
80
81
  SplitDistributionStatusSchema: () => SplitDistributionStatusSchema,
82
+ SplitRecipientSchema: () => SplitRecipientSchema,
81
83
  TOKEN_ADDRESSES: () => TOKEN_ADDRESSES,
82
84
  TOKEN_DECIMALS: () => TOKEN_DECIMALS,
83
85
  TimelineEventSchema: () => TimelineEventSchema,
@@ -238,27 +240,50 @@ var TOKEN_ADDRESSES = {
238
240
  };
239
241
 
240
242
  // src/charges.ts
243
+ var import_zod8 = require("zod");
244
+
245
+ // src/checkout-metadata.ts
241
246
  var import_zod7 = require("zod");
242
- var ChargeStatusSchema = import_zod7.z.enum(["pending", "partially_paid", "confirmed", "expired", "underpaid"]).describe(
247
+ var CHECKOUT_PRODUCTS_MAX = 20;
248
+ var CheckoutProductSchema = import_zod7.z.object({
249
+ name: import_zod7.z.string().min(1).max(200).describe("What the payer is buying, shown as-is on the hosted checkout page."),
250
+ quantity: import_zod7.z.number().int().positive().max(9999).optional().describe("How many of this item. Omit for a single, unquantified item."),
251
+ imageUrl: import_zod7.z.string().url().max(2048).refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
252
+ "Product image, fetched only by the payer's own browser \u2014 Klappay never fetches it server-side. Must be `http(s)`."
253
+ )
254
+ });
255
+ var KlappayCheckoutMetadataSchema = import_zod7.z.object({
256
+ products: import_zod7.z.array(CheckoutProductSchema).max(CHECKOUT_PRODUCTS_MAX).optional().describe(
257
+ `What the payer is buying, shown on the hosted checkout page \u2014 up to ${CHECKOUT_PRODUCTS_MAX} items. Purely informational: never validated against \`amount\`, never used by any payment or distribution logic.`
258
+ )
259
+ }).describe(
260
+ "Reserved for Klappay \u2014 the one namespace inside `metadata` whose format is defined and enforced by Klappay, not by you. A `metadata.klappay` that does not match this shape is rejected outright (`400 validation_error`), unlike every other key in `metadata`, which accepts absolutely anything and never fails validation."
261
+ );
262
+ var MetadataWithKlappaySchema = import_zod7.z.object({ klappay: KlappayCheckoutMetadataSchema.optional() }).catchall(import_zod7.z.unknown()).describe(
263
+ "Arbitrary key/value data, returned as-is on every read. Put whatever you want in here \u2014 none of it is validated, except the `klappay` key, which is reserved for Klappay: if present, it must match `KlappayCheckoutMetadataSchema` exactly, or the whole request is rejected with `400 validation_error`."
264
+ );
265
+
266
+ // src/charges.ts
267
+ var ChargeStatusSchema = import_zod8.z.enum(["pending", "partially_paid", "confirmed", "expired", "underpaid"]).describe(
243
268
  "Payment progress, from the payer side. `pending`: created, nothing received yet. `partially_paid`: some funds received, less than `amount`. `confirmed`: full amount received (or more \u2014 see `isOverpaid`). `expired`: `expiresAt` passed with zero funds received. `underpaid`: `expiresAt` passed while `partially_paid`. Every status is reached automatically, on its own timeline \u2014 there is no merchant-initiated cancellation. This never reflects whether funds actually reached the merchant \u2014 see `settlementStatus` for that."
244
269
  );
245
- var SettlementStatusSchema = import_zod7.z.enum(["pending", "completed", "failed"]).describe(
270
+ var SettlementStatusSchema = import_zod8.z.enum(["pending", "completed", "failed"]).describe(
246
271
  "Progress of the payout to the merchant's wallet, a separate step from `status` \u2014 `status: confirmed` only means the payment was detected on-chain, not that the merchant has been paid yet. `pending`: payment detected, payout not yet attempted. `completed`: the merchant's wallet has the funds. `failed`: the payout attempt failed and retries were exhausted (rare; contact support). `null` on the parent `Charge` means no payout has been attempted yet \u2014 nothing has been received, or the charge is still in progress."
247
272
  );
248
273
  var CHARGE_EXPIRES_IN_MIN_SECONDS = 60;
249
274
  var CHARGE_EXPIRES_IN_MAX_SECONDS = 3600;
250
275
  var CHARGE_ACCEPTED_PAYMENTS_MAX = 14;
251
- var AcceptedPaymentSchema = import_zod7.z.object({
276
+ var AcceptedPaymentSchema = import_zod8.z.object({
252
277
  token: TokenSchema,
253
278
  network: NetworkSchema
254
279
  });
255
- var AcceptedPaymentsSchema = import_zod7.z.array(AcceptedPaymentSchema).min(1, "At least one accepted payment is required.").max(CHARGE_ACCEPTED_PAYMENTS_MAX).superRefine((pairs, ctx) => {
280
+ var AcceptedPaymentsSchema = import_zod8.z.array(AcceptedPaymentSchema).min(1, "At least one accepted payment is required.").max(CHARGE_ACCEPTED_PAYMENTS_MAX).superRefine((pairs, ctx) => {
256
281
  const seen = /* @__PURE__ */ new Set();
257
282
  pairs.forEach((pair, index) => {
258
283
  const key = `${pair.token}:${pair.network}`;
259
284
  if (seen.has(key)) {
260
285
  ctx.addIssue({
261
- code: import_zod7.z.ZodIssueCode.custom,
286
+ code: import_zod8.z.ZodIssueCode.custom,
262
287
  message: `Duplicate accepted payment: ${pair.token} on ${pair.network}.`,
263
288
  path: [index]
264
289
  });
@@ -266,7 +291,7 @@ var AcceptedPaymentsSchema = import_zod7.z.array(AcceptedPaymentSchema).min(1, "
266
291
  seen.add(key);
267
292
  if (!OPERATIONAL_NETWORKS.includes(pair.network)) {
268
293
  ctx.addIssue({
269
- code: import_zod7.z.ZodIssueCode.custom,
294
+ code: import_zod8.z.ZodIssueCode.custom,
270
295
  message: `Network "${pair.network}" isn't live yet \u2014 only ${OPERATIONAL_NETWORKS.join(", ")} today.`,
271
296
  path: [index, "network"]
272
297
  });
@@ -275,78 +300,106 @@ var AcceptedPaymentsSchema = import_zod7.z.array(AcceptedPaymentSchema).min(1, "
275
300
  }).describe(
276
301
  `Every \`(token, network)\` pair the payer is allowed to pay with \u2014 at least one, up to ${CHARGE_ACCEPTED_PAYMENTS_MAX}. This list is also the only restriction knob: the payer can use any combination of the pairs listed here, and every transfer on one of them is credited and sums toward the charge total (see \`paidWith\`) \u2014 e.g. a charge accepting USDC and USDT can be confirmed by $9 in USDC plus $1 in USDT, or by USDC arriving on two different accepted networks. To require payment in one specific token on one specific network, list only that single pair \u2014 a transfer on any pair not in this list is still recorded (for audit) but never credited. Each network must be live (see \`GET /v1/networks\` for the current matrix) \u2014 an unconfigured \`(token, network)\` combination for your environment is rejected with \`422 token_not_supported\`.`
277
302
  );
303
+ var CHARGE_SPLIT_RECIPIENTS_MAX = 5;
304
+ var SplitRecipientSchema = import_zod8.z.object({
305
+ address: import_zod8.z.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 20-byte hex address").describe("EVM address to send a slice of this charge to."),
306
+ percent: import_zod8.z.number().positive().max(100).describe(
307
+ "Percent of *your own* net share (i.e. of `100 - feePercent`, not of the charge's gross `amount`) to route to this address instead of your own payout wallet. Klappay's fee is computed on the gross amount first and is never diluted by how you choose to split what's left \u2014 see `docs/payments.md`'s \"Settling the payout\" section for the exact math."
308
+ ),
309
+ label: import_zod8.z.string().min(1).max(64).optional().describe(
310
+ 'Free-form label for your own bookkeeping (e.g. `"supplier"`, `"sales rep"`) \u2014 echoed back unchanged, never interpreted by Klappay.'
311
+ )
312
+ });
313
+ var SplitRecipientsSchema = import_zod8.z.array(SplitRecipientSchema).max(CHARGE_SPLIT_RECIPIENTS_MAX).superRefine((recipients, ctx) => {
314
+ const seen = /* @__PURE__ */ new Set();
315
+ recipients.forEach((recipient, index) => {
316
+ const key = recipient.address.toLowerCase();
317
+ if (seen.has(key)) {
318
+ ctx.addIssue({
319
+ code: import_zod8.z.ZodIssueCode.custom,
320
+ message: `Duplicate split recipient address: ${recipient.address}.`,
321
+ path: [index, "address"]
322
+ });
323
+ }
324
+ seen.add(key);
325
+ });
326
+ }).describe(
327
+ `Optional extra recipients for this charge's split \u2014 e.g. a supplier or the sales rep who closed the deal \u2014 up to ${CHARGE_SPLIT_RECIPIENTS_MAX}. Frozen at creation exactly like everything else that shapes the split address; cannot be changed afterward. The sum of every \`percent\` here must fit within \`100 - feePercent\` (your own net share) \u2014 a request that doesn't is rejected with \`422 split_recipients_exceed_available_percent\`.`
328
+ );
278
329
  var CHARGE_AMOUNT_MAX = 999999999999;
279
- var CreateChargeSchema = import_zod7.z.object({
280
- amount: import_zod7.z.number().positive().max(CHARGE_AMOUNT_MAX).describe(
330
+ var CreateChargeSchema = import_zod8.z.object({
331
+ amount: import_zod8.z.number().positive().max(CHARGE_AMOUNT_MAX).describe(
281
332
  "Amount to charge, in `currency` units (e.g. `49.9` = $49.90) \u2014 up to 6 decimal places; anything more precise is silently truncated. Required \u2014 every charge has a target amount, the first credited transfer that reaches it confirms the charge."
282
333
  ),
283
- currency: import_zod7.z.literal("USD").default("USD").describe("Always `USD` today \u2014 the only supported currency."),
334
+ currency: import_zod8.z.literal("USD").default("USD").describe("Always `USD` today \u2014 the only supported currency."),
284
335
  acceptedPayments: AcceptedPaymentsSchema,
285
- expiresIn: import_zod7.z.number().int().min(CHARGE_EXPIRES_IN_MIN_SECONDS).max(CHARGE_EXPIRES_IN_MAX_SECONDS).describe(
336
+ expiresIn: import_zod8.z.number().int().min(CHARGE_EXPIRES_IN_MIN_SECONDS).max(CHARGE_EXPIRES_IN_MAX_SECONDS).describe(
286
337
  "Seconds, not minutes or milliseconds \u2014 how long the charge stays open before it expires. Required, min 60, max 3600 (60 minutes) \u2014 sized off the slowest chain Klappay supports today (Ethereum mainnet, where a safely-confirmed transfer takes up to ~15 minutes), leaving real margin for payer-side delay (gas spikes, wallet friction) on top of that. Cannot be extended or shortened after creation."
287
338
  ),
288
- idempotencyKey: import_zod7.z.string().min(1).max(255).optional().describe(
339
+ idempotencyKey: import_zod8.z.string().min(1).max(255).optional().describe(
289
340
  "Scoped to your tenant. Replaying the same key returns the original charge unchanged instead of creating a duplicate \u2014 safe to retry a request after a timeout without double-charging."
290
341
  ),
291
- externalRef: import_zod7.z.string().min(1).max(255).optional().describe(
342
+ externalRef: import_zod8.z.string().min(1).max(255).optional().describe(
292
343
  "An opaque correlation id from your own system (e.g. an order id) \u2014 echoed back on the charge and in every webhook payload. Not interpreted or validated by Klappay."
293
344
  ),
294
- source: import_zod7.z.string().min(1).max(64).optional().describe(
345
+ source: import_zod8.z.string().min(1).max(64).optional().describe(
295
346
  'Free-form label for what created this charge (e.g. `"checkout"`, `"invoice"`) \u2014 useful if you create charges from more than one flow and want to tell them apart later. Not a fixed enum; use whatever values make sense to you.'
296
347
  ),
297
- metadata: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown()).optional().describe("Arbitrary key/value data to attach to the charge, returned as-is on every read."),
298
- redirectUrl: import_zod7.z.string().url().refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
348
+ metadata: MetadataWithKlappaySchema.optional(),
349
+ redirectUrl: import_zod8.z.string().url().refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
299
350
  "Where to send the payer once this charge resolves, if you use Klappay's hosted checkout page (see `checkoutUrl` on the read shape) \u2014 ignored otherwise. Must be `http(s)` \u2014 a browser will navigate here, so `javascript:`/`data:` and other non-navigational schemes are rejected. Otherwise not validated beyond being well-formed; what happens at that destination is yours to build."
300
- )
351
+ ),
352
+ splitRecipients: SplitRecipientsSchema.optional()
301
353
  });
302
- var ChargeSchema = import_zod7.z.object({
303
- id: import_zod7.z.string().describe("Klappay-generated id, e.g. `ch_...`. Use this to look up the charge later."),
304
- amount: import_zod7.z.number().describe("The amount originally requested, in `currency` units (up to 6 decimal places)."),
305
- amountReceived: import_zod7.z.number().nullable().describe(
354
+ var ChargeSchema = import_zod8.z.object({
355
+ id: import_zod8.z.string().describe("Klappay-generated id, e.g. `ch_...`. Use this to look up the charge later."),
356
+ amount: import_zod8.z.number().describe("The amount originally requested, in `currency` units (up to 6 decimal places)."),
357
+ amountReceived: import_zod8.z.number().nullable().describe(
306
358
  "Cumulative amount actually received on-chain so far, in `currency` units (up to 6 decimal places). `null` until the first transfer arrives. Can exceed `amount` \u2014 see `isOverpaid`."
307
359
  ),
308
- isOverpaid: import_zod7.z.boolean().describe(
360
+ isOverpaid: import_zod8.z.boolean().describe(
309
361
  "`true` if `amountReceived` ended up greater than `amount`. Klappay never refunds the difference automatically \u2014 see the docs for why."
310
362
  ),
311
- currency: import_zod7.z.string().describe("Always `USD` today \u2014 the only supported currency."),
312
- acceptedPayments: import_zod7.z.array(AcceptedPaymentSchema).describe(
363
+ currency: import_zod8.z.string().describe("Always `USD` today \u2014 the only supported currency."),
364
+ acceptedPayments: import_zod8.z.array(AcceptedPaymentSchema).describe(
313
365
  "Every `(token, network)` pair this charge was configured to accept, unchanged after creation."
314
366
  ),
315
- paidWith: import_zod7.z.array(AcceptedPaymentSchema).describe(
367
+ paidWith: import_zod8.z.array(AcceptedPaymentSchema).describe(
316
368
  "Every distinct `(token, network)` pair that has actually contributed a credited transfer so far \u2014 empty until the first one arrives. Can hold more than one entry: a charge accepting several pairs can be paid across a combination of them, and every entry here sums toward `amountReceived`."
317
369
  ),
318
- address: import_zod7.z.string().describe(
370
+ address: import_zod8.z.string().describe(
319
371
  "The on-chain address the payer must send funds to \u2014 identical across every accepted network (0xSplits addresses are chain-agnostic). Unique per charge, predicted at creation time \u2014 funds sent here go directly to the merchant, Klappay never custodies them."
320
372
  ),
321
373
  status: ChargeStatusSchema,
322
374
  settlementStatus: SettlementStatusSchema.nullable(),
323
375
  environment: EnvironmentSchema,
324
- apiKeyId: import_zod7.z.string().nullable().describe(
376
+ apiKeyId: import_zod8.z.string().nullable().describe(
325
377
  "Which of your API keys created this charge. `null` for a charge created before this field existed."
326
378
  ),
327
- txHash: import_zod7.z.string().nullable().describe(
379
+ txHash: import_zod8.z.string().nullable().describe(
328
380
  "Transaction hash of the most recent transfer detected for this charge. `null` until a payment is detected."
329
381
  ),
330
- externalRef: import_zod7.z.string().nullable(),
331
- source: import_zod7.z.string().nullable(),
332
- metadata: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown()).nullable(),
333
- redirectUrl: import_zod7.z.string().nullable().describe("Echoes the `redirectUrl` set at creation, if any. `null` if none was set."),
334
- checkoutUrl: import_zod7.z.string().nullable().describe(
382
+ externalRef: import_zod8.z.string().nullable(),
383
+ source: import_zod8.z.string().nullable(),
384
+ metadata: MetadataWithKlappaySchema.nullable(),
385
+ redirectUrl: import_zod8.z.string().nullable().describe("Echoes the `redirectUrl` set at creation, if any. `null` if none was set."),
386
+ checkoutUrl: import_zod8.z.string().nullable().describe(
335
387
  "Link to Klappay's hosted checkout page for this charge. `null` if this deployment has no hosted checkout configured \u2014 build your own payment UI from `address`/`acceptedPayments` instead."
336
388
  ),
337
- createdAt: import_zod7.z.string().datetime(),
338
- expiresAt: import_zod7.z.string().datetime().describe(
389
+ splitRecipients: import_zod8.z.array(SplitRecipientSchema).describe("Echoes whatever extra split recipients were set at creation \u2014 empty array if none."),
390
+ createdAt: import_zod8.z.string().datetime(),
391
+ expiresAt: import_zod8.z.string().datetime().describe(
339
392
  "When this charge stops accepting payment, if still `pending`/`partially_paid` by then."
340
393
  ),
341
- confirmedAt: import_zod7.z.string().datetime().nullable().describe("When `status` first reached `confirmed`. `null` until then."),
342
- settledAt: import_zod7.z.string().datetime().nullable().describe(
394
+ confirmedAt: import_zod8.z.string().datetime().nullable().describe("When `status` first reached `confirmed`. `null` until then."),
395
+ settledAt: import_zod8.z.string().datetime().nullable().describe(
343
396
  "When `settlementStatus` first reached `completed` \u2014 the merchant's wallet actually has the funds. `null` until then, including while `settlementStatus` is `pending`/`failed`."
344
397
  ),
345
- lastActivityAt: import_zod7.z.string().datetime().describe(
398
+ lastActivityAt: import_zod8.z.string().datetime().describe(
346
399
  "When a transfer was last credited toward this charge, or `createdAt` if none has arrived yet."
347
400
  )
348
401
  });
349
- var ListChargesSchema = import_zod7.z.object({
402
+ var ListChargesSchema = import_zod8.z.object({
350
403
  status: ChargeStatusSchema.optional(),
351
404
  token: TokenSchema.optional().describe(
352
405
  "Filters on `paidWith.token` \u2014 the pair actually paid, not accepted."
@@ -355,13 +408,13 @@ var ListChargesSchema = import_zod7.z.object({
355
408
  "Filters on `paidWith.network` \u2014 the pair actually paid, not accepted."
356
409
  ),
357
410
  environment: EnvironmentSchema.optional(),
358
- since: import_zod7.z.string().datetime().optional().describe(
411
+ since: import_zod8.z.string().datetime().optional().describe(
359
412
  "Only return charges created at or after this timestamp (filters on `createdAt`, not on when the status last changed). If polling as a fallback for missed webhooks, use a window at least as wide as the longest `expiresIn` your charges use, or you can miss a long-lived charge that changed status outside a narrower window."
360
413
  ),
361
- isOverpaid: import_zod7.z.enum(["true", "false"]).transform((v) => v === "true").optional()
414
+ isOverpaid: import_zod8.z.enum(["true", "false"]).transform((v) => v === "true").optional()
362
415
  }).extend(PaginationQuerySchema.shape);
363
416
  var PaginatedChargesSchema = paginatedSchema(ChargeSchema);
364
- var GetChargeQrCodeQuerySchema = import_zod7.z.object({
417
+ var GetChargeQrCodeQuerySchema = import_zod8.z.object({
365
418
  token: TokenSchema.optional().describe(
366
419
  "Which accepted `(token, network)` pair to encode in the QR \u2014 required if `acceptedPayments` has more than one pair, since there is no single unambiguous default to fall back to. Ignored (and unnecessary) when the charge accepts exactly one pair."
367
420
  ),
@@ -369,61 +422,61 @@ var GetChargeQrCodeQuerySchema = import_zod7.z.object({
369
422
  });
370
423
 
371
424
  // src/distributions.ts
372
- var import_zod8 = require("zod");
373
- var SplitDistributionStatusSchema = import_zod8.z.enum(["pending", "processing", "completed", "failed"]).describe(
425
+ var import_zod9 = require("zod");
426
+ var SplitDistributionStatusSchema = import_zod9.z.enum(["pending", "processing", "completed", "failed"]).describe(
374
427
  "Status of one payout attempt to the merchant, for a single `(token, network)` pair \u2014 a charge that settles across more than one pair has one of these per pair. `pending`: queued, not yet claimed by a distributor. `processing`: a distributor (Klappay's own worker, or anyone racing to call `distribute()` first, see `PendingDistributionSchema`) has claimed it and is submitting the on-chain transaction. `completed`: the merchant's wallet has the funds. `failed`: every automatic retry was exhausted."
375
428
  );
376
- var PendingDistributionRecipientSchema = import_zod8.z.object({
377
- address: import_zod8.z.string().describe("On-chain recipient address."),
378
- percentAllocation: import_zod8.z.number().describe("This recipient's share of the split, as a percentage (e.g. `99.0991` = 99.0991%).")
429
+ var PendingDistributionRecipientSchema = import_zod9.z.object({
430
+ address: import_zod9.z.string().describe("On-chain recipient address."),
431
+ percentAllocation: import_zod9.z.number().describe("This recipient's share of the split, as a percentage (e.g. `99.0991` = 99.0991%).")
379
432
  });
380
- var PendingDistributionSchema = import_zod8.z.object({
381
- splitAddress: import_zod8.z.string().describe("The on-chain 0xSplits address to call `distribute()` on."),
433
+ var PendingDistributionSchema = import_zod9.z.object({
434
+ splitAddress: import_zod9.z.string().describe("The on-chain 0xSplits address to call `distribute()` on."),
382
435
  network: NetworkSchema,
383
436
  token: TokenSchema,
384
- recipients: import_zod8.z.array(PendingDistributionRecipientSchema).describe(
437
+ recipients: import_zod9.z.array(PendingDistributionRecipientSchema).describe(
385
438
  "The exact recipient list to pass to `distribute()` \u2014 the split contract only stores a hash of this config, so the caller must supply the identical array to prove it matches. Always present, never reconstructed from partial data."
386
439
  ),
387
- distributorFeePercent: import_zod8.z.number().describe(
440
+ distributorFeePercent: import_zod9.z.number().describe(
388
441
  "Percentage of the split balance paid to whoever calls `distribute()` first (e.g. `0.1` = 0.1%). Frozen at charge creation, same for every distribution today."
389
442
  ),
390
- estimatedRewardAmount: import_zod8.z.number().describe(
443
+ estimatedRewardAmount: import_zod9.z.number().describe(
391
444
  "Estimate only, in the charge's `currency` units, based on the amount Klappay detected on-chain \u2014 not a live read of the split's current balance. Read the balance yourself before submitting a transaction; a stale estimate is harmless (see the docs), never a reason to skip that check."
392
445
  ),
393
- availableSince: import_zod8.z.string().datetime().describe("When this distribution entered its grace period."),
394
- graceEndsAt: import_zod8.z.string().datetime().describe(
446
+ availableSince: import_zod9.z.string().datetime().describe("When this distribution entered its grace period."),
447
+ graceEndsAt: import_zod9.z.string().datetime().describe(
395
448
  "When Klappay's own worker may claim this distribution. Racing to call `distribute()` after this timestamp is possible but increasingly likely to lose to the worker."
396
449
  )
397
450
  });
398
451
  var PaginatedPendingDistributionsSchema = paginatedSchema(PendingDistributionSchema);
399
- var ListenPendingDistributionsQuerySchema = import_zod8.z.object({
400
- limit: import_zod8.z.coerce.number().int().min(0).max(PAGINATION_LIMIT_MAX).default(0).describe(
452
+ var ListenPendingDistributionsQuerySchema = import_zod9.z.object({
453
+ limit: import_zod9.z.coerce.number().int().min(0).max(PAGINATION_LIMIT_MAX).default(0).describe(
401
454
  "How many currently-claimable distributions to emit as an initial snapshot right after connecting \u2014 each as a synthetic `distribution.available` event \u2014 before continuing with real-time deltas. `0` (the default, same as omitting it) sends no snapshot at all, matching this endpoint's original behavior: connect first, then call `GET /v1/distributions/pending` yourself to bootstrap. Not a page \u2014 there is no cursor for this snapshot, so if more than `limit` are claimable at connect time, the excess is simply not sent; call `GET /v1/distributions/pending` directly for a complete, paginated listing."
402
455
  )
403
456
  });
404
- var PendingDistributionEventSchema = import_zod8.z.discriminatedUnion("type", [
405
- import_zod8.z.object({
406
- type: import_zod8.z.literal("distribution.available"),
457
+ var PendingDistributionEventSchema = import_zod9.z.discriminatedUnion("type", [
458
+ import_zod9.z.object({
459
+ type: import_zod9.z.literal("distribution.available"),
407
460
  distribution: PendingDistributionSchema
408
461
  }),
409
- import_zod8.z.object({
410
- type: import_zod8.z.literal("distribution.claimed"),
411
- splitAddress: import_zod8.z.string().describe("No longer claimable \u2014 either settled by someone, or picked up by the worker.")
462
+ import_zod9.z.object({
463
+ type: import_zod9.z.literal("distribution.claimed"),
464
+ splitAddress: import_zod9.z.string().describe("No longer claimable \u2014 either settled by someone, or picked up by the worker.")
412
465
  })
413
466
  ]);
414
467
 
415
468
  // src/metrics.ts
416
- var import_zod9 = require("zod");
417
- var MetricsResourceSchema = import_zod9.z.enum(["charges", "transactions", "distributions"]).describe(
469
+ var import_zod10 = require("zod");
470
+ var MetricsResourceSchema = import_zod10.z.enum(["charges", "transactions", "distributions"]).describe(
418
471
  "Which underlying dataset to query. `charges`: one row per charge. `transactions`: one row per detected on-chain transfer \u2014 a charge paid in installments has more than one. `distributions`: one row per payout attempt to the merchant, one per `(token, network)` pair a charge settled across."
419
472
  );
420
- var MetricsAggregationSchema = import_zod9.z.enum(["count", "sum", "avg", "min", "max"]).describe(
473
+ var MetricsAggregationSchema = import_zod10.z.enum(["count", "sum", "avg", "min", "max"]).describe(
421
474
  "`count` counts matching rows and never takes `field`. `sum`/`avg`/`min`/`max` require `field` to be set to one of the resource\u2019s numeric fields."
422
475
  );
423
- var MetricsFilterOperatorSchema = import_zod9.z.enum(["eq", "neq", "in", "gt", "gte", "lt", "lte"]).describe(
476
+ var MetricsFilterOperatorSchema = import_zod10.z.enum(["eq", "neq", "in", "gt", "gte", "lt", "lte"]).describe(
424
477
  "`in` expects an array value (max 50 entries); every other operator expects a single scalar."
425
478
  );
426
- var MetricsDateGranularitySchema = import_zod9.z.enum(["day", "week", "month", "year"]).describe(
479
+ var MetricsDateGranularitySchema = import_zod10.z.enum(["day", "week", "month", "year"]).describe(
427
480
  "Bucket width for a `date_bucket` `groupBy` entry \u2014 Postgres `date_trunc` semantics (UTC)."
428
481
  );
429
482
  var metricsQueryEnvironmentSchema = EnvironmentSchema.describe(
@@ -436,151 +489,151 @@ var METRICS_QUERY_MAX_GROUP_BY = 3;
436
489
  var METRICS_QUERY_MAX_FILTERS = 20;
437
490
  var METRICS_QUERY_MAX_METRICS = 10;
438
491
  var METRIC_ALIAS_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
439
- var metricAliasSchema = import_zod9.z.string().min(1).max(64).regex(
492
+ var metricAliasSchema = import_zod10.z.string().min(1).max(64).regex(
440
493
  METRIC_ALIAS_PATTERN,
441
494
  "Must start with a letter or underscore, and contain only letters, digits, and underscores \u2014 this becomes a SQL column alias."
442
495
  ).optional();
443
- var MetricsFilterValueSchema = import_zod9.z.union([
444
- import_zod9.z.string().max(255),
445
- import_zod9.z.number(),
446
- import_zod9.z.boolean(),
447
- import_zod9.z.array(import_zod9.z.union([import_zod9.z.string().max(255), import_zod9.z.number()])).min(1).max(50)
496
+ var MetricsFilterValueSchema = import_zod10.z.union([
497
+ import_zod10.z.string().max(255),
498
+ import_zod10.z.number(),
499
+ import_zod10.z.boolean(),
500
+ import_zod10.z.array(import_zod10.z.union([import_zod10.z.string().max(255), import_zod10.z.number()])).min(1).max(50)
448
501
  ]);
449
- var orderBySchema = import_zod9.z.object({
450
- key: import_zod9.z.string().min(1).max(64).regex(
502
+ var orderBySchema = import_zod10.z.object({
503
+ key: import_zod10.z.string().min(1).max(64).regex(
451
504
  METRIC_ALIAS_PATTERN,
452
505
  "Must start with a letter or underscore, and contain only letters, digits, and underscores \u2014 every valid output column name already looks like this."
453
506
  ).describe(
454
507
  "An output column name from this same query \u2014 either a `groupBy` field name, or a metric\u2019s `alias` (or its default name: `${aggregation}` for `count`, `${aggregation}_${field}` otherwise, e.g. `sum_amount`). Must match `^[a-zA-Z_][a-zA-Z0-9_]*$` \u2014 every real output column name already does, so this only ever rejects a value that could never have been one."
455
508
  ),
456
- direction: import_zod9.z.enum(["asc", "desc"])
509
+ direction: import_zod10.z.enum(["asc", "desc"])
457
510
  }).describe(
458
511
  "Sort the result rows by any output column \u2014 including the bucket field itself for a `date_bucket` query (e.g. `createdAt`). Omit to get ascending-by-bucket order for a date-bucketed query, or implementation-defined (not guaranteed stable) order otherwise."
459
512
  );
460
- var limitSchema = import_zod9.z.number().int().min(1).max(METRICS_QUERY_MAX_ROW_LIMIT).default(METRICS_QUERY_DEFAULT_ROW_LIMIT).describe(
513
+ var limitSchema = import_zod10.z.number().int().min(1).max(METRICS_QUERY_MAX_ROW_LIMIT).default(METRICS_QUERY_DEFAULT_ROW_LIMIT).describe(
461
514
  `Max rows to return, ${1}\u2013${METRICS_QUERY_MAX_ROW_LIMIT}, default ${METRICS_QUERY_DEFAULT_ROW_LIMIT}. If more rows matched, \`meta.truncated\` is \`true\` on the response \u2014 narrow the query instead of just raising this.`
462
515
  );
463
- var ChargesQueryFieldSchema = import_zod9.z.enum(["status", "source", "apiKeyId", "currency", "isOverpaid", "externalRef"]).describe(
516
+ var ChargesQueryFieldSchema = import_zod10.z.enum(["status", "source", "apiKeyId", "currency", "isOverpaid", "externalRef"]).describe(
464
517
  "A `Charge` field to filter or group by \u2014 see `ChargeStatusSchema` for `status`'s own possible values (charges.md). `source`/`externalRef` are free-form strings your own integration set at creation, not a fixed enum."
465
518
  );
466
- var ChargesMetricFieldSchema = import_zod9.z.enum(["amount", "amountReceived", "feePercent"]).describe(
519
+ var ChargesMetricFieldSchema = import_zod10.z.enum(["amount", "amountReceived", "feePercent"]).describe(
467
520
  "A `Charge` numeric field to aggregate. `amount`/`amountReceived` are decimal currency amounts (requested vs. actually received \u2014 see `charges.md`). `feePercent` is the platform fee frozen on the charge at creation, e.g. `1.5` means 1.5%."
468
521
  );
469
- var ChargesDateFieldSchema = import_zod9.z.enum(["createdAt", "confirmedAt", "lastActivityAt", "expiresAt"]).describe(
522
+ var ChargesDateFieldSchema = import_zod10.z.enum(["createdAt", "confirmedAt", "lastActivityAt", "expiresAt"]).describe(
470
523
  "A `Charge` timestamp to filter/bucket by. `confirmedAt` is `null` until the charge reaches `confirmed` \u2014 a `dateRange`/`date_bucket` on it implicitly excludes every charge that never confirmed. `expiresAt` is always present (set at creation), useful for e.g. finding charges expiring soon or measuring how close to expiry charges typically resolve."
471
524
  );
472
- var ChargesFilterSchema = import_zod9.z.object({
525
+ var ChargesFilterSchema = import_zod10.z.object({
473
526
  field: ChargesQueryFieldSchema,
474
527
  operator: MetricsFilterOperatorSchema,
475
528
  value: MetricsFilterValueSchema
476
529
  });
477
- var ChargesGroupBySchema = import_zod9.z.union([
478
- import_zod9.z.object({ type: import_zod9.z.literal("field"), field: ChargesQueryFieldSchema }),
479
- import_zod9.z.object({
480
- type: import_zod9.z.literal("date_bucket"),
530
+ var ChargesGroupBySchema = import_zod10.z.union([
531
+ import_zod10.z.object({ type: import_zod10.z.literal("field"), field: ChargesQueryFieldSchema }),
532
+ import_zod10.z.object({
533
+ type: import_zod10.z.literal("date_bucket"),
481
534
  field: ChargesDateFieldSchema,
482
535
  granularity: MetricsDateGranularitySchema
483
536
  })
484
537
  ]);
485
- var ChargesMetricSchema = import_zod9.z.object({
538
+ var ChargesMetricSchema = import_zod10.z.object({
486
539
  aggregation: MetricsAggregationSchema,
487
540
  field: ChargesMetricFieldSchema.optional(),
488
541
  alias: metricAliasSchema
489
542
  });
490
- var ChargesMetricsQuerySchema = import_zod9.z.object({
491
- resource: import_zod9.z.literal("charges"),
543
+ var ChargesMetricsQuerySchema = import_zod10.z.object({
544
+ resource: import_zod10.z.literal("charges"),
492
545
  environment: metricsQueryEnvironmentSchema,
493
- dateRange: import_zod9.z.object({
546
+ dateRange: import_zod10.z.object({
494
547
  field: ChargesDateFieldSchema,
495
- from: import_zod9.z.string().max(64).datetime(),
496
- to: import_zod9.z.string().max(64).datetime()
548
+ from: import_zod10.z.string().max(64).datetime(),
549
+ to: import_zod10.z.string().max(64).datetime()
497
550
  }),
498
- groupBy: import_zod9.z.array(ChargesGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
499
- metrics: import_zod9.z.array(ChargesMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
500
- filters: import_zod9.z.array(ChargesFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
551
+ groupBy: import_zod10.z.array(ChargesGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
552
+ metrics: import_zod10.z.array(ChargesMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
553
+ filters: import_zod10.z.array(ChargesFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
501
554
  orderBy: orderBySchema.optional(),
502
555
  limit: limitSchema
503
556
  });
504
- var TransactionsQueryFieldSchema = import_zod9.z.enum(["network", "token", "source", "causedTransition"]).describe(
557
+ var TransactionsQueryFieldSchema = import_zod10.z.enum(["network", "token", "source", "causedTransition"]).describe(
505
558
  "A `Transaction` field to filter or group by \u2014 see `NetworkSchema`/`TokenSchema`/`TransactionSourceSchema` for their possible values. `causedTransition` is `true` only for the transfer(s) that actually flipped the charge's `status` \u2014 a charge paid in installments can have more than one; filtering/grouping on it excludes no-op duplicate transfers (see `TimelineEvent.causedTransition` in charges.md for the full explanation)."
506
559
  );
507
- var TransactionsMetricFieldSchema = import_zod9.z.enum(["amount"]).describe("The transfer amount, in the charge's `currency` units.");
508
- var TransactionsDateFieldSchema = import_zod9.z.enum(["detectedAt"]).describe("When Klappay detected this transfer on-chain (not when it was mined).");
509
- var TransactionsFilterSchema = import_zod9.z.object({
560
+ var TransactionsMetricFieldSchema = import_zod10.z.enum(["amount"]).describe("The transfer amount, in the charge's `currency` units.");
561
+ var TransactionsDateFieldSchema = import_zod10.z.enum(["detectedAt"]).describe("When Klappay detected this transfer on-chain (not when it was mined).");
562
+ var TransactionsFilterSchema = import_zod10.z.object({
510
563
  field: TransactionsQueryFieldSchema,
511
564
  operator: MetricsFilterOperatorSchema,
512
565
  value: MetricsFilterValueSchema
513
566
  });
514
- var TransactionsGroupBySchema = import_zod9.z.union([
515
- import_zod9.z.object({ type: import_zod9.z.literal("field"), field: TransactionsQueryFieldSchema }),
516
- import_zod9.z.object({
517
- type: import_zod9.z.literal("date_bucket"),
567
+ var TransactionsGroupBySchema = import_zod10.z.union([
568
+ import_zod10.z.object({ type: import_zod10.z.literal("field"), field: TransactionsQueryFieldSchema }),
569
+ import_zod10.z.object({
570
+ type: import_zod10.z.literal("date_bucket"),
518
571
  field: TransactionsDateFieldSchema,
519
572
  granularity: MetricsDateGranularitySchema
520
573
  })
521
574
  ]);
522
- var TransactionsMetricSchema = import_zod9.z.object({
575
+ var TransactionsMetricSchema = import_zod10.z.object({
523
576
  aggregation: MetricsAggregationSchema,
524
577
  field: TransactionsMetricFieldSchema.optional(),
525
578
  alias: metricAliasSchema
526
579
  });
527
- var TransactionsMetricsQuerySchema = import_zod9.z.object({
528
- resource: import_zod9.z.literal("transactions"),
580
+ var TransactionsMetricsQuerySchema = import_zod10.z.object({
581
+ resource: import_zod10.z.literal("transactions"),
529
582
  environment: metricsQueryEnvironmentSchema,
530
- dateRange: import_zod9.z.object({
583
+ dateRange: import_zod10.z.object({
531
584
  field: TransactionsDateFieldSchema,
532
- from: import_zod9.z.string().max(64).datetime(),
533
- to: import_zod9.z.string().max(64).datetime()
585
+ from: import_zod10.z.string().max(64).datetime(),
586
+ to: import_zod10.z.string().max(64).datetime()
534
587
  }),
535
- groupBy: import_zod9.z.array(TransactionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
536
- metrics: import_zod9.z.array(TransactionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
537
- filters: import_zod9.z.array(TransactionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
588
+ groupBy: import_zod10.z.array(TransactionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
589
+ metrics: import_zod10.z.array(TransactionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
590
+ filters: import_zod10.z.array(TransactionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
538
591
  orderBy: orderBySchema.optional(),
539
592
  limit: limitSchema
540
593
  });
541
- var DistributionsQueryFieldSchema = import_zod9.z.enum(["status", "network", "token", "distributorAddress"]).describe(
594
+ var DistributionsQueryFieldSchema = import_zod10.z.enum(["status", "network", "token", "distributorAddress"]).describe(
542
595
  "A `SplitDistribution` field to filter or group by \u2014 see `SplitDistributionStatusSchema`/`NetworkSchema`/`TokenSchema` for their possible values. `distributorAddress` is the public on-chain address that actually called `distribute()` for a `completed` distribution \u2014 Klappay's own operator address if settled by Klappay's own worker, a community keeper's address if settled externally (or `null` on the rare case that lookup failed), `null` for every non-`completed` status."
543
596
  );
544
- var DistributionsMetricFieldSchema = import_zod9.z.enum(["attempts"]).describe(
597
+ var DistributionsMetricFieldSchema = import_zod10.z.enum(["attempts"]).describe(
545
598
  "How many times a payout was attempted for this settlement so far \u2014 incremented on every attempt, whether it succeeded or is being retried after failing. A high `attempts` alongside `status: 'failed'` means every automatic retry was exhausted."
546
599
  );
547
- var DistributionsDateFieldSchema = import_zod9.z.enum(["createdAt", "processingStartedAt", "completedAt"]).describe(
600
+ var DistributionsDateFieldSchema = import_zod10.z.enum(["createdAt", "processingStartedAt", "completedAt"]).describe(
548
601
  "`createdAt`: when this settlement was queued. `processingStartedAt`: when a worker began its most recent attempt at the payout \u2014 `null` until the first attempt, then overwritten on every subsequent retry, so it reflects the *latest* attempt's start, not the first. `completedAt`: when it actually paid out \u2014 `null` until `status` reaches `completed`, so a `dateRange`/`date_bucket` on it implicitly excludes every distribution still pending/processing/failed."
549
602
  );
550
- var DistributionsFilterSchema = import_zod9.z.object({
603
+ var DistributionsFilterSchema = import_zod10.z.object({
551
604
  field: DistributionsQueryFieldSchema,
552
605
  operator: MetricsFilterOperatorSchema,
553
606
  value: MetricsFilterValueSchema
554
607
  });
555
- var DistributionsGroupBySchema = import_zod9.z.union([
556
- import_zod9.z.object({ type: import_zod9.z.literal("field"), field: DistributionsQueryFieldSchema }),
557
- import_zod9.z.object({
558
- type: import_zod9.z.literal("date_bucket"),
608
+ var DistributionsGroupBySchema = import_zod10.z.union([
609
+ import_zod10.z.object({ type: import_zod10.z.literal("field"), field: DistributionsQueryFieldSchema }),
610
+ import_zod10.z.object({
611
+ type: import_zod10.z.literal("date_bucket"),
559
612
  field: DistributionsDateFieldSchema,
560
613
  granularity: MetricsDateGranularitySchema
561
614
  })
562
615
  ]);
563
- var DistributionsMetricSchema = import_zod9.z.object({
616
+ var DistributionsMetricSchema = import_zod10.z.object({
564
617
  aggregation: MetricsAggregationSchema,
565
618
  field: DistributionsMetricFieldSchema.optional(),
566
619
  alias: metricAliasSchema
567
620
  });
568
- var DistributionsMetricsQuerySchema = import_zod9.z.object({
569
- resource: import_zod9.z.literal("distributions"),
621
+ var DistributionsMetricsQuerySchema = import_zod10.z.object({
622
+ resource: import_zod10.z.literal("distributions"),
570
623
  environment: metricsQueryEnvironmentSchema,
571
- dateRange: import_zod9.z.object({
624
+ dateRange: import_zod10.z.object({
572
625
  field: DistributionsDateFieldSchema,
573
- from: import_zod9.z.string().max(64).datetime(),
574
- to: import_zod9.z.string().max(64).datetime()
626
+ from: import_zod10.z.string().max(64).datetime(),
627
+ to: import_zod10.z.string().max(64).datetime()
575
628
  }),
576
- groupBy: import_zod9.z.array(DistributionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
577
- metrics: import_zod9.z.array(DistributionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
578
- filters: import_zod9.z.array(DistributionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
629
+ groupBy: import_zod10.z.array(DistributionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
630
+ metrics: import_zod10.z.array(DistributionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
631
+ filters: import_zod10.z.array(DistributionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
579
632
  orderBy: orderBySchema.optional(),
580
633
  limit: limitSchema
581
634
  });
582
635
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
583
- var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
636
+ var MetricsQuerySchema = import_zod10.z.discriminatedUnion("resource", [
584
637
  ChargesMetricsQuerySchema,
585
638
  TransactionsMetricsQuerySchema,
586
639
  DistributionsMetricsQuerySchema
@@ -589,7 +642,7 @@ var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
589
642
  const to = new Date(input.dateRange.to);
590
643
  if (from >= to) {
591
644
  ctx.addIssue({
592
- code: import_zod9.z.ZodIssueCode.custom,
645
+ code: import_zod10.z.ZodIssueCode.custom,
593
646
  message: "`dateRange.from` must be before `dateRange.to`.",
594
647
  path: ["dateRange", "from"]
595
648
  });
@@ -597,7 +650,7 @@ var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
597
650
  const spanDays = (to.getTime() - from.getTime()) / ONE_DAY_MS;
598
651
  if (spanDays > MAX_METRICS_QUERY_DATE_RANGE_DAYS) {
599
652
  ctx.addIssue({
600
- code: import_zod9.z.ZodIssueCode.custom,
653
+ code: import_zod10.z.ZodIssueCode.custom,
601
654
  message: `\`dateRange\` cannot span more than ${MAX_METRICS_QUERY_DATE_RANGE_DAYS} days.`,
602
655
  path: ["dateRange", "to"]
603
656
  });
@@ -605,7 +658,7 @@ var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
605
658
  const dateBucketCount = input.groupBy.filter((entry) => entry.type === "date_bucket").length;
606
659
  if (dateBucketCount > 1) {
607
660
  ctx.addIssue({
608
- code: import_zod9.z.ZodIssueCode.custom,
661
+ code: import_zod10.z.ZodIssueCode.custom,
609
662
  message: "At most one `date_bucket` entry is allowed in `groupBy`.",
610
663
  path: ["groupBy"]
611
664
  });
@@ -613,7 +666,7 @@ var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
613
666
  input.metrics.forEach((metric, index) => {
614
667
  if (metric.aggregation !== "count" && metric.field === void 0) {
615
668
  ctx.addIssue({
616
- code: import_zod9.z.ZodIssueCode.custom,
669
+ code: import_zod10.z.ZodIssueCode.custom,
617
670
  message: "`field` is required unless `aggregation` is `count`.",
618
671
  path: ["metrics", index, "field"]
619
672
  });
@@ -622,7 +675,7 @@ var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
622
675
  const aliases = input.metrics.map((metric) => metric.alias).filter((alias) => alias !== void 0);
623
676
  if (new Set(aliases).size !== aliases.length) {
624
677
  ctx.addIssue({
625
- code: import_zod9.z.ZodIssueCode.custom,
678
+ code: import_zod10.z.ZodIssueCode.custom,
626
679
  message: "Every `metrics[].alias` must be unique.",
627
680
  path: ["metrics"]
628
681
  });
@@ -631,32 +684,32 @@ var MetricsQuerySchema = import_zod9.z.discriminatedUnion("resource", [
631
684
  input.metrics.forEach((metric, index) => {
632
685
  if (metric.alias !== void 0 && reservedNames.has(metric.alias)) {
633
686
  ctx.addIssue({
634
- code: import_zod9.z.ZodIssueCode.custom,
687
+ code: import_zod10.z.ZodIssueCode.custom,
635
688
  message: `\`alias\` "${metric.alias}" collides with a \`groupBy\` field name (or the reserved word "bucket") \u2014 choose a different alias.`,
636
689
  path: ["metrics", index, "alias"]
637
690
  });
638
691
  }
639
692
  });
640
693
  });
641
- var MetricsQueryResultRowSchema = import_zod9.z.record(
642
- import_zod9.z.string(),
643
- import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number(), import_zod9.z.boolean(), import_zod9.z.null()])
694
+ var MetricsQueryResultRowSchema = import_zod10.z.record(
695
+ import_zod10.z.string(),
696
+ import_zod10.z.union([import_zod10.z.string(), import_zod10.z.number(), import_zod10.z.boolean(), import_zod10.z.null()])
644
697
  );
645
- var MetricsQueryResultSchema = import_zod9.z.object({
646
- data: import_zod9.z.array(MetricsQueryResultRowSchema),
647
- meta: import_zod9.z.object({
698
+ var MetricsQueryResultSchema = import_zod10.z.object({
699
+ data: import_zod10.z.array(MetricsQueryResultRowSchema),
700
+ meta: import_zod10.z.object({
648
701
  resource: MetricsResourceSchema,
649
702
  environment: EnvironmentSchema,
650
- rowCount: import_zod9.z.number().int().describe("Number of rows in `data`."),
651
- truncated: import_zod9.z.boolean().describe(
703
+ rowCount: import_zod10.z.number().int().describe("Number of rows in `data`."),
704
+ truncated: import_zod10.z.boolean().describe(
652
705
  "`true` if more rows matched than `limit` allowed \u2014 `data` holds only the first `limit`."
653
706
  )
654
707
  })
655
708
  });
656
709
 
657
710
  // src/webhook-events.ts
658
- var import_zod10 = require("zod");
659
- var ChargeWebhookEventTypeSchema = import_zod10.z.enum([
711
+ var import_zod11 = require("zod");
712
+ var ChargeWebhookEventTypeSchema = import_zod11.z.enum([
660
713
  "charge.created",
661
714
  "charge.partially_paid",
662
715
  "charge.confirmed",
@@ -668,14 +721,14 @@ var ChargeWebhookEventTypeSchema = import_zod10.z.enum([
668
721
  ]).describe(
669
722
  'Note the distinction between `charge.confirmed` and `charge.settled`: `confirmed` means the payment was detected on-chain; `settled` means the merchant\'s wallet actually received the funds \u2014 a separate, later step. Subscribe to `confirmed` if you only need "will I get paid," or `settled` if you need "has the money actually arrived." `charge.overpaid` fires alongside `charge.confirmed`/`charge.partially_paid` whenever the cumulative amount received ends up above `amount` (see `Charge.isOverpaid`). Every event in this category carries the full `Charge` object as `data`.'
670
723
  );
671
- var WebhookDeliveryEventTypeSchema = import_zod10.z.enum(["webhook.delivery_failed", "webhook.delivery_recovered", "webhook.endpoint_unhealthy"]).describe(
724
+ var WebhookDeliveryEventTypeSchema = import_zod11.z.enum(["webhook.delivery_failed", "webhook.delivery_recovered", "webhook.endpoint_unhealthy"]).describe(
672
725
  "Meta-events about the health of your own webhook endpoints \u2014 useful for monitoring without polling `GET /v1/webhooks/{id}/deliveries`. `webhook.endpoint_unhealthy` fires once when a webhook's failure rate over the trailing 24h crosses 20%, and `webhook.delivery_recovered` fires once when a delivery to that webhook next succeeds. `data` for every event in this category: `{ webhookId, url, failureRatio? }` (`failureRatio` only present on `webhook.endpoint_unhealthy`)."
673
726
  );
674
- var WebhookEventTypeSchema = import_zod10.z.union([
727
+ var WebhookEventTypeSchema = import_zod11.z.union([
675
728
  ChargeWebhookEventTypeSchema,
676
729
  WebhookDeliveryEventTypeSchema
677
730
  ]);
678
- var WebhookCategorySchema = import_zod10.z.enum(["payments", "webhooks"]).describe(
731
+ var WebhookCategorySchema = import_zod11.z.enum(["payments", "webhooks"]).describe(
679
732
  "Subscribe to every event in a category via `eventCategories` instead of listing events one by one \u2014 new events added to a category later arrive automatically, no subscription update needed."
680
733
  );
681
734
  function buildCategoryMap() {
@@ -703,78 +756,78 @@ var TriggerableChargeEventSchema = ChargeWebhookEventTypeSchema.exclude([
703
756
  );
704
757
 
705
758
  // src/webhooks.ts
706
- var import_zod11 = require("zod");
759
+ var import_zod12 = require("zod");
707
760
  var WEBHOOK_EVENTS_WILDCARD = "*";
708
- var CreateWebhookSchema = import_zod11.z.object({
709
- url: import_zod11.z.string().max(2048).url().describe(
761
+ var CreateWebhookSchema = import_zod12.z.object({
762
+ url: import_zod12.z.string().max(2048).url().describe(
710
763
  "Must be HTTPS and resolve to a public address \u2014 private/internal IPs are rejected."
711
764
  ),
712
- events: import_zod11.z.array(import_zod11.z.union([WebhookEventTypeSchema, import_zod11.z.literal(WEBHOOK_EVENTS_WILDCARD)])).max(Object.keys(EVENT_CATEGORY_MAP).length + 1).default([]).describe(
765
+ events: import_zod12.z.array(import_zod12.z.union([WebhookEventTypeSchema, import_zod12.z.literal(WEBHOOK_EVENTS_WILDCARD)])).max(Object.keys(EVENT_CATEGORY_MAP).length + 1).default([]).describe(
713
766
  'Individual event types to receive, or `"*"` for every event (combine with `excludeEvents` to opt back out of specific ones). Omit in favor of `eventCategories` if you want whole categories instead.'
714
767
  ),
715
- eventCategories: import_zod11.z.array(WebhookCategorySchema).max(WebhookCategorySchema.options.length).default([]).describe(
768
+ eventCategories: import_zod12.z.array(WebhookCategorySchema).max(WebhookCategorySchema.options.length).default([]).describe(
716
769
  "Subscribe to every event in these categories. At least one of `events` or `eventCategories` is required."
717
770
  ),
718
- excludeEvents: import_zod11.z.array(WebhookEventTypeSchema).max(Object.keys(EVENT_CATEGORY_MAP).length).default([]).describe(
771
+ excludeEvents: import_zod12.z.array(WebhookEventTypeSchema).max(Object.keys(EVENT_CATEGORY_MAP).length).default([]).describe(
719
772
  'Event types to exclude even if selected via `events: ["*"]` or `eventCategories`.'
720
773
  )
721
774
  }).refine((v) => v.events.length > 0 || v.eventCategories.length > 0, {
722
775
  message: "must select at least one event via `events` or `eventCategories`",
723
776
  path: ["events"]
724
777
  });
725
- var WebhookSchema = import_zod11.z.object({
726
- id: import_zod11.z.string(),
778
+ var WebhookSchema = import_zod12.z.object({
779
+ id: import_zod12.z.string(),
727
780
  environment: EnvironmentSchema.nullable().describe(
728
781
  "Which environment's API key created this webhook \u2014 `live` or `test`. Every event is only ever delivered to a webhook whose `environment` matches the event's own (or to a webhook with `environment: null`, which receives every environment \u2014 the case for every webhook created before this field existed)."
729
782
  ),
730
- url: import_zod11.z.string(),
731
- events: import_zod11.z.array(WebhookEventTypeSchema),
732
- eventCategories: import_zod11.z.array(WebhookCategorySchema),
733
- excludeEvents: import_zod11.z.array(WebhookEventTypeSchema),
734
- isWildcard: import_zod11.z.boolean(),
735
- secret: import_zod11.z.string().describe(
783
+ url: import_zod12.z.string(),
784
+ events: import_zod12.z.array(WebhookEventTypeSchema),
785
+ eventCategories: import_zod12.z.array(WebhookCategorySchema),
786
+ excludeEvents: import_zod12.z.array(WebhookEventTypeSchema),
787
+ isWildcard: import_zod12.z.boolean(),
788
+ secret: import_zod12.z.string().describe(
736
789
  "The signing secret, used to verify the `X-Klappay-Signature` header on every delivery. Returned in full only this once \u2014 store it now, it is not recoverable afterward. Header format: `t=<unix-seconds>,v1=<hex-encoded HMAC-SHA256>`. Compute the expected signature as `HMAC-SHA256(secret, \"${t}.${raw request body}\")` (hex-encoded) and compare it to `v1` using a constant-time comparison; as a replay-protection measure, also reject if `t` is too far from the current time \u2014 Klappay does not enforce or check any particular tolerance server-side, so the exact threshold is entirely the receiver's own policy call. An official SDK's `constructEvent()`/`verifySignature()` do this for you, defaulting to a 300-second tolerance, overridable via `constructEvent`'s `toleranceSeconds` option \u2014 see github.com/klappay for available SDKs."
737
790
  ),
738
- createdAt: import_zod11.z.string().datetime()
791
+ createdAt: import_zod12.z.string().datetime()
739
792
  });
740
793
  var WebhookListItemSchema = WebhookSchema.omit({ secret: true }).extend({
741
- hint: import_zod11.z.string().describe("A truncated, safe-to-display form of the secret (e.g. `whsec_...ab12`).")
794
+ hint: import_zod12.z.string().describe("A truncated, safe-to-display form of the secret (e.g. `whsec_...ab12`).")
742
795
  });
743
- var WebhookPayloadSchema = import_zod11.z.object({
744
- id: import_zod11.z.string().describe(
796
+ var WebhookPayloadSchema = import_zod12.z.object({
797
+ id: import_zod12.z.string().describe(
745
798
  "Unique id for this specific delivery \u2014 also sent as the `X-Klappay-Delivery` header."
746
799
  ),
747
800
  event: WebhookEventTypeSchema,
748
- createdAt: import_zod11.z.string().datetime(),
749
- data: import_zod11.z.unknown().describe(
801
+ createdAt: import_zod12.z.string().datetime(),
802
+ data: import_zod12.z.unknown().describe(
750
803
  "Event-specific data. Charge events (`charge.*`) carry the full `Charge` object; webhook-delivery events carry a smaller, event-specific object \u2014 see `WebhookEventDataMap`/`TypedWebhookPayload` for the exact shape per event, or docs/webhooks.md."
751
804
  )
752
805
  });
753
- var WebhookDeliveryStatusSchema = import_zod11.z.enum(["pending", "delivered", "failed"]);
754
- var WebhookDeliverySchema = import_zod11.z.object({
755
- id: import_zod11.z.string(),
756
- webhookId: import_zod11.z.string(),
806
+ var WebhookDeliveryStatusSchema = import_zod12.z.enum(["pending", "delivered", "failed"]);
807
+ var WebhookDeliverySchema = import_zod12.z.object({
808
+ id: import_zod12.z.string(),
809
+ webhookId: import_zod12.z.string(),
757
810
  event: WebhookEventTypeSchema,
758
811
  status: WebhookDeliveryStatusSchema.describe(
759
812
  "`pending`: still retrying. `delivered`: got a 2xx response. `failed`: retries exhausted (5 attempts over ~24h) \u2014 use `POST /v1/webhooks/{id}/deliveries/{deliveryId}/retry` to try again manually."
760
813
  ),
761
- attempts: import_zod11.z.number(),
762
- responseCode: import_zod11.z.number().nullable().describe(
814
+ attempts: import_zod12.z.number(),
815
+ responseCode: import_zod12.z.number().nullable().describe(
763
816
  "HTTP status your endpoint returned on the most recent attempt. `null` if every attempt failed to connect at all."
764
817
  ),
765
- nextRetryAt: import_zod11.z.string().datetime().nullable(),
766
- deliveredAt: import_zod11.z.string().datetime().nullable(),
767
- createdAt: import_zod11.z.string().datetime()
818
+ nextRetryAt: import_zod12.z.string().datetime().nullable(),
819
+ deliveredAt: import_zod12.z.string().datetime().nullable(),
820
+ createdAt: import_zod12.z.string().datetime()
768
821
  });
769
822
  var ListWebhookDeliveriesSchema = PaginationQuerySchema;
770
823
  var PaginatedWebhookDeliveriesSchema = paginatedSchema(WebhookDeliverySchema);
771
824
 
772
825
  // src/timeline.ts
773
- var import_zod12 = require("zod");
774
- var TransactionSourceSchema = import_zod12.z.enum(["moralis_webhook", "reconciliation_job", "sandbox"]).describe(
826
+ var import_zod13 = require("zod");
827
+ var TransactionSourceSchema = import_zod13.z.enum(["moralis_webhook", "reconciliation_job", "sandbox"]).describe(
775
828
  "How this transfer was detected: `moralis_webhook` (the normal path), `reconciliation_job` (a fallback poller caught it after the webhook was missed or delayed), or `sandbox` (simulated via `POST /v1/sandbox/charges/{id}/trigger`, no real on-chain transfer)."
776
829
  );
777
- var TimelineEventTypeSchema = import_zod12.z.enum([
830
+ var TimelineEventTypeSchema = import_zod13.z.enum([
778
831
  "charge.created",
779
832
  "charge.expired",
780
833
  "transaction.detected",
@@ -785,11 +838,11 @@ var TimelineEventTypeSchema = import_zod12.z.enum([
785
838
  ]).describe(
786
839
  "`charge.created`: the charge was created. `charge.expired`: `expiresAt` passed with no full payment. `transaction.detected`: a raw on-chain transfer was seen (see the `event`-shaped fields below for details \u2014 a charge can have more than one, e.g. a partial payment followed by the rest). `split.distributed`: a payout to the merchant completed on-chain, for one contributing `(token, network)` pair \u2014 a charge settled across more than one pair emits one of these per pair (see the `token`/`network` fields below). `webhook.dispatched`/`webhook.delivered`/`webhook.failed`: one specific delivery *attempt* for one webhook subscription \u2014 `failed` here means this single attempt failed, not that all retries were exhausted (see `WebhookDeliveryStatusSchema` for the exhausted-all-retries state)."
787
840
  );
788
- var TimelineEventSchema = import_zod12.z.object({
841
+ var TimelineEventSchema = import_zod13.z.object({
789
842
  type: TimelineEventTypeSchema,
790
- at: import_zod12.z.string().datetime(),
791
- txHash: import_zod12.z.string().optional().describe("Present for `transaction.detected` and `split.distributed` events only."),
792
- amount: import_zod12.z.number().optional().describe(
843
+ at: import_zod13.z.string().datetime(),
844
+ txHash: import_zod13.z.string().optional().describe("Present for `transaction.detected` and `split.distributed` events only."),
845
+ amount: import_zod13.z.number().optional().describe(
793
846
  "Present for `transaction.detected` events only \u2014 the amount that specific transfer carried."
794
847
  ),
795
848
  source: TransactionSourceSchema.optional().describe(
@@ -801,49 +854,49 @@ var TimelineEventSchema = import_zod12.z.object({
801
854
  network: NetworkSchema.optional().describe(
802
855
  "Present for `transaction.detected` and `split.distributed` events \u2014 which network this specific transfer, or settlement, used."
803
856
  ),
804
- causedTransition: import_zod12.z.boolean().optional().describe(
857
+ causedTransition: import_zod13.z.boolean().optional().describe(
805
858
  "Present for `transaction.detected` events only. `true` if this specific transfer changed the charge's status (e.g. PENDING\u2192CONFIRMED) \u2014 a charge paid in installments can have more than one such event."
806
859
  ),
807
860
  event: WebhookEventTypeSchema.optional().describe(
808
861
  "Present for `webhook.*` events only \u2014 which event type this delivery was for."
809
862
  ),
810
- responseCode: import_zod12.z.number().nullable().optional().describe(
863
+ responseCode: import_zod13.z.number().nullable().optional().describe(
811
864
  "Present for `webhook.*` events only \u2014 HTTP status your endpoint returned, or `null` if the request never connected."
812
865
  ),
813
- attempts: import_zod12.z.number().optional().describe(
866
+ attempts: import_zod13.z.number().optional().describe(
814
867
  "Present for `webhook.*` events only \u2014 how many delivery attempts have been made so far."
815
868
  )
816
869
  });
817
870
 
818
871
  // src/health.ts
819
- var import_zod13 = require("zod");
820
- var HealthSchema = import_zod13.z.object({
821
- status: import_zod13.z.enum(["ok", "error"]).describe(
872
+ var import_zod14 = require("zod");
873
+ var HealthSchema = import_zod14.z.object({
874
+ status: import_zod14.z.enum(["ok", "error"]).describe(
822
875
  "`error` when the database connectivity check fails \u2014 the HTTP status code mirrors this (503 instead of 200), so a plain uptime check (not just a JSON-aware one) still catches a DB outage."
823
876
  ),
824
- version: import_zod13.z.string(),
825
- timestamp: import_zod13.z.string().datetime(),
826
- db: import_zod13.z.enum(["ok", "error"]).describe("Result of a real database connectivity check, not just a process-alive check."),
827
- pendingWebhooks: import_zod13.z.number().describe("Count of webhook deliveries still awaiting a successful attempt."),
828
- oldestPendingChargeAgeSeconds: import_zod13.z.number().nullable().describe("Age of the oldest still-unpaid charge, in seconds. `null` if there are none."),
829
- lastMoralisEventAgeSeconds: import_zod13.z.number().nullable().describe(
877
+ version: import_zod14.z.string(),
878
+ timestamp: import_zod14.z.string().datetime(),
879
+ db: import_zod14.z.enum(["ok", "error"]).describe("Result of a real database connectivity check, not just a process-alive check."),
880
+ pendingWebhooks: import_zod14.z.number().describe("Count of webhook deliveries still awaiting a successful attempt."),
881
+ oldestPendingChargeAgeSeconds: import_zod14.z.number().nullable().describe("Age of the oldest still-unpaid charge, in seconds. `null` if there are none."),
882
+ lastMoralisEventAgeSeconds: import_zod14.z.number().nullable().describe(
830
883
  "Seconds since the last on-chain payment notification was received \u2014 a cheap signal for whether payment detection is currently working. `null` if none have ever been received."
831
884
  )
832
885
  });
833
886
 
834
887
  // src/sandbox.ts
835
- var import_zod14 = require("zod");
836
- var SandboxTriggerSchema = import_zod14.z.object({
888
+ var import_zod15 = require("zod");
889
+ var SandboxTriggerSchema = import_zod15.z.object({
837
890
  event: TriggerableChargeEventSchema,
838
- amount: import_zod14.z.number().positive().max(CHARGE_AMOUNT_MAX).optional().describe(
891
+ amount: import_zod15.z.number().positive().max(CHARGE_AMOUNT_MAX).optional().describe(
839
892
  "Used with `charge.partially_paid` (amount to simulate as received so far \u2014 must be less than the charge amount, defaults to half of it if omitted) and with `charge.overpaid` (amount received \u2014 must be greater than the charge amount, defaults to 1.5x it if omitted). Ignored for every other event."
840
893
  )
841
894
  });
842
895
 
843
896
  // src/capabilities.ts
844
- var import_zod15 = require("zod");
845
- var CapabilitiesSchema = import_zod15.z.object({
846
- acceptedPayments: import_zod15.z.array(AcceptedPaymentSchema).describe(
897
+ var import_zod16 = require("zod");
898
+ var CapabilitiesSchema = import_zod16.z.object({
899
+ acceptedPayments: import_zod16.z.array(AcceptedPaymentSchema).describe(
847
900
  "Every `(token, network)` pair actually configured for your environment right now \u2014 read straight from the same lookup `POST /v1/charges` validates `acceptedPayments` against, so it can never list a pair that charge creation would then reject. Use this to build a picker UI instead of hardcoding the matrix client-side."
848
901
  )
849
902
  });
@@ -856,6 +909,7 @@ var CapabilitiesSchema = import_zod15.z.object({
856
909
  CHARGE_AMOUNT_MAX,
857
910
  CHARGE_EXPIRES_IN_MAX_SECONDS,
858
911
  CHARGE_EXPIRES_IN_MIN_SECONDS,
912
+ CHARGE_SPLIT_RECIPIENTS_MAX,
859
913
  CapabilitiesSchema,
860
914
  ChargeSchema,
861
915
  ChargeStatusSchema,
@@ -907,6 +961,7 @@ var CapabilitiesSchema = import_zod15.z.object({
907
961
  SandboxTriggerSchema,
908
962
  SettlementStatusSchema,
909
963
  SplitDistributionStatusSchema,
964
+ SplitRecipientSchema,
910
965
  TOKEN_ADDRESSES,
911
966
  TOKEN_DECIMALS,
912
967
  TimelineEventSchema,