@nokinc-flur/sdk 2.0.0 → 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 +706 -169
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +326 -11
- package/dist/index.d.ts +326 -11
- package/dist/index.js +666 -169
- 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,6 +17,14 @@ 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
|
|
@@ -35,6 +45,9 @@ __export(index_exports, {
|
|
|
35
45
|
COLLECTION_INTENT_STATUSES: () => COLLECTION_INTENT_STATUSES,
|
|
36
46
|
COLLECTION_PAYMENT_STATUSES: () => COLLECTION_PAYMENT_STATUSES,
|
|
37
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,
|
|
38
51
|
CUSTODIAL_MODES: () => CUSTODIAL_MODES,
|
|
39
52
|
CollectionIntentSchema: () => CollectionIntentSchema,
|
|
40
53
|
CollectionPaymentResultSchema: () => CollectionPaymentResultSchema,
|
|
@@ -44,6 +57,7 @@ __export(index_exports, {
|
|
|
44
57
|
ConsumerOACRecordSchema: () => OACRecordSchema,
|
|
45
58
|
ConsumerOACSchema: () => ConsumerOACSchema,
|
|
46
59
|
ConsumerPaymentClaimSchema: () => ConsumerPaymentClaimSchema,
|
|
60
|
+
ConsumerPaymentRequestEnvelopeSchema: () => ConsumerPaymentRequestEnvelopeSchema,
|
|
47
61
|
ConsumerSettleResultSchema: () => ConsumerSettleResultSchema,
|
|
48
62
|
ConsumerSettlementSchema: () => ConsumerSettlementSchema,
|
|
49
63
|
CreateCollectionIntentInputSchema: () => CreateCollectionIntentInputSchema,
|
|
@@ -85,6 +99,12 @@ __export(index_exports, {
|
|
|
85
99
|
OAC_DEFAULT_PER_TX_KOBO: () => OAC_DEFAULT_PER_TX_KOBO,
|
|
86
100
|
OAC_DEFAULT_VALIDITY_MS: () => OAC_DEFAULT_VALIDITY_MS,
|
|
87
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,
|
|
88
108
|
OfflineClaimArtifactSchema: () => OfflineClaimArtifactSchema,
|
|
89
109
|
OfflinePaymentAuthorizationArtifactSchema: () => OfflinePaymentAuthorizationArtifactSchema,
|
|
90
110
|
OfflinePaymentAuthorizationSchema: () => OfflinePaymentAuthorizationSchema,
|
|
@@ -144,18 +164,25 @@ __export(index_exports, {
|
|
|
144
164
|
bodySha256Hex: () => bodySha256Hex,
|
|
145
165
|
buildArtifactBody: () => buildArtifactBody,
|
|
146
166
|
buildAuthorization: () => buildAuthorization,
|
|
167
|
+
buildConsumerPaymentRequest: () => buildConsumerPaymentRequest,
|
|
147
168
|
buildOAC: () => buildOAC,
|
|
148
169
|
buildPass: () => buildPass,
|
|
149
170
|
buildPaymentRequest: () => buildPaymentRequest,
|
|
150
171
|
buildReceipt: () => buildReceipt,
|
|
151
172
|
buildRedemption: () => buildRedemption,
|
|
173
|
+
buildSmsSettleHeader: () => buildSmsSettleHeader,
|
|
174
|
+
buildSmsSettleSignedBytes: () => domainTag,
|
|
152
175
|
canonicalClaimSigningBytes: () => canonicalClaimSigningBytes,
|
|
153
176
|
canonicalClaimSigningPayload: () => canonicalClaimSigningPayload,
|
|
154
177
|
canonicalJSONBytes: () => canonicalJSONBytes,
|
|
155
178
|
canonicalJSONStringify: () => canonicalJSONStringify,
|
|
156
179
|
canonicalRequestString: () => canonicalRequestString,
|
|
180
|
+
computeConsumerClaimEncounterId: () => computeConsumerClaimEncounterId,
|
|
157
181
|
computeEncounterId: () => computeEncounterId,
|
|
158
182
|
constantTimeEqual: () => constantTimeEqual,
|
|
183
|
+
consumerPaymentRequestSigningBytes: () => consumerPaymentRequestSigningBytes,
|
|
184
|
+
consumerPaymentRequestSigningPayload: () => consumerPaymentRequestSigningPayload,
|
|
185
|
+
consumerSettlementSigningPayload: () => consumerSettlementSigningPayload,
|
|
159
186
|
crc16ccitt: () => crc16ccitt,
|
|
160
187
|
crc16ccittHex: () => crc16ccittHex,
|
|
161
188
|
createAccountsClient: () => createAccountsClient,
|
|
@@ -179,19 +206,27 @@ __export(index_exports, {
|
|
|
179
206
|
decodeArtifactUri: () => decodeArtifactUri,
|
|
180
207
|
decodeAuthorizationQR: () => decodeAuthorizationQR,
|
|
181
208
|
decodeBase45: () => decodeBase45,
|
|
209
|
+
decodeConsumerSettlementReceiptQR: () => decodeConsumerSettlementReceiptQR,
|
|
182
210
|
decodeOfflineClaimSmsMessage: () => decodeOfflineClaimSmsMessage,
|
|
211
|
+
decodeOfflineSmsSettleToken: () => decodeOfflineSmsSettleToken,
|
|
183
212
|
decodePaymentRequestQR: () => decodePaymentRequestQR,
|
|
213
|
+
decodeUnverifiedConsumerSettlementReceiptQR: () => decodeUnverifiedConsumerSettlementReceiptQR,
|
|
214
|
+
derToRawP256Signature: () => derToRawP256Signature,
|
|
184
215
|
encodeArtifactUri: () => encodeArtifactUri,
|
|
185
216
|
encodeAuthorizationQR: () => encodeAuthorizationQR,
|
|
186
217
|
encodeBase45: () => encodeBase45,
|
|
218
|
+
encodeConsumerSettlementReceiptQR: () => encodeConsumerSettlementReceiptQR,
|
|
187
219
|
encodeNQR: () => encodeNQR,
|
|
188
220
|
encodeOfflineClaimSmsMessage: () => encodeOfflineClaimSmsMessage,
|
|
221
|
+
encodeOfflineSmsSettleToken: () => encodeOfflineSmsSettleToken,
|
|
189
222
|
encodePaymentRequestQR: () => encodePaymentRequestQR,
|
|
190
223
|
extractOfflineClaimSmsToken: () => extractOfflineClaimSmsToken,
|
|
224
|
+
extractOfflineSmsSettleToken: () => extractOfflineSmsSettleToken,
|
|
191
225
|
formatAmount: () => formatAmount,
|
|
192
226
|
generateDynamicQR: () => generateDynamicQR,
|
|
193
227
|
generateStaticQR: () => generateStaticQR,
|
|
194
228
|
init: () => init,
|
|
229
|
+
isConsumerPaymentRequestExpired: () => isConsumerPaymentRequestExpired,
|
|
195
230
|
isHardenedArtifactType: () => isHardenedArtifactType,
|
|
196
231
|
isKnownArtifactType: () => isKnownArtifactType,
|
|
197
232
|
isPassWithinValidity: () => isPassWithinValidity,
|
|
@@ -204,6 +239,7 @@ __export(index_exports, {
|
|
|
204
239
|
routingHint: () => routingHint,
|
|
205
240
|
signArtifact: () => signArtifact,
|
|
206
241
|
signAuthorization: () => signAuthorization,
|
|
242
|
+
signConsumerPaymentRequest: () => signConsumerPaymentRequest,
|
|
207
243
|
signOAC: () => signOAC,
|
|
208
244
|
signPartnerRequest: () => signPartnerRequest,
|
|
209
245
|
signPass: () => signPass,
|
|
@@ -215,7 +251,11 @@ __export(index_exports, {
|
|
|
215
251
|
verifyArtifactUri: () => verifyArtifactUri,
|
|
216
252
|
verifyAuthorization: () => verifyAuthorization,
|
|
217
253
|
verifyClaimSignature: () => verifyClaimSignature,
|
|
254
|
+
verifyConsumerPaymentRequest: () => verifyConsumerPaymentRequest,
|
|
255
|
+
verifyConsumerSettlement: () => verifyConsumerSettlement,
|
|
256
|
+
verifyConsumerSettlementReceiptQR: () => verifyConsumerSettlementReceiptQR,
|
|
218
257
|
verifyOAC: () => verifyOAC,
|
|
258
|
+
verifyOfflineSmsSettleToken: () => verifyOfflineSmsSettleToken,
|
|
219
259
|
verifyPass: () => verifyPass,
|
|
220
260
|
verifyPaymentRequest: () => verifyPaymentRequest,
|
|
221
261
|
verifyReceipt: () => verifyReceipt,
|
|
@@ -3185,6 +3225,9 @@ function createAccountsClient(opts) {
|
|
|
3185
3225
|
var import_zod13 = require("zod");
|
|
3186
3226
|
var Sha256Hex = import_zod13.z.string().regex(/^[0-9a-f]{64}$/);
|
|
3187
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
|
+
});
|
|
3188
3231
|
var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
|
|
3189
3232
|
var CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1e3 * 60 * 60 * 24;
|
|
3190
3233
|
var AttestationSecurityLevelSchema = import_zod13.z.enum([
|
|
@@ -3277,13 +3320,25 @@ var ConsumerPaymentClaimSchema = import_zod13.z.object({
|
|
|
3277
3320
|
payerUserId: import_zod13.z.string().uuid(),
|
|
3278
3321
|
payeeUserId: import_zod13.z.string().uuid(),
|
|
3279
3322
|
payerDeviceId: import_zod13.z.string().min(1).max(128),
|
|
3280
|
-
payerNonce:
|
|
3281
|
-
payeeNonce:
|
|
3323
|
+
payerNonce: ClaimNonce,
|
|
3324
|
+
payeeNonce: ClaimNonce,
|
|
3282
3325
|
amountKobo: import_zod13.z.number().int().positive(),
|
|
3283
3326
|
currency: import_zod13.z.string().length(3).default("NGN"),
|
|
3284
3327
|
occurredAtMs: import_zod13.z.number().int().nonnegative(),
|
|
3285
3328
|
completedAtMs: import_zod13.z.number().int().nonnegative().optional(),
|
|
3286
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(),
|
|
3287
3342
|
payerPubkeySpkiB64: Base64Std3.min(64).max(4096),
|
|
3288
3343
|
payerSignatureDerB64: Base64Std3.min(16).max(2048),
|
|
3289
3344
|
payeePubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
|
|
@@ -3303,7 +3358,10 @@ var ConsumerSettlementSchema = import_zod13.z.object({
|
|
|
3303
3358
|
ledgerRef: import_zod13.z.string().nullable(),
|
|
3304
3359
|
/** ASN.1 DER ECDSA P-256 issuer signature, base64. */
|
|
3305
3360
|
issuerSig: Base64Std3.min(16).max(2048),
|
|
3306
|
-
|
|
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()
|
|
3307
3365
|
});
|
|
3308
3366
|
var ConsumerSettleResultSchema = import_zod13.z.object({
|
|
3309
3367
|
settlement: ConsumerSettlementSchema,
|
|
@@ -3392,13 +3450,21 @@ function createMeOfflineClient(opts) {
|
|
|
3392
3450
|
"/v1/me/offline/claims",
|
|
3393
3451
|
ConsumerPaymentClaimSchema.parse(claim),
|
|
3394
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)
|
|
3395
3459
|
)
|
|
3396
3460
|
};
|
|
3397
3461
|
}
|
|
3398
3462
|
|
|
3399
3463
|
// src/me-offline/signer.ts
|
|
3400
3464
|
var import_nist2 = require("@noble/curves/nist");
|
|
3465
|
+
var import_sha2 = require("@noble/hashes/sha2");
|
|
3401
3466
|
var CLAIM_DOMAIN_V2 = "flur:consumer-offline:v2:claim";
|
|
3467
|
+
var ENCOUNTER_DOMAIN2 = "flur:consumer-offline:v1:encounter";
|
|
3402
3468
|
function canonicalClaimSigningPayload(claim) {
|
|
3403
3469
|
return {
|
|
3404
3470
|
domain: CLAIM_DOMAIN_V2,
|
|
@@ -3419,6 +3485,27 @@ function canonicalClaimSigningPayload(claim) {
|
|
|
3419
3485
|
function canonicalClaimSigningBytes(claim) {
|
|
3420
3486
|
return canonicalJSONBytes(canonicalClaimSigningPayload(claim));
|
|
3421
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
|
+
}
|
|
3422
3509
|
function bytesToBase642(bytes) {
|
|
3423
3510
|
if (typeof Buffer !== "undefined") {
|
|
3424
3511
|
return Buffer.from(bytes).toString("base64");
|
|
@@ -3514,38 +3601,192 @@ function verifyClaimSignature(input) {
|
|
|
3514
3601
|
}
|
|
3515
3602
|
}
|
|
3516
3603
|
|
|
3517
|
-
// src/me-offline/
|
|
3518
|
-
var
|
|
3519
|
-
var
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
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;
|
|
3524
3676
|
}
|
|
3525
|
-
function
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
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");
|
|
3529
3699
|
}
|
|
3530
|
-
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);
|
|
3531
3770
|
let raw;
|
|
3532
3771
|
try {
|
|
3533
3772
|
raw = JSON.parse(base64UrlDecodeUtf8(encoded));
|
|
3534
3773
|
} catch {
|
|
3535
|
-
throw new Error("
|
|
3774
|
+
throw new Error("consumer settlement receipt QR is malformed");
|
|
3536
3775
|
}
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
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");
|
|
3540
3782
|
}
|
|
3541
|
-
return
|
|
3783
|
+
return settlement;
|
|
3542
3784
|
}
|
|
3543
|
-
function
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
return trimmed.split(/\s+/, 1)[0] ?? null;
|
|
3785
|
+
function decodeConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64) {
|
|
3786
|
+
if (!issuerPublicKeySpkiB64) {
|
|
3787
|
+
return decodeUnverifiedConsumerSettlementReceiptQR(value);
|
|
3547
3788
|
}
|
|
3548
|
-
return
|
|
3789
|
+
return verifyConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64);
|
|
3549
3790
|
}
|
|
3550
3791
|
function base64UrlEncodeUtf8(input) {
|
|
3551
3792
|
const bytes = new TextEncoder().encode(input);
|
|
@@ -3575,15 +3816,281 @@ function base64UrlDecodeUtf8(input) {
|
|
|
3575
3816
|
throw new Error("base64 decoder unavailable");
|
|
3576
3817
|
}
|
|
3577
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
|
+
|
|
3578
4085
|
// src/partner-funding/client.ts
|
|
3579
|
-
var
|
|
3580
|
-
var MinorString =
|
|
3581
|
-
var PositiveMinor =
|
|
3582
|
-
|
|
3583
|
-
|
|
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}$/)
|
|
3584
4091
|
]);
|
|
3585
|
-
var Currency =
|
|
3586
|
-
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());
|
|
3587
4094
|
var PARTNER_KINDS = ["bank", "merchant"];
|
|
3588
4095
|
var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
|
|
3589
4096
|
var PARTNER_PROFILE_STATUSES = [
|
|
@@ -3610,126 +4117,126 @@ var WITHDRAWAL_STATES = [
|
|
|
3610
4117
|
"failed",
|
|
3611
4118
|
"reversed"
|
|
3612
4119
|
];
|
|
3613
|
-
var PartnerProfileSchema =
|
|
3614
|
-
partnerAccountId:
|
|
3615
|
-
kind:
|
|
3616
|
-
custodialMode:
|
|
3617
|
-
displayName:
|
|
3618
|
-
bankCode:
|
|
3619
|
-
poolAccountNumber:
|
|
3620
|
-
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),
|
|
3621
4128
|
metadata: Metadata,
|
|
3622
|
-
createdAtMs:
|
|
3623
|
-
updatedAtMs:
|
|
4129
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4130
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3624
4131
|
});
|
|
3625
|
-
var UpsertPartnerProfileInputSchema =
|
|
3626
|
-
kind:
|
|
3627
|
-
custodialMode:
|
|
3628
|
-
displayName:
|
|
3629
|
-
bankCode:
|
|
3630
|
-
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(),
|
|
3631
4138
|
metadata: Metadata.optional()
|
|
3632
4139
|
});
|
|
3633
|
-
var PartnerFundingEventInputSchema =
|
|
3634
|
-
externalRef:
|
|
3635
|
-
direction:
|
|
3636
|
-
userId:
|
|
3637
|
-
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(),
|
|
3638
4145
|
amountMinor: PositiveMinor,
|
|
3639
4146
|
currency: Currency,
|
|
3640
|
-
fundingSource:
|
|
4147
|
+
fundingSource: import_zod15.z.string().trim().min(1).max(64).optional(),
|
|
3641
4148
|
providerMetadata: Metadata.optional()
|
|
3642
4149
|
});
|
|
3643
|
-
var PartnerFundingSchema =
|
|
3644
|
-
fundingId:
|
|
3645
|
-
partnerId:
|
|
3646
|
-
accountId:
|
|
3647
|
-
userId:
|
|
3648
|
-
direction:
|
|
3649
|
-
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(),
|
|
3650
4157
|
amountMinor: MinorString,
|
|
3651
|
-
externalRef:
|
|
3652
|
-
status:
|
|
3653
|
-
fundingSource:
|
|
3654
|
-
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(),
|
|
3655
4162
|
providerMetadata: Metadata,
|
|
3656
|
-
createdAtMs:
|
|
3657
|
-
updatedAtMs:
|
|
4163
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4164
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3658
4165
|
});
|
|
3659
|
-
var IngestFundingResultSchema =
|
|
4166
|
+
var IngestFundingResultSchema = import_zod15.z.object({
|
|
3660
4167
|
funding: PartnerFundingSchema,
|
|
3661
|
-
replayed:
|
|
4168
|
+
replayed: import_zod15.z.boolean()
|
|
3662
4169
|
});
|
|
3663
|
-
var PayoutDestinationSchema =
|
|
3664
|
-
destinationId:
|
|
3665
|
-
accountId:
|
|
3666
|
-
partnerId:
|
|
3667
|
-
bankCode:
|
|
3668
|
-
accountNumber:
|
|
3669
|
-
accountName:
|
|
3670
|
-
status:
|
|
3671
|
-
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(),
|
|
3672
4179
|
metadata: Metadata,
|
|
3673
|
-
createdAtMs:
|
|
3674
|
-
updatedAtMs:
|
|
4180
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4181
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3675
4182
|
});
|
|
3676
|
-
var CreatePayoutDestinationInputSchema =
|
|
3677
|
-
partnerId:
|
|
3678
|
-
bankCode:
|
|
3679
|
-
accountNumber:
|
|
3680
|
-
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),
|
|
3681
4188
|
metadata: Metadata.optional()
|
|
3682
4189
|
});
|
|
3683
|
-
var ListPayoutDestinationsResultSchema =
|
|
3684
|
-
items:
|
|
4190
|
+
var ListPayoutDestinationsResultSchema = import_zod15.z.object({
|
|
4191
|
+
items: import_zod15.z.array(PayoutDestinationSchema)
|
|
3685
4192
|
});
|
|
3686
|
-
var WithdrawalSchema =
|
|
3687
|
-
withdrawalId:
|
|
3688
|
-
accountId:
|
|
3689
|
-
userId:
|
|
3690
|
-
partnerId:
|
|
3691
|
-
destinationId:
|
|
3692
|
-
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(),
|
|
3693
4200
|
amountMinor: MinorString,
|
|
3694
|
-
state:
|
|
3695
|
-
idempotencyKey:
|
|
3696
|
-
providerRef:
|
|
3697
|
-
lastError:
|
|
3698
|
-
ledgerRef:
|
|
3699
|
-
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(),
|
|
3700
4207
|
metadata: Metadata,
|
|
3701
|
-
createdAtMs:
|
|
3702
|
-
updatedAtMs:
|
|
4208
|
+
createdAtMs: import_zod15.z.number().int().nonnegative(),
|
|
4209
|
+
updatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3703
4210
|
});
|
|
3704
|
-
var CreateWithdrawalInputSchema =
|
|
3705
|
-
destinationId:
|
|
4211
|
+
var CreateWithdrawalInputSchema = import_zod15.z.object({
|
|
4212
|
+
destinationId: import_zod15.z.string().uuid(),
|
|
3706
4213
|
amountMinor: PositiveMinor,
|
|
3707
4214
|
currency: Currency,
|
|
3708
|
-
idempotencyKey:
|
|
4215
|
+
idempotencyKey: import_zod15.z.string().trim().min(8).max(128),
|
|
3709
4216
|
metadata: Metadata.optional()
|
|
3710
4217
|
});
|
|
3711
|
-
var CreateWithdrawalResultSchema =
|
|
4218
|
+
var CreateWithdrawalResultSchema = import_zod15.z.object({
|
|
3712
4219
|
withdrawal: WithdrawalSchema,
|
|
3713
|
-
replayed:
|
|
4220
|
+
replayed: import_zod15.z.boolean()
|
|
3714
4221
|
});
|
|
3715
|
-
var PayoutEventInputSchema =
|
|
3716
|
-
externalRef:
|
|
3717
|
-
withdrawalId:
|
|
3718
|
-
state:
|
|
3719
|
-
providerRef:
|
|
3720
|
-
failureCode:
|
|
3721
|
-
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(),
|
|
3722
4229
|
providerMetadata: Metadata.optional()
|
|
3723
4230
|
});
|
|
3724
|
-
var RecordPayoutEventResultSchema =
|
|
4231
|
+
var RecordPayoutEventResultSchema = import_zod15.z.object({
|
|
3725
4232
|
withdrawal: WithdrawalSchema,
|
|
3726
|
-
replayed:
|
|
4233
|
+
replayed: import_zod15.z.boolean()
|
|
3727
4234
|
});
|
|
3728
|
-
var ReconciliationReportSchema =
|
|
3729
|
-
partnerId:
|
|
3730
|
-
currency:
|
|
3731
|
-
fromMs:
|
|
3732
|
-
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(),
|
|
3733
4240
|
fundingsCreditMinor: MinorString,
|
|
3734
4241
|
fundingsDebitMinor: MinorString,
|
|
3735
4242
|
withdrawalsPaidMinor: MinorString,
|
|
@@ -3738,7 +4245,7 @@ var ReconciliationReportSchema = import_zod14.z.object({
|
|
|
3738
4245
|
expectedReserveBalanceMinor: MinorString,
|
|
3739
4246
|
actualReserveBalanceMinor: MinorString,
|
|
3740
4247
|
imbalanceMinor: MinorString,
|
|
3741
|
-
generatedAtMs:
|
|
4248
|
+
generatedAtMs: import_zod15.z.number().int().nonnegative()
|
|
3742
4249
|
});
|
|
3743
4250
|
function createPartnerFundingClient(partner) {
|
|
3744
4251
|
return {
|
|
@@ -3890,19 +4397,19 @@ function createPartnerProfileAdminClient(opts) {
|
|
|
3890
4397
|
}
|
|
3891
4398
|
|
|
3892
4399
|
// src/artifacts/envelope.ts
|
|
3893
|
-
var
|
|
4400
|
+
var import_zod16 = require("zod");
|
|
3894
4401
|
var FLUR_ARTIFACT_URI_SCHEME = "flur";
|
|
3895
4402
|
var FLUR_ARTIFACT_VERSION = 1;
|
|
3896
4403
|
var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
|
|
3897
4404
|
var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
|
|
3898
|
-
var ArtifactHeaderSchema =
|
|
3899
|
-
v:
|
|
3900
|
-
t:
|
|
3901
|
-
iss:
|
|
3902
|
-
kid:
|
|
3903
|
-
iat:
|
|
3904
|
-
exp:
|
|
3905
|
-
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")
|
|
3906
4413
|
});
|
|
3907
4414
|
var FlurArtifactError = class extends Error {
|
|
3908
4415
|
constructor(message, code) {
|
|
@@ -4041,7 +4548,7 @@ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
|
|
|
4041
4548
|
}
|
|
4042
4549
|
|
|
4043
4550
|
// src/artifacts/types.ts
|
|
4044
|
-
var
|
|
4551
|
+
var import_zod17 = require("zod");
|
|
4045
4552
|
var ARTIFACT_TYPES = {
|
|
4046
4553
|
OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
|
|
4047
4554
|
RECEIPT: "receipt",
|
|
@@ -4056,32 +4563,32 @@ var ARTIFACT_TYPES = {
|
|
|
4056
4563
|
PASS: "pass",
|
|
4057
4564
|
IDENTITY: "identity"
|
|
4058
4565
|
};
|
|
4059
|
-
var HexString = (length) =>
|
|
4566
|
+
var HexString = (length) => import_zod17.z.string().regex(
|
|
4060
4567
|
new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
|
|
4061
4568
|
`expected ${length}-byte hex string`
|
|
4062
4569
|
);
|
|
4063
|
-
var OfflinePaymentAuthorizationArtifactSchema =
|
|
4570
|
+
var OfflinePaymentAuthorizationArtifactSchema = import_zod17.z.object({
|
|
4064
4571
|
authorization: OfflinePaymentAuthorizationSchema
|
|
4065
4572
|
});
|
|
4066
|
-
var ReceiptArtifactSchema =
|
|
4067
|
-
receiptId:
|
|
4068
|
-
paymentReference:
|
|
4069
|
-
payerUserId:
|
|
4070
|
-
payeeUserId:
|
|
4071
|
-
amountKobo:
|
|
4072
|
-
currency:
|
|
4073
|
-
channel:
|
|
4074
|
-
settledAtMs:
|
|
4075
|
-
ledgerTxnId:
|
|
4076
|
-
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(),
|
|
4077
4584
|
hashChainPrev: HexString(32).optional()
|
|
4078
4585
|
});
|
|
4079
|
-
var ShortId =
|
|
4080
|
-
var PositiveInt =
|
|
4081
|
-
var NonNegativeInt =
|
|
4082
|
-
var Currency2 =
|
|
4083
|
-
var Memo =
|
|
4084
|
-
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({
|
|
4085
4592
|
requestId: ShortId,
|
|
4086
4593
|
payeeUserId: ShortId,
|
|
4087
4594
|
amountKobo: PositiveInt.optional(),
|
|
@@ -4089,7 +4596,7 @@ var NqrPaymentRequestArtifactSchema = import_zod16.z.object({
|
|
|
4089
4596
|
memo: Memo.optional(),
|
|
4090
4597
|
expiresAtMs: PositiveInt.optional()
|
|
4091
4598
|
});
|
|
4092
|
-
var PaymentIntentArtifactSchema =
|
|
4599
|
+
var PaymentIntentArtifactSchema = import_zod17.z.object({
|
|
4093
4600
|
intentId: ShortId,
|
|
4094
4601
|
payerUserId: ShortId,
|
|
4095
4602
|
payeeUserId: ShortId,
|
|
@@ -4098,7 +4605,7 @@ var PaymentIntentArtifactSchema = import_zod16.z.object({
|
|
|
4098
4605
|
idempotencyKey: ShortId,
|
|
4099
4606
|
createdAtMs: PositiveInt
|
|
4100
4607
|
});
|
|
4101
|
-
var OfflineClaimArtifactSchema =
|
|
4608
|
+
var OfflineClaimArtifactSchema = import_zod17.z.object({
|
|
4102
4609
|
claimId: ShortId,
|
|
4103
4610
|
authorizationId: ShortId,
|
|
4104
4611
|
payeeUserId: ShortId,
|
|
@@ -4107,10 +4614,10 @@ var OfflineClaimArtifactSchema = import_zod16.z.object({
|
|
|
4107
4614
|
claimedAtMs: PositiveInt,
|
|
4108
4615
|
paymentReference: ShortId.optional()
|
|
4109
4616
|
});
|
|
4110
|
-
var SettlementRecordArtifactSchema =
|
|
4617
|
+
var SettlementRecordArtifactSchema = import_zod17.z.object({
|
|
4111
4618
|
settlementId: ShortId,
|
|
4112
4619
|
ledgerTxnId: ShortId,
|
|
4113
|
-
sourceRefType:
|
|
4620
|
+
sourceRefType: import_zod17.z.enum([
|
|
4114
4621
|
"offline_authorization",
|
|
4115
4622
|
"offline_claim",
|
|
4116
4623
|
"transfer",
|
|
@@ -4121,12 +4628,12 @@ var SettlementRecordArtifactSchema = import_zod16.z.object({
|
|
|
4121
4628
|
currency: Currency2,
|
|
4122
4629
|
settledAtMs: PositiveInt
|
|
4123
4630
|
});
|
|
4124
|
-
var ReversalRecordArtifactSchema =
|
|
4631
|
+
var ReversalRecordArtifactSchema = import_zod17.z.object({
|
|
4125
4632
|
reversalId: ShortId,
|
|
4126
4633
|
originalTxnId: ShortId,
|
|
4127
4634
|
amountKobo: PositiveInt,
|
|
4128
4635
|
currency: Currency2,
|
|
4129
|
-
reason:
|
|
4636
|
+
reason: import_zod17.z.enum([
|
|
4130
4637
|
"user_dispute",
|
|
4131
4638
|
"fraud",
|
|
4132
4639
|
"duplicate",
|
|
@@ -4136,7 +4643,7 @@ var ReversalRecordArtifactSchema = import_zod16.z.object({
|
|
|
4136
4643
|
reversedAtMs: PositiveInt,
|
|
4137
4644
|
memo: Memo.optional()
|
|
4138
4645
|
});
|
|
4139
|
-
var LedgerJournalEntryArtifactSchema =
|
|
4646
|
+
var LedgerJournalEntryArtifactSchema = import_zod17.z.object({
|
|
4140
4647
|
entryId: ShortId,
|
|
4141
4648
|
journalId: ShortId,
|
|
4142
4649
|
debitAccountId: ShortId,
|
|
@@ -4147,13 +4654,13 @@ var LedgerJournalEntryArtifactSchema = import_zod16.z.object({
|
|
|
4147
4654
|
refType: ShortId.optional(),
|
|
4148
4655
|
refId: ShortId.optional()
|
|
4149
4656
|
});
|
|
4150
|
-
var StatementArtifactSchema =
|
|
4657
|
+
var StatementArtifactSchema = import_zod17.z.object({
|
|
4151
4658
|
statementId: ShortId,
|
|
4152
4659
|
userId: ShortId,
|
|
4153
4660
|
periodStartMs: PositiveInt,
|
|
4154
4661
|
periodEndMs: PositiveInt,
|
|
4155
|
-
openingBalanceKobo:
|
|
4156
|
-
closingBalanceKobo:
|
|
4662
|
+
openingBalanceKobo: import_zod17.z.number().int(),
|
|
4663
|
+
closingBalanceKobo: import_zod17.z.number().int(),
|
|
4157
4664
|
transactionCount: NonNegativeInt,
|
|
4158
4665
|
currency: Currency2,
|
|
4159
4666
|
hashChainPrev: HexString(32).optional()
|
|
@@ -4161,16 +4668,16 @@ var StatementArtifactSchema = import_zod16.z.object({
|
|
|
4161
4668
|
message: "periodEndMs must be greater than periodStartMs",
|
|
4162
4669
|
path: ["periodEndMs"]
|
|
4163
4670
|
});
|
|
4164
|
-
var PassArtifactSchema =
|
|
4671
|
+
var PassArtifactSchema = import_zod17.z.object({
|
|
4165
4672
|
passId: ShortId,
|
|
4166
4673
|
holderId: ShortId,
|
|
4167
|
-
category:
|
|
4168
|
-
title:
|
|
4674
|
+
category: import_zod17.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
|
|
4675
|
+
title: import_zod17.z.string().min(1).max(120),
|
|
4169
4676
|
validFromMs: PositiveInt,
|
|
4170
4677
|
validUntilMs: PositiveInt.optional(),
|
|
4171
|
-
metadata:
|
|
4172
|
-
|
|
4173
|
-
|
|
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()])
|
|
4174
4681
|
).optional()
|
|
4175
4682
|
}).refine(
|
|
4176
4683
|
(v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
|
|
@@ -4179,10 +4686,10 @@ var PassArtifactSchema = import_zod16.z.object({
|
|
|
4179
4686
|
path: ["validUntilMs"]
|
|
4180
4687
|
}
|
|
4181
4688
|
);
|
|
4182
|
-
var IdentityArtifactSchema =
|
|
4689
|
+
var IdentityArtifactSchema = import_zod17.z.object({
|
|
4183
4690
|
attestationId: ShortId,
|
|
4184
4691
|
subjectId: ShortId,
|
|
4185
|
-
claimType:
|
|
4692
|
+
claimType: import_zod17.z.enum([
|
|
4186
4693
|
"phone_verified",
|
|
4187
4694
|
"email_verified",
|
|
4188
4695
|
"bvn_verified",
|
|
@@ -4318,6 +4825,9 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4318
4825
|
COLLECTION_INTENT_STATUSES,
|
|
4319
4826
|
COLLECTION_PAYMENT_STATUSES,
|
|
4320
4827
|
CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
|
|
4828
|
+
CONSUMER_PAYMENT_REQUEST_DOMAIN,
|
|
4829
|
+
CONSUMER_SETTLEMENT_DOMAIN,
|
|
4830
|
+
CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX,
|
|
4321
4831
|
CUSTODIAL_MODES,
|
|
4322
4832
|
CollectionIntentSchema,
|
|
4323
4833
|
CollectionPaymentResultSchema,
|
|
@@ -4327,6 +4837,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4327
4837
|
ConsumerOACRecordSchema,
|
|
4328
4838
|
ConsumerOACSchema,
|
|
4329
4839
|
ConsumerPaymentClaimSchema,
|
|
4840
|
+
ConsumerPaymentRequestEnvelopeSchema,
|
|
4330
4841
|
ConsumerSettleResultSchema,
|
|
4331
4842
|
ConsumerSettlementSchema,
|
|
4332
4843
|
CreateCollectionIntentInputSchema,
|
|
@@ -4368,6 +4879,12 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4368
4879
|
OAC_DEFAULT_PER_TX_KOBO,
|
|
4369
4880
|
OAC_DEFAULT_VALIDITY_MS,
|
|
4370
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,
|
|
4371
4888
|
OfflineClaimArtifactSchema,
|
|
4372
4889
|
OfflinePaymentAuthorizationArtifactSchema,
|
|
4373
4890
|
OfflinePaymentAuthorizationSchema,
|
|
@@ -4427,18 +4944,25 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4427
4944
|
bodySha256Hex,
|
|
4428
4945
|
buildArtifactBody,
|
|
4429
4946
|
buildAuthorization,
|
|
4947
|
+
buildConsumerPaymentRequest,
|
|
4430
4948
|
buildOAC,
|
|
4431
4949
|
buildPass,
|
|
4432
4950
|
buildPaymentRequest,
|
|
4433
4951
|
buildReceipt,
|
|
4434
4952
|
buildRedemption,
|
|
4953
|
+
buildSmsSettleHeader,
|
|
4954
|
+
buildSmsSettleSignedBytes,
|
|
4435
4955
|
canonicalClaimSigningBytes,
|
|
4436
4956
|
canonicalClaimSigningPayload,
|
|
4437
4957
|
canonicalJSONBytes,
|
|
4438
4958
|
canonicalJSONStringify,
|
|
4439
4959
|
canonicalRequestString,
|
|
4960
|
+
computeConsumerClaimEncounterId,
|
|
4440
4961
|
computeEncounterId,
|
|
4441
4962
|
constantTimeEqual,
|
|
4963
|
+
consumerPaymentRequestSigningBytes,
|
|
4964
|
+
consumerPaymentRequestSigningPayload,
|
|
4965
|
+
consumerSettlementSigningPayload,
|
|
4442
4966
|
crc16ccitt,
|
|
4443
4967
|
crc16ccittHex,
|
|
4444
4968
|
createAccountsClient,
|
|
@@ -4462,19 +4986,27 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4462
4986
|
decodeArtifactUri,
|
|
4463
4987
|
decodeAuthorizationQR,
|
|
4464
4988
|
decodeBase45,
|
|
4989
|
+
decodeConsumerSettlementReceiptQR,
|
|
4465
4990
|
decodeOfflineClaimSmsMessage,
|
|
4991
|
+
decodeOfflineSmsSettleToken,
|
|
4466
4992
|
decodePaymentRequestQR,
|
|
4993
|
+
decodeUnverifiedConsumerSettlementReceiptQR,
|
|
4994
|
+
derToRawP256Signature,
|
|
4467
4995
|
encodeArtifactUri,
|
|
4468
4996
|
encodeAuthorizationQR,
|
|
4469
4997
|
encodeBase45,
|
|
4998
|
+
encodeConsumerSettlementReceiptQR,
|
|
4470
4999
|
encodeNQR,
|
|
4471
5000
|
encodeOfflineClaimSmsMessage,
|
|
5001
|
+
encodeOfflineSmsSettleToken,
|
|
4472
5002
|
encodePaymentRequestQR,
|
|
4473
5003
|
extractOfflineClaimSmsToken,
|
|
5004
|
+
extractOfflineSmsSettleToken,
|
|
4474
5005
|
formatAmount,
|
|
4475
5006
|
generateDynamicQR,
|
|
4476
5007
|
generateStaticQR,
|
|
4477
5008
|
init,
|
|
5009
|
+
isConsumerPaymentRequestExpired,
|
|
4478
5010
|
isHardenedArtifactType,
|
|
4479
5011
|
isKnownArtifactType,
|
|
4480
5012
|
isPassWithinValidity,
|
|
@@ -4487,6 +5019,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4487
5019
|
routingHint,
|
|
4488
5020
|
signArtifact,
|
|
4489
5021
|
signAuthorization,
|
|
5022
|
+
signConsumerPaymentRequest,
|
|
4490
5023
|
signOAC,
|
|
4491
5024
|
signPartnerRequest,
|
|
4492
5025
|
signPass,
|
|
@@ -4498,7 +5031,11 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4498
5031
|
verifyArtifactUri,
|
|
4499
5032
|
verifyAuthorization,
|
|
4500
5033
|
verifyClaimSignature,
|
|
5034
|
+
verifyConsumerPaymentRequest,
|
|
5035
|
+
verifyConsumerSettlement,
|
|
5036
|
+
verifyConsumerSettlementReceiptQR,
|
|
4501
5037
|
verifyOAC,
|
|
5038
|
+
verifyOfflineSmsSettleToken,
|
|
4502
5039
|
verifyPass,
|
|
4503
5040
|
verifyPaymentRequest,
|
|
4504
5041
|
verifyReceipt,
|