@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.cjs CHANGED
@@ -26,6 +26,29 @@ __export(index_exports, {
26
26
  AccountMembershipSchema: () => AccountMembershipSchema,
27
27
  AccountSchema: () => AccountSchema,
28
28
  ApiCredentialPublicSchema: () => ApiCredentialPublicSchema,
29
+ COLLECTION_INTENT_STATUSES: () => COLLECTION_INTENT_STATUSES,
30
+ COLLECTION_PAYMENT_STATUSES: () => COLLECTION_PAYMENT_STATUSES,
31
+ CUSTODIAL_MODES: () => CUSTODIAL_MODES,
32
+ CollectionIntentSchema: () => CollectionIntentSchema,
33
+ CollectionPaymentResultSchema: () => CollectionPaymentResultSchema,
34
+ CollectionPaymentSchema: () => CollectionPaymentSchema,
35
+ CollectionReportSummarySchema: () => CollectionReportSummarySchema,
36
+ CollectionStatementSchema: () => CollectionStatementSchema,
37
+ ConsumerOACRecordSchema: () => OACRecordSchema,
38
+ ConsumerOACSchema: () => ConsumerOACSchema,
39
+ ConsumerPaymentClaimSchema: () => ConsumerPaymentClaimSchema,
40
+ ConsumerSettleResultSchema: () => ConsumerSettleResultSchema,
41
+ ConsumerSettlementSchema: () => ConsumerSettlementSchema,
42
+ CreateCollectionIntentInputSchema: () => CreateCollectionIntentInputSchema,
43
+ CreatePayoutDestinationInputSchema: () => CreatePayoutDestinationInputSchema,
44
+ CreatePayoutInputSchema: () => CreatePayoutInputSchema,
45
+ CreateWithdrawalInputSchema: () => CreateWithdrawalInputSchema,
46
+ CreateWithdrawalResultSchema: () => CreateWithdrawalResultSchema,
47
+ DeviceKeyRecordSchema: () => DeviceKeyRecordSchema,
48
+ DisableOfflineInputSchema: () => DisableOfflineInputSchema,
49
+ DisableOfflineResultSchema: () => DisableOfflineResultSchema,
50
+ EnableOfflineInputSchema: () => EnableOfflineInputSchema,
51
+ EnableOfflineResultSchema: () => EnableOfflineResultSchema,
29
52
  FIELD: () => FIELD,
30
53
  FlurApiError: () => FlurApiError,
31
54
  FlurCapExceededError: () => FlurCapExceededError,
@@ -33,7 +56,14 @@ __export(index_exports, {
33
56
  FlurError: () => FlurError,
34
57
  FlurExpiredError: () => FlurExpiredError,
35
58
  FlurReplayError: () => FlurReplayError,
59
+ IngestFundingResultSchema: () => IngestFundingResultSchema,
60
+ IssueOACInputSchema: () => IssueOACInputSchema,
61
+ ListPayoutDestinationsResultSchema: () => ListPayoutDestinationsResultSchema,
36
62
  MEMBERSHIP_ROLES: () => MEMBERSHIP_ROLES,
63
+ MERCHANT_PAYOUT_STATUSES: () => MERCHANT_PAYOUT_STATUSES,
64
+ MERCHANT_PROFILE_STATUSES: () => MERCHANT_PROFILE_STATUSES,
65
+ MerchantPayoutSchema: () => MerchantPayoutSchema,
66
+ MerchantProfileSchema: () => MerchantProfileSchema,
37
67
  MintedApiCredentialSchema: () => MintedApiCredentialSchema,
38
68
  NGN_CURRENCY_CODE: () => NGN_CURRENCY_CODE,
39
69
  NG_COUNTRY_CODE: () => NG_COUNTRY_CODE,
@@ -42,25 +72,52 @@ __export(index_exports, {
42
72
  OAC_DEFAULT_CUMULATIVE_KOBO: () => OAC_DEFAULT_CUMULATIVE_KOBO,
43
73
  OAC_DEFAULT_PER_TX_KOBO: () => OAC_DEFAULT_PER_TX_KOBO,
44
74
  OAC_DEFAULT_VALIDITY_MS: () => OAC_DEFAULT_VALIDITY_MS,
75
+ OfflineHoldRecordSchema: () => OfflineHoldRecordSchema,
45
76
  OfflinePaymentAuthorizationSchema: () => OfflinePaymentAuthorizationSchema,
46
77
  OfflinePaymentRequestSchema: () => OfflinePaymentRequestSchema,
78
+ OfflineStateResultSchema: () => OfflineStateResultSchema,
79
+ OfflineStatusResultSchema: () => OfflineStatusResultSchema,
47
80
  OfflineTokenSchema: () => OfflineTokenSchema,
81
+ PARTNER_FUNDING_DIRECTIONS: () => PARTNER_FUNDING_DIRECTIONS,
82
+ PARTNER_FUNDING_STATUSES: () => PARTNER_FUNDING_STATUSES,
83
+ PARTNER_KINDS: () => PARTNER_KINDS,
84
+ PARTNER_PROFILE_STATUSES: () => PARTNER_PROFILE_STATUSES,
48
85
  PARTNER_SCOPES: () => PARTNER_SCOPES,
49
86
  PASS_KINDS: () => PASS_KINDS,
50
87
  PASS_STATES: () => PASS_STATES,
51
88
  PAYLOAD_FORMAT_INDICATOR_VALUE: () => PAYLOAD_FORMAT_INDICATOR_VALUE,
89
+ PAYOUT_DESTINATION_STATUSES: () => PAYOUT_DESTINATION_STATUSES,
52
90
  POINT_OF_INITIATION: () => POINT_OF_INITIATION,
91
+ PartnerFundingEventInputSchema: () => PartnerFundingEventInputSchema,
92
+ PartnerFundingSchema: () => PartnerFundingSchema,
93
+ PartnerProfileSchema: () => PartnerProfileSchema,
53
94
  PassMetadataSchema: () => PassMetadataSchema,
54
95
  PassSchema: () => PassSchema,
96
+ PayCollectionInputSchema: () => PayCollectionInputSchema,
55
97
  PaymentClaimSchema: () => PaymentClaimSchema,
98
+ PayoutDestinationSchema: () => PayoutDestinationSchema,
99
+ PayoutEventInputSchema: () => PayoutEventInputSchema,
100
+ ProviderEventInputSchema: () => ProviderEventInputSchema,
101
+ ProviderEventRecordSchema: () => ProviderEventRecordSchema,
102
+ PublicCollectionIntentSchema: () => PublicCollectionIntentSchema,
56
103
  RECEIPT_CHANNELS: () => RECEIPT_CHANNELS,
57
104
  RECEIPT_KINDS: () => RECEIPT_KINDS,
58
105
  REPLAY_WINDOW_MS: () => REPLAY_WINDOW_MS,
59
106
  ReceiptPayloadSchema: () => ReceiptPayloadSchema,
60
107
  ReceiptSchema: () => ReceiptSchema,
108
+ ReconciliationReportSchema: () => ReconciliationReportSchema,
109
+ RecordPayoutEventResultSchema: () => RecordPayoutEventResultSchema,
61
110
  RedemptionSchema: () => RedemptionSchema,
111
+ RegisterDeviceKeyInputSchema: () => RegisterDeviceKeyInputSchema,
112
+ RevokeDeviceKeyInputSchema: () => RevokeDeviceKeyInputSchema,
113
+ SETTLEMENT_SCHEDULES: () => SETTLEMENT_SCHEDULES,
62
114
  SettleResponseSchema: () => SettleResponseSchema,
63
115
  SettlementSchema: () => SettlementSchema,
116
+ SignedConsumerOACSchema: () => SignedConsumerOACSchema,
117
+ UpsertMerchantProfileInputSchema: () => UpsertMerchantProfileInputSchema,
118
+ UpsertPartnerProfileInputSchema: () => UpsertPartnerProfileInputSchema,
119
+ WITHDRAWAL_STATES: () => WITHDRAWAL_STATES,
120
+ WithdrawalSchema: () => WithdrawalSchema,
64
121
  bodySha256Hex: () => bodySha256Hex,
65
122
  buildAuthorization: () => buildAuthorization,
66
123
  buildOAC: () => buildOAC,
@@ -77,9 +134,16 @@ __export(index_exports, {
77
134
  crc16ccittHex: () => crc16ccittHex,
78
135
  createAccountsClient: () => createAccountsClient,
79
136
  createApiCredentialsAdminClient: () => createApiCredentialsAdminClient,
137
+ createCollectionsClient: () => createCollectionsClient,
138
+ createConsumerCollectionsClient: () => createConsumerCollectionsClient,
139
+ createConsumerWithdrawalsClient: () => createConsumerWithdrawalsClient,
80
140
  createFlurPartnerClient: () => createFlurPartnerClient,
81
141
  createHmacFetch: () => createHmacFetch,
142
+ createMeOfflineClient: () => createMeOfflineClient,
82
143
  createOfflineSettlementsClient: () => createOfflineSettlementsClient,
144
+ createPartnerCollectionsClient: () => createPartnerCollectionsClient,
145
+ createPartnerFundingClient: () => createPartnerFundingClient,
146
+ createPartnerProfileAdminClient: () => createPartnerProfileAdminClient,
83
147
  createPassesClient: () => createPassesClient,
84
148
  createReceiptsClient: () => createReceiptsClient,
85
149
  decodeAuthorizationQR: () => decodeAuthorizationQR,
@@ -127,7 +191,7 @@ __export(index_exports, {
127
191
  module.exports = __toCommonJS(index_exports);
128
192
 
129
193
  // src/client.ts
130
- var import_zod3 = require("zod");
194
+ var import_zod4 = require("zod");
131
195
 
132
196
  // src/contracts.ts
133
197
  var import_zod = require("zod");
@@ -169,7 +233,9 @@ var OnboardingCompleteResponseSchema = import_zod.z.object({
169
233
  sessionToken: import_zod.z.string().min(1),
170
234
  userId: UuidSchema,
171
235
  restricted: import_zod.z.boolean(),
172
- risk_reasons: import_zod.z.array(import_zod.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])),
236
+ risk_reasons: import_zod.z.array(
237
+ import_zod.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
238
+ ),
173
239
  stepUpRequired: import_zod.z.boolean().optional(),
174
240
  riskStatus: import_zod.z.enum(["ok", "unavailable"]).optional()
175
241
  });
@@ -222,9 +288,11 @@ var RegisterSendDeviceKeyRequestSchema = import_zod.z.object({
222
288
  deviceId: import_zod.z.string().min(3),
223
289
  publicKey: import_zod.z.string().min(32)
224
290
  });
291
+ var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
225
292
  var SendChallengeRequestSchema = import_zod.z.object({
226
293
  userId: UuidSchema,
227
- deviceId: import_zod.z.string().min(3)
294
+ deviceId: import_zod.z.string().min(3),
295
+ purpose: import_zod.z.enum(SEND_AUTH_PURPOSES).optional()
228
296
  });
229
297
  var SendChallengeResponseSchema = import_zod.z.object({
230
298
  challengeId: UuidSchema,
@@ -511,6 +579,341 @@ function moneyMinorToNumber(amountMinor) {
511
579
  return asNumber;
512
580
  }
513
581
 
582
+ // src/collections/client.ts
583
+ var import_zod3 = require("zod");
584
+ var MERCHANT_PROFILE_STATUSES = [
585
+ "pending",
586
+ "active",
587
+ "suspended",
588
+ "closed"
589
+ ];
590
+ var SETTLEMENT_SCHEDULES = ["manual", "daily", "t1"];
591
+ var COLLECTION_INTENT_STATUSES = [
592
+ "created",
593
+ "pending",
594
+ "paid",
595
+ "expired",
596
+ "cancelled",
597
+ "failed",
598
+ "reversed"
599
+ ];
600
+ var COLLECTION_PAYMENT_STATUSES = [
601
+ "pending",
602
+ "paid",
603
+ "failed",
604
+ "reversed"
605
+ ];
606
+ var MERCHANT_PAYOUT_STATUSES = [
607
+ "requested",
608
+ "processing",
609
+ "paid",
610
+ "failed",
611
+ "cancelled"
612
+ ];
613
+ var MoneyKoboSchema = import_zod3.z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
614
+ var MetadataSchema = import_zod3.z.record(
615
+ import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()])
616
+ );
617
+ var CurrencySchema2 = import_zod3.z.string().trim().length(3).transform((value) => value.toUpperCase());
618
+ var ReferenceSchema = import_zod3.z.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
619
+ var MerchantProfileSchema = import_zod3.z.object({
620
+ accountId: import_zod3.z.string().uuid(),
621
+ legalName: import_zod3.z.string(),
622
+ tradingName: import_zod3.z.string(),
623
+ merchantCategoryCode: import_zod3.z.string().regex(/^\d{4}$/),
624
+ nqrMerchantId: import_zod3.z.string(),
625
+ settlementBankCode: import_zod3.z.string(),
626
+ settlementAccountNumber: import_zod3.z.string(),
627
+ settlementAccountName: import_zod3.z.string(),
628
+ settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES),
629
+ status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES),
630
+ offlineEnabled: import_zod3.z.boolean(),
631
+ perTxLimitKobo: MoneyKoboSchema,
632
+ dailyLimitKobo: MoneyKoboSchema,
633
+ metadata: MetadataSchema,
634
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
635
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
636
+ });
637
+ var UpsertMerchantProfileInputSchema = import_zod3.z.object({
638
+ legalName: import_zod3.z.string().trim().min(1).max(200),
639
+ tradingName: import_zod3.z.string().trim().min(1).max(25),
640
+ merchantCategoryCode: import_zod3.z.string().trim().regex(/^\d{4}$/),
641
+ nqrMerchantId: import_zod3.z.string().trim().min(3).max(64),
642
+ settlementBankCode: import_zod3.z.string().trim().min(2).max(16),
643
+ settlementAccountNumber: import_zod3.z.string().trim().min(5).max(32),
644
+ settlementAccountName: import_zod3.z.string().trim().min(1).max(200),
645
+ settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES).optional(),
646
+ status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES).optional(),
647
+ offlineEnabled: import_zod3.z.boolean().optional(),
648
+ perTxLimitKobo: MoneyKoboSchema.optional(),
649
+ dailyLimitKobo: MoneyKoboSchema.optional(),
650
+ metadata: MetadataSchema.optional()
651
+ });
652
+ var CollectionIntentSchema = import_zod3.z.object({
653
+ intentId: import_zod3.z.string().uuid(),
654
+ accountId: import_zod3.z.string().uuid(),
655
+ terminalId: import_zod3.z.string().uuid().nullable(),
656
+ reference: import_zod3.z.string(),
657
+ amountKobo: import_zod3.z.number().int().positive().nullable(),
658
+ currency: import_zod3.z.string().length(3),
659
+ status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
660
+ description: import_zod3.z.string().nullable(),
661
+ nqrPayload: import_zod3.z.string(),
662
+ provider: import_zod3.z.string(),
663
+ providerReference: import_zod3.z.string().nullable(),
664
+ metadata: MetadataSchema,
665
+ expiresAtMs: import_zod3.z.number().int().nonnegative().nullable(),
666
+ paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
667
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
668
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
669
+ });
670
+ var CreateCollectionIntentInputSchema = import_zod3.z.object({
671
+ reference: ReferenceSchema.optional(),
672
+ amountKobo: MoneyKoboSchema.optional(),
673
+ currency: CurrencySchema2.optional(),
674
+ terminalId: import_zod3.z.string().uuid().optional(),
675
+ terminalLabel: import_zod3.z.string().trim().min(1).max(25).optional(),
676
+ merchantCity: import_zod3.z.string().trim().min(1).max(15).optional(),
677
+ description: import_zod3.z.string().trim().min(1).max(280).optional(),
678
+ expiresAtMs: import_zod3.z.number().int().positive().optional(),
679
+ provider: import_zod3.z.string().trim().min(1).max(40).optional(),
680
+ metadata: MetadataSchema.optional()
681
+ });
682
+ var PublicCollectionIntentSchema = import_zod3.z.object({
683
+ intentId: import_zod3.z.string().uuid(),
684
+ reference: import_zod3.z.string(),
685
+ amountKobo: import_zod3.z.number().int().positive().nullable(),
686
+ currency: import_zod3.z.string().length(3),
687
+ status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
688
+ merchantAccountId: import_zod3.z.string().uuid(),
689
+ merchantName: import_zod3.z.string(),
690
+ merchantCategoryCode: import_zod3.z.string(),
691
+ description: import_zod3.z.string().nullable(),
692
+ expiresAtMs: import_zod3.z.number().int().nonnegative().nullable()
693
+ });
694
+ var PayCollectionInputSchema = import_zod3.z.object({
695
+ reference: ReferenceSchema,
696
+ amountKobo: MoneyKoboSchema.optional(),
697
+ currency: CurrencySchema2.optional(),
698
+ idempotencyKey: import_zod3.z.string().trim().min(8).max(160).optional()
699
+ });
700
+ var CollectionPaymentSchema = import_zod3.z.object({
701
+ paymentId: import_zod3.z.string().uuid(),
702
+ intentId: import_zod3.z.string().uuid(),
703
+ accountId: import_zod3.z.string().uuid(),
704
+ payerUserId: import_zod3.z.string().uuid().nullable(),
705
+ merchantOwnerUserId: import_zod3.z.string().uuid(),
706
+ amountKobo: MoneyKoboSchema,
707
+ currency: import_zod3.z.string().length(3),
708
+ status: import_zod3.z.enum(COLLECTION_PAYMENT_STATUSES),
709
+ provider: import_zod3.z.string(),
710
+ providerReference: import_zod3.z.string().nullable(),
711
+ idempotencyKey: import_zod3.z.string().nullable(),
712
+ ledgerRef: import_zod3.z.string(),
713
+ failureCode: import_zod3.z.string().nullable(),
714
+ failureMessage: import_zod3.z.string().nullable(),
715
+ paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
716
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
717
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
718
+ });
719
+ var CollectionPaymentResultSchema = import_zod3.z.object({
720
+ payment: CollectionPaymentSchema,
721
+ intent: CollectionIntentSchema,
722
+ receipt: import_zod3.z.unknown().optional(),
723
+ replayed: import_zod3.z.boolean()
724
+ });
725
+ var CollectionReportSummarySchema = import_zod3.z.object({
726
+ accountId: import_zod3.z.string().uuid(),
727
+ fromMs: import_zod3.z.number().int().nonnegative(),
728
+ toMs: import_zod3.z.number().int().nonnegative(),
729
+ currency: import_zod3.z.string().length(3),
730
+ paidCount: import_zod3.z.number().int().nonnegative(),
731
+ paidAmountKobo: import_zod3.z.number().int().nonnegative(),
732
+ pendingCount: import_zod3.z.number().int().nonnegative(),
733
+ failedCount: import_zod3.z.number().int().nonnegative(),
734
+ reversedCount: import_zod3.z.number().int().nonnegative(),
735
+ availableBalanceKobo: import_zod3.z.number().int().nonnegative()
736
+ });
737
+ var CollectionStatementSchema = import_zod3.z.object({
738
+ accountId: import_zod3.z.string().uuid(),
739
+ year: import_zod3.z.number().int(),
740
+ month: import_zod3.z.number().int().min(1).max(12),
741
+ currency: import_zod3.z.string().length(3),
742
+ totalPaidKobo: import_zod3.z.number().int().nonnegative(),
743
+ items: import_zod3.z.array(CollectionPaymentSchema)
744
+ });
745
+ var CreatePayoutInputSchema = import_zod3.z.object({
746
+ amountKobo: MoneyKoboSchema,
747
+ currency: CurrencySchema2.optional(),
748
+ idempotencyKey: import_zod3.z.string().trim().min(8).max(160)
749
+ });
750
+ var MerchantPayoutSchema = import_zod3.z.object({
751
+ payoutId: import_zod3.z.string().uuid(),
752
+ accountId: import_zod3.z.string().uuid(),
753
+ amountKobo: MoneyKoboSchema,
754
+ currency: import_zod3.z.string().length(3),
755
+ status: import_zod3.z.enum(MERCHANT_PAYOUT_STATUSES),
756
+ idempotencyKey: import_zod3.z.string().nullable(),
757
+ ledgerRef: import_zod3.z.string(),
758
+ providerReference: import_zod3.z.string().nullable(),
759
+ requestedByUserId: import_zod3.z.string().uuid().nullable(),
760
+ failureCode: import_zod3.z.string().nullable(),
761
+ failureMessage: import_zod3.z.string().nullable(),
762
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
763
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
764
+ });
765
+ var ProviderEventInputSchema = import_zod3.z.object({
766
+ provider: import_zod3.z.string().trim().min(1).max(80),
767
+ eventId: import_zod3.z.string().trim().min(1).max(160),
768
+ eventType: import_zod3.z.string().trim().min(1).max(120),
769
+ payload: import_zod3.z.record(import_zod3.z.unknown()).optional()
770
+ });
771
+ var ProviderEventRecordSchema = import_zod3.z.object({
772
+ id: import_zod3.z.string().uuid(),
773
+ provider: import_zod3.z.string(),
774
+ eventId: import_zod3.z.string(),
775
+ eventType: import_zod3.z.string(),
776
+ signatureVerified: import_zod3.z.boolean(),
777
+ receivedAtMs: import_zod3.z.number().int().nonnegative(),
778
+ processedAtMs: import_zod3.z.number().int().nonnegative().nullable()
779
+ });
780
+ function createCollectionsClient(opts) {
781
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
782
+ if (!fetchImpl) {
783
+ throw new Error(
784
+ "createCollectionsClient: no fetch implementation available"
785
+ );
786
+ }
787
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
788
+ async function call(method, path, body, parser) {
789
+ const init2 = {
790
+ method,
791
+ headers: { accept: "application/json" }
792
+ };
793
+ if (body !== void 0) {
794
+ init2.body = JSON.stringify(body);
795
+ init2.headers = { ...init2.headers, "content-type": "application/json" };
796
+ }
797
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
798
+ const text = await resp.text();
799
+ let raw;
800
+ if (text) {
801
+ try {
802
+ raw = JSON.parse(text);
803
+ } catch {
804
+ raw = text;
805
+ }
806
+ }
807
+ if (!resp.ok) {
808
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
809
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
810
+ throw new FlurApiError(resp.status, code, message, raw);
811
+ }
812
+ return parser(raw);
813
+ }
814
+ return {
815
+ upsertMerchantProfile: (accountId, input) => call(
816
+ "PUT",
817
+ `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,
818
+ UpsertMerchantProfileInputSchema.parse(input),
819
+ (raw) => MerchantProfileSchema.parse(raw)
820
+ ),
821
+ getMerchantProfile: (accountId) => call(
822
+ "GET",
823
+ `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,
824
+ void 0,
825
+ (raw) => MerchantProfileSchema.parse(raw)
826
+ ),
827
+ createIntent: (input) => call(
828
+ "POST",
829
+ "/v1/collections/intents",
830
+ CreateCollectionIntentInputSchema.parse(input),
831
+ (raw) => CollectionIntentSchema.parse(raw)
832
+ ),
833
+ getIntent: (intentId) => call(
834
+ "GET",
835
+ `/v1/collections/intents/${encodeURIComponent(intentId)}`,
836
+ void 0,
837
+ (raw) => CollectionIntentSchema.parse(raw)
838
+ ),
839
+ resolveIntent: (reference) => call(
840
+ "GET",
841
+ `/v1/collections/resolve/${encodeURIComponent(reference)}`,
842
+ void 0,
843
+ (raw) => PublicCollectionIntentSchema.parse(raw)
844
+ ),
845
+ pay: (input) => call(
846
+ "POST",
847
+ "/v1/collections/pay",
848
+ PayCollectionInputSchema.parse(input),
849
+ (raw) => CollectionPaymentResultSchema.parse(raw)
850
+ ),
851
+ reportSummary: (input) => {
852
+ const qs = new URLSearchParams({
853
+ fromMs: String(input.fromMs),
854
+ toMs: String(input.toMs)
855
+ });
856
+ if (input.currency) qs.set("currency", input.currency);
857
+ return call(
858
+ "GET",
859
+ `/v1/collections/reports/summary?${qs.toString()}`,
860
+ void 0,
861
+ (raw) => CollectionReportSummarySchema.parse(raw)
862
+ );
863
+ },
864
+ monthlyStatement: (input) => {
865
+ const qs = new URLSearchParams({
866
+ year: String(input.year),
867
+ month: String(input.month)
868
+ });
869
+ if (input.currency) qs.set("currency", input.currency);
870
+ return call(
871
+ "GET",
872
+ `/v1/collections/statements/monthly?${qs.toString()}`,
873
+ void 0,
874
+ (raw) => CollectionStatementSchema.parse(raw)
875
+ );
876
+ },
877
+ createPayout: (input) => call(
878
+ "POST",
879
+ "/v1/collections/payouts",
880
+ CreatePayoutInputSchema.parse(input),
881
+ (raw) => MerchantPayoutSchema.parse(raw)
882
+ ),
883
+ getPayout: (payoutId) => call(
884
+ "GET",
885
+ `/v1/collections/payouts/${encodeURIComponent(payoutId)}`,
886
+ void 0,
887
+ (raw) => MerchantPayoutSchema.parse(raw)
888
+ ),
889
+ recordProviderEvent: (input) => call(
890
+ "POST",
891
+ "/v1/collections/provider-events",
892
+ ProviderEventInputSchema.parse(input),
893
+ (raw) => ProviderEventRecordSchema.parse(raw)
894
+ )
895
+ };
896
+ }
897
+ function createPartnerCollectionsClient(opts) {
898
+ const client = createCollectionsClient(opts);
899
+ return {
900
+ createIntent: client.createIntent,
901
+ getIntent: client.getIntent,
902
+ reportSummary: client.reportSummary,
903
+ monthlyStatement: client.monthlyStatement,
904
+ createPayout: client.createPayout,
905
+ getPayout: client.getPayout,
906
+ recordProviderEvent: client.recordProviderEvent
907
+ };
908
+ }
909
+ function createConsumerCollectionsClient(opts) {
910
+ const client = createCollectionsClient(opts);
911
+ return {
912
+ resolveIntent: client.resolveIntent,
913
+ pay: client.pay
914
+ };
915
+ }
916
+
514
917
  // src/client.ts
515
918
  var FlurClient = class {
516
919
  baseUrl;
@@ -524,10 +927,20 @@ var FlurClient = class {
524
927
  this.getExtraHeaders = opts.getExtraHeaders;
525
928
  }
526
929
  async health() {
527
- return this.requestJson("/health", { method: "GET" }, void 0, HealthResponseSchema);
930
+ return this.requestJson(
931
+ "/health",
932
+ { method: "GET" },
933
+ void 0,
934
+ HealthResponseSchema
935
+ );
528
936
  }
529
937
  async welcome() {
530
- return this.requestJson("/welcome", { method: "GET" }, void 0, WelcomeResponseSchema);
938
+ return this.requestJson(
939
+ "/welcome",
940
+ { method: "GET" },
941
+ void 0,
942
+ WelcomeResponseSchema
943
+ );
531
944
  }
532
945
  async onboardingStart(input) {
533
946
  return this.requestJson(
@@ -672,24 +1085,33 @@ var FlurClient = class {
672
1085
  }
673
1086
  async registerBiometricDeviceKey(input) {
674
1087
  const publicKey = await input.signer.getOrCreateKeyPair(input.deviceId);
675
- return this.registerSendDeviceKey({
676
- userId: input.userId,
677
- deviceId: input.deviceId,
678
- publicKey
679
- }, { accessToken: input.accessToken });
1088
+ return this.registerSendDeviceKey(
1089
+ {
1090
+ userId: input.userId,
1091
+ deviceId: input.deviceId,
1092
+ publicKey
1093
+ },
1094
+ { accessToken: input.accessToken }
1095
+ );
680
1096
  }
681
1097
  async authorizeSendWithBiometric(input) {
682
- const challenge = await this.createSendChallenge({
683
- userId: input.userId,
684
- deviceId: input.deviceId
685
- }, { accessToken: input.accessToken });
1098
+ const challenge = await this.createSendChallenge(
1099
+ {
1100
+ userId: input.userId,
1101
+ deviceId: input.deviceId
1102
+ },
1103
+ { accessToken: input.accessToken }
1104
+ );
686
1105
  const signature = await input.signer.sign(challenge.nonce);
687
- return this.verifySendChallenge({
688
- userId: input.userId,
689
- deviceId: input.deviceId,
690
- challengeId: challenge.challengeId,
691
- signature
692
- }, { accessToken: input.accessToken });
1106
+ return this.verifySendChallenge(
1107
+ {
1108
+ userId: input.userId,
1109
+ deviceId: input.deviceId,
1110
+ challengeId: challenge.challengeId,
1111
+ signature
1112
+ },
1113
+ { accessToken: input.accessToken }
1114
+ );
693
1115
  }
694
1116
  async resolveRecipient(input, options) {
695
1117
  return this.requestJson(
@@ -740,6 +1162,36 @@ var FlurClient = class {
740
1162
  }
741
1163
  );
742
1164
  }
1165
+ async resolveCollection(reference, options) {
1166
+ return this.requestJson(
1167
+ `/v1/collections/resolve/${encodeURIComponent(reference)}`,
1168
+ {
1169
+ method: "GET",
1170
+ headers: {
1171
+ authorization: `Bearer ${options.accessToken}`
1172
+ }
1173
+ },
1174
+ void 0,
1175
+ PublicCollectionIntentSchema
1176
+ );
1177
+ }
1178
+ async payCollection(input, options) {
1179
+ const idempotencyKey = input.idempotencyKey ?? options.idempotencyKey ?? getSecureRandomUuid();
1180
+ return this.requestJson(
1181
+ "/v1/collections/pay",
1182
+ {
1183
+ method: "POST",
1184
+ headers: {
1185
+ "content-type": "application/json",
1186
+ authorization: `Bearer ${options.accessToken}`,
1187
+ "x-idempotency-key": idempotencyKey
1188
+ }
1189
+ },
1190
+ PayCollectionInputSchema,
1191
+ CollectionPaymentResultSchema,
1192
+ { ...input, idempotencyKey }
1193
+ );
1194
+ }
743
1195
  async accountSummary(options) {
744
1196
  return this.requestJson(
745
1197
  "/api/v1/account/summary",
@@ -838,7 +1290,7 @@ var FlurClient = class {
838
1290
  try {
839
1291
  body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
840
1292
  } catch (err) {
841
- if (err instanceof import_zod3.z.ZodError) {
1293
+ if (err instanceof import_zod4.z.ZodError) {
842
1294
  throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
843
1295
  details: err.flatten()
844
1296
  });
@@ -854,17 +1306,26 @@ var FlurClient = class {
854
1306
  ...init2.headers,
855
1307
  ...extraHeaders
856
1308
  };
857
- const res = await this.fetchImpl(url, { ...init2, headers: finalHeaders, body, signal: controller.signal });
1309
+ const res = await this.fetchImpl(url, {
1310
+ ...init2,
1311
+ headers: finalHeaders,
1312
+ body,
1313
+ signal: controller.signal
1314
+ });
858
1315
  if (!res.ok) throw await mapToFlurError(res);
859
1316
  const payload = await res.json();
860
1317
  if (!responseSchema) return payload;
861
1318
  try {
862
1319
  return responseSchema.parse(payload);
863
1320
  } catch (err) {
864
- if (err instanceof import_zod3.z.ZodError) {
865
- throw new FlurError("SDK contract validation failed", "INVALID_REQUEST", {
866
- details: err.flatten()
867
- });
1321
+ if (err instanceof import_zod4.z.ZodError) {
1322
+ throw new FlurError(
1323
+ "SDK contract validation failed",
1324
+ "INVALID_REQUEST",
1325
+ {
1326
+ details: err.flatten()
1327
+ }
1328
+ );
868
1329
  }
869
1330
  throw err;
870
1331
  }
@@ -873,7 +1334,9 @@ var FlurClient = class {
873
1334
  throw new FlurError("Request timed out", "TIMEOUT");
874
1335
  }
875
1336
  if (err instanceof FlurError) throw err;
876
- throw new FlurError("Network error", "NETWORK_ERROR", { details: String(err) });
1337
+ throw new FlurError("Network error", "NETWORK_ERROR", {
1338
+ details: String(err)
1339
+ });
877
1340
  } finally {
878
1341
  clearTimeout(t);
879
1342
  }
@@ -883,7 +1346,10 @@ function getSecureRandomUuid() {
883
1346
  if (typeof globalThis.crypto?.randomUUID === "function") {
884
1347
  return globalThis.crypto.randomUUID();
885
1348
  }
886
- throw new FlurError("Secure UUID generator unavailable; provide idempotencyKey", "INVALID_REQUEST");
1349
+ throw new FlurError(
1350
+ "Secure UUID generator unavailable; provide idempotencyKey",
1351
+ "INVALID_REQUEST"
1352
+ );
887
1353
  }
888
1354
 
889
1355
  // src/nqr/fields.ts
@@ -1310,24 +1776,24 @@ function verifyCanonical(value, signature, publicKey) {
1310
1776
  }
1311
1777
 
1312
1778
  // src/offline/oac.ts
1313
- var import_zod4 = require("zod");
1779
+ var import_zod5 = require("zod");
1314
1780
  var OAC_DEFAULT_PER_TX_KOBO = 5e5;
1315
1781
  var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
1316
1782
  var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
1317
- var HexString = (length) => import_zod4.z.string().regex(
1783
+ var HexString = (length) => import_zod5.z.string().regex(
1318
1784
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1319
1785
  `expected ${length}-byte hex string`
1320
1786
  );
1321
- var OACSchema = import_zod4.z.object({
1322
- userId: import_zod4.z.string().min(1),
1323
- deviceId: import_zod4.z.string().min(1),
1787
+ var OACSchema = import_zod5.z.object({
1788
+ userId: import_zod5.z.string().min(1),
1789
+ deviceId: import_zod5.z.string().min(1),
1324
1790
  devicePublicKey: HexString(32),
1325
- perTxCapKobo: import_zod4.z.number().int().nonnegative(),
1326
- cumulativeCapKobo: import_zod4.z.number().int().nonnegative(),
1327
- validFromMs: import_zod4.z.number().int().nonnegative(),
1328
- validUntilMs: import_zod4.z.number().int().positive(),
1329
- counterSeed: import_zod4.z.number().int().nonnegative(),
1330
- nonce: import_zod4.z.string().min(1),
1791
+ perTxCapKobo: import_zod5.z.number().int().nonnegative(),
1792
+ cumulativeCapKobo: import_zod5.z.number().int().nonnegative(),
1793
+ validFromMs: import_zod5.z.number().int().nonnegative(),
1794
+ validUntilMs: import_zod5.z.number().int().positive(),
1795
+ counterSeed: import_zod5.z.number().int().nonnegative(),
1796
+ nonce: import_zod5.z.string().min(1),
1331
1797
  issuerSig: HexString(64)
1332
1798
  }).refine((v) => v.validUntilMs > v.validFromMs, {
1333
1799
  message: "validUntilMs must be greater than validFromMs"
@@ -1434,19 +1900,19 @@ function decodeBase45(s) {
1434
1900
  }
1435
1901
 
1436
1902
  // src/offline/messages.ts
1437
- var import_zod5 = require("zod");
1438
- var HexSig = import_zod5.z.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1439
- var OfflinePaymentRequestSchema = import_zod5.z.object({
1440
- reference: import_zod5.z.string().min(1),
1441
- amountKobo: import_zod5.z.number().int().positive(),
1903
+ var import_zod6 = require("zod");
1904
+ var HexSig = import_zod6.z.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1905
+ var OfflinePaymentRequestSchema = import_zod6.z.object({
1906
+ reference: import_zod6.z.string().min(1),
1907
+ amountKobo: import_zod6.z.number().int().positive(),
1442
1908
  merchantOAC: OACSchema,
1443
- expiresAtMs: import_zod5.z.number().int().positive(),
1909
+ expiresAtMs: import_zod6.z.number().int().positive(),
1444
1910
  merchantSig: HexSig
1445
1911
  });
1446
- var OfflinePaymentAuthorizationSchema = import_zod5.z.object({
1912
+ var OfflinePaymentAuthorizationSchema = import_zod6.z.object({
1447
1913
  request: OfflinePaymentRequestSchema,
1448
1914
  payerOAC: OACSchema,
1449
- payerCounter: import_zod5.z.number().int().positive(),
1915
+ payerCounter: import_zod6.z.number().int().positive(),
1450
1916
  payerSig: HexSig
1451
1917
  });
1452
1918
  function buildPaymentRequest(input) {
@@ -1555,56 +2021,56 @@ function decodeAuthorizationQR(s) {
1555
2021
  }
1556
2022
 
1557
2023
  // src/offline/settlements.ts
1558
- var import_zod6 = require("zod");
2024
+ var import_zod7 = require("zod");
1559
2025
  var import_sha256 = require("@noble/hashes/sha256");
1560
2026
  var import_utils = require("@noble/hashes/utils");
1561
- var OfflineTokenSchema = import_zod6.z.object({
1562
- tokenId: import_zod6.z.string().uuid(),
1563
- tokenSerial: import_zod6.z.string(),
1564
- issuerAccountId: import_zod6.z.string().uuid(),
1565
- payerUserId: import_zod6.z.string().uuid(),
1566
- maxAmountKobo: import_zod6.z.number().int().positive(),
1567
- currency: import_zod6.z.string().length(3),
1568
- issuedAtMs: import_zod6.z.number().int().nonnegative(),
1569
- expiresAtMs: import_zod6.z.number().int().nonnegative(),
1570
- issuerSig: import_zod6.z.string()
1571
- });
1572
- var PaymentClaimSchema = import_zod6.z.object({
1573
- encounterId: import_zod6.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
1574
- tokenSerial: import_zod6.z.string(),
1575
- payerUserId: import_zod6.z.string().uuid(),
1576
- payeeUserId: import_zod6.z.string().uuid(),
1577
- payerNonce: import_zod6.z.string(),
1578
- payeeNonce: import_zod6.z.string(),
1579
- amountKobo: import_zod6.z.number().int().positive(),
1580
- currency: import_zod6.z.string().length(3).default("NGN"),
1581
- occurredAtMs: import_zod6.z.number().int().nonnegative(),
1582
- completedAtMs: import_zod6.z.number().int().nonnegative().optional(),
1583
- contextId: import_zod6.z.string().optional(),
1584
- payerPubkey: import_zod6.z.string().regex(/^[0-9a-f]{64}$/i),
1585
- payerSignature: import_zod6.z.string().regex(/^[0-9a-f]+$/i),
1586
- payeePubkey: import_zod6.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
1587
- payeeSignature: import_zod6.z.string().regex(/^[0-9a-f]+$/i).optional()
1588
- });
1589
- var SettlementSchema = import_zod6.z.object({
1590
- settlementId: import_zod6.z.string().uuid(),
1591
- settlementKey: import_zod6.z.string().regex(/^[0-9a-f]{64}$/i),
1592
- encounterId: import_zod6.z.string().regex(/^[0-9a-f]{64}$/i),
1593
- issuerAccountId: import_zod6.z.string().uuid(),
1594
- tokenSerial: import_zod6.z.string(),
1595
- payerUserId: import_zod6.z.string().uuid(),
1596
- payeeUserId: import_zod6.z.string().uuid(),
1597
- amountKobo: import_zod6.z.number().int().nonnegative(),
1598
- currency: import_zod6.z.string().length(3),
1599
- receiptId: import_zod6.z.string().nullable(),
1600
- status: import_zod6.z.enum(["SETTLED", "REVIEW", "REJECTED"]),
1601
- issuerSig: import_zod6.z.string(),
1602
- createdAtMs: import_zod6.z.number().int().nonnegative()
1603
- });
1604
- var SettleResponseSchema = import_zod6.z.object({
2027
+ var OfflineTokenSchema = import_zod7.z.object({
2028
+ tokenId: import_zod7.z.string().uuid(),
2029
+ tokenSerial: import_zod7.z.string(),
2030
+ issuerAccountId: import_zod7.z.string().uuid(),
2031
+ payerUserId: import_zod7.z.string().uuid(),
2032
+ maxAmountKobo: import_zod7.z.number().int().positive(),
2033
+ currency: import_zod7.z.string().length(3),
2034
+ issuedAtMs: import_zod7.z.number().int().nonnegative(),
2035
+ expiresAtMs: import_zod7.z.number().int().nonnegative(),
2036
+ issuerSig: import_zod7.z.string()
2037
+ });
2038
+ var PaymentClaimSchema = import_zod7.z.object({
2039
+ encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
2040
+ tokenSerial: import_zod7.z.string(),
2041
+ payerUserId: import_zod7.z.string().uuid(),
2042
+ payeeUserId: import_zod7.z.string().uuid(),
2043
+ payerNonce: import_zod7.z.string(),
2044
+ payeeNonce: import_zod7.z.string(),
2045
+ amountKobo: import_zod7.z.number().int().positive(),
2046
+ currency: import_zod7.z.string().length(3).default("NGN"),
2047
+ occurredAtMs: import_zod7.z.number().int().nonnegative(),
2048
+ completedAtMs: import_zod7.z.number().int().nonnegative().optional(),
2049
+ contextId: import_zod7.z.string().optional(),
2050
+ payerPubkey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2051
+ payerSignature: import_zod7.z.string().regex(/^[0-9a-f]+$/i),
2052
+ payeePubkey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
2053
+ payeeSignature: import_zod7.z.string().regex(/^[0-9a-f]+$/i).optional()
2054
+ });
2055
+ var SettlementSchema = import_zod7.z.object({
2056
+ settlementId: import_zod7.z.string().uuid(),
2057
+ settlementKey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2058
+ encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2059
+ issuerAccountId: import_zod7.z.string().uuid(),
2060
+ tokenSerial: import_zod7.z.string(),
2061
+ payerUserId: import_zod7.z.string().uuid(),
2062
+ payeeUserId: import_zod7.z.string().uuid(),
2063
+ amountKobo: import_zod7.z.number().int().nonnegative(),
2064
+ currency: import_zod7.z.string().length(3),
2065
+ receiptId: import_zod7.z.string().nullable(),
2066
+ status: import_zod7.z.enum(["SETTLED", "REVIEW", "REJECTED"]),
2067
+ issuerSig: import_zod7.z.string(),
2068
+ createdAtMs: import_zod7.z.number().int().nonnegative()
2069
+ });
2070
+ var SettleResponseSchema = import_zod7.z.object({
1605
2071
  settlement: SettlementSchema,
1606
- encounterId: import_zod6.z.string().regex(/^[0-9a-f]{64}$/i),
1607
- replayed: import_zod6.z.boolean()
2072
+ encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2073
+ replayed: import_zod7.z.boolean()
1608
2074
  });
1609
2075
  var ENCOUNTER_DOMAIN = "offline:v1:encounter";
1610
2076
  async function sha256Hex(input) {
@@ -1777,126 +2243,344 @@ function createHmacFetch(opts) {
1777
2243
  });
1778
2244
  }
1779
2245
 
1780
- // src/passes/pass.ts
1781
- var import_zod7 = require("zod");
1782
- var PASS_KINDS = [
1783
- "ride-ticket",
1784
- "transit-pass",
1785
- "event-ticket",
1786
- "voucher",
1787
- "loyalty",
1788
- "receipt-link"
1789
- ];
1790
- var PASS_STATES = [
1791
- "issued",
1792
- "active",
1793
- "redeemed",
1794
- "expired",
1795
- "revoked"
2246
+ // src/partner/client.ts
2247
+ var import_zod8 = require("zod");
2248
+ var import_sha2563 = require("@noble/hashes/sha256");
2249
+ var import_hmac4 = require("@noble/hashes/hmac");
2250
+ var import_utils2 = require("@noble/hashes/utils");
2251
+ var PARTNER_SCOPES = [
2252
+ "passes:write",
2253
+ "passes:read",
2254
+ "passes:redeem",
2255
+ "receipts:write",
2256
+ "receipts:read",
2257
+ "offline:issue",
2258
+ "offline:settle",
2259
+ "offline:read",
2260
+ "collections:write",
2261
+ "collections:read",
2262
+ "collections:pay",
2263
+ "collections:webhook",
2264
+ "reports:read",
2265
+ "payouts:write",
2266
+ "payouts:read",
2267
+ "partner:funding:write",
2268
+ "partner:payout:write",
2269
+ "partner:reconciliation:read"
1796
2270
  ];
1797
- var HexString2 = (length) => import_zod7.z.string().regex(
1798
- new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1799
- `expected ${length}-byte hex string`
1800
- );
1801
- var PassMetadataSchema = import_zod7.z.record(
1802
- import_zod7.z.union([import_zod7.z.string(), import_zod7.z.number(), import_zod7.z.boolean(), import_zod7.z.null()])
1803
- );
1804
- var PassSchema = import_zod7.z.object({
1805
- passId: import_zod7.z.string().min(1),
1806
- /** Optional client/template grouping id (server may omit). */
1807
- templateId: import_zod7.z.string().min(1).optional(),
1808
- /** Optional human-facing holder identity (server may omit). The cryptographic binding
1809
- * is `holderDevicePubkey` below. */
1810
- holderUserId: import_zod7.z.string().min(1).optional(),
1811
- kind: import_zod7.z.enum(PASS_KINDS),
1812
- issuerId: import_zod7.z.string().min(1),
1813
- issuedAtMs: import_zod7.z.number().int().nonnegative(),
1814
- validFromMs: import_zod7.z.number().int().nonnegative(),
1815
- validUntilMs: import_zod7.z.number().int().positive(),
1816
- state: import_zod7.z.enum(PASS_STATES),
1817
- metadata: PassMetadataSchema,
1818
- nonce: import_zod7.z.string().min(1),
1819
- /** Device id this pass is bound to (FK to backend `device_keys`). */
1820
- holderDeviceId: import_zod7.z.string().min(1),
1821
- /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
1822
- * is verified against this key — it is the security-critical binding. */
1823
- holderDevicePubkey: HexString2(32),
1824
- /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
1825
- amountKobo: import_zod7.z.number().int().nonnegative().optional(),
1826
- /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
1827
- currency: import_zod7.z.string().min(3).max(8),
1828
- /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
1829
- counterSeed: import_zod7.z.number().int().nonnegative(),
1830
- /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
1831
- cumulativeCapKobo: import_zod7.z.number().int().nonnegative().optional(),
1832
- issuerSig: HexString2(64)
1833
- }).refine((v) => v.validUntilMs > v.validFromMs, {
1834
- message: "validUntilMs must be greater than validFromMs"
2271
+ var ApiCredentialPublicSchema = import_zod8.z.object({
2272
+ id: import_zod8.z.string().uuid(),
2273
+ accountId: import_zod8.z.string().uuid(),
2274
+ keyId: import_zod8.z.string(),
2275
+ scopes: import_zod8.z.array(import_zod8.z.enum(PARTNER_SCOPES)),
2276
+ label: import_zod8.z.string().nullable(),
2277
+ createdAtMs: import_zod8.z.number().int().nonnegative(),
2278
+ lastUsedAtMs: import_zod8.z.number().int().nonnegative().nullable(),
2279
+ revokedAtMs: import_zod8.z.number().int().nonnegative().nullable()
1835
2280
  });
1836
- function buildPass(input) {
1837
- if (input.validUntilMs <= input.validFromMs) {
1838
- throw new Error("validUntilMs must be greater than validFromMs");
1839
- }
1840
- const out = {
1841
- passId: input.passId,
1842
- kind: input.kind,
1843
- issuerId: input.issuerId,
1844
- issuedAtMs: input.issuedAtMs,
1845
- validFromMs: input.validFromMs,
1846
- validUntilMs: input.validUntilMs,
1847
- state: input.state,
1848
- metadata: input.metadata,
1849
- nonce: input.nonce,
1850
- holderDeviceId: input.holderDeviceId,
1851
- holderDevicePubkey: input.holderDevicePubkey,
1852
- currency: input.currency ?? "NGN",
1853
- counterSeed: input.counterSeed
1854
- };
1855
- if (typeof input.templateId === "string") out.templateId = input.templateId;
1856
- if (typeof input.holderUserId === "string")
1857
- out.holderUserId = input.holderUserId;
1858
- if (typeof input.amountKobo === "number") out.amountKobo = input.amountKobo;
1859
- if (typeof input.cumulativeCapKobo === "number") {
1860
- out.cumulativeCapKobo = input.cumulativeCapKobo;
1861
- }
1862
- return out;
2281
+ var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2282
+ secret: import_zod8.z.string().min(1)
2283
+ });
2284
+ var enc = new TextEncoder();
2285
+ async function sha256Hex2(input) {
2286
+ const data = typeof input === "string" ? enc.encode(input) : input;
2287
+ return (0, import_utils2.bytesToHex)((0, import_sha2563.sha256)(data));
1863
2288
  }
1864
- function signPass(unsigned, issuerPrivateKey) {
1865
- const issuerSig = bytesToHex(
1866
- sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
1867
- );
1868
- return { ...unsigned, issuerSig };
2289
+ async function hmacSha256Hex(keyHex, message) {
2290
+ return (0, import_utils2.bytesToHex)((0, import_hmac4.hmac)(import_sha2563.sha256, enc.encode(keyHex), enc.encode(message)));
1869
2291
  }
1870
- function verifyPass(pass, issuerPublicKey) {
1871
- try {
1872
- const parsed = PassSchema.parse(pass);
1873
- const { issuerSig, ...unsigned } = parsed;
1874
- return verify(
1875
- canonicalJSONBytes(unsigned),
1876
- hexToBytes(issuerSig),
1877
- issuerPublicKey
1878
- );
1879
- } catch {
1880
- return false;
1881
- }
2292
+ function defaultNonce2() {
2293
+ const c = globalThis.crypto;
2294
+ if (c?.randomUUID) return c.randomUUID();
2295
+ return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
1882
2296
  }
1883
- function isPassWithinValidity(pass, nowMs) {
1884
- return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;
2297
+ function canonical(params) {
2298
+ return [
2299
+ params.method.toUpperCase(),
2300
+ params.path,
2301
+ params.ts,
2302
+ params.nonce,
2303
+ params.bodyHash
2304
+ ].join("\n");
1885
2305
  }
1886
-
2306
+ async function signPartnerRequest(params) {
2307
+ const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
2308
+ const nonce = params.nonce ?? defaultNonce2();
2309
+ const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
2310
+ const bodyHash = await sha256Hex2(bodyData);
2311
+ const message = canonical({
2312
+ method: params.method,
2313
+ path: params.path,
2314
+ ts,
2315
+ nonce,
2316
+ bodyHash
2317
+ });
2318
+ const signingKey = await sha256Hex2(params.secret);
2319
+ const sig = await hmacSha256Hex(signingKey, message);
2320
+ return {
2321
+ authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
2322
+ ts,
2323
+ nonce,
2324
+ bodyHash
2325
+ };
2326
+ }
2327
+ function createFlurPartnerClient(opts) {
2328
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2329
+ if (!fetchImpl) {
2330
+ throw new Error(
2331
+ "createFlurPartnerClient: no fetch implementation available"
2332
+ );
2333
+ }
2334
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2335
+ const scopeHeader = normalizeScopeHeader(opts.scope);
2336
+ async function makeSignedInit(method, path, body) {
2337
+ const sig = await signPartnerRequest({
2338
+ keyId: opts.keyId,
2339
+ secret: opts.secret,
2340
+ method,
2341
+ path,
2342
+ body: body ?? "",
2343
+ nowMs: opts.nowMs?.(),
2344
+ nonce: opts.nonce?.()
2345
+ });
2346
+ const headers = {
2347
+ authorization: sig.authorization,
2348
+ accept: "application/json"
2349
+ };
2350
+ if (scopeHeader) headers["x-flur-scope"] = scopeHeader;
2351
+ if (body !== void 0) headers["content-type"] = "application/json";
2352
+ const init2 = { method, headers };
2353
+ if (body !== void 0) init2.body = body;
2354
+ return init2;
2355
+ }
2356
+ async function request(opts2) {
2357
+ const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
2358
+ const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
2359
+ const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
2360
+ const text = await resp.text();
2361
+ let raw;
2362
+ if (text) {
2363
+ try {
2364
+ raw = JSON.parse(text);
2365
+ } catch {
2366
+ }
2367
+ }
2368
+ if (!resp.ok) {
2369
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2370
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2371
+ throw new FlurApiError(resp.status, code, message, raw);
2372
+ }
2373
+ return raw;
2374
+ }
2375
+ const fetchLike = async (input, init2) => {
2376
+ const url = typeof input === "string" ? input : input.toString();
2377
+ const u = new URL(url, baseUrl);
2378
+ const path = `${u.pathname}${u.search}`;
2379
+ const method = (init2?.method ?? "GET").toUpperCase();
2380
+ let bodyStr;
2381
+ if (init2?.body) {
2382
+ bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
2383
+ }
2384
+ const signed = await makeSignedInit(method, path, bodyStr);
2385
+ return fetchImpl(`${baseUrl}${path}`, {
2386
+ ...init2,
2387
+ ...signed,
2388
+ headers: {
2389
+ ...init2?.headers,
2390
+ ...signed.headers
2391
+ }
2392
+ });
2393
+ };
2394
+ return { request, fetch: fetchLike };
2395
+ }
2396
+ function normalizeScopeHeader(scope) {
2397
+ if (!scope || scope.length === 0) return void 0;
2398
+ const unique = Array.from(new Set(scope));
2399
+ for (const item of unique) {
2400
+ if (!PARTNER_SCOPES.includes(item)) {
2401
+ throw new Error(`unsupported partner scope: ${item}`);
2402
+ }
2403
+ }
2404
+ return unique.join(" ");
2405
+ }
2406
+ function createApiCredentialsAdminClient(opts) {
2407
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2408
+ if (!fetchImpl) {
2409
+ throw new Error(
2410
+ "createApiCredentialsAdminClient: no fetch implementation available"
2411
+ );
2412
+ }
2413
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2414
+ async function call(method, path, body, parser) {
2415
+ const init2 = {
2416
+ method,
2417
+ headers: {
2418
+ "content-type": "application/json",
2419
+ accept: "application/json"
2420
+ }
2421
+ };
2422
+ if (body !== void 0) init2.body = JSON.stringify(body);
2423
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2424
+ const text = await resp.text();
2425
+ let raw;
2426
+ if (text) {
2427
+ try {
2428
+ raw = JSON.parse(text);
2429
+ } catch {
2430
+ }
2431
+ }
2432
+ if (!resp.ok) {
2433
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2434
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2435
+ throw new FlurApiError(resp.status, code, message, raw);
2436
+ }
2437
+ return parser(raw);
2438
+ }
2439
+ const listSchema = import_zod8.z.object({
2440
+ items: import_zod8.z.array(ApiCredentialPublicSchema)
2441
+ });
2442
+ return {
2443
+ list: (accountId) => call(
2444
+ "GET",
2445
+ `/v1/accounts/${accountId}/api-credentials`,
2446
+ void 0,
2447
+ (raw) => listSchema.parse(raw)
2448
+ ),
2449
+ mint: (accountId, input) => call(
2450
+ "POST",
2451
+ `/v1/accounts/${accountId}/api-credentials`,
2452
+ input,
2453
+ (raw) => MintedApiCredentialSchema.parse(raw)
2454
+ ),
2455
+ revoke: (accountId, credentialId) => call(
2456
+ "DELETE",
2457
+ `/v1/accounts/${accountId}/api-credentials/${credentialId}`,
2458
+ void 0,
2459
+ (raw) => ApiCredentialPublicSchema.parse(raw)
2460
+ )
2461
+ };
2462
+ }
2463
+
2464
+ // src/passes/pass.ts
2465
+ var import_zod9 = require("zod");
2466
+ var PASS_KINDS = [
2467
+ "ride-ticket",
2468
+ "transit-pass",
2469
+ "event-ticket",
2470
+ "voucher",
2471
+ "loyalty",
2472
+ "receipt-link"
2473
+ ];
2474
+ var PASS_STATES = [
2475
+ "issued",
2476
+ "active",
2477
+ "redeemed",
2478
+ "expired",
2479
+ "revoked"
2480
+ ];
2481
+ var HexString2 = (length) => import_zod9.z.string().regex(
2482
+ new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
2483
+ `expected ${length}-byte hex string`
2484
+ );
2485
+ var PassMetadataSchema = import_zod9.z.record(
2486
+ import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number(), import_zod9.z.boolean(), import_zod9.z.null()])
2487
+ );
2488
+ var PassSchema = import_zod9.z.object({
2489
+ passId: import_zod9.z.string().min(1),
2490
+ /** Optional client/template grouping id (server may omit). */
2491
+ templateId: import_zod9.z.string().min(1).optional(),
2492
+ /** Optional human-facing holder identity (server may omit). The cryptographic binding
2493
+ * is `holderDevicePubkey` below. */
2494
+ holderUserId: import_zod9.z.string().min(1).optional(),
2495
+ kind: import_zod9.z.enum(PASS_KINDS),
2496
+ issuerId: import_zod9.z.string().min(1),
2497
+ issuedAtMs: import_zod9.z.number().int().nonnegative(),
2498
+ validFromMs: import_zod9.z.number().int().nonnegative(),
2499
+ validUntilMs: import_zod9.z.number().int().positive(),
2500
+ state: import_zod9.z.enum(PASS_STATES),
2501
+ metadata: PassMetadataSchema,
2502
+ nonce: import_zod9.z.string().min(1),
2503
+ /** Device id this pass is bound to (FK to backend `device_keys`). */
2504
+ holderDeviceId: import_zod9.z.string().min(1),
2505
+ /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
2506
+ * is verified against this key — it is the security-critical binding. */
2507
+ holderDevicePubkey: HexString2(32),
2508
+ /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
2509
+ amountKobo: import_zod9.z.number().int().nonnegative().optional(),
2510
+ /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
2511
+ currency: import_zod9.z.string().min(3).max(8),
2512
+ /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
2513
+ counterSeed: import_zod9.z.number().int().nonnegative(),
2514
+ /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
2515
+ cumulativeCapKobo: import_zod9.z.number().int().nonnegative().optional(),
2516
+ issuerSig: HexString2(64)
2517
+ }).refine((v) => v.validUntilMs > v.validFromMs, {
2518
+ message: "validUntilMs must be greater than validFromMs"
2519
+ });
2520
+ function buildPass(input) {
2521
+ if (input.validUntilMs <= input.validFromMs) {
2522
+ throw new Error("validUntilMs must be greater than validFromMs");
2523
+ }
2524
+ const out = {
2525
+ passId: input.passId,
2526
+ kind: input.kind,
2527
+ issuerId: input.issuerId,
2528
+ issuedAtMs: input.issuedAtMs,
2529
+ validFromMs: input.validFromMs,
2530
+ validUntilMs: input.validUntilMs,
2531
+ state: input.state,
2532
+ metadata: input.metadata,
2533
+ nonce: input.nonce,
2534
+ holderDeviceId: input.holderDeviceId,
2535
+ holderDevicePubkey: input.holderDevicePubkey,
2536
+ currency: input.currency ?? "NGN",
2537
+ counterSeed: input.counterSeed
2538
+ };
2539
+ if (typeof input.templateId === "string") out.templateId = input.templateId;
2540
+ if (typeof input.holderUserId === "string")
2541
+ out.holderUserId = input.holderUserId;
2542
+ if (typeof input.amountKobo === "number") out.amountKobo = input.amountKobo;
2543
+ if (typeof input.cumulativeCapKobo === "number") {
2544
+ out.cumulativeCapKobo = input.cumulativeCapKobo;
2545
+ }
2546
+ return out;
2547
+ }
2548
+ function signPass(unsigned, issuerPrivateKey) {
2549
+ const issuerSig = bytesToHex(
2550
+ sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
2551
+ );
2552
+ return { ...unsigned, issuerSig };
2553
+ }
2554
+ function verifyPass(pass, issuerPublicKey) {
2555
+ try {
2556
+ const parsed = PassSchema.parse(pass);
2557
+ const { issuerSig, ...unsigned } = parsed;
2558
+ return verify(
2559
+ canonicalJSONBytes(unsigned),
2560
+ hexToBytes(issuerSig),
2561
+ issuerPublicKey
2562
+ );
2563
+ } catch {
2564
+ return false;
2565
+ }
2566
+ }
2567
+ function isPassWithinValidity(pass, nowMs) {
2568
+ return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;
2569
+ }
2570
+
1887
2571
  // src/passes/redemption.ts
1888
- var import_zod8 = require("zod");
1889
- var HexSig2 = import_zod8.z.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1890
- var RedemptionSchema = import_zod8.z.object({
2572
+ var import_zod10 = require("zod");
2573
+ var HexSig2 = import_zod10.z.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
2574
+ var RedemptionSchema = import_zod10.z.object({
1891
2575
  pass: PassSchema,
1892
- redeemerId: import_zod8.z.string().min(1),
1893
- redeemedAtMs: import_zod8.z.number().int().nonnegative(),
2576
+ redeemerId: import_zod10.z.string().min(1),
2577
+ redeemedAtMs: import_zod10.z.number().int().nonnegative(),
1894
2578
  /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
1895
2579
  * and > the redeemer's lastSeenCounter for this pass. */
1896
- counter: import_zod8.z.number().int().positive(),
2580
+ counter: import_zod10.z.number().int().positive(),
1897
2581
  /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
1898
- amountKobo: import_zod8.z.number().int().nonnegative(),
1899
- nonce: import_zod8.z.string().min(1),
2582
+ amountKobo: import_zod10.z.number().int().nonnegative(),
2583
+ nonce: import_zod10.z.string().min(1),
1900
2584
  holderSig: HexSig2
1901
2585
  });
1902
2586
  var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
@@ -1982,43 +2666,43 @@ function verifyRedemption(r, issuerPublicKey) {
1982
2666
  }
1983
2667
 
1984
2668
  // src/receipts/receipt.ts
1985
- var import_zod9 = require("zod");
2669
+ var import_zod11 = require("zod");
1986
2670
  var RECEIPT_CHANNELS = ["cash", "pass"];
1987
2671
  var RECEIPT_KINDS = RECEIPT_CHANNELS;
1988
- var HexString3 = (length) => import_zod9.z.string().regex(
2672
+ var HexString3 = (length) => import_zod11.z.string().regex(
1989
2673
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1990
2674
  `expected ${length}-byte hex string`
1991
2675
  );
1992
- var ReceiptPayloadSchema = import_zod9.z.record(
1993
- import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number(), import_zod9.z.boolean(), import_zod9.z.null()])
2676
+ var ReceiptPayloadSchema = import_zod11.z.record(
2677
+ import_zod11.z.union([import_zod11.z.string(), import_zod11.z.number(), import_zod11.z.boolean(), import_zod11.z.null()])
1994
2678
  );
1995
- var ReceiptSchema = import_zod9.z.object({
1996
- receiptId: import_zod9.z.string().min(1),
1997
- channel: import_zod9.z.enum(RECEIPT_CHANNELS),
2679
+ var ReceiptSchema = import_zod11.z.object({
2680
+ receiptId: import_zod11.z.string().min(1),
2681
+ channel: import_zod11.z.enum(RECEIPT_CHANNELS),
1998
2682
  /** Cash-channel: send_intents.id. Required when channel === 'cash'. */
1999
- intentId: import_zod9.z.string().min(1).optional(),
2683
+ intentId: import_zod11.z.string().min(1).optional(),
2000
2684
  /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
2001
- passRedemptionId: import_zod9.z.string().min(1).optional(),
2002
- payerUserId: import_zod9.z.string().min(1),
2003
- payeeUserId: import_zod9.z.string().min(1),
2004
- amountKobo: import_zod9.z.number().int().nonnegative(),
2005
- currency: import_zod9.z.string().min(3).max(8),
2006
- issuedAtMs: import_zod9.z.number().int().nonnegative(),
2007
- issuerId: import_zod9.z.string().min(1),
2685
+ passRedemptionId: import_zod11.z.string().min(1).optional(),
2686
+ payerUserId: import_zod11.z.string().min(1),
2687
+ payeeUserId: import_zod11.z.string().min(1),
2688
+ amountKobo: import_zod11.z.number().int().nonnegative(),
2689
+ currency: import_zod11.z.string().min(3).max(8),
2690
+ issuedAtMs: import_zod11.z.number().int().nonnegative(),
2691
+ issuerId: import_zod11.z.string().min(1),
2008
2692
  payload: ReceiptPayloadSchema,
2009
2693
  issuerSig: HexString3(64)
2010
2694
  }).superRefine((v, ctx) => {
2011
2695
  if (v.channel === "cash") {
2012
2696
  if (!v.intentId) {
2013
2697
  ctx.addIssue({
2014
- code: import_zod9.z.ZodIssueCode.custom,
2698
+ code: import_zod11.z.ZodIssueCode.custom,
2015
2699
  message: "cash receipts require intentId",
2016
2700
  path: ["intentId"]
2017
2701
  });
2018
2702
  }
2019
2703
  if (v.passRedemptionId) {
2020
2704
  ctx.addIssue({
2021
- code: import_zod9.z.ZodIssueCode.custom,
2705
+ code: import_zod11.z.ZodIssueCode.custom,
2022
2706
  message: "cash receipts must not carry passRedemptionId",
2023
2707
  path: ["passRedemptionId"]
2024
2708
  });
@@ -2026,14 +2710,14 @@ var ReceiptSchema = import_zod9.z.object({
2026
2710
  } else if (v.channel === "pass") {
2027
2711
  if (!v.passRedemptionId) {
2028
2712
  ctx.addIssue({
2029
- code: import_zod9.z.ZodIssueCode.custom,
2713
+ code: import_zod11.z.ZodIssueCode.custom,
2030
2714
  message: "pass receipts require passRedemptionId",
2031
2715
  path: ["passRedemptionId"]
2032
2716
  });
2033
2717
  }
2034
2718
  if (v.intentId) {
2035
2719
  ctx.addIssue({
2036
- code: import_zod9.z.ZodIssueCode.custom,
2720
+ code: import_zod11.z.ZodIssueCode.custom,
2037
2721
  message: "pass receipts must not carry intentId",
2038
2722
  path: ["intentId"]
2039
2723
  });
@@ -2284,55 +2968,27 @@ function parseQR(payload) {
2284
2968
  return parseNQR(payload);
2285
2969
  }
2286
2970
  function init(opts) {
2287
- const signedFetch = createHmacFetch({
2288
- apiKey: opts.apiKey,
2289
- apiSecret: opts.apiSecret,
2971
+ const partner = createFlurPartnerClient({
2972
+ baseUrl: opts.baseUrl,
2973
+ keyId: opts.apiKey,
2974
+ secret: opts.apiSecret,
2290
2975
  fetchImpl: opts.fetchImpl,
2291
2976
  scope: opts.scope
2292
2977
  });
2978
+ const signedFetch = partner.fetch;
2293
2979
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2294
2980
  function subscribeToPayments(s) {
2295
- const controller = new AbortController();
2296
2981
  let cancelled = false;
2297
- (async () => {
2298
- try {
2299
- const url = `${baseUrl}/v1/payments/subscribe?reference=${encodeURIComponent(s.reference)}`;
2300
- const resp = await signedFetch(url, {
2301
- method: "GET",
2302
- headers: { accept: "text/event-stream" },
2303
- signal: controller.signal
2304
- });
2305
- if (!resp.body) return;
2306
- const reader = resp.body.getReader();
2307
- const decoder = new TextDecoder();
2308
- let buffer = "";
2309
- while (!cancelled) {
2310
- const { value, done } = await reader.read();
2311
- if (done) return;
2312
- buffer += decoder.decode(value, { stream: true });
2313
- let idx;
2314
- while ((idx = buffer.indexOf("\n\n")) >= 0) {
2315
- const chunk = buffer.slice(0, idx);
2316
- buffer = buffer.slice(idx + 2);
2317
- for (const line of chunk.split("\n")) {
2318
- if (!line.startsWith("data:")) continue;
2319
- const json = line.slice(5).trim();
2320
- if (!json) continue;
2321
- try {
2322
- s.onEvent(JSON.parse(json));
2323
- } catch (err) {
2324
- s.onError?.(err);
2325
- }
2326
- }
2327
- }
2328
- }
2329
- } catch (err) {
2330
- if (!cancelled) s.onError?.(err);
2331
- }
2332
- })();
2982
+ queueMicrotask(() => {
2983
+ if (cancelled) return;
2984
+ s.onError?.(
2985
+ new Error(
2986
+ "cash.subscribeToPayments is not available on this backend release; use collections reports or provider webhooks for payment status."
2987
+ )
2988
+ );
2989
+ });
2333
2990
  return () => {
2334
2991
  cancelled = true;
2335
- controller.abort();
2336
2992
  };
2337
2993
  }
2338
2994
  const cash = {
@@ -2343,6 +2999,10 @@ function init(opts) {
2343
2999
  };
2344
3000
  const passes = createPassesClient({ baseUrl, fetchImpl: signedFetch });
2345
3001
  const receipts = createReceiptsClient({ baseUrl, fetchImpl: signedFetch });
3002
+ const collections = createPartnerCollectionsClient({
3003
+ baseUrl,
3004
+ fetchImpl: signedFetch
3005
+ });
2346
3006
  return {
2347
3007
  // top-level back-compat surface
2348
3008
  generateStaticQR,
@@ -2351,29 +3011,30 @@ function init(opts) {
2351
3011
  subscribeToPayments,
2352
3012
  // namespaces
2353
3013
  cash,
3014
+ collections,
2354
3015
  passes,
2355
3016
  receipts
2356
3017
  };
2357
3018
  }
2358
3019
 
2359
3020
  // src/accounts/client.ts
2360
- var import_zod10 = require("zod");
3021
+ var import_zod12 = require("zod");
2361
3022
  var ACCOUNT_TYPES = ["personal", "business", "partner"];
2362
3023
  var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
2363
3024
  var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
2364
- var AccountSchema = import_zod10.z.object({
2365
- accountId: import_zod10.z.string().uuid(),
2366
- type: import_zod10.z.enum(ACCOUNT_TYPES),
2367
- displayName: import_zod10.z.string().min(1),
2368
- status: import_zod10.z.enum(ACCOUNT_STATUSES),
2369
- ownerUserId: import_zod10.z.string().uuid().nullable(),
2370
- createdAtMs: import_zod10.z.number().int().nonnegative()
2371
- });
2372
- var AccountMembershipSchema = import_zod10.z.object({
2373
- accountId: import_zod10.z.string().uuid(),
2374
- userId: import_zod10.z.string().uuid(),
2375
- role: import_zod10.z.enum(MEMBERSHIP_ROLES),
2376
- createdAtMs: import_zod10.z.number().int().nonnegative()
3025
+ var AccountSchema = import_zod12.z.object({
3026
+ accountId: import_zod12.z.string().uuid(),
3027
+ type: import_zod12.z.enum(ACCOUNT_TYPES),
3028
+ displayName: import_zod12.z.string().min(1),
3029
+ status: import_zod12.z.enum(ACCOUNT_STATUSES),
3030
+ ownerUserId: import_zod12.z.string().uuid().nullable(),
3031
+ createdAtMs: import_zod12.z.number().int().nonnegative()
3032
+ });
3033
+ var AccountMembershipSchema = import_zod12.z.object({
3034
+ accountId: import_zod12.z.string().uuid(),
3035
+ userId: import_zod12.z.string().uuid(),
3036
+ role: import_zod12.z.enum(MEMBERSHIP_ROLES),
3037
+ createdAtMs: import_zod12.z.number().int().nonnegative()
2377
3038
  });
2378
3039
  function createAccountsClient(opts) {
2379
3040
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -2406,9 +3067,9 @@ function createAccountsClient(opts) {
2406
3067
  }
2407
3068
  return parser(raw);
2408
3069
  }
2409
- const itemsSchema = import_zod10.z.object({ items: import_zod10.z.array(AccountSchema) });
2410
- const memberItemsSchema = import_zod10.z.object({
2411
- items: import_zod10.z.array(AccountMembershipSchema)
3070
+ const itemsSchema = import_zod12.z.object({ items: import_zod12.z.array(AccountSchema) });
3071
+ const memberItemsSchema = import_zod12.z.object({
3072
+ items: import_zod12.z.array(AccountMembershipSchema)
2412
3073
  });
2413
3074
  return {
2414
3075
  listMyAccounts: () => call(
@@ -2439,110 +3100,182 @@ function createAccountsClient(opts) {
2439
3100
  };
2440
3101
  }
2441
3102
 
2442
- // src/partner/client.ts
2443
- var import_zod11 = require("zod");
2444
- var import_sha2563 = require("@noble/hashes/sha256");
2445
- var import_hmac4 = require("@noble/hashes/hmac");
2446
- var import_utils2 = require("@noble/hashes/utils");
2447
- var PARTNER_SCOPES = [
2448
- "passes:write",
2449
- "passes:read",
2450
- "passes:redeem",
2451
- "receipts:write",
2452
- "receipts:read",
2453
- "offline:issue",
2454
- "offline:settle",
2455
- "offline:read"
2456
- ];
2457
- var ApiCredentialPublicSchema = import_zod11.z.object({
2458
- id: import_zod11.z.string().uuid(),
2459
- accountId: import_zod11.z.string().uuid(),
2460
- keyId: import_zod11.z.string(),
2461
- scopes: import_zod11.z.array(import_zod11.z.enum(PARTNER_SCOPES)),
2462
- label: import_zod11.z.string().nullable(),
2463
- createdAtMs: import_zod11.z.number().int().nonnegative(),
2464
- lastUsedAtMs: import_zod11.z.number().int().nonnegative().nullable(),
2465
- revokedAtMs: import_zod11.z.number().int().nonnegative().nullable()
3103
+ // src/me-offline/client.ts
3104
+ var import_zod13 = require("zod");
3105
+ var Hex64 = import_zod13.z.string().regex(/^[0-9a-f]{64}$/i);
3106
+ var HexAny = import_zod13.z.string().regex(/^[0-9a-f]+$/i);
3107
+ var Sha256Hex = import_zod13.z.string().regex(/^[0-9a-f]{64}$/i);
3108
+ var RegisterDeviceKeyInputSchema = import_zod13.z.object({
3109
+ deviceId: import_zod13.z.string().min(1).max(128),
3110
+ publicKeyHex: Hex64
2466
3111
  });
2467
- var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2468
- secret: import_zod11.z.string().min(1)
3112
+ var DeviceKeyRecordSchema = import_zod13.z.object({
3113
+ id: import_zod13.z.string().uuid(),
3114
+ userId: import_zod13.z.string().uuid(),
3115
+ deviceId: import_zod13.z.string(),
3116
+ publicKeyHex: Hex64,
3117
+ createdAtMs: import_zod13.z.number().int().nonnegative(),
3118
+ revokedAtMs: import_zod13.z.number().int().nonnegative().nullable()
2469
3119
  });
2470
- var enc = new TextEncoder();
2471
- async function sha256Hex2(input) {
2472
- const data = typeof input === "string" ? enc.encode(input) : input;
2473
- return (0, import_utils2.bytesToHex)((0, import_sha2563.sha256)(data));
2474
- }
2475
- async function hmacSha256Hex(keyHex, message) {
2476
- return (0, import_utils2.bytesToHex)((0, import_hmac4.hmac)(import_sha2563.sha256, enc.encode(keyHex), enc.encode(message)));
2477
- }
2478
- function defaultNonce2() {
2479
- const c = globalThis.crypto;
2480
- if (c?.randomUUID) return c.randomUUID();
2481
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
2482
- }
2483
- function canonical(params) {
2484
- return [
2485
- params.method.toUpperCase(),
2486
- params.path,
2487
- params.ts,
2488
- params.nonce,
2489
- params.bodyHash
2490
- ].join("\n");
2491
- }
2492
- async function signPartnerRequest(params) {
2493
- const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
2494
- const nonce = params.nonce ?? defaultNonce2();
2495
- const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
2496
- const bodyHash = await sha256Hex2(bodyData);
2497
- const message = canonical({
2498
- method: params.method,
2499
- path: params.path,
2500
- ts,
2501
- nonce,
2502
- bodyHash
2503
- });
2504
- const signingKey = await sha256Hex2(params.secret);
2505
- const sig = await hmacSha256Hex(signingKey, message);
2506
- return {
2507
- authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
2508
- ts,
2509
- nonce,
2510
- bodyHash
2511
- };
2512
- }
2513
- function createFlurPartnerClient(opts) {
3120
+ var ConsumerOACSchema = import_zod13.z.object({
3121
+ oacId: import_zod13.z.string().uuid(),
3122
+ issuerId: import_zod13.z.string().min(1).max(64),
3123
+ userId: import_zod13.z.string().uuid(),
3124
+ deviceId: import_zod13.z.string().min(1).max(128),
3125
+ devicePubkeyHex: Hex64,
3126
+ perTxCapKobo: import_zod13.z.number().int().positive(),
3127
+ cumulativeCapKobo: import_zod13.z.number().int().positive(),
3128
+ currency: import_zod13.z.string().length(3),
3129
+ validFromMs: import_zod13.z.number().int().nonnegative(),
3130
+ validUntilMs: import_zod13.z.number().int().nonnegative(),
3131
+ counterSeed: import_zod13.z.number().int().nonnegative(),
3132
+ issuedAtMs: import_zod13.z.number().int().nonnegative()
3133
+ });
3134
+ var SignedConsumerOACSchema = import_zod13.z.object({
3135
+ oac: ConsumerOACSchema,
3136
+ issuerSig: HexAny,
3137
+ issuerPublicKeyHex: Hex64
3138
+ });
3139
+ var OACRecordSchema = SignedConsumerOACSchema.extend({
3140
+ currentOfflineSpentKobo: import_zod13.z.number().int().nonnegative(),
3141
+ status: import_zod13.z.enum([
3142
+ "active",
3143
+ "superseded",
3144
+ "expired",
3145
+ "revoked",
3146
+ "disabling",
3147
+ "draining",
3148
+ "closed"
3149
+ ]),
3150
+ supersededAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3151
+ revokedAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3152
+ holdId: import_zod13.z.string().uuid().nullable().optional()
3153
+ });
3154
+ var IssueOACInputSchema = import_zod13.z.object({
3155
+ deviceId: import_zod13.z.string().min(1).max(128),
3156
+ perTxCapKobo: import_zod13.z.number().int().positive().optional(),
3157
+ cumulativeCapKobo: import_zod13.z.number().int().positive().optional(),
3158
+ ttlMs: import_zod13.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
3159
+ spendableOnlineKobo: import_zod13.z.number().int().nonnegative().optional()
3160
+ });
3161
+ var EnableOfflineInputSchema = import_zod13.z.object({
3162
+ deviceId: import_zod13.z.string().min(1).max(128),
3163
+ amountKobo: import_zod13.z.number().int().positive(),
3164
+ perTxCapKobo: import_zod13.z.number().int().positive().optional(),
3165
+ ttlMs: import_zod13.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
3166
+ installId: import_zod13.z.string().min(1).max(128),
3167
+ partnerId: import_zod13.z.string().min(1).max(64).optional()
3168
+ });
3169
+ var DisableOfflineInputSchema = import_zod13.z.object({
3170
+ deviceId: import_zod13.z.string().min(1).max(128),
3171
+ installId: import_zod13.z.string().min(1).max(128).optional(),
3172
+ claims: import_zod13.z.array(import_zod13.z.unknown()).max(256).optional()
3173
+ });
3174
+ var OfflineHoldRecordSchema = import_zod13.z.object({
3175
+ holdId: import_zod13.z.string().uuid(),
3176
+ userId: import_zod13.z.string().uuid(),
3177
+ deviceId: import_zod13.z.string(),
3178
+ partnerId: import_zod13.z.string(),
3179
+ adapterKind: import_zod13.z.string(),
3180
+ externalHoldRef: import_zod13.z.string().nullable(),
3181
+ amountKobo: import_zod13.z.number().int().nonnegative(),
3182
+ capturedKobo: import_zod13.z.number().int().nonnegative(),
3183
+ releasedKobo: import_zod13.z.number().int().nonnegative(),
3184
+ remainingKobo: import_zod13.z.number().int().nonnegative(),
3185
+ currency: import_zod13.z.string().length(3),
3186
+ status: import_zod13.z.enum([
3187
+ "placing",
3188
+ "active",
3189
+ "disabling",
3190
+ "draining",
3191
+ "closed",
3192
+ "revoked",
3193
+ "failed"
3194
+ ]),
3195
+ installId: import_zod13.z.string().nullable(),
3196
+ drainDeadlineMs: import_zod13.z.number().int().nonnegative(),
3197
+ disableRequestedAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3198
+ createdAtMs: import_zod13.z.number().int().nonnegative(),
3199
+ closedAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3200
+ isTrusted: import_zod13.z.boolean().optional()
3201
+ });
3202
+ var EnableOfflineResultSchema = import_zod13.z.object({
3203
+ hold: OfflineHoldRecordSchema,
3204
+ oac: OACRecordSchema
3205
+ });
3206
+ var DisableOfflineResultSchema = import_zod13.z.object({
3207
+ hold: OfflineHoldRecordSchema,
3208
+ trusted: import_zod13.z.boolean(),
3209
+ settledClaims: import_zod13.z.number().int().nonnegative()
3210
+ });
3211
+ var OfflineStatusResultSchema = import_zod13.z.object({
3212
+ hold: OfflineHoldRecordSchema.nullable(),
3213
+ active: OACRecordSchema.nullable()
3214
+ });
3215
+ var OfflineStateResultSchema = import_zod13.z.object({
3216
+ active: OACRecordSchema.nullable()
3217
+ });
3218
+ var ConsumerPaymentClaimSchema = import_zod13.z.object({
3219
+ oacId: import_zod13.z.string().uuid(),
3220
+ encounterId: Sha256Hex.optional(),
3221
+ payerUserId: import_zod13.z.string().uuid(),
3222
+ payeeUserId: import_zod13.z.string().uuid(),
3223
+ payerDeviceId: import_zod13.z.string().min(1).max(128),
3224
+ payerNonce: import_zod13.z.string().min(8).max(128),
3225
+ payeeNonce: import_zod13.z.string().min(8).max(128),
3226
+ amountKobo: import_zod13.z.number().int().positive(),
3227
+ currency: import_zod13.z.string().length(3).default("NGN"),
3228
+ occurredAtMs: import_zod13.z.number().int().nonnegative(),
3229
+ completedAtMs: import_zod13.z.number().int().nonnegative().optional(),
3230
+ contextId: import_zod13.z.string().max(128).optional(),
3231
+ payerPubkeyHex: Hex64,
3232
+ payerSignature: HexAny,
3233
+ payeePubkeyHex: Hex64.optional(),
3234
+ payeeSignature: HexAny.optional()
3235
+ });
3236
+ var ConsumerSettlementSchema = import_zod13.z.object({
3237
+ settlementId: import_zod13.z.string().uuid(),
3238
+ settlementKey: Sha256Hex,
3239
+ encounterId: Sha256Hex,
3240
+ oacId: import_zod13.z.string().uuid(),
3241
+ payerUserId: import_zod13.z.string().uuid(),
3242
+ payeeUserId: import_zod13.z.string().uuid(),
3243
+ amountKobo: import_zod13.z.number().int().positive(),
3244
+ currency: import_zod13.z.string().length(3),
3245
+ status: import_zod13.z.enum(["SETTLED", "REVIEW"]),
3246
+ reviewReason: import_zod13.z.string().nullable(),
3247
+ ledgerRef: import_zod13.z.string().nullable(),
3248
+ issuerSig: HexAny,
3249
+ createdAtMs: import_zod13.z.number().int().nonnegative()
3250
+ });
3251
+ var ConsumerSettleResultSchema = import_zod13.z.object({
3252
+ settlement: ConsumerSettlementSchema,
3253
+ encounterId: Sha256Hex,
3254
+ replayed: import_zod13.z.boolean()
3255
+ });
3256
+ var RevokeDeviceKeyInputSchema = import_zod13.z.object({
3257
+ deviceId: import_zod13.z.string().min(1).max(128),
3258
+ /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
3259
+ sendAuthToken: import_zod13.z.string().min(16)
3260
+ });
3261
+ function createMeOfflineClient(opts) {
2514
3262
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2515
3263
  if (!fetchImpl) {
2516
- throw new Error(
2517
- "createFlurPartnerClient: no fetch implementation available"
2518
- );
3264
+ throw new Error("createMeOfflineClient: no fetch implementation available");
2519
3265
  }
2520
3266
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2521
- async function makeSignedInit(method, path, body) {
2522
- const sig = await signPartnerRequest({
2523
- keyId: opts.keyId,
2524
- secret: opts.secret,
3267
+ async function call(method, path, body, parser) {
3268
+ const init2 = {
2525
3269
  method,
2526
- path,
2527
- body: body ?? "",
2528
- nowMs: opts.nowMs?.(),
2529
- nonce: opts.nonce?.()
2530
- });
2531
- const headers = {
2532
- authorization: sig.authorization,
2533
- accept: "application/json"
3270
+ headers: {
3271
+ "content-type": "application/json",
3272
+ accept: "application/json"
3273
+ }
2534
3274
  };
2535
- if (body !== void 0) headers["content-type"] = "application/json";
2536
- const init2 = { method, headers };
2537
- if (body !== void 0) init2.body = body;
2538
- return init2;
2539
- }
2540
- async function request(opts2) {
2541
- const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
2542
- const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
2543
- const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
3275
+ if (body !== void 0) init2.body = JSON.stringify(body);
3276
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2544
3277
  const text = await resp.text();
2545
- let raw;
3278
+ let raw = void 0;
2546
3279
  if (text) {
2547
3280
  try {
2548
3281
  raw = JSON.parse(text);
@@ -2554,46 +3287,290 @@ function createFlurPartnerClient(opts) {
2554
3287
  const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2555
3288
  throw new FlurApiError(resp.status, code, message, raw);
2556
3289
  }
2557
- return raw;
3290
+ return parser(raw);
2558
3291
  }
2559
- const fetchLike = async (input, init2) => {
2560
- const url = typeof input === "string" ? input : input.toString();
2561
- const u = new URL(url, baseUrl);
2562
- const path = `${u.pathname}${u.search}`;
2563
- const method = (init2?.method ?? "GET").toUpperCase();
2564
- let bodyStr;
2565
- if (init2?.body) {
2566
- bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
3292
+ const deviceKeyItems = import_zod13.z.object({ items: import_zod13.z.array(DeviceKeyRecordSchema) });
3293
+ return {
3294
+ registerDeviceKey: (input) => call(
3295
+ "POST",
3296
+ "/v1/me/offline/keys",
3297
+ RegisterDeviceKeyInputSchema.parse(input),
3298
+ (raw) => DeviceKeyRecordSchema.parse(raw)
3299
+ ),
3300
+ listDeviceKeys: () => call(
3301
+ "GET",
3302
+ "/v1/me/offline/keys",
3303
+ void 0,
3304
+ (raw) => deviceKeyItems.parse(raw)
3305
+ ),
3306
+ revokeDeviceKey: (input) => call(
3307
+ "POST",
3308
+ "/v1/me/offline/keys/revoke",
3309
+ RevokeDeviceKeyInputSchema.parse(input),
3310
+ () => void 0
3311
+ ),
3312
+ enable: (input) => call(
3313
+ "POST",
3314
+ "/v1/me/offline/enable",
3315
+ EnableOfflineInputSchema.parse(input),
3316
+ (raw) => EnableOfflineResultSchema.parse(raw)
3317
+ ),
3318
+ refresh: (input) => call(
3319
+ "POST",
3320
+ "/v1/me/offline/refresh",
3321
+ IssueOACInputSchema.parse(input),
3322
+ (raw) => OACRecordSchema.parse(raw)
3323
+ ),
3324
+ disable: (input) => call(
3325
+ "POST",
3326
+ "/v1/me/offline/disable",
3327
+ DisableOfflineInputSchema.parse(input),
3328
+ (raw) => DisableOfflineResultSchema.parse(raw)
3329
+ ),
3330
+ getStatus: (deviceId) => {
3331
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3332
+ return call(
3333
+ "GET",
3334
+ `/v1/me/offline/status${qs}`,
3335
+ void 0,
3336
+ (raw) => OfflineStatusResultSchema.parse(raw)
3337
+ );
3338
+ },
3339
+ getState: (deviceId) => {
3340
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3341
+ return call(
3342
+ "GET",
3343
+ `/v1/me/offline/state${qs}`,
3344
+ void 0,
3345
+ (raw) => OfflineStateResultSchema.parse(raw)
3346
+ );
3347
+ },
3348
+ submitClaim: (claim) => call(
3349
+ "POST",
3350
+ "/v1/me/offline/claims",
3351
+ ConsumerPaymentClaimSchema.parse(claim),
3352
+ (raw) => ConsumerSettleResultSchema.parse(raw)
3353
+ )
3354
+ };
3355
+ }
3356
+
3357
+ // src/partner-funding/client.ts
3358
+ var import_zod14 = require("zod");
3359
+ var MinorString = import_zod14.z.string().regex(/^-?\d+$/);
3360
+ var PositiveMinor = import_zod14.z.union([
3361
+ import_zod14.z.number().int().positive(),
3362
+ import_zod14.z.string().regex(/^[1-9]\d{0,18}$/)
3363
+ ]);
3364
+ var Currency = import_zod14.z.string().trim().length(3).transform((v) => v.toUpperCase());
3365
+ var Metadata = import_zod14.z.record(import_zod14.z.unknown());
3366
+ var PARTNER_KINDS = ["bank", "merchant"];
3367
+ var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
3368
+ var PARTNER_PROFILE_STATUSES = [
3369
+ "active",
3370
+ "suspended",
3371
+ "closed"
3372
+ ];
3373
+ var PARTNER_FUNDING_DIRECTIONS = ["credit", "debit"];
3374
+ var PARTNER_FUNDING_STATUSES = [
3375
+ "pending",
3376
+ "posted",
3377
+ "failed"
3378
+ ];
3379
+ var PAYOUT_DESTINATION_STATUSES = [
3380
+ "pending",
3381
+ "verified",
3382
+ "disabled"
3383
+ ];
3384
+ var WITHDRAWAL_STATES = [
3385
+ "requested",
3386
+ "submitted",
3387
+ "processing",
3388
+ "paid",
3389
+ "failed",
3390
+ "reversed"
3391
+ ];
3392
+ var PartnerProfileSchema = import_zod14.z.object({
3393
+ partnerAccountId: import_zod14.z.string().uuid(),
3394
+ kind: import_zod14.z.enum(PARTNER_KINDS),
3395
+ custodialMode: import_zod14.z.enum(CUSTODIAL_MODES),
3396
+ displayName: import_zod14.z.string(),
3397
+ bankCode: import_zod14.z.string().nullable(),
3398
+ poolAccountNumber: import_zod14.z.string().nullable(),
3399
+ status: import_zod14.z.enum(PARTNER_PROFILE_STATUSES),
3400
+ metadata: Metadata,
3401
+ createdAtMs: import_zod14.z.number().int().nonnegative(),
3402
+ updatedAtMs: import_zod14.z.number().int().nonnegative()
3403
+ });
3404
+ var UpsertPartnerProfileInputSchema = import_zod14.z.object({
3405
+ kind: import_zod14.z.enum(PARTNER_KINDS),
3406
+ custodialMode: import_zod14.z.enum(CUSTODIAL_MODES),
3407
+ displayName: import_zod14.z.string().trim().min(1).max(200),
3408
+ bankCode: import_zod14.z.string().trim().min(1).max(64).optional(),
3409
+ poolAccountNumber: import_zod14.z.string().trim().min(1).max(64).optional(),
3410
+ metadata: Metadata.optional()
3411
+ });
3412
+ var PartnerFundingEventInputSchema = import_zod14.z.object({
3413
+ externalRef: import_zod14.z.string().trim().min(8).max(128),
3414
+ direction: import_zod14.z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
3415
+ userId: import_zod14.z.string().uuid().optional(),
3416
+ accountId: import_zod14.z.string().uuid().optional(),
3417
+ amountMinor: PositiveMinor,
3418
+ currency: Currency,
3419
+ fundingSource: import_zod14.z.string().trim().min(1).max(64).optional(),
3420
+ providerMetadata: Metadata.optional()
3421
+ });
3422
+ var PartnerFundingSchema = import_zod14.z.object({
3423
+ fundingId: import_zod14.z.string().uuid(),
3424
+ partnerId: import_zod14.z.string().uuid(),
3425
+ accountId: import_zod14.z.string().uuid(),
3426
+ userId: import_zod14.z.string().uuid().nullable(),
3427
+ direction: import_zod14.z.enum(PARTNER_FUNDING_DIRECTIONS),
3428
+ currency: import_zod14.z.string(),
3429
+ amountMinor: MinorString,
3430
+ externalRef: import_zod14.z.string(),
3431
+ status: import_zod14.z.enum(PARTNER_FUNDING_STATUSES),
3432
+ fundingSource: import_zod14.z.string(),
3433
+ ledgerRef: import_zod14.z.string(),
3434
+ providerMetadata: Metadata,
3435
+ createdAtMs: import_zod14.z.number().int().nonnegative(),
3436
+ updatedAtMs: import_zod14.z.number().int().nonnegative()
3437
+ });
3438
+ var IngestFundingResultSchema = import_zod14.z.object({
3439
+ funding: PartnerFundingSchema,
3440
+ replayed: import_zod14.z.boolean()
3441
+ });
3442
+ var PayoutDestinationSchema = import_zod14.z.object({
3443
+ destinationId: import_zod14.z.string().uuid(),
3444
+ accountId: import_zod14.z.string().uuid(),
3445
+ partnerId: import_zod14.z.string().uuid(),
3446
+ bankCode: import_zod14.z.string(),
3447
+ accountNumber: import_zod14.z.string(),
3448
+ accountName: import_zod14.z.string(),
3449
+ status: import_zod14.z.enum(PAYOUT_DESTINATION_STATUSES),
3450
+ verifiedAtMs: import_zod14.z.number().int().nonnegative().nullable(),
3451
+ metadata: Metadata,
3452
+ createdAtMs: import_zod14.z.number().int().nonnegative(),
3453
+ updatedAtMs: import_zod14.z.number().int().nonnegative()
3454
+ });
3455
+ var CreatePayoutDestinationInputSchema = import_zod14.z.object({
3456
+ partnerId: import_zod14.z.string().uuid(),
3457
+ bankCode: import_zod14.z.string().trim().min(1).max(32),
3458
+ accountNumber: import_zod14.z.string().trim().min(4).max(64),
3459
+ accountName: import_zod14.z.string().trim().min(1).max(200),
3460
+ metadata: Metadata.optional()
3461
+ });
3462
+ var ListPayoutDestinationsResultSchema = import_zod14.z.object({
3463
+ items: import_zod14.z.array(PayoutDestinationSchema)
3464
+ });
3465
+ var WithdrawalSchema = import_zod14.z.object({
3466
+ withdrawalId: import_zod14.z.string().uuid(),
3467
+ accountId: import_zod14.z.string().uuid(),
3468
+ userId: import_zod14.z.string().uuid(),
3469
+ partnerId: import_zod14.z.string().uuid(),
3470
+ destinationId: import_zod14.z.string().uuid(),
3471
+ currency: import_zod14.z.string(),
3472
+ amountMinor: MinorString,
3473
+ state: import_zod14.z.enum(WITHDRAWAL_STATES),
3474
+ idempotencyKey: import_zod14.z.string(),
3475
+ providerRef: import_zod14.z.string().nullable(),
3476
+ lastError: import_zod14.z.string().nullable(),
3477
+ ledgerRef: import_zod14.z.string(),
3478
+ reverseLedgerRef: import_zod14.z.string().nullable(),
3479
+ metadata: Metadata,
3480
+ createdAtMs: import_zod14.z.number().int().nonnegative(),
3481
+ updatedAtMs: import_zod14.z.number().int().nonnegative()
3482
+ });
3483
+ var CreateWithdrawalInputSchema = import_zod14.z.object({
3484
+ destinationId: import_zod14.z.string().uuid(),
3485
+ amountMinor: PositiveMinor,
3486
+ currency: Currency,
3487
+ idempotencyKey: import_zod14.z.string().trim().min(8).max(128),
3488
+ metadata: Metadata.optional()
3489
+ });
3490
+ var CreateWithdrawalResultSchema = import_zod14.z.object({
3491
+ withdrawal: WithdrawalSchema,
3492
+ replayed: import_zod14.z.boolean()
3493
+ });
3494
+ var PayoutEventInputSchema = import_zod14.z.object({
3495
+ externalRef: import_zod14.z.string().trim().min(8).max(128),
3496
+ withdrawalId: import_zod14.z.string().uuid().optional(),
3497
+ state: import_zod14.z.enum(["submitted", "processing", "paid", "failed"]),
3498
+ providerRef: import_zod14.z.string().trim().min(1).max(128).optional(),
3499
+ failureCode: import_zod14.z.string().trim().max(64).optional(),
3500
+ failureMessage: import_zod14.z.string().trim().max(512).optional(),
3501
+ providerMetadata: Metadata.optional()
3502
+ });
3503
+ var RecordPayoutEventResultSchema = import_zod14.z.object({
3504
+ withdrawal: WithdrawalSchema,
3505
+ replayed: import_zod14.z.boolean()
3506
+ });
3507
+ var ReconciliationReportSchema = import_zod14.z.object({
3508
+ partnerId: import_zod14.z.string().uuid(),
3509
+ currency: import_zod14.z.string(),
3510
+ fromMs: import_zod14.z.number().int().nonnegative(),
3511
+ toMs: import_zod14.z.number().int().nonnegative(),
3512
+ fundingsCreditMinor: MinorString,
3513
+ fundingsDebitMinor: MinorString,
3514
+ withdrawalsPaidMinor: MinorString,
3515
+ withdrawalsReversedMinor: MinorString,
3516
+ withdrawalsInFlightMinor: MinorString,
3517
+ expectedReserveBalanceMinor: MinorString,
3518
+ actualReserveBalanceMinor: MinorString,
3519
+ imbalanceMinor: MinorString,
3520
+ generatedAtMs: import_zod14.z.number().int().nonnegative()
3521
+ });
3522
+ function createPartnerFundingClient(partner) {
3523
+ return {
3524
+ ingestFunding: async (input) => {
3525
+ const body = PartnerFundingEventInputSchema.parse(input);
3526
+ const raw = await partner.request({
3527
+ method: "POST",
3528
+ path: "/v1/partners/fundings",
3529
+ body
3530
+ });
3531
+ return IngestFundingResultSchema.parse(raw);
3532
+ },
3533
+ recordPayoutEvent: async (input) => {
3534
+ const body = PayoutEventInputSchema.parse(input);
3535
+ const raw = await partner.request({
3536
+ method: "POST",
3537
+ path: "/v1/partners/payouts/events",
3538
+ body
3539
+ });
3540
+ return RecordPayoutEventResultSchema.parse(raw);
3541
+ },
3542
+ reconciliation: async (input) => {
3543
+ const qs = new URLSearchParams({
3544
+ currency: input.currency
3545
+ });
3546
+ if (typeof input.fromMs === "number")
3547
+ qs.set("fromMs", String(input.fromMs));
3548
+ if (typeof input.toMs === "number") qs.set("toMs", String(input.toMs));
3549
+ const raw = await partner.request({
3550
+ method: "GET",
3551
+ path: `/v1/partners/reconciliation/daily?${qs.toString()}`
3552
+ });
3553
+ return ReconciliationReportSchema.parse(raw);
2567
3554
  }
2568
- const signed = await makeSignedInit(method, path, bodyStr);
2569
- return fetchImpl(`${baseUrl}${path}`, {
2570
- ...init2,
2571
- ...signed,
2572
- headers: {
2573
- ...init2?.headers,
2574
- ...signed.headers
2575
- }
2576
- });
2577
3555
  };
2578
- return { request, fetch: fetchLike };
2579
3556
  }
2580
- function createApiCredentialsAdminClient(opts) {
3557
+ function createConsumerWithdrawalsClient(opts) {
2581
3558
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2582
3559
  if (!fetchImpl) {
2583
3560
  throw new Error(
2584
- "createApiCredentialsAdminClient: no fetch implementation available"
3561
+ "createConsumerWithdrawalsClient: no fetch implementation available"
2585
3562
  );
2586
3563
  }
2587
3564
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
2588
3565
  async function call(method, path, body, parser) {
2589
3566
  const init2 = {
2590
3567
  method,
2591
- headers: {
2592
- "content-type": "application/json",
2593
- accept: "application/json"
2594
- }
3568
+ headers: { accept: "application/json" }
2595
3569
  };
2596
- if (body !== void 0) init2.body = JSON.stringify(body);
3570
+ if (body !== void 0) {
3571
+ init2.body = JSON.stringify(body);
3572
+ init2.headers = { ...init2.headers, "content-type": "application/json" };
3573
+ }
2597
3574
  const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2598
3575
  const text = await resp.text();
2599
3576
  let raw;
@@ -2601,6 +3578,7 @@ function createApiCredentialsAdminClient(opts) {
2601
3578
  try {
2602
3579
  raw = JSON.parse(text);
2603
3580
  } catch {
3581
+ raw = text;
2604
3582
  }
2605
3583
  }
2606
3584
  if (!resp.ok) {
@@ -2610,30 +3588,85 @@ function createApiCredentialsAdminClient(opts) {
2610
3588
  }
2611
3589
  return parser(raw);
2612
3590
  }
2613
- const listSchema = import_zod11.z.object({
2614
- items: import_zod11.z.array(ApiCredentialPublicSchema)
2615
- });
2616
3591
  return {
2617
- list: (accountId) => call(
3592
+ listDestinations: () => call(
2618
3593
  "GET",
2619
- `/v1/accounts/${accountId}/api-credentials`,
3594
+ "/v1/me/payout-destinations",
2620
3595
  void 0,
2621
- (raw) => listSchema.parse(raw)
3596
+ (raw) => ListPayoutDestinationsResultSchema.parse(raw)
2622
3597
  ),
2623
- mint: (accountId, input) => call(
3598
+ createDestination: (input) => call(
2624
3599
  "POST",
2625
- `/v1/accounts/${accountId}/api-credentials`,
2626
- input,
2627
- (raw) => MintedApiCredentialSchema.parse(raw)
3600
+ "/v1/me/payout-destinations",
3601
+ CreatePayoutDestinationInputSchema.parse(input),
3602
+ (raw) => PayoutDestinationSchema.parse(raw)
2628
3603
  ),
2629
- revoke: (accountId, credentialId) => call(
2630
- "DELETE",
2631
- `/v1/accounts/${accountId}/api-credentials/${credentialId}`,
3604
+ verifyDestination: (destinationId) => call(
3605
+ "POST",
3606
+ `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/verify`,
3607
+ {},
3608
+ (raw) => PayoutDestinationSchema.parse(raw)
3609
+ ),
3610
+ disableDestination: (destinationId) => call(
3611
+ "POST",
3612
+ `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/disable`,
3613
+ {},
3614
+ (raw) => PayoutDestinationSchema.parse(raw)
3615
+ ),
3616
+ createWithdrawal: (input) => call(
3617
+ "POST",
3618
+ "/v1/me/withdrawals",
3619
+ CreateWithdrawalInputSchema.parse(input),
3620
+ (raw) => CreateWithdrawalResultSchema.parse(raw)
3621
+ ),
3622
+ getWithdrawal: (withdrawalId) => call(
3623
+ "GET",
3624
+ `/v1/me/withdrawals/${encodeURIComponent(withdrawalId)}`,
2632
3625
  void 0,
2633
- (raw) => ApiCredentialPublicSchema.parse(raw)
3626
+ (raw) => WithdrawalSchema.parse(raw)
2634
3627
  )
2635
3628
  };
2636
3629
  }
3630
+ function createPartnerProfileAdminClient(opts) {
3631
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3632
+ if (!fetchImpl) {
3633
+ throw new Error(
3634
+ "createPartnerProfileAdminClient: no fetch implementation available"
3635
+ );
3636
+ }
3637
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
3638
+ return {
3639
+ upsertProfile: async (partnerAccountId, input) => {
3640
+ const body = {
3641
+ partnerAccountId,
3642
+ ...UpsertPartnerProfileInputSchema.parse(input)
3643
+ };
3644
+ const resp = await fetchImpl(`${baseUrl}/v1/partners/profile`, {
3645
+ method: "POST",
3646
+ headers: {
3647
+ "content-type": "application/json",
3648
+ accept: "application/json"
3649
+ },
3650
+ body: JSON.stringify(body)
3651
+ });
3652
+ const text = await resp.text();
3653
+ let raw;
3654
+ if (text) {
3655
+ try {
3656
+ raw = JSON.parse(text);
3657
+ } catch {
3658
+ raw = text;
3659
+ }
3660
+ }
3661
+ if (!resp.ok) {
3662
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3663
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3664
+ throw new FlurApiError(resp.status, code, message, raw);
3665
+ }
3666
+ return PartnerProfileSchema.parse(raw);
3667
+ }
3668
+ };
3669
+ }
2637
3670
  // Annotate the CommonJS export names for ESM import in node:
2638
3671
  0 && (module.exports = {
2639
3672
  ACCOUNT_STATUSES,
@@ -2642,6 +3675,29 @@ function createApiCredentialsAdminClient(opts) {
2642
3675
  AccountMembershipSchema,
2643
3676
  AccountSchema,
2644
3677
  ApiCredentialPublicSchema,
3678
+ COLLECTION_INTENT_STATUSES,
3679
+ COLLECTION_PAYMENT_STATUSES,
3680
+ CUSTODIAL_MODES,
3681
+ CollectionIntentSchema,
3682
+ CollectionPaymentResultSchema,
3683
+ CollectionPaymentSchema,
3684
+ CollectionReportSummarySchema,
3685
+ CollectionStatementSchema,
3686
+ ConsumerOACRecordSchema,
3687
+ ConsumerOACSchema,
3688
+ ConsumerPaymentClaimSchema,
3689
+ ConsumerSettleResultSchema,
3690
+ ConsumerSettlementSchema,
3691
+ CreateCollectionIntentInputSchema,
3692
+ CreatePayoutDestinationInputSchema,
3693
+ CreatePayoutInputSchema,
3694
+ CreateWithdrawalInputSchema,
3695
+ CreateWithdrawalResultSchema,
3696
+ DeviceKeyRecordSchema,
3697
+ DisableOfflineInputSchema,
3698
+ DisableOfflineResultSchema,
3699
+ EnableOfflineInputSchema,
3700
+ EnableOfflineResultSchema,
2645
3701
  FIELD,
2646
3702
  FlurApiError,
2647
3703
  FlurCapExceededError,
@@ -2649,7 +3705,14 @@ function createApiCredentialsAdminClient(opts) {
2649
3705
  FlurError,
2650
3706
  FlurExpiredError,
2651
3707
  FlurReplayError,
3708
+ IngestFundingResultSchema,
3709
+ IssueOACInputSchema,
3710
+ ListPayoutDestinationsResultSchema,
2652
3711
  MEMBERSHIP_ROLES,
3712
+ MERCHANT_PAYOUT_STATUSES,
3713
+ MERCHANT_PROFILE_STATUSES,
3714
+ MerchantPayoutSchema,
3715
+ MerchantProfileSchema,
2653
3716
  MintedApiCredentialSchema,
2654
3717
  NGN_CURRENCY_CODE,
2655
3718
  NG_COUNTRY_CODE,
@@ -2658,25 +3721,52 @@ function createApiCredentialsAdminClient(opts) {
2658
3721
  OAC_DEFAULT_CUMULATIVE_KOBO,
2659
3722
  OAC_DEFAULT_PER_TX_KOBO,
2660
3723
  OAC_DEFAULT_VALIDITY_MS,
3724
+ OfflineHoldRecordSchema,
2661
3725
  OfflinePaymentAuthorizationSchema,
2662
3726
  OfflinePaymentRequestSchema,
3727
+ OfflineStateResultSchema,
3728
+ OfflineStatusResultSchema,
2663
3729
  OfflineTokenSchema,
3730
+ PARTNER_FUNDING_DIRECTIONS,
3731
+ PARTNER_FUNDING_STATUSES,
3732
+ PARTNER_KINDS,
3733
+ PARTNER_PROFILE_STATUSES,
2664
3734
  PARTNER_SCOPES,
2665
3735
  PASS_KINDS,
2666
3736
  PASS_STATES,
2667
3737
  PAYLOAD_FORMAT_INDICATOR_VALUE,
3738
+ PAYOUT_DESTINATION_STATUSES,
2668
3739
  POINT_OF_INITIATION,
3740
+ PartnerFundingEventInputSchema,
3741
+ PartnerFundingSchema,
3742
+ PartnerProfileSchema,
2669
3743
  PassMetadataSchema,
2670
3744
  PassSchema,
3745
+ PayCollectionInputSchema,
2671
3746
  PaymentClaimSchema,
3747
+ PayoutDestinationSchema,
3748
+ PayoutEventInputSchema,
3749
+ ProviderEventInputSchema,
3750
+ ProviderEventRecordSchema,
3751
+ PublicCollectionIntentSchema,
2672
3752
  RECEIPT_CHANNELS,
2673
3753
  RECEIPT_KINDS,
2674
3754
  REPLAY_WINDOW_MS,
2675
3755
  ReceiptPayloadSchema,
2676
3756
  ReceiptSchema,
3757
+ ReconciliationReportSchema,
3758
+ RecordPayoutEventResultSchema,
2677
3759
  RedemptionSchema,
3760
+ RegisterDeviceKeyInputSchema,
3761
+ RevokeDeviceKeyInputSchema,
3762
+ SETTLEMENT_SCHEDULES,
2678
3763
  SettleResponseSchema,
2679
3764
  SettlementSchema,
3765
+ SignedConsumerOACSchema,
3766
+ UpsertMerchantProfileInputSchema,
3767
+ UpsertPartnerProfileInputSchema,
3768
+ WITHDRAWAL_STATES,
3769
+ WithdrawalSchema,
2680
3770
  bodySha256Hex,
2681
3771
  buildAuthorization,
2682
3772
  buildOAC,
@@ -2693,9 +3783,16 @@ function createApiCredentialsAdminClient(opts) {
2693
3783
  crc16ccittHex,
2694
3784
  createAccountsClient,
2695
3785
  createApiCredentialsAdminClient,
3786
+ createCollectionsClient,
3787
+ createConsumerCollectionsClient,
3788
+ createConsumerWithdrawalsClient,
2696
3789
  createFlurPartnerClient,
2697
3790
  createHmacFetch,
3791
+ createMeOfflineClient,
2698
3792
  createOfflineSettlementsClient,
3793
+ createPartnerCollectionsClient,
3794
+ createPartnerFundingClient,
3795
+ createPartnerProfileAdminClient,
2699
3796
  createPassesClient,
2700
3797
  createReceiptsClient,
2701
3798
  decodeAuthorizationQR,