@nokinc-flur/sdk 1.1.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1417 -1038
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1146 -2049
- package/dist/index.d.ts +1146 -2049
- package/dist/index.js +1375 -1028
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,11 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
33
|
+
ACCOUNT_FUNDED_OAC_MAX_TTL_MS: () => ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
|
|
23
34
|
ACCOUNT_STATUSES: () => ACCOUNT_STATUSES,
|
|
24
35
|
ACCOUNT_TYPES: () => ACCOUNT_TYPES,
|
|
25
36
|
ADDITIONAL_DATA_SUBFIELD: () => ADDITIONAL_DATA_SUBFIELD,
|
|
@@ -33,6 +44,10 @@ __export(index_exports, {
|
|
|
33
44
|
CLAIM_DOMAIN_V2: () => CLAIM_DOMAIN_V2,
|
|
34
45
|
COLLECTION_INTENT_STATUSES: () => COLLECTION_INTENT_STATUSES,
|
|
35
46
|
COLLECTION_PAYMENT_STATUSES: () => COLLECTION_PAYMENT_STATUSES,
|
|
47
|
+
CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS: () => CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
|
|
48
|
+
CONSUMER_PAYMENT_REQUEST_DOMAIN: () => CONSUMER_PAYMENT_REQUEST_DOMAIN,
|
|
49
|
+
CONSUMER_SETTLEMENT_DOMAIN: () => CONSUMER_SETTLEMENT_DOMAIN,
|
|
50
|
+
CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX: () => CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX,
|
|
36
51
|
CUSTODIAL_MODES: () => CUSTODIAL_MODES,
|
|
37
52
|
CollectionIntentSchema: () => CollectionIntentSchema,
|
|
38
53
|
CollectionPaymentResultSchema: () => CollectionPaymentResultSchema,
|
|
@@ -42,6 +57,7 @@ __export(index_exports, {
|
|
|
42
57
|
ConsumerOACRecordSchema: () => OACRecordSchema,
|
|
43
58
|
ConsumerOACSchema: () => ConsumerOACSchema,
|
|
44
59
|
ConsumerPaymentClaimSchema: () => ConsumerPaymentClaimSchema,
|
|
60
|
+
ConsumerPaymentRequestEnvelopeSchema: () => ConsumerPaymentRequestEnvelopeSchema,
|
|
45
61
|
ConsumerSettleResultSchema: () => ConsumerSettleResultSchema,
|
|
46
62
|
ConsumerSettlementSchema: () => ConsumerSettlementSchema,
|
|
47
63
|
CreateCollectionIntentInputSchema: () => CreateCollectionIntentInputSchema,
|
|
@@ -51,10 +67,6 @@ __export(index_exports, {
|
|
|
51
67
|
CreateWithdrawalResultSchema: () => CreateWithdrawalResultSchema,
|
|
52
68
|
DeviceKeyAlgSchema: () => DeviceKeyAlgSchema,
|
|
53
69
|
DeviceKeyRecordSchema: () => DeviceKeyRecordSchema,
|
|
54
|
-
DisableOfflineInputSchema: () => DisableOfflineInputSchema,
|
|
55
|
-
DisableOfflineResultSchema: () => DisableOfflineResultSchema,
|
|
56
|
-
EnableOfflineInputSchema: () => EnableOfflineInputSchema,
|
|
57
|
-
EnableOfflineResultSchema: () => EnableOfflineResultSchema,
|
|
58
70
|
FIELD: () => FIELD,
|
|
59
71
|
FLUR_ARTIFACT_URI_PREFIX: () => FLUR_ARTIFACT_URI_PREFIX,
|
|
60
72
|
FLUR_ARTIFACT_URI_SCHEME: () => FLUR_ARTIFACT_URI_SCHEME,
|
|
@@ -70,7 +82,6 @@ __export(index_exports, {
|
|
|
70
82
|
IdentityArtifactSchema: () => IdentityArtifactSchema,
|
|
71
83
|
IngestFundingResultSchema: () => IngestFundingResultSchema,
|
|
72
84
|
IssueAccountOacInputSchema: () => IssueAccountOacInputSchema,
|
|
73
|
-
IssueOACInputSchema: () => IssueOACInputSchema,
|
|
74
85
|
LedgerJournalEntryArtifactSchema: () => LedgerJournalEntryArtifactSchema,
|
|
75
86
|
ListPayoutDestinationsResultSchema: () => ListPayoutDestinationsResultSchema,
|
|
76
87
|
MEMBERSHIP_ROLES: () => MEMBERSHIP_ROLES,
|
|
@@ -88,12 +99,16 @@ __export(index_exports, {
|
|
|
88
99
|
OAC_DEFAULT_PER_TX_KOBO: () => OAC_DEFAULT_PER_TX_KOBO,
|
|
89
100
|
OAC_DEFAULT_VALIDITY_MS: () => OAC_DEFAULT_VALIDITY_MS,
|
|
90
101
|
OFFLINE_CLAIM_SMS_PREFIX: () => OFFLINE_CLAIM_SMS_PREFIX,
|
|
102
|
+
OFFLINE_SMS_SETTLE_DOMAIN: () => OFFLINE_SMS_SETTLE_DOMAIN,
|
|
103
|
+
OFFLINE_SMS_SETTLE_HEADER_BYTES: () => OFFLINE_SMS_SETTLE_HEADER_BYTES,
|
|
104
|
+
OFFLINE_SMS_SETTLE_PREFIX: () => OFFLINE_SMS_SETTLE_PREFIX,
|
|
105
|
+
OFFLINE_SMS_SETTLE_SIGNATURE_BYTES: () => OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
|
|
106
|
+
OFFLINE_SMS_SETTLE_TOKEN_BYTES: () => OFFLINE_SMS_SETTLE_TOKEN_BYTES,
|
|
107
|
+
OFFLINE_SMS_SETTLE_VERSION: () => OFFLINE_SMS_SETTLE_VERSION,
|
|
91
108
|
OfflineClaimArtifactSchema: () => OfflineClaimArtifactSchema,
|
|
92
|
-
OfflineHoldRecordSchema: () => OfflineHoldRecordSchema,
|
|
93
109
|
OfflinePaymentAuthorizationArtifactSchema: () => OfflinePaymentAuthorizationArtifactSchema,
|
|
94
110
|
OfflinePaymentAuthorizationSchema: () => OfflinePaymentAuthorizationSchema,
|
|
95
111
|
OfflinePaymentRequestSchema: () => OfflinePaymentRequestSchema,
|
|
96
|
-
OfflineStateResultSchema: () => OfflineStateResultSchema,
|
|
97
112
|
OfflineStatusResultSchema: () => OfflineStatusResultSchema,
|
|
98
113
|
OfflineTokenSchema: () => OfflineTokenSchema,
|
|
99
114
|
P256EnrollmentChallengeInputSchema: () => P256EnrollmentChallengeInputSchema,
|
|
@@ -121,8 +136,6 @@ __export(index_exports, {
|
|
|
121
136
|
PayoutEventInputSchema: () => PayoutEventInputSchema,
|
|
122
137
|
ProviderEventInputSchema: () => ProviderEventInputSchema,
|
|
123
138
|
ProviderEventRecordSchema: () => ProviderEventRecordSchema,
|
|
124
|
-
ProvisionOfflineAllowanceInputSchema: () => ProvisionOfflineAllowanceInputSchema,
|
|
125
|
-
ProvisionOfflineAllowanceResultSchema: () => ProvisionOfflineAllowanceResultSchema,
|
|
126
139
|
PublicCollectionIntentSchema: () => PublicCollectionIntentSchema,
|
|
127
140
|
RECEIPT_CHANNELS: () => RECEIPT_CHANNELS,
|
|
128
141
|
RECEIPT_KINDS: () => RECEIPT_KINDS,
|
|
@@ -133,7 +146,6 @@ __export(index_exports, {
|
|
|
133
146
|
ReconciliationReportSchema: () => ReconciliationReportSchema,
|
|
134
147
|
RecordPayoutEventResultSchema: () => RecordPayoutEventResultSchema,
|
|
135
148
|
RedemptionSchema: () => RedemptionSchema,
|
|
136
|
-
RegisterDeviceKeyInputSchema: () => RegisterDeviceKeyInputSchema,
|
|
137
149
|
RegisterDeviceKeyP256InputSchema: () => RegisterDeviceKeyP256InputSchema,
|
|
138
150
|
ReversalRecordArtifactSchema: () => ReversalRecordArtifactSchema,
|
|
139
151
|
RevokeDeviceKeyInputSchema: () => RevokeDeviceKeyInputSchema,
|
|
@@ -152,18 +164,25 @@ __export(index_exports, {
|
|
|
152
164
|
bodySha256Hex: () => bodySha256Hex,
|
|
153
165
|
buildArtifactBody: () => buildArtifactBody,
|
|
154
166
|
buildAuthorization: () => buildAuthorization,
|
|
167
|
+
buildConsumerPaymentRequest: () => buildConsumerPaymentRequest,
|
|
155
168
|
buildOAC: () => buildOAC,
|
|
156
169
|
buildPass: () => buildPass,
|
|
157
170
|
buildPaymentRequest: () => buildPaymentRequest,
|
|
158
171
|
buildReceipt: () => buildReceipt,
|
|
159
172
|
buildRedemption: () => buildRedemption,
|
|
173
|
+
buildSmsSettleHeader: () => buildSmsSettleHeader,
|
|
174
|
+
buildSmsSettleSignedBytes: () => domainTag,
|
|
160
175
|
canonicalClaimSigningBytes: () => canonicalClaimSigningBytes,
|
|
161
176
|
canonicalClaimSigningPayload: () => canonicalClaimSigningPayload,
|
|
162
177
|
canonicalJSONBytes: () => canonicalJSONBytes,
|
|
163
178
|
canonicalJSONStringify: () => canonicalJSONStringify,
|
|
164
179
|
canonicalRequestString: () => canonicalRequestString,
|
|
180
|
+
computeConsumerClaimEncounterId: () => computeConsumerClaimEncounterId,
|
|
165
181
|
computeEncounterId: () => computeEncounterId,
|
|
166
182
|
constantTimeEqual: () => constantTimeEqual,
|
|
183
|
+
consumerPaymentRequestSigningBytes: () => consumerPaymentRequestSigningBytes,
|
|
184
|
+
consumerPaymentRequestSigningPayload: () => consumerPaymentRequestSigningPayload,
|
|
185
|
+
consumerSettlementSigningPayload: () => consumerSettlementSigningPayload,
|
|
167
186
|
crc16ccitt: () => crc16ccitt,
|
|
168
187
|
crc16ccittHex: () => crc16ccittHex,
|
|
169
188
|
createAccountsClient: () => createAccountsClient,
|
|
@@ -187,19 +206,27 @@ __export(index_exports, {
|
|
|
187
206
|
decodeArtifactUri: () => decodeArtifactUri,
|
|
188
207
|
decodeAuthorizationQR: () => decodeAuthorizationQR,
|
|
189
208
|
decodeBase45: () => decodeBase45,
|
|
209
|
+
decodeConsumerSettlementReceiptQR: () => decodeConsumerSettlementReceiptQR,
|
|
190
210
|
decodeOfflineClaimSmsMessage: () => decodeOfflineClaimSmsMessage,
|
|
211
|
+
decodeOfflineSmsSettleToken: () => decodeOfflineSmsSettleToken,
|
|
191
212
|
decodePaymentRequestQR: () => decodePaymentRequestQR,
|
|
213
|
+
decodeUnverifiedConsumerSettlementReceiptQR: () => decodeUnverifiedConsumerSettlementReceiptQR,
|
|
214
|
+
derToRawP256Signature: () => derToRawP256Signature,
|
|
192
215
|
encodeArtifactUri: () => encodeArtifactUri,
|
|
193
216
|
encodeAuthorizationQR: () => encodeAuthorizationQR,
|
|
194
217
|
encodeBase45: () => encodeBase45,
|
|
218
|
+
encodeConsumerSettlementReceiptQR: () => encodeConsumerSettlementReceiptQR,
|
|
195
219
|
encodeNQR: () => encodeNQR,
|
|
196
220
|
encodeOfflineClaimSmsMessage: () => encodeOfflineClaimSmsMessage,
|
|
221
|
+
encodeOfflineSmsSettleToken: () => encodeOfflineSmsSettleToken,
|
|
197
222
|
encodePaymentRequestQR: () => encodePaymentRequestQR,
|
|
198
223
|
extractOfflineClaimSmsToken: () => extractOfflineClaimSmsToken,
|
|
224
|
+
extractOfflineSmsSettleToken: () => extractOfflineSmsSettleToken,
|
|
199
225
|
formatAmount: () => formatAmount,
|
|
200
226
|
generateDynamicQR: () => generateDynamicQR,
|
|
201
227
|
generateStaticQR: () => generateStaticQR,
|
|
202
228
|
init: () => init,
|
|
229
|
+
isConsumerPaymentRequestExpired: () => isConsumerPaymentRequestExpired,
|
|
203
230
|
isHardenedArtifactType: () => isHardenedArtifactType,
|
|
204
231
|
isKnownArtifactType: () => isKnownArtifactType,
|
|
205
232
|
isPassWithinValidity: () => isPassWithinValidity,
|
|
@@ -212,6 +239,7 @@ __export(index_exports, {
|
|
|
212
239
|
routingHint: () => routingHint,
|
|
213
240
|
signArtifact: () => signArtifact,
|
|
214
241
|
signAuthorization: () => signAuthorization,
|
|
242
|
+
signConsumerPaymentRequest: () => signConsumerPaymentRequest,
|
|
215
243
|
signOAC: () => signOAC,
|
|
216
244
|
signPartnerRequest: () => signPartnerRequest,
|
|
217
245
|
signPass: () => signPass,
|
|
@@ -223,7 +251,11 @@ __export(index_exports, {
|
|
|
223
251
|
verifyArtifactUri: () => verifyArtifactUri,
|
|
224
252
|
verifyAuthorization: () => verifyAuthorization,
|
|
225
253
|
verifyClaimSignature: () => verifyClaimSignature,
|
|
254
|
+
verifyConsumerPaymentRequest: () => verifyConsumerPaymentRequest,
|
|
255
|
+
verifyConsumerSettlement: () => verifyConsumerSettlement,
|
|
256
|
+
verifyConsumerSettlementReceiptQR: () => verifyConsumerSettlementReceiptQR,
|
|
226
257
|
verifyOAC: () => verifyOAC,
|
|
258
|
+
verifyOfflineSmsSettleToken: () => verifyOfflineSmsSettleToken,
|
|
227
259
|
verifyPass: () => verifyPass,
|
|
228
260
|
verifyPaymentRequest: () => verifyPaymentRequest,
|
|
229
261
|
verifyReceipt: () => verifyReceipt,
|
|
@@ -234,13 +266,203 @@ __export(index_exports, {
|
|
|
234
266
|
module.exports = __toCommonJS(index_exports);
|
|
235
267
|
|
|
236
268
|
// src/client.ts
|
|
237
|
-
var
|
|
269
|
+
var import_zod4 = require("zod");
|
|
238
270
|
|
|
239
271
|
// src/contracts.ts
|
|
240
|
-
var import_zod2 = require("zod");
|
|
241
|
-
|
|
242
|
-
// src/me-offline/client.ts
|
|
243
272
|
var import_zod = require("zod");
|
|
273
|
+
var E164Regex = /^\+[1-9]\d{7,14}$/;
|
|
274
|
+
var UuidSchema = import_zod.z.string().uuid();
|
|
275
|
+
var IsoDateSchema = import_zod.z.string().datetime({ offset: true });
|
|
276
|
+
var CurrencySchema = import_zod.z.string().trim().length(3).transform((value) => value.toUpperCase());
|
|
277
|
+
var HealthResponseSchema = import_zod.z.object({
|
|
278
|
+
ok: import_zod.z.boolean()
|
|
279
|
+
});
|
|
280
|
+
var WelcomeResponseSchema = import_zod.z.object({
|
|
281
|
+
message: import_zod.z.string()
|
|
282
|
+
});
|
|
283
|
+
var OnboardingStartRequestSchema = import_zod.z.object({
|
|
284
|
+
phoneE164: import_zod.z.string().regex(E164Regex),
|
|
285
|
+
appInstanceId: import_zod.z.string().min(3),
|
|
286
|
+
platform: import_zod.z.enum(["android", "ios", "web"]),
|
|
287
|
+
turnstileToken: import_zod.z.string().min(20).optional(),
|
|
288
|
+
appAttestation: import_zod.z.object({
|
|
289
|
+
provider: import_zod.z.enum(["android", "ios", "web"]),
|
|
290
|
+
token: import_zod.z.string().min(24)
|
|
291
|
+
}).optional(),
|
|
292
|
+
firstName: import_zod.z.string().trim().min(1).max(80).optional(),
|
|
293
|
+
lastName: import_zod.z.string().trim().min(1).max(80).optional()
|
|
294
|
+
});
|
|
295
|
+
var OnboardingStartResponseSchema = import_zod.z.object({
|
|
296
|
+
requestId: import_zod.z.string().min(1),
|
|
297
|
+
checkUrl: import_zod.z.string().url().optional(),
|
|
298
|
+
expiresInSec: import_zod.z.number().int().positive(),
|
|
299
|
+
fallback: import_zod.z.enum(["SILENT_AUTH", "OTP"])
|
|
300
|
+
});
|
|
301
|
+
var OnboardingCompleteRequestSchema = import_zod.z.object({
|
|
302
|
+
requestId: import_zod.z.string().min(1),
|
|
303
|
+
code: import_zod.z.string().min(1).max(32),
|
|
304
|
+
appInstanceId: import_zod.z.string().min(3),
|
|
305
|
+
fingerprintHash: import_zod.z.string().min(3).optional()
|
|
306
|
+
});
|
|
307
|
+
var OnboardingCompleteResponseSchema = import_zod.z.object({
|
|
308
|
+
sessionToken: import_zod.z.string().min(1),
|
|
309
|
+
userId: UuidSchema,
|
|
310
|
+
restricted: import_zod.z.boolean(),
|
|
311
|
+
risk_reasons: import_zod.z.array(
|
|
312
|
+
import_zod.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
|
|
313
|
+
),
|
|
314
|
+
stepUpRequired: import_zod.z.boolean().optional(),
|
|
315
|
+
riskStatus: import_zod.z.enum(["ok", "unavailable"]).optional()
|
|
316
|
+
});
|
|
317
|
+
var RegisterDeviceRequestSchema = import_zod.z.object({
|
|
318
|
+
userId: UuidSchema,
|
|
319
|
+
appInstanceId: import_zod.z.string().min(3),
|
|
320
|
+
platform: import_zod.z.string().min(2),
|
|
321
|
+
model: import_zod.z.string().optional(),
|
|
322
|
+
networkSignals: import_zod.z.object({
|
|
323
|
+
ip: import_zod.z.string().min(3),
|
|
324
|
+
asn: import_zod.z.number().int().optional(),
|
|
325
|
+
country: import_zod.z.string().min(2).optional(),
|
|
326
|
+
carrier: import_zod.z.string().optional()
|
|
327
|
+
})
|
|
328
|
+
});
|
|
329
|
+
var RegisterDeviceResponseSchema = import_zod.z.object({
|
|
330
|
+
deviceId: import_zod.z.string().min(1),
|
|
331
|
+
fingerprintHash: import_zod.z.string().min(1),
|
|
332
|
+
driftScore: import_zod.z.number(),
|
|
333
|
+
trustState: import_zod.z.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
|
|
334
|
+
stepUpRequired: import_zod.z.boolean()
|
|
335
|
+
});
|
|
336
|
+
var AuthRefreshRequestSchema = import_zod.z.object({
|
|
337
|
+
userId: UuidSchema,
|
|
338
|
+
refreshToken: import_zod.z.string().min(8),
|
|
339
|
+
appInstanceId: import_zod.z.string().min(3),
|
|
340
|
+
fingerprintHash: import_zod.z.string().min(3)
|
|
341
|
+
});
|
|
342
|
+
var AuthRefreshResponseSchema = import_zod.z.object({
|
|
343
|
+
refreshToken: import_zod.z.string().min(8),
|
|
344
|
+
stepUpRequired: import_zod.z.boolean()
|
|
345
|
+
});
|
|
346
|
+
var AuthLogoutRequestSchema = import_zod.z.object({
|
|
347
|
+
userId: UuidSchema,
|
|
348
|
+
refreshToken: import_zod.z.string().min(8)
|
|
349
|
+
});
|
|
350
|
+
var PinSetRequestSchema = import_zod.z.object({
|
|
351
|
+
userId: UuidSchema,
|
|
352
|
+
pin: import_zod.z.string().regex(/^\d{6}$/)
|
|
353
|
+
});
|
|
354
|
+
var PinVerifyRequestSchema = import_zod.z.object({
|
|
355
|
+
userId: UuidSchema,
|
|
356
|
+
pin: import_zod.z.string().regex(/^\d{6}$/)
|
|
357
|
+
});
|
|
358
|
+
var OkResponseSchema = import_zod.z.object({
|
|
359
|
+
ok: import_zod.z.boolean()
|
|
360
|
+
});
|
|
361
|
+
var RegisterSendDeviceKeyRequestSchema = import_zod.z.object({
|
|
362
|
+
userId: UuidSchema,
|
|
363
|
+
deviceId: import_zod.z.string().min(3),
|
|
364
|
+
publicKey: import_zod.z.string().min(32)
|
|
365
|
+
});
|
|
366
|
+
var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
|
|
367
|
+
var SendChallengeRequestSchema = import_zod.z.object({
|
|
368
|
+
userId: UuidSchema,
|
|
369
|
+
deviceId: import_zod.z.string().min(3),
|
|
370
|
+
purpose: import_zod.z.enum(SEND_AUTH_PURPOSES).optional()
|
|
371
|
+
});
|
|
372
|
+
var SendChallengeResponseSchema = import_zod.z.object({
|
|
373
|
+
challengeId: UuidSchema,
|
|
374
|
+
nonce: import_zod.z.string().min(1),
|
|
375
|
+
expiresAt: IsoDateSchema
|
|
376
|
+
});
|
|
377
|
+
var SendVerifyRequestSchema = import_zod.z.object({
|
|
378
|
+
userId: UuidSchema,
|
|
379
|
+
deviceId: import_zod.z.string().min(3),
|
|
380
|
+
challengeId: UuidSchema,
|
|
381
|
+
signature: import_zod.z.string().min(16)
|
|
382
|
+
});
|
|
383
|
+
var SendVerifyResponseSchema = import_zod.z.object({
|
|
384
|
+
sendAuthToken: import_zod.z.string().min(16)
|
|
385
|
+
});
|
|
386
|
+
var ResolveRecipientRequestSchema = import_zod.z.object({
|
|
387
|
+
identifier: import_zod.z.string().min(3)
|
|
388
|
+
});
|
|
389
|
+
var ResolveRecipientResponseSchema = import_zod.z.object({
|
|
390
|
+
recipientUserId: UuidSchema,
|
|
391
|
+
displayName: import_zod.z.string().min(1),
|
|
392
|
+
normalizedIdentifier: import_zod.z.string().regex(E164Regex),
|
|
393
|
+
isActive: import_zod.z.boolean()
|
|
394
|
+
});
|
|
395
|
+
var CreateTransferRequestSchema = import_zod.z.object({
|
|
396
|
+
recipientIdentifier: import_zod.z.string().min(3),
|
|
397
|
+
amountMinor: import_zod.z.number().int().positive(),
|
|
398
|
+
currency: CurrencySchema,
|
|
399
|
+
sendAuthToken: import_zod.z.string().min(16)
|
|
400
|
+
});
|
|
401
|
+
var TransferStatusSchema = import_zod.z.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
|
|
402
|
+
var TransferResponseSchema = import_zod.z.object({
|
|
403
|
+
transactionId: import_zod.z.string().min(1),
|
|
404
|
+
status: TransferStatusSchema,
|
|
405
|
+
userStatus: TransferStatusSchema,
|
|
406
|
+
recipientName: import_zod.z.string().min(1),
|
|
407
|
+
timestamp: IsoDateSchema
|
|
408
|
+
});
|
|
409
|
+
var DirectionSchema = import_zod.z.enum(["OUTGOING", "INCOMING"]);
|
|
410
|
+
var AccountActivityItemSchema = import_zod.z.object({
|
|
411
|
+
id: import_zod.z.string().min(1),
|
|
412
|
+
type: import_zod.z.string().min(1),
|
|
413
|
+
direction: DirectionSchema,
|
|
414
|
+
name: import_zod.z.string().min(1),
|
|
415
|
+
identifier: import_zod.z.string().min(1),
|
|
416
|
+
amountMinor: import_zod.z.number().int(),
|
|
417
|
+
currency: CurrencySchema,
|
|
418
|
+
status: import_zod.z.string().min(1),
|
|
419
|
+
timestamp: IsoDateSchema
|
|
420
|
+
});
|
|
421
|
+
var AccountSummaryResponseSchema = import_zod.z.object({
|
|
422
|
+
/** Authenticated user's stable internal id. */
|
|
423
|
+
userId: UuidSchema,
|
|
424
|
+
/**
|
|
425
|
+
* 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
|
|
426
|
+
* bank partner. `null` when the user has no partner-allocated account yet.
|
|
427
|
+
*/
|
|
428
|
+
nuban: import_zod.z.string().regex(/^[0-9]{10}$/).nullable(),
|
|
429
|
+
balance: import_zod.z.number().int(),
|
|
430
|
+
currency: CurrencySchema,
|
|
431
|
+
dailySendLimit: import_zod.z.number().int().nonnegative(),
|
|
432
|
+
dailySendRemaining: import_zod.z.number().int().nonnegative(),
|
|
433
|
+
kycTier: import_zod.z.string().min(1),
|
|
434
|
+
kycStatus: import_zod.z.string().min(1),
|
|
435
|
+
recentActivity: import_zod.z.array(AccountActivityItemSchema)
|
|
436
|
+
});
|
|
437
|
+
var TransactionsListResponseSchema = import_zod.z.object({
|
|
438
|
+
items: import_zod.z.array(AccountActivityItemSchema),
|
|
439
|
+
nextCursor: import_zod.z.string().nullable()
|
|
440
|
+
});
|
|
441
|
+
var TransactionDetailResponseSchema = import_zod.z.object({
|
|
442
|
+
transactionId: import_zod.z.string().min(1),
|
|
443
|
+
type: import_zod.z.string().min(1),
|
|
444
|
+
direction: DirectionSchema,
|
|
445
|
+
counterpartyName: import_zod.z.string().min(1),
|
|
446
|
+
counterpartyIdentifier: import_zod.z.string().min(1),
|
|
447
|
+
amountMinor: import_zod.z.number().int(),
|
|
448
|
+
currency: CurrencySchema,
|
|
449
|
+
status: import_zod.z.string().min(1),
|
|
450
|
+
timestamp: IsoDateSchema
|
|
451
|
+
});
|
|
452
|
+
var PushRegisterRequestSchema = import_zod.z.object({
|
|
453
|
+
deviceId: import_zod.z.string().min(3),
|
|
454
|
+
platform: import_zod.z.enum(["ios", "android", "web"]),
|
|
455
|
+
token: import_zod.z.string().min(16)
|
|
456
|
+
});
|
|
457
|
+
var CreatePayLinkResponseSchema = import_zod.z.object({
|
|
458
|
+
token: import_zod.z.string().min(1)
|
|
459
|
+
});
|
|
460
|
+
var ResolvePayLinkResponseSchema = import_zod.z.object({
|
|
461
|
+
recipientUserId: UuidSchema,
|
|
462
|
+
displayName: import_zod.z.string().min(1),
|
|
463
|
+
normalizedIdentifier: import_zod.z.string().regex(E164Regex),
|
|
464
|
+
isActive: import_zod.z.boolean()
|
|
465
|
+
});
|
|
244
466
|
|
|
245
467
|
// src/errors.ts
|
|
246
468
|
var backendErrorCodeSet = /* @__PURE__ */ new Set([
|
|
@@ -344,556 +566,9 @@ async function mapToFlurError(res) {
|
|
|
344
566
|
});
|
|
345
567
|
}
|
|
346
568
|
|
|
347
|
-
// src/me-offline/client.ts
|
|
348
|
-
var Hex64 = import_zod.z.string().regex(/^[0-9a-f]{64}$/i);
|
|
349
|
-
var Sha256Hex = import_zod.z.string().regex(/^[0-9a-f]{64}$/i);
|
|
350
|
-
var Base64Std = import_zod.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
|
|
351
|
-
var RegisterDeviceKeyInputSchema = import_zod.z.object({
|
|
352
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
353
|
-
publicKeyHex: Hex64
|
|
354
|
-
});
|
|
355
|
-
var AttestationSecurityLevelSchema = import_zod.z.enum([
|
|
356
|
-
"STRONGBOX",
|
|
357
|
-
"TEE",
|
|
358
|
-
"SECURE_ENCLAVE",
|
|
359
|
-
"SOFTWARE"
|
|
360
|
-
]);
|
|
361
|
-
var DeviceKeyAlgSchema = import_zod.z.literal("p256");
|
|
362
|
-
var RegisterDeviceKeyP256InputSchema = import_zod.z.object({
|
|
363
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
364
|
-
/** P-256 SubjectPublicKeyInfo DER, base64. */
|
|
365
|
-
publicKeySpkiB64: Base64Std.min(64).max(4096),
|
|
366
|
-
/** Base64 of the server-issued enrollment challenge string. */
|
|
367
|
-
challengeB64: Base64Std.min(8).max(1024),
|
|
368
|
-
/** iOS App Attest payload or Android X.509 Key Attestation chain. */
|
|
369
|
-
attestationChainB64: import_zod.z.array(Base64Std.min(16).max(16384)).min(1).max(16),
|
|
370
|
-
securityLevel: AttestationSecurityLevelSchema
|
|
371
|
-
});
|
|
372
|
-
var P256EnrollmentChallengeInputSchema = import_zod.z.object({
|
|
373
|
-
deviceId: import_zod.z.string().min(1).max(128)
|
|
374
|
-
});
|
|
375
|
-
var P256EnrollmentChallengeResultSchema = import_zod.z.object({
|
|
376
|
-
challenge: import_zod.z.string().min(16),
|
|
377
|
-
expiresAtMs: import_zod.z.number().int().positive()
|
|
378
|
-
});
|
|
379
|
-
var DeviceKeyRecordSchema = import_zod.z.object({
|
|
380
|
-
id: import_zod.z.string().uuid(),
|
|
381
|
-
userId: import_zod.z.string().uuid(),
|
|
382
|
-
deviceId: import_zod.z.string(),
|
|
383
|
-
/** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
|
|
384
|
-
alg: DeviceKeyAlgSchema.default("p256"),
|
|
385
|
-
/** Legacy ed25519 hex key. Always null on new records (kept for back-compat reads). */
|
|
386
|
-
publicKeyHex: Hex64.nullable().default(null),
|
|
387
|
-
/** P-256 SubjectPublicKeyInfo DER, base64. Required for new records. */
|
|
388
|
-
publicKeySpkiB64: Base64Std.nullable().default(null),
|
|
389
|
-
securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
|
|
390
|
-
hardwareBacked: import_zod.z.boolean().default(false),
|
|
391
|
-
attestedAtMs: import_zod.z.number().int().nonnegative().nullable().default(null),
|
|
392
|
-
createdAtMs: import_zod.z.number().int().nonnegative(),
|
|
393
|
-
revokedAtMs: import_zod.z.number().int().nonnegative().nullable()
|
|
394
|
-
});
|
|
395
|
-
var ConsumerOACSchema = import_zod.z.object({
|
|
396
|
-
oacId: import_zod.z.string().uuid(),
|
|
397
|
-
issuerId: import_zod.z.string().min(1).max(64),
|
|
398
|
-
userId: import_zod.z.string().uuid(),
|
|
399
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
400
|
-
/**
|
|
401
|
-
* Always 'p256'. Required on the wire (backend always emits it).
|
|
402
|
-
* Kept as a literal so input/output infer identically and the schema
|
|
403
|
-
* can be nested inside other response shapes without Zod input/output
|
|
404
|
-
* divergence under tsup DTS bundling.
|
|
405
|
-
*/
|
|
406
|
-
alg: import_zod.z.literal("p256"),
|
|
407
|
-
/** P-256 SubjectPublicKeyInfo DER, base64. */
|
|
408
|
-
devicePubkeySpkiB64: Base64Std.min(64).max(4096),
|
|
409
|
-
perTxCapKobo: import_zod.z.number().int().positive(),
|
|
410
|
-
cumulativeCapKobo: import_zod.z.number().int().positive(),
|
|
411
|
-
currency: import_zod.z.string().length(3),
|
|
412
|
-
validFromMs: import_zod.z.number().int().nonnegative(),
|
|
413
|
-
validUntilMs: import_zod.z.number().int().nonnegative(),
|
|
414
|
-
counterSeed: import_zod.z.number().int().nonnegative(),
|
|
415
|
-
issuedAtMs: import_zod.z.number().int().nonnegative()
|
|
416
|
-
});
|
|
417
|
-
var SignedConsumerOACSchema = import_zod.z.object({
|
|
418
|
-
oac: ConsumerOACSchema,
|
|
419
|
-
/** ASN.1 DER ECDSA P-256 issuer signature, base64. */
|
|
420
|
-
issuerSig: Base64Std.min(16).max(2048),
|
|
421
|
-
/** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
|
|
422
|
-
issuerPublicKeySpkiB64: Base64Std.min(64).max(4096)
|
|
423
|
-
});
|
|
424
|
-
var OACRecordSchema = SignedConsumerOACSchema.extend({
|
|
425
|
-
currentOfflineSpentKobo: import_zod.z.number().int().nonnegative(),
|
|
426
|
-
status: import_zod.z.enum([
|
|
427
|
-
"active",
|
|
428
|
-
"superseded",
|
|
429
|
-
"expired",
|
|
430
|
-
"revoked",
|
|
431
|
-
"disabling",
|
|
432
|
-
"draining",
|
|
433
|
-
"closed"
|
|
434
|
-
]),
|
|
435
|
-
supersededAtMs: import_zod.z.number().int().nonnegative().nullable(),
|
|
436
|
-
revokedAtMs: import_zod.z.number().int().nonnegative().nullable(),
|
|
437
|
-
holdId: import_zod.z.string().uuid().nullable().optional()
|
|
438
|
-
});
|
|
439
|
-
var IssueOACInputSchema = import_zod.z.object({
|
|
440
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
441
|
-
perTxCapKobo: import_zod.z.number().int().positive().optional(),
|
|
442
|
-
cumulativeCapKobo: import_zod.z.number().int().positive().optional(),
|
|
443
|
-
ttlMs: import_zod.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
|
|
444
|
-
spendableOnlineKobo: import_zod.z.number().int().nonnegative().optional()
|
|
445
|
-
});
|
|
446
|
-
var IssueAccountOacInputSchema = import_zod.z.object({
|
|
447
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
448
|
-
perTxCapKobo: import_zod.z.number().int().positive().optional(),
|
|
449
|
-
cumulativeCapKobo: import_zod.z.number().int().positive().optional(),
|
|
450
|
-
ttlMs: import_zod.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional()
|
|
451
|
-
});
|
|
452
|
-
var EnableOfflineInputSchema = import_zod.z.object({
|
|
453
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
454
|
-
amountKobo: import_zod.z.number().int().positive(),
|
|
455
|
-
perTxCapKobo: import_zod.z.number().int().positive().optional(),
|
|
456
|
-
ttlMs: import_zod.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
|
|
457
|
-
installId: import_zod.z.string().min(1).max(128),
|
|
458
|
-
partnerId: import_zod.z.string().min(1).max(64).optional()
|
|
459
|
-
});
|
|
460
|
-
var ProvisionOfflineAllowanceInputSchema = EnableOfflineInputSchema;
|
|
461
|
-
var DisableOfflineInputSchema = import_zod.z.object({
|
|
462
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
463
|
-
installId: import_zod.z.string().min(1).max(128).optional(),
|
|
464
|
-
claims: import_zod.z.array(import_zod.z.unknown()).max(256).optional()
|
|
465
|
-
});
|
|
466
|
-
var OfflineHoldRecordSchema = import_zod.z.object({
|
|
467
|
-
holdId: import_zod.z.string().uuid(),
|
|
468
|
-
userId: import_zod.z.string().uuid(),
|
|
469
|
-
deviceId: import_zod.z.string(),
|
|
470
|
-
partnerId: import_zod.z.string(),
|
|
471
|
-
adapterKind: import_zod.z.string(),
|
|
472
|
-
externalHoldRef: import_zod.z.string().nullable(),
|
|
473
|
-
amountKobo: import_zod.z.number().int().nonnegative(),
|
|
474
|
-
capturedKobo: import_zod.z.number().int().nonnegative(),
|
|
475
|
-
releasedKobo: import_zod.z.number().int().nonnegative(),
|
|
476
|
-
remainingKobo: import_zod.z.number().int().nonnegative(),
|
|
477
|
-
currency: import_zod.z.string().length(3),
|
|
478
|
-
status: import_zod.z.enum([
|
|
479
|
-
"placing",
|
|
480
|
-
"active",
|
|
481
|
-
"disabling",
|
|
482
|
-
"draining",
|
|
483
|
-
"closed",
|
|
484
|
-
"revoked",
|
|
485
|
-
"failed"
|
|
486
|
-
]),
|
|
487
|
-
installId: import_zod.z.string().nullable(),
|
|
488
|
-
drainDeadlineMs: import_zod.z.number().int().nonnegative(),
|
|
489
|
-
disableRequestedAtMs: import_zod.z.number().int().nonnegative().nullable(),
|
|
490
|
-
createdAtMs: import_zod.z.number().int().nonnegative(),
|
|
491
|
-
closedAtMs: import_zod.z.number().int().nonnegative().nullable(),
|
|
492
|
-
isTrusted: import_zod.z.boolean().optional()
|
|
493
|
-
});
|
|
494
|
-
var EnableOfflineResultSchema = import_zod.z.object({
|
|
495
|
-
hold: OfflineHoldRecordSchema,
|
|
496
|
-
oac: OACRecordSchema
|
|
497
|
-
});
|
|
498
|
-
var ProvisionOfflineAllowanceResultSchema = EnableOfflineResultSchema;
|
|
499
|
-
var DisableOfflineResultSchema = import_zod.z.object({
|
|
500
|
-
hold: OfflineHoldRecordSchema,
|
|
501
|
-
trusted: import_zod.z.boolean(),
|
|
502
|
-
settledClaims: import_zod.z.number().int().nonnegative()
|
|
503
|
-
});
|
|
504
|
-
var OfflineStatusResultSchema = import_zod.z.object({
|
|
505
|
-
hold: OfflineHoldRecordSchema.nullable(),
|
|
506
|
-
active: OACRecordSchema.nullable()
|
|
507
|
-
});
|
|
508
|
-
var OfflineStateResultSchema = import_zod.z.object({
|
|
509
|
-
active: OACRecordSchema.nullable()
|
|
510
|
-
});
|
|
511
|
-
var ConsumerPaymentClaimSchema = import_zod.z.object({
|
|
512
|
-
/** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
|
|
513
|
-
alg: import_zod.z.literal("p256").default("p256"),
|
|
514
|
-
oacId: import_zod.z.string().uuid(),
|
|
515
|
-
encounterId: Sha256Hex.optional(),
|
|
516
|
-
payerUserId: import_zod.z.string().uuid(),
|
|
517
|
-
payeeUserId: import_zod.z.string().uuid(),
|
|
518
|
-
payerDeviceId: import_zod.z.string().min(1).max(128),
|
|
519
|
-
payerNonce: import_zod.z.string().min(8).max(128),
|
|
520
|
-
payeeNonce: import_zod.z.string().min(8).max(128),
|
|
521
|
-
amountKobo: import_zod.z.number().int().positive(),
|
|
522
|
-
currency: import_zod.z.string().length(3).default("NGN"),
|
|
523
|
-
occurredAtMs: import_zod.z.number().int().nonnegative(),
|
|
524
|
-
completedAtMs: import_zod.z.number().int().nonnegative().optional(),
|
|
525
|
-
contextId: import_zod.z.string().max(128).optional(),
|
|
526
|
-
payerPubkeySpkiB64: Base64Std.min(64).max(4096),
|
|
527
|
-
payerSignatureDerB64: Base64Std.min(16).max(2048),
|
|
528
|
-
payeePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),
|
|
529
|
-
payeeSignatureDerB64: Base64Std.min(16).max(2048).optional()
|
|
530
|
-
});
|
|
531
|
-
var ConsumerSettlementSchema = import_zod.z.object({
|
|
532
|
-
settlementId: import_zod.z.string().uuid(),
|
|
533
|
-
settlementKey: Sha256Hex,
|
|
534
|
-
encounterId: Sha256Hex,
|
|
535
|
-
oacId: import_zod.z.string().uuid(),
|
|
536
|
-
payerUserId: import_zod.z.string().uuid(),
|
|
537
|
-
payeeUserId: import_zod.z.string().uuid(),
|
|
538
|
-
amountKobo: import_zod.z.number().int().positive(),
|
|
539
|
-
currency: import_zod.z.string().length(3),
|
|
540
|
-
status: import_zod.z.enum(["SETTLED", "REVIEW"]),
|
|
541
|
-
reviewReason: import_zod.z.string().nullable(),
|
|
542
|
-
ledgerRef: import_zod.z.string().nullable(),
|
|
543
|
-
/** ASN.1 DER ECDSA P-256 issuer signature, base64. */
|
|
544
|
-
issuerSig: Base64Std.min(16).max(2048),
|
|
545
|
-
createdAtMs: import_zod.z.number().int().nonnegative()
|
|
546
|
-
});
|
|
547
|
-
var ConsumerSettleResultSchema = import_zod.z.object({
|
|
548
|
-
settlement: ConsumerSettlementSchema,
|
|
549
|
-
encounterId: Sha256Hex,
|
|
550
|
-
replayed: import_zod.z.boolean()
|
|
551
|
-
});
|
|
552
|
-
var RevokeDeviceKeyInputSchema = import_zod.z.object({
|
|
553
|
-
deviceId: import_zod.z.string().min(1).max(128),
|
|
554
|
-
/** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
|
|
555
|
-
sendAuthToken: import_zod.z.string().min(16)
|
|
556
|
-
});
|
|
557
|
-
function createMeOfflineClient(opts) {
|
|
558
|
-
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
559
|
-
if (!fetchImpl) {
|
|
560
|
-
throw new Error("createMeOfflineClient: no fetch implementation available");
|
|
561
|
-
}
|
|
562
|
-
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
563
|
-
async function call(method, path, body, parser) {
|
|
564
|
-
const init2 = {
|
|
565
|
-
method,
|
|
566
|
-
headers: {
|
|
567
|
-
"content-type": "application/json",
|
|
568
|
-
accept: "application/json"
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
if (body !== void 0) init2.body = JSON.stringify(body);
|
|
572
|
-
const resp = await fetchImpl(`${baseUrl}${path}`, init2);
|
|
573
|
-
const text = await resp.text();
|
|
574
|
-
let raw = void 0;
|
|
575
|
-
if (text) {
|
|
576
|
-
try {
|
|
577
|
-
raw = JSON.parse(text);
|
|
578
|
-
} catch {
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
if (!resp.ok) {
|
|
582
|
-
const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
|
|
583
|
-
const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
|
|
584
|
-
throw new FlurApiError(resp.status, code, message, raw);
|
|
585
|
-
}
|
|
586
|
-
return parser(raw);
|
|
587
|
-
}
|
|
588
|
-
const deviceKeyItems = import_zod.z.object({ items: import_zod.z.array(DeviceKeyRecordSchema) });
|
|
589
|
-
return {
|
|
590
|
-
registerDeviceKey: (input) => call(
|
|
591
|
-
"POST",
|
|
592
|
-
"/v1/me/offline/keys",
|
|
593
|
-
RegisterDeviceKeyInputSchema.parse(input),
|
|
594
|
-
(raw) => DeviceKeyRecordSchema.parse(raw)
|
|
595
|
-
),
|
|
596
|
-
issueP256EnrollmentChallenge: (input) => call(
|
|
597
|
-
"POST",
|
|
598
|
-
"/v1/me/offline/keys/p256/challenge",
|
|
599
|
-
P256EnrollmentChallengeInputSchema.parse(input),
|
|
600
|
-
(raw) => P256EnrollmentChallengeResultSchema.parse(raw)
|
|
601
|
-
),
|
|
602
|
-
registerDeviceKeyP256: (input) => call(
|
|
603
|
-
"POST",
|
|
604
|
-
"/v1/me/offline/keys/p256",
|
|
605
|
-
RegisterDeviceKeyP256InputSchema.parse(input),
|
|
606
|
-
(raw) => DeviceKeyRecordSchema.parse(raw)
|
|
607
|
-
),
|
|
608
|
-
listDeviceKeys: () => call(
|
|
609
|
-
"GET",
|
|
610
|
-
"/v1/me/offline/keys",
|
|
611
|
-
void 0,
|
|
612
|
-
(raw) => deviceKeyItems.parse(raw)
|
|
613
|
-
),
|
|
614
|
-
revokeDeviceKey: (input) => call(
|
|
615
|
-
"POST",
|
|
616
|
-
"/v1/me/offline/keys/revoke",
|
|
617
|
-
RevokeDeviceKeyInputSchema.parse(input),
|
|
618
|
-
() => void 0
|
|
619
|
-
),
|
|
620
|
-
issueAccountOac: (input) => call(
|
|
621
|
-
"POST",
|
|
622
|
-
"/v1/me/offline/oac",
|
|
623
|
-
IssueAccountOacInputSchema.parse(input),
|
|
624
|
-
(raw) => OACRecordSchema.parse(raw)
|
|
625
|
-
),
|
|
626
|
-
provisionAllowance: (input) => call(
|
|
627
|
-
"POST",
|
|
628
|
-
"/v1/me/offline/allowance",
|
|
629
|
-
ProvisionOfflineAllowanceInputSchema.parse(input),
|
|
630
|
-
(raw) => ProvisionOfflineAllowanceResultSchema.parse(raw)
|
|
631
|
-
),
|
|
632
|
-
enable: (input) => call(
|
|
633
|
-
"POST",
|
|
634
|
-
"/v1/me/offline/enable",
|
|
635
|
-
EnableOfflineInputSchema.parse(input),
|
|
636
|
-
(raw) => EnableOfflineResultSchema.parse(raw)
|
|
637
|
-
),
|
|
638
|
-
refresh: (input) => call(
|
|
639
|
-
"POST",
|
|
640
|
-
"/v1/me/offline/refresh",
|
|
641
|
-
IssueOACInputSchema.parse(input),
|
|
642
|
-
(raw) => OACRecordSchema.parse(raw)
|
|
643
|
-
),
|
|
644
|
-
disable: (input) => call(
|
|
645
|
-
"POST",
|
|
646
|
-
"/v1/me/offline/disable",
|
|
647
|
-
DisableOfflineInputSchema.parse(input),
|
|
648
|
-
(raw) => DisableOfflineResultSchema.parse(raw)
|
|
649
|
-
),
|
|
650
|
-
getStatus: (deviceId) => {
|
|
651
|
-
const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
|
|
652
|
-
return call(
|
|
653
|
-
"GET",
|
|
654
|
-
`/v1/me/offline/status${qs}`,
|
|
655
|
-
void 0,
|
|
656
|
-
(raw) => OfflineStatusResultSchema.parse(raw)
|
|
657
|
-
);
|
|
658
|
-
},
|
|
659
|
-
getState: (deviceId) => {
|
|
660
|
-
const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
|
|
661
|
-
return call(
|
|
662
|
-
"GET",
|
|
663
|
-
`/v1/me/offline/state${qs}`,
|
|
664
|
-
void 0,
|
|
665
|
-
(raw) => OfflineStateResultSchema.parse(raw)
|
|
666
|
-
);
|
|
667
|
-
},
|
|
668
|
-
submitClaim: (claim) => call(
|
|
669
|
-
"POST",
|
|
670
|
-
"/v1/me/offline/claims",
|
|
671
|
-
ConsumerPaymentClaimSchema.parse(claim),
|
|
672
|
-
(raw) => ConsumerSettleResultSchema.parse(raw)
|
|
673
|
-
)
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// src/contracts.ts
|
|
678
|
-
var E164Regex = /^\+[1-9]\d{7,14}$/;
|
|
679
|
-
var UuidSchema = import_zod2.z.string().uuid();
|
|
680
|
-
var IsoDateSchema = import_zod2.z.string().datetime({ offset: true });
|
|
681
|
-
var CurrencySchema = import_zod2.z.string().trim().length(3).transform((value) => value.toUpperCase());
|
|
682
|
-
var HealthResponseSchema = import_zod2.z.object({
|
|
683
|
-
ok: import_zod2.z.boolean()
|
|
684
|
-
});
|
|
685
|
-
var WelcomeResponseSchema = import_zod2.z.object({
|
|
686
|
-
message: import_zod2.z.string()
|
|
687
|
-
});
|
|
688
|
-
var OnboardingStartRequestSchema = import_zod2.z.object({
|
|
689
|
-
phoneE164: import_zod2.z.string().regex(E164Regex),
|
|
690
|
-
appInstanceId: import_zod2.z.string().min(3),
|
|
691
|
-
platform: import_zod2.z.enum(["android", "ios", "web"]),
|
|
692
|
-
turnstileToken: import_zod2.z.string().min(20).optional(),
|
|
693
|
-
appAttestation: import_zod2.z.object({
|
|
694
|
-
provider: import_zod2.z.enum(["android", "ios", "web"]),
|
|
695
|
-
token: import_zod2.z.string().min(24)
|
|
696
|
-
}).optional(),
|
|
697
|
-
firstName: import_zod2.z.string().trim().min(1).max(80).optional(),
|
|
698
|
-
lastName: import_zod2.z.string().trim().min(1).max(80).optional()
|
|
699
|
-
});
|
|
700
|
-
var OnboardingStartResponseSchema = import_zod2.z.object({
|
|
701
|
-
requestId: import_zod2.z.string().min(1),
|
|
702
|
-
checkUrl: import_zod2.z.string().url().optional(),
|
|
703
|
-
expiresInSec: import_zod2.z.number().int().positive(),
|
|
704
|
-
fallback: import_zod2.z.enum(["SILENT_AUTH", "OTP"])
|
|
705
|
-
});
|
|
706
|
-
var OnboardingCompleteRequestSchema = import_zod2.z.object({
|
|
707
|
-
requestId: import_zod2.z.string().min(1),
|
|
708
|
-
code: import_zod2.z.string().min(1).max(32),
|
|
709
|
-
appInstanceId: import_zod2.z.string().min(3),
|
|
710
|
-
fingerprintHash: import_zod2.z.string().min(3).optional()
|
|
711
|
-
});
|
|
712
|
-
var OnboardingCompleteResponseSchema = import_zod2.z.object({
|
|
713
|
-
sessionToken: import_zod2.z.string().min(1),
|
|
714
|
-
userId: UuidSchema,
|
|
715
|
-
restricted: import_zod2.z.boolean(),
|
|
716
|
-
risk_reasons: import_zod2.z.array(
|
|
717
|
-
import_zod2.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
|
|
718
|
-
),
|
|
719
|
-
stepUpRequired: import_zod2.z.boolean().optional(),
|
|
720
|
-
riskStatus: import_zod2.z.enum(["ok", "unavailable"]).optional()
|
|
721
|
-
});
|
|
722
|
-
var RegisterDeviceRequestSchema = import_zod2.z.object({
|
|
723
|
-
userId: UuidSchema,
|
|
724
|
-
appInstanceId: import_zod2.z.string().min(3),
|
|
725
|
-
platform: import_zod2.z.string().min(2),
|
|
726
|
-
model: import_zod2.z.string().optional(),
|
|
727
|
-
networkSignals: import_zod2.z.object({
|
|
728
|
-
ip: import_zod2.z.string().min(3),
|
|
729
|
-
asn: import_zod2.z.number().int().optional(),
|
|
730
|
-
country: import_zod2.z.string().min(2).optional(),
|
|
731
|
-
carrier: import_zod2.z.string().optional()
|
|
732
|
-
})
|
|
733
|
-
});
|
|
734
|
-
var RegisterDeviceResponseSchema = import_zod2.z.object({
|
|
735
|
-
deviceId: import_zod2.z.string().min(1),
|
|
736
|
-
fingerprintHash: import_zod2.z.string().min(1),
|
|
737
|
-
driftScore: import_zod2.z.number(),
|
|
738
|
-
trustState: import_zod2.z.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
|
|
739
|
-
stepUpRequired: import_zod2.z.boolean()
|
|
740
|
-
});
|
|
741
|
-
var AuthRefreshRequestSchema = import_zod2.z.object({
|
|
742
|
-
userId: UuidSchema,
|
|
743
|
-
refreshToken: import_zod2.z.string().min(8),
|
|
744
|
-
appInstanceId: import_zod2.z.string().min(3),
|
|
745
|
-
fingerprintHash: import_zod2.z.string().min(3)
|
|
746
|
-
});
|
|
747
|
-
var AuthRefreshResponseSchema = import_zod2.z.object({
|
|
748
|
-
refreshToken: import_zod2.z.string().min(8),
|
|
749
|
-
stepUpRequired: import_zod2.z.boolean()
|
|
750
|
-
});
|
|
751
|
-
var AuthLogoutRequestSchema = import_zod2.z.object({
|
|
752
|
-
userId: UuidSchema,
|
|
753
|
-
refreshToken: import_zod2.z.string().min(8)
|
|
754
|
-
});
|
|
755
|
-
var PinSetRequestSchema = import_zod2.z.object({
|
|
756
|
-
userId: UuidSchema,
|
|
757
|
-
pin: import_zod2.z.string().regex(/^\d{6}$/)
|
|
758
|
-
});
|
|
759
|
-
var PinVerifyRequestSchema = import_zod2.z.object({
|
|
760
|
-
userId: UuidSchema,
|
|
761
|
-
pin: import_zod2.z.string().regex(/^\d{6}$/)
|
|
762
|
-
});
|
|
763
|
-
var OkResponseSchema = import_zod2.z.object({
|
|
764
|
-
ok: import_zod2.z.boolean()
|
|
765
|
-
});
|
|
766
|
-
var RegisterSendDeviceKeyRequestSchema = import_zod2.z.object({
|
|
767
|
-
userId: UuidSchema,
|
|
768
|
-
deviceId: import_zod2.z.string().min(3),
|
|
769
|
-
publicKey: import_zod2.z.string().min(32)
|
|
770
|
-
});
|
|
771
|
-
var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
|
|
772
|
-
var SendChallengeRequestSchema = import_zod2.z.object({
|
|
773
|
-
userId: UuidSchema,
|
|
774
|
-
deviceId: import_zod2.z.string().min(3),
|
|
775
|
-
purpose: import_zod2.z.enum(SEND_AUTH_PURPOSES).optional()
|
|
776
|
-
});
|
|
777
|
-
var SendChallengeResponseSchema = import_zod2.z.object({
|
|
778
|
-
challengeId: UuidSchema,
|
|
779
|
-
nonce: import_zod2.z.string().min(1),
|
|
780
|
-
expiresAt: IsoDateSchema
|
|
781
|
-
});
|
|
782
|
-
var SendVerifyRequestSchema = import_zod2.z.object({
|
|
783
|
-
userId: UuidSchema,
|
|
784
|
-
deviceId: import_zod2.z.string().min(3),
|
|
785
|
-
challengeId: UuidSchema,
|
|
786
|
-
signature: import_zod2.z.string().min(16)
|
|
787
|
-
});
|
|
788
|
-
var SendVerifyResponseSchema = import_zod2.z.object({
|
|
789
|
-
sendAuthToken: import_zod2.z.string().min(16)
|
|
790
|
-
});
|
|
791
|
-
var ResolveRecipientRequestSchema = import_zod2.z.object({
|
|
792
|
-
identifier: import_zod2.z.string().min(3)
|
|
793
|
-
});
|
|
794
|
-
var ResolveRecipientResponseSchema = import_zod2.z.object({
|
|
795
|
-
recipientUserId: UuidSchema,
|
|
796
|
-
displayName: import_zod2.z.string().min(1),
|
|
797
|
-
normalizedIdentifier: import_zod2.z.string().regex(E164Regex),
|
|
798
|
-
isActive: import_zod2.z.boolean()
|
|
799
|
-
});
|
|
800
|
-
var CreateTransferRequestSchema = import_zod2.z.object({
|
|
801
|
-
recipientIdentifier: import_zod2.z.string().min(3),
|
|
802
|
-
amountMinor: import_zod2.z.number().int().positive(),
|
|
803
|
-
currency: CurrencySchema,
|
|
804
|
-
sendAuthToken: import_zod2.z.string().min(16)
|
|
805
|
-
});
|
|
806
|
-
var TransferStatusSchema = import_zod2.z.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
|
|
807
|
-
var TransferResponseSchema = import_zod2.z.object({
|
|
808
|
-
transactionId: import_zod2.z.string().min(1),
|
|
809
|
-
status: TransferStatusSchema,
|
|
810
|
-
userStatus: TransferStatusSchema,
|
|
811
|
-
recipientName: import_zod2.z.string().min(1),
|
|
812
|
-
timestamp: IsoDateSchema,
|
|
813
|
-
/**
|
|
814
|
-
* Fresh issuer-signed OACs returned by the backend's post-commit
|
|
815
|
-
* rotation hook on `SETTLED` transfers.
|
|
816
|
-
*
|
|
817
|
-
* In the current backend implementation this hook rotates LEGACY
|
|
818
|
-
* hold-backed OACs only. Account-funded (no-hold) OACs introduced by
|
|
819
|
-
* the unified-pay-rails refactor are NOT rotated here — their
|
|
820
|
-
* cumulative spend counter and main-balance check are enforced at
|
|
821
|
-
* claim submission time via `createTransfer` under the per-sender
|
|
822
|
-
* advisory lock, so a stale no-hold OAC cannot authorise overspending
|
|
823
|
-
* (it can only resolve to REVIEW on submission).
|
|
824
|
-
*
|
|
825
|
-
* Optional: omitted when the sender has no registered hold-backed
|
|
826
|
-
* devices, when the refresh failed (best-effort), or on retry replays
|
|
827
|
-
* that pre-date the refresh. When present, the entries supersede any
|
|
828
|
-
* locally cached OACs for the listed devices; when absent, clients
|
|
829
|
-
* should fall back to `/v1/me/offline/refresh`.
|
|
830
|
-
*
|
|
831
|
-
* Each entry is validated against the canonical `OACRecordSchema`,
|
|
832
|
-
* so consumers can trust the runtime shape matches the static type.
|
|
833
|
-
*/
|
|
834
|
-
offlineOacs: OACRecordSchema.array().optional()
|
|
835
|
-
});
|
|
836
|
-
var DirectionSchema = import_zod2.z.enum(["OUTGOING", "INCOMING"]);
|
|
837
|
-
var AccountActivityItemSchema = import_zod2.z.object({
|
|
838
|
-
id: import_zod2.z.string().min(1),
|
|
839
|
-
type: import_zod2.z.string().min(1),
|
|
840
|
-
direction: DirectionSchema,
|
|
841
|
-
name: import_zod2.z.string().min(1),
|
|
842
|
-
identifier: import_zod2.z.string().min(1),
|
|
843
|
-
amountMinor: import_zod2.z.number().int(),
|
|
844
|
-
currency: CurrencySchema,
|
|
845
|
-
status: import_zod2.z.string().min(1),
|
|
846
|
-
timestamp: IsoDateSchema
|
|
847
|
-
});
|
|
848
|
-
var AccountSummaryResponseSchema = import_zod2.z.object({
|
|
849
|
-
/** Authenticated user's stable internal id. */
|
|
850
|
-
userId: UuidSchema,
|
|
851
|
-
/**
|
|
852
|
-
* 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
|
|
853
|
-
* bank partner. `null` when the user has no partner-allocated account yet.
|
|
854
|
-
*/
|
|
855
|
-
nuban: import_zod2.z.string().regex(/^[0-9]{10}$/).nullable(),
|
|
856
|
-
balance: import_zod2.z.number().int(),
|
|
857
|
-
currency: CurrencySchema,
|
|
858
|
-
dailySendLimit: import_zod2.z.number().int().nonnegative(),
|
|
859
|
-
dailySendRemaining: import_zod2.z.number().int().nonnegative(),
|
|
860
|
-
kycTier: import_zod2.z.string().min(1),
|
|
861
|
-
kycStatus: import_zod2.z.string().min(1),
|
|
862
|
-
recentActivity: import_zod2.z.array(AccountActivityItemSchema)
|
|
863
|
-
});
|
|
864
|
-
var TransactionsListResponseSchema = import_zod2.z.object({
|
|
865
|
-
items: import_zod2.z.array(AccountActivityItemSchema),
|
|
866
|
-
nextCursor: import_zod2.z.string().nullable()
|
|
867
|
-
});
|
|
868
|
-
var TransactionDetailResponseSchema = import_zod2.z.object({
|
|
869
|
-
transactionId: import_zod2.z.string().min(1),
|
|
870
|
-
type: import_zod2.z.string().min(1),
|
|
871
|
-
direction: DirectionSchema,
|
|
872
|
-
counterpartyName: import_zod2.z.string().min(1),
|
|
873
|
-
counterpartyIdentifier: import_zod2.z.string().min(1),
|
|
874
|
-
amountMinor: import_zod2.z.number().int(),
|
|
875
|
-
currency: CurrencySchema,
|
|
876
|
-
status: import_zod2.z.string().min(1),
|
|
877
|
-
timestamp: IsoDateSchema
|
|
878
|
-
});
|
|
879
|
-
var PushRegisterRequestSchema = import_zod2.z.object({
|
|
880
|
-
deviceId: import_zod2.z.string().min(3),
|
|
881
|
-
platform: import_zod2.z.enum(["ios", "android", "web"]),
|
|
882
|
-
token: import_zod2.z.string().min(16)
|
|
883
|
-
});
|
|
884
|
-
var CreatePayLinkResponseSchema = import_zod2.z.object({
|
|
885
|
-
token: import_zod2.z.string().min(1)
|
|
886
|
-
});
|
|
887
|
-
var ResolvePayLinkResponseSchema = import_zod2.z.object({
|
|
888
|
-
recipientUserId: UuidSchema,
|
|
889
|
-
displayName: import_zod2.z.string().min(1),
|
|
890
|
-
normalizedIdentifier: import_zod2.z.string().regex(E164Regex),
|
|
891
|
-
isActive: import_zod2.z.boolean()
|
|
892
|
-
});
|
|
893
|
-
|
|
894
569
|
// src/primitives.ts
|
|
895
|
-
var
|
|
896
|
-
var CurrencyCodeSchema =
|
|
570
|
+
var import_zod2 = require("zod");
|
|
571
|
+
var CurrencyCodeSchema = import_zod2.z.string().trim().length(3).transform((value) => value.toUpperCase());
|
|
897
572
|
var currencyFractionDigits = {
|
|
898
573
|
NGN: 2,
|
|
899
574
|
USD: 2,
|
|
@@ -987,7 +662,7 @@ function moneyMinorToNumber(amountMinor) {
|
|
|
987
662
|
}
|
|
988
663
|
|
|
989
664
|
// src/collections/client.ts
|
|
990
|
-
var
|
|
665
|
+
var import_zod3 = require("zod");
|
|
991
666
|
var MERCHANT_PROFILE_STATUSES = [
|
|
992
667
|
"pending",
|
|
993
668
|
"active",
|
|
@@ -1017,172 +692,172 @@ var MERCHANT_PAYOUT_STATUSES = [
|
|
|
1017
692
|
"failed",
|
|
1018
693
|
"cancelled"
|
|
1019
694
|
];
|
|
1020
|
-
var MoneyKoboSchema =
|
|
1021
|
-
var MetadataSchema =
|
|
1022
|
-
|
|
695
|
+
var MoneyKoboSchema = import_zod3.z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
696
|
+
var MetadataSchema = import_zod3.z.record(
|
|
697
|
+
import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()])
|
|
1023
698
|
);
|
|
1024
|
-
var CurrencySchema2 =
|
|
1025
|
-
var ReferenceSchema =
|
|
1026
|
-
var MerchantProfileSchema =
|
|
1027
|
-
accountId:
|
|
1028
|
-
legalName:
|
|
1029
|
-
tradingName:
|
|
1030
|
-
merchantCategoryCode:
|
|
1031
|
-
nqrMerchantId:
|
|
1032
|
-
settlementBankCode:
|
|
1033
|
-
settlementAccountNumber:
|
|
1034
|
-
settlementAccountName:
|
|
1035
|
-
settlementSchedule:
|
|
1036
|
-
status:
|
|
1037
|
-
offlineEnabled:
|
|
699
|
+
var CurrencySchema2 = import_zod3.z.string().trim().length(3).transform((value) => value.toUpperCase());
|
|
700
|
+
var ReferenceSchema = import_zod3.z.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
|
|
701
|
+
var MerchantProfileSchema = import_zod3.z.object({
|
|
702
|
+
accountId: import_zod3.z.string().uuid(),
|
|
703
|
+
legalName: import_zod3.z.string(),
|
|
704
|
+
tradingName: import_zod3.z.string(),
|
|
705
|
+
merchantCategoryCode: import_zod3.z.string().regex(/^\d{4}$/),
|
|
706
|
+
nqrMerchantId: import_zod3.z.string(),
|
|
707
|
+
settlementBankCode: import_zod3.z.string(),
|
|
708
|
+
settlementAccountNumber: import_zod3.z.string(),
|
|
709
|
+
settlementAccountName: import_zod3.z.string(),
|
|
710
|
+
settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES),
|
|
711
|
+
status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES),
|
|
712
|
+
offlineEnabled: import_zod3.z.boolean(),
|
|
1038
713
|
perTxLimitKobo: MoneyKoboSchema,
|
|
1039
714
|
dailyLimitKobo: MoneyKoboSchema,
|
|
1040
715
|
metadata: MetadataSchema,
|
|
1041
|
-
createdAtMs:
|
|
1042
|
-
updatedAtMs:
|
|
716
|
+
createdAtMs: import_zod3.z.number().int().nonnegative(),
|
|
717
|
+
updatedAtMs: import_zod3.z.number().int().nonnegative()
|
|
1043
718
|
});
|
|
1044
|
-
var UpsertMerchantProfileInputSchema =
|
|
1045
|
-
legalName:
|
|
1046
|
-
tradingName:
|
|
1047
|
-
merchantCategoryCode:
|
|
1048
|
-
nqrMerchantId:
|
|
1049
|
-
settlementBankCode:
|
|
1050
|
-
settlementAccountNumber:
|
|
1051
|
-
settlementAccountName:
|
|
1052
|
-
settlementSchedule:
|
|
1053
|
-
status:
|
|
1054
|
-
offlineEnabled:
|
|
719
|
+
var UpsertMerchantProfileInputSchema = import_zod3.z.object({
|
|
720
|
+
legalName: import_zod3.z.string().trim().min(1).max(200),
|
|
721
|
+
tradingName: import_zod3.z.string().trim().min(1).max(25),
|
|
722
|
+
merchantCategoryCode: import_zod3.z.string().trim().regex(/^\d{4}$/),
|
|
723
|
+
nqrMerchantId: import_zod3.z.string().trim().min(3).max(64),
|
|
724
|
+
settlementBankCode: import_zod3.z.string().trim().min(2).max(16),
|
|
725
|
+
settlementAccountNumber: import_zod3.z.string().trim().min(5).max(32),
|
|
726
|
+
settlementAccountName: import_zod3.z.string().trim().min(1).max(200),
|
|
727
|
+
settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES).optional(),
|
|
728
|
+
status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES).optional(),
|
|
729
|
+
offlineEnabled: import_zod3.z.boolean().optional(),
|
|
1055
730
|
perTxLimitKobo: MoneyKoboSchema.optional(),
|
|
1056
731
|
dailyLimitKobo: MoneyKoboSchema.optional(),
|
|
1057
732
|
metadata: MetadataSchema.optional()
|
|
1058
733
|
});
|
|
1059
|
-
var CollectionIntentSchema =
|
|
1060
|
-
intentId:
|
|
1061
|
-
accountId:
|
|
1062
|
-
terminalId:
|
|
1063
|
-
reference:
|
|
1064
|
-
amountKobo:
|
|
1065
|
-
currency:
|
|
1066
|
-
status:
|
|
1067
|
-
description:
|
|
1068
|
-
nqrPayload:
|
|
1069
|
-
provider:
|
|
1070
|
-
providerReference:
|
|
734
|
+
var CollectionIntentSchema = import_zod3.z.object({
|
|
735
|
+
intentId: import_zod3.z.string().uuid(),
|
|
736
|
+
accountId: import_zod3.z.string().uuid(),
|
|
737
|
+
terminalId: import_zod3.z.string().uuid().nullable(),
|
|
738
|
+
reference: import_zod3.z.string(),
|
|
739
|
+
amountKobo: import_zod3.z.number().int().positive().nullable(),
|
|
740
|
+
currency: import_zod3.z.string().length(3),
|
|
741
|
+
status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
|
|
742
|
+
description: import_zod3.z.string().nullable(),
|
|
743
|
+
nqrPayload: import_zod3.z.string(),
|
|
744
|
+
provider: import_zod3.z.string(),
|
|
745
|
+
providerReference: import_zod3.z.string().nullable(),
|
|
1071
746
|
metadata: MetadataSchema,
|
|
1072
|
-
expiresAtMs:
|
|
1073
|
-
paidAtMs:
|
|
1074
|
-
createdAtMs:
|
|
1075
|
-
updatedAtMs:
|
|
747
|
+
expiresAtMs: import_zod3.z.number().int().nonnegative().nullable(),
|
|
748
|
+
paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
|
|
749
|
+
createdAtMs: import_zod3.z.number().int().nonnegative(),
|
|
750
|
+
updatedAtMs: import_zod3.z.number().int().nonnegative()
|
|
1076
751
|
});
|
|
1077
|
-
var CreateCollectionIntentInputSchema =
|
|
752
|
+
var CreateCollectionIntentInputSchema = import_zod3.z.object({
|
|
1078
753
|
reference: ReferenceSchema.optional(),
|
|
1079
754
|
amountKobo: MoneyKoboSchema.optional(),
|
|
1080
755
|
currency: CurrencySchema2.optional(),
|
|
1081
|
-
terminalId:
|
|
1082
|
-
terminalLabel:
|
|
1083
|
-
merchantCity:
|
|
1084
|
-
description:
|
|
1085
|
-
expiresAtMs:
|
|
1086
|
-
provider:
|
|
756
|
+
terminalId: import_zod3.z.string().uuid().optional(),
|
|
757
|
+
terminalLabel: import_zod3.z.string().trim().min(1).max(25).optional(),
|
|
758
|
+
merchantCity: import_zod3.z.string().trim().min(1).max(15).optional(),
|
|
759
|
+
description: import_zod3.z.string().trim().min(1).max(280).optional(),
|
|
760
|
+
expiresAtMs: import_zod3.z.number().int().positive().optional(),
|
|
761
|
+
provider: import_zod3.z.string().trim().min(1).max(40).optional(),
|
|
1087
762
|
metadata: MetadataSchema.optional()
|
|
1088
763
|
});
|
|
1089
|
-
var PublicCollectionIntentSchema =
|
|
1090
|
-
intentId:
|
|
1091
|
-
reference:
|
|
1092
|
-
amountKobo:
|
|
1093
|
-
currency:
|
|
1094
|
-
status:
|
|
1095
|
-
merchantAccountId:
|
|
1096
|
-
merchantName:
|
|
1097
|
-
merchantCategoryCode:
|
|
1098
|
-
description:
|
|
1099
|
-
expiresAtMs:
|
|
764
|
+
var PublicCollectionIntentSchema = import_zod3.z.object({
|
|
765
|
+
intentId: import_zod3.z.string().uuid(),
|
|
766
|
+
reference: import_zod3.z.string(),
|
|
767
|
+
amountKobo: import_zod3.z.number().int().positive().nullable(),
|
|
768
|
+
currency: import_zod3.z.string().length(3),
|
|
769
|
+
status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
|
|
770
|
+
merchantAccountId: import_zod3.z.string().uuid(),
|
|
771
|
+
merchantName: import_zod3.z.string(),
|
|
772
|
+
merchantCategoryCode: import_zod3.z.string(),
|
|
773
|
+
description: import_zod3.z.string().nullable(),
|
|
774
|
+
expiresAtMs: import_zod3.z.number().int().nonnegative().nullable()
|
|
1100
775
|
});
|
|
1101
|
-
var PayCollectionInputSchema =
|
|
776
|
+
var PayCollectionInputSchema = import_zod3.z.object({
|
|
1102
777
|
reference: ReferenceSchema,
|
|
1103
778
|
amountKobo: MoneyKoboSchema.optional(),
|
|
1104
779
|
currency: CurrencySchema2.optional(),
|
|
1105
|
-
idempotencyKey:
|
|
780
|
+
idempotencyKey: import_zod3.z.string().trim().min(8).max(160).optional()
|
|
1106
781
|
});
|
|
1107
|
-
var CollectionPaymentSchema =
|
|
1108
|
-
paymentId:
|
|
1109
|
-
intentId:
|
|
1110
|
-
accountId:
|
|
1111
|
-
payerUserId:
|
|
1112
|
-
merchantOwnerUserId:
|
|
782
|
+
var CollectionPaymentSchema = import_zod3.z.object({
|
|
783
|
+
paymentId: import_zod3.z.string().uuid(),
|
|
784
|
+
intentId: import_zod3.z.string().uuid(),
|
|
785
|
+
accountId: import_zod3.z.string().uuid(),
|
|
786
|
+
payerUserId: import_zod3.z.string().uuid().nullable(),
|
|
787
|
+
merchantOwnerUserId: import_zod3.z.string().uuid(),
|
|
1113
788
|
amountKobo: MoneyKoboSchema,
|
|
1114
|
-
currency:
|
|
1115
|
-
status:
|
|
1116
|
-
provider:
|
|
1117
|
-
providerReference:
|
|
1118
|
-
idempotencyKey:
|
|
1119
|
-
ledgerRef:
|
|
1120
|
-
failureCode:
|
|
1121
|
-
failureMessage:
|
|
1122
|
-
paidAtMs:
|
|
1123
|
-
createdAtMs:
|
|
1124
|
-
updatedAtMs:
|
|
789
|
+
currency: import_zod3.z.string().length(3),
|
|
790
|
+
status: import_zod3.z.enum(COLLECTION_PAYMENT_STATUSES),
|
|
791
|
+
provider: import_zod3.z.string(),
|
|
792
|
+
providerReference: import_zod3.z.string().nullable(),
|
|
793
|
+
idempotencyKey: import_zod3.z.string().nullable(),
|
|
794
|
+
ledgerRef: import_zod3.z.string(),
|
|
795
|
+
failureCode: import_zod3.z.string().nullable(),
|
|
796
|
+
failureMessage: import_zod3.z.string().nullable(),
|
|
797
|
+
paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
|
|
798
|
+
createdAtMs: import_zod3.z.number().int().nonnegative(),
|
|
799
|
+
updatedAtMs: import_zod3.z.number().int().nonnegative()
|
|
1125
800
|
});
|
|
1126
|
-
var CollectionPaymentResultSchema =
|
|
801
|
+
var CollectionPaymentResultSchema = import_zod3.z.object({
|
|
1127
802
|
payment: CollectionPaymentSchema,
|
|
1128
803
|
intent: CollectionIntentSchema,
|
|
1129
|
-
receipt:
|
|
1130
|
-
replayed:
|
|
804
|
+
receipt: import_zod3.z.unknown().optional(),
|
|
805
|
+
replayed: import_zod3.z.boolean()
|
|
1131
806
|
});
|
|
1132
|
-
var CollectionReportSummarySchema =
|
|
1133
|
-
accountId:
|
|
1134
|
-
fromMs:
|
|
1135
|
-
toMs:
|
|
1136
|
-
currency:
|
|
1137
|
-
paidCount:
|
|
1138
|
-
paidAmountKobo:
|
|
1139
|
-
pendingCount:
|
|
1140
|
-
failedCount:
|
|
1141
|
-
reversedCount:
|
|
1142
|
-
availableBalanceKobo:
|
|
807
|
+
var CollectionReportSummarySchema = import_zod3.z.object({
|
|
808
|
+
accountId: import_zod3.z.string().uuid(),
|
|
809
|
+
fromMs: import_zod3.z.number().int().nonnegative(),
|
|
810
|
+
toMs: import_zod3.z.number().int().nonnegative(),
|
|
811
|
+
currency: import_zod3.z.string().length(3),
|
|
812
|
+
paidCount: import_zod3.z.number().int().nonnegative(),
|
|
813
|
+
paidAmountKobo: import_zod3.z.number().int().nonnegative(),
|
|
814
|
+
pendingCount: import_zod3.z.number().int().nonnegative(),
|
|
815
|
+
failedCount: import_zod3.z.number().int().nonnegative(),
|
|
816
|
+
reversedCount: import_zod3.z.number().int().nonnegative(),
|
|
817
|
+
availableBalanceKobo: import_zod3.z.number().int().nonnegative()
|
|
1143
818
|
});
|
|
1144
|
-
var CollectionStatementSchema =
|
|
1145
|
-
accountId:
|
|
1146
|
-
year:
|
|
1147
|
-
month:
|
|
1148
|
-
currency:
|
|
1149
|
-
totalPaidKobo:
|
|
1150
|
-
items:
|
|
819
|
+
var CollectionStatementSchema = import_zod3.z.object({
|
|
820
|
+
accountId: import_zod3.z.string().uuid(),
|
|
821
|
+
year: import_zod3.z.number().int(),
|
|
822
|
+
month: import_zod3.z.number().int().min(1).max(12),
|
|
823
|
+
currency: import_zod3.z.string().length(3),
|
|
824
|
+
totalPaidKobo: import_zod3.z.number().int().nonnegative(),
|
|
825
|
+
items: import_zod3.z.array(CollectionPaymentSchema)
|
|
1151
826
|
});
|
|
1152
|
-
var CreatePayoutInputSchema =
|
|
827
|
+
var CreatePayoutInputSchema = import_zod3.z.object({
|
|
1153
828
|
amountKobo: MoneyKoboSchema,
|
|
1154
829
|
currency: CurrencySchema2.optional(),
|
|
1155
|
-
idempotencyKey:
|
|
830
|
+
idempotencyKey: import_zod3.z.string().trim().min(8).max(160)
|
|
1156
831
|
});
|
|
1157
|
-
var MerchantPayoutSchema =
|
|
1158
|
-
payoutId:
|
|
1159
|
-
accountId:
|
|
832
|
+
var MerchantPayoutSchema = import_zod3.z.object({
|
|
833
|
+
payoutId: import_zod3.z.string().uuid(),
|
|
834
|
+
accountId: import_zod3.z.string().uuid(),
|
|
1160
835
|
amountKobo: MoneyKoboSchema,
|
|
1161
|
-
currency:
|
|
1162
|
-
status:
|
|
1163
|
-
idempotencyKey:
|
|
1164
|
-
ledgerRef:
|
|
1165
|
-
providerReference:
|
|
1166
|
-
requestedByUserId:
|
|
1167
|
-
failureCode:
|
|
1168
|
-
failureMessage:
|
|
1169
|
-
createdAtMs:
|
|
1170
|
-
updatedAtMs:
|
|
836
|
+
currency: import_zod3.z.string().length(3),
|
|
837
|
+
status: import_zod3.z.enum(MERCHANT_PAYOUT_STATUSES),
|
|
838
|
+
idempotencyKey: import_zod3.z.string().nullable(),
|
|
839
|
+
ledgerRef: import_zod3.z.string(),
|
|
840
|
+
providerReference: import_zod3.z.string().nullable(),
|
|
841
|
+
requestedByUserId: import_zod3.z.string().uuid().nullable(),
|
|
842
|
+
failureCode: import_zod3.z.string().nullable(),
|
|
843
|
+
failureMessage: import_zod3.z.string().nullable(),
|
|
844
|
+
createdAtMs: import_zod3.z.number().int().nonnegative(),
|
|
845
|
+
updatedAtMs: import_zod3.z.number().int().nonnegative()
|
|
1171
846
|
});
|
|
1172
|
-
var ProviderEventInputSchema =
|
|
1173
|
-
provider:
|
|
1174
|
-
eventId:
|
|
1175
|
-
eventType:
|
|
1176
|
-
payload:
|
|
847
|
+
var ProviderEventInputSchema = import_zod3.z.object({
|
|
848
|
+
provider: import_zod3.z.string().trim().min(1).max(80),
|
|
849
|
+
eventId: import_zod3.z.string().trim().min(1).max(160),
|
|
850
|
+
eventType: import_zod3.z.string().trim().min(1).max(120),
|
|
851
|
+
payload: import_zod3.z.record(import_zod3.z.unknown()).optional()
|
|
1177
852
|
});
|
|
1178
|
-
var ProviderEventRecordSchema =
|
|
1179
|
-
id:
|
|
1180
|
-
provider:
|
|
1181
|
-
eventId:
|
|
1182
|
-
eventType:
|
|
1183
|
-
signatureVerified:
|
|
1184
|
-
receivedAtMs:
|
|
1185
|
-
processedAtMs:
|
|
853
|
+
var ProviderEventRecordSchema = import_zod3.z.object({
|
|
854
|
+
id: import_zod3.z.string().uuid(),
|
|
855
|
+
provider: import_zod3.z.string(),
|
|
856
|
+
eventId: import_zod3.z.string(),
|
|
857
|
+
eventType: import_zod3.z.string(),
|
|
858
|
+
signatureVerified: import_zod3.z.boolean(),
|
|
859
|
+
receivedAtMs: import_zod3.z.number().int().nonnegative(),
|
|
860
|
+
processedAtMs: import_zod3.z.number().int().nonnegative().nullable()
|
|
1186
861
|
});
|
|
1187
862
|
function createCollectionsClient(opts) {
|
|
1188
863
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
@@ -1697,7 +1372,7 @@ var FlurClient = class {
|
|
|
1697
1372
|
try {
|
|
1698
1373
|
body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
|
|
1699
1374
|
} catch (err) {
|
|
1700
|
-
if (err instanceof
|
|
1375
|
+
if (err instanceof import_zod4.z.ZodError) {
|
|
1701
1376
|
throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
|
|
1702
1377
|
details: err.flatten()
|
|
1703
1378
|
});
|
|
@@ -1725,7 +1400,7 @@ var FlurClient = class {
|
|
|
1725
1400
|
try {
|
|
1726
1401
|
return responseSchema.parse(payload);
|
|
1727
1402
|
} catch (err) {
|
|
1728
|
-
if (err instanceof
|
|
1403
|
+
if (err instanceof import_zod4.z.ZodError) {
|
|
1729
1404
|
throw new FlurError(
|
|
1730
1405
|
"SDK contract validation failed",
|
|
1731
1406
|
"INVALID_REQUEST",
|
|
@@ -2156,7 +1831,7 @@ function constantTimeEqual(a, b) {
|
|
|
2156
1831
|
}
|
|
2157
1832
|
|
|
2158
1833
|
// src/offline/oac.ts
|
|
2159
|
-
var
|
|
1834
|
+
var import_zod5 = require("zod");
|
|
2160
1835
|
|
|
2161
1836
|
// src/crypto/p256-issuer.ts
|
|
2162
1837
|
var import_nist = require("@noble/curves/nist");
|
|
@@ -2238,20 +1913,20 @@ function verifyIssuerP256(bytes, signatureB64, issuerPublicKeySpkiB64) {
|
|
|
2238
1913
|
var OAC_DEFAULT_PER_TX_KOBO = 5e5;
|
|
2239
1914
|
var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
|
|
2240
1915
|
var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
|
|
2241
|
-
var
|
|
2242
|
-
var OACSchema =
|
|
2243
|
-
userId:
|
|
2244
|
-
deviceId:
|
|
1916
|
+
var Base64Std = import_zod5.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) string");
|
|
1917
|
+
var OACSchema = import_zod5.z.object({
|
|
1918
|
+
userId: import_zod5.z.string().min(1),
|
|
1919
|
+
deviceId: import_zod5.z.string().min(1),
|
|
2245
1920
|
/** SubjectPublicKeyInfo DER, base64 (P-256). */
|
|
2246
|
-
devicePublicKey:
|
|
2247
|
-
perTxCapKobo:
|
|
2248
|
-
cumulativeCapKobo:
|
|
2249
|
-
validFromMs:
|
|
2250
|
-
validUntilMs:
|
|
2251
|
-
counterSeed:
|
|
2252
|
-
nonce:
|
|
1921
|
+
devicePublicKey: Base64Std,
|
|
1922
|
+
perTxCapKobo: import_zod5.z.number().int().nonnegative(),
|
|
1923
|
+
cumulativeCapKobo: import_zod5.z.number().int().nonnegative(),
|
|
1924
|
+
validFromMs: import_zod5.z.number().int().nonnegative(),
|
|
1925
|
+
validUntilMs: import_zod5.z.number().int().positive(),
|
|
1926
|
+
counterSeed: import_zod5.z.number().int().nonnegative(),
|
|
1927
|
+
nonce: import_zod5.z.string().min(1),
|
|
2253
1928
|
/** ASN.1 DER ECDSA(SHA-256) signature, base64. */
|
|
2254
|
-
issuerSig:
|
|
1929
|
+
issuerSig: Base64Std
|
|
2255
1930
|
}).refine((v) => v.validUntilMs > v.validFromMs, {
|
|
2256
1931
|
message: "validUntilMs must be greater than validFromMs"
|
|
2257
1932
|
}).refine((v) => v.perTxCapKobo <= v.cumulativeCapKobo, {
|
|
@@ -2345,19 +2020,19 @@ function decodeBase45(s) {
|
|
|
2345
2020
|
}
|
|
2346
2021
|
|
|
2347
2022
|
// src/offline/messages.ts
|
|
2348
|
-
var
|
|
2349
|
-
var Base64Sig =
|
|
2350
|
-
var OfflinePaymentRequestSchema =
|
|
2351
|
-
reference:
|
|
2352
|
-
amountKobo:
|
|
2023
|
+
var import_zod6 = require("zod");
|
|
2024
|
+
var Base64Sig = import_zod6.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) signature");
|
|
2025
|
+
var OfflinePaymentRequestSchema = import_zod6.z.object({
|
|
2026
|
+
reference: import_zod6.z.string().min(1),
|
|
2027
|
+
amountKobo: import_zod6.z.number().int().positive(),
|
|
2353
2028
|
merchantOAC: OACSchema,
|
|
2354
|
-
expiresAtMs:
|
|
2029
|
+
expiresAtMs: import_zod6.z.number().int().positive(),
|
|
2355
2030
|
merchantSig: Base64Sig
|
|
2356
2031
|
});
|
|
2357
|
-
var OfflinePaymentAuthorizationSchema =
|
|
2032
|
+
var OfflinePaymentAuthorizationSchema = import_zod6.z.object({
|
|
2358
2033
|
request: OfflinePaymentRequestSchema,
|
|
2359
2034
|
payerOAC: OACSchema,
|
|
2360
|
-
payerCounter:
|
|
2035
|
+
payerCounter: import_zod6.z.number().int().positive(),
|
|
2361
2036
|
payerSig: Base64Sig
|
|
2362
2037
|
});
|
|
2363
2038
|
function buildPaymentRequest(input) {
|
|
@@ -2469,60 +2144,60 @@ function decodeAuthorizationQR(s) {
|
|
|
2469
2144
|
}
|
|
2470
2145
|
|
|
2471
2146
|
// src/offline/settlements.ts
|
|
2472
|
-
var
|
|
2147
|
+
var import_zod7 = require("zod");
|
|
2473
2148
|
var import_sha256 = require("@noble/hashes/sha256");
|
|
2474
2149
|
var import_utils = require("@noble/hashes/utils");
|
|
2475
|
-
var OfflineTokenSchema =
|
|
2476
|
-
tokenId:
|
|
2477
|
-
tokenSerial:
|
|
2478
|
-
issuerAccountId:
|
|
2479
|
-
payerUserId:
|
|
2480
|
-
maxAmountKobo:
|
|
2481
|
-
currency:
|
|
2482
|
-
issuedAtMs:
|
|
2483
|
-
expiresAtMs:
|
|
2484
|
-
issuerSig:
|
|
2150
|
+
var OfflineTokenSchema = import_zod7.z.object({
|
|
2151
|
+
tokenId: import_zod7.z.string().uuid(),
|
|
2152
|
+
tokenSerial: import_zod7.z.string(),
|
|
2153
|
+
issuerAccountId: import_zod7.z.string().uuid(),
|
|
2154
|
+
payerUserId: import_zod7.z.string().uuid(),
|
|
2155
|
+
maxAmountKobo: import_zod7.z.number().int().positive(),
|
|
2156
|
+
currency: import_zod7.z.string().length(3),
|
|
2157
|
+
issuedAtMs: import_zod7.z.number().int().nonnegative(),
|
|
2158
|
+
expiresAtMs: import_zod7.z.number().int().nonnegative(),
|
|
2159
|
+
issuerSig: import_zod7.z.string()
|
|
2485
2160
|
});
|
|
2486
|
-
var PaymentClaimSchema =
|
|
2487
|
-
encounterId:
|
|
2488
|
-
tokenSerial:
|
|
2489
|
-
payerUserId:
|
|
2490
|
-
payeeUserId:
|
|
2491
|
-
payerNonce:
|
|
2492
|
-
payeeNonce:
|
|
2493
|
-
amountKobo:
|
|
2494
|
-
currency:
|
|
2495
|
-
occurredAtMs:
|
|
2496
|
-
completedAtMs:
|
|
2497
|
-
contextId:
|
|
2161
|
+
var PaymentClaimSchema = import_zod7.z.object({
|
|
2162
|
+
encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
|
|
2163
|
+
tokenSerial: import_zod7.z.string(),
|
|
2164
|
+
payerUserId: import_zod7.z.string().uuid(),
|
|
2165
|
+
payeeUserId: import_zod7.z.string().uuid(),
|
|
2166
|
+
payerNonce: import_zod7.z.string(),
|
|
2167
|
+
payeeNonce: import_zod7.z.string(),
|
|
2168
|
+
amountKobo: import_zod7.z.number().int().positive(),
|
|
2169
|
+
currency: import_zod7.z.string().length(3).default("NGN"),
|
|
2170
|
+
occurredAtMs: import_zod7.z.number().int().nonnegative(),
|
|
2171
|
+
completedAtMs: import_zod7.z.number().int().nonnegative().optional(),
|
|
2172
|
+
contextId: import_zod7.z.string().optional(),
|
|
2498
2173
|
// Stage 2c: P-256 device keys are now SubjectPublicKeyInfo DER, base64.
|
|
2499
2174
|
// Signatures are ASN.1 DER ECDSA(SHA-256), base64. Backwards-incompatible
|
|
2500
2175
|
// wire change; the backend has the matching widening in offline-settlements
|
|
2501
2176
|
// service + zod schema.
|
|
2502
|
-
payerPubkey:
|
|
2503
|
-
payerSignature:
|
|
2504
|
-
payeePubkey:
|
|
2505
|
-
payeeSignature:
|
|
2177
|
+
payerPubkey: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
|
|
2178
|
+
payerSignature: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
|
|
2179
|
+
payeePubkey: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional(),
|
|
2180
|
+
payeeSignature: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional()
|
|
2506
2181
|
});
|
|
2507
|
-
var SettlementSchema =
|
|
2508
|
-
settlementId:
|
|
2509
|
-
settlementKey:
|
|
2510
|
-
encounterId:
|
|
2511
|
-
issuerAccountId:
|
|
2512
|
-
tokenSerial:
|
|
2513
|
-
payerUserId:
|
|
2514
|
-
payeeUserId:
|
|
2515
|
-
amountKobo:
|
|
2516
|
-
currency:
|
|
2517
|
-
receiptId:
|
|
2518
|
-
status:
|
|
2519
|
-
issuerSig:
|
|
2520
|
-
createdAtMs:
|
|
2182
|
+
var SettlementSchema = import_zod7.z.object({
|
|
2183
|
+
settlementId: import_zod7.z.string().uuid(),
|
|
2184
|
+
settlementKey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
|
|
2185
|
+
encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
|
|
2186
|
+
issuerAccountId: import_zod7.z.string().uuid(),
|
|
2187
|
+
tokenSerial: import_zod7.z.string(),
|
|
2188
|
+
payerUserId: import_zod7.z.string().uuid(),
|
|
2189
|
+
payeeUserId: import_zod7.z.string().uuid(),
|
|
2190
|
+
amountKobo: import_zod7.z.number().int().nonnegative(),
|
|
2191
|
+
currency: import_zod7.z.string().length(3),
|
|
2192
|
+
receiptId: import_zod7.z.string().nullable(),
|
|
2193
|
+
status: import_zod7.z.enum(["SETTLED", "REVIEW", "REJECTED"]),
|
|
2194
|
+
issuerSig: import_zod7.z.string(),
|
|
2195
|
+
createdAtMs: import_zod7.z.number().int().nonnegative()
|
|
2521
2196
|
});
|
|
2522
|
-
var SettleResponseSchema =
|
|
2197
|
+
var SettleResponseSchema = import_zod7.z.object({
|
|
2523
2198
|
settlement: SettlementSchema,
|
|
2524
|
-
encounterId:
|
|
2525
|
-
replayed:
|
|
2199
|
+
encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
|
|
2200
|
+
replayed: import_zod7.z.boolean()
|
|
2526
2201
|
});
|
|
2527
2202
|
var ENCOUNTER_DOMAIN = "offline:v1:encounter";
|
|
2528
2203
|
async function sha256Hex(input) {
|
|
@@ -2696,7 +2371,7 @@ function createHmacFetch(opts) {
|
|
|
2696
2371
|
}
|
|
2697
2372
|
|
|
2698
2373
|
// src/partner/client.ts
|
|
2699
|
-
var
|
|
2374
|
+
var import_zod8 = require("zod");
|
|
2700
2375
|
var import_sha2563 = require("@noble/hashes/sha256");
|
|
2701
2376
|
var import_hmac4 = require("@noble/hashes/hmac");
|
|
2702
2377
|
var import_utils2 = require("@noble/hashes/utils");
|
|
@@ -2720,18 +2395,18 @@ var PARTNER_SCOPES = [
|
|
|
2720
2395
|
"partner:payout:write",
|
|
2721
2396
|
"partner:reconciliation:read"
|
|
2722
2397
|
];
|
|
2723
|
-
var ApiCredentialPublicSchema =
|
|
2724
|
-
id:
|
|
2725
|
-
accountId:
|
|
2726
|
-
keyId:
|
|
2727
|
-
scopes:
|
|
2728
|
-
label:
|
|
2729
|
-
createdAtMs:
|
|
2730
|
-
lastUsedAtMs:
|
|
2731
|
-
revokedAtMs:
|
|
2398
|
+
var ApiCredentialPublicSchema = import_zod8.z.object({
|
|
2399
|
+
id: import_zod8.z.string().uuid(),
|
|
2400
|
+
accountId: import_zod8.z.string().uuid(),
|
|
2401
|
+
keyId: import_zod8.z.string(),
|
|
2402
|
+
scopes: import_zod8.z.array(import_zod8.z.enum(PARTNER_SCOPES)),
|
|
2403
|
+
label: import_zod8.z.string().nullable(),
|
|
2404
|
+
createdAtMs: import_zod8.z.number().int().nonnegative(),
|
|
2405
|
+
lastUsedAtMs: import_zod8.z.number().int().nonnegative().nullable(),
|
|
2406
|
+
revokedAtMs: import_zod8.z.number().int().nonnegative().nullable()
|
|
2732
2407
|
});
|
|
2733
2408
|
var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
|
|
2734
|
-
secret:
|
|
2409
|
+
secret: import_zod8.z.string().min(1)
|
|
2735
2410
|
});
|
|
2736
2411
|
var enc = new TextEncoder();
|
|
2737
2412
|
async function sha256Hex2(input) {
|
|
@@ -2888,8 +2563,8 @@ function createApiCredentialsAdminClient(opts) {
|
|
|
2888
2563
|
}
|
|
2889
2564
|
return parser(raw);
|
|
2890
2565
|
}
|
|
2891
|
-
const listSchema =
|
|
2892
|
-
items:
|
|
2566
|
+
const listSchema = import_zod8.z.object({
|
|
2567
|
+
items: import_zod8.z.array(ApiCredentialPublicSchema)
|
|
2893
2568
|
});
|
|
2894
2569
|
return {
|
|
2895
2570
|
list: (accountId) => call(
|
|
@@ -2914,7 +2589,7 @@ function createApiCredentialsAdminClient(opts) {
|
|
|
2914
2589
|
}
|
|
2915
2590
|
|
|
2916
2591
|
// src/passes/pass.ts
|
|
2917
|
-
var
|
|
2592
|
+
var import_zod9 = require("zod");
|
|
2918
2593
|
var PASS_KINDS = [
|
|
2919
2594
|
"ride-ticket",
|
|
2920
2595
|
"transit-pass",
|
|
@@ -2930,39 +2605,39 @@ var PASS_STATES = [
|
|
|
2930
2605
|
"expired",
|
|
2931
2606
|
"revoked"
|
|
2932
2607
|
];
|
|
2933
|
-
var PassMetadataSchema =
|
|
2934
|
-
|
|
2608
|
+
var PassMetadataSchema = import_zod9.z.record(
|
|
2609
|
+
import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number(), import_zod9.z.boolean(), import_zod9.z.null()])
|
|
2935
2610
|
);
|
|
2936
|
-
var PassSchema =
|
|
2937
|
-
passId:
|
|
2611
|
+
var PassSchema = import_zod9.z.object({
|
|
2612
|
+
passId: import_zod9.z.string().min(1),
|
|
2938
2613
|
/** Optional client/template grouping id (server may omit). */
|
|
2939
|
-
templateId:
|
|
2614
|
+
templateId: import_zod9.z.string().min(1).optional(),
|
|
2940
2615
|
/** Optional human-facing holder identity (server may omit). The cryptographic binding
|
|
2941
2616
|
* is `holderDevicePubkey` below. */
|
|
2942
|
-
holderUserId:
|
|
2943
|
-
kind:
|
|
2944
|
-
issuerId:
|
|
2945
|
-
issuedAtMs:
|
|
2946
|
-
validFromMs:
|
|
2947
|
-
validUntilMs:
|
|
2948
|
-
state:
|
|
2617
|
+
holderUserId: import_zod9.z.string().min(1).optional(),
|
|
2618
|
+
kind: import_zod9.z.enum(PASS_KINDS),
|
|
2619
|
+
issuerId: import_zod9.z.string().min(1),
|
|
2620
|
+
issuedAtMs: import_zod9.z.number().int().nonnegative(),
|
|
2621
|
+
validFromMs: import_zod9.z.number().int().nonnegative(),
|
|
2622
|
+
validUntilMs: import_zod9.z.number().int().positive(),
|
|
2623
|
+
state: import_zod9.z.enum(PASS_STATES),
|
|
2949
2624
|
metadata: PassMetadataSchema,
|
|
2950
|
-
nonce:
|
|
2625
|
+
nonce: import_zod9.z.string().min(1),
|
|
2951
2626
|
/** Device id this pass is bound to (FK to backend `device_keys`). */
|
|
2952
|
-
holderDeviceId:
|
|
2627
|
+
holderDeviceId: import_zod9.z.string().min(1),
|
|
2953
2628
|
/** SubjectPublicKeyInfo DER (P-256) of the bound device, base64. The redemption
|
|
2954
2629
|
* signature is verified against this key — it is the security-critical binding. */
|
|
2955
|
-
holderDevicePubkey:
|
|
2630
|
+
holderDevicePubkey: import_zod9.z.string().min(64).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
|
|
2956
2631
|
/** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
|
|
2957
|
-
amountKobo:
|
|
2632
|
+
amountKobo: import_zod9.z.number().int().nonnegative().optional(),
|
|
2958
2633
|
/** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
|
|
2959
|
-
currency:
|
|
2634
|
+
currency: import_zod9.z.string().min(3).max(8),
|
|
2960
2635
|
/** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
|
|
2961
|
-
counterSeed:
|
|
2636
|
+
counterSeed: import_zod9.z.number().int().nonnegative(),
|
|
2962
2637
|
/** Optional cumulative spend cap in kobo across all redemptions of this pass. */
|
|
2963
|
-
cumulativeCapKobo:
|
|
2638
|
+
cumulativeCapKobo: import_zod9.z.number().int().nonnegative().optional(),
|
|
2964
2639
|
/** ASN.1 DER ECDSA P-256 signature, base64. */
|
|
2965
|
-
issuerSig:
|
|
2640
|
+
issuerSig: import_zod9.z.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
|
|
2966
2641
|
}).refine((v) => v.validUntilMs > v.validFromMs, {
|
|
2967
2642
|
message: "validUntilMs must be greater than validFromMs"
|
|
2968
2643
|
});
|
|
@@ -3019,20 +2694,20 @@ function isPassWithinValidity(pass, nowMs) {
|
|
|
3019
2694
|
}
|
|
3020
2695
|
|
|
3021
2696
|
// src/passes/redemption.ts
|
|
3022
|
-
var
|
|
3023
|
-
var
|
|
3024
|
-
var RedemptionSchema =
|
|
2697
|
+
var import_zod10 = require("zod");
|
|
2698
|
+
var Base64Std2 = import_zod10.z.string().min(16).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (std)");
|
|
2699
|
+
var RedemptionSchema = import_zod10.z.object({
|
|
3025
2700
|
pass: PassSchema,
|
|
3026
|
-
redeemerId:
|
|
3027
|
-
redeemedAtMs:
|
|
2701
|
+
redeemerId: import_zod10.z.string().min(1),
|
|
2702
|
+
redeemedAtMs: import_zod10.z.number().int().nonnegative(),
|
|
3028
2703
|
/** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
|
|
3029
2704
|
* and > the redeemer's lastSeenCounter for this pass. */
|
|
3030
|
-
counter:
|
|
2705
|
+
counter: import_zod10.z.number().int().positive(),
|
|
3031
2706
|
/** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
|
|
3032
|
-
amountKobo:
|
|
3033
|
-
nonce:
|
|
2707
|
+
amountKobo: import_zod10.z.number().int().nonnegative(),
|
|
2708
|
+
nonce: import_zod10.z.string().min(1),
|
|
3034
2709
|
/** ASN.1 DER ECDSA P-256 signature over canonicalJSONBytes(unsigned), base64. */
|
|
3035
|
-
holderSig:
|
|
2710
|
+
holderSig: Base64Std2
|
|
3036
2711
|
});
|
|
3037
2712
|
var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
|
|
3038
2713
|
function buildRedemption(input) {
|
|
@@ -3114,40 +2789,40 @@ function verifyRedemption(r, issuerPublicKeySpkiB64) {
|
|
|
3114
2789
|
}
|
|
3115
2790
|
|
|
3116
2791
|
// src/receipts/receipt.ts
|
|
3117
|
-
var
|
|
2792
|
+
var import_zod11 = require("zod");
|
|
3118
2793
|
var RECEIPT_CHANNELS = ["cash", "pass"];
|
|
3119
2794
|
var RECEIPT_KINDS = RECEIPT_CHANNELS;
|
|
3120
|
-
var ReceiptPayloadSchema =
|
|
3121
|
-
|
|
2795
|
+
var ReceiptPayloadSchema = import_zod11.z.record(
|
|
2796
|
+
import_zod11.z.union([import_zod11.z.string(), import_zod11.z.number(), import_zod11.z.boolean(), import_zod11.z.null()])
|
|
3122
2797
|
);
|
|
3123
|
-
var ReceiptSchema =
|
|
3124
|
-
receiptId:
|
|
3125
|
-
channel:
|
|
2798
|
+
var ReceiptSchema = import_zod11.z.object({
|
|
2799
|
+
receiptId: import_zod11.z.string().min(1),
|
|
2800
|
+
channel: import_zod11.z.enum(RECEIPT_CHANNELS),
|
|
3126
2801
|
/** Cash-channel: send_intents.id. Required when channel === 'cash'. */
|
|
3127
|
-
intentId:
|
|
2802
|
+
intentId: import_zod11.z.string().min(1).optional(),
|
|
3128
2803
|
/** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
|
|
3129
|
-
passRedemptionId:
|
|
3130
|
-
payerUserId:
|
|
3131
|
-
payeeUserId:
|
|
3132
|
-
amountKobo:
|
|
3133
|
-
currency:
|
|
3134
|
-
issuedAtMs:
|
|
3135
|
-
issuerId:
|
|
2804
|
+
passRedemptionId: import_zod11.z.string().min(1).optional(),
|
|
2805
|
+
payerUserId: import_zod11.z.string().min(1),
|
|
2806
|
+
payeeUserId: import_zod11.z.string().min(1),
|
|
2807
|
+
amountKobo: import_zod11.z.number().int().nonnegative(),
|
|
2808
|
+
currency: import_zod11.z.string().min(3).max(8),
|
|
2809
|
+
issuedAtMs: import_zod11.z.number().int().nonnegative(),
|
|
2810
|
+
issuerId: import_zod11.z.string().min(1),
|
|
3136
2811
|
payload: ReceiptPayloadSchema,
|
|
3137
2812
|
/** ASN.1 DER ECDSA P-256 signature, base64. */
|
|
3138
|
-
issuerSig:
|
|
2813
|
+
issuerSig: import_zod11.z.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
|
|
3139
2814
|
}).superRefine((v, ctx) => {
|
|
3140
2815
|
if (v.channel === "cash") {
|
|
3141
2816
|
if (!v.intentId) {
|
|
3142
2817
|
ctx.addIssue({
|
|
3143
|
-
code:
|
|
2818
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
3144
2819
|
message: "cash receipts require intentId",
|
|
3145
2820
|
path: ["intentId"]
|
|
3146
2821
|
});
|
|
3147
2822
|
}
|
|
3148
2823
|
if (v.passRedemptionId) {
|
|
3149
2824
|
ctx.addIssue({
|
|
3150
|
-
code:
|
|
2825
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
3151
2826
|
message: "cash receipts must not carry passRedemptionId",
|
|
3152
2827
|
path: ["passRedemptionId"]
|
|
3153
2828
|
});
|
|
@@ -3155,14 +2830,14 @@ var ReceiptSchema = import_zod12.z.object({
|
|
|
3155
2830
|
} else if (v.channel === "pass") {
|
|
3156
2831
|
if (!v.passRedemptionId) {
|
|
3157
2832
|
ctx.addIssue({
|
|
3158
|
-
code:
|
|
2833
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
3159
2834
|
message: "pass receipts require passRedemptionId",
|
|
3160
2835
|
path: ["passRedemptionId"]
|
|
3161
2836
|
});
|
|
3162
2837
|
}
|
|
3163
2838
|
if (v.intentId) {
|
|
3164
2839
|
ctx.addIssue({
|
|
3165
|
-
code:
|
|
2840
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
3166
2841
|
message: "pass receipts must not carry intentId",
|
|
3167
2842
|
path: ["intentId"]
|
|
3168
2843
|
});
|
|
@@ -3464,28 +3139,244 @@ function init(opts) {
|
|
|
3464
3139
|
}
|
|
3465
3140
|
|
|
3466
3141
|
// src/accounts/client.ts
|
|
3467
|
-
var
|
|
3142
|
+
var import_zod12 = require("zod");
|
|
3468
3143
|
var ACCOUNT_TYPES = ["personal", "business", "partner"];
|
|
3469
3144
|
var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
|
|
3470
3145
|
var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
|
|
3471
|
-
var AccountSchema =
|
|
3472
|
-
accountId:
|
|
3473
|
-
type:
|
|
3474
|
-
displayName:
|
|
3475
|
-
status:
|
|
3476
|
-
ownerUserId:
|
|
3477
|
-
createdAtMs:
|
|
3146
|
+
var AccountSchema = import_zod12.z.object({
|
|
3147
|
+
accountId: import_zod12.z.string().uuid(),
|
|
3148
|
+
type: import_zod12.z.enum(ACCOUNT_TYPES),
|
|
3149
|
+
displayName: import_zod12.z.string().min(1),
|
|
3150
|
+
status: import_zod12.z.enum(ACCOUNT_STATUSES),
|
|
3151
|
+
ownerUserId: import_zod12.z.string().uuid().nullable(),
|
|
3152
|
+
createdAtMs: import_zod12.z.number().int().nonnegative()
|
|
3153
|
+
});
|
|
3154
|
+
var AccountMembershipSchema = import_zod12.z.object({
|
|
3155
|
+
accountId: import_zod12.z.string().uuid(),
|
|
3156
|
+
userId: import_zod12.z.string().uuid(),
|
|
3157
|
+
role: import_zod12.z.enum(MEMBERSHIP_ROLES),
|
|
3158
|
+
createdAtMs: import_zod12.z.number().int().nonnegative()
|
|
3159
|
+
});
|
|
3160
|
+
function createAccountsClient(opts) {
|
|
3161
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
3162
|
+
if (!fetchImpl) {
|
|
3163
|
+
throw new Error("createAccountsClient: no fetch implementation available");
|
|
3164
|
+
}
|
|
3165
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
3166
|
+
async function call(method, path, body, parser) {
|
|
3167
|
+
const init2 = {
|
|
3168
|
+
method,
|
|
3169
|
+
headers: {
|
|
3170
|
+
"content-type": "application/json",
|
|
3171
|
+
accept: "application/json"
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
if (body !== void 0) init2.body = JSON.stringify(body);
|
|
3175
|
+
const resp = await fetchImpl(`${baseUrl}${path}`, init2);
|
|
3176
|
+
const text = await resp.text();
|
|
3177
|
+
let raw = void 0;
|
|
3178
|
+
if (text) {
|
|
3179
|
+
try {
|
|
3180
|
+
raw = JSON.parse(text);
|
|
3181
|
+
} catch {
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
if (!resp.ok) {
|
|
3185
|
+
const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
|
|
3186
|
+
const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
|
|
3187
|
+
throw new FlurApiError(resp.status, code, message, raw);
|
|
3188
|
+
}
|
|
3189
|
+
return parser(raw);
|
|
3190
|
+
}
|
|
3191
|
+
const itemsSchema = import_zod12.z.object({ items: import_zod12.z.array(AccountSchema) });
|
|
3192
|
+
const memberItemsSchema = import_zod12.z.object({
|
|
3193
|
+
items: import_zod12.z.array(AccountMembershipSchema)
|
|
3194
|
+
});
|
|
3195
|
+
return {
|
|
3196
|
+
listMyAccounts: () => call(
|
|
3197
|
+
"GET",
|
|
3198
|
+
"/v1/accounts/me",
|
|
3199
|
+
void 0,
|
|
3200
|
+
(raw) => itemsSchema.parse(raw)
|
|
3201
|
+
),
|
|
3202
|
+
getAccount: (accountId) => call(
|
|
3203
|
+
"GET",
|
|
3204
|
+
`/v1/accounts/${encodeURIComponent(accountId)}`,
|
|
3205
|
+
void 0,
|
|
3206
|
+
(raw) => AccountSchema.parse(raw)
|
|
3207
|
+
),
|
|
3208
|
+
listMembers: (accountId) => call(
|
|
3209
|
+
"GET",
|
|
3210
|
+
`/v1/accounts/${encodeURIComponent(accountId)}/members`,
|
|
3211
|
+
void 0,
|
|
3212
|
+
(raw) => memberItemsSchema.parse(raw)
|
|
3213
|
+
),
|
|
3214
|
+
createBusinessAccount: (input) => call("POST", "/v1/accounts", input, (raw) => AccountSchema.parse(raw)),
|
|
3215
|
+
addMember: (accountId, input) => call(
|
|
3216
|
+
"POST",
|
|
3217
|
+
`/v1/accounts/${encodeURIComponent(accountId)}/members`,
|
|
3218
|
+
input,
|
|
3219
|
+
(raw) => AccountMembershipSchema.parse(raw)
|
|
3220
|
+
)
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
// src/me-offline/client.ts
|
|
3225
|
+
var import_zod13 = require("zod");
|
|
3226
|
+
var Sha256Hex = import_zod13.z.string().regex(/^[0-9a-f]{64}$/);
|
|
3227
|
+
var Base64Std3 = import_zod13.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
|
|
3228
|
+
var ClaimNonce = import_zod13.z.string().min(8).max(128).refine((value) => !value.includes("|"), {
|
|
3229
|
+
message: "nonce must not contain |"
|
|
3230
|
+
});
|
|
3231
|
+
var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
|
|
3232
|
+
var CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1e3 * 60 * 60 * 24;
|
|
3233
|
+
var AttestationSecurityLevelSchema = import_zod13.z.enum([
|
|
3234
|
+
"STRONGBOX",
|
|
3235
|
+
"TEE",
|
|
3236
|
+
"SECURE_ENCLAVE",
|
|
3237
|
+
"SOFTWARE"
|
|
3238
|
+
]);
|
|
3239
|
+
var DeviceKeyAlgSchema = import_zod13.z.literal("p256");
|
|
3240
|
+
var RegisterDeviceKeyP256InputSchema = import_zod13.z.object({
|
|
3241
|
+
deviceId: import_zod13.z.string().min(1).max(128),
|
|
3242
|
+
/** P-256 SubjectPublicKeyInfo DER, base64. */
|
|
3243
|
+
publicKeySpkiB64: Base64Std3.min(64).max(4096),
|
|
3244
|
+
/** Base64 of the server-issued enrollment challenge string. */
|
|
3245
|
+
challengeB64: Base64Std3.min(8).max(1024),
|
|
3246
|
+
/** iOS App Attest payload or Android X.509 Key Attestation chain. */
|
|
3247
|
+
attestationChainB64: import_zod13.z.array(Base64Std3.min(16).max(16384)).min(1).max(16),
|
|
3248
|
+
securityLevel: AttestationSecurityLevelSchema
|
|
3249
|
+
});
|
|
3250
|
+
var P256EnrollmentChallengeInputSchema = import_zod13.z.object({
|
|
3251
|
+
deviceId: import_zod13.z.string().min(1).max(128)
|
|
3252
|
+
});
|
|
3253
|
+
var P256EnrollmentChallengeResultSchema = import_zod13.z.object({
|
|
3254
|
+
challenge: import_zod13.z.string().min(16),
|
|
3255
|
+
expiresAtMs: import_zod13.z.number().int().positive()
|
|
3256
|
+
});
|
|
3257
|
+
var DeviceKeyRecordSchema = import_zod13.z.object({
|
|
3258
|
+
id: import_zod13.z.string().uuid(),
|
|
3259
|
+
userId: import_zod13.z.string().uuid(),
|
|
3260
|
+
deviceId: import_zod13.z.string(),
|
|
3261
|
+
/** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
|
|
3262
|
+
alg: DeviceKeyAlgSchema.default("p256"),
|
|
3263
|
+
/** P-256 SubjectPublicKeyInfo DER, base64. */
|
|
3264
|
+
publicKeySpkiB64: Base64Std3.nullable().default(null),
|
|
3265
|
+
securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
|
|
3266
|
+
hardwareBacked: import_zod13.z.boolean().default(false),
|
|
3267
|
+
attestedAtMs: import_zod13.z.number().int().nonnegative().nullable().default(null),
|
|
3268
|
+
createdAtMs: import_zod13.z.number().int().nonnegative(),
|
|
3269
|
+
revokedAtMs: import_zod13.z.number().int().nonnegative().nullable()
|
|
3270
|
+
});
|
|
3271
|
+
var ConsumerOACSchema = import_zod13.z.object({
|
|
3272
|
+
oacId: import_zod13.z.string().uuid(),
|
|
3273
|
+
issuerId: import_zod13.z.string().min(1).max(64),
|
|
3274
|
+
userId: import_zod13.z.string().uuid(),
|
|
3275
|
+
deviceId: import_zod13.z.string().min(1).max(128),
|
|
3276
|
+
/**
|
|
3277
|
+
* Always 'p256'. Required on the wire (backend always emits it).
|
|
3278
|
+
* Kept as a literal so input/output infer identically and the schema
|
|
3279
|
+
* can be nested inside other response shapes without Zod input/output
|
|
3280
|
+
* divergence under tsup DTS bundling.
|
|
3281
|
+
*/
|
|
3282
|
+
alg: import_zod13.z.literal("p256"),
|
|
3283
|
+
/** P-256 SubjectPublicKeyInfo DER, base64. */
|
|
3284
|
+
devicePubkeySpkiB64: Base64Std3.min(64).max(4096),
|
|
3285
|
+
perTxCapKobo: import_zod13.z.number().int().positive(),
|
|
3286
|
+
cumulativeCapKobo: import_zod13.z.number().int().positive(),
|
|
3287
|
+
currency: import_zod13.z.string().length(3),
|
|
3288
|
+
validFromMs: import_zod13.z.number().int().nonnegative(),
|
|
3289
|
+
validUntilMs: import_zod13.z.number().int().nonnegative(),
|
|
3290
|
+
counterSeed: import_zod13.z.number().int().nonnegative(),
|
|
3291
|
+
issuedAtMs: import_zod13.z.number().int().nonnegative()
|
|
3292
|
+
});
|
|
3293
|
+
var SignedConsumerOACSchema = import_zod13.z.object({
|
|
3294
|
+
oac: ConsumerOACSchema,
|
|
3295
|
+
/** ASN.1 DER ECDSA P-256 issuer signature, base64. */
|
|
3296
|
+
issuerSig: Base64Std3.min(16).max(2048),
|
|
3297
|
+
/** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
|
|
3298
|
+
issuerPublicKeySpkiB64: Base64Std3.min(64).max(4096)
|
|
3478
3299
|
});
|
|
3479
|
-
var
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3300
|
+
var OACRecordSchema = SignedConsumerOACSchema.extend({
|
|
3301
|
+
currentOfflineSpentKobo: import_zod13.z.number().int().nonnegative(),
|
|
3302
|
+
status: import_zod13.z.enum(["active", "superseded", "expired", "revoked"]),
|
|
3303
|
+
supersededAtMs: import_zod13.z.number().int().nonnegative().nullable(),
|
|
3304
|
+
revokedAtMs: import_zod13.z.number().int().nonnegative().nullable()
|
|
3484
3305
|
});
|
|
3485
|
-
|
|
3306
|
+
var IssueAccountOacInputSchema = import_zod13.z.object({
|
|
3307
|
+
deviceId: import_zod13.z.string().min(1).max(128),
|
|
3308
|
+
perTxCapKobo: import_zod13.z.number().int().positive().optional(),
|
|
3309
|
+
cumulativeCapKobo: import_zod13.z.number().int().positive().optional(),
|
|
3310
|
+
ttlMs: import_zod13.z.number().int().min(6e4).max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS).optional()
|
|
3311
|
+
});
|
|
3312
|
+
var OfflineStatusResultSchema = import_zod13.z.object({
|
|
3313
|
+
active: OACRecordSchema.nullable()
|
|
3314
|
+
});
|
|
3315
|
+
var ConsumerPaymentClaimSchema = import_zod13.z.object({
|
|
3316
|
+
/** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
|
|
3317
|
+
alg: import_zod13.z.literal("p256").default("p256"),
|
|
3318
|
+
oacId: import_zod13.z.string().uuid(),
|
|
3319
|
+
encounterId: Sha256Hex.optional(),
|
|
3320
|
+
payerUserId: import_zod13.z.string().uuid(),
|
|
3321
|
+
payeeUserId: import_zod13.z.string().uuid(),
|
|
3322
|
+
payerDeviceId: import_zod13.z.string().min(1).max(128),
|
|
3323
|
+
payerNonce: ClaimNonce,
|
|
3324
|
+
payeeNonce: ClaimNonce,
|
|
3325
|
+
amountKobo: import_zod13.z.number().int().positive(),
|
|
3326
|
+
currency: import_zod13.z.string().length(3).default("NGN"),
|
|
3327
|
+
occurredAtMs: import_zod13.z.number().int().nonnegative(),
|
|
3328
|
+
completedAtMs: import_zod13.z.number().int().nonnegative().optional(),
|
|
3329
|
+
contextId: import_zod13.z.string().max(128).optional(),
|
|
3330
|
+
requestId: import_zod13.z.string().uuid().optional(),
|
|
3331
|
+
requestMode: import_zod13.z.enum(["fixed", "editable"]).optional(),
|
|
3332
|
+
requestTakerUserId: import_zod13.z.string().uuid().optional(),
|
|
3333
|
+
requestAmountKobo: import_zod13.z.number().int().positive().optional(),
|
|
3334
|
+
requestCurrency: import_zod13.z.string().length(3).optional(),
|
|
3335
|
+
requestReference: import_zod13.z.string().max(128).nullable().optional(),
|
|
3336
|
+
requestCreatedAtMs: import_zod13.z.number().int().nonnegative().optional(),
|
|
3337
|
+
requestExpiresAtMs: import_zod13.z.number().int().positive().optional(),
|
|
3338
|
+
requestNonce: import_zod13.z.string().min(8).max(128).optional(),
|
|
3339
|
+
requestTakerDeviceId: import_zod13.z.string().min(1).max(128).nullable().optional(),
|
|
3340
|
+
requestTakerPubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
|
|
3341
|
+
requestTakerSignatureDerB64: Base64Std3.min(16).max(2048).optional(),
|
|
3342
|
+
payerPubkeySpkiB64: Base64Std3.min(64).max(4096),
|
|
3343
|
+
payerSignatureDerB64: Base64Std3.min(16).max(2048),
|
|
3344
|
+
payeePubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
|
|
3345
|
+
payeeSignatureDerB64: Base64Std3.min(16).max(2048).optional()
|
|
3346
|
+
});
|
|
3347
|
+
var ConsumerSettlementSchema = import_zod13.z.object({
|
|
3348
|
+
settlementId: import_zod13.z.string().uuid(),
|
|
3349
|
+
settlementKey: Sha256Hex,
|
|
3350
|
+
encounterId: Sha256Hex,
|
|
3351
|
+
oacId: import_zod13.z.string().uuid(),
|
|
3352
|
+
payerUserId: import_zod13.z.string().uuid(),
|
|
3353
|
+
payeeUserId: import_zod13.z.string().uuid(),
|
|
3354
|
+
amountKobo: import_zod13.z.number().int().positive(),
|
|
3355
|
+
currency: import_zod13.z.string().length(3),
|
|
3356
|
+
status: import_zod13.z.enum(["SETTLED", "REVIEW"]),
|
|
3357
|
+
reviewReason: import_zod13.z.string().nullable(),
|
|
3358
|
+
ledgerRef: import_zod13.z.string().nullable(),
|
|
3359
|
+
/** ASN.1 DER ECDSA P-256 issuer signature, base64. */
|
|
3360
|
+
issuerSig: Base64Std3.min(16).max(2048),
|
|
3361
|
+
/** Canonical millisecond timestamp signed into the settlement receipt. */
|
|
3362
|
+
issuedAtMs: import_zod13.z.number().int().nonnegative(),
|
|
3363
|
+
/** Compatibility alias for API consumers that predate issuedAtMs. */
|
|
3364
|
+
createdAtMs: import_zod13.z.number().int().nonnegative().optional()
|
|
3365
|
+
});
|
|
3366
|
+
var ConsumerSettleResultSchema = import_zod13.z.object({
|
|
3367
|
+
settlement: ConsumerSettlementSchema,
|
|
3368
|
+
encounterId: Sha256Hex,
|
|
3369
|
+
replayed: import_zod13.z.boolean()
|
|
3370
|
+
});
|
|
3371
|
+
var RevokeDeviceKeyInputSchema = import_zod13.z.object({
|
|
3372
|
+
deviceId: import_zod13.z.string().min(1).max(128),
|
|
3373
|
+
/** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
|
|
3374
|
+
sendAuthToken: import_zod13.z.string().min(16)
|
|
3375
|
+
});
|
|
3376
|
+
function createMeOfflineClient(opts) {
|
|
3486
3377
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
3487
3378
|
if (!fetchImpl) {
|
|
3488
|
-
throw new Error("
|
|
3379
|
+
throw new Error("createMeOfflineClient: no fetch implementation available");
|
|
3489
3380
|
}
|
|
3490
3381
|
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
3491
3382
|
async function call(method, path, body, parser) {
|
|
@@ -3513,42 +3404,67 @@ function createAccountsClient(opts) {
|
|
|
3513
3404
|
}
|
|
3514
3405
|
return parser(raw);
|
|
3515
3406
|
}
|
|
3516
|
-
const
|
|
3517
|
-
const memberItemsSchema = import_zod13.z.object({
|
|
3518
|
-
items: import_zod13.z.array(AccountMembershipSchema)
|
|
3519
|
-
});
|
|
3407
|
+
const deviceKeyItems = import_zod13.z.object({ items: import_zod13.z.array(DeviceKeyRecordSchema) });
|
|
3520
3408
|
return {
|
|
3521
|
-
|
|
3522
|
-
"
|
|
3523
|
-
"/v1/
|
|
3524
|
-
|
|
3525
|
-
(raw) =>
|
|
3409
|
+
issueP256EnrollmentChallenge: (input) => call(
|
|
3410
|
+
"POST",
|
|
3411
|
+
"/v1/me/offline/keys/p256/challenge",
|
|
3412
|
+
P256EnrollmentChallengeInputSchema.parse(input),
|
|
3413
|
+
(raw) => P256EnrollmentChallengeResultSchema.parse(raw)
|
|
3526
3414
|
),
|
|
3527
|
-
|
|
3528
|
-
"
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
(raw) =>
|
|
3415
|
+
registerDeviceKeyP256: (input) => call(
|
|
3416
|
+
"POST",
|
|
3417
|
+
"/v1/me/offline/keys/p256",
|
|
3418
|
+
RegisterDeviceKeyP256InputSchema.parse(input),
|
|
3419
|
+
(raw) => DeviceKeyRecordSchema.parse(raw)
|
|
3532
3420
|
),
|
|
3533
|
-
|
|
3421
|
+
listDeviceKeys: () => call(
|
|
3534
3422
|
"GET",
|
|
3535
|
-
|
|
3423
|
+
"/v1/me/offline/keys",
|
|
3536
3424
|
void 0,
|
|
3537
|
-
(raw) =>
|
|
3425
|
+
(raw) => deviceKeyItems.parse(raw)
|
|
3538
3426
|
),
|
|
3539
|
-
|
|
3540
|
-
addMember: (accountId, input) => call(
|
|
3427
|
+
revokeDeviceKey: (input) => call(
|
|
3541
3428
|
"POST",
|
|
3542
|
-
|
|
3543
|
-
input,
|
|
3544
|
-
(
|
|
3429
|
+
"/v1/me/offline/keys/revoke",
|
|
3430
|
+
RevokeDeviceKeyInputSchema.parse(input),
|
|
3431
|
+
() => void 0
|
|
3432
|
+
),
|
|
3433
|
+
issueAccountOac: (input) => call(
|
|
3434
|
+
"POST",
|
|
3435
|
+
"/v1/me/offline/oac",
|
|
3436
|
+
IssueAccountOacInputSchema.parse(input),
|
|
3437
|
+
(raw) => OACRecordSchema.parse(raw)
|
|
3438
|
+
),
|
|
3439
|
+
getStatus: (deviceId) => {
|
|
3440
|
+
const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
|
|
3441
|
+
return call(
|
|
3442
|
+
"GET",
|
|
3443
|
+
`/v1/me/offline/status${qs}`,
|
|
3444
|
+
void 0,
|
|
3445
|
+
(raw) => OfflineStatusResultSchema.parse(raw)
|
|
3446
|
+
);
|
|
3447
|
+
},
|
|
3448
|
+
submitClaim: (claim) => call(
|
|
3449
|
+
"POST",
|
|
3450
|
+
"/v1/me/offline/claims",
|
|
3451
|
+
ConsumerPaymentClaimSchema.parse(claim),
|
|
3452
|
+
(raw) => ConsumerSettleResultSchema.parse(raw)
|
|
3453
|
+
),
|
|
3454
|
+
getSettlement: (idOrKey) => call(
|
|
3455
|
+
"GET",
|
|
3456
|
+
`/v1/me/offline/settlements/${encodeURIComponent(idOrKey)}`,
|
|
3457
|
+
void 0,
|
|
3458
|
+
(raw) => ConsumerSettlementSchema.parse(raw)
|
|
3545
3459
|
)
|
|
3546
3460
|
};
|
|
3547
3461
|
}
|
|
3548
3462
|
|
|
3549
3463
|
// src/me-offline/signer.ts
|
|
3550
3464
|
var import_nist2 = require("@noble/curves/nist");
|
|
3465
|
+
var import_sha2 = require("@noble/hashes/sha2");
|
|
3551
3466
|
var CLAIM_DOMAIN_V2 = "flur:consumer-offline:v2:claim";
|
|
3467
|
+
var ENCOUNTER_DOMAIN2 = "flur:consumer-offline:v1:encounter";
|
|
3552
3468
|
function canonicalClaimSigningPayload(claim) {
|
|
3553
3469
|
return {
|
|
3554
3470
|
domain: CLAIM_DOMAIN_V2,
|
|
@@ -3569,6 +3485,27 @@ function canonicalClaimSigningPayload(claim) {
|
|
|
3569
3485
|
function canonicalClaimSigningBytes(claim) {
|
|
3570
3486
|
return canonicalJSONBytes(canonicalClaimSigningPayload(claim));
|
|
3571
3487
|
}
|
|
3488
|
+
function computeConsumerClaimEncounterId(input) {
|
|
3489
|
+
const material = `${ENCOUNTER_DOMAIN2}|${[
|
|
3490
|
+
assertEncounterPart("oacId", input.oacId),
|
|
3491
|
+
assertEncounterPart("payerUserId", input.payerUserId),
|
|
3492
|
+
assertEncounterPart("payeeUserId", input.payeeUserId),
|
|
3493
|
+
assertEncounterPart("payerNonce", input.payerNonce),
|
|
3494
|
+
assertEncounterPart("payeeNonce", input.payeeNonce)
|
|
3495
|
+
].join("|")}`;
|
|
3496
|
+
return bytesToHex5((0, import_sha2.sha256)(new TextEncoder().encode(material)));
|
|
3497
|
+
}
|
|
3498
|
+
function assertEncounterPart(field, value) {
|
|
3499
|
+
if (value.includes("|")) {
|
|
3500
|
+
throw new Error(`consumer encounter id ${field} must not contain |`);
|
|
3501
|
+
}
|
|
3502
|
+
return value;
|
|
3503
|
+
}
|
|
3504
|
+
function bytesToHex5(bytes) {
|
|
3505
|
+
let out = "";
|
|
3506
|
+
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
3507
|
+
return out;
|
|
3508
|
+
}
|
|
3572
3509
|
function bytesToBase642(bytes) {
|
|
3573
3510
|
if (typeof Buffer !== "undefined") {
|
|
3574
3511
|
return Buffer.from(bytes).toString("base64");
|
|
@@ -3664,38 +3601,192 @@ function verifyClaimSignature(input) {
|
|
|
3664
3601
|
}
|
|
3665
3602
|
}
|
|
3666
3603
|
|
|
3667
|
-
// src/me-offline/
|
|
3668
|
-
var
|
|
3669
|
-
var
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3604
|
+
// src/me-offline/request.ts
|
|
3605
|
+
var import_zod14 = require("zod");
|
|
3606
|
+
var Base64Std4 = import_zod14.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
|
|
3607
|
+
var CONSUMER_PAYMENT_REQUEST_DOMAIN = "flur:consumer-offline:v1:request";
|
|
3608
|
+
var ConsumerPaymentRequestEnvelopeSchema = import_zod14.z.object({
|
|
3609
|
+
requestId: import_zod14.z.string().uuid(),
|
|
3610
|
+
mode: import_zod14.z.enum(["fixed", "editable"]),
|
|
3611
|
+
takerUserId: import_zod14.z.string().uuid(),
|
|
3612
|
+
amountKobo: import_zod14.z.number().int().positive(),
|
|
3613
|
+
currency: import_zod14.z.string().length(3).default("NGN"),
|
|
3614
|
+
reference: import_zod14.z.string().max(128).nullable().default(null),
|
|
3615
|
+
createdAtMs: import_zod14.z.number().int().nonnegative(),
|
|
3616
|
+
expiresAtMs: import_zod14.z.number().int().positive(),
|
|
3617
|
+
nonce: import_zod14.z.string().min(8).max(128),
|
|
3618
|
+
takerDeviceId: import_zod14.z.string().min(1).max(128).nullable().default(null),
|
|
3619
|
+
takerPubkeySpkiB64: Base64Std4.min(64).max(4096).optional(),
|
|
3620
|
+
takerSignatureDerB64: Base64Std4.min(16).max(2048).optional()
|
|
3621
|
+
}).superRefine((value, ctx) => {
|
|
3622
|
+
if (value.expiresAtMs <= value.createdAtMs) {
|
|
3623
|
+
ctx.addIssue({
|
|
3624
|
+
code: import_zod14.z.ZodIssueCode.custom,
|
|
3625
|
+
path: ["expiresAtMs"],
|
|
3626
|
+
message: "expiresAtMs must be greater than createdAtMs"
|
|
3627
|
+
});
|
|
3628
|
+
}
|
|
3629
|
+
const hasSignature = Boolean(
|
|
3630
|
+
value.takerPubkeySpkiB64 || value.takerSignatureDerB64
|
|
3631
|
+
);
|
|
3632
|
+
if (value.mode === "fixed" || hasSignature) {
|
|
3633
|
+
if (!value.takerDeviceId) {
|
|
3634
|
+
ctx.addIssue({
|
|
3635
|
+
code: import_zod14.z.ZodIssueCode.custom,
|
|
3636
|
+
path: ["takerDeviceId"],
|
|
3637
|
+
message: "signed requests require takerDeviceId"
|
|
3638
|
+
});
|
|
3639
|
+
}
|
|
3640
|
+
if (!value.takerPubkeySpkiB64) {
|
|
3641
|
+
ctx.addIssue({
|
|
3642
|
+
code: import_zod14.z.ZodIssueCode.custom,
|
|
3643
|
+
path: ["takerPubkeySpkiB64"],
|
|
3644
|
+
message: "signed requests require takerPubkeySpkiB64"
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3647
|
+
if (!value.takerSignatureDerB64) {
|
|
3648
|
+
ctx.addIssue({
|
|
3649
|
+
code: import_zod14.z.ZodIssueCode.custom,
|
|
3650
|
+
path: ["takerSignatureDerB64"],
|
|
3651
|
+
message: "signed requests require takerSignatureDerB64"
|
|
3652
|
+
});
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
});
|
|
3656
|
+
function buildConsumerPaymentRequest(input) {
|
|
3657
|
+
const unsigned = {
|
|
3658
|
+
requestId: input.requestId,
|
|
3659
|
+
mode: input.mode,
|
|
3660
|
+
takerUserId: input.takerUserId,
|
|
3661
|
+
amountKobo: input.amountKobo,
|
|
3662
|
+
currency: input.currency ?? "NGN",
|
|
3663
|
+
reference: input.reference ?? null,
|
|
3664
|
+
createdAtMs: input.createdAtMs,
|
|
3665
|
+
expiresAtMs: input.expiresAtMs,
|
|
3666
|
+
nonce: input.nonce,
|
|
3667
|
+
takerDeviceId: input.takerDeviceId ?? null
|
|
3668
|
+
};
|
|
3669
|
+
if (unsigned.mode === "fixed" && !unsigned.takerDeviceId) {
|
|
3670
|
+
throw new Error("fixed requests require takerDeviceId");
|
|
3671
|
+
}
|
|
3672
|
+
if (unsigned.expiresAtMs <= unsigned.createdAtMs) {
|
|
3673
|
+
throw new Error("expiresAtMs must be greater than createdAtMs");
|
|
3674
|
+
}
|
|
3675
|
+
return unsigned;
|
|
3674
3676
|
}
|
|
3675
|
-
function
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3677
|
+
function consumerPaymentRequestSigningPayload(request) {
|
|
3678
|
+
return {
|
|
3679
|
+
domain: CONSUMER_PAYMENT_REQUEST_DOMAIN,
|
|
3680
|
+
version: 1,
|
|
3681
|
+
requestId: request.requestId,
|
|
3682
|
+
mode: request.mode,
|
|
3683
|
+
takerUserId: request.takerUserId,
|
|
3684
|
+
amountKobo: request.amountKobo,
|
|
3685
|
+
currency: request.currency,
|
|
3686
|
+
reference: request.reference ?? null,
|
|
3687
|
+
createdAtMs: request.createdAtMs,
|
|
3688
|
+
expiresAtMs: request.expiresAtMs,
|
|
3689
|
+
nonce: request.nonce,
|
|
3690
|
+
takerDeviceId: request.takerDeviceId ?? null
|
|
3691
|
+
};
|
|
3692
|
+
}
|
|
3693
|
+
function consumerPaymentRequestSigningBytes(request) {
|
|
3694
|
+
return canonicalJSONBytes(consumerPaymentRequestSigningPayload(request));
|
|
3695
|
+
}
|
|
3696
|
+
async function signConsumerPaymentRequest(unsigned, signer) {
|
|
3697
|
+
if (signer.alg !== "p256") {
|
|
3698
|
+
throw new Error("consumer payment requests require p256 signer");
|
|
3679
3699
|
}
|
|
3680
|
-
const
|
|
3700
|
+
const publicKey = await signer.getPublicKey();
|
|
3701
|
+
if (publicKey.alg !== "p256") {
|
|
3702
|
+
throw new Error("consumer payment requests require p256 public key");
|
|
3703
|
+
}
|
|
3704
|
+
const signature = await signer.sign(
|
|
3705
|
+
consumerPaymentRequestSigningBytes(unsigned)
|
|
3706
|
+
);
|
|
3707
|
+
return ConsumerPaymentRequestEnvelopeSchema.parse({
|
|
3708
|
+
...unsigned,
|
|
3709
|
+
takerPubkeySpkiB64: publicKey.publicKey,
|
|
3710
|
+
takerSignatureDerB64: signature.signature
|
|
3711
|
+
});
|
|
3712
|
+
}
|
|
3713
|
+
function verifyConsumerPaymentRequest(request) {
|
|
3714
|
+
const parsed = ConsumerPaymentRequestEnvelopeSchema.safeParse(request);
|
|
3715
|
+
if (!parsed.success) return false;
|
|
3716
|
+
const value = parsed.data;
|
|
3717
|
+
if (!value.takerPubkeySpkiB64 || !value.takerSignatureDerB64) return false;
|
|
3718
|
+
return verifyClaimSignature({
|
|
3719
|
+
alg: "p256",
|
|
3720
|
+
bytes: consumerPaymentRequestSigningBytes(value),
|
|
3721
|
+
signature: value.takerSignatureDerB64,
|
|
3722
|
+
publicKey: value.takerPubkeySpkiB64
|
|
3723
|
+
});
|
|
3724
|
+
}
|
|
3725
|
+
function isConsumerPaymentRequestExpired(request, nowMs = Date.now()) {
|
|
3726
|
+
const parsed = ConsumerPaymentRequestEnvelopeSchema.parse(request);
|
|
3727
|
+
return parsed.expiresAtMs <= nowMs;
|
|
3728
|
+
}
|
|
3729
|
+
|
|
3730
|
+
// src/me-offline/settlement.ts
|
|
3731
|
+
var CONSUMER_SETTLEMENT_DOMAIN = "flur:consumer-offline:v1:settlement";
|
|
3732
|
+
var CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX = "FLURSR1.";
|
|
3733
|
+
function consumerSettlementSigningPayload(settlement) {
|
|
3734
|
+
return {
|
|
3735
|
+
domain: CONSUMER_SETTLEMENT_DOMAIN,
|
|
3736
|
+
settlementId: settlement.settlementId,
|
|
3737
|
+
settlementKey: settlement.settlementKey,
|
|
3738
|
+
encounterId: settlement.encounterId,
|
|
3739
|
+
oacId: settlement.oacId,
|
|
3740
|
+
payerUserId: settlement.payerUserId,
|
|
3741
|
+
payeeUserId: settlement.payeeUserId,
|
|
3742
|
+
amountKobo: settlement.amountKobo,
|
|
3743
|
+
currency: settlement.currency,
|
|
3744
|
+
status: settlement.status,
|
|
3745
|
+
reviewReason: settlement.reviewReason,
|
|
3746
|
+
ledgerRef: settlement.ledgerRef,
|
|
3747
|
+
issuedAtMs: settlement.issuedAtMs
|
|
3748
|
+
};
|
|
3749
|
+
}
|
|
3750
|
+
function verifyConsumerSettlement(settlement, issuerPublicKeySpkiB64) {
|
|
3751
|
+
const parsed = ConsumerSettlementSchema.safeParse(settlement);
|
|
3752
|
+
if (!parsed.success) return false;
|
|
3753
|
+
return verifyIssuerP256(
|
|
3754
|
+
canonicalJSONBytes(consumerSettlementSigningPayload(parsed.data)),
|
|
3755
|
+
parsed.data.issuerSig,
|
|
3756
|
+
issuerPublicKeySpkiB64
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
function encodeConsumerSettlementReceiptQR(settlement) {
|
|
3760
|
+
const parsed = ConsumerSettlementSchema.parse(settlement);
|
|
3761
|
+
return `${CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX}${base64UrlEncodeUtf8(
|
|
3762
|
+
JSON.stringify(parsed)
|
|
3763
|
+
)}`;
|
|
3764
|
+
}
|
|
3765
|
+
function decodeUnverifiedConsumerSettlementReceiptQR(value) {
|
|
3766
|
+
if (!value.startsWith(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX)) {
|
|
3767
|
+
throw new Error("not a Flur consumer settlement receipt QR");
|
|
3768
|
+
}
|
|
3769
|
+
const encoded = value.slice(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX.length);
|
|
3681
3770
|
let raw;
|
|
3682
3771
|
try {
|
|
3683
3772
|
raw = JSON.parse(base64UrlDecodeUtf8(encoded));
|
|
3684
3773
|
} catch {
|
|
3685
|
-
throw new Error("
|
|
3774
|
+
throw new Error("consumer settlement receipt QR is malformed");
|
|
3686
3775
|
}
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3776
|
+
return ConsumerSettlementSchema.parse(raw);
|
|
3777
|
+
}
|
|
3778
|
+
function verifyConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64) {
|
|
3779
|
+
const settlement = decodeUnverifiedConsumerSettlementReceiptQR(value);
|
|
3780
|
+
if (!verifyConsumerSettlement(settlement, issuerPublicKeySpkiB64)) {
|
|
3781
|
+
throw new Error("consumer settlement receipt QR signature invalid");
|
|
3690
3782
|
}
|
|
3691
|
-
return
|
|
3783
|
+
return settlement;
|
|
3692
3784
|
}
|
|
3693
|
-
function
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
return trimmed.split(/\s+/, 1)[0] ?? null;
|
|
3785
|
+
function decodeConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64) {
|
|
3786
|
+
if (!issuerPublicKeySpkiB64) {
|
|
3787
|
+
return decodeUnverifiedConsumerSettlementReceiptQR(value);
|
|
3697
3788
|
}
|
|
3698
|
-
return
|
|
3789
|
+
return verifyConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64);
|
|
3699
3790
|
}
|
|
3700
3791
|
function base64UrlEncodeUtf8(input) {
|
|
3701
3792
|
const bytes = new TextEncoder().encode(input);
|
|
@@ -3725,15 +3816,281 @@ function base64UrlDecodeUtf8(input) {
|
|
|
3725
3816
|
throw new Error("base64 decoder unavailable");
|
|
3726
3817
|
}
|
|
3727
3818
|
|
|
3819
|
+
// src/me-offline/sms.ts
|
|
3820
|
+
var import_nist3 = require("@noble/curves/nist");
|
|
3821
|
+
var OFFLINE_CLAIM_SMS_PREFIX = "FLURC1.";
|
|
3822
|
+
var CLAIM_TOKEN_RE = /(?:^|\s)(FLURC1\.[A-Za-z0-9_-]+={0,2})(?:\s|$)/;
|
|
3823
|
+
function encodeOfflineClaimSmsMessage(claim) {
|
|
3824
|
+
const parsed = ConsumerPaymentClaimSchema.parse(claim);
|
|
3825
|
+
return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf82(
|
|
3826
|
+
JSON.stringify(parsed)
|
|
3827
|
+
)}`;
|
|
3828
|
+
}
|
|
3829
|
+
function decodeOfflineClaimSmsMessage(message) {
|
|
3830
|
+
const token = extractOfflineClaimSmsToken(message);
|
|
3831
|
+
if (!token) throw new Error("offline claim QR token not found");
|
|
3832
|
+
const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);
|
|
3833
|
+
let raw;
|
|
3834
|
+
try {
|
|
3835
|
+
raw = JSON.parse(base64UrlDecodeUtf82(encoded));
|
|
3836
|
+
} catch {
|
|
3837
|
+
throw new Error("offline claim QR token is malformed");
|
|
3838
|
+
}
|
|
3839
|
+
const parsed = ConsumerPaymentClaimSchema.safeParse(raw);
|
|
3840
|
+
if (!parsed.success) throw new Error("offline claim QR token is invalid");
|
|
3841
|
+
return parsed.data;
|
|
3842
|
+
}
|
|
3843
|
+
function extractOfflineClaimSmsToken(message) {
|
|
3844
|
+
const trimmed = message.trim();
|
|
3845
|
+
if (trimmed.startsWith(OFFLINE_CLAIM_SMS_PREFIX)) {
|
|
3846
|
+
return trimmed.split(/\s+/, 1)[0] ?? null;
|
|
3847
|
+
}
|
|
3848
|
+
return CLAIM_TOKEN_RE.exec(message)?.[1] ?? null;
|
|
3849
|
+
}
|
|
3850
|
+
var OFFLINE_SMS_SETTLE_PREFIX = "FLURA1.";
|
|
3851
|
+
var OFFLINE_SMS_SETTLE_DOMAIN = "flur:consumer-offline:v1:attest";
|
|
3852
|
+
var OFFLINE_SMS_SETTLE_TOKEN_BYTES = 112;
|
|
3853
|
+
var OFFLINE_SMS_SETTLE_HEADER_BYTES = 48;
|
|
3854
|
+
var OFFLINE_SMS_SETTLE_SIGNATURE_BYTES = 64;
|
|
3855
|
+
var OFFLINE_SMS_SETTLE_VERSION = 1;
|
|
3856
|
+
var TOKEN_RE = /(?:^|[\s,;:()<>"'])(FLURA1\.[A-Za-z0-9_-]{150})/;
|
|
3857
|
+
async function encodeOfflineSmsSettleToken(input, signer) {
|
|
3858
|
+
const header = await buildSmsSettleHeader(input);
|
|
3859
|
+
const sig = await signer.signRaw(domainTag(header));
|
|
3860
|
+
if (sig.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {
|
|
3861
|
+
throw new Error(
|
|
3862
|
+
`FLURA1: signer returned ${sig.length}-byte sig; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`
|
|
3863
|
+
);
|
|
3864
|
+
}
|
|
3865
|
+
const out = new Uint8Array(OFFLINE_SMS_SETTLE_TOKEN_BYTES);
|
|
3866
|
+
out.set(header, 0);
|
|
3867
|
+
out.set(sig, OFFLINE_SMS_SETTLE_HEADER_BYTES);
|
|
3868
|
+
return `${OFFLINE_SMS_SETTLE_PREFIX}${bytesToBase64Url(out)}`;
|
|
3869
|
+
}
|
|
3870
|
+
async function buildSmsSettleHeader(input) {
|
|
3871
|
+
assertSafeUint64(input.amountKobo, "amountKobo");
|
|
3872
|
+
if (input.amountKobo <= 0) {
|
|
3873
|
+
throw new Error("FLURA1: amountKobo must be greater than zero");
|
|
3874
|
+
}
|
|
3875
|
+
assertSafeUint48(input.occurredAtMs, "occurredAtMs");
|
|
3876
|
+
const encounterPrefix = (await sha2565(utf8(input.encounterId))).slice(0, 16);
|
|
3877
|
+
const payerPrefix = uuidToBytes(input.payerUserId).slice(0, 8);
|
|
3878
|
+
const payeePrefix = uuidToBytes(input.payeeUserId).slice(0, 8);
|
|
3879
|
+
const header = new Uint8Array(OFFLINE_SMS_SETTLE_HEADER_BYTES);
|
|
3880
|
+
const dv = new DataView(header.buffer);
|
|
3881
|
+
header[0] = OFFLINE_SMS_SETTLE_VERSION;
|
|
3882
|
+
header[1] = 0;
|
|
3883
|
+
header.set(encounterPrefix, 2);
|
|
3884
|
+
header.set(payerPrefix, 18);
|
|
3885
|
+
header.set(payeePrefix, 26);
|
|
3886
|
+
writeUint64BE(dv, 34, input.amountKobo);
|
|
3887
|
+
writeUint48BE(dv, 42, input.occurredAtMs);
|
|
3888
|
+
return header;
|
|
3889
|
+
}
|
|
3890
|
+
function domainTag(header) {
|
|
3891
|
+
if (header.length !== OFFLINE_SMS_SETTLE_HEADER_BYTES) {
|
|
3892
|
+
throw new Error(
|
|
3893
|
+
`FLURA1: header must be ${OFFLINE_SMS_SETTLE_HEADER_BYTES} bytes`
|
|
3894
|
+
);
|
|
3895
|
+
}
|
|
3896
|
+
const domain = utf8(OFFLINE_SMS_SETTLE_DOMAIN);
|
|
3897
|
+
const out = new Uint8Array(domain.length + header.length);
|
|
3898
|
+
out.set(domain, 0);
|
|
3899
|
+
out.set(header, domain.length);
|
|
3900
|
+
return out;
|
|
3901
|
+
}
|
|
3902
|
+
function decodeOfflineSmsSettleToken(message) {
|
|
3903
|
+
const token = extractOfflineSmsSettleToken(message);
|
|
3904
|
+
if (!token) throw new Error("FLURA1: token not found");
|
|
3905
|
+
const encoded = token.slice(OFFLINE_SMS_SETTLE_PREFIX.length);
|
|
3906
|
+
let bytes;
|
|
3907
|
+
try {
|
|
3908
|
+
bytes = base64UrlToBytes(encoded);
|
|
3909
|
+
} catch {
|
|
3910
|
+
throw new Error("FLURA1: token base64url is malformed");
|
|
3911
|
+
}
|
|
3912
|
+
if (bytesToBase64Url(bytes) !== encoded) {
|
|
3913
|
+
throw new Error("FLURA1: token base64url is malformed");
|
|
3914
|
+
}
|
|
3915
|
+
if (bytes.length !== OFFLINE_SMS_SETTLE_TOKEN_BYTES) {
|
|
3916
|
+
throw new Error(
|
|
3917
|
+
`FLURA1: expected ${OFFLINE_SMS_SETTLE_TOKEN_BYTES} bytes, got ${bytes.length}`
|
|
3918
|
+
);
|
|
3919
|
+
}
|
|
3920
|
+
const version = bytes[0];
|
|
3921
|
+
const flags = bytes[1];
|
|
3922
|
+
if (version !== OFFLINE_SMS_SETTLE_VERSION) {
|
|
3923
|
+
throw new Error(`FLURA1: unsupported version ${version}`);
|
|
3924
|
+
}
|
|
3925
|
+
if (flags !== 0) {
|
|
3926
|
+
throw new Error(`FLURA1: reserved flags must be 0, got ${flags}`);
|
|
3927
|
+
}
|
|
3928
|
+
const header = bytes.slice(0, OFFLINE_SMS_SETTLE_HEADER_BYTES);
|
|
3929
|
+
const signature = bytes.slice(OFFLINE_SMS_SETTLE_HEADER_BYTES);
|
|
3930
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
3931
|
+
const amountKobo = readUint64BE(dv, 34);
|
|
3932
|
+
if (amountKobo <= 0) {
|
|
3933
|
+
throw new Error("FLURA1: amountKobo must be greater than zero");
|
|
3934
|
+
}
|
|
3935
|
+
return {
|
|
3936
|
+
version,
|
|
3937
|
+
flags,
|
|
3938
|
+
encounterIdPrefixHex: bytesToHex6(bytes.slice(2, 18)),
|
|
3939
|
+
payerUserIdPrefixHex: bytesToHex6(bytes.slice(18, 26)),
|
|
3940
|
+
payeeUserIdPrefixHex: bytesToHex6(bytes.slice(26, 34)),
|
|
3941
|
+
amountKobo,
|
|
3942
|
+
occurredAtMs: readUint48BE(dv, 42),
|
|
3943
|
+
signature,
|
|
3944
|
+
header,
|
|
3945
|
+
signedBytes: domainTag(header)
|
|
3946
|
+
};
|
|
3947
|
+
}
|
|
3948
|
+
function extractOfflineSmsSettleToken(message) {
|
|
3949
|
+
const trimmed = message.trim();
|
|
3950
|
+
if (trimmed.startsWith(OFFLINE_SMS_SETTLE_PREFIX)) {
|
|
3951
|
+
return trimmed.split(/\s+/, 1)[0] ?? null;
|
|
3952
|
+
}
|
|
3953
|
+
return TOKEN_RE.exec(message)?.[1] ?? null;
|
|
3954
|
+
}
|
|
3955
|
+
function verifyOfflineSmsSettleToken(decoded, payerPubkeySpkiB64) {
|
|
3956
|
+
try {
|
|
3957
|
+
const pubRaw = p256SpkiB64ToRaw(payerPubkeySpkiB64);
|
|
3958
|
+
return import_nist3.p256.verify(decoded.signature, decoded.signedBytes, pubRaw, {
|
|
3959
|
+
prehash: true,
|
|
3960
|
+
format: "compact"
|
|
3961
|
+
});
|
|
3962
|
+
} catch {
|
|
3963
|
+
return false;
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
function derToRawP256Signature(derBytes) {
|
|
3967
|
+
const sig = import_nist3.p256.Signature.fromBytes(derBytes, "der");
|
|
3968
|
+
const raw = sig.toBytes("compact");
|
|
3969
|
+
if (raw.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {
|
|
3970
|
+
throw new Error(
|
|
3971
|
+
`FLURA1: DER\u2192raw produced ${raw.length} bytes; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`
|
|
3972
|
+
);
|
|
3973
|
+
}
|
|
3974
|
+
return raw;
|
|
3975
|
+
}
|
|
3976
|
+
function utf8(s) {
|
|
3977
|
+
return new TextEncoder().encode(s);
|
|
3978
|
+
}
|
|
3979
|
+
async function sha2565(bytes) {
|
|
3980
|
+
const subtle = typeof globalThis !== "undefined" && globalThis.crypto?.subtle || void 0;
|
|
3981
|
+
if (subtle) {
|
|
3982
|
+
const digest = await subtle.digest("SHA-256", bytes);
|
|
3983
|
+
return new Uint8Array(digest);
|
|
3984
|
+
}
|
|
3985
|
+
const { sha256: nobleSha256 } = await import("@noble/hashes/sha2");
|
|
3986
|
+
return nobleSha256(bytes);
|
|
3987
|
+
}
|
|
3988
|
+
function uuidToBytes(uuid) {
|
|
3989
|
+
const hex = uuid.replace(/-/g, "").toLowerCase();
|
|
3990
|
+
if (hex.length !== 32 || !/^[0-9a-f]{32}$/.test(hex)) {
|
|
3991
|
+
throw new Error(`FLURA1: invalid UUID: ${uuid}`);
|
|
3992
|
+
}
|
|
3993
|
+
const out = new Uint8Array(16);
|
|
3994
|
+
for (let i = 0; i < 16; i++) {
|
|
3995
|
+
out[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
3996
|
+
}
|
|
3997
|
+
return out;
|
|
3998
|
+
}
|
|
3999
|
+
function assertSafeUint64(value, field) {
|
|
4000
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
4001
|
+
throw new Error(`FLURA1: ${field} must be a non-negative integer`);
|
|
4002
|
+
}
|
|
4003
|
+
if (value > Number.MAX_SAFE_INTEGER) {
|
|
4004
|
+
throw new Error(`FLURA1: ${field} exceeds Number.MAX_SAFE_INTEGER`);
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
function assertSafeUint48(value, field) {
|
|
4008
|
+
assertSafeUint64(value, field);
|
|
4009
|
+
if (value > 281474976710655) {
|
|
4010
|
+
throw new Error(`FLURA1: ${field} exceeds uint48 range`);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
function writeUint64BE(dv, offset, value) {
|
|
4014
|
+
const high = Math.floor(value / 4294967296);
|
|
4015
|
+
const low = value >>> 0;
|
|
4016
|
+
dv.setUint32(offset, high, false);
|
|
4017
|
+
dv.setUint32(offset + 4, low, false);
|
|
4018
|
+
}
|
|
4019
|
+
function readUint64BE(dv, offset) {
|
|
4020
|
+
const high = dv.getUint32(offset, false);
|
|
4021
|
+
const low = dv.getUint32(offset + 4, false);
|
|
4022
|
+
if (high > 2097151) {
|
|
4023
|
+
throw new Error("FLURA1: amountKobo exceeds Number.MAX_SAFE_INTEGER");
|
|
4024
|
+
}
|
|
4025
|
+
return high * 4294967296 + low;
|
|
4026
|
+
}
|
|
4027
|
+
function writeUint48BE(dv, offset, value) {
|
|
4028
|
+
const high = Math.floor(value / 65536);
|
|
4029
|
+
const low = value & 65535;
|
|
4030
|
+
dv.setUint32(offset, high, false);
|
|
4031
|
+
dv.setUint16(offset + 4, low, false);
|
|
4032
|
+
}
|
|
4033
|
+
function readUint48BE(dv, offset) {
|
|
4034
|
+
const high = dv.getUint32(offset, false);
|
|
4035
|
+
const low = dv.getUint16(offset + 4, false);
|
|
4036
|
+
return high * 65536 + low;
|
|
4037
|
+
}
|
|
4038
|
+
function bytesToHex6(bytes) {
|
|
4039
|
+
let out = "";
|
|
4040
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
4041
|
+
out += bytes[i].toString(16).padStart(2, "0");
|
|
4042
|
+
}
|
|
4043
|
+
return out;
|
|
4044
|
+
}
|
|
4045
|
+
function bytesToBase64Url(bytes) {
|
|
4046
|
+
let base64;
|
|
4047
|
+
if (typeof Buffer !== "undefined") {
|
|
4048
|
+
base64 = Buffer.from(bytes).toString("base64");
|
|
4049
|
+
} else {
|
|
4050
|
+
let binary = "";
|
|
4051
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
4052
|
+
binary += String.fromCharCode(bytes[i]);
|
|
4053
|
+
}
|
|
4054
|
+
if (typeof btoa !== "function") {
|
|
4055
|
+
throw new Error("FLURA1: base64 encoder unavailable");
|
|
4056
|
+
}
|
|
4057
|
+
base64 = btoa(binary);
|
|
4058
|
+
}
|
|
4059
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
4060
|
+
}
|
|
4061
|
+
function base64UrlEncodeUtf82(input) {
|
|
4062
|
+
return bytesToBase64Url(utf8(input));
|
|
4063
|
+
}
|
|
4064
|
+
function base64UrlDecodeUtf82(input) {
|
|
4065
|
+
return new TextDecoder().decode(base64UrlToBytes(input));
|
|
4066
|
+
}
|
|
4067
|
+
function base64UrlToBytes(input) {
|
|
4068
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
4069
|
+
const padded = base64.padEnd(
|
|
4070
|
+
base64.length + (4 - base64.length % 4) % 4,
|
|
4071
|
+
"="
|
|
4072
|
+
);
|
|
4073
|
+
if (typeof Buffer !== "undefined") {
|
|
4074
|
+
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
4075
|
+
}
|
|
4076
|
+
if (typeof atob !== "function") {
|
|
4077
|
+
throw new Error("FLURA1: base64 decoder unavailable");
|
|
4078
|
+
}
|
|
4079
|
+
const binary = atob(padded);
|
|
4080
|
+
const out = new Uint8Array(binary.length);
|
|
4081
|
+
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
4082
|
+
return out;
|
|
4083
|
+
}
|
|
4084
|
+
|
|
3728
4085
|
// src/partner-funding/client.ts
|
|
3729
|
-
var
|
|
3730
|
-
var MinorString =
|
|
3731
|
-
var PositiveMinor =
|
|
3732
|
-
|
|
3733
|
-
|
|
4086
|
+
var import_zod15 = require("zod");
|
|
4087
|
+
var MinorString = import_zod15.z.string().regex(/^-?\d+$/);
|
|
4088
|
+
var PositiveMinor = import_zod15.z.union([
|
|
4089
|
+
import_zod15.z.number().int().positive(),
|
|
4090
|
+
import_zod15.z.string().regex(/^[1-9]\d{0,18}$/)
|
|
3734
4091
|
]);
|
|
3735
|
-
var Currency =
|
|
3736
|
-
var Metadata =
|
|
4092
|
+
var Currency = import_zod15.z.string().trim().length(3).transform((v) => v.toUpperCase());
|
|
4093
|
+
var Metadata = import_zod15.z.record(import_zod15.z.unknown());
|
|
3737
4094
|
var PARTNER_KINDS = ["bank", "merchant"];
|
|
3738
4095
|
var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
|
|
3739
4096
|
var PARTNER_PROFILE_STATUSES = [
|
|
@@ -3760,126 +4117,126 @@ var WITHDRAWAL_STATES = [
|
|
|
3760
4117
|
"failed",
|
|
3761
4118
|
"reversed"
|
|
3762
4119
|
];
|
|
3763
|
-
var PartnerProfileSchema =
|
|
3764
|
-
partnerAccountId:
|
|
3765
|
-
kind:
|
|
3766
|
-
custodialMode:
|
|
3767
|
-
displayName:
|
|
3768
|
-
bankCode:
|
|
3769
|
-
poolAccountNumber:
|
|
3770
|
-
status:
|
|
4120
|
+
var PartnerProfileSchema = import_zod15.z.object({
|
|
4121
|
+
partnerAccountId: import_zod15.z.string().uuid(),
|
|
4122
|
+
kind: import_zod15.z.enum(PARTNER_KINDS),
|
|
4123
|
+
custodialMode: import_zod15.z.enum(CUSTODIAL_MODES),
|
|
4124
|
+
displayName: import_zod15.z.string(),
|
|
4125
|
+
bankCode: import_zod15.z.string().nullable(),
|
|
4126
|
+
poolAccountNumber: import_zod15.z.string().nullable(),
|
|
4127
|
+
status: import_zod15.z.enum(PARTNER_PROFILE_STATUSES),
|
|
3771
4128
|
metadata: Metadata,
|
|
3772
|
-
createdAtMs:
|
|
3773
|
-
updatedAtMs:
|
|
4129
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4130
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3774
4131
|
});
|
|
3775
|
-
var UpsertPartnerProfileInputSchema =
|
|
3776
|
-
kind:
|
|
3777
|
-
custodialMode:
|
|
3778
|
-
displayName:
|
|
3779
|
-
bankCode:
|
|
3780
|
-
poolAccountNumber:
|
|
4132
|
+
var UpsertPartnerProfileInputSchema = import_zod15.z.object({
|
|
4133
|
+
kind: import_zod15.z.enum(PARTNER_KINDS),
|
|
4134
|
+
custodialMode: import_zod15.z.enum(CUSTODIAL_MODES),
|
|
4135
|
+
displayName: import_zod15.z.string().trim().min(1).max(200),
|
|
4136
|
+
bankCode: import_zod15.z.string().trim().min(1).max(64).optional(),
|
|
4137
|
+
poolAccountNumber: import_zod15.z.string().trim().min(1).max(64).optional(),
|
|
3781
4138
|
metadata: Metadata.optional()
|
|
3782
4139
|
});
|
|
3783
|
-
var PartnerFundingEventInputSchema =
|
|
3784
|
-
externalRef:
|
|
3785
|
-
direction:
|
|
3786
|
-
userId:
|
|
3787
|
-
accountId:
|
|
4140
|
+
var PartnerFundingEventInputSchema = import_zod15.z.object({
|
|
4141
|
+
externalRef: import_zod15.z.string().trim().min(8).max(128),
|
|
4142
|
+
direction: import_zod15.z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
|
|
4143
|
+
userId: import_zod15.z.string().uuid().optional(),
|
|
4144
|
+
accountId: import_zod15.z.string().uuid().optional(),
|
|
3788
4145
|
amountMinor: PositiveMinor,
|
|
3789
4146
|
currency: Currency,
|
|
3790
|
-
fundingSource:
|
|
4147
|
+
fundingSource: import_zod15.z.string().trim().min(1).max(64).optional(),
|
|
3791
4148
|
providerMetadata: Metadata.optional()
|
|
3792
4149
|
});
|
|
3793
|
-
var PartnerFundingSchema =
|
|
3794
|
-
fundingId:
|
|
3795
|
-
partnerId:
|
|
3796
|
-
accountId:
|
|
3797
|
-
userId:
|
|
3798
|
-
direction:
|
|
3799
|
-
currency:
|
|
4150
|
+
var PartnerFundingSchema = import_zod15.z.object({
|
|
4151
|
+
fundingId: import_zod15.z.string().uuid(),
|
|
4152
|
+
partnerId: import_zod15.z.string().uuid(),
|
|
4153
|
+
accountId: import_zod15.z.string().uuid(),
|
|
4154
|
+
userId: import_zod15.z.string().uuid().nullable(),
|
|
4155
|
+
direction: import_zod15.z.enum(PARTNER_FUNDING_DIRECTIONS),
|
|
4156
|
+
currency: import_zod15.z.string(),
|
|
3800
4157
|
amountMinor: MinorString,
|
|
3801
|
-
externalRef:
|
|
3802
|
-
status:
|
|
3803
|
-
fundingSource:
|
|
3804
|
-
ledgerRef:
|
|
4158
|
+
externalRef: import_zod15.z.string(),
|
|
4159
|
+
status: import_zod15.z.enum(PARTNER_FUNDING_STATUSES),
|
|
4160
|
+
fundingSource: import_zod15.z.string(),
|
|
4161
|
+
ledgerRef: import_zod15.z.string(),
|
|
3805
4162
|
providerMetadata: Metadata,
|
|
3806
|
-
createdAtMs:
|
|
3807
|
-
updatedAtMs:
|
|
4163
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4164
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3808
4165
|
});
|
|
3809
|
-
var IngestFundingResultSchema =
|
|
4166
|
+
var IngestFundingResultSchema = import_zod15.z.object({
|
|
3810
4167
|
funding: PartnerFundingSchema,
|
|
3811
|
-
replayed:
|
|
4168
|
+
replayed: import_zod15.z.boolean()
|
|
3812
4169
|
});
|
|
3813
|
-
var PayoutDestinationSchema =
|
|
3814
|
-
destinationId:
|
|
3815
|
-
accountId:
|
|
3816
|
-
partnerId:
|
|
3817
|
-
bankCode:
|
|
3818
|
-
accountNumber:
|
|
3819
|
-
accountName:
|
|
3820
|
-
status:
|
|
3821
|
-
verifiedAtMs:
|
|
4170
|
+
var PayoutDestinationSchema = import_zod15.z.object({
|
|
4171
|
+
destinationId: import_zod15.z.string().uuid(),
|
|
4172
|
+
accountId: import_zod15.z.string().uuid(),
|
|
4173
|
+
partnerId: import_zod15.z.string().uuid(),
|
|
4174
|
+
bankCode: import_zod15.z.string(),
|
|
4175
|
+
accountNumber: import_zod15.z.string(),
|
|
4176
|
+
accountName: import_zod15.z.string(),
|
|
4177
|
+
status: import_zod15.z.enum(PAYOUT_DESTINATION_STATUSES),
|
|
4178
|
+
verifiedAtMs: import_zod15.z.number().int().nonnegative().nullable(),
|
|
3822
4179
|
metadata: Metadata,
|
|
3823
|
-
createdAtMs:
|
|
3824
|
-
updatedAtMs:
|
|
4180
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4181
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3825
4182
|
});
|
|
3826
|
-
var CreatePayoutDestinationInputSchema =
|
|
3827
|
-
partnerId:
|
|
3828
|
-
bankCode:
|
|
3829
|
-
accountNumber:
|
|
3830
|
-
accountName:
|
|
4183
|
+
var CreatePayoutDestinationInputSchema = import_zod15.z.object({
|
|
4184
|
+
partnerId: import_zod15.z.string().uuid(),
|
|
4185
|
+
bankCode: import_zod15.z.string().trim().min(1).max(32),
|
|
4186
|
+
accountNumber: import_zod15.z.string().trim().min(4).max(64),
|
|
4187
|
+
accountName: import_zod15.z.string().trim().min(1).max(200),
|
|
3831
4188
|
metadata: Metadata.optional()
|
|
3832
4189
|
});
|
|
3833
|
-
var ListPayoutDestinationsResultSchema =
|
|
3834
|
-
items:
|
|
4190
|
+
var ListPayoutDestinationsResultSchema = import_zod15.z.object({
|
|
4191
|
+
items: import_zod15.z.array(PayoutDestinationSchema)
|
|
3835
4192
|
});
|
|
3836
|
-
var WithdrawalSchema =
|
|
3837
|
-
withdrawalId:
|
|
3838
|
-
accountId:
|
|
3839
|
-
userId:
|
|
3840
|
-
partnerId:
|
|
3841
|
-
destinationId:
|
|
3842
|
-
currency:
|
|
4193
|
+
var WithdrawalSchema = import_zod15.z.object({
|
|
4194
|
+
withdrawalId: import_zod15.z.string().uuid(),
|
|
4195
|
+
accountId: import_zod15.z.string().uuid(),
|
|
4196
|
+
userId: import_zod15.z.string().uuid(),
|
|
4197
|
+
partnerId: import_zod15.z.string().uuid(),
|
|
4198
|
+
destinationId: import_zod15.z.string().uuid(),
|
|
4199
|
+
currency: import_zod15.z.string(),
|
|
3843
4200
|
amountMinor: MinorString,
|
|
3844
|
-
state:
|
|
3845
|
-
idempotencyKey:
|
|
3846
|
-
providerRef:
|
|
3847
|
-
lastError:
|
|
3848
|
-
ledgerRef:
|
|
3849
|
-
reverseLedgerRef:
|
|
4201
|
+
state: import_zod15.z.enum(WITHDRAWAL_STATES),
|
|
4202
|
+
idempotencyKey: import_zod15.z.string(),
|
|
4203
|
+
providerRef: import_zod15.z.string().nullable(),
|
|
4204
|
+
lastError: import_zod15.z.string().nullable(),
|
|
4205
|
+
ledgerRef: import_zod15.z.string(),
|
|
4206
|
+
reverseLedgerRef: import_zod15.z.string().nullable(),
|
|
3850
4207
|
metadata: Metadata,
|
|
3851
|
-
createdAtMs:
|
|
3852
|
-
updatedAtMs:
|
|
4208
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4209
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3853
4210
|
});
|
|
3854
|
-
var CreateWithdrawalInputSchema =
|
|
3855
|
-
destinationId:
|
|
4211
|
+
var CreateWithdrawalInputSchema = import_zod15.z.object({
|
|
4212
|
+
destinationId: import_zod15.z.string().uuid(),
|
|
3856
4213
|
amountMinor: PositiveMinor,
|
|
3857
4214
|
currency: Currency,
|
|
3858
|
-
idempotencyKey:
|
|
4215
|
+
idempotencyKey: import_zod15.z.string().trim().min(8).max(128),
|
|
3859
4216
|
metadata: Metadata.optional()
|
|
3860
4217
|
});
|
|
3861
|
-
var CreateWithdrawalResultSchema =
|
|
4218
|
+
var CreateWithdrawalResultSchema = import_zod15.z.object({
|
|
3862
4219
|
withdrawal: WithdrawalSchema,
|
|
3863
|
-
replayed:
|
|
4220
|
+
replayed: import_zod15.z.boolean()
|
|
3864
4221
|
});
|
|
3865
|
-
var PayoutEventInputSchema =
|
|
3866
|
-
externalRef:
|
|
3867
|
-
withdrawalId:
|
|
3868
|
-
state:
|
|
3869
|
-
providerRef:
|
|
3870
|
-
failureCode:
|
|
3871
|
-
failureMessage:
|
|
4222
|
+
var PayoutEventInputSchema = import_zod15.z.object({
|
|
4223
|
+
externalRef: import_zod15.z.string().trim().min(8).max(128),
|
|
4224
|
+
withdrawalId: import_zod15.z.string().uuid().optional(),
|
|
4225
|
+
state: import_zod15.z.enum(["submitted", "processing", "paid", "failed"]),
|
|
4226
|
+
providerRef: import_zod15.z.string().trim().min(1).max(128).optional(),
|
|
4227
|
+
failureCode: import_zod15.z.string().trim().max(64).optional(),
|
|
4228
|
+
failureMessage: import_zod15.z.string().trim().max(512).optional(),
|
|
3872
4229
|
providerMetadata: Metadata.optional()
|
|
3873
4230
|
});
|
|
3874
|
-
var RecordPayoutEventResultSchema =
|
|
4231
|
+
var RecordPayoutEventResultSchema = import_zod15.z.object({
|
|
3875
4232
|
withdrawal: WithdrawalSchema,
|
|
3876
|
-
replayed:
|
|
4233
|
+
replayed: import_zod15.z.boolean()
|
|
3877
4234
|
});
|
|
3878
|
-
var ReconciliationReportSchema =
|
|
3879
|
-
partnerId:
|
|
3880
|
-
currency:
|
|
3881
|
-
fromMs:
|
|
3882
|
-
toMs:
|
|
4235
|
+
var ReconciliationReportSchema = import_zod15.z.object({
|
|
4236
|
+
partnerId: import_zod15.z.string().uuid(),
|
|
4237
|
+
currency: import_zod15.z.string(),
|
|
4238
|
+
fromMs: import_zod15.z.number().int().nonnegative(),
|
|
4239
|
+
toMs: import_zod15.z.number().int().nonnegative(),
|
|
3883
4240
|
fundingsCreditMinor: MinorString,
|
|
3884
4241
|
fundingsDebitMinor: MinorString,
|
|
3885
4242
|
withdrawalsPaidMinor: MinorString,
|
|
@@ -3888,7 +4245,7 @@ var ReconciliationReportSchema = import_zod14.z.object({
|
|
|
3888
4245
|
expectedReserveBalanceMinor: MinorString,
|
|
3889
4246
|
actualReserveBalanceMinor: MinorString,
|
|
3890
4247
|
imbalanceMinor: MinorString,
|
|
3891
|
-
generatedAtMs:
|
|
4248
|
+
generatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3892
4249
|
});
|
|
3893
4250
|
function createPartnerFundingClient(partner) {
|
|
3894
4251
|
return {
|
|
@@ -4040,19 +4397,19 @@ function createPartnerProfileAdminClient(opts) {
|
|
|
4040
4397
|
}
|
|
4041
4398
|
|
|
4042
4399
|
// src/artifacts/envelope.ts
|
|
4043
|
-
var
|
|
4400
|
+
var import_zod16 = require("zod");
|
|
4044
4401
|
var FLUR_ARTIFACT_URI_SCHEME = "flur";
|
|
4045
4402
|
var FLUR_ARTIFACT_VERSION = 1;
|
|
4046
4403
|
var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
|
|
4047
4404
|
var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
|
|
4048
|
-
var ArtifactHeaderSchema =
|
|
4049
|
-
v:
|
|
4050
|
-
t:
|
|
4051
|
-
iss:
|
|
4052
|
-
kid:
|
|
4053
|
-
iat:
|
|
4054
|
-
exp:
|
|
4055
|
-
nonce:
|
|
4405
|
+
var ArtifactHeaderSchema = import_zod16.z.object({
|
|
4406
|
+
v: import_zod16.z.literal(FLUR_ARTIFACT_VERSION),
|
|
4407
|
+
t: import_zod16.z.string().regex(ArtifactTypeRe, "invalid artifact type"),
|
|
4408
|
+
iss: import_zod16.z.string().min(1).max(128),
|
|
4409
|
+
kid: import_zod16.z.string().min(1).max(128),
|
|
4410
|
+
iat: import_zod16.z.number().int().nonnegative(),
|
|
4411
|
+
exp: import_zod16.z.number().int().positive().optional(),
|
|
4412
|
+
nonce: import_zod16.z.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
|
|
4056
4413
|
});
|
|
4057
4414
|
var FlurArtifactError = class extends Error {
|
|
4058
4415
|
constructor(message, code) {
|
|
@@ -4191,7 +4548,7 @@ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
|
|
|
4191
4548
|
}
|
|
4192
4549
|
|
|
4193
4550
|
// src/artifacts/types.ts
|
|
4194
|
-
var
|
|
4551
|
+
var import_zod17 = require("zod");
|
|
4195
4552
|
var ARTIFACT_TYPES = {
|
|
4196
4553
|
OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
|
|
4197
4554
|
RECEIPT: "receipt",
|
|
@@ -4206,32 +4563,32 @@ var ARTIFACT_TYPES = {
|
|
|
4206
4563
|
PASS: "pass",
|
|
4207
4564
|
IDENTITY: "identity"
|
|
4208
4565
|
};
|
|
4209
|
-
var HexString = (length) =>
|
|
4566
|
+
var HexString = (length) => import_zod17.z.string().regex(
|
|
4210
4567
|
new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
|
|
4211
4568
|
`expected ${length}-byte hex string`
|
|
4212
4569
|
);
|
|
4213
|
-
var OfflinePaymentAuthorizationArtifactSchema =
|
|
4570
|
+
var OfflinePaymentAuthorizationArtifactSchema = import_zod17.z.object({
|
|
4214
4571
|
authorization: OfflinePaymentAuthorizationSchema
|
|
4215
4572
|
});
|
|
4216
|
-
var ReceiptArtifactSchema =
|
|
4217
|
-
receiptId:
|
|
4218
|
-
paymentReference:
|
|
4219
|
-
payerUserId:
|
|
4220
|
-
payeeUserId:
|
|
4221
|
-
amountKobo:
|
|
4222
|
-
currency:
|
|
4223
|
-
channel:
|
|
4224
|
-
settledAtMs:
|
|
4225
|
-
ledgerTxnId:
|
|
4226
|
-
memo:
|
|
4573
|
+
var ReceiptArtifactSchema = import_zod17.z.object({
|
|
4574
|
+
receiptId: import_zod17.z.string().min(1).max(64),
|
|
4575
|
+
paymentReference: import_zod17.z.string().min(1).max(64),
|
|
4576
|
+
payerUserId: import_zod17.z.string().min(1).max(64).optional(),
|
|
4577
|
+
payeeUserId: import_zod17.z.string().min(1).max(64),
|
|
4578
|
+
amountKobo: import_zod17.z.number().int().positive(),
|
|
4579
|
+
currency: import_zod17.z.literal("NGN"),
|
|
4580
|
+
channel: import_zod17.z.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
|
|
4581
|
+
settledAtMs: import_zod17.z.number().int().positive(),
|
|
4582
|
+
ledgerTxnId: import_zod17.z.string().min(1).max(64).optional(),
|
|
4583
|
+
memo: import_zod17.z.string().max(140).optional(),
|
|
4227
4584
|
hashChainPrev: HexString(32).optional()
|
|
4228
4585
|
});
|
|
4229
|
-
var ShortId =
|
|
4230
|
-
var PositiveInt =
|
|
4231
|
-
var NonNegativeInt =
|
|
4232
|
-
var Currency2 =
|
|
4233
|
-
var Memo =
|
|
4234
|
-
var NqrPaymentRequestArtifactSchema =
|
|
4586
|
+
var ShortId = import_zod17.z.string().min(1).max(64);
|
|
4587
|
+
var PositiveInt = import_zod17.z.number().int().positive();
|
|
4588
|
+
var NonNegativeInt = import_zod17.z.number().int().nonnegative();
|
|
4589
|
+
var Currency2 = import_zod17.z.literal("NGN");
|
|
4590
|
+
var Memo = import_zod17.z.string().max(140);
|
|
4591
|
+
var NqrPaymentRequestArtifactSchema = import_zod17.z.object({
|
|
4235
4592
|
requestId: ShortId,
|
|
4236
4593
|
payeeUserId: ShortId,
|
|
4237
4594
|
amountKobo: PositiveInt.optional(),
|
|
@@ -4239,7 +4596,7 @@ var NqrPaymentRequestArtifactSchema = import_zod16.z.object({
|
|
|
4239
4596
|
memo: Memo.optional(),
|
|
4240
4597
|
expiresAtMs: PositiveInt.optional()
|
|
4241
4598
|
});
|
|
4242
|
-
var PaymentIntentArtifactSchema =
|
|
4599
|
+
var PaymentIntentArtifactSchema = import_zod17.z.object({
|
|
4243
4600
|
intentId: ShortId,
|
|
4244
4601
|
payerUserId: ShortId,
|
|
4245
4602
|
payeeUserId: ShortId,
|
|
@@ -4248,7 +4605,7 @@ var PaymentIntentArtifactSchema = import_zod16.z.object({
|
|
|
4248
4605
|
idempotencyKey: ShortId,
|
|
4249
4606
|
createdAtMs: PositiveInt
|
|
4250
4607
|
});
|
|
4251
|
-
var OfflineClaimArtifactSchema =
|
|
4608
|
+
var OfflineClaimArtifactSchema = import_zod17.z.object({
|
|
4252
4609
|
claimId: ShortId,
|
|
4253
4610
|
authorizationId: ShortId,
|
|
4254
4611
|
payeeUserId: ShortId,
|
|
@@ -4257,10 +4614,10 @@ var OfflineClaimArtifactSchema = import_zod16.z.object({
|
|
|
4257
4614
|
claimedAtMs: PositiveInt,
|
|
4258
4615
|
paymentReference: ShortId.optional()
|
|
4259
4616
|
});
|
|
4260
|
-
var SettlementRecordArtifactSchema =
|
|
4617
|
+
var SettlementRecordArtifactSchema = import_zod17.z.object({
|
|
4261
4618
|
settlementId: ShortId,
|
|
4262
4619
|
ledgerTxnId: ShortId,
|
|
4263
|
-
sourceRefType:
|
|
4620
|
+
sourceRefType: import_zod17.z.enum([
|
|
4264
4621
|
"offline_authorization",
|
|
4265
4622
|
"offline_claim",
|
|
4266
4623
|
"transfer",
|
|
@@ -4271,12 +4628,12 @@ var SettlementRecordArtifactSchema = import_zod16.z.object({
|
|
|
4271
4628
|
currency: Currency2,
|
|
4272
4629
|
settledAtMs: PositiveInt
|
|
4273
4630
|
});
|
|
4274
|
-
var ReversalRecordArtifactSchema =
|
|
4631
|
+
var ReversalRecordArtifactSchema = import_zod17.z.object({
|
|
4275
4632
|
reversalId: ShortId,
|
|
4276
4633
|
originalTxnId: ShortId,
|
|
4277
4634
|
amountKobo: PositiveInt,
|
|
4278
4635
|
currency: Currency2,
|
|
4279
|
-
reason:
|
|
4636
|
+
reason: import_zod17.z.enum([
|
|
4280
4637
|
"user_dispute",
|
|
4281
4638
|
"fraud",
|
|
4282
4639
|
"duplicate",
|
|
@@ -4286,7 +4643,7 @@ var ReversalRecordArtifactSchema = import_zod16.z.object({
|
|
|
4286
4643
|
reversedAtMs: PositiveInt,
|
|
4287
4644
|
memo: Memo.optional()
|
|
4288
4645
|
});
|
|
4289
|
-
var LedgerJournalEntryArtifactSchema =
|
|
4646
|
+
var LedgerJournalEntryArtifactSchema = import_zod17.z.object({
|
|
4290
4647
|
entryId: ShortId,
|
|
4291
4648
|
journalId: ShortId,
|
|
4292
4649
|
debitAccountId: ShortId,
|
|
@@ -4297,13 +4654,13 @@ var LedgerJournalEntryArtifactSchema = import_zod16.z.object({
|
|
|
4297
4654
|
refType: ShortId.optional(),
|
|
4298
4655
|
refId: ShortId.optional()
|
|
4299
4656
|
});
|
|
4300
|
-
var StatementArtifactSchema =
|
|
4657
|
+
var StatementArtifactSchema = import_zod17.z.object({
|
|
4301
4658
|
statementId: ShortId,
|
|
4302
4659
|
userId: ShortId,
|
|
4303
4660
|
periodStartMs: PositiveInt,
|
|
4304
4661
|
periodEndMs: PositiveInt,
|
|
4305
|
-
openingBalanceKobo:
|
|
4306
|
-
closingBalanceKobo:
|
|
4662
|
+
openingBalanceKobo: import_zod17.z.number().int(),
|
|
4663
|
+
closingBalanceKobo: import_zod17.z.number().int(),
|
|
4307
4664
|
transactionCount: NonNegativeInt,
|
|
4308
4665
|
currency: Currency2,
|
|
4309
4666
|
hashChainPrev: HexString(32).optional()
|
|
@@ -4311,16 +4668,16 @@ var StatementArtifactSchema = import_zod16.z.object({
|
|
|
4311
4668
|
message: "periodEndMs must be greater than periodStartMs",
|
|
4312
4669
|
path: ["periodEndMs"]
|
|
4313
4670
|
});
|
|
4314
|
-
var PassArtifactSchema =
|
|
4671
|
+
var PassArtifactSchema = import_zod17.z.object({
|
|
4315
4672
|
passId: ShortId,
|
|
4316
4673
|
holderId: ShortId,
|
|
4317
|
-
category:
|
|
4318
|
-
title:
|
|
4674
|
+
category: import_zod17.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
|
|
4675
|
+
title: import_zod17.z.string().min(1).max(120),
|
|
4319
4676
|
validFromMs: PositiveInt,
|
|
4320
4677
|
validUntilMs: PositiveInt.optional(),
|
|
4321
|
-
metadata:
|
|
4322
|
-
|
|
4323
|
-
|
|
4678
|
+
metadata: import_zod17.z.record(
|
|
4679
|
+
import_zod17.z.string().min(1).max(64),
|
|
4680
|
+
import_zod17.z.union([import_zod17.z.string().max(280), import_zod17.z.number(), import_zod17.z.boolean()])
|
|
4324
4681
|
).optional()
|
|
4325
4682
|
}).refine(
|
|
4326
4683
|
(v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
|
|
@@ -4329,10 +4686,10 @@ var PassArtifactSchema = import_zod16.z.object({
|
|
|
4329
4686
|
path: ["validUntilMs"]
|
|
4330
4687
|
}
|
|
4331
4688
|
);
|
|
4332
|
-
var IdentityArtifactSchema =
|
|
4689
|
+
var IdentityArtifactSchema = import_zod17.z.object({
|
|
4333
4690
|
attestationId: ShortId,
|
|
4334
4691
|
subjectId: ShortId,
|
|
4335
|
-
claimType:
|
|
4692
|
+
claimType: import_zod17.z.enum([
|
|
4336
4693
|
"phone_verified",
|
|
4337
4694
|
"email_verified",
|
|
4338
4695
|
"bvn_verified",
|
|
@@ -4453,6 +4810,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4453
4810
|
}
|
|
4454
4811
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4455
4812
|
0 && (module.exports = {
|
|
4813
|
+
ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
|
|
4456
4814
|
ACCOUNT_STATUSES,
|
|
4457
4815
|
ACCOUNT_TYPES,
|
|
4458
4816
|
ADDITIONAL_DATA_SUBFIELD,
|
|
@@ -4466,6 +4824,10 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4466
4824
|
CLAIM_DOMAIN_V2,
|
|
4467
4825
|
COLLECTION_INTENT_STATUSES,
|
|
4468
4826
|
COLLECTION_PAYMENT_STATUSES,
|
|
4827
|
+
CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
|
|
4828
|
+
CONSUMER_PAYMENT_REQUEST_DOMAIN,
|
|
4829
|
+
CONSUMER_SETTLEMENT_DOMAIN,
|
|
4830
|
+
CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX,
|
|
4469
4831
|
CUSTODIAL_MODES,
|
|
4470
4832
|
CollectionIntentSchema,
|
|
4471
4833
|
CollectionPaymentResultSchema,
|
|
@@ -4475,6 +4837,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4475
4837
|
ConsumerOACRecordSchema,
|
|
4476
4838
|
ConsumerOACSchema,
|
|
4477
4839
|
ConsumerPaymentClaimSchema,
|
|
4840
|
+
ConsumerPaymentRequestEnvelopeSchema,
|
|
4478
4841
|
ConsumerSettleResultSchema,
|
|
4479
4842
|
ConsumerSettlementSchema,
|
|
4480
4843
|
CreateCollectionIntentInputSchema,
|
|
@@ -4484,10 +4847,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4484
4847
|
CreateWithdrawalResultSchema,
|
|
4485
4848
|
DeviceKeyAlgSchema,
|
|
4486
4849
|
DeviceKeyRecordSchema,
|
|
4487
|
-
DisableOfflineInputSchema,
|
|
4488
|
-
DisableOfflineResultSchema,
|
|
4489
|
-
EnableOfflineInputSchema,
|
|
4490
|
-
EnableOfflineResultSchema,
|
|
4491
4850
|
FIELD,
|
|
4492
4851
|
FLUR_ARTIFACT_URI_PREFIX,
|
|
4493
4852
|
FLUR_ARTIFACT_URI_SCHEME,
|
|
@@ -4503,7 +4862,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4503
4862
|
IdentityArtifactSchema,
|
|
4504
4863
|
IngestFundingResultSchema,
|
|
4505
4864
|
IssueAccountOacInputSchema,
|
|
4506
|
-
IssueOACInputSchema,
|
|
4507
4865
|
LedgerJournalEntryArtifactSchema,
|
|
4508
4866
|
ListPayoutDestinationsResultSchema,
|
|
4509
4867
|
MEMBERSHIP_ROLES,
|
|
@@ -4521,12 +4879,16 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4521
4879
|
OAC_DEFAULT_PER_TX_KOBO,
|
|
4522
4880
|
OAC_DEFAULT_VALIDITY_MS,
|
|
4523
4881
|
OFFLINE_CLAIM_SMS_PREFIX,
|
|
4882
|
+
OFFLINE_SMS_SETTLE_DOMAIN,
|
|
4883
|
+
OFFLINE_SMS_SETTLE_HEADER_BYTES,
|
|
4884
|
+
OFFLINE_SMS_SETTLE_PREFIX,
|
|
4885
|
+
OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
|
|
4886
|
+
OFFLINE_SMS_SETTLE_TOKEN_BYTES,
|
|
4887
|
+
OFFLINE_SMS_SETTLE_VERSION,
|
|
4524
4888
|
OfflineClaimArtifactSchema,
|
|
4525
|
-
OfflineHoldRecordSchema,
|
|
4526
4889
|
OfflinePaymentAuthorizationArtifactSchema,
|
|
4527
4890
|
OfflinePaymentAuthorizationSchema,
|
|
4528
4891
|
OfflinePaymentRequestSchema,
|
|
4529
|
-
OfflineStateResultSchema,
|
|
4530
4892
|
OfflineStatusResultSchema,
|
|
4531
4893
|
OfflineTokenSchema,
|
|
4532
4894
|
P256EnrollmentChallengeInputSchema,
|
|
@@ -4554,8 +4916,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4554
4916
|
PayoutEventInputSchema,
|
|
4555
4917
|
ProviderEventInputSchema,
|
|
4556
4918
|
ProviderEventRecordSchema,
|
|
4557
|
-
ProvisionOfflineAllowanceInputSchema,
|
|
4558
|
-
ProvisionOfflineAllowanceResultSchema,
|
|
4559
4919
|
PublicCollectionIntentSchema,
|
|
4560
4920
|
RECEIPT_CHANNELS,
|
|
4561
4921
|
RECEIPT_KINDS,
|
|
@@ -4566,7 +4926,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4566
4926
|
ReconciliationReportSchema,
|
|
4567
4927
|
RecordPayoutEventResultSchema,
|
|
4568
4928
|
RedemptionSchema,
|
|
4569
|
-
RegisterDeviceKeyInputSchema,
|
|
4570
4929
|
RegisterDeviceKeyP256InputSchema,
|
|
4571
4930
|
ReversalRecordArtifactSchema,
|
|
4572
4931
|
RevokeDeviceKeyInputSchema,
|
|
@@ -4585,18 +4944,25 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4585
4944
|
bodySha256Hex,
|
|
4586
4945
|
buildArtifactBody,
|
|
4587
4946
|
buildAuthorization,
|
|
4947
|
+
buildConsumerPaymentRequest,
|
|
4588
4948
|
buildOAC,
|
|
4589
4949
|
buildPass,
|
|
4590
4950
|
buildPaymentRequest,
|
|
4591
4951
|
buildReceipt,
|
|
4592
4952
|
buildRedemption,
|
|
4953
|
+
buildSmsSettleHeader,
|
|
4954
|
+
buildSmsSettleSignedBytes,
|
|
4593
4955
|
canonicalClaimSigningBytes,
|
|
4594
4956
|
canonicalClaimSigningPayload,
|
|
4595
4957
|
canonicalJSONBytes,
|
|
4596
4958
|
canonicalJSONStringify,
|
|
4597
4959
|
canonicalRequestString,
|
|
4960
|
+
computeConsumerClaimEncounterId,
|
|
4598
4961
|
computeEncounterId,
|
|
4599
4962
|
constantTimeEqual,
|
|
4963
|
+
consumerPaymentRequestSigningBytes,
|
|
4964
|
+
consumerPaymentRequestSigningPayload,
|
|
4965
|
+
consumerSettlementSigningPayload,
|
|
4600
4966
|
crc16ccitt,
|
|
4601
4967
|
crc16ccittHex,
|
|
4602
4968
|
createAccountsClient,
|
|
@@ -4620,19 +4986,27 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4620
4986
|
decodeArtifactUri,
|
|
4621
4987
|
decodeAuthorizationQR,
|
|
4622
4988
|
decodeBase45,
|
|
4989
|
+
decodeConsumerSettlementReceiptQR,
|
|
4623
4990
|
decodeOfflineClaimSmsMessage,
|
|
4991
|
+
decodeOfflineSmsSettleToken,
|
|
4624
4992
|
decodePaymentRequestQR,
|
|
4993
|
+
decodeUnverifiedConsumerSettlementReceiptQR,
|
|
4994
|
+
derToRawP256Signature,
|
|
4625
4995
|
encodeArtifactUri,
|
|
4626
4996
|
encodeAuthorizationQR,
|
|
4627
4997
|
encodeBase45,
|
|
4998
|
+
encodeConsumerSettlementReceiptQR,
|
|
4628
4999
|
encodeNQR,
|
|
4629
5000
|
encodeOfflineClaimSmsMessage,
|
|
5001
|
+
encodeOfflineSmsSettleToken,
|
|
4630
5002
|
encodePaymentRequestQR,
|
|
4631
5003
|
extractOfflineClaimSmsToken,
|
|
5004
|
+
extractOfflineSmsSettleToken,
|
|
4632
5005
|
formatAmount,
|
|
4633
5006
|
generateDynamicQR,
|
|
4634
5007
|
generateStaticQR,
|
|
4635
5008
|
init,
|
|
5009
|
+
isConsumerPaymentRequestExpired,
|
|
4636
5010
|
isHardenedArtifactType,
|
|
4637
5011
|
isKnownArtifactType,
|
|
4638
5012
|
isPassWithinValidity,
|
|
@@ -4645,6 +5019,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4645
5019
|
routingHint,
|
|
4646
5020
|
signArtifact,
|
|
4647
5021
|
signAuthorization,
|
|
5022
|
+
signConsumerPaymentRequest,
|
|
4648
5023
|
signOAC,
|
|
4649
5024
|
signPartnerRequest,
|
|
4650
5025
|
signPass,
|
|
@@ -4656,7 +5031,11 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4656
5031
|
verifyArtifactUri,
|
|
4657
5032
|
verifyAuthorization,
|
|
4658
5033
|
verifyClaimSignature,
|
|
5034
|
+
verifyConsumerPaymentRequest,
|
|
5035
|
+
verifyConsumerSettlement,
|
|
5036
|
+
verifyConsumerSettlementReceiptQR,
|
|
4659
5037
|
verifyOAC,
|
|
5038
|
+
verifyOfflineSmsSettleToken,
|
|
4660
5039
|
verifyPass,
|
|
4661
5040
|
verifyPaymentRequest,
|
|
4662
5041
|
verifyReceipt,
|