@nokinc-flur/sdk 1.0.4 → 1.0.6

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";
@@ -41,7 +41,9 @@ var OnboardingCompleteResponseSchema = z.object({
41
41
  sessionToken: z.string().min(1),
42
42
  userId: UuidSchema,
43
43
  restricted: z.boolean(),
44
- risk_reasons: z.array(z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])),
44
+ risk_reasons: z.array(
45
+ z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
46
+ ),
45
47
  stepUpRequired: z.boolean().optional(),
46
48
  riskStatus: z.enum(["ok", "unavailable"]).optional()
47
49
  });
@@ -94,9 +96,11 @@ var RegisterSendDeviceKeyRequestSchema = z.object({
94
96
  deviceId: z.string().min(3),
95
97
  publicKey: z.string().min(32)
96
98
  });
99
+ var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
97
100
  var SendChallengeRequestSchema = z.object({
98
101
  userId: UuidSchema,
99
- deviceId: z.string().min(3)
102
+ deviceId: z.string().min(3),
103
+ purpose: z.enum(SEND_AUTH_PURPOSES).optional()
100
104
  });
101
105
  var SendChallengeResponseSchema = z.object({
102
106
  challengeId: UuidSchema,
@@ -383,6 +387,341 @@ function moneyMinorToNumber(amountMinor) {
383
387
  return asNumber;
384
388
  }
385
389
 
390
+ // src/collections/client.ts
391
+ import { z as z3 } from "zod";
392
+ var MERCHANT_PROFILE_STATUSES = [
393
+ "pending",
394
+ "active",
395
+ "suspended",
396
+ "closed"
397
+ ];
398
+ var SETTLEMENT_SCHEDULES = ["manual", "daily", "t1"];
399
+ var COLLECTION_INTENT_STATUSES = [
400
+ "created",
401
+ "pending",
402
+ "paid",
403
+ "expired",
404
+ "cancelled",
405
+ "failed",
406
+ "reversed"
407
+ ];
408
+ var COLLECTION_PAYMENT_STATUSES = [
409
+ "pending",
410
+ "paid",
411
+ "failed",
412
+ "reversed"
413
+ ];
414
+ var MERCHANT_PAYOUT_STATUSES = [
415
+ "requested",
416
+ "processing",
417
+ "paid",
418
+ "failed",
419
+ "cancelled"
420
+ ];
421
+ var MoneyKoboSchema = z3.number().int().positive().max(Number.MAX_SAFE_INTEGER);
422
+ var MetadataSchema = z3.record(
423
+ z3.union([z3.string(), z3.number(), z3.boolean(), z3.null()])
424
+ );
425
+ var CurrencySchema2 = z3.string().trim().length(3).transform((value) => value.toUpperCase());
426
+ var ReferenceSchema = z3.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
427
+ var MerchantProfileSchema = z3.object({
428
+ accountId: z3.string().uuid(),
429
+ legalName: z3.string(),
430
+ tradingName: z3.string(),
431
+ merchantCategoryCode: z3.string().regex(/^\d{4}$/),
432
+ nqrMerchantId: z3.string(),
433
+ settlementBankCode: z3.string(),
434
+ settlementAccountNumber: z3.string(),
435
+ settlementAccountName: z3.string(),
436
+ settlementSchedule: z3.enum(SETTLEMENT_SCHEDULES),
437
+ status: z3.enum(MERCHANT_PROFILE_STATUSES),
438
+ offlineEnabled: z3.boolean(),
439
+ perTxLimitKobo: MoneyKoboSchema,
440
+ dailyLimitKobo: MoneyKoboSchema,
441
+ metadata: MetadataSchema,
442
+ createdAtMs: z3.number().int().nonnegative(),
443
+ updatedAtMs: z3.number().int().nonnegative()
444
+ });
445
+ var UpsertMerchantProfileInputSchema = z3.object({
446
+ legalName: z3.string().trim().min(1).max(200),
447
+ tradingName: z3.string().trim().min(1).max(25),
448
+ merchantCategoryCode: z3.string().trim().regex(/^\d{4}$/),
449
+ nqrMerchantId: z3.string().trim().min(3).max(64),
450
+ settlementBankCode: z3.string().trim().min(2).max(16),
451
+ settlementAccountNumber: z3.string().trim().min(5).max(32),
452
+ settlementAccountName: z3.string().trim().min(1).max(200),
453
+ settlementSchedule: z3.enum(SETTLEMENT_SCHEDULES).optional(),
454
+ status: z3.enum(MERCHANT_PROFILE_STATUSES).optional(),
455
+ offlineEnabled: z3.boolean().optional(),
456
+ perTxLimitKobo: MoneyKoboSchema.optional(),
457
+ dailyLimitKobo: MoneyKoboSchema.optional(),
458
+ metadata: MetadataSchema.optional()
459
+ });
460
+ var CollectionIntentSchema = z3.object({
461
+ intentId: z3.string().uuid(),
462
+ accountId: z3.string().uuid(),
463
+ terminalId: z3.string().uuid().nullable(),
464
+ reference: z3.string(),
465
+ amountKobo: z3.number().int().positive().nullable(),
466
+ currency: z3.string().length(3),
467
+ status: z3.enum(COLLECTION_INTENT_STATUSES),
468
+ description: z3.string().nullable(),
469
+ nqrPayload: z3.string(),
470
+ provider: z3.string(),
471
+ providerReference: z3.string().nullable(),
472
+ metadata: MetadataSchema,
473
+ expiresAtMs: z3.number().int().nonnegative().nullable(),
474
+ paidAtMs: z3.number().int().nonnegative().nullable(),
475
+ createdAtMs: z3.number().int().nonnegative(),
476
+ updatedAtMs: z3.number().int().nonnegative()
477
+ });
478
+ var CreateCollectionIntentInputSchema = z3.object({
479
+ reference: ReferenceSchema.optional(),
480
+ amountKobo: MoneyKoboSchema.optional(),
481
+ currency: CurrencySchema2.optional(),
482
+ terminalId: z3.string().uuid().optional(),
483
+ terminalLabel: z3.string().trim().min(1).max(25).optional(),
484
+ merchantCity: z3.string().trim().min(1).max(15).optional(),
485
+ description: z3.string().trim().min(1).max(280).optional(),
486
+ expiresAtMs: z3.number().int().positive().optional(),
487
+ provider: z3.string().trim().min(1).max(40).optional(),
488
+ metadata: MetadataSchema.optional()
489
+ });
490
+ var PublicCollectionIntentSchema = z3.object({
491
+ intentId: z3.string().uuid(),
492
+ reference: z3.string(),
493
+ amountKobo: z3.number().int().positive().nullable(),
494
+ currency: z3.string().length(3),
495
+ status: z3.enum(COLLECTION_INTENT_STATUSES),
496
+ merchantAccountId: z3.string().uuid(),
497
+ merchantName: z3.string(),
498
+ merchantCategoryCode: z3.string(),
499
+ description: z3.string().nullable(),
500
+ expiresAtMs: z3.number().int().nonnegative().nullable()
501
+ });
502
+ var PayCollectionInputSchema = z3.object({
503
+ reference: ReferenceSchema,
504
+ amountKobo: MoneyKoboSchema.optional(),
505
+ currency: CurrencySchema2.optional(),
506
+ idempotencyKey: z3.string().trim().min(8).max(160).optional()
507
+ });
508
+ var CollectionPaymentSchema = z3.object({
509
+ paymentId: z3.string().uuid(),
510
+ intentId: z3.string().uuid(),
511
+ accountId: z3.string().uuid(),
512
+ payerUserId: z3.string().uuid().nullable(),
513
+ merchantOwnerUserId: z3.string().uuid(),
514
+ amountKobo: MoneyKoboSchema,
515
+ currency: z3.string().length(3),
516
+ status: z3.enum(COLLECTION_PAYMENT_STATUSES),
517
+ provider: z3.string(),
518
+ providerReference: z3.string().nullable(),
519
+ idempotencyKey: z3.string().nullable(),
520
+ ledgerRef: z3.string(),
521
+ failureCode: z3.string().nullable(),
522
+ failureMessage: z3.string().nullable(),
523
+ paidAtMs: z3.number().int().nonnegative().nullable(),
524
+ createdAtMs: z3.number().int().nonnegative(),
525
+ updatedAtMs: z3.number().int().nonnegative()
526
+ });
527
+ var CollectionPaymentResultSchema = z3.object({
528
+ payment: CollectionPaymentSchema,
529
+ intent: CollectionIntentSchema,
530
+ receipt: z3.unknown().optional(),
531
+ replayed: z3.boolean()
532
+ });
533
+ var CollectionReportSummarySchema = z3.object({
534
+ accountId: z3.string().uuid(),
535
+ fromMs: z3.number().int().nonnegative(),
536
+ toMs: z3.number().int().nonnegative(),
537
+ currency: z3.string().length(3),
538
+ paidCount: z3.number().int().nonnegative(),
539
+ paidAmountKobo: z3.number().int().nonnegative(),
540
+ pendingCount: z3.number().int().nonnegative(),
541
+ failedCount: z3.number().int().nonnegative(),
542
+ reversedCount: z3.number().int().nonnegative(),
543
+ availableBalanceKobo: z3.number().int().nonnegative()
544
+ });
545
+ var CollectionStatementSchema = z3.object({
546
+ accountId: z3.string().uuid(),
547
+ year: z3.number().int(),
548
+ month: z3.number().int().min(1).max(12),
549
+ currency: z3.string().length(3),
550
+ totalPaidKobo: z3.number().int().nonnegative(),
551
+ items: z3.array(CollectionPaymentSchema)
552
+ });
553
+ var CreatePayoutInputSchema = z3.object({
554
+ amountKobo: MoneyKoboSchema,
555
+ currency: CurrencySchema2.optional(),
556
+ idempotencyKey: z3.string().trim().min(8).max(160)
557
+ });
558
+ var MerchantPayoutSchema = z3.object({
559
+ payoutId: z3.string().uuid(),
560
+ accountId: z3.string().uuid(),
561
+ amountKobo: MoneyKoboSchema,
562
+ currency: z3.string().length(3),
563
+ status: z3.enum(MERCHANT_PAYOUT_STATUSES),
564
+ idempotencyKey: z3.string().nullable(),
565
+ ledgerRef: z3.string(),
566
+ providerReference: z3.string().nullable(),
567
+ requestedByUserId: z3.string().uuid().nullable(),
568
+ failureCode: z3.string().nullable(),
569
+ failureMessage: z3.string().nullable(),
570
+ createdAtMs: z3.number().int().nonnegative(),
571
+ updatedAtMs: z3.number().int().nonnegative()
572
+ });
573
+ var ProviderEventInputSchema = z3.object({
574
+ provider: z3.string().trim().min(1).max(80),
575
+ eventId: z3.string().trim().min(1).max(160),
576
+ eventType: z3.string().trim().min(1).max(120),
577
+ payload: z3.record(z3.unknown()).optional()
578
+ });
579
+ var ProviderEventRecordSchema = z3.object({
580
+ id: z3.string().uuid(),
581
+ provider: z3.string(),
582
+ eventId: z3.string(),
583
+ eventType: z3.string(),
584
+ signatureVerified: z3.boolean(),
585
+ receivedAtMs: z3.number().int().nonnegative(),
586
+ processedAtMs: z3.number().int().nonnegative().nullable()
587
+ });
588
+ function createCollectionsClient(opts) {
589
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
590
+ if (!fetchImpl) {
591
+ throw new Error(
592
+ "createCollectionsClient: no fetch implementation available"
593
+ );
594
+ }
595
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
596
+ async function call(method, path, body, parser) {
597
+ const init2 = {
598
+ method,
599
+ headers: { accept: "application/json" }
600
+ };
601
+ if (body !== void 0) {
602
+ init2.body = JSON.stringify(body);
603
+ init2.headers = { ...init2.headers, "content-type": "application/json" };
604
+ }
605
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
606
+ const text = await resp.text();
607
+ let raw;
608
+ if (text) {
609
+ try {
610
+ raw = JSON.parse(text);
611
+ } catch {
612
+ raw = text;
613
+ }
614
+ }
615
+ if (!resp.ok) {
616
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
617
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
618
+ throw new FlurApiError(resp.status, code, message, raw);
619
+ }
620
+ return parser(raw);
621
+ }
622
+ return {
623
+ upsertMerchantProfile: (accountId, input) => call(
624
+ "PUT",
625
+ `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,
626
+ UpsertMerchantProfileInputSchema.parse(input),
627
+ (raw) => MerchantProfileSchema.parse(raw)
628
+ ),
629
+ getMerchantProfile: (accountId) => call(
630
+ "GET",
631
+ `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,
632
+ void 0,
633
+ (raw) => MerchantProfileSchema.parse(raw)
634
+ ),
635
+ createIntent: (input) => call(
636
+ "POST",
637
+ "/v1/collections/intents",
638
+ CreateCollectionIntentInputSchema.parse(input),
639
+ (raw) => CollectionIntentSchema.parse(raw)
640
+ ),
641
+ getIntent: (intentId) => call(
642
+ "GET",
643
+ `/v1/collections/intents/${encodeURIComponent(intentId)}`,
644
+ void 0,
645
+ (raw) => CollectionIntentSchema.parse(raw)
646
+ ),
647
+ resolveIntent: (reference) => call(
648
+ "GET",
649
+ `/v1/collections/resolve/${encodeURIComponent(reference)}`,
650
+ void 0,
651
+ (raw) => PublicCollectionIntentSchema.parse(raw)
652
+ ),
653
+ pay: (input) => call(
654
+ "POST",
655
+ "/v1/collections/pay",
656
+ PayCollectionInputSchema.parse(input),
657
+ (raw) => CollectionPaymentResultSchema.parse(raw)
658
+ ),
659
+ reportSummary: (input) => {
660
+ const qs = new URLSearchParams({
661
+ fromMs: String(input.fromMs),
662
+ toMs: String(input.toMs)
663
+ });
664
+ if (input.currency) qs.set("currency", input.currency);
665
+ return call(
666
+ "GET",
667
+ `/v1/collections/reports/summary?${qs.toString()}`,
668
+ void 0,
669
+ (raw) => CollectionReportSummarySchema.parse(raw)
670
+ );
671
+ },
672
+ monthlyStatement: (input) => {
673
+ const qs = new URLSearchParams({
674
+ year: String(input.year),
675
+ month: String(input.month)
676
+ });
677
+ if (input.currency) qs.set("currency", input.currency);
678
+ return call(
679
+ "GET",
680
+ `/v1/collections/statements/monthly?${qs.toString()}`,
681
+ void 0,
682
+ (raw) => CollectionStatementSchema.parse(raw)
683
+ );
684
+ },
685
+ createPayout: (input) => call(
686
+ "POST",
687
+ "/v1/collections/payouts",
688
+ CreatePayoutInputSchema.parse(input),
689
+ (raw) => MerchantPayoutSchema.parse(raw)
690
+ ),
691
+ getPayout: (payoutId) => call(
692
+ "GET",
693
+ `/v1/collections/payouts/${encodeURIComponent(payoutId)}`,
694
+ void 0,
695
+ (raw) => MerchantPayoutSchema.parse(raw)
696
+ ),
697
+ recordProviderEvent: (input) => call(
698
+ "POST",
699
+ "/v1/collections/provider-events",
700
+ ProviderEventInputSchema.parse(input),
701
+ (raw) => ProviderEventRecordSchema.parse(raw)
702
+ )
703
+ };
704
+ }
705
+ function createPartnerCollectionsClient(opts) {
706
+ const client = createCollectionsClient(opts);
707
+ return {
708
+ createIntent: client.createIntent,
709
+ getIntent: client.getIntent,
710
+ reportSummary: client.reportSummary,
711
+ monthlyStatement: client.monthlyStatement,
712
+ createPayout: client.createPayout,
713
+ getPayout: client.getPayout,
714
+ recordProviderEvent: client.recordProviderEvent
715
+ };
716
+ }
717
+ function createConsumerCollectionsClient(opts) {
718
+ const client = createCollectionsClient(opts);
719
+ return {
720
+ resolveIntent: client.resolveIntent,
721
+ pay: client.pay
722
+ };
723
+ }
724
+
386
725
  // src/client.ts
387
726
  var FlurClient = class {
388
727
  baseUrl;
@@ -396,10 +735,20 @@ var FlurClient = class {
396
735
  this.getExtraHeaders = opts.getExtraHeaders;
397
736
  }
398
737
  async health() {
399
- return this.requestJson("/health", { method: "GET" }, void 0, HealthResponseSchema);
738
+ return this.requestJson(
739
+ "/health",
740
+ { method: "GET" },
741
+ void 0,
742
+ HealthResponseSchema
743
+ );
400
744
  }
401
745
  async welcome() {
402
- return this.requestJson("/welcome", { method: "GET" }, void 0, WelcomeResponseSchema);
746
+ return this.requestJson(
747
+ "/welcome",
748
+ { method: "GET" },
749
+ void 0,
750
+ WelcomeResponseSchema
751
+ );
403
752
  }
404
753
  async onboardingStart(input) {
405
754
  return this.requestJson(
@@ -544,24 +893,33 @@ var FlurClient = class {
544
893
  }
545
894
  async registerBiometricDeviceKey(input) {
546
895
  const publicKey = await input.signer.getOrCreateKeyPair(input.deviceId);
547
- return this.registerSendDeviceKey({
548
- userId: input.userId,
549
- deviceId: input.deviceId,
550
- publicKey
551
- }, { accessToken: input.accessToken });
896
+ return this.registerSendDeviceKey(
897
+ {
898
+ userId: input.userId,
899
+ deviceId: input.deviceId,
900
+ publicKey
901
+ },
902
+ { accessToken: input.accessToken }
903
+ );
552
904
  }
553
905
  async authorizeSendWithBiometric(input) {
554
- const challenge = await this.createSendChallenge({
555
- userId: input.userId,
556
- deviceId: input.deviceId
557
- }, { accessToken: input.accessToken });
906
+ const challenge = await this.createSendChallenge(
907
+ {
908
+ userId: input.userId,
909
+ deviceId: input.deviceId
910
+ },
911
+ { accessToken: input.accessToken }
912
+ );
558
913
  const signature = await input.signer.sign(challenge.nonce);
559
- return this.verifySendChallenge({
560
- userId: input.userId,
561
- deviceId: input.deviceId,
562
- challengeId: challenge.challengeId,
563
- signature
564
- }, { accessToken: input.accessToken });
914
+ return this.verifySendChallenge(
915
+ {
916
+ userId: input.userId,
917
+ deviceId: input.deviceId,
918
+ challengeId: challenge.challengeId,
919
+ signature
920
+ },
921
+ { accessToken: input.accessToken }
922
+ );
565
923
  }
566
924
  async resolveRecipient(input, options) {
567
925
  return this.requestJson(
@@ -612,6 +970,36 @@ var FlurClient = class {
612
970
  }
613
971
  );
614
972
  }
973
+ async resolveCollection(reference, options) {
974
+ return this.requestJson(
975
+ `/v1/collections/resolve/${encodeURIComponent(reference)}`,
976
+ {
977
+ method: "GET",
978
+ headers: {
979
+ authorization: `Bearer ${options.accessToken}`
980
+ }
981
+ },
982
+ void 0,
983
+ PublicCollectionIntentSchema
984
+ );
985
+ }
986
+ async payCollection(input, options) {
987
+ const idempotencyKey = input.idempotencyKey ?? options.idempotencyKey ?? getSecureRandomUuid();
988
+ return this.requestJson(
989
+ "/v1/collections/pay",
990
+ {
991
+ method: "POST",
992
+ headers: {
993
+ "content-type": "application/json",
994
+ authorization: `Bearer ${options.accessToken}`,
995
+ "x-idempotency-key": idempotencyKey
996
+ }
997
+ },
998
+ PayCollectionInputSchema,
999
+ CollectionPaymentResultSchema,
1000
+ { ...input, idempotencyKey }
1001
+ );
1002
+ }
615
1003
  async accountSummary(options) {
616
1004
  return this.requestJson(
617
1005
  "/api/v1/account/summary",
@@ -710,7 +1098,7 @@ var FlurClient = class {
710
1098
  try {
711
1099
  body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
712
1100
  } catch (err) {
713
- if (err instanceof z3.ZodError) {
1101
+ if (err instanceof z4.ZodError) {
714
1102
  throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
715
1103
  details: err.flatten()
716
1104
  });
@@ -726,17 +1114,26 @@ var FlurClient = class {
726
1114
  ...init2.headers,
727
1115
  ...extraHeaders
728
1116
  };
729
- const res = await this.fetchImpl(url, { ...init2, headers: finalHeaders, body, signal: controller.signal });
1117
+ const res = await this.fetchImpl(url, {
1118
+ ...init2,
1119
+ headers: finalHeaders,
1120
+ body,
1121
+ signal: controller.signal
1122
+ });
730
1123
  if (!res.ok) throw await mapToFlurError(res);
731
1124
  const payload = await res.json();
732
1125
  if (!responseSchema) return payload;
733
1126
  try {
734
1127
  return responseSchema.parse(payload);
735
1128
  } catch (err) {
736
- if (err instanceof z3.ZodError) {
737
- throw new FlurError("SDK contract validation failed", "INVALID_REQUEST", {
738
- details: err.flatten()
739
- });
1129
+ if (err instanceof z4.ZodError) {
1130
+ throw new FlurError(
1131
+ "SDK contract validation failed",
1132
+ "INVALID_REQUEST",
1133
+ {
1134
+ details: err.flatten()
1135
+ }
1136
+ );
740
1137
  }
741
1138
  throw err;
742
1139
  }
@@ -745,7 +1142,9 @@ var FlurClient = class {
745
1142
  throw new FlurError("Request timed out", "TIMEOUT");
746
1143
  }
747
1144
  if (err instanceof FlurError) throw err;
748
- throw new FlurError("Network error", "NETWORK_ERROR", { details: String(err) });
1145
+ throw new FlurError("Network error", "NETWORK_ERROR", {
1146
+ details: String(err)
1147
+ });
749
1148
  } finally {
750
1149
  clearTimeout(t);
751
1150
  }
@@ -755,7 +1154,10 @@ function getSecureRandomUuid() {
755
1154
  if (typeof globalThis.crypto?.randomUUID === "function") {
756
1155
  return globalThis.crypto.randomUUID();
757
1156
  }
758
- throw new FlurError("Secure UUID generator unavailable; provide idempotencyKey", "INVALID_REQUEST");
1157
+ throw new FlurError(
1158
+ "Secure UUID generator unavailable; provide idempotencyKey",
1159
+ "INVALID_REQUEST"
1160
+ );
759
1161
  }
760
1162
 
761
1163
  // src/nqr/fields.ts
@@ -1182,24 +1584,24 @@ function verifyCanonical(value, signature, publicKey) {
1182
1584
  }
1183
1585
 
1184
1586
  // src/offline/oac.ts
1185
- import { z as z4 } from "zod";
1587
+ import { z as z5 } from "zod";
1186
1588
  var OAC_DEFAULT_PER_TX_KOBO = 5e5;
1187
1589
  var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
1188
1590
  var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
1189
- var HexString = (length) => z4.string().regex(
1591
+ var HexString = (length) => z5.string().regex(
1190
1592
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1191
1593
  `expected ${length}-byte hex string`
1192
1594
  );
1193
- var OACSchema = z4.object({
1194
- userId: z4.string().min(1),
1195
- deviceId: z4.string().min(1),
1595
+ var OACSchema = z5.object({
1596
+ userId: z5.string().min(1),
1597
+ deviceId: z5.string().min(1),
1196
1598
  devicePublicKey: HexString(32),
1197
- perTxCapKobo: z4.number().int().nonnegative(),
1198
- cumulativeCapKobo: z4.number().int().nonnegative(),
1199
- validFromMs: z4.number().int().nonnegative(),
1200
- validUntilMs: z4.number().int().positive(),
1201
- counterSeed: z4.number().int().nonnegative(),
1202
- nonce: z4.string().min(1),
1599
+ perTxCapKobo: z5.number().int().nonnegative(),
1600
+ cumulativeCapKobo: z5.number().int().nonnegative(),
1601
+ validFromMs: z5.number().int().nonnegative(),
1602
+ validUntilMs: z5.number().int().positive(),
1603
+ counterSeed: z5.number().int().nonnegative(),
1604
+ nonce: z5.string().min(1),
1203
1605
  issuerSig: HexString(64)
1204
1606
  }).refine((v) => v.validUntilMs > v.validFromMs, {
1205
1607
  message: "validUntilMs must be greater than validFromMs"
@@ -1306,19 +1708,19 @@ function decodeBase45(s) {
1306
1708
  }
1307
1709
 
1308
1710
  // src/offline/messages.ts
1309
- import { z as z5 } from "zod";
1310
- var HexSig = z5.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1311
- var OfflinePaymentRequestSchema = z5.object({
1312
- reference: z5.string().min(1),
1313
- amountKobo: z5.number().int().positive(),
1711
+ import { z as z6 } from "zod";
1712
+ var HexSig = z6.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1713
+ var OfflinePaymentRequestSchema = z6.object({
1714
+ reference: z6.string().min(1),
1715
+ amountKobo: z6.number().int().positive(),
1314
1716
  merchantOAC: OACSchema,
1315
- expiresAtMs: z5.number().int().positive(),
1717
+ expiresAtMs: z6.number().int().positive(),
1316
1718
  merchantSig: HexSig
1317
1719
  });
1318
- var OfflinePaymentAuthorizationSchema = z5.object({
1720
+ var OfflinePaymentAuthorizationSchema = z6.object({
1319
1721
  request: OfflinePaymentRequestSchema,
1320
1722
  payerOAC: OACSchema,
1321
- payerCounter: z5.number().int().positive(),
1723
+ payerCounter: z6.number().int().positive(),
1322
1724
  payerSig: HexSig
1323
1725
  });
1324
1726
  function buildPaymentRequest(input) {
@@ -1427,56 +1829,56 @@ function decodeAuthorizationQR(s) {
1427
1829
  }
1428
1830
 
1429
1831
  // src/offline/settlements.ts
1430
- import { z as z6 } from "zod";
1832
+ import { z as z7 } from "zod";
1431
1833
  import { sha256 } from "@noble/hashes/sha256";
1432
1834
  import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
1433
- var OfflineTokenSchema = z6.object({
1434
- tokenId: z6.string().uuid(),
1435
- tokenSerial: z6.string(),
1436
- issuerAccountId: z6.string().uuid(),
1437
- payerUserId: z6.string().uuid(),
1438
- maxAmountKobo: z6.number().int().positive(),
1439
- currency: z6.string().length(3),
1440
- issuedAtMs: z6.number().int().nonnegative(),
1441
- expiresAtMs: z6.number().int().nonnegative(),
1442
- issuerSig: z6.string()
1443
- });
1444
- var PaymentClaimSchema = z6.object({
1445
- encounterId: z6.string().regex(/^[0-9a-f]{64}$/i).optional(),
1446
- tokenSerial: z6.string(),
1447
- payerUserId: z6.string().uuid(),
1448
- payeeUserId: z6.string().uuid(),
1449
- payerNonce: z6.string(),
1450
- payeeNonce: z6.string(),
1451
- amountKobo: z6.number().int().positive(),
1452
- currency: z6.string().length(3).default("NGN"),
1453
- occurredAtMs: z6.number().int().nonnegative(),
1454
- completedAtMs: z6.number().int().nonnegative().optional(),
1455
- contextId: z6.string().optional(),
1456
- payerPubkey: z6.string().regex(/^[0-9a-f]{64}$/i),
1457
- payerSignature: z6.string().regex(/^[0-9a-f]+$/i),
1458
- payeePubkey: z6.string().regex(/^[0-9a-f]{64}$/i).optional(),
1459
- payeeSignature: z6.string().regex(/^[0-9a-f]+$/i).optional()
1460
- });
1461
- var SettlementSchema = z6.object({
1462
- settlementId: z6.string().uuid(),
1463
- settlementKey: z6.string().regex(/^[0-9a-f]{64}$/i),
1464
- encounterId: z6.string().regex(/^[0-9a-f]{64}$/i),
1465
- issuerAccountId: z6.string().uuid(),
1466
- tokenSerial: z6.string(),
1467
- payerUserId: z6.string().uuid(),
1468
- payeeUserId: z6.string().uuid(),
1469
- amountKobo: z6.number().int().nonnegative(),
1470
- currency: z6.string().length(3),
1471
- receiptId: z6.string().nullable(),
1472
- status: z6.enum(["SETTLED", "REVIEW", "REJECTED"]),
1473
- issuerSig: z6.string(),
1474
- createdAtMs: z6.number().int().nonnegative()
1475
- });
1476
- var SettleResponseSchema = z6.object({
1835
+ var OfflineTokenSchema = z7.object({
1836
+ tokenId: z7.string().uuid(),
1837
+ tokenSerial: z7.string(),
1838
+ issuerAccountId: z7.string().uuid(),
1839
+ payerUserId: z7.string().uuid(),
1840
+ maxAmountKobo: z7.number().int().positive(),
1841
+ currency: z7.string().length(3),
1842
+ issuedAtMs: z7.number().int().nonnegative(),
1843
+ expiresAtMs: z7.number().int().nonnegative(),
1844
+ issuerSig: z7.string()
1845
+ });
1846
+ var PaymentClaimSchema = z7.object({
1847
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i).optional(),
1848
+ tokenSerial: z7.string(),
1849
+ payerUserId: z7.string().uuid(),
1850
+ payeeUserId: z7.string().uuid(),
1851
+ payerNonce: z7.string(),
1852
+ payeeNonce: z7.string(),
1853
+ amountKobo: z7.number().int().positive(),
1854
+ currency: z7.string().length(3).default("NGN"),
1855
+ occurredAtMs: z7.number().int().nonnegative(),
1856
+ completedAtMs: z7.number().int().nonnegative().optional(),
1857
+ contextId: z7.string().optional(),
1858
+ payerPubkey: z7.string().regex(/^[0-9a-f]{64}$/i),
1859
+ payerSignature: z7.string().regex(/^[0-9a-f]+$/i),
1860
+ payeePubkey: z7.string().regex(/^[0-9a-f]{64}$/i).optional(),
1861
+ payeeSignature: z7.string().regex(/^[0-9a-f]+$/i).optional()
1862
+ });
1863
+ var SettlementSchema = z7.object({
1864
+ settlementId: z7.string().uuid(),
1865
+ settlementKey: z7.string().regex(/^[0-9a-f]{64}$/i),
1866
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i),
1867
+ issuerAccountId: z7.string().uuid(),
1868
+ tokenSerial: z7.string(),
1869
+ payerUserId: z7.string().uuid(),
1870
+ payeeUserId: z7.string().uuid(),
1871
+ amountKobo: z7.number().int().nonnegative(),
1872
+ currency: z7.string().length(3),
1873
+ receiptId: z7.string().nullable(),
1874
+ status: z7.enum(["SETTLED", "REVIEW", "REJECTED"]),
1875
+ issuerSig: z7.string(),
1876
+ createdAtMs: z7.number().int().nonnegative()
1877
+ });
1878
+ var SettleResponseSchema = z7.object({
1477
1879
  settlement: SettlementSchema,
1478
- encounterId: z6.string().regex(/^[0-9a-f]{64}$/i),
1479
- replayed: z6.boolean()
1880
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i),
1881
+ replayed: z7.boolean()
1480
1882
  });
1481
1883
  var ENCOUNTER_DOMAIN = "offline:v1:encounter";
1482
1884
  async function sha256Hex(input) {
@@ -1649,126 +2051,344 @@ function createHmacFetch(opts) {
1649
2051
  });
1650
2052
  }
1651
2053
 
1652
- // src/passes/pass.ts
1653
- import { z as z7 } from "zod";
1654
- var PASS_KINDS = [
1655
- "ride-ticket",
1656
- "transit-pass",
1657
- "event-ticket",
1658
- "voucher",
1659
- "loyalty",
1660
- "receipt-link"
1661
- ];
1662
- var PASS_STATES = [
1663
- "issued",
1664
- "active",
1665
- "redeemed",
1666
- "expired",
1667
- "revoked"
2054
+ // src/partner/client.ts
2055
+ import { z as z8 } from "zod";
2056
+ import { sha256 as sha2563 } from "@noble/hashes/sha256";
2057
+ import { hmac as hmac2 } from "@noble/hashes/hmac";
2058
+ import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils";
2059
+ var PARTNER_SCOPES = [
2060
+ "passes:write",
2061
+ "passes:read",
2062
+ "passes:redeem",
2063
+ "receipts:write",
2064
+ "receipts:read",
2065
+ "offline:issue",
2066
+ "offline:settle",
2067
+ "offline:read",
2068
+ "collections:write",
2069
+ "collections:read",
2070
+ "collections:pay",
2071
+ "collections:webhook",
2072
+ "reports:read",
2073
+ "payouts:write",
2074
+ "payouts:read",
2075
+ "partner:funding:write",
2076
+ "partner:payout:write",
2077
+ "partner:reconciliation:read"
1668
2078
  ];
1669
- var HexString2 = (length) => z7.string().regex(
1670
- new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1671
- `expected ${length}-byte hex string`
1672
- );
1673
- var PassMetadataSchema = z7.record(
1674
- z7.union([z7.string(), z7.number(), z7.boolean(), z7.null()])
1675
- );
1676
- var PassSchema = z7.object({
1677
- passId: z7.string().min(1),
1678
- /** Optional client/template grouping id (server may omit). */
1679
- templateId: z7.string().min(1).optional(),
1680
- /** Optional human-facing holder identity (server may omit). The cryptographic binding
1681
- * is `holderDevicePubkey` below. */
1682
- holderUserId: z7.string().min(1).optional(),
1683
- kind: z7.enum(PASS_KINDS),
1684
- issuerId: z7.string().min(1),
1685
- issuedAtMs: z7.number().int().nonnegative(),
1686
- validFromMs: z7.number().int().nonnegative(),
1687
- validUntilMs: z7.number().int().positive(),
1688
- state: z7.enum(PASS_STATES),
1689
- metadata: PassMetadataSchema,
1690
- nonce: z7.string().min(1),
1691
- /** Device id this pass is bound to (FK to backend `device_keys`). */
1692
- holderDeviceId: z7.string().min(1),
1693
- /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
1694
- * is verified against this key — it is the security-critical binding. */
1695
- holderDevicePubkey: HexString2(32),
1696
- /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
1697
- amountKobo: z7.number().int().nonnegative().optional(),
1698
- /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
1699
- currency: z7.string().min(3).max(8),
1700
- /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
1701
- counterSeed: z7.number().int().nonnegative(),
1702
- /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
1703
- cumulativeCapKobo: z7.number().int().nonnegative().optional(),
1704
- issuerSig: HexString2(64)
1705
- }).refine((v) => v.validUntilMs > v.validFromMs, {
1706
- message: "validUntilMs must be greater than validFromMs"
2079
+ var ApiCredentialPublicSchema = z8.object({
2080
+ id: z8.string().uuid(),
2081
+ accountId: z8.string().uuid(),
2082
+ keyId: z8.string(),
2083
+ scopes: z8.array(z8.enum(PARTNER_SCOPES)),
2084
+ label: z8.string().nullable(),
2085
+ createdAtMs: z8.number().int().nonnegative(),
2086
+ lastUsedAtMs: z8.number().int().nonnegative().nullable(),
2087
+ revokedAtMs: z8.number().int().nonnegative().nullable()
1707
2088
  });
1708
- function buildPass(input) {
1709
- if (input.validUntilMs <= input.validFromMs) {
1710
- throw new Error("validUntilMs must be greater than validFromMs");
1711
- }
1712
- const out = {
1713
- passId: input.passId,
1714
- kind: input.kind,
1715
- issuerId: input.issuerId,
1716
- issuedAtMs: input.issuedAtMs,
1717
- validFromMs: input.validFromMs,
1718
- validUntilMs: input.validUntilMs,
1719
- state: input.state,
1720
- metadata: input.metadata,
1721
- nonce: input.nonce,
1722
- holderDeviceId: input.holderDeviceId,
1723
- holderDevicePubkey: input.holderDevicePubkey,
1724
- currency: input.currency ?? "NGN",
1725
- counterSeed: input.counterSeed
1726
- };
1727
- if (typeof input.templateId === "string") out.templateId = input.templateId;
1728
- if (typeof input.holderUserId === "string")
1729
- out.holderUserId = input.holderUserId;
1730
- if (typeof input.amountKobo === "number") out.amountKobo = input.amountKobo;
1731
- if (typeof input.cumulativeCapKobo === "number") {
1732
- out.cumulativeCapKobo = input.cumulativeCapKobo;
1733
- }
1734
- return out;
2089
+ var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2090
+ secret: z8.string().min(1)
2091
+ });
2092
+ var enc = new TextEncoder();
2093
+ async function sha256Hex2(input) {
2094
+ const data = typeof input === "string" ? enc.encode(input) : input;
2095
+ return bytesToHex4(sha2563(data));
1735
2096
  }
1736
- function signPass(unsigned, issuerPrivateKey) {
1737
- const issuerSig = bytesToHex(
1738
- sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
1739
- );
1740
- return { ...unsigned, issuerSig };
2097
+ async function hmacSha256Hex(keyHex, message) {
2098
+ return bytesToHex4(hmac2(sha2563, enc.encode(keyHex), enc.encode(message)));
1741
2099
  }
1742
- function verifyPass(pass, issuerPublicKey) {
1743
- try {
1744
- const parsed = PassSchema.parse(pass);
1745
- const { issuerSig, ...unsigned } = parsed;
1746
- return verify(
1747
- canonicalJSONBytes(unsigned),
1748
- hexToBytes(issuerSig),
1749
- issuerPublicKey
1750
- );
1751
- } catch {
1752
- return false;
1753
- }
2100
+ function defaultNonce2() {
2101
+ const c = globalThis.crypto;
2102
+ if (c?.randomUUID) return c.randomUUID();
2103
+ return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
1754
2104
  }
1755
- function isPassWithinValidity(pass, nowMs) {
1756
- return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;
2105
+ function canonical(params) {
2106
+ return [
2107
+ params.method.toUpperCase(),
2108
+ params.path,
2109
+ params.ts,
2110
+ params.nonce,
2111
+ params.bodyHash
2112
+ ].join("\n");
1757
2113
  }
1758
-
2114
+ async function signPartnerRequest(params) {
2115
+ const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
2116
+ const nonce = params.nonce ?? defaultNonce2();
2117
+ const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
2118
+ const bodyHash = await sha256Hex2(bodyData);
2119
+ const message = canonical({
2120
+ method: params.method,
2121
+ path: params.path,
2122
+ ts,
2123
+ nonce,
2124
+ bodyHash
2125
+ });
2126
+ const signingKey = await sha256Hex2(params.secret);
2127
+ const sig = await hmacSha256Hex(signingKey, message);
2128
+ return {
2129
+ authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
2130
+ ts,
2131
+ nonce,
2132
+ bodyHash
2133
+ };
2134
+ }
2135
+ function createFlurPartnerClient(opts) {
2136
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2137
+ if (!fetchImpl) {
2138
+ throw new Error(
2139
+ "createFlurPartnerClient: no fetch implementation available"
2140
+ );
2141
+ }
2142
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2143
+ const scopeHeader = normalizeScopeHeader(opts.scope);
2144
+ async function makeSignedInit(method, path, body) {
2145
+ const sig = await signPartnerRequest({
2146
+ keyId: opts.keyId,
2147
+ secret: opts.secret,
2148
+ method,
2149
+ path,
2150
+ body: body ?? "",
2151
+ nowMs: opts.nowMs?.(),
2152
+ nonce: opts.nonce?.()
2153
+ });
2154
+ const headers = {
2155
+ authorization: sig.authorization,
2156
+ accept: "application/json"
2157
+ };
2158
+ if (scopeHeader) headers["x-flur-scope"] = scopeHeader;
2159
+ if (body !== void 0) headers["content-type"] = "application/json";
2160
+ const init2 = { method, headers };
2161
+ if (body !== void 0) init2.body = body;
2162
+ return init2;
2163
+ }
2164
+ async function request(opts2) {
2165
+ const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
2166
+ const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
2167
+ const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
2168
+ const text = await resp.text();
2169
+ let raw;
2170
+ if (text) {
2171
+ try {
2172
+ raw = JSON.parse(text);
2173
+ } catch {
2174
+ }
2175
+ }
2176
+ if (!resp.ok) {
2177
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2178
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2179
+ throw new FlurApiError(resp.status, code, message, raw);
2180
+ }
2181
+ return raw;
2182
+ }
2183
+ const fetchLike = async (input, init2) => {
2184
+ const url = typeof input === "string" ? input : input.toString();
2185
+ const u = new URL(url, baseUrl);
2186
+ const path = `${u.pathname}${u.search}`;
2187
+ const method = (init2?.method ?? "GET").toUpperCase();
2188
+ let bodyStr;
2189
+ if (init2?.body) {
2190
+ bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
2191
+ }
2192
+ const signed = await makeSignedInit(method, path, bodyStr);
2193
+ return fetchImpl(`${baseUrl}${path}`, {
2194
+ ...init2,
2195
+ ...signed,
2196
+ headers: {
2197
+ ...init2?.headers,
2198
+ ...signed.headers
2199
+ }
2200
+ });
2201
+ };
2202
+ return { request, fetch: fetchLike };
2203
+ }
2204
+ function normalizeScopeHeader(scope) {
2205
+ if (!scope || scope.length === 0) return void 0;
2206
+ const unique = Array.from(new Set(scope));
2207
+ for (const item of unique) {
2208
+ if (!PARTNER_SCOPES.includes(item)) {
2209
+ throw new Error(`unsupported partner scope: ${item}`);
2210
+ }
2211
+ }
2212
+ return unique.join(" ");
2213
+ }
2214
+ function createApiCredentialsAdminClient(opts) {
2215
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2216
+ if (!fetchImpl) {
2217
+ throw new Error(
2218
+ "createApiCredentialsAdminClient: no fetch implementation available"
2219
+ );
2220
+ }
2221
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2222
+ async function call(method, path, body, parser) {
2223
+ const init2 = {
2224
+ method,
2225
+ headers: {
2226
+ "content-type": "application/json",
2227
+ accept: "application/json"
2228
+ }
2229
+ };
2230
+ if (body !== void 0) init2.body = JSON.stringify(body);
2231
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2232
+ const text = await resp.text();
2233
+ let raw;
2234
+ if (text) {
2235
+ try {
2236
+ raw = JSON.parse(text);
2237
+ } catch {
2238
+ }
2239
+ }
2240
+ if (!resp.ok) {
2241
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2242
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2243
+ throw new FlurApiError(resp.status, code, message, raw);
2244
+ }
2245
+ return parser(raw);
2246
+ }
2247
+ const listSchema = z8.object({
2248
+ items: z8.array(ApiCredentialPublicSchema)
2249
+ });
2250
+ return {
2251
+ list: (accountId) => call(
2252
+ "GET",
2253
+ `/v1/accounts/${accountId}/api-credentials`,
2254
+ void 0,
2255
+ (raw) => listSchema.parse(raw)
2256
+ ),
2257
+ mint: (accountId, input) => call(
2258
+ "POST",
2259
+ `/v1/accounts/${accountId}/api-credentials`,
2260
+ input,
2261
+ (raw) => MintedApiCredentialSchema.parse(raw)
2262
+ ),
2263
+ revoke: (accountId, credentialId) => call(
2264
+ "DELETE",
2265
+ `/v1/accounts/${accountId}/api-credentials/${credentialId}`,
2266
+ void 0,
2267
+ (raw) => ApiCredentialPublicSchema.parse(raw)
2268
+ )
2269
+ };
2270
+ }
2271
+
2272
+ // src/passes/pass.ts
2273
+ import { z as z9 } from "zod";
2274
+ var PASS_KINDS = [
2275
+ "ride-ticket",
2276
+ "transit-pass",
2277
+ "event-ticket",
2278
+ "voucher",
2279
+ "loyalty",
2280
+ "receipt-link"
2281
+ ];
2282
+ var PASS_STATES = [
2283
+ "issued",
2284
+ "active",
2285
+ "redeemed",
2286
+ "expired",
2287
+ "revoked"
2288
+ ];
2289
+ var HexString2 = (length) => z9.string().regex(
2290
+ new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
2291
+ `expected ${length}-byte hex string`
2292
+ );
2293
+ var PassMetadataSchema = z9.record(
2294
+ z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
2295
+ );
2296
+ var PassSchema = z9.object({
2297
+ passId: z9.string().min(1),
2298
+ /** Optional client/template grouping id (server may omit). */
2299
+ templateId: z9.string().min(1).optional(),
2300
+ /** Optional human-facing holder identity (server may omit). The cryptographic binding
2301
+ * is `holderDevicePubkey` below. */
2302
+ holderUserId: z9.string().min(1).optional(),
2303
+ kind: z9.enum(PASS_KINDS),
2304
+ issuerId: z9.string().min(1),
2305
+ issuedAtMs: z9.number().int().nonnegative(),
2306
+ validFromMs: z9.number().int().nonnegative(),
2307
+ validUntilMs: z9.number().int().positive(),
2308
+ state: z9.enum(PASS_STATES),
2309
+ metadata: PassMetadataSchema,
2310
+ nonce: z9.string().min(1),
2311
+ /** Device id this pass is bound to (FK to backend `device_keys`). */
2312
+ holderDeviceId: z9.string().min(1),
2313
+ /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
2314
+ * is verified against this key — it is the security-critical binding. */
2315
+ holderDevicePubkey: HexString2(32),
2316
+ /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
2317
+ amountKobo: z9.number().int().nonnegative().optional(),
2318
+ /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
2319
+ currency: z9.string().min(3).max(8),
2320
+ /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
2321
+ counterSeed: z9.number().int().nonnegative(),
2322
+ /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
2323
+ cumulativeCapKobo: z9.number().int().nonnegative().optional(),
2324
+ issuerSig: HexString2(64)
2325
+ }).refine((v) => v.validUntilMs > v.validFromMs, {
2326
+ message: "validUntilMs must be greater than validFromMs"
2327
+ });
2328
+ function buildPass(input) {
2329
+ if (input.validUntilMs <= input.validFromMs) {
2330
+ throw new Error("validUntilMs must be greater than validFromMs");
2331
+ }
2332
+ const out = {
2333
+ passId: input.passId,
2334
+ kind: input.kind,
2335
+ issuerId: input.issuerId,
2336
+ issuedAtMs: input.issuedAtMs,
2337
+ validFromMs: input.validFromMs,
2338
+ validUntilMs: input.validUntilMs,
2339
+ state: input.state,
2340
+ metadata: input.metadata,
2341
+ nonce: input.nonce,
2342
+ holderDeviceId: input.holderDeviceId,
2343
+ holderDevicePubkey: input.holderDevicePubkey,
2344
+ currency: input.currency ?? "NGN",
2345
+ counterSeed: input.counterSeed
2346
+ };
2347
+ if (typeof input.templateId === "string") out.templateId = input.templateId;
2348
+ if (typeof input.holderUserId === "string")
2349
+ out.holderUserId = input.holderUserId;
2350
+ if (typeof input.amountKobo === "number") out.amountKobo = input.amountKobo;
2351
+ if (typeof input.cumulativeCapKobo === "number") {
2352
+ out.cumulativeCapKobo = input.cumulativeCapKobo;
2353
+ }
2354
+ return out;
2355
+ }
2356
+ function signPass(unsigned, issuerPrivateKey) {
2357
+ const issuerSig = bytesToHex(
2358
+ sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
2359
+ );
2360
+ return { ...unsigned, issuerSig };
2361
+ }
2362
+ function verifyPass(pass, issuerPublicKey) {
2363
+ try {
2364
+ const parsed = PassSchema.parse(pass);
2365
+ const { issuerSig, ...unsigned } = parsed;
2366
+ return verify(
2367
+ canonicalJSONBytes(unsigned),
2368
+ hexToBytes(issuerSig),
2369
+ issuerPublicKey
2370
+ );
2371
+ } catch {
2372
+ return false;
2373
+ }
2374
+ }
2375
+ function isPassWithinValidity(pass, nowMs) {
2376
+ return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;
2377
+ }
2378
+
1759
2379
  // src/passes/redemption.ts
1760
- import { z as z8 } from "zod";
1761
- var HexSig2 = z8.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1762
- var RedemptionSchema = z8.object({
2380
+ import { z as z10 } from "zod";
2381
+ var HexSig2 = z10.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
2382
+ var RedemptionSchema = z10.object({
1763
2383
  pass: PassSchema,
1764
- redeemerId: z8.string().min(1),
1765
- redeemedAtMs: z8.number().int().nonnegative(),
2384
+ redeemerId: z10.string().min(1),
2385
+ redeemedAtMs: z10.number().int().nonnegative(),
1766
2386
  /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
1767
2387
  * and > the redeemer's lastSeenCounter for this pass. */
1768
- counter: z8.number().int().positive(),
2388
+ counter: z10.number().int().positive(),
1769
2389
  /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
1770
- amountKobo: z8.number().int().nonnegative(),
1771
- nonce: z8.string().min(1),
2390
+ amountKobo: z10.number().int().nonnegative(),
2391
+ nonce: z10.string().min(1),
1772
2392
  holderSig: HexSig2
1773
2393
  });
1774
2394
  var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
@@ -1854,43 +2474,43 @@ function verifyRedemption(r, issuerPublicKey) {
1854
2474
  }
1855
2475
 
1856
2476
  // src/receipts/receipt.ts
1857
- import { z as z9 } from "zod";
2477
+ import { z as z11 } from "zod";
1858
2478
  var RECEIPT_CHANNELS = ["cash", "pass"];
1859
2479
  var RECEIPT_KINDS = RECEIPT_CHANNELS;
1860
- var HexString3 = (length) => z9.string().regex(
2480
+ var HexString3 = (length) => z11.string().regex(
1861
2481
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1862
2482
  `expected ${length}-byte hex string`
1863
2483
  );
1864
- var ReceiptPayloadSchema = z9.record(
1865
- z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
2484
+ var ReceiptPayloadSchema = z11.record(
2485
+ z11.union([z11.string(), z11.number(), z11.boolean(), z11.null()])
1866
2486
  );
1867
- var ReceiptSchema = z9.object({
1868
- receiptId: z9.string().min(1),
1869
- channel: z9.enum(RECEIPT_CHANNELS),
2487
+ var ReceiptSchema = z11.object({
2488
+ receiptId: z11.string().min(1),
2489
+ channel: z11.enum(RECEIPT_CHANNELS),
1870
2490
  /** Cash-channel: send_intents.id. Required when channel === 'cash'. */
1871
- intentId: z9.string().min(1).optional(),
2491
+ intentId: z11.string().min(1).optional(),
1872
2492
  /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
1873
- passRedemptionId: z9.string().min(1).optional(),
1874
- payerUserId: z9.string().min(1),
1875
- payeeUserId: z9.string().min(1),
1876
- amountKobo: z9.number().int().nonnegative(),
1877
- currency: z9.string().min(3).max(8),
1878
- issuedAtMs: z9.number().int().nonnegative(),
1879
- issuerId: z9.string().min(1),
2493
+ passRedemptionId: z11.string().min(1).optional(),
2494
+ payerUserId: z11.string().min(1),
2495
+ payeeUserId: z11.string().min(1),
2496
+ amountKobo: z11.number().int().nonnegative(),
2497
+ currency: z11.string().min(3).max(8),
2498
+ issuedAtMs: z11.number().int().nonnegative(),
2499
+ issuerId: z11.string().min(1),
1880
2500
  payload: ReceiptPayloadSchema,
1881
2501
  issuerSig: HexString3(64)
1882
2502
  }).superRefine((v, ctx) => {
1883
2503
  if (v.channel === "cash") {
1884
2504
  if (!v.intentId) {
1885
2505
  ctx.addIssue({
1886
- code: z9.ZodIssueCode.custom,
2506
+ code: z11.ZodIssueCode.custom,
1887
2507
  message: "cash receipts require intentId",
1888
2508
  path: ["intentId"]
1889
2509
  });
1890
2510
  }
1891
2511
  if (v.passRedemptionId) {
1892
2512
  ctx.addIssue({
1893
- code: z9.ZodIssueCode.custom,
2513
+ code: z11.ZodIssueCode.custom,
1894
2514
  message: "cash receipts must not carry passRedemptionId",
1895
2515
  path: ["passRedemptionId"]
1896
2516
  });
@@ -1898,14 +2518,14 @@ var ReceiptSchema = z9.object({
1898
2518
  } else if (v.channel === "pass") {
1899
2519
  if (!v.passRedemptionId) {
1900
2520
  ctx.addIssue({
1901
- code: z9.ZodIssueCode.custom,
2521
+ code: z11.ZodIssueCode.custom,
1902
2522
  message: "pass receipts require passRedemptionId",
1903
2523
  path: ["passRedemptionId"]
1904
2524
  });
1905
2525
  }
1906
2526
  if (v.intentId) {
1907
2527
  ctx.addIssue({
1908
- code: z9.ZodIssueCode.custom,
2528
+ code: z11.ZodIssueCode.custom,
1909
2529
  message: "pass receipts must not carry intentId",
1910
2530
  path: ["intentId"]
1911
2531
  });
@@ -2156,55 +2776,27 @@ function parseQR(payload) {
2156
2776
  return parseNQR(payload);
2157
2777
  }
2158
2778
  function init(opts) {
2159
- const signedFetch = createHmacFetch({
2160
- apiKey: opts.apiKey,
2161
- apiSecret: opts.apiSecret,
2779
+ const partner = createFlurPartnerClient({
2780
+ baseUrl: opts.baseUrl,
2781
+ keyId: opts.apiKey,
2782
+ secret: opts.apiSecret,
2162
2783
  fetchImpl: opts.fetchImpl,
2163
2784
  scope: opts.scope
2164
2785
  });
2786
+ const signedFetch = partner.fetch;
2165
2787
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2166
2788
  function subscribeToPayments(s) {
2167
- const controller = new AbortController();
2168
2789
  let cancelled = false;
2169
- (async () => {
2170
- try {
2171
- const url = `${baseUrl}/v1/payments/subscribe?reference=${encodeURIComponent(s.reference)}`;
2172
- const resp = await signedFetch(url, {
2173
- method: "GET",
2174
- headers: { accept: "text/event-stream" },
2175
- signal: controller.signal
2176
- });
2177
- if (!resp.body) return;
2178
- const reader = resp.body.getReader();
2179
- const decoder = new TextDecoder();
2180
- let buffer = "";
2181
- while (!cancelled) {
2182
- const { value, done } = await reader.read();
2183
- if (done) return;
2184
- buffer += decoder.decode(value, { stream: true });
2185
- let idx;
2186
- while ((idx = buffer.indexOf("\n\n")) >= 0) {
2187
- const chunk = buffer.slice(0, idx);
2188
- buffer = buffer.slice(idx + 2);
2189
- for (const line of chunk.split("\n")) {
2190
- if (!line.startsWith("data:")) continue;
2191
- const json = line.slice(5).trim();
2192
- if (!json) continue;
2193
- try {
2194
- s.onEvent(JSON.parse(json));
2195
- } catch (err) {
2196
- s.onError?.(err);
2197
- }
2198
- }
2199
- }
2200
- }
2201
- } catch (err) {
2202
- if (!cancelled) s.onError?.(err);
2203
- }
2204
- })();
2790
+ queueMicrotask(() => {
2791
+ if (cancelled) return;
2792
+ s.onError?.(
2793
+ new Error(
2794
+ "cash.subscribeToPayments is not available on this backend release; use collections reports or provider webhooks for payment status."
2795
+ )
2796
+ );
2797
+ });
2205
2798
  return () => {
2206
2799
  cancelled = true;
2207
- controller.abort();
2208
2800
  };
2209
2801
  }
2210
2802
  const cash = {
@@ -2215,6 +2807,10 @@ function init(opts) {
2215
2807
  };
2216
2808
  const passes = createPassesClient({ baseUrl, fetchImpl: signedFetch });
2217
2809
  const receipts = createReceiptsClient({ baseUrl, fetchImpl: signedFetch });
2810
+ const collections = createPartnerCollectionsClient({
2811
+ baseUrl,
2812
+ fetchImpl: signedFetch
2813
+ });
2218
2814
  return {
2219
2815
  // top-level back-compat surface
2220
2816
  generateStaticQR,
@@ -2223,29 +2819,30 @@ function init(opts) {
2223
2819
  subscribeToPayments,
2224
2820
  // namespaces
2225
2821
  cash,
2822
+ collections,
2226
2823
  passes,
2227
2824
  receipts
2228
2825
  };
2229
2826
  }
2230
2827
 
2231
2828
  // src/accounts/client.ts
2232
- import { z as z10 } from "zod";
2829
+ import { z as z12 } from "zod";
2233
2830
  var ACCOUNT_TYPES = ["personal", "business", "partner"];
2234
2831
  var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
2235
2832
  var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
2236
- var AccountSchema = z10.object({
2237
- accountId: z10.string().uuid(),
2238
- type: z10.enum(ACCOUNT_TYPES),
2239
- displayName: z10.string().min(1),
2240
- status: z10.enum(ACCOUNT_STATUSES),
2241
- ownerUserId: z10.string().uuid().nullable(),
2242
- createdAtMs: z10.number().int().nonnegative()
2243
- });
2244
- var AccountMembershipSchema = z10.object({
2245
- accountId: z10.string().uuid(),
2246
- userId: z10.string().uuid(),
2247
- role: z10.enum(MEMBERSHIP_ROLES),
2248
- createdAtMs: z10.number().int().nonnegative()
2833
+ var AccountSchema = z12.object({
2834
+ accountId: z12.string().uuid(),
2835
+ type: z12.enum(ACCOUNT_TYPES),
2836
+ displayName: z12.string().min(1),
2837
+ status: z12.enum(ACCOUNT_STATUSES),
2838
+ ownerUserId: z12.string().uuid().nullable(),
2839
+ createdAtMs: z12.number().int().nonnegative()
2840
+ });
2841
+ var AccountMembershipSchema = z12.object({
2842
+ accountId: z12.string().uuid(),
2843
+ userId: z12.string().uuid(),
2844
+ role: z12.enum(MEMBERSHIP_ROLES),
2845
+ createdAtMs: z12.number().int().nonnegative()
2249
2846
  });
2250
2847
  function createAccountsClient(opts) {
2251
2848
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -2278,9 +2875,9 @@ function createAccountsClient(opts) {
2278
2875
  }
2279
2876
  return parser(raw);
2280
2877
  }
2281
- const itemsSchema = z10.object({ items: z10.array(AccountSchema) });
2282
- const memberItemsSchema = z10.object({
2283
- items: z10.array(AccountMembershipSchema)
2878
+ const itemsSchema = z12.object({ items: z12.array(AccountSchema) });
2879
+ const memberItemsSchema = z12.object({
2880
+ items: z12.array(AccountMembershipSchema)
2284
2881
  });
2285
2882
  return {
2286
2883
  listMyAccounts: () => call(
@@ -2311,110 +2908,182 @@ function createAccountsClient(opts) {
2311
2908
  };
2312
2909
  }
2313
2910
 
2314
- // src/partner/client.ts
2315
- import { z as z11 } from "zod";
2316
- import { sha256 as sha2563 } from "@noble/hashes/sha256";
2317
- import { hmac as hmac2 } from "@noble/hashes/hmac";
2318
- import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils";
2319
- var PARTNER_SCOPES = [
2320
- "passes:write",
2321
- "passes:read",
2322
- "passes:redeem",
2323
- "receipts:write",
2324
- "receipts:read",
2325
- "offline:issue",
2326
- "offline:settle",
2327
- "offline:read"
2328
- ];
2329
- var ApiCredentialPublicSchema = z11.object({
2330
- id: z11.string().uuid(),
2331
- accountId: z11.string().uuid(),
2332
- keyId: z11.string(),
2333
- scopes: z11.array(z11.enum(PARTNER_SCOPES)),
2334
- label: z11.string().nullable(),
2335
- createdAtMs: z11.number().int().nonnegative(),
2336
- lastUsedAtMs: z11.number().int().nonnegative().nullable(),
2337
- revokedAtMs: z11.number().int().nonnegative().nullable()
2911
+ // src/me-offline/client.ts
2912
+ import { z as z13 } from "zod";
2913
+ var Hex64 = z13.string().regex(/^[0-9a-f]{64}$/i);
2914
+ var HexAny = z13.string().regex(/^[0-9a-f]+$/i);
2915
+ var Sha256Hex = z13.string().regex(/^[0-9a-f]{64}$/i);
2916
+ var RegisterDeviceKeyInputSchema = z13.object({
2917
+ deviceId: z13.string().min(1).max(128),
2918
+ publicKeyHex: Hex64
2338
2919
  });
2339
- var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2340
- secret: z11.string().min(1)
2920
+ var DeviceKeyRecordSchema = z13.object({
2921
+ id: z13.string().uuid(),
2922
+ userId: z13.string().uuid(),
2923
+ deviceId: z13.string(),
2924
+ publicKeyHex: Hex64,
2925
+ createdAtMs: z13.number().int().nonnegative(),
2926
+ revokedAtMs: z13.number().int().nonnegative().nullable()
2341
2927
  });
2342
- var enc = new TextEncoder();
2343
- async function sha256Hex2(input) {
2344
- const data = typeof input === "string" ? enc.encode(input) : input;
2345
- return bytesToHex4(sha2563(data));
2346
- }
2347
- async function hmacSha256Hex(keyHex, message) {
2348
- return bytesToHex4(hmac2(sha2563, enc.encode(keyHex), enc.encode(message)));
2349
- }
2350
- function defaultNonce2() {
2351
- const c = globalThis.crypto;
2352
- if (c?.randomUUID) return c.randomUUID();
2353
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
2354
- }
2355
- function canonical(params) {
2356
- return [
2357
- params.method.toUpperCase(),
2358
- params.path,
2359
- params.ts,
2360
- params.nonce,
2361
- params.bodyHash
2362
- ].join("\n");
2363
- }
2364
- async function signPartnerRequest(params) {
2365
- const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
2366
- const nonce = params.nonce ?? defaultNonce2();
2367
- const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
2368
- const bodyHash = await sha256Hex2(bodyData);
2369
- const message = canonical({
2370
- method: params.method,
2371
- path: params.path,
2372
- ts,
2373
- nonce,
2374
- bodyHash
2375
- });
2376
- const signingKey = await sha256Hex2(params.secret);
2377
- const sig = await hmacSha256Hex(signingKey, message);
2378
- return {
2379
- authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
2380
- ts,
2381
- nonce,
2382
- bodyHash
2383
- };
2384
- }
2385
- function createFlurPartnerClient(opts) {
2928
+ var ConsumerOACSchema = z13.object({
2929
+ oacId: z13.string().uuid(),
2930
+ issuerId: z13.string().min(1).max(64),
2931
+ userId: z13.string().uuid(),
2932
+ deviceId: z13.string().min(1).max(128),
2933
+ devicePubkeyHex: Hex64,
2934
+ perTxCapKobo: z13.number().int().positive(),
2935
+ cumulativeCapKobo: z13.number().int().positive(),
2936
+ currency: z13.string().length(3),
2937
+ validFromMs: z13.number().int().nonnegative(),
2938
+ validUntilMs: z13.number().int().nonnegative(),
2939
+ counterSeed: z13.number().int().nonnegative(),
2940
+ issuedAtMs: z13.number().int().nonnegative()
2941
+ });
2942
+ var SignedConsumerOACSchema = z13.object({
2943
+ oac: ConsumerOACSchema,
2944
+ issuerSig: HexAny,
2945
+ issuerPublicKeyHex: Hex64
2946
+ });
2947
+ var OACRecordSchema = SignedConsumerOACSchema.extend({
2948
+ currentOfflineSpentKobo: z13.number().int().nonnegative(),
2949
+ status: z13.enum([
2950
+ "active",
2951
+ "superseded",
2952
+ "expired",
2953
+ "revoked",
2954
+ "disabling",
2955
+ "draining",
2956
+ "closed"
2957
+ ]),
2958
+ supersededAtMs: z13.number().int().nonnegative().nullable(),
2959
+ revokedAtMs: z13.number().int().nonnegative().nullable(),
2960
+ holdId: z13.string().uuid().nullable().optional()
2961
+ });
2962
+ var IssueOACInputSchema = z13.object({
2963
+ deviceId: z13.string().min(1).max(128),
2964
+ perTxCapKobo: z13.number().int().positive().optional(),
2965
+ cumulativeCapKobo: z13.number().int().positive().optional(),
2966
+ ttlMs: z13.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2967
+ spendableOnlineKobo: z13.number().int().nonnegative().optional()
2968
+ });
2969
+ var EnableOfflineInputSchema = z13.object({
2970
+ deviceId: z13.string().min(1).max(128),
2971
+ amountKobo: z13.number().int().positive(),
2972
+ perTxCapKobo: z13.number().int().positive().optional(),
2973
+ ttlMs: z13.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2974
+ installId: z13.string().min(1).max(128),
2975
+ partnerId: z13.string().min(1).max(64).optional()
2976
+ });
2977
+ var DisableOfflineInputSchema = z13.object({
2978
+ deviceId: z13.string().min(1).max(128),
2979
+ installId: z13.string().min(1).max(128).optional(),
2980
+ claims: z13.array(z13.unknown()).max(256).optional()
2981
+ });
2982
+ var OfflineHoldRecordSchema = z13.object({
2983
+ holdId: z13.string().uuid(),
2984
+ userId: z13.string().uuid(),
2985
+ deviceId: z13.string(),
2986
+ partnerId: z13.string(),
2987
+ adapterKind: z13.string(),
2988
+ externalHoldRef: z13.string().nullable(),
2989
+ amountKobo: z13.number().int().nonnegative(),
2990
+ capturedKobo: z13.number().int().nonnegative(),
2991
+ releasedKobo: z13.number().int().nonnegative(),
2992
+ remainingKobo: z13.number().int().nonnegative(),
2993
+ currency: z13.string().length(3),
2994
+ status: z13.enum([
2995
+ "placing",
2996
+ "active",
2997
+ "disabling",
2998
+ "draining",
2999
+ "closed",
3000
+ "revoked",
3001
+ "failed"
3002
+ ]),
3003
+ installId: z13.string().nullable(),
3004
+ drainDeadlineMs: z13.number().int().nonnegative(),
3005
+ disableRequestedAtMs: z13.number().int().nonnegative().nullable(),
3006
+ createdAtMs: z13.number().int().nonnegative(),
3007
+ closedAtMs: z13.number().int().nonnegative().nullable(),
3008
+ isTrusted: z13.boolean().optional()
3009
+ });
3010
+ var EnableOfflineResultSchema = z13.object({
3011
+ hold: OfflineHoldRecordSchema,
3012
+ oac: OACRecordSchema
3013
+ });
3014
+ var DisableOfflineResultSchema = z13.object({
3015
+ hold: OfflineHoldRecordSchema,
3016
+ trusted: z13.boolean(),
3017
+ settledClaims: z13.number().int().nonnegative()
3018
+ });
3019
+ var OfflineStatusResultSchema = z13.object({
3020
+ hold: OfflineHoldRecordSchema.nullable(),
3021
+ active: OACRecordSchema.nullable()
3022
+ });
3023
+ var OfflineStateResultSchema = z13.object({
3024
+ active: OACRecordSchema.nullable()
3025
+ });
3026
+ var ConsumerPaymentClaimSchema = z13.object({
3027
+ oacId: z13.string().uuid(),
3028
+ encounterId: Sha256Hex.optional(),
3029
+ payerUserId: z13.string().uuid(),
3030
+ payeeUserId: z13.string().uuid(),
3031
+ payerDeviceId: z13.string().min(1).max(128),
3032
+ payerNonce: z13.string().min(8).max(128),
3033
+ payeeNonce: z13.string().min(8).max(128),
3034
+ amountKobo: z13.number().int().positive(),
3035
+ currency: z13.string().length(3).default("NGN"),
3036
+ occurredAtMs: z13.number().int().nonnegative(),
3037
+ completedAtMs: z13.number().int().nonnegative().optional(),
3038
+ contextId: z13.string().max(128).optional(),
3039
+ payerPubkeyHex: Hex64,
3040
+ payerSignature: HexAny,
3041
+ payeePubkeyHex: Hex64.optional(),
3042
+ payeeSignature: HexAny.optional()
3043
+ });
3044
+ var ConsumerSettlementSchema = z13.object({
3045
+ settlementId: z13.string().uuid(),
3046
+ settlementKey: Sha256Hex,
3047
+ encounterId: Sha256Hex,
3048
+ oacId: z13.string().uuid(),
3049
+ payerUserId: z13.string().uuid(),
3050
+ payeeUserId: z13.string().uuid(),
3051
+ amountKobo: z13.number().int().positive(),
3052
+ currency: z13.string().length(3),
3053
+ status: z13.enum(["SETTLED", "REVIEW"]),
3054
+ reviewReason: z13.string().nullable(),
3055
+ ledgerRef: z13.string().nullable(),
3056
+ issuerSig: HexAny,
3057
+ createdAtMs: z13.number().int().nonnegative()
3058
+ });
3059
+ var ConsumerSettleResultSchema = z13.object({
3060
+ settlement: ConsumerSettlementSchema,
3061
+ encounterId: Sha256Hex,
3062
+ replayed: z13.boolean()
3063
+ });
3064
+ var RevokeDeviceKeyInputSchema = z13.object({
3065
+ deviceId: z13.string().min(1).max(128),
3066
+ /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
3067
+ sendAuthToken: z13.string().min(16)
3068
+ });
3069
+ function createMeOfflineClient(opts) {
2386
3070
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2387
3071
  if (!fetchImpl) {
2388
- throw new Error(
2389
- "createFlurPartnerClient: no fetch implementation available"
2390
- );
3072
+ throw new Error("createMeOfflineClient: no fetch implementation available");
2391
3073
  }
2392
3074
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2393
- async function makeSignedInit(method, path, body) {
2394
- const sig = await signPartnerRequest({
2395
- keyId: opts.keyId,
2396
- secret: opts.secret,
3075
+ async function call(method, path, body, parser) {
3076
+ const init2 = {
2397
3077
  method,
2398
- path,
2399
- body: body ?? "",
2400
- nowMs: opts.nowMs?.(),
2401
- nonce: opts.nonce?.()
2402
- });
2403
- const headers = {
2404
- authorization: sig.authorization,
2405
- accept: "application/json"
3078
+ headers: {
3079
+ "content-type": "application/json",
3080
+ accept: "application/json"
3081
+ }
2406
3082
  };
2407
- if (body !== void 0) headers["content-type"] = "application/json";
2408
- const init2 = { method, headers };
2409
- if (body !== void 0) init2.body = body;
2410
- return init2;
2411
- }
2412
- async function request(opts2) {
2413
- const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
2414
- const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
2415
- const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
3083
+ if (body !== void 0) init2.body = JSON.stringify(body);
3084
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2416
3085
  const text = await resp.text();
2417
- let raw;
3086
+ let raw = void 0;
2418
3087
  if (text) {
2419
3088
  try {
2420
3089
  raw = JSON.parse(text);
@@ -2426,46 +3095,290 @@ function createFlurPartnerClient(opts) {
2426
3095
  const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2427
3096
  throw new FlurApiError(resp.status, code, message, raw);
2428
3097
  }
2429
- return raw;
3098
+ return parser(raw);
2430
3099
  }
2431
- const fetchLike = async (input, init2) => {
2432
- const url = typeof input === "string" ? input : input.toString();
2433
- const u = new URL(url, baseUrl);
2434
- const path = `${u.pathname}${u.search}`;
2435
- const method = (init2?.method ?? "GET").toUpperCase();
2436
- let bodyStr;
2437
- if (init2?.body) {
2438
- bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
3100
+ const deviceKeyItems = z13.object({ items: z13.array(DeviceKeyRecordSchema) });
3101
+ return {
3102
+ registerDeviceKey: (input) => call(
3103
+ "POST",
3104
+ "/v1/me/offline/keys",
3105
+ RegisterDeviceKeyInputSchema.parse(input),
3106
+ (raw) => DeviceKeyRecordSchema.parse(raw)
3107
+ ),
3108
+ listDeviceKeys: () => call(
3109
+ "GET",
3110
+ "/v1/me/offline/keys",
3111
+ void 0,
3112
+ (raw) => deviceKeyItems.parse(raw)
3113
+ ),
3114
+ revokeDeviceKey: (input) => call(
3115
+ "POST",
3116
+ "/v1/me/offline/keys/revoke",
3117
+ RevokeDeviceKeyInputSchema.parse(input),
3118
+ () => void 0
3119
+ ),
3120
+ enable: (input) => call(
3121
+ "POST",
3122
+ "/v1/me/offline/enable",
3123
+ EnableOfflineInputSchema.parse(input),
3124
+ (raw) => EnableOfflineResultSchema.parse(raw)
3125
+ ),
3126
+ refresh: (input) => call(
3127
+ "POST",
3128
+ "/v1/me/offline/refresh",
3129
+ IssueOACInputSchema.parse(input),
3130
+ (raw) => OACRecordSchema.parse(raw)
3131
+ ),
3132
+ disable: (input) => call(
3133
+ "POST",
3134
+ "/v1/me/offline/disable",
3135
+ DisableOfflineInputSchema.parse(input),
3136
+ (raw) => DisableOfflineResultSchema.parse(raw)
3137
+ ),
3138
+ getStatus: (deviceId) => {
3139
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3140
+ return call(
3141
+ "GET",
3142
+ `/v1/me/offline/status${qs}`,
3143
+ void 0,
3144
+ (raw) => OfflineStatusResultSchema.parse(raw)
3145
+ );
3146
+ },
3147
+ getState: (deviceId) => {
3148
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3149
+ return call(
3150
+ "GET",
3151
+ `/v1/me/offline/state${qs}`,
3152
+ void 0,
3153
+ (raw) => OfflineStateResultSchema.parse(raw)
3154
+ );
3155
+ },
3156
+ submitClaim: (claim) => call(
3157
+ "POST",
3158
+ "/v1/me/offline/claims",
3159
+ ConsumerPaymentClaimSchema.parse(claim),
3160
+ (raw) => ConsumerSettleResultSchema.parse(raw)
3161
+ )
3162
+ };
3163
+ }
3164
+
3165
+ // src/partner-funding/client.ts
3166
+ import { z as z14 } from "zod";
3167
+ var MinorString = z14.string().regex(/^-?\d+$/);
3168
+ var PositiveMinor = z14.union([
3169
+ z14.number().int().positive(),
3170
+ z14.string().regex(/^[1-9]\d{0,18}$/)
3171
+ ]);
3172
+ var Currency = z14.string().trim().length(3).transform((v) => v.toUpperCase());
3173
+ var Metadata = z14.record(z14.unknown());
3174
+ var PARTNER_KINDS = ["bank", "merchant"];
3175
+ var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
3176
+ var PARTNER_PROFILE_STATUSES = [
3177
+ "active",
3178
+ "suspended",
3179
+ "closed"
3180
+ ];
3181
+ var PARTNER_FUNDING_DIRECTIONS = ["credit", "debit"];
3182
+ var PARTNER_FUNDING_STATUSES = [
3183
+ "pending",
3184
+ "posted",
3185
+ "failed"
3186
+ ];
3187
+ var PAYOUT_DESTINATION_STATUSES = [
3188
+ "pending",
3189
+ "verified",
3190
+ "disabled"
3191
+ ];
3192
+ var WITHDRAWAL_STATES = [
3193
+ "requested",
3194
+ "submitted",
3195
+ "processing",
3196
+ "paid",
3197
+ "failed",
3198
+ "reversed"
3199
+ ];
3200
+ var PartnerProfileSchema = z14.object({
3201
+ partnerAccountId: z14.string().uuid(),
3202
+ kind: z14.enum(PARTNER_KINDS),
3203
+ custodialMode: z14.enum(CUSTODIAL_MODES),
3204
+ displayName: z14.string(),
3205
+ bankCode: z14.string().nullable(),
3206
+ poolAccountNumber: z14.string().nullable(),
3207
+ status: z14.enum(PARTNER_PROFILE_STATUSES),
3208
+ metadata: Metadata,
3209
+ createdAtMs: z14.number().int().nonnegative(),
3210
+ updatedAtMs: z14.number().int().nonnegative()
3211
+ });
3212
+ var UpsertPartnerProfileInputSchema = z14.object({
3213
+ kind: z14.enum(PARTNER_KINDS),
3214
+ custodialMode: z14.enum(CUSTODIAL_MODES),
3215
+ displayName: z14.string().trim().min(1).max(200),
3216
+ bankCode: z14.string().trim().min(1).max(64).optional(),
3217
+ poolAccountNumber: z14.string().trim().min(1).max(64).optional(),
3218
+ metadata: Metadata.optional()
3219
+ });
3220
+ var PartnerFundingEventInputSchema = z14.object({
3221
+ externalRef: z14.string().trim().min(8).max(128),
3222
+ direction: z14.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
3223
+ userId: z14.string().uuid().optional(),
3224
+ accountId: z14.string().uuid().optional(),
3225
+ amountMinor: PositiveMinor,
3226
+ currency: Currency,
3227
+ fundingSource: z14.string().trim().min(1).max(64).optional(),
3228
+ providerMetadata: Metadata.optional()
3229
+ });
3230
+ var PartnerFundingSchema = z14.object({
3231
+ fundingId: z14.string().uuid(),
3232
+ partnerId: z14.string().uuid(),
3233
+ accountId: z14.string().uuid(),
3234
+ userId: z14.string().uuid().nullable(),
3235
+ direction: z14.enum(PARTNER_FUNDING_DIRECTIONS),
3236
+ currency: z14.string(),
3237
+ amountMinor: MinorString,
3238
+ externalRef: z14.string(),
3239
+ status: z14.enum(PARTNER_FUNDING_STATUSES),
3240
+ fundingSource: z14.string(),
3241
+ ledgerRef: z14.string(),
3242
+ providerMetadata: Metadata,
3243
+ createdAtMs: z14.number().int().nonnegative(),
3244
+ updatedAtMs: z14.number().int().nonnegative()
3245
+ });
3246
+ var IngestFundingResultSchema = z14.object({
3247
+ funding: PartnerFundingSchema,
3248
+ replayed: z14.boolean()
3249
+ });
3250
+ var PayoutDestinationSchema = z14.object({
3251
+ destinationId: z14.string().uuid(),
3252
+ accountId: z14.string().uuid(),
3253
+ partnerId: z14.string().uuid(),
3254
+ bankCode: z14.string(),
3255
+ accountNumber: z14.string(),
3256
+ accountName: z14.string(),
3257
+ status: z14.enum(PAYOUT_DESTINATION_STATUSES),
3258
+ verifiedAtMs: z14.number().int().nonnegative().nullable(),
3259
+ metadata: Metadata,
3260
+ createdAtMs: z14.number().int().nonnegative(),
3261
+ updatedAtMs: z14.number().int().nonnegative()
3262
+ });
3263
+ var CreatePayoutDestinationInputSchema = z14.object({
3264
+ partnerId: z14.string().uuid(),
3265
+ bankCode: z14.string().trim().min(1).max(32),
3266
+ accountNumber: z14.string().trim().min(4).max(64),
3267
+ accountName: z14.string().trim().min(1).max(200),
3268
+ metadata: Metadata.optional()
3269
+ });
3270
+ var ListPayoutDestinationsResultSchema = z14.object({
3271
+ items: z14.array(PayoutDestinationSchema)
3272
+ });
3273
+ var WithdrawalSchema = z14.object({
3274
+ withdrawalId: z14.string().uuid(),
3275
+ accountId: z14.string().uuid(),
3276
+ userId: z14.string().uuid(),
3277
+ partnerId: z14.string().uuid(),
3278
+ destinationId: z14.string().uuid(),
3279
+ currency: z14.string(),
3280
+ amountMinor: MinorString,
3281
+ state: z14.enum(WITHDRAWAL_STATES),
3282
+ idempotencyKey: z14.string(),
3283
+ providerRef: z14.string().nullable(),
3284
+ lastError: z14.string().nullable(),
3285
+ ledgerRef: z14.string(),
3286
+ reverseLedgerRef: z14.string().nullable(),
3287
+ metadata: Metadata,
3288
+ createdAtMs: z14.number().int().nonnegative(),
3289
+ updatedAtMs: z14.number().int().nonnegative()
3290
+ });
3291
+ var CreateWithdrawalInputSchema = z14.object({
3292
+ destinationId: z14.string().uuid(),
3293
+ amountMinor: PositiveMinor,
3294
+ currency: Currency,
3295
+ idempotencyKey: z14.string().trim().min(8).max(128),
3296
+ metadata: Metadata.optional()
3297
+ });
3298
+ var CreateWithdrawalResultSchema = z14.object({
3299
+ withdrawal: WithdrawalSchema,
3300
+ replayed: z14.boolean()
3301
+ });
3302
+ var PayoutEventInputSchema = z14.object({
3303
+ externalRef: z14.string().trim().min(8).max(128),
3304
+ withdrawalId: z14.string().uuid().optional(),
3305
+ state: z14.enum(["submitted", "processing", "paid", "failed"]),
3306
+ providerRef: z14.string().trim().min(1).max(128).optional(),
3307
+ failureCode: z14.string().trim().max(64).optional(),
3308
+ failureMessage: z14.string().trim().max(512).optional(),
3309
+ providerMetadata: Metadata.optional()
3310
+ });
3311
+ var RecordPayoutEventResultSchema = z14.object({
3312
+ withdrawal: WithdrawalSchema,
3313
+ replayed: z14.boolean()
3314
+ });
3315
+ var ReconciliationReportSchema = z14.object({
3316
+ partnerId: z14.string().uuid(),
3317
+ currency: z14.string(),
3318
+ fromMs: z14.number().int().nonnegative(),
3319
+ toMs: z14.number().int().nonnegative(),
3320
+ fundingsCreditMinor: MinorString,
3321
+ fundingsDebitMinor: MinorString,
3322
+ withdrawalsPaidMinor: MinorString,
3323
+ withdrawalsReversedMinor: MinorString,
3324
+ withdrawalsInFlightMinor: MinorString,
3325
+ expectedReserveBalanceMinor: MinorString,
3326
+ actualReserveBalanceMinor: MinorString,
3327
+ imbalanceMinor: MinorString,
3328
+ generatedAtMs: z14.number().int().nonnegative()
3329
+ });
3330
+ function createPartnerFundingClient(partner) {
3331
+ return {
3332
+ ingestFunding: async (input) => {
3333
+ const body = PartnerFundingEventInputSchema.parse(input);
3334
+ const raw = await partner.request({
3335
+ method: "POST",
3336
+ path: "/v1/partners/fundings",
3337
+ body
3338
+ });
3339
+ return IngestFundingResultSchema.parse(raw);
3340
+ },
3341
+ recordPayoutEvent: async (input) => {
3342
+ const body = PayoutEventInputSchema.parse(input);
3343
+ const raw = await partner.request({
3344
+ method: "POST",
3345
+ path: "/v1/partners/payouts/events",
3346
+ body
3347
+ });
3348
+ return RecordPayoutEventResultSchema.parse(raw);
3349
+ },
3350
+ reconciliation: async (input) => {
3351
+ const qs = new URLSearchParams({
3352
+ currency: input.currency
3353
+ });
3354
+ if (typeof input.fromMs === "number")
3355
+ qs.set("fromMs", String(input.fromMs));
3356
+ if (typeof input.toMs === "number") qs.set("toMs", String(input.toMs));
3357
+ const raw = await partner.request({
3358
+ method: "GET",
3359
+ path: `/v1/partners/reconciliation/daily?${qs.toString()}`
3360
+ });
3361
+ return ReconciliationReportSchema.parse(raw);
2439
3362
  }
2440
- const signed = await makeSignedInit(method, path, bodyStr);
2441
- return fetchImpl(`${baseUrl}${path}`, {
2442
- ...init2,
2443
- ...signed,
2444
- headers: {
2445
- ...init2?.headers,
2446
- ...signed.headers
2447
- }
2448
- });
2449
3363
  };
2450
- return { request, fetch: fetchLike };
2451
3364
  }
2452
- function createApiCredentialsAdminClient(opts) {
3365
+ function createConsumerWithdrawalsClient(opts) {
2453
3366
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2454
3367
  if (!fetchImpl) {
2455
3368
  throw new Error(
2456
- "createApiCredentialsAdminClient: no fetch implementation available"
3369
+ "createConsumerWithdrawalsClient: no fetch implementation available"
2457
3370
  );
2458
3371
  }
2459
3372
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2460
3373
  async function call(method, path, body, parser) {
2461
3374
  const init2 = {
2462
3375
  method,
2463
- headers: {
2464
- "content-type": "application/json",
2465
- accept: "application/json"
2466
- }
3376
+ headers: { accept: "application/json" }
2467
3377
  };
2468
- if (body !== void 0) init2.body = JSON.stringify(body);
3378
+ if (body !== void 0) {
3379
+ init2.body = JSON.stringify(body);
3380
+ init2.headers = { ...init2.headers, "content-type": "application/json" };
3381
+ }
2469
3382
  const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2470
3383
  const text = await resp.text();
2471
3384
  let raw;
@@ -2473,6 +3386,7 @@ function createApiCredentialsAdminClient(opts) {
2473
3386
  try {
2474
3387
  raw = JSON.parse(text);
2475
3388
  } catch {
3389
+ raw = text;
2476
3390
  }
2477
3391
  }
2478
3392
  if (!resp.ok) {
@@ -2482,30 +3396,85 @@ function createApiCredentialsAdminClient(opts) {
2482
3396
  }
2483
3397
  return parser(raw);
2484
3398
  }
2485
- const listSchema = z11.object({
2486
- items: z11.array(ApiCredentialPublicSchema)
2487
- });
2488
3399
  return {
2489
- list: (accountId) => call(
3400
+ listDestinations: () => call(
2490
3401
  "GET",
2491
- `/v1/accounts/${accountId}/api-credentials`,
3402
+ "/v1/me/payout-destinations",
2492
3403
  void 0,
2493
- (raw) => listSchema.parse(raw)
3404
+ (raw) => ListPayoutDestinationsResultSchema.parse(raw)
2494
3405
  ),
2495
- mint: (accountId, input) => call(
3406
+ createDestination: (input) => call(
2496
3407
  "POST",
2497
- `/v1/accounts/${accountId}/api-credentials`,
2498
- input,
2499
- (raw) => MintedApiCredentialSchema.parse(raw)
3408
+ "/v1/me/payout-destinations",
3409
+ CreatePayoutDestinationInputSchema.parse(input),
3410
+ (raw) => PayoutDestinationSchema.parse(raw)
2500
3411
  ),
2501
- revoke: (accountId, credentialId) => call(
2502
- "DELETE",
2503
- `/v1/accounts/${accountId}/api-credentials/${credentialId}`,
3412
+ verifyDestination: (destinationId) => call(
3413
+ "POST",
3414
+ `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/verify`,
3415
+ {},
3416
+ (raw) => PayoutDestinationSchema.parse(raw)
3417
+ ),
3418
+ disableDestination: (destinationId) => call(
3419
+ "POST",
3420
+ `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/disable`,
3421
+ {},
3422
+ (raw) => PayoutDestinationSchema.parse(raw)
3423
+ ),
3424
+ createWithdrawal: (input) => call(
3425
+ "POST",
3426
+ "/v1/me/withdrawals",
3427
+ CreateWithdrawalInputSchema.parse(input),
3428
+ (raw) => CreateWithdrawalResultSchema.parse(raw)
3429
+ ),
3430
+ getWithdrawal: (withdrawalId) => call(
3431
+ "GET",
3432
+ `/v1/me/withdrawals/${encodeURIComponent(withdrawalId)}`,
2504
3433
  void 0,
2505
- (raw) => ApiCredentialPublicSchema.parse(raw)
3434
+ (raw) => WithdrawalSchema.parse(raw)
2506
3435
  )
2507
3436
  };
2508
3437
  }
3438
+ function createPartnerProfileAdminClient(opts) {
3439
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3440
+ if (!fetchImpl) {
3441
+ throw new Error(
3442
+ "createPartnerProfileAdminClient: no fetch implementation available"
3443
+ );
3444
+ }
3445
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
3446
+ return {
3447
+ upsertProfile: async (partnerAccountId, input) => {
3448
+ const body = {
3449
+ partnerAccountId,
3450
+ ...UpsertPartnerProfileInputSchema.parse(input)
3451
+ };
3452
+ const resp = await fetchImpl(`${baseUrl}/v1/partners/profile`, {
3453
+ method: "POST",
3454
+ headers: {
3455
+ "content-type": "application/json",
3456
+ accept: "application/json"
3457
+ },
3458
+ body: JSON.stringify(body)
3459
+ });
3460
+ const text = await resp.text();
3461
+ let raw;
3462
+ if (text) {
3463
+ try {
3464
+ raw = JSON.parse(text);
3465
+ } catch {
3466
+ raw = text;
3467
+ }
3468
+ }
3469
+ if (!resp.ok) {
3470
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3471
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3472
+ throw new FlurApiError(resp.status, code, message, raw);
3473
+ }
3474
+ return PartnerProfileSchema.parse(raw);
3475
+ }
3476
+ };
3477
+ }
2509
3478
  export {
2510
3479
  ACCOUNT_STATUSES,
2511
3480
  ACCOUNT_TYPES,
@@ -2513,6 +3482,29 @@ export {
2513
3482
  AccountMembershipSchema,
2514
3483
  AccountSchema,
2515
3484
  ApiCredentialPublicSchema,
3485
+ COLLECTION_INTENT_STATUSES,
3486
+ COLLECTION_PAYMENT_STATUSES,
3487
+ CUSTODIAL_MODES,
3488
+ CollectionIntentSchema,
3489
+ CollectionPaymentResultSchema,
3490
+ CollectionPaymentSchema,
3491
+ CollectionReportSummarySchema,
3492
+ CollectionStatementSchema,
3493
+ OACRecordSchema as ConsumerOACRecordSchema,
3494
+ ConsumerOACSchema,
3495
+ ConsumerPaymentClaimSchema,
3496
+ ConsumerSettleResultSchema,
3497
+ ConsumerSettlementSchema,
3498
+ CreateCollectionIntentInputSchema,
3499
+ CreatePayoutDestinationInputSchema,
3500
+ CreatePayoutInputSchema,
3501
+ CreateWithdrawalInputSchema,
3502
+ CreateWithdrawalResultSchema,
3503
+ DeviceKeyRecordSchema,
3504
+ DisableOfflineInputSchema,
3505
+ DisableOfflineResultSchema,
3506
+ EnableOfflineInputSchema,
3507
+ EnableOfflineResultSchema,
2516
3508
  FIELD,
2517
3509
  FlurApiError,
2518
3510
  FlurCapExceededError,
@@ -2520,7 +3512,14 @@ export {
2520
3512
  FlurError,
2521
3513
  FlurExpiredError,
2522
3514
  FlurReplayError,
3515
+ IngestFundingResultSchema,
3516
+ IssueOACInputSchema,
3517
+ ListPayoutDestinationsResultSchema,
2523
3518
  MEMBERSHIP_ROLES,
3519
+ MERCHANT_PAYOUT_STATUSES,
3520
+ MERCHANT_PROFILE_STATUSES,
3521
+ MerchantPayoutSchema,
3522
+ MerchantProfileSchema,
2524
3523
  MintedApiCredentialSchema,
2525
3524
  NGN_CURRENCY_CODE,
2526
3525
  NG_COUNTRY_CODE,
@@ -2529,25 +3528,52 @@ export {
2529
3528
  OAC_DEFAULT_CUMULATIVE_KOBO,
2530
3529
  OAC_DEFAULT_PER_TX_KOBO,
2531
3530
  OAC_DEFAULT_VALIDITY_MS,
3531
+ OfflineHoldRecordSchema,
2532
3532
  OfflinePaymentAuthorizationSchema,
2533
3533
  OfflinePaymentRequestSchema,
3534
+ OfflineStateResultSchema,
3535
+ OfflineStatusResultSchema,
2534
3536
  OfflineTokenSchema,
3537
+ PARTNER_FUNDING_DIRECTIONS,
3538
+ PARTNER_FUNDING_STATUSES,
3539
+ PARTNER_KINDS,
3540
+ PARTNER_PROFILE_STATUSES,
2535
3541
  PARTNER_SCOPES,
2536
3542
  PASS_KINDS,
2537
3543
  PASS_STATES,
2538
3544
  PAYLOAD_FORMAT_INDICATOR_VALUE,
3545
+ PAYOUT_DESTINATION_STATUSES,
2539
3546
  POINT_OF_INITIATION,
3547
+ PartnerFundingEventInputSchema,
3548
+ PartnerFundingSchema,
3549
+ PartnerProfileSchema,
2540
3550
  PassMetadataSchema,
2541
3551
  PassSchema,
3552
+ PayCollectionInputSchema,
2542
3553
  PaymentClaimSchema,
3554
+ PayoutDestinationSchema,
3555
+ PayoutEventInputSchema,
3556
+ ProviderEventInputSchema,
3557
+ ProviderEventRecordSchema,
3558
+ PublicCollectionIntentSchema,
2543
3559
  RECEIPT_CHANNELS,
2544
3560
  RECEIPT_KINDS,
2545
3561
  REPLAY_WINDOW_MS,
2546
3562
  ReceiptPayloadSchema,
2547
3563
  ReceiptSchema,
3564
+ ReconciliationReportSchema,
3565
+ RecordPayoutEventResultSchema,
2548
3566
  RedemptionSchema,
3567
+ RegisterDeviceKeyInputSchema,
3568
+ RevokeDeviceKeyInputSchema,
3569
+ SETTLEMENT_SCHEDULES,
2549
3570
  SettleResponseSchema,
2550
3571
  SettlementSchema,
3572
+ SignedConsumerOACSchema,
3573
+ UpsertMerchantProfileInputSchema,
3574
+ UpsertPartnerProfileInputSchema,
3575
+ WITHDRAWAL_STATES,
3576
+ WithdrawalSchema,
2551
3577
  bodySha256Hex,
2552
3578
  buildAuthorization,
2553
3579
  buildOAC,
@@ -2564,9 +3590,16 @@ export {
2564
3590
  crc16ccittHex,
2565
3591
  createAccountsClient,
2566
3592
  createApiCredentialsAdminClient,
3593
+ createCollectionsClient,
3594
+ createConsumerCollectionsClient,
3595
+ createConsumerWithdrawalsClient,
2567
3596
  createFlurPartnerClient,
2568
3597
  createHmacFetch,
3598
+ createMeOfflineClient,
2569
3599
  createOfflineSettlementsClient,
3600
+ createPartnerCollectionsClient,
3601
+ createPartnerFundingClient,
3602
+ createPartnerProfileAdminClient,
2570
3603
  createPassesClient,
2571
3604
  createReceiptsClient,
2572
3605
  decodeAuthorizationQR,