@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 +1512 -415
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2962 -93
- package/dist/index.d.ts +2962 -93
- package/dist/index.js +1448 -415
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
|
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, {
|
|
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
|
|
865
|
-
throw new FlurError(
|
|
866
|
-
|
|
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", {
|
|
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(
|
|
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
|
|
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) =>
|
|
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 =
|
|
1322
|
-
userId:
|
|
1323
|
-
deviceId:
|
|
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:
|
|
1326
|
-
cumulativeCapKobo:
|
|
1327
|
-
validFromMs:
|
|
1328
|
-
validUntilMs:
|
|
1329
|
-
counterSeed:
|
|
1330
|
-
nonce:
|
|
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
|
|
1438
|
-
var HexSig =
|
|
1439
|
-
var OfflinePaymentRequestSchema =
|
|
1440
|
-
reference:
|
|
1441
|
-
amountKobo:
|
|
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:
|
|
1909
|
+
expiresAtMs: import_zod6.z.number().int().positive(),
|
|
1444
1910
|
merchantSig: HexSig
|
|
1445
1911
|
});
|
|
1446
|
-
var OfflinePaymentAuthorizationSchema =
|
|
1912
|
+
var OfflinePaymentAuthorizationSchema = import_zod6.z.object({
|
|
1447
1913
|
request: OfflinePaymentRequestSchema,
|
|
1448
1914
|
payerOAC: OACSchema,
|
|
1449
|
-
payerCounter:
|
|
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
|
|
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 =
|
|
1562
|
-
tokenId:
|
|
1563
|
-
tokenSerial:
|
|
1564
|
-
issuerAccountId:
|
|
1565
|
-
payerUserId:
|
|
1566
|
-
maxAmountKobo:
|
|
1567
|
-
currency:
|
|
1568
|
-
issuedAtMs:
|
|
1569
|
-
expiresAtMs:
|
|
1570
|
-
issuerSig:
|
|
1571
|
-
});
|
|
1572
|
-
var PaymentClaimSchema =
|
|
1573
|
-
encounterId:
|
|
1574
|
-
tokenSerial:
|
|
1575
|
-
payerUserId:
|
|
1576
|
-
payeeUserId:
|
|
1577
|
-
payerNonce:
|
|
1578
|
-
payeeNonce:
|
|
1579
|
-
amountKobo:
|
|
1580
|
-
currency:
|
|
1581
|
-
occurredAtMs:
|
|
1582
|
-
completedAtMs:
|
|
1583
|
-
contextId:
|
|
1584
|
-
payerPubkey:
|
|
1585
|
-
payerSignature:
|
|
1586
|
-
payeePubkey:
|
|
1587
|
-
payeeSignature:
|
|
1588
|
-
});
|
|
1589
|
-
var SettlementSchema =
|
|
1590
|
-
settlementId:
|
|
1591
|
-
settlementKey:
|
|
1592
|
-
encounterId:
|
|
1593
|
-
issuerAccountId:
|
|
1594
|
-
tokenSerial:
|
|
1595
|
-
payerUserId:
|
|
1596
|
-
payeeUserId:
|
|
1597
|
-
amountKobo:
|
|
1598
|
-
currency:
|
|
1599
|
-
receiptId:
|
|
1600
|
-
status:
|
|
1601
|
-
issuerSig:
|
|
1602
|
-
createdAtMs:
|
|
1603
|
-
});
|
|
1604
|
-
var SettleResponseSchema =
|
|
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:
|
|
1607
|
-
replayed:
|
|
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/
|
|
1781
|
-
var
|
|
1782
|
-
var
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
"
|
|
1787
|
-
"
|
|
1788
|
-
"
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
"
|
|
1792
|
-
"
|
|
1793
|
-
"
|
|
1794
|
-
"
|
|
1795
|
-
"
|
|
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
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
)
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
)
|
|
1804
|
-
|
|
1805
|
-
|
|
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
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
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
|
|
1865
|
-
|
|
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
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
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
|
|
1884
|
-
return
|
|
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
|
|
1889
|
-
var HexSig2 =
|
|
1890
|
-
var RedemptionSchema =
|
|
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:
|
|
1893
|
-
redeemedAtMs:
|
|
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:
|
|
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:
|
|
1899
|
-
nonce:
|
|
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
|
|
2669
|
+
var import_zod11 = require("zod");
|
|
1986
2670
|
var RECEIPT_CHANNELS = ["cash", "pass"];
|
|
1987
2671
|
var RECEIPT_KINDS = RECEIPT_CHANNELS;
|
|
1988
|
-
var HexString3 = (length) =>
|
|
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 =
|
|
1993
|
-
|
|
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 =
|
|
1996
|
-
receiptId:
|
|
1997
|
-
channel:
|
|
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:
|
|
2683
|
+
intentId: import_zod11.z.string().min(1).optional(),
|
|
2000
2684
|
/** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
|
|
2001
|
-
passRedemptionId:
|
|
2002
|
-
payerUserId:
|
|
2003
|
-
payeeUserId:
|
|
2004
|
-
amountKobo:
|
|
2005
|
-
currency:
|
|
2006
|
-
issuedAtMs:
|
|
2007
|
-
issuerId:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
2288
|
-
|
|
2289
|
-
|
|
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
|
-
(
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
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
|
|
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 =
|
|
2365
|
-
accountId:
|
|
2366
|
-
type:
|
|
2367
|
-
displayName:
|
|
2368
|
-
status:
|
|
2369
|
-
ownerUserId:
|
|
2370
|
-
createdAtMs:
|
|
2371
|
-
});
|
|
2372
|
-
var AccountMembershipSchema =
|
|
2373
|
-
accountId:
|
|
2374
|
-
userId:
|
|
2375
|
-
role:
|
|
2376
|
-
createdAtMs:
|
|
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 =
|
|
2410
|
-
const memberItemsSchema =
|
|
2411
|
-
items:
|
|
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/
|
|
2443
|
-
var
|
|
2444
|
-
var
|
|
2445
|
-
var
|
|
2446
|
-
var
|
|
2447
|
-
var
|
|
2448
|
-
|
|
2449
|
-
|
|
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
|
|
2468
|
-
|
|
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
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
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
|
|
2522
|
-
const
|
|
2523
|
-
keyId: opts.keyId,
|
|
2524
|
-
secret: opts.secret,
|
|
3267
|
+
async function call(method, path, body, parser) {
|
|
3268
|
+
const init2 = {
|
|
2525
3269
|
method,
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
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)
|
|
2536
|
-
const
|
|
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
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
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
|
|
3557
|
+
function createConsumerWithdrawalsClient(opts) {
|
|
2581
3558
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
2582
3559
|
if (!fetchImpl) {
|
|
2583
3560
|
throw new Error(
|
|
2584
|
-
"
|
|
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)
|
|
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
|
-
|
|
3592
|
+
listDestinations: () => call(
|
|
2618
3593
|
"GET",
|
|
2619
|
-
|
|
3594
|
+
"/v1/me/payout-destinations",
|
|
2620
3595
|
void 0,
|
|
2621
|
-
(raw) =>
|
|
3596
|
+
(raw) => ListPayoutDestinationsResultSchema.parse(raw)
|
|
2622
3597
|
),
|
|
2623
|
-
|
|
3598
|
+
createDestination: (input) => call(
|
|
2624
3599
|
"POST",
|
|
2625
|
-
|
|
2626
|
-
input,
|
|
2627
|
-
(raw) =>
|
|
3600
|
+
"/v1/me/payout-destinations",
|
|
3601
|
+
CreatePayoutDestinationInputSchema.parse(input),
|
|
3602
|
+
(raw) => PayoutDestinationSchema.parse(raw)
|
|
2628
3603
|
),
|
|
2629
|
-
|
|
2630
|
-
"
|
|
2631
|
-
`/v1/
|
|
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) =>
|
|
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,
|