@nokinc-flur/sdk 1.0.5 → 1.1.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/client.ts
2
- import { z as z3 } from "zod";
2
+ import { z as z4 } from "zod";
3
3
 
4
4
  // src/contracts.ts
5
5
  import { z } from "zod";
@@ -152,6 +152,13 @@ var AccountActivityItemSchema = z.object({
152
152
  timestamp: IsoDateSchema
153
153
  });
154
154
  var AccountSummaryResponseSchema = z.object({
155
+ /** Authenticated user's stable internal id. */
156
+ userId: UuidSchema,
157
+ /**
158
+ * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
159
+ * bank partner. `null` when the user has no partner-allocated account yet.
160
+ */
161
+ nuban: z.string().regex(/^[0-9]{10}$/).nullable(),
155
162
  balance: z.number().int(),
156
163
  currency: CurrencySchema,
157
164
  dailySendLimit: z.number().int().nonnegative(),
@@ -387,6 +394,341 @@ function moneyMinorToNumber(amountMinor) {
387
394
  return asNumber;
388
395
  }
389
396
 
397
+ // src/collections/client.ts
398
+ import { z as z3 } from "zod";
399
+ var MERCHANT_PROFILE_STATUSES = [
400
+ "pending",
401
+ "active",
402
+ "suspended",
403
+ "closed"
404
+ ];
405
+ var SETTLEMENT_SCHEDULES = ["manual", "daily", "t1"];
406
+ var COLLECTION_INTENT_STATUSES = [
407
+ "created",
408
+ "pending",
409
+ "paid",
410
+ "expired",
411
+ "cancelled",
412
+ "failed",
413
+ "reversed"
414
+ ];
415
+ var COLLECTION_PAYMENT_STATUSES = [
416
+ "pending",
417
+ "paid",
418
+ "failed",
419
+ "reversed"
420
+ ];
421
+ var MERCHANT_PAYOUT_STATUSES = [
422
+ "requested",
423
+ "processing",
424
+ "paid",
425
+ "failed",
426
+ "cancelled"
427
+ ];
428
+ var MoneyKoboSchema = z3.number().int().positive().max(Number.MAX_SAFE_INTEGER);
429
+ var MetadataSchema = z3.record(
430
+ z3.union([z3.string(), z3.number(), z3.boolean(), z3.null()])
431
+ );
432
+ var CurrencySchema2 = z3.string().trim().length(3).transform((value) => value.toUpperCase());
433
+ var ReferenceSchema = z3.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
434
+ var MerchantProfileSchema = z3.object({
435
+ accountId: z3.string().uuid(),
436
+ legalName: z3.string(),
437
+ tradingName: z3.string(),
438
+ merchantCategoryCode: z3.string().regex(/^\d{4}$/),
439
+ nqrMerchantId: z3.string(),
440
+ settlementBankCode: z3.string(),
441
+ settlementAccountNumber: z3.string(),
442
+ settlementAccountName: z3.string(),
443
+ settlementSchedule: z3.enum(SETTLEMENT_SCHEDULES),
444
+ status: z3.enum(MERCHANT_PROFILE_STATUSES),
445
+ offlineEnabled: z3.boolean(),
446
+ perTxLimitKobo: MoneyKoboSchema,
447
+ dailyLimitKobo: MoneyKoboSchema,
448
+ metadata: MetadataSchema,
449
+ createdAtMs: z3.number().int().nonnegative(),
450
+ updatedAtMs: z3.number().int().nonnegative()
451
+ });
452
+ var UpsertMerchantProfileInputSchema = z3.object({
453
+ legalName: z3.string().trim().min(1).max(200),
454
+ tradingName: z3.string().trim().min(1).max(25),
455
+ merchantCategoryCode: z3.string().trim().regex(/^\d{4}$/),
456
+ nqrMerchantId: z3.string().trim().min(3).max(64),
457
+ settlementBankCode: z3.string().trim().min(2).max(16),
458
+ settlementAccountNumber: z3.string().trim().min(5).max(32),
459
+ settlementAccountName: z3.string().trim().min(1).max(200),
460
+ settlementSchedule: z3.enum(SETTLEMENT_SCHEDULES).optional(),
461
+ status: z3.enum(MERCHANT_PROFILE_STATUSES).optional(),
462
+ offlineEnabled: z3.boolean().optional(),
463
+ perTxLimitKobo: MoneyKoboSchema.optional(),
464
+ dailyLimitKobo: MoneyKoboSchema.optional(),
465
+ metadata: MetadataSchema.optional()
466
+ });
467
+ var CollectionIntentSchema = z3.object({
468
+ intentId: z3.string().uuid(),
469
+ accountId: z3.string().uuid(),
470
+ terminalId: z3.string().uuid().nullable(),
471
+ reference: z3.string(),
472
+ amountKobo: z3.number().int().positive().nullable(),
473
+ currency: z3.string().length(3),
474
+ status: z3.enum(COLLECTION_INTENT_STATUSES),
475
+ description: z3.string().nullable(),
476
+ nqrPayload: z3.string(),
477
+ provider: z3.string(),
478
+ providerReference: z3.string().nullable(),
479
+ metadata: MetadataSchema,
480
+ expiresAtMs: z3.number().int().nonnegative().nullable(),
481
+ paidAtMs: z3.number().int().nonnegative().nullable(),
482
+ createdAtMs: z3.number().int().nonnegative(),
483
+ updatedAtMs: z3.number().int().nonnegative()
484
+ });
485
+ var CreateCollectionIntentInputSchema = z3.object({
486
+ reference: ReferenceSchema.optional(),
487
+ amountKobo: MoneyKoboSchema.optional(),
488
+ currency: CurrencySchema2.optional(),
489
+ terminalId: z3.string().uuid().optional(),
490
+ terminalLabel: z3.string().trim().min(1).max(25).optional(),
491
+ merchantCity: z3.string().trim().min(1).max(15).optional(),
492
+ description: z3.string().trim().min(1).max(280).optional(),
493
+ expiresAtMs: z3.number().int().positive().optional(),
494
+ provider: z3.string().trim().min(1).max(40).optional(),
495
+ metadata: MetadataSchema.optional()
496
+ });
497
+ var PublicCollectionIntentSchema = z3.object({
498
+ intentId: z3.string().uuid(),
499
+ reference: z3.string(),
500
+ amountKobo: z3.number().int().positive().nullable(),
501
+ currency: z3.string().length(3),
502
+ status: z3.enum(COLLECTION_INTENT_STATUSES),
503
+ merchantAccountId: z3.string().uuid(),
504
+ merchantName: z3.string(),
505
+ merchantCategoryCode: z3.string(),
506
+ description: z3.string().nullable(),
507
+ expiresAtMs: z3.number().int().nonnegative().nullable()
508
+ });
509
+ var PayCollectionInputSchema = z3.object({
510
+ reference: ReferenceSchema,
511
+ amountKobo: MoneyKoboSchema.optional(),
512
+ currency: CurrencySchema2.optional(),
513
+ idempotencyKey: z3.string().trim().min(8).max(160).optional()
514
+ });
515
+ var CollectionPaymentSchema = z3.object({
516
+ paymentId: z3.string().uuid(),
517
+ intentId: z3.string().uuid(),
518
+ accountId: z3.string().uuid(),
519
+ payerUserId: z3.string().uuid().nullable(),
520
+ merchantOwnerUserId: z3.string().uuid(),
521
+ amountKobo: MoneyKoboSchema,
522
+ currency: z3.string().length(3),
523
+ status: z3.enum(COLLECTION_PAYMENT_STATUSES),
524
+ provider: z3.string(),
525
+ providerReference: z3.string().nullable(),
526
+ idempotencyKey: z3.string().nullable(),
527
+ ledgerRef: z3.string(),
528
+ failureCode: z3.string().nullable(),
529
+ failureMessage: z3.string().nullable(),
530
+ paidAtMs: z3.number().int().nonnegative().nullable(),
531
+ createdAtMs: z3.number().int().nonnegative(),
532
+ updatedAtMs: z3.number().int().nonnegative()
533
+ });
534
+ var CollectionPaymentResultSchema = z3.object({
535
+ payment: CollectionPaymentSchema,
536
+ intent: CollectionIntentSchema,
537
+ receipt: z3.unknown().optional(),
538
+ replayed: z3.boolean()
539
+ });
540
+ var CollectionReportSummarySchema = z3.object({
541
+ accountId: z3.string().uuid(),
542
+ fromMs: z3.number().int().nonnegative(),
543
+ toMs: z3.number().int().nonnegative(),
544
+ currency: z3.string().length(3),
545
+ paidCount: z3.number().int().nonnegative(),
546
+ paidAmountKobo: z3.number().int().nonnegative(),
547
+ pendingCount: z3.number().int().nonnegative(),
548
+ failedCount: z3.number().int().nonnegative(),
549
+ reversedCount: z3.number().int().nonnegative(),
550
+ availableBalanceKobo: z3.number().int().nonnegative()
551
+ });
552
+ var CollectionStatementSchema = z3.object({
553
+ accountId: z3.string().uuid(),
554
+ year: z3.number().int(),
555
+ month: z3.number().int().min(1).max(12),
556
+ currency: z3.string().length(3),
557
+ totalPaidKobo: z3.number().int().nonnegative(),
558
+ items: z3.array(CollectionPaymentSchema)
559
+ });
560
+ var CreatePayoutInputSchema = z3.object({
561
+ amountKobo: MoneyKoboSchema,
562
+ currency: CurrencySchema2.optional(),
563
+ idempotencyKey: z3.string().trim().min(8).max(160)
564
+ });
565
+ var MerchantPayoutSchema = z3.object({
566
+ payoutId: z3.string().uuid(),
567
+ accountId: z3.string().uuid(),
568
+ amountKobo: MoneyKoboSchema,
569
+ currency: z3.string().length(3),
570
+ status: z3.enum(MERCHANT_PAYOUT_STATUSES),
571
+ idempotencyKey: z3.string().nullable(),
572
+ ledgerRef: z3.string(),
573
+ providerReference: z3.string().nullable(),
574
+ requestedByUserId: z3.string().uuid().nullable(),
575
+ failureCode: z3.string().nullable(),
576
+ failureMessage: z3.string().nullable(),
577
+ createdAtMs: z3.number().int().nonnegative(),
578
+ updatedAtMs: z3.number().int().nonnegative()
579
+ });
580
+ var ProviderEventInputSchema = z3.object({
581
+ provider: z3.string().trim().min(1).max(80),
582
+ eventId: z3.string().trim().min(1).max(160),
583
+ eventType: z3.string().trim().min(1).max(120),
584
+ payload: z3.record(z3.unknown()).optional()
585
+ });
586
+ var ProviderEventRecordSchema = z3.object({
587
+ id: z3.string().uuid(),
588
+ provider: z3.string(),
589
+ eventId: z3.string(),
590
+ eventType: z3.string(),
591
+ signatureVerified: z3.boolean(),
592
+ receivedAtMs: z3.number().int().nonnegative(),
593
+ processedAtMs: z3.number().int().nonnegative().nullable()
594
+ });
595
+ function createCollectionsClient(opts) {
596
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
597
+ if (!fetchImpl) {
598
+ throw new Error(
599
+ "createCollectionsClient: no fetch implementation available"
600
+ );
601
+ }
602
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
603
+ async function call(method, path, body, parser) {
604
+ const init2 = {
605
+ method,
606
+ headers: { accept: "application/json" }
607
+ };
608
+ if (body !== void 0) {
609
+ init2.body = JSON.stringify(body);
610
+ init2.headers = { ...init2.headers, "content-type": "application/json" };
611
+ }
612
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
613
+ const text = await resp.text();
614
+ let raw;
615
+ if (text) {
616
+ try {
617
+ raw = JSON.parse(text);
618
+ } catch {
619
+ raw = text;
620
+ }
621
+ }
622
+ if (!resp.ok) {
623
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
624
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
625
+ throw new FlurApiError(resp.status, code, message, raw);
626
+ }
627
+ return parser(raw);
628
+ }
629
+ return {
630
+ upsertMerchantProfile: (accountId, input) => call(
631
+ "PUT",
632
+ `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,
633
+ UpsertMerchantProfileInputSchema.parse(input),
634
+ (raw) => MerchantProfileSchema.parse(raw)
635
+ ),
636
+ getMerchantProfile: (accountId) => call(
637
+ "GET",
638
+ `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,
639
+ void 0,
640
+ (raw) => MerchantProfileSchema.parse(raw)
641
+ ),
642
+ createIntent: (input) => call(
643
+ "POST",
644
+ "/v1/collections/intents",
645
+ CreateCollectionIntentInputSchema.parse(input),
646
+ (raw) => CollectionIntentSchema.parse(raw)
647
+ ),
648
+ getIntent: (intentId) => call(
649
+ "GET",
650
+ `/v1/collections/intents/${encodeURIComponent(intentId)}`,
651
+ void 0,
652
+ (raw) => CollectionIntentSchema.parse(raw)
653
+ ),
654
+ resolveIntent: (reference) => call(
655
+ "GET",
656
+ `/v1/collections/resolve/${encodeURIComponent(reference)}`,
657
+ void 0,
658
+ (raw) => PublicCollectionIntentSchema.parse(raw)
659
+ ),
660
+ pay: (input) => call(
661
+ "POST",
662
+ "/v1/collections/pay",
663
+ PayCollectionInputSchema.parse(input),
664
+ (raw) => CollectionPaymentResultSchema.parse(raw)
665
+ ),
666
+ reportSummary: (input) => {
667
+ const qs = new URLSearchParams({
668
+ fromMs: String(input.fromMs),
669
+ toMs: String(input.toMs)
670
+ });
671
+ if (input.currency) qs.set("currency", input.currency);
672
+ return call(
673
+ "GET",
674
+ `/v1/collections/reports/summary?${qs.toString()}`,
675
+ void 0,
676
+ (raw) => CollectionReportSummarySchema.parse(raw)
677
+ );
678
+ },
679
+ monthlyStatement: (input) => {
680
+ const qs = new URLSearchParams({
681
+ year: String(input.year),
682
+ month: String(input.month)
683
+ });
684
+ if (input.currency) qs.set("currency", input.currency);
685
+ return call(
686
+ "GET",
687
+ `/v1/collections/statements/monthly?${qs.toString()}`,
688
+ void 0,
689
+ (raw) => CollectionStatementSchema.parse(raw)
690
+ );
691
+ },
692
+ createPayout: (input) => call(
693
+ "POST",
694
+ "/v1/collections/payouts",
695
+ CreatePayoutInputSchema.parse(input),
696
+ (raw) => MerchantPayoutSchema.parse(raw)
697
+ ),
698
+ getPayout: (payoutId) => call(
699
+ "GET",
700
+ `/v1/collections/payouts/${encodeURIComponent(payoutId)}`,
701
+ void 0,
702
+ (raw) => MerchantPayoutSchema.parse(raw)
703
+ ),
704
+ recordProviderEvent: (input) => call(
705
+ "POST",
706
+ "/v1/collections/provider-events",
707
+ ProviderEventInputSchema.parse(input),
708
+ (raw) => ProviderEventRecordSchema.parse(raw)
709
+ )
710
+ };
711
+ }
712
+ function createPartnerCollectionsClient(opts) {
713
+ const client = createCollectionsClient(opts);
714
+ return {
715
+ createIntent: client.createIntent,
716
+ getIntent: client.getIntent,
717
+ reportSummary: client.reportSummary,
718
+ monthlyStatement: client.monthlyStatement,
719
+ createPayout: client.createPayout,
720
+ getPayout: client.getPayout,
721
+ recordProviderEvent: client.recordProviderEvent
722
+ };
723
+ }
724
+ function createConsumerCollectionsClient(opts) {
725
+ const client = createCollectionsClient(opts);
726
+ return {
727
+ resolveIntent: client.resolveIntent,
728
+ pay: client.pay
729
+ };
730
+ }
731
+
390
732
  // src/client.ts
391
733
  var FlurClient = class {
392
734
  baseUrl;
@@ -635,6 +977,36 @@ var FlurClient = class {
635
977
  }
636
978
  );
637
979
  }
980
+ async resolveCollection(reference, options) {
981
+ return this.requestJson(
982
+ `/v1/collections/resolve/${encodeURIComponent(reference)}`,
983
+ {
984
+ method: "GET",
985
+ headers: {
986
+ authorization: `Bearer ${options.accessToken}`
987
+ }
988
+ },
989
+ void 0,
990
+ PublicCollectionIntentSchema
991
+ );
992
+ }
993
+ async payCollection(input, options) {
994
+ const idempotencyKey = input.idempotencyKey ?? options.idempotencyKey ?? getSecureRandomUuid();
995
+ return this.requestJson(
996
+ "/v1/collections/pay",
997
+ {
998
+ method: "POST",
999
+ headers: {
1000
+ "content-type": "application/json",
1001
+ authorization: `Bearer ${options.accessToken}`,
1002
+ "x-idempotency-key": idempotencyKey
1003
+ }
1004
+ },
1005
+ PayCollectionInputSchema,
1006
+ CollectionPaymentResultSchema,
1007
+ { ...input, idempotencyKey }
1008
+ );
1009
+ }
638
1010
  async accountSummary(options) {
639
1011
  return this.requestJson(
640
1012
  "/api/v1/account/summary",
@@ -733,7 +1105,7 @@ var FlurClient = class {
733
1105
  try {
734
1106
  body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
735
1107
  } catch (err) {
736
- if (err instanceof z3.ZodError) {
1108
+ if (err instanceof z4.ZodError) {
737
1109
  throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
738
1110
  details: err.flatten()
739
1111
  });
@@ -761,7 +1133,7 @@ var FlurClient = class {
761
1133
  try {
762
1134
  return responseSchema.parse(payload);
763
1135
  } catch (err) {
764
- if (err instanceof z3.ZodError) {
1136
+ if (err instanceof z4.ZodError) {
765
1137
  throw new FlurError(
766
1138
  "SDK contract validation failed",
767
1139
  "INVALID_REQUEST",
@@ -1219,24 +1591,24 @@ function verifyCanonical(value, signature, publicKey) {
1219
1591
  }
1220
1592
 
1221
1593
  // src/offline/oac.ts
1222
- import { z as z4 } from "zod";
1594
+ import { z as z5 } from "zod";
1223
1595
  var OAC_DEFAULT_PER_TX_KOBO = 5e5;
1224
1596
  var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
1225
1597
  var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
1226
- var HexString = (length) => z4.string().regex(
1598
+ var HexString = (length) => z5.string().regex(
1227
1599
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1228
1600
  `expected ${length}-byte hex string`
1229
1601
  );
1230
- var OACSchema = z4.object({
1231
- userId: z4.string().min(1),
1232
- deviceId: z4.string().min(1),
1602
+ var OACSchema = z5.object({
1603
+ userId: z5.string().min(1),
1604
+ deviceId: z5.string().min(1),
1233
1605
  devicePublicKey: HexString(32),
1234
- perTxCapKobo: z4.number().int().nonnegative(),
1235
- cumulativeCapKobo: z4.number().int().nonnegative(),
1236
- validFromMs: z4.number().int().nonnegative(),
1237
- validUntilMs: z4.number().int().positive(),
1238
- counterSeed: z4.number().int().nonnegative(),
1239
- nonce: z4.string().min(1),
1606
+ perTxCapKobo: z5.number().int().nonnegative(),
1607
+ cumulativeCapKobo: z5.number().int().nonnegative(),
1608
+ validFromMs: z5.number().int().nonnegative(),
1609
+ validUntilMs: z5.number().int().positive(),
1610
+ counterSeed: z5.number().int().nonnegative(),
1611
+ nonce: z5.string().min(1),
1240
1612
  issuerSig: HexString(64)
1241
1613
  }).refine((v) => v.validUntilMs > v.validFromMs, {
1242
1614
  message: "validUntilMs must be greater than validFromMs"
@@ -1343,19 +1715,19 @@ function decodeBase45(s) {
1343
1715
  }
1344
1716
 
1345
1717
  // src/offline/messages.ts
1346
- import { z as z5 } from "zod";
1347
- var HexSig = z5.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1348
- var OfflinePaymentRequestSchema = z5.object({
1349
- reference: z5.string().min(1),
1350
- amountKobo: z5.number().int().positive(),
1718
+ import { z as z6 } from "zod";
1719
+ var HexSig = z6.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1720
+ var OfflinePaymentRequestSchema = z6.object({
1721
+ reference: z6.string().min(1),
1722
+ amountKobo: z6.number().int().positive(),
1351
1723
  merchantOAC: OACSchema,
1352
- expiresAtMs: z5.number().int().positive(),
1724
+ expiresAtMs: z6.number().int().positive(),
1353
1725
  merchantSig: HexSig
1354
1726
  });
1355
- var OfflinePaymentAuthorizationSchema = z5.object({
1727
+ var OfflinePaymentAuthorizationSchema = z6.object({
1356
1728
  request: OfflinePaymentRequestSchema,
1357
1729
  payerOAC: OACSchema,
1358
- payerCounter: z5.number().int().positive(),
1730
+ payerCounter: z6.number().int().positive(),
1359
1731
  payerSig: HexSig
1360
1732
  });
1361
1733
  function buildPaymentRequest(input) {
@@ -1464,56 +1836,56 @@ function decodeAuthorizationQR(s) {
1464
1836
  }
1465
1837
 
1466
1838
  // src/offline/settlements.ts
1467
- import { z as z6 } from "zod";
1839
+ import { z as z7 } from "zod";
1468
1840
  import { sha256 } from "@noble/hashes/sha256";
1469
1841
  import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
1470
- var OfflineTokenSchema = z6.object({
1471
- tokenId: z6.string().uuid(),
1472
- tokenSerial: z6.string(),
1473
- issuerAccountId: z6.string().uuid(),
1474
- payerUserId: z6.string().uuid(),
1475
- maxAmountKobo: z6.number().int().positive(),
1476
- currency: z6.string().length(3),
1477
- issuedAtMs: z6.number().int().nonnegative(),
1478
- expiresAtMs: z6.number().int().nonnegative(),
1479
- issuerSig: z6.string()
1480
- });
1481
- var PaymentClaimSchema = z6.object({
1482
- encounterId: z6.string().regex(/^[0-9a-f]{64}$/i).optional(),
1483
- tokenSerial: z6.string(),
1484
- payerUserId: z6.string().uuid(),
1485
- payeeUserId: z6.string().uuid(),
1486
- payerNonce: z6.string(),
1487
- payeeNonce: z6.string(),
1488
- amountKobo: z6.number().int().positive(),
1489
- currency: z6.string().length(3).default("NGN"),
1490
- occurredAtMs: z6.number().int().nonnegative(),
1491
- completedAtMs: z6.number().int().nonnegative().optional(),
1492
- contextId: z6.string().optional(),
1493
- payerPubkey: z6.string().regex(/^[0-9a-f]{64}$/i),
1494
- payerSignature: z6.string().regex(/^[0-9a-f]+$/i),
1495
- payeePubkey: z6.string().regex(/^[0-9a-f]{64}$/i).optional(),
1496
- payeeSignature: z6.string().regex(/^[0-9a-f]+$/i).optional()
1497
- });
1498
- var SettlementSchema = z6.object({
1499
- settlementId: z6.string().uuid(),
1500
- settlementKey: z6.string().regex(/^[0-9a-f]{64}$/i),
1501
- encounterId: z6.string().regex(/^[0-9a-f]{64}$/i),
1502
- issuerAccountId: z6.string().uuid(),
1503
- tokenSerial: z6.string(),
1504
- payerUserId: z6.string().uuid(),
1505
- payeeUserId: z6.string().uuid(),
1506
- amountKobo: z6.number().int().nonnegative(),
1507
- currency: z6.string().length(3),
1508
- receiptId: z6.string().nullable(),
1509
- status: z6.enum(["SETTLED", "REVIEW", "REJECTED"]),
1510
- issuerSig: z6.string(),
1511
- createdAtMs: z6.number().int().nonnegative()
1512
- });
1513
- var SettleResponseSchema = z6.object({
1842
+ var OfflineTokenSchema = z7.object({
1843
+ tokenId: z7.string().uuid(),
1844
+ tokenSerial: z7.string(),
1845
+ issuerAccountId: z7.string().uuid(),
1846
+ payerUserId: z7.string().uuid(),
1847
+ maxAmountKobo: z7.number().int().positive(),
1848
+ currency: z7.string().length(3),
1849
+ issuedAtMs: z7.number().int().nonnegative(),
1850
+ expiresAtMs: z7.number().int().nonnegative(),
1851
+ issuerSig: z7.string()
1852
+ });
1853
+ var PaymentClaimSchema = z7.object({
1854
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i).optional(),
1855
+ tokenSerial: z7.string(),
1856
+ payerUserId: z7.string().uuid(),
1857
+ payeeUserId: z7.string().uuid(),
1858
+ payerNonce: z7.string(),
1859
+ payeeNonce: z7.string(),
1860
+ amountKobo: z7.number().int().positive(),
1861
+ currency: z7.string().length(3).default("NGN"),
1862
+ occurredAtMs: z7.number().int().nonnegative(),
1863
+ completedAtMs: z7.number().int().nonnegative().optional(),
1864
+ contextId: z7.string().optional(),
1865
+ payerPubkey: z7.string().regex(/^[0-9a-f]{64}$/i),
1866
+ payerSignature: z7.string().regex(/^[0-9a-f]+$/i),
1867
+ payeePubkey: z7.string().regex(/^[0-9a-f]{64}$/i).optional(),
1868
+ payeeSignature: z7.string().regex(/^[0-9a-f]+$/i).optional()
1869
+ });
1870
+ var SettlementSchema = z7.object({
1871
+ settlementId: z7.string().uuid(),
1872
+ settlementKey: z7.string().regex(/^[0-9a-f]{64}$/i),
1873
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i),
1874
+ issuerAccountId: z7.string().uuid(),
1875
+ tokenSerial: z7.string(),
1876
+ payerUserId: z7.string().uuid(),
1877
+ payeeUserId: z7.string().uuid(),
1878
+ amountKobo: z7.number().int().nonnegative(),
1879
+ currency: z7.string().length(3),
1880
+ receiptId: z7.string().nullable(),
1881
+ status: z7.enum(["SETTLED", "REVIEW", "REJECTED"]),
1882
+ issuerSig: z7.string(),
1883
+ createdAtMs: z7.number().int().nonnegative()
1884
+ });
1885
+ var SettleResponseSchema = z7.object({
1514
1886
  settlement: SettlementSchema,
1515
- encounterId: z6.string().regex(/^[0-9a-f]{64}$/i),
1516
- replayed: z6.boolean()
1887
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i),
1888
+ replayed: z7.boolean()
1517
1889
  });
1518
1890
  var ENCOUNTER_DOMAIN = "offline:v1:encounter";
1519
1891
  async function sha256Hex(input) {
@@ -1686,133 +2058,351 @@ function createHmacFetch(opts) {
1686
2058
  });
1687
2059
  }
1688
2060
 
1689
- // src/passes/pass.ts
1690
- import { z as z7 } from "zod";
1691
- var PASS_KINDS = [
1692
- "ride-ticket",
1693
- "transit-pass",
1694
- "event-ticket",
1695
- "voucher",
1696
- "loyalty",
1697
- "receipt-link"
1698
- ];
1699
- var PASS_STATES = [
1700
- "issued",
1701
- "active",
1702
- "redeemed",
1703
- "expired",
1704
- "revoked"
2061
+ // src/partner/client.ts
2062
+ import { z as z8 } from "zod";
2063
+ import { sha256 as sha2563 } from "@noble/hashes/sha256";
2064
+ import { hmac as hmac2 } from "@noble/hashes/hmac";
2065
+ import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils";
2066
+ var PARTNER_SCOPES = [
2067
+ "passes:write",
2068
+ "passes:read",
2069
+ "passes:redeem",
2070
+ "receipts:write",
2071
+ "receipts:read",
2072
+ "offline:issue",
2073
+ "offline:settle",
2074
+ "offline:read",
2075
+ "collections:write",
2076
+ "collections:read",
2077
+ "collections:pay",
2078
+ "collections:webhook",
2079
+ "reports:read",
2080
+ "payouts:write",
2081
+ "payouts:read",
2082
+ "partner:funding:write",
2083
+ "partner:payout:write",
2084
+ "partner:reconciliation:read"
1705
2085
  ];
1706
- var HexString2 = (length) => z7.string().regex(
1707
- new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1708
- `expected ${length}-byte hex string`
1709
- );
1710
- var PassMetadataSchema = z7.record(
1711
- z7.union([z7.string(), z7.number(), z7.boolean(), z7.null()])
1712
- );
1713
- var PassSchema = z7.object({
1714
- passId: z7.string().min(1),
1715
- /** Optional client/template grouping id (server may omit). */
1716
- templateId: z7.string().min(1).optional(),
1717
- /** Optional human-facing holder identity (server may omit). The cryptographic binding
1718
- * is `holderDevicePubkey` below. */
1719
- holderUserId: z7.string().min(1).optional(),
1720
- kind: z7.enum(PASS_KINDS),
1721
- issuerId: z7.string().min(1),
1722
- issuedAtMs: z7.number().int().nonnegative(),
1723
- validFromMs: z7.number().int().nonnegative(),
1724
- validUntilMs: z7.number().int().positive(),
1725
- state: z7.enum(PASS_STATES),
1726
- metadata: PassMetadataSchema,
1727
- nonce: z7.string().min(1),
1728
- /** Device id this pass is bound to (FK to backend `device_keys`). */
1729
- holderDeviceId: z7.string().min(1),
1730
- /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
1731
- * is verified against this key — it is the security-critical binding. */
1732
- holderDevicePubkey: HexString2(32),
1733
- /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
1734
- amountKobo: z7.number().int().nonnegative().optional(),
1735
- /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
1736
- currency: z7.string().min(3).max(8),
1737
- /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
1738
- counterSeed: z7.number().int().nonnegative(),
1739
- /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
1740
- cumulativeCapKobo: z7.number().int().nonnegative().optional(),
1741
- issuerSig: HexString2(64)
1742
- }).refine((v) => v.validUntilMs > v.validFromMs, {
1743
- message: "validUntilMs must be greater than validFromMs"
2086
+ var ApiCredentialPublicSchema = z8.object({
2087
+ id: z8.string().uuid(),
2088
+ accountId: z8.string().uuid(),
2089
+ keyId: z8.string(),
2090
+ scopes: z8.array(z8.enum(PARTNER_SCOPES)),
2091
+ label: z8.string().nullable(),
2092
+ createdAtMs: z8.number().int().nonnegative(),
2093
+ lastUsedAtMs: z8.number().int().nonnegative().nullable(),
2094
+ revokedAtMs: z8.number().int().nonnegative().nullable()
1744
2095
  });
1745
- function buildPass(input) {
1746
- if (input.validUntilMs <= input.validFromMs) {
1747
- throw new Error("validUntilMs must be greater than validFromMs");
1748
- }
1749
- const out = {
1750
- passId: input.passId,
1751
- kind: input.kind,
1752
- issuerId: input.issuerId,
1753
- issuedAtMs: input.issuedAtMs,
1754
- validFromMs: input.validFromMs,
1755
- validUntilMs: input.validUntilMs,
1756
- state: input.state,
1757
- metadata: input.metadata,
1758
- nonce: input.nonce,
1759
- holderDeviceId: input.holderDeviceId,
1760
- holderDevicePubkey: input.holderDevicePubkey,
1761
- currency: input.currency ?? "NGN",
1762
- counterSeed: input.counterSeed
1763
- };
1764
- if (typeof input.templateId === "string") out.templateId = input.templateId;
1765
- if (typeof input.holderUserId === "string")
1766
- out.holderUserId = input.holderUserId;
1767
- if (typeof input.amountKobo === "number") out.amountKobo = input.amountKobo;
1768
- if (typeof input.cumulativeCapKobo === "number") {
1769
- out.cumulativeCapKobo = input.cumulativeCapKobo;
1770
- }
1771
- return out;
2096
+ var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2097
+ secret: z8.string().min(1)
2098
+ });
2099
+ var enc = new TextEncoder();
2100
+ async function sha256Hex2(input) {
2101
+ const data = typeof input === "string" ? enc.encode(input) : input;
2102
+ return bytesToHex4(sha2563(data));
1772
2103
  }
1773
- function signPass(unsigned, issuerPrivateKey) {
1774
- const issuerSig = bytesToHex(
1775
- sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
1776
- );
1777
- return { ...unsigned, issuerSig };
2104
+ async function hmacSha256Hex(keyHex, message) {
2105
+ return bytesToHex4(hmac2(sha2563, enc.encode(keyHex), enc.encode(message)));
1778
2106
  }
1779
- function verifyPass(pass, issuerPublicKey) {
1780
- try {
1781
- const parsed = PassSchema.parse(pass);
1782
- const { issuerSig, ...unsigned } = parsed;
1783
- return verify(
1784
- canonicalJSONBytes(unsigned),
1785
- hexToBytes(issuerSig),
1786
- issuerPublicKey
1787
- );
1788
- } catch {
1789
- return false;
1790
- }
2107
+ function defaultNonce2() {
2108
+ const c = globalThis.crypto;
2109
+ if (c?.randomUUID) return c.randomUUID();
2110
+ return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
1791
2111
  }
1792
- function isPassWithinValidity(pass, nowMs) {
1793
- return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;
2112
+ function canonical(params) {
2113
+ return [
2114
+ params.method.toUpperCase(),
2115
+ params.path,
2116
+ params.ts,
2117
+ params.nonce,
2118
+ params.bodyHash
2119
+ ].join("\n");
1794
2120
  }
1795
-
1796
- // src/passes/redemption.ts
1797
- import { z as z8 } from "zod";
1798
- var HexSig2 = z8.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1799
- var RedemptionSchema = z8.object({
1800
- pass: PassSchema,
1801
- redeemerId: z8.string().min(1),
1802
- redeemedAtMs: z8.number().int().nonnegative(),
1803
- /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
1804
- * and > the redeemer's lastSeenCounter for this pass. */
1805
- counter: z8.number().int().positive(),
1806
- /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
1807
- amountKobo: z8.number().int().nonnegative(),
1808
- nonce: z8.string().min(1),
1809
- holderSig: HexSig2
1810
- });
1811
- var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
1812
- function buildRedemption(input) {
1813
- if (!REDEEMABLE_STATES.has(input.pass.state)) {
1814
- throw new Error(`pass not in redeemable state: ${input.pass.state}`);
1815
- }
2121
+ async function signPartnerRequest(params) {
2122
+ const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
2123
+ const nonce = params.nonce ?? defaultNonce2();
2124
+ const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
2125
+ const bodyHash = await sha256Hex2(bodyData);
2126
+ const message = canonical({
2127
+ method: params.method,
2128
+ path: params.path,
2129
+ ts,
2130
+ nonce,
2131
+ bodyHash
2132
+ });
2133
+ const signingKey = await sha256Hex2(params.secret);
2134
+ const sig = await hmacSha256Hex(signingKey, message);
2135
+ return {
2136
+ authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
2137
+ ts,
2138
+ nonce,
2139
+ bodyHash
2140
+ };
2141
+ }
2142
+ function createFlurPartnerClient(opts) {
2143
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2144
+ if (!fetchImpl) {
2145
+ throw new Error(
2146
+ "createFlurPartnerClient: no fetch implementation available"
2147
+ );
2148
+ }
2149
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2150
+ const scopeHeader = normalizeScopeHeader(opts.scope);
2151
+ async function makeSignedInit(method, path, body) {
2152
+ const sig = await signPartnerRequest({
2153
+ keyId: opts.keyId,
2154
+ secret: opts.secret,
2155
+ method,
2156
+ path,
2157
+ body: body ?? "",
2158
+ nowMs: opts.nowMs?.(),
2159
+ nonce: opts.nonce?.()
2160
+ });
2161
+ const headers = {
2162
+ authorization: sig.authorization,
2163
+ accept: "application/json"
2164
+ };
2165
+ if (scopeHeader) headers["x-flur-scope"] = scopeHeader;
2166
+ if (body !== void 0) headers["content-type"] = "application/json";
2167
+ const init2 = { method, headers };
2168
+ if (body !== void 0) init2.body = body;
2169
+ return init2;
2170
+ }
2171
+ async function request(opts2) {
2172
+ const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
2173
+ const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
2174
+ const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
2175
+ const text = await resp.text();
2176
+ let raw;
2177
+ if (text) {
2178
+ try {
2179
+ raw = JSON.parse(text);
2180
+ } catch {
2181
+ }
2182
+ }
2183
+ if (!resp.ok) {
2184
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2185
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2186
+ throw new FlurApiError(resp.status, code, message, raw);
2187
+ }
2188
+ return raw;
2189
+ }
2190
+ const fetchLike = async (input, init2) => {
2191
+ const url = typeof input === "string" ? input : input.toString();
2192
+ const u = new URL(url, baseUrl);
2193
+ const path = `${u.pathname}${u.search}`;
2194
+ const method = (init2?.method ?? "GET").toUpperCase();
2195
+ let bodyStr;
2196
+ if (init2?.body) {
2197
+ bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
2198
+ }
2199
+ const signed = await makeSignedInit(method, path, bodyStr);
2200
+ return fetchImpl(`${baseUrl}${path}`, {
2201
+ ...init2,
2202
+ ...signed,
2203
+ headers: {
2204
+ ...init2?.headers,
2205
+ ...signed.headers
2206
+ }
2207
+ });
2208
+ };
2209
+ return { request, fetch: fetchLike };
2210
+ }
2211
+ function normalizeScopeHeader(scope) {
2212
+ if (!scope || scope.length === 0) return void 0;
2213
+ const unique = Array.from(new Set(scope));
2214
+ for (const item of unique) {
2215
+ if (!PARTNER_SCOPES.includes(item)) {
2216
+ throw new Error(`unsupported partner scope: ${item}`);
2217
+ }
2218
+ }
2219
+ return unique.join(" ");
2220
+ }
2221
+ function createApiCredentialsAdminClient(opts) {
2222
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2223
+ if (!fetchImpl) {
2224
+ throw new Error(
2225
+ "createApiCredentialsAdminClient: no fetch implementation available"
2226
+ );
2227
+ }
2228
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2229
+ async function call(method, path, body, parser) {
2230
+ const init2 = {
2231
+ method,
2232
+ headers: {
2233
+ "content-type": "application/json",
2234
+ accept: "application/json"
2235
+ }
2236
+ };
2237
+ if (body !== void 0) init2.body = JSON.stringify(body);
2238
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2239
+ const text = await resp.text();
2240
+ let raw;
2241
+ if (text) {
2242
+ try {
2243
+ raw = JSON.parse(text);
2244
+ } catch {
2245
+ }
2246
+ }
2247
+ if (!resp.ok) {
2248
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2249
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2250
+ throw new FlurApiError(resp.status, code, message, raw);
2251
+ }
2252
+ return parser(raw);
2253
+ }
2254
+ const listSchema = z8.object({
2255
+ items: z8.array(ApiCredentialPublicSchema)
2256
+ });
2257
+ return {
2258
+ list: (accountId) => call(
2259
+ "GET",
2260
+ `/v1/accounts/${accountId}/api-credentials`,
2261
+ void 0,
2262
+ (raw) => listSchema.parse(raw)
2263
+ ),
2264
+ mint: (accountId, input) => call(
2265
+ "POST",
2266
+ `/v1/accounts/${accountId}/api-credentials`,
2267
+ input,
2268
+ (raw) => MintedApiCredentialSchema.parse(raw)
2269
+ ),
2270
+ revoke: (accountId, credentialId) => call(
2271
+ "DELETE",
2272
+ `/v1/accounts/${accountId}/api-credentials/${credentialId}`,
2273
+ void 0,
2274
+ (raw) => ApiCredentialPublicSchema.parse(raw)
2275
+ )
2276
+ };
2277
+ }
2278
+
2279
+ // src/passes/pass.ts
2280
+ import { z as z9 } from "zod";
2281
+ var PASS_KINDS = [
2282
+ "ride-ticket",
2283
+ "transit-pass",
2284
+ "event-ticket",
2285
+ "voucher",
2286
+ "loyalty",
2287
+ "receipt-link"
2288
+ ];
2289
+ var PASS_STATES = [
2290
+ "issued",
2291
+ "active",
2292
+ "redeemed",
2293
+ "expired",
2294
+ "revoked"
2295
+ ];
2296
+ var HexString2 = (length) => z9.string().regex(
2297
+ new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
2298
+ `expected ${length}-byte hex string`
2299
+ );
2300
+ var PassMetadataSchema = z9.record(
2301
+ z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
2302
+ );
2303
+ var PassSchema = z9.object({
2304
+ passId: z9.string().min(1),
2305
+ /** Optional client/template grouping id (server may omit). */
2306
+ templateId: z9.string().min(1).optional(),
2307
+ /** Optional human-facing holder identity (server may omit). The cryptographic binding
2308
+ * is `holderDevicePubkey` below. */
2309
+ holderUserId: z9.string().min(1).optional(),
2310
+ kind: z9.enum(PASS_KINDS),
2311
+ issuerId: z9.string().min(1),
2312
+ issuedAtMs: z9.number().int().nonnegative(),
2313
+ validFromMs: z9.number().int().nonnegative(),
2314
+ validUntilMs: z9.number().int().positive(),
2315
+ state: z9.enum(PASS_STATES),
2316
+ metadata: PassMetadataSchema,
2317
+ nonce: z9.string().min(1),
2318
+ /** Device id this pass is bound to (FK to backend `device_keys`). */
2319
+ holderDeviceId: z9.string().min(1),
2320
+ /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
2321
+ * is verified against this key — it is the security-critical binding. */
2322
+ holderDevicePubkey: HexString2(32),
2323
+ /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
2324
+ amountKobo: z9.number().int().nonnegative().optional(),
2325
+ /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
2326
+ currency: z9.string().min(3).max(8),
2327
+ /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
2328
+ counterSeed: z9.number().int().nonnegative(),
2329
+ /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
2330
+ cumulativeCapKobo: z9.number().int().nonnegative().optional(),
2331
+ issuerSig: HexString2(64)
2332
+ }).refine((v) => v.validUntilMs > v.validFromMs, {
2333
+ message: "validUntilMs must be greater than validFromMs"
2334
+ });
2335
+ function buildPass(input) {
2336
+ if (input.validUntilMs <= input.validFromMs) {
2337
+ throw new Error("validUntilMs must be greater than validFromMs");
2338
+ }
2339
+ const out = {
2340
+ passId: input.passId,
2341
+ kind: input.kind,
2342
+ issuerId: input.issuerId,
2343
+ issuedAtMs: input.issuedAtMs,
2344
+ validFromMs: input.validFromMs,
2345
+ validUntilMs: input.validUntilMs,
2346
+ state: input.state,
2347
+ metadata: input.metadata,
2348
+ nonce: input.nonce,
2349
+ holderDeviceId: input.holderDeviceId,
2350
+ holderDevicePubkey: input.holderDevicePubkey,
2351
+ currency: input.currency ?? "NGN",
2352
+ counterSeed: input.counterSeed
2353
+ };
2354
+ if (typeof input.templateId === "string") out.templateId = input.templateId;
2355
+ if (typeof input.holderUserId === "string")
2356
+ out.holderUserId = input.holderUserId;
2357
+ if (typeof input.amountKobo === "number") out.amountKobo = input.amountKobo;
2358
+ if (typeof input.cumulativeCapKobo === "number") {
2359
+ out.cumulativeCapKobo = input.cumulativeCapKobo;
2360
+ }
2361
+ return out;
2362
+ }
2363
+ function signPass(unsigned, issuerPrivateKey) {
2364
+ const issuerSig = bytesToHex(
2365
+ sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
2366
+ );
2367
+ return { ...unsigned, issuerSig };
2368
+ }
2369
+ function verifyPass(pass, issuerPublicKey) {
2370
+ try {
2371
+ const parsed = PassSchema.parse(pass);
2372
+ const { issuerSig, ...unsigned } = parsed;
2373
+ return verify(
2374
+ canonicalJSONBytes(unsigned),
2375
+ hexToBytes(issuerSig),
2376
+ issuerPublicKey
2377
+ );
2378
+ } catch {
2379
+ return false;
2380
+ }
2381
+ }
2382
+ function isPassWithinValidity(pass, nowMs) {
2383
+ return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;
2384
+ }
2385
+
2386
+ // src/passes/redemption.ts
2387
+ import { z as z10 } from "zod";
2388
+ var HexSig2 = z10.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
2389
+ var RedemptionSchema = z10.object({
2390
+ pass: PassSchema,
2391
+ redeemerId: z10.string().min(1),
2392
+ redeemedAtMs: z10.number().int().nonnegative(),
2393
+ /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
2394
+ * and > the redeemer's lastSeenCounter for this pass. */
2395
+ counter: z10.number().int().positive(),
2396
+ /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
2397
+ amountKobo: z10.number().int().nonnegative(),
2398
+ nonce: z10.string().min(1),
2399
+ holderSig: HexSig2
2400
+ });
2401
+ var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
2402
+ function buildRedemption(input) {
2403
+ if (!REDEEMABLE_STATES.has(input.pass.state)) {
2404
+ throw new Error(`pass not in redeemable state: ${input.pass.state}`);
2405
+ }
1816
2406
  if (input.redeemedAtMs < input.pass.validFromMs) {
1817
2407
  throw new Error("redeemedAtMs is before pass validFromMs");
1818
2408
  }
@@ -1891,43 +2481,43 @@ function verifyRedemption(r, issuerPublicKey) {
1891
2481
  }
1892
2482
 
1893
2483
  // src/receipts/receipt.ts
1894
- import { z as z9 } from "zod";
2484
+ import { z as z11 } from "zod";
1895
2485
  var RECEIPT_CHANNELS = ["cash", "pass"];
1896
2486
  var RECEIPT_KINDS = RECEIPT_CHANNELS;
1897
- var HexString3 = (length) => z9.string().regex(
2487
+ var HexString3 = (length) => z11.string().regex(
1898
2488
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1899
2489
  `expected ${length}-byte hex string`
1900
2490
  );
1901
- var ReceiptPayloadSchema = z9.record(
1902
- z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
2491
+ var ReceiptPayloadSchema = z11.record(
2492
+ z11.union([z11.string(), z11.number(), z11.boolean(), z11.null()])
1903
2493
  );
1904
- var ReceiptSchema = z9.object({
1905
- receiptId: z9.string().min(1),
1906
- channel: z9.enum(RECEIPT_CHANNELS),
2494
+ var ReceiptSchema = z11.object({
2495
+ receiptId: z11.string().min(1),
2496
+ channel: z11.enum(RECEIPT_CHANNELS),
1907
2497
  /** Cash-channel: send_intents.id. Required when channel === 'cash'. */
1908
- intentId: z9.string().min(1).optional(),
2498
+ intentId: z11.string().min(1).optional(),
1909
2499
  /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
1910
- passRedemptionId: z9.string().min(1).optional(),
1911
- payerUserId: z9.string().min(1),
1912
- payeeUserId: z9.string().min(1),
1913
- amountKobo: z9.number().int().nonnegative(),
1914
- currency: z9.string().min(3).max(8),
1915
- issuedAtMs: z9.number().int().nonnegative(),
1916
- issuerId: z9.string().min(1),
2500
+ passRedemptionId: z11.string().min(1).optional(),
2501
+ payerUserId: z11.string().min(1),
2502
+ payeeUserId: z11.string().min(1),
2503
+ amountKobo: z11.number().int().nonnegative(),
2504
+ currency: z11.string().min(3).max(8),
2505
+ issuedAtMs: z11.number().int().nonnegative(),
2506
+ issuerId: z11.string().min(1),
1917
2507
  payload: ReceiptPayloadSchema,
1918
2508
  issuerSig: HexString3(64)
1919
2509
  }).superRefine((v, ctx) => {
1920
2510
  if (v.channel === "cash") {
1921
2511
  if (!v.intentId) {
1922
2512
  ctx.addIssue({
1923
- code: z9.ZodIssueCode.custom,
2513
+ code: z11.ZodIssueCode.custom,
1924
2514
  message: "cash receipts require intentId",
1925
2515
  path: ["intentId"]
1926
2516
  });
1927
2517
  }
1928
2518
  if (v.passRedemptionId) {
1929
2519
  ctx.addIssue({
1930
- code: z9.ZodIssueCode.custom,
2520
+ code: z11.ZodIssueCode.custom,
1931
2521
  message: "cash receipts must not carry passRedemptionId",
1932
2522
  path: ["passRedemptionId"]
1933
2523
  });
@@ -1935,14 +2525,14 @@ var ReceiptSchema = z9.object({
1935
2525
  } else if (v.channel === "pass") {
1936
2526
  if (!v.passRedemptionId) {
1937
2527
  ctx.addIssue({
1938
- code: z9.ZodIssueCode.custom,
2528
+ code: z11.ZodIssueCode.custom,
1939
2529
  message: "pass receipts require passRedemptionId",
1940
2530
  path: ["passRedemptionId"]
1941
2531
  });
1942
2532
  }
1943
2533
  if (v.intentId) {
1944
2534
  ctx.addIssue({
1945
- code: z9.ZodIssueCode.custom,
2535
+ code: z11.ZodIssueCode.custom,
1946
2536
  message: "pass receipts must not carry intentId",
1947
2537
  path: ["intentId"]
1948
2538
  });
@@ -2181,317 +2771,90 @@ function createReceiptsClient(opts) {
2181
2771
  verifyReceipt: (receipt, issuerPublicKey) => verifyReceipt(receipt, issuerPublicKey)
2182
2772
  };
2183
2773
  }
2184
-
2185
- // src/client/flur.ts
2186
- function generateStaticQR(input) {
2187
- return encodeNQR({ ...input, pointOfInitiation: "static" });
2188
- }
2189
- function generateDynamicQR(input) {
2190
- return encodeNQR({ ...input, pointOfInitiation: "dynamic" });
2191
- }
2192
- function parseQR(payload) {
2193
- return parseNQR(payload);
2194
- }
2195
- function init(opts) {
2196
- const signedFetch = createHmacFetch({
2197
- apiKey: opts.apiKey,
2198
- apiSecret: opts.apiSecret,
2199
- fetchImpl: opts.fetchImpl,
2200
- scope: opts.scope
2201
- });
2202
- const baseUrl = opts.baseUrl.replace(/\/$/, "");
2203
- function subscribeToPayments(s) {
2204
- const controller = new AbortController();
2205
- let cancelled = false;
2206
- (async () => {
2207
- try {
2208
- const url = `${baseUrl}/v1/payments/subscribe?reference=${encodeURIComponent(s.reference)}`;
2209
- const resp = await signedFetch(url, {
2210
- method: "GET",
2211
- headers: { accept: "text/event-stream" },
2212
- signal: controller.signal
2213
- });
2214
- if (!resp.body) return;
2215
- const reader = resp.body.getReader();
2216
- const decoder = new TextDecoder();
2217
- let buffer = "";
2218
- while (!cancelled) {
2219
- const { value, done } = await reader.read();
2220
- if (done) return;
2221
- buffer += decoder.decode(value, { stream: true });
2222
- let idx;
2223
- while ((idx = buffer.indexOf("\n\n")) >= 0) {
2224
- const chunk = buffer.slice(0, idx);
2225
- buffer = buffer.slice(idx + 2);
2226
- for (const line of chunk.split("\n")) {
2227
- if (!line.startsWith("data:")) continue;
2228
- const json = line.slice(5).trim();
2229
- if (!json) continue;
2230
- try {
2231
- s.onEvent(JSON.parse(json));
2232
- } catch (err) {
2233
- s.onError?.(err);
2234
- }
2235
- }
2236
- }
2237
- }
2238
- } catch (err) {
2239
- if (!cancelled) s.onError?.(err);
2240
- }
2241
- })();
2242
- return () => {
2243
- cancelled = true;
2244
- controller.abort();
2245
- };
2246
- }
2247
- const cash = {
2248
- generateStaticQR,
2249
- generateDynamicQR,
2250
- parseQR,
2251
- subscribeToPayments
2252
- };
2253
- const passes = createPassesClient({ baseUrl, fetchImpl: signedFetch });
2254
- const receipts = createReceiptsClient({ baseUrl, fetchImpl: signedFetch });
2255
- return {
2256
- // top-level back-compat surface
2257
- generateStaticQR,
2258
- generateDynamicQR,
2259
- parseQR,
2260
- subscribeToPayments,
2261
- // namespaces
2262
- cash,
2263
- passes,
2264
- receipts
2265
- };
2266
- }
2267
-
2268
- // src/accounts/client.ts
2269
- import { z as z10 } from "zod";
2270
- var ACCOUNT_TYPES = ["personal", "business", "partner"];
2271
- var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
2272
- var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
2273
- var AccountSchema = z10.object({
2274
- accountId: z10.string().uuid(),
2275
- type: z10.enum(ACCOUNT_TYPES),
2276
- displayName: z10.string().min(1),
2277
- status: z10.enum(ACCOUNT_STATUSES),
2278
- ownerUserId: z10.string().uuid().nullable(),
2279
- createdAtMs: z10.number().int().nonnegative()
2280
- });
2281
- var AccountMembershipSchema = z10.object({
2282
- accountId: z10.string().uuid(),
2283
- userId: z10.string().uuid(),
2284
- role: z10.enum(MEMBERSHIP_ROLES),
2285
- createdAtMs: z10.number().int().nonnegative()
2286
- });
2287
- function createAccountsClient(opts) {
2288
- const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2289
- if (!fetchImpl) {
2290
- throw new Error("createAccountsClient: no fetch implementation available");
2291
- }
2292
- const baseUrl = opts.baseUrl.replace(/\/$/, "");
2293
- async function call(method, path, body, parser) {
2294
- const init2 = {
2295
- method,
2296
- headers: {
2297
- "content-type": "application/json",
2298
- accept: "application/json"
2299
- }
2300
- };
2301
- if (body !== void 0) init2.body = JSON.stringify(body);
2302
- const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2303
- const text = await resp.text();
2304
- let raw = void 0;
2305
- if (text) {
2306
- try {
2307
- raw = JSON.parse(text);
2308
- } catch {
2309
- }
2310
- }
2311
- if (!resp.ok) {
2312
- const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2313
- const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2314
- throw new FlurApiError(resp.status, code, message, raw);
2315
- }
2316
- return parser(raw);
2317
- }
2318
- const itemsSchema = z10.object({ items: z10.array(AccountSchema) });
2319
- const memberItemsSchema = z10.object({
2320
- items: z10.array(AccountMembershipSchema)
2321
- });
2322
- return {
2323
- listMyAccounts: () => call(
2324
- "GET",
2325
- "/v1/accounts/me",
2326
- void 0,
2327
- (raw) => itemsSchema.parse(raw)
2328
- ),
2329
- getAccount: (accountId) => call(
2330
- "GET",
2331
- `/v1/accounts/${encodeURIComponent(accountId)}`,
2332
- void 0,
2333
- (raw) => AccountSchema.parse(raw)
2334
- ),
2335
- listMembers: (accountId) => call(
2336
- "GET",
2337
- `/v1/accounts/${encodeURIComponent(accountId)}/members`,
2338
- void 0,
2339
- (raw) => memberItemsSchema.parse(raw)
2340
- ),
2341
- createBusinessAccount: (input) => call("POST", "/v1/accounts", input, (raw) => AccountSchema.parse(raw)),
2342
- addMember: (accountId, input) => call(
2343
- "POST",
2344
- `/v1/accounts/${encodeURIComponent(accountId)}/members`,
2345
- input,
2346
- (raw) => AccountMembershipSchema.parse(raw)
2347
- )
2348
- };
2349
- }
2350
-
2351
- // src/partner/client.ts
2352
- import { z as z11 } from "zod";
2353
- import { sha256 as sha2563 } from "@noble/hashes/sha256";
2354
- import { hmac as hmac2 } from "@noble/hashes/hmac";
2355
- import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils";
2356
- var PARTNER_SCOPES = [
2357
- "passes:write",
2358
- "passes:read",
2359
- "passes:redeem",
2360
- "receipts:write",
2361
- "receipts:read",
2362
- "offline:issue",
2363
- "offline:settle",
2364
- "offline:read"
2365
- ];
2366
- var ApiCredentialPublicSchema = z11.object({
2367
- id: z11.string().uuid(),
2368
- accountId: z11.string().uuid(),
2369
- keyId: z11.string(),
2370
- scopes: z11.array(z11.enum(PARTNER_SCOPES)),
2371
- label: z11.string().nullable(),
2372
- createdAtMs: z11.number().int().nonnegative(),
2373
- lastUsedAtMs: z11.number().int().nonnegative().nullable(),
2374
- revokedAtMs: z11.number().int().nonnegative().nullable()
2375
- });
2376
- var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2377
- secret: z11.string().min(1)
2378
- });
2379
- var enc = new TextEncoder();
2380
- async function sha256Hex2(input) {
2381
- const data = typeof input === "string" ? enc.encode(input) : input;
2382
- return bytesToHex4(sha2563(data));
2383
- }
2384
- async function hmacSha256Hex(keyHex, message) {
2385
- return bytesToHex4(hmac2(sha2563, enc.encode(keyHex), enc.encode(message)));
2386
- }
2387
- function defaultNonce2() {
2388
- const c = globalThis.crypto;
2389
- if (c?.randomUUID) return c.randomUUID();
2390
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
2391
- }
2392
- function canonical(params) {
2393
- return [
2394
- params.method.toUpperCase(),
2395
- params.path,
2396
- params.ts,
2397
- params.nonce,
2398
- params.bodyHash
2399
- ].join("\n");
2400
- }
2401
- async function signPartnerRequest(params) {
2402
- const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
2403
- const nonce = params.nonce ?? defaultNonce2();
2404
- const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
2405
- const bodyHash = await sha256Hex2(bodyData);
2406
- const message = canonical({
2407
- method: params.method,
2408
- path: params.path,
2409
- ts,
2410
- nonce,
2411
- bodyHash
2412
- });
2413
- const signingKey = await sha256Hex2(params.secret);
2414
- const sig = await hmacSha256Hex(signingKey, message);
2415
- return {
2416
- authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
2417
- ts,
2418
- nonce,
2419
- bodyHash
2420
- };
2774
+
2775
+ // src/client/flur.ts
2776
+ function generateStaticQR(input) {
2777
+ return encodeNQR({ ...input, pointOfInitiation: "static" });
2421
2778
  }
2422
- function createFlurPartnerClient(opts) {
2423
- const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2424
- if (!fetchImpl) {
2425
- throw new Error(
2426
- "createFlurPartnerClient: no fetch implementation available"
2427
- );
2428
- }
2779
+ function generateDynamicQR(input) {
2780
+ return encodeNQR({ ...input, pointOfInitiation: "dynamic" });
2781
+ }
2782
+ function parseQR(payload) {
2783
+ return parseNQR(payload);
2784
+ }
2785
+ function init(opts) {
2786
+ const partner = createFlurPartnerClient({
2787
+ baseUrl: opts.baseUrl,
2788
+ keyId: opts.apiKey,
2789
+ secret: opts.apiSecret,
2790
+ fetchImpl: opts.fetchImpl,
2791
+ scope: opts.scope
2792
+ });
2793
+ const signedFetch = partner.fetch;
2429
2794
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2430
- async function makeSignedInit(method, path, body) {
2431
- const sig = await signPartnerRequest({
2432
- keyId: opts.keyId,
2433
- secret: opts.secret,
2434
- method,
2435
- path,
2436
- body: body ?? "",
2437
- nowMs: opts.nowMs?.(),
2438
- nonce: opts.nonce?.()
2795
+ function subscribeToPayments(s) {
2796
+ let cancelled = false;
2797
+ queueMicrotask(() => {
2798
+ if (cancelled) return;
2799
+ s.onError?.(
2800
+ new Error(
2801
+ "cash.subscribeToPayments is not available on this backend release; use collections reports or provider webhooks for payment status."
2802
+ )
2803
+ );
2439
2804
  });
2440
- const headers = {
2441
- authorization: sig.authorization,
2442
- accept: "application/json"
2805
+ return () => {
2806
+ cancelled = true;
2443
2807
  };
2444
- if (body !== void 0) headers["content-type"] = "application/json";
2445
- const init2 = { method, headers };
2446
- if (body !== void 0) init2.body = body;
2447
- return init2;
2448
- }
2449
- async function request(opts2) {
2450
- const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
2451
- const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
2452
- const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
2453
- const text = await resp.text();
2454
- let raw;
2455
- if (text) {
2456
- try {
2457
- raw = JSON.parse(text);
2458
- } catch {
2459
- }
2460
- }
2461
- if (!resp.ok) {
2462
- const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2463
- const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2464
- throw new FlurApiError(resp.status, code, message, raw);
2465
- }
2466
- return raw;
2467
2808
  }
2468
- const fetchLike = async (input, init2) => {
2469
- const url = typeof input === "string" ? input : input.toString();
2470
- const u = new URL(url, baseUrl);
2471
- const path = `${u.pathname}${u.search}`;
2472
- const method = (init2?.method ?? "GET").toUpperCase();
2473
- let bodyStr;
2474
- if (init2?.body) {
2475
- bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
2476
- }
2477
- const signed = await makeSignedInit(method, path, bodyStr);
2478
- return fetchImpl(`${baseUrl}${path}`, {
2479
- ...init2,
2480
- ...signed,
2481
- headers: {
2482
- ...init2?.headers,
2483
- ...signed.headers
2484
- }
2485
- });
2809
+ const cash = {
2810
+ generateStaticQR,
2811
+ generateDynamicQR,
2812
+ parseQR,
2813
+ subscribeToPayments
2814
+ };
2815
+ const passes = createPassesClient({ baseUrl, fetchImpl: signedFetch });
2816
+ const receipts = createReceiptsClient({ baseUrl, fetchImpl: signedFetch });
2817
+ const collections = createPartnerCollectionsClient({
2818
+ baseUrl,
2819
+ fetchImpl: signedFetch
2820
+ });
2821
+ return {
2822
+ // top-level back-compat surface
2823
+ generateStaticQR,
2824
+ generateDynamicQR,
2825
+ parseQR,
2826
+ subscribeToPayments,
2827
+ // namespaces
2828
+ cash,
2829
+ collections,
2830
+ passes,
2831
+ receipts
2486
2832
  };
2487
- return { request, fetch: fetchLike };
2488
2833
  }
2489
- function createApiCredentialsAdminClient(opts) {
2834
+
2835
+ // src/accounts/client.ts
2836
+ import { z as z12 } from "zod";
2837
+ var ACCOUNT_TYPES = ["personal", "business", "partner"];
2838
+ var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
2839
+ var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
2840
+ var AccountSchema = z12.object({
2841
+ accountId: z12.string().uuid(),
2842
+ type: z12.enum(ACCOUNT_TYPES),
2843
+ displayName: z12.string().min(1),
2844
+ status: z12.enum(ACCOUNT_STATUSES),
2845
+ ownerUserId: z12.string().uuid().nullable(),
2846
+ createdAtMs: z12.number().int().nonnegative()
2847
+ });
2848
+ var AccountMembershipSchema = z12.object({
2849
+ accountId: z12.string().uuid(),
2850
+ userId: z12.string().uuid(),
2851
+ role: z12.enum(MEMBERSHIP_ROLES),
2852
+ createdAtMs: z12.number().int().nonnegative()
2853
+ });
2854
+ function createAccountsClient(opts) {
2490
2855
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2491
2856
  if (!fetchImpl) {
2492
- throw new Error(
2493
- "createApiCredentialsAdminClient: no fetch implementation available"
2494
- );
2857
+ throw new Error("createAccountsClient: no fetch implementation available");
2495
2858
  }
2496
2859
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2497
2860
  async function call(method, path, body, parser) {
@@ -2505,7 +2868,7 @@ function createApiCredentialsAdminClient(opts) {
2505
2868
  if (body !== void 0) init2.body = JSON.stringify(body);
2506
2869
  const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2507
2870
  const text = await resp.text();
2508
- let raw;
2871
+ let raw = void 0;
2509
2872
  if (text) {
2510
2873
  try {
2511
2874
  raw = JSON.parse(text);
@@ -2519,70 +2882,78 @@ function createApiCredentialsAdminClient(opts) {
2519
2882
  }
2520
2883
  return parser(raw);
2521
2884
  }
2522
- const listSchema = z11.object({
2523
- items: z11.array(ApiCredentialPublicSchema)
2885
+ const itemsSchema = z12.object({ items: z12.array(AccountSchema) });
2886
+ const memberItemsSchema = z12.object({
2887
+ items: z12.array(AccountMembershipSchema)
2524
2888
  });
2525
2889
  return {
2526
- list: (accountId) => call(
2890
+ listMyAccounts: () => call(
2527
2891
  "GET",
2528
- `/v1/accounts/${accountId}/api-credentials`,
2892
+ "/v1/accounts/me",
2529
2893
  void 0,
2530
- (raw) => listSchema.parse(raw)
2894
+ (raw) => itemsSchema.parse(raw)
2531
2895
  ),
2532
- mint: (accountId, input) => call(
2533
- "POST",
2534
- `/v1/accounts/${accountId}/api-credentials`,
2535
- input,
2536
- (raw) => MintedApiCredentialSchema.parse(raw)
2896
+ getAccount: (accountId) => call(
2897
+ "GET",
2898
+ `/v1/accounts/${encodeURIComponent(accountId)}`,
2899
+ void 0,
2900
+ (raw) => AccountSchema.parse(raw)
2537
2901
  ),
2538
- revoke: (accountId, credentialId) => call(
2539
- "DELETE",
2540
- `/v1/accounts/${accountId}/api-credentials/${credentialId}`,
2902
+ listMembers: (accountId) => call(
2903
+ "GET",
2904
+ `/v1/accounts/${encodeURIComponent(accountId)}/members`,
2541
2905
  void 0,
2542
- (raw) => ApiCredentialPublicSchema.parse(raw)
2906
+ (raw) => memberItemsSchema.parse(raw)
2907
+ ),
2908
+ createBusinessAccount: (input) => call("POST", "/v1/accounts", input, (raw) => AccountSchema.parse(raw)),
2909
+ addMember: (accountId, input) => call(
2910
+ "POST",
2911
+ `/v1/accounts/${encodeURIComponent(accountId)}/members`,
2912
+ input,
2913
+ (raw) => AccountMembershipSchema.parse(raw)
2543
2914
  )
2544
2915
  };
2545
2916
  }
2546
2917
 
2547
2918
  // src/me-offline/client.ts
2548
- import { z as z12 } from "zod";
2549
- var Hex64 = z12.string().regex(/^[0-9a-f]{64}$/i);
2550
- var HexAny = z12.string().regex(/^[0-9a-f]+$/i);
2551
- var Sha256Hex = z12.string().regex(/^[0-9a-f]{64}$/i);
2552
- var RegisterDeviceKeyInputSchema = z12.object({
2553
- deviceId: z12.string().min(1).max(128),
2919
+ import { z as z13 } from "zod";
2920
+ var Hex64 = z13.string().regex(/^[0-9a-f]{64}$/i);
2921
+ var HexAny = z13.string().regex(/^[0-9a-f]+$/i);
2922
+ var Sha256Hex = z13.string().regex(/^[0-9a-f]{64}$/i);
2923
+ var RegisterDeviceKeyInputSchema = z13.object({
2924
+ deviceId: z13.string().min(1).max(128),
2554
2925
  publicKeyHex: Hex64
2555
2926
  });
2556
- var DeviceKeyRecordSchema = z12.object({
2557
- id: z12.string().uuid(),
2558
- userId: z12.string().uuid(),
2559
- deviceId: z12.string(),
2927
+ var DeviceKeyRecordSchema = z13.object({
2928
+ id: z13.string().uuid(),
2929
+ userId: z13.string().uuid(),
2930
+ deviceId: z13.string(),
2560
2931
  publicKeyHex: Hex64,
2561
- createdAtMs: z12.number().int().nonnegative(),
2562
- revokedAtMs: z12.number().int().nonnegative().nullable()
2932
+ createdAtMs: z13.number().int().nonnegative(),
2933
+ revokedAtMs: z13.number().int().nonnegative().nullable()
2563
2934
  });
2564
- var ConsumerOACSchema = z12.object({
2565
- oacId: z12.string().uuid(),
2566
- issuerId: z12.string().min(1).max(64),
2567
- userId: z12.string().uuid(),
2568
- deviceId: z12.string().min(1).max(128),
2935
+ var ConsumerOACSchema = z13.object({
2936
+ oacId: z13.string().uuid(),
2937
+ issuerId: z13.string().min(1).max(64),
2938
+ userId: z13.string().uuid(),
2939
+ deviceId: z13.string().min(1).max(128),
2569
2940
  devicePubkeyHex: Hex64,
2570
- perTxCapKobo: z12.number().int().positive(),
2571
- cumulativeCapKobo: z12.number().int().positive(),
2572
- currency: z12.string().length(3),
2573
- validFromMs: z12.number().int().nonnegative(),
2574
- validUntilMs: z12.number().int().nonnegative(),
2575
- counterSeed: z12.number().int().nonnegative(),
2576
- issuedAtMs: z12.number().int().nonnegative()
2577
- });
2578
- var SignedConsumerOACSchema = z12.object({
2941
+ perTxCapKobo: z13.number().int().positive(),
2942
+ cumulativeCapKobo: z13.number().int().positive(),
2943
+ currency: z13.string().length(3),
2944
+ validFromMs: z13.number().int().nonnegative(),
2945
+ validUntilMs: z13.number().int().nonnegative(),
2946
+ counterSeed: z13.number().int().nonnegative(),
2947
+ issuedAtMs: z13.number().int().nonnegative()
2948
+ });
2949
+ var SignedConsumerOACSchema = z13.object({
2579
2950
  oac: ConsumerOACSchema,
2580
2951
  issuerSig: HexAny,
2581
2952
  issuerPublicKeyHex: Hex64
2582
2953
  });
2583
2954
  var OACRecordSchema = SignedConsumerOACSchema.extend({
2584
- currentOfflineSpentKobo: z12.number().int().nonnegative(),
2585
- status: z12.enum([
2955
+ currentOfflineSpentKobo: z13.number().int().nonnegative(),
2956
+ status: z13.enum([
2586
2957
  "active",
2587
2958
  "superseded",
2588
2959
  "expired",
@@ -2591,43 +2962,43 @@ var OACRecordSchema = SignedConsumerOACSchema.extend({
2591
2962
  "draining",
2592
2963
  "closed"
2593
2964
  ]),
2594
- supersededAtMs: z12.number().int().nonnegative().nullable(),
2595
- revokedAtMs: z12.number().int().nonnegative().nullable(),
2596
- holdId: z12.string().uuid().nullable().optional()
2597
- });
2598
- var IssueOACInputSchema = z12.object({
2599
- deviceId: z12.string().min(1).max(128),
2600
- perTxCapKobo: z12.number().int().positive().optional(),
2601
- cumulativeCapKobo: z12.number().int().positive().optional(),
2602
- ttlMs: z12.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2603
- spendableOnlineKobo: z12.number().int().nonnegative().optional()
2604
- });
2605
- var EnableOfflineInputSchema = z12.object({
2606
- deviceId: z12.string().min(1).max(128),
2607
- amountKobo: z12.number().int().positive(),
2608
- perTxCapKobo: z12.number().int().positive().optional(),
2609
- ttlMs: z12.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2610
- installId: z12.string().min(1).max(128),
2611
- partnerId: z12.string().min(1).max(64).optional()
2612
- });
2613
- var DisableOfflineInputSchema = z12.object({
2614
- deviceId: z12.string().min(1).max(128),
2615
- installId: z12.string().min(1).max(128).optional(),
2616
- claims: z12.array(z12.unknown()).max(256).optional()
2617
- });
2618
- var OfflineHoldRecordSchema = z12.object({
2619
- holdId: z12.string().uuid(),
2620
- userId: z12.string().uuid(),
2621
- deviceId: z12.string(),
2622
- partnerId: z12.string(),
2623
- adapterKind: z12.string(),
2624
- externalHoldRef: z12.string().nullable(),
2625
- amountKobo: z12.number().int().nonnegative(),
2626
- capturedKobo: z12.number().int().nonnegative(),
2627
- releasedKobo: z12.number().int().nonnegative(),
2628
- remainingKobo: z12.number().int().nonnegative(),
2629
- currency: z12.string().length(3),
2630
- status: z12.enum([
2965
+ supersededAtMs: z13.number().int().nonnegative().nullable(),
2966
+ revokedAtMs: z13.number().int().nonnegative().nullable(),
2967
+ holdId: z13.string().uuid().nullable().optional()
2968
+ });
2969
+ var IssueOACInputSchema = z13.object({
2970
+ deviceId: z13.string().min(1).max(128),
2971
+ perTxCapKobo: z13.number().int().positive().optional(),
2972
+ cumulativeCapKobo: z13.number().int().positive().optional(),
2973
+ ttlMs: z13.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2974
+ spendableOnlineKobo: z13.number().int().nonnegative().optional()
2975
+ });
2976
+ var EnableOfflineInputSchema = z13.object({
2977
+ deviceId: z13.string().min(1).max(128),
2978
+ amountKobo: z13.number().int().positive(),
2979
+ perTxCapKobo: z13.number().int().positive().optional(),
2980
+ ttlMs: z13.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2981
+ installId: z13.string().min(1).max(128),
2982
+ partnerId: z13.string().min(1).max(64).optional()
2983
+ });
2984
+ var DisableOfflineInputSchema = z13.object({
2985
+ deviceId: z13.string().min(1).max(128),
2986
+ installId: z13.string().min(1).max(128).optional(),
2987
+ claims: z13.array(z13.unknown()).max(256).optional()
2988
+ });
2989
+ var OfflineHoldRecordSchema = z13.object({
2990
+ holdId: z13.string().uuid(),
2991
+ userId: z13.string().uuid(),
2992
+ deviceId: z13.string(),
2993
+ partnerId: z13.string(),
2994
+ adapterKind: z13.string(),
2995
+ externalHoldRef: z13.string().nullable(),
2996
+ amountKobo: z13.number().int().nonnegative(),
2997
+ capturedKobo: z13.number().int().nonnegative(),
2998
+ releasedKobo: z13.number().int().nonnegative(),
2999
+ remainingKobo: z13.number().int().nonnegative(),
3000
+ currency: z13.string().length(3),
3001
+ status: z13.enum([
2631
3002
  "placing",
2632
3003
  "active",
2633
3004
  "disabling",
@@ -2636,71 +3007,71 @@ var OfflineHoldRecordSchema = z12.object({
2636
3007
  "revoked",
2637
3008
  "failed"
2638
3009
  ]),
2639
- installId: z12.string().nullable(),
2640
- drainDeadlineMs: z12.number().int().nonnegative(),
2641
- disableRequestedAtMs: z12.number().int().nonnegative().nullable(),
2642
- createdAtMs: z12.number().int().nonnegative(),
2643
- closedAtMs: z12.number().int().nonnegative().nullable(),
2644
- isTrusted: z12.boolean().optional()
2645
- });
2646
- var EnableOfflineResultSchema = z12.object({
3010
+ installId: z13.string().nullable(),
3011
+ drainDeadlineMs: z13.number().int().nonnegative(),
3012
+ disableRequestedAtMs: z13.number().int().nonnegative().nullable(),
3013
+ createdAtMs: z13.number().int().nonnegative(),
3014
+ closedAtMs: z13.number().int().nonnegative().nullable(),
3015
+ isTrusted: z13.boolean().optional()
3016
+ });
3017
+ var EnableOfflineResultSchema = z13.object({
2647
3018
  hold: OfflineHoldRecordSchema,
2648
3019
  oac: OACRecordSchema
2649
3020
  });
2650
- var DisableOfflineResultSchema = z12.object({
3021
+ var DisableOfflineResultSchema = z13.object({
2651
3022
  hold: OfflineHoldRecordSchema,
2652
- trusted: z12.boolean(),
2653
- settledClaims: z12.number().int().nonnegative()
3023
+ trusted: z13.boolean(),
3024
+ settledClaims: z13.number().int().nonnegative()
2654
3025
  });
2655
- var OfflineStatusResultSchema = z12.object({
3026
+ var OfflineStatusResultSchema = z13.object({
2656
3027
  hold: OfflineHoldRecordSchema.nullable(),
2657
3028
  active: OACRecordSchema.nullable()
2658
3029
  });
2659
- var OfflineStateResultSchema = z12.object({
3030
+ var OfflineStateResultSchema = z13.object({
2660
3031
  active: OACRecordSchema.nullable()
2661
3032
  });
2662
- var ConsumerPaymentClaimSchema = z12.object({
2663
- oacId: z12.string().uuid(),
3033
+ var ConsumerPaymentClaimSchema = z13.object({
3034
+ oacId: z13.string().uuid(),
2664
3035
  encounterId: Sha256Hex.optional(),
2665
- payerUserId: z12.string().uuid(),
2666
- payeeUserId: z12.string().uuid(),
2667
- payerDeviceId: z12.string().min(1).max(128),
2668
- payerNonce: z12.string().min(8).max(128),
2669
- payeeNonce: z12.string().min(8).max(128),
2670
- amountKobo: z12.number().int().positive(),
2671
- currency: z12.string().length(3).default("NGN"),
2672
- occurredAtMs: z12.number().int().nonnegative(),
2673
- completedAtMs: z12.number().int().nonnegative().optional(),
2674
- contextId: z12.string().max(128).optional(),
3036
+ payerUserId: z13.string().uuid(),
3037
+ payeeUserId: z13.string().uuid(),
3038
+ payerDeviceId: z13.string().min(1).max(128),
3039
+ payerNonce: z13.string().min(8).max(128),
3040
+ payeeNonce: z13.string().min(8).max(128),
3041
+ amountKobo: z13.number().int().positive(),
3042
+ currency: z13.string().length(3).default("NGN"),
3043
+ occurredAtMs: z13.number().int().nonnegative(),
3044
+ completedAtMs: z13.number().int().nonnegative().optional(),
3045
+ contextId: z13.string().max(128).optional(),
2675
3046
  payerPubkeyHex: Hex64,
2676
3047
  payerSignature: HexAny,
2677
3048
  payeePubkeyHex: Hex64.optional(),
2678
3049
  payeeSignature: HexAny.optional()
2679
3050
  });
2680
- var ConsumerSettlementSchema = z12.object({
2681
- settlementId: z12.string().uuid(),
3051
+ var ConsumerSettlementSchema = z13.object({
3052
+ settlementId: z13.string().uuid(),
2682
3053
  settlementKey: Sha256Hex,
2683
3054
  encounterId: Sha256Hex,
2684
- oacId: z12.string().uuid(),
2685
- payerUserId: z12.string().uuid(),
2686
- payeeUserId: z12.string().uuid(),
2687
- amountKobo: z12.number().int().positive(),
2688
- currency: z12.string().length(3),
2689
- status: z12.enum(["SETTLED", "REVIEW"]),
2690
- reviewReason: z12.string().nullable(),
2691
- ledgerRef: z12.string().nullable(),
3055
+ oacId: z13.string().uuid(),
3056
+ payerUserId: z13.string().uuid(),
3057
+ payeeUserId: z13.string().uuid(),
3058
+ amountKobo: z13.number().int().positive(),
3059
+ currency: z13.string().length(3),
3060
+ status: z13.enum(["SETTLED", "REVIEW"]),
3061
+ reviewReason: z13.string().nullable(),
3062
+ ledgerRef: z13.string().nullable(),
2692
3063
  issuerSig: HexAny,
2693
- createdAtMs: z12.number().int().nonnegative()
3064
+ createdAtMs: z13.number().int().nonnegative()
2694
3065
  });
2695
- var ConsumerSettleResultSchema = z12.object({
3066
+ var ConsumerSettleResultSchema = z13.object({
2696
3067
  settlement: ConsumerSettlementSchema,
2697
3068
  encounterId: Sha256Hex,
2698
- replayed: z12.boolean()
3069
+ replayed: z13.boolean()
2699
3070
  });
2700
- var RevokeDeviceKeyInputSchema = z12.object({
2701
- deviceId: z12.string().min(1).max(128),
3071
+ var RevokeDeviceKeyInputSchema = z13.object({
3072
+ deviceId: z13.string().min(1).max(128),
2702
3073
  /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
2703
- sendAuthToken: z12.string().min(16)
3074
+ sendAuthToken: z13.string().min(16)
2704
3075
  });
2705
3076
  function createMeOfflineClient(opts) {
2706
3077
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -2733,7 +3104,7 @@ function createMeOfflineClient(opts) {
2733
3104
  }
2734
3105
  return parser(raw);
2735
3106
  }
2736
- const deviceKeyItems = z12.object({ items: z12.array(DeviceKeyRecordSchema) });
3107
+ const deviceKeyItems = z13.object({ items: z13.array(DeviceKeyRecordSchema) });
2737
3108
  return {
2738
3109
  registerDeviceKey: (input) => call(
2739
3110
  "POST",
@@ -2797,6 +3168,320 @@ function createMeOfflineClient(opts) {
2797
3168
  )
2798
3169
  };
2799
3170
  }
3171
+
3172
+ // src/partner-funding/client.ts
3173
+ import { z as z14 } from "zod";
3174
+ var MinorString = z14.string().regex(/^-?\d+$/);
3175
+ var PositiveMinor = z14.union([
3176
+ z14.number().int().positive(),
3177
+ z14.string().regex(/^[1-9]\d{0,18}$/)
3178
+ ]);
3179
+ var Currency = z14.string().trim().length(3).transform((v) => v.toUpperCase());
3180
+ var Metadata = z14.record(z14.unknown());
3181
+ var PARTNER_KINDS = ["bank", "merchant"];
3182
+ var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
3183
+ var PARTNER_PROFILE_STATUSES = [
3184
+ "active",
3185
+ "suspended",
3186
+ "closed"
3187
+ ];
3188
+ var PARTNER_FUNDING_DIRECTIONS = ["credit", "debit"];
3189
+ var PARTNER_FUNDING_STATUSES = [
3190
+ "pending",
3191
+ "posted",
3192
+ "failed"
3193
+ ];
3194
+ var PAYOUT_DESTINATION_STATUSES = [
3195
+ "pending",
3196
+ "verified",
3197
+ "disabled"
3198
+ ];
3199
+ var WITHDRAWAL_STATES = [
3200
+ "requested",
3201
+ "submitted",
3202
+ "processing",
3203
+ "paid",
3204
+ "failed",
3205
+ "reversed"
3206
+ ];
3207
+ var PartnerProfileSchema = z14.object({
3208
+ partnerAccountId: z14.string().uuid(),
3209
+ kind: z14.enum(PARTNER_KINDS),
3210
+ custodialMode: z14.enum(CUSTODIAL_MODES),
3211
+ displayName: z14.string(),
3212
+ bankCode: z14.string().nullable(),
3213
+ poolAccountNumber: z14.string().nullable(),
3214
+ status: z14.enum(PARTNER_PROFILE_STATUSES),
3215
+ metadata: Metadata,
3216
+ createdAtMs: z14.number().int().nonnegative(),
3217
+ updatedAtMs: z14.number().int().nonnegative()
3218
+ });
3219
+ var UpsertPartnerProfileInputSchema = z14.object({
3220
+ kind: z14.enum(PARTNER_KINDS),
3221
+ custodialMode: z14.enum(CUSTODIAL_MODES),
3222
+ displayName: z14.string().trim().min(1).max(200),
3223
+ bankCode: z14.string().trim().min(1).max(64).optional(),
3224
+ poolAccountNumber: z14.string().trim().min(1).max(64).optional(),
3225
+ metadata: Metadata.optional()
3226
+ });
3227
+ var PartnerFundingEventInputSchema = z14.object({
3228
+ externalRef: z14.string().trim().min(8).max(128),
3229
+ direction: z14.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
3230
+ userId: z14.string().uuid().optional(),
3231
+ accountId: z14.string().uuid().optional(),
3232
+ amountMinor: PositiveMinor,
3233
+ currency: Currency,
3234
+ fundingSource: z14.string().trim().min(1).max(64).optional(),
3235
+ providerMetadata: Metadata.optional()
3236
+ });
3237
+ var PartnerFundingSchema = z14.object({
3238
+ fundingId: z14.string().uuid(),
3239
+ partnerId: z14.string().uuid(),
3240
+ accountId: z14.string().uuid(),
3241
+ userId: z14.string().uuid().nullable(),
3242
+ direction: z14.enum(PARTNER_FUNDING_DIRECTIONS),
3243
+ currency: z14.string(),
3244
+ amountMinor: MinorString,
3245
+ externalRef: z14.string(),
3246
+ status: z14.enum(PARTNER_FUNDING_STATUSES),
3247
+ fundingSource: z14.string(),
3248
+ ledgerRef: z14.string(),
3249
+ providerMetadata: Metadata,
3250
+ createdAtMs: z14.number().int().nonnegative(),
3251
+ updatedAtMs: z14.number().int().nonnegative()
3252
+ });
3253
+ var IngestFundingResultSchema = z14.object({
3254
+ funding: PartnerFundingSchema,
3255
+ replayed: z14.boolean()
3256
+ });
3257
+ var PayoutDestinationSchema = z14.object({
3258
+ destinationId: z14.string().uuid(),
3259
+ accountId: z14.string().uuid(),
3260
+ partnerId: z14.string().uuid(),
3261
+ bankCode: z14.string(),
3262
+ accountNumber: z14.string(),
3263
+ accountName: z14.string(),
3264
+ status: z14.enum(PAYOUT_DESTINATION_STATUSES),
3265
+ verifiedAtMs: z14.number().int().nonnegative().nullable(),
3266
+ metadata: Metadata,
3267
+ createdAtMs: z14.number().int().nonnegative(),
3268
+ updatedAtMs: z14.number().int().nonnegative()
3269
+ });
3270
+ var CreatePayoutDestinationInputSchema = z14.object({
3271
+ partnerId: z14.string().uuid(),
3272
+ bankCode: z14.string().trim().min(1).max(32),
3273
+ accountNumber: z14.string().trim().min(4).max(64),
3274
+ accountName: z14.string().trim().min(1).max(200),
3275
+ metadata: Metadata.optional()
3276
+ });
3277
+ var ListPayoutDestinationsResultSchema = z14.object({
3278
+ items: z14.array(PayoutDestinationSchema)
3279
+ });
3280
+ var WithdrawalSchema = z14.object({
3281
+ withdrawalId: z14.string().uuid(),
3282
+ accountId: z14.string().uuid(),
3283
+ userId: z14.string().uuid(),
3284
+ partnerId: z14.string().uuid(),
3285
+ destinationId: z14.string().uuid(),
3286
+ currency: z14.string(),
3287
+ amountMinor: MinorString,
3288
+ state: z14.enum(WITHDRAWAL_STATES),
3289
+ idempotencyKey: z14.string(),
3290
+ providerRef: z14.string().nullable(),
3291
+ lastError: z14.string().nullable(),
3292
+ ledgerRef: z14.string(),
3293
+ reverseLedgerRef: z14.string().nullable(),
3294
+ metadata: Metadata,
3295
+ createdAtMs: z14.number().int().nonnegative(),
3296
+ updatedAtMs: z14.number().int().nonnegative()
3297
+ });
3298
+ var CreateWithdrawalInputSchema = z14.object({
3299
+ destinationId: z14.string().uuid(),
3300
+ amountMinor: PositiveMinor,
3301
+ currency: Currency,
3302
+ idempotencyKey: z14.string().trim().min(8).max(128),
3303
+ metadata: Metadata.optional()
3304
+ });
3305
+ var CreateWithdrawalResultSchema = z14.object({
3306
+ withdrawal: WithdrawalSchema,
3307
+ replayed: z14.boolean()
3308
+ });
3309
+ var PayoutEventInputSchema = z14.object({
3310
+ externalRef: z14.string().trim().min(8).max(128),
3311
+ withdrawalId: z14.string().uuid().optional(),
3312
+ state: z14.enum(["submitted", "processing", "paid", "failed"]),
3313
+ providerRef: z14.string().trim().min(1).max(128).optional(),
3314
+ failureCode: z14.string().trim().max(64).optional(),
3315
+ failureMessage: z14.string().trim().max(512).optional(),
3316
+ providerMetadata: Metadata.optional()
3317
+ });
3318
+ var RecordPayoutEventResultSchema = z14.object({
3319
+ withdrawal: WithdrawalSchema,
3320
+ replayed: z14.boolean()
3321
+ });
3322
+ var ReconciliationReportSchema = z14.object({
3323
+ partnerId: z14.string().uuid(),
3324
+ currency: z14.string(),
3325
+ fromMs: z14.number().int().nonnegative(),
3326
+ toMs: z14.number().int().nonnegative(),
3327
+ fundingsCreditMinor: MinorString,
3328
+ fundingsDebitMinor: MinorString,
3329
+ withdrawalsPaidMinor: MinorString,
3330
+ withdrawalsReversedMinor: MinorString,
3331
+ withdrawalsInFlightMinor: MinorString,
3332
+ expectedReserveBalanceMinor: MinorString,
3333
+ actualReserveBalanceMinor: MinorString,
3334
+ imbalanceMinor: MinorString,
3335
+ generatedAtMs: z14.number().int().nonnegative()
3336
+ });
3337
+ function createPartnerFundingClient(partner) {
3338
+ return {
3339
+ ingestFunding: async (input) => {
3340
+ const body = PartnerFundingEventInputSchema.parse(input);
3341
+ const raw = await partner.request({
3342
+ method: "POST",
3343
+ path: "/v1/partners/fundings",
3344
+ body
3345
+ });
3346
+ return IngestFundingResultSchema.parse(raw);
3347
+ },
3348
+ recordPayoutEvent: async (input) => {
3349
+ const body = PayoutEventInputSchema.parse(input);
3350
+ const raw = await partner.request({
3351
+ method: "POST",
3352
+ path: "/v1/partners/payouts/events",
3353
+ body
3354
+ });
3355
+ return RecordPayoutEventResultSchema.parse(raw);
3356
+ },
3357
+ reconciliation: async (input) => {
3358
+ const qs = new URLSearchParams({
3359
+ currency: input.currency
3360
+ });
3361
+ if (typeof input.fromMs === "number")
3362
+ qs.set("fromMs", String(input.fromMs));
3363
+ if (typeof input.toMs === "number") qs.set("toMs", String(input.toMs));
3364
+ const raw = await partner.request({
3365
+ method: "GET",
3366
+ path: `/v1/partners/reconciliation/daily?${qs.toString()}`
3367
+ });
3368
+ return ReconciliationReportSchema.parse(raw);
3369
+ }
3370
+ };
3371
+ }
3372
+ function createConsumerWithdrawalsClient(opts) {
3373
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3374
+ if (!fetchImpl) {
3375
+ throw new Error(
3376
+ "createConsumerWithdrawalsClient: no fetch implementation available"
3377
+ );
3378
+ }
3379
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
3380
+ async function call(method, path, body, parser) {
3381
+ const init2 = {
3382
+ method,
3383
+ headers: { accept: "application/json" }
3384
+ };
3385
+ if (body !== void 0) {
3386
+ init2.body = JSON.stringify(body);
3387
+ init2.headers = { ...init2.headers, "content-type": "application/json" };
3388
+ }
3389
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
3390
+ const text = await resp.text();
3391
+ let raw;
3392
+ if (text) {
3393
+ try {
3394
+ raw = JSON.parse(text);
3395
+ } catch {
3396
+ raw = text;
3397
+ }
3398
+ }
3399
+ if (!resp.ok) {
3400
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3401
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3402
+ throw new FlurApiError(resp.status, code, message, raw);
3403
+ }
3404
+ return parser(raw);
3405
+ }
3406
+ return {
3407
+ listDestinations: () => call(
3408
+ "GET",
3409
+ "/v1/me/payout-destinations",
3410
+ void 0,
3411
+ (raw) => ListPayoutDestinationsResultSchema.parse(raw)
3412
+ ),
3413
+ createDestination: (input) => call(
3414
+ "POST",
3415
+ "/v1/me/payout-destinations",
3416
+ CreatePayoutDestinationInputSchema.parse(input),
3417
+ (raw) => PayoutDestinationSchema.parse(raw)
3418
+ ),
3419
+ verifyDestination: (destinationId) => call(
3420
+ "POST",
3421
+ `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/verify`,
3422
+ {},
3423
+ (raw) => PayoutDestinationSchema.parse(raw)
3424
+ ),
3425
+ disableDestination: (destinationId) => call(
3426
+ "POST",
3427
+ `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/disable`,
3428
+ {},
3429
+ (raw) => PayoutDestinationSchema.parse(raw)
3430
+ ),
3431
+ createWithdrawal: (input) => call(
3432
+ "POST",
3433
+ "/v1/me/withdrawals",
3434
+ CreateWithdrawalInputSchema.parse(input),
3435
+ (raw) => CreateWithdrawalResultSchema.parse(raw)
3436
+ ),
3437
+ getWithdrawal: (withdrawalId) => call(
3438
+ "GET",
3439
+ `/v1/me/withdrawals/${encodeURIComponent(withdrawalId)}`,
3440
+ void 0,
3441
+ (raw) => WithdrawalSchema.parse(raw)
3442
+ )
3443
+ };
3444
+ }
3445
+ function createPartnerProfileAdminClient(opts) {
3446
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3447
+ if (!fetchImpl) {
3448
+ throw new Error(
3449
+ "createPartnerProfileAdminClient: no fetch implementation available"
3450
+ );
3451
+ }
3452
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
3453
+ return {
3454
+ upsertProfile: async (partnerAccountId, input) => {
3455
+ const body = {
3456
+ partnerAccountId,
3457
+ ...UpsertPartnerProfileInputSchema.parse(input)
3458
+ };
3459
+ const resp = await fetchImpl(`${baseUrl}/v1/partners/profile`, {
3460
+ method: "POST",
3461
+ headers: {
3462
+ "content-type": "application/json",
3463
+ accept: "application/json"
3464
+ },
3465
+ body: JSON.stringify(body)
3466
+ });
3467
+ const text = await resp.text();
3468
+ let raw;
3469
+ if (text) {
3470
+ try {
3471
+ raw = JSON.parse(text);
3472
+ } catch {
3473
+ raw = text;
3474
+ }
3475
+ }
3476
+ if (!resp.ok) {
3477
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3478
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3479
+ throw new FlurApiError(resp.status, code, message, raw);
3480
+ }
3481
+ return PartnerProfileSchema.parse(raw);
3482
+ }
3483
+ };
3484
+ }
2800
3485
  export {
2801
3486
  ACCOUNT_STATUSES,
2802
3487
  ACCOUNT_TYPES,
@@ -2804,11 +3489,24 @@ export {
2804
3489
  AccountMembershipSchema,
2805
3490
  AccountSchema,
2806
3491
  ApiCredentialPublicSchema,
3492
+ COLLECTION_INTENT_STATUSES,
3493
+ COLLECTION_PAYMENT_STATUSES,
3494
+ CUSTODIAL_MODES,
3495
+ CollectionIntentSchema,
3496
+ CollectionPaymentResultSchema,
3497
+ CollectionPaymentSchema,
3498
+ CollectionReportSummarySchema,
3499
+ CollectionStatementSchema,
2807
3500
  OACRecordSchema as ConsumerOACRecordSchema,
2808
3501
  ConsumerOACSchema,
2809
3502
  ConsumerPaymentClaimSchema,
2810
3503
  ConsumerSettleResultSchema,
2811
3504
  ConsumerSettlementSchema,
3505
+ CreateCollectionIntentInputSchema,
3506
+ CreatePayoutDestinationInputSchema,
3507
+ CreatePayoutInputSchema,
3508
+ CreateWithdrawalInputSchema,
3509
+ CreateWithdrawalResultSchema,
2812
3510
  DeviceKeyRecordSchema,
2813
3511
  DisableOfflineInputSchema,
2814
3512
  DisableOfflineResultSchema,
@@ -2821,8 +3519,14 @@ export {
2821
3519
  FlurError,
2822
3520
  FlurExpiredError,
2823
3521
  FlurReplayError,
3522
+ IngestFundingResultSchema,
2824
3523
  IssueOACInputSchema,
3524
+ ListPayoutDestinationsResultSchema,
2825
3525
  MEMBERSHIP_ROLES,
3526
+ MERCHANT_PAYOUT_STATUSES,
3527
+ MERCHANT_PROFILE_STATUSES,
3528
+ MerchantPayoutSchema,
3529
+ MerchantProfileSchema,
2826
3530
  MintedApiCredentialSchema,
2827
3531
  NGN_CURRENCY_CODE,
2828
3532
  NG_COUNTRY_CODE,
@@ -2837,25 +3541,46 @@ export {
2837
3541
  OfflineStateResultSchema,
2838
3542
  OfflineStatusResultSchema,
2839
3543
  OfflineTokenSchema,
3544
+ PARTNER_FUNDING_DIRECTIONS,
3545
+ PARTNER_FUNDING_STATUSES,
3546
+ PARTNER_KINDS,
3547
+ PARTNER_PROFILE_STATUSES,
2840
3548
  PARTNER_SCOPES,
2841
3549
  PASS_KINDS,
2842
3550
  PASS_STATES,
2843
3551
  PAYLOAD_FORMAT_INDICATOR_VALUE,
3552
+ PAYOUT_DESTINATION_STATUSES,
2844
3553
  POINT_OF_INITIATION,
3554
+ PartnerFundingEventInputSchema,
3555
+ PartnerFundingSchema,
3556
+ PartnerProfileSchema,
2845
3557
  PassMetadataSchema,
2846
3558
  PassSchema,
3559
+ PayCollectionInputSchema,
2847
3560
  PaymentClaimSchema,
3561
+ PayoutDestinationSchema,
3562
+ PayoutEventInputSchema,
3563
+ ProviderEventInputSchema,
3564
+ ProviderEventRecordSchema,
3565
+ PublicCollectionIntentSchema,
2848
3566
  RECEIPT_CHANNELS,
2849
3567
  RECEIPT_KINDS,
2850
3568
  REPLAY_WINDOW_MS,
2851
3569
  ReceiptPayloadSchema,
2852
3570
  ReceiptSchema,
3571
+ ReconciliationReportSchema,
3572
+ RecordPayoutEventResultSchema,
2853
3573
  RedemptionSchema,
2854
3574
  RegisterDeviceKeyInputSchema,
2855
3575
  RevokeDeviceKeyInputSchema,
3576
+ SETTLEMENT_SCHEDULES,
2856
3577
  SettleResponseSchema,
2857
3578
  SettlementSchema,
2858
3579
  SignedConsumerOACSchema,
3580
+ UpsertMerchantProfileInputSchema,
3581
+ UpsertPartnerProfileInputSchema,
3582
+ WITHDRAWAL_STATES,
3583
+ WithdrawalSchema,
2859
3584
  bodySha256Hex,
2860
3585
  buildAuthorization,
2861
3586
  buildOAC,
@@ -2872,10 +3597,16 @@ export {
2872
3597
  crc16ccittHex,
2873
3598
  createAccountsClient,
2874
3599
  createApiCredentialsAdminClient,
3600
+ createCollectionsClient,
3601
+ createConsumerCollectionsClient,
3602
+ createConsumerWithdrawalsClient,
2875
3603
  createFlurPartnerClient,
2876
3604
  createHmacFetch,
2877
3605
  createMeOfflineClient,
2878
3606
  createOfflineSettlementsClient,
3607
+ createPartnerCollectionsClient,
3608
+ createPartnerFundingClient,
3609
+ createPartnerProfileAdminClient,
2879
3610
  createPassesClient,
2880
3611
  createReceiptsClient,
2881
3612
  decodeAuthorizationQR,