@nokinc-flur/sdk 1.0.6 → 1.1.1
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 +474 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1522 -1
- package/dist/index.d.ts +1522 -1
- package/dist/index.js +442 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -152,6 +152,13 @@ var AccountActivityItemSchema = z.object({
|
|
|
152
152
|
timestamp: IsoDateSchema
|
|
153
153
|
});
|
|
154
154
|
var AccountSummaryResponseSchema = z.object({
|
|
155
|
+
/** Authenticated user's stable internal id. */
|
|
156
|
+
userId: UuidSchema,
|
|
157
|
+
/**
|
|
158
|
+
* 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
|
|
159
|
+
* bank partner. `null` when the user has no partner-allocated account yet.
|
|
160
|
+
*/
|
|
161
|
+
nuban: z.string().regex(/^[0-9]{10}$/).nullable(),
|
|
155
162
|
balance: z.number().int(),
|
|
156
163
|
currency: CurrencySchema,
|
|
157
164
|
dailySendLimit: z.number().int().nonnegative(),
|
|
@@ -3475,13 +3482,419 @@ function createPartnerProfileAdminClient(opts) {
|
|
|
3475
3482
|
}
|
|
3476
3483
|
};
|
|
3477
3484
|
}
|
|
3485
|
+
|
|
3486
|
+
// src/artifacts/envelope.ts
|
|
3487
|
+
import { z as z15 } from "zod";
|
|
3488
|
+
var FLUR_ARTIFACT_URI_SCHEME = "flur";
|
|
3489
|
+
var FLUR_ARTIFACT_VERSION = 1;
|
|
3490
|
+
var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
|
|
3491
|
+
var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
|
|
3492
|
+
var ArtifactHeaderSchema = z15.object({
|
|
3493
|
+
v: z15.literal(FLUR_ARTIFACT_VERSION),
|
|
3494
|
+
t: z15.string().regex(ArtifactTypeRe, "invalid artifact type"),
|
|
3495
|
+
iss: z15.string().min(1).max(128),
|
|
3496
|
+
kid: z15.string().min(1).max(128),
|
|
3497
|
+
iat: z15.number().int().nonnegative(),
|
|
3498
|
+
exp: z15.number().int().positive().optional(),
|
|
3499
|
+
nonce: z15.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
|
|
3500
|
+
});
|
|
3501
|
+
var FlurArtifactError = class extends Error {
|
|
3502
|
+
constructor(message, code) {
|
|
3503
|
+
super(message);
|
|
3504
|
+
this.code = code;
|
|
3505
|
+
this.name = "FlurArtifactError";
|
|
3506
|
+
}
|
|
3507
|
+
code;
|
|
3508
|
+
};
|
|
3509
|
+
function base64UrlEncode(bytes) {
|
|
3510
|
+
let bin = "";
|
|
3511
|
+
for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
|
|
3512
|
+
const b64 = typeof btoa === "function" ? btoa(bin) : Buffer.from(bytes).toString("base64");
|
|
3513
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
3514
|
+
}
|
|
3515
|
+
function base64UrlDecode(s) {
|
|
3516
|
+
const pad = s.length % 4 === 0 ? "" : "=".repeat(4 - s.length % 4);
|
|
3517
|
+
const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + pad;
|
|
3518
|
+
if (typeof atob === "function") {
|
|
3519
|
+
const bin = atob(b64);
|
|
3520
|
+
const out = new Uint8Array(bin.length);
|
|
3521
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
3522
|
+
return out;
|
|
3523
|
+
}
|
|
3524
|
+
return new Uint8Array(Buffer.from(b64, "base64"));
|
|
3525
|
+
}
|
|
3526
|
+
function buildArtifactBody(input) {
|
|
3527
|
+
if (!ArtifactTypeRe.test(input.type)) {
|
|
3528
|
+
throw new FlurArtifactError(
|
|
3529
|
+
`Invalid artifact type: ${input.type}`,
|
|
3530
|
+
"INVALID_TYPE"
|
|
3531
|
+
);
|
|
3532
|
+
}
|
|
3533
|
+
const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
|
|
3534
|
+
const header = {
|
|
3535
|
+
v: FLUR_ARTIFACT_VERSION,
|
|
3536
|
+
t: input.type,
|
|
3537
|
+
iss: input.issuer,
|
|
3538
|
+
kid: input.keyId,
|
|
3539
|
+
iat,
|
|
3540
|
+
...input.expiresAtSeconds !== void 0 ? { exp: input.expiresAtSeconds } : {},
|
|
3541
|
+
nonce: input.nonce
|
|
3542
|
+
};
|
|
3543
|
+
ArtifactHeaderSchema.parse(header);
|
|
3544
|
+
return { ...header, data: input.data };
|
|
3545
|
+
}
|
|
3546
|
+
function signArtifact(body, privateKey) {
|
|
3547
|
+
const sig = bytesToHex(sign(canonicalJSONBytes(body), privateKey));
|
|
3548
|
+
return { body, sig };
|
|
3549
|
+
}
|
|
3550
|
+
function encodeArtifactUri(signed) {
|
|
3551
|
+
const bodyBytes = canonicalJSONBytes(signed.body);
|
|
3552
|
+
const bodyB64 = base64UrlEncode(bodyBytes);
|
|
3553
|
+
const sigB64 = base64UrlEncode(hexToBytes(signed.sig));
|
|
3554
|
+
return `${FLUR_ARTIFACT_URI_PREFIX}${signed.body.t}/${bodyB64}.${sigB64}`;
|
|
3555
|
+
}
|
|
3556
|
+
function decodeArtifactUri(uri) {
|
|
3557
|
+
if (!uri.startsWith(FLUR_ARTIFACT_URI_PREFIX)) {
|
|
3558
|
+
throw new FlurArtifactError(
|
|
3559
|
+
`URI does not start with ${FLUR_ARTIFACT_URI_PREFIX}`,
|
|
3560
|
+
"INVALID_URI"
|
|
3561
|
+
);
|
|
3562
|
+
}
|
|
3563
|
+
const rest = uri.slice(FLUR_ARTIFACT_URI_PREFIX.length);
|
|
3564
|
+
const slash = rest.indexOf("/");
|
|
3565
|
+
if (slash <= 0) {
|
|
3566
|
+
throw new FlurArtifactError("Missing artifact type segment", "INVALID_URI");
|
|
3567
|
+
}
|
|
3568
|
+
const type = rest.slice(0, slash);
|
|
3569
|
+
const payload = rest.slice(slash + 1);
|
|
3570
|
+
const dot = payload.indexOf(".");
|
|
3571
|
+
if (dot <= 0 || dot === payload.length - 1) {
|
|
3572
|
+
throw new FlurArtifactError(
|
|
3573
|
+
"Missing body/signature separator",
|
|
3574
|
+
"INVALID_URI"
|
|
3575
|
+
);
|
|
3576
|
+
}
|
|
3577
|
+
if (!ArtifactTypeRe.test(type)) {
|
|
3578
|
+
throw new FlurArtifactError(
|
|
3579
|
+
`Invalid artifact type: ${type}`,
|
|
3580
|
+
"INVALID_TYPE"
|
|
3581
|
+
);
|
|
3582
|
+
}
|
|
3583
|
+
const bodyBytes = base64UrlDecode(payload.slice(0, dot));
|
|
3584
|
+
const sigBytes = base64UrlDecode(payload.slice(dot + 1));
|
|
3585
|
+
if (sigBytes.length !== 64) {
|
|
3586
|
+
throw new FlurArtifactError(
|
|
3587
|
+
`Signature must be 64 bytes, got ${sigBytes.length}`,
|
|
3588
|
+
"INVALID_SIGNATURE"
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
let bodyJson;
|
|
3592
|
+
try {
|
|
3593
|
+
bodyJson = JSON.parse(new TextDecoder().decode(bodyBytes));
|
|
3594
|
+
} catch {
|
|
3595
|
+
throw new FlurArtifactError("Body is not valid JSON", "INVALID_BODY");
|
|
3596
|
+
}
|
|
3597
|
+
const headerOnly = ArtifactHeaderSchema.safeParse(bodyJson);
|
|
3598
|
+
if (!headerOnly.success) {
|
|
3599
|
+
throw new FlurArtifactError(
|
|
3600
|
+
`Body header invalid: ${headerOnly.error.message}`,
|
|
3601
|
+
"INVALID_BODY"
|
|
3602
|
+
);
|
|
3603
|
+
}
|
|
3604
|
+
if (headerOnly.data.t !== type) {
|
|
3605
|
+
throw new FlurArtifactError(
|
|
3606
|
+
`URI type ${type} does not match body type ${headerOnly.data.t}`,
|
|
3607
|
+
"TYPE_MISMATCH"
|
|
3608
|
+
);
|
|
3609
|
+
}
|
|
3610
|
+
return {
|
|
3611
|
+
type,
|
|
3612
|
+
bodyBytes,
|
|
3613
|
+
body: bodyJson,
|
|
3614
|
+
sig: bytesToHex(sigBytes)
|
|
3615
|
+
};
|
|
3616
|
+
}
|
|
3617
|
+
function verifyArtifactSignature(decoded, publicKey, options = {}) {
|
|
3618
|
+
if (options.enforceExpiry !== false && decoded.body.exp !== void 0) {
|
|
3619
|
+
const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
3620
|
+
if (decoded.body.exp < now) {
|
|
3621
|
+
throw new FlurArtifactError("Artifact has expired", "EXPIRED");
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
return verify(decoded.bodyBytes, hexToBytes(decoded.sig), publicKey);
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
// src/artifacts/types.ts
|
|
3628
|
+
import { z as z16 } from "zod";
|
|
3629
|
+
var ARTIFACT_TYPES = {
|
|
3630
|
+
OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
|
|
3631
|
+
RECEIPT: "receipt",
|
|
3632
|
+
// --- stubs, schemas to be hardened in follow-ups ---
|
|
3633
|
+
NQR_PAYMENT_REQUEST: "nqr_payment_request",
|
|
3634
|
+
PAYMENT_INTENT: "payment_intent",
|
|
3635
|
+
OFFLINE_CLAIM: "offline_claim",
|
|
3636
|
+
SETTLEMENT_RECORD: "settlement_record",
|
|
3637
|
+
REVERSAL_RECORD: "reversal_record",
|
|
3638
|
+
LEDGER_JOURNAL_ENTRY: "ledger_journal_entry",
|
|
3639
|
+
STATEMENT: "statement",
|
|
3640
|
+
PASS: "pass",
|
|
3641
|
+
IDENTITY: "identity"
|
|
3642
|
+
};
|
|
3643
|
+
var HexString4 = (length) => z16.string().regex(
|
|
3644
|
+
new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
|
|
3645
|
+
`expected ${length}-byte hex string`
|
|
3646
|
+
);
|
|
3647
|
+
var OfflinePaymentAuthorizationArtifactSchema = z16.object({
|
|
3648
|
+
authorization: OfflinePaymentAuthorizationSchema
|
|
3649
|
+
});
|
|
3650
|
+
var ReceiptArtifactSchema = z16.object({
|
|
3651
|
+
receiptId: z16.string().min(1).max(64),
|
|
3652
|
+
paymentReference: z16.string().min(1).max(64),
|
|
3653
|
+
payerUserId: z16.string().min(1).max(64).optional(),
|
|
3654
|
+
payeeUserId: z16.string().min(1).max(64),
|
|
3655
|
+
amountKobo: z16.number().int().positive(),
|
|
3656
|
+
currency: z16.literal("NGN"),
|
|
3657
|
+
channel: z16.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
|
|
3658
|
+
settledAtMs: z16.number().int().positive(),
|
|
3659
|
+
ledgerTxnId: z16.string().min(1).max(64).optional(),
|
|
3660
|
+
memo: z16.string().max(140).optional(),
|
|
3661
|
+
hashChainPrev: HexString4(32).optional()
|
|
3662
|
+
});
|
|
3663
|
+
var ShortId = z16.string().min(1).max(64);
|
|
3664
|
+
var PositiveInt = z16.number().int().positive();
|
|
3665
|
+
var NonNegativeInt = z16.number().int().nonnegative();
|
|
3666
|
+
var Currency2 = z16.literal("NGN");
|
|
3667
|
+
var Memo = z16.string().max(140);
|
|
3668
|
+
var NqrPaymentRequestArtifactSchema = z16.object({
|
|
3669
|
+
requestId: ShortId,
|
|
3670
|
+
payeeUserId: ShortId,
|
|
3671
|
+
amountKobo: PositiveInt.optional(),
|
|
3672
|
+
currency: Currency2,
|
|
3673
|
+
memo: Memo.optional(),
|
|
3674
|
+
expiresAtMs: PositiveInt.optional()
|
|
3675
|
+
});
|
|
3676
|
+
var PaymentIntentArtifactSchema = z16.object({
|
|
3677
|
+
intentId: ShortId,
|
|
3678
|
+
payerUserId: ShortId,
|
|
3679
|
+
payeeUserId: ShortId,
|
|
3680
|
+
amountKobo: PositiveInt,
|
|
3681
|
+
currency: Currency2,
|
|
3682
|
+
idempotencyKey: ShortId,
|
|
3683
|
+
createdAtMs: PositiveInt
|
|
3684
|
+
});
|
|
3685
|
+
var OfflineClaimArtifactSchema = z16.object({
|
|
3686
|
+
claimId: ShortId,
|
|
3687
|
+
authorizationId: ShortId,
|
|
3688
|
+
payeeUserId: ShortId,
|
|
3689
|
+
claimedAmountKobo: PositiveInt,
|
|
3690
|
+
currency: Currency2,
|
|
3691
|
+
claimedAtMs: PositiveInt,
|
|
3692
|
+
paymentReference: ShortId.optional()
|
|
3693
|
+
});
|
|
3694
|
+
var SettlementRecordArtifactSchema = z16.object({
|
|
3695
|
+
settlementId: ShortId,
|
|
3696
|
+
ledgerTxnId: ShortId,
|
|
3697
|
+
sourceRefType: z16.enum([
|
|
3698
|
+
"offline_authorization",
|
|
3699
|
+
"offline_claim",
|
|
3700
|
+
"transfer",
|
|
3701
|
+
"pay_link"
|
|
3702
|
+
]),
|
|
3703
|
+
sourceRefId: ShortId,
|
|
3704
|
+
amountKobo: PositiveInt,
|
|
3705
|
+
currency: Currency2,
|
|
3706
|
+
settledAtMs: PositiveInt
|
|
3707
|
+
});
|
|
3708
|
+
var ReversalRecordArtifactSchema = z16.object({
|
|
3709
|
+
reversalId: ShortId,
|
|
3710
|
+
originalTxnId: ShortId,
|
|
3711
|
+
amountKobo: PositiveInt,
|
|
3712
|
+
currency: Currency2,
|
|
3713
|
+
reason: z16.enum([
|
|
3714
|
+
"user_dispute",
|
|
3715
|
+
"fraud",
|
|
3716
|
+
"duplicate",
|
|
3717
|
+
"admin_correction",
|
|
3718
|
+
"other"
|
|
3719
|
+
]),
|
|
3720
|
+
reversedAtMs: PositiveInt,
|
|
3721
|
+
memo: Memo.optional()
|
|
3722
|
+
});
|
|
3723
|
+
var LedgerJournalEntryArtifactSchema = z16.object({
|
|
3724
|
+
entryId: ShortId,
|
|
3725
|
+
journalId: ShortId,
|
|
3726
|
+
debitAccountId: ShortId,
|
|
3727
|
+
creditAccountId: ShortId,
|
|
3728
|
+
amountKobo: PositiveInt,
|
|
3729
|
+
currency: Currency2,
|
|
3730
|
+
postedAtMs: PositiveInt,
|
|
3731
|
+
refType: ShortId.optional(),
|
|
3732
|
+
refId: ShortId.optional()
|
|
3733
|
+
});
|
|
3734
|
+
var StatementArtifactSchema = z16.object({
|
|
3735
|
+
statementId: ShortId,
|
|
3736
|
+
userId: ShortId,
|
|
3737
|
+
periodStartMs: PositiveInt,
|
|
3738
|
+
periodEndMs: PositiveInt,
|
|
3739
|
+
openingBalanceKobo: z16.number().int(),
|
|
3740
|
+
closingBalanceKobo: z16.number().int(),
|
|
3741
|
+
transactionCount: NonNegativeInt,
|
|
3742
|
+
currency: Currency2,
|
|
3743
|
+
hashChainPrev: HexString4(32).optional()
|
|
3744
|
+
}).refine((v) => v.periodEndMs > v.periodStartMs, {
|
|
3745
|
+
message: "periodEndMs must be greater than periodStartMs",
|
|
3746
|
+
path: ["periodEndMs"]
|
|
3747
|
+
});
|
|
3748
|
+
var PassArtifactSchema = z16.object({
|
|
3749
|
+
passId: ShortId,
|
|
3750
|
+
holderId: ShortId,
|
|
3751
|
+
category: z16.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
|
|
3752
|
+
title: z16.string().min(1).max(120),
|
|
3753
|
+
validFromMs: PositiveInt,
|
|
3754
|
+
validUntilMs: PositiveInt.optional(),
|
|
3755
|
+
metadata: z16.record(
|
|
3756
|
+
z16.string().min(1).max(64),
|
|
3757
|
+
z16.union([z16.string().max(280), z16.number(), z16.boolean()])
|
|
3758
|
+
).optional()
|
|
3759
|
+
}).refine(
|
|
3760
|
+
(v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
|
|
3761
|
+
{
|
|
3762
|
+
message: "validUntilMs must be greater than validFromMs",
|
|
3763
|
+
path: ["validUntilMs"]
|
|
3764
|
+
}
|
|
3765
|
+
);
|
|
3766
|
+
var IdentityArtifactSchema = z16.object({
|
|
3767
|
+
attestationId: ShortId,
|
|
3768
|
+
subjectId: ShortId,
|
|
3769
|
+
claimType: z16.enum([
|
|
3770
|
+
"phone_verified",
|
|
3771
|
+
"email_verified",
|
|
3772
|
+
"bvn_verified",
|
|
3773
|
+
"kyc_tier",
|
|
3774
|
+
"age_band"
|
|
3775
|
+
]),
|
|
3776
|
+
claimValueHash: HexString4(32),
|
|
3777
|
+
attestedAtMs: PositiveInt
|
|
3778
|
+
});
|
|
3779
|
+
var ARTIFACT_BODY_SCHEMAS = {
|
|
3780
|
+
[ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]: OfflinePaymentAuthorizationArtifactSchema,
|
|
3781
|
+
[ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,
|
|
3782
|
+
[ARTIFACT_TYPES.NQR_PAYMENT_REQUEST]: NqrPaymentRequestArtifactSchema,
|
|
3783
|
+
[ARTIFACT_TYPES.PAYMENT_INTENT]: PaymentIntentArtifactSchema,
|
|
3784
|
+
[ARTIFACT_TYPES.OFFLINE_CLAIM]: OfflineClaimArtifactSchema,
|
|
3785
|
+
[ARTIFACT_TYPES.SETTLEMENT_RECORD]: SettlementRecordArtifactSchema,
|
|
3786
|
+
[ARTIFACT_TYPES.REVERSAL_RECORD]: ReversalRecordArtifactSchema,
|
|
3787
|
+
[ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,
|
|
3788
|
+
[ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,
|
|
3789
|
+
[ARTIFACT_TYPES.PASS]: PassArtifactSchema,
|
|
3790
|
+
[ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
|
|
3791
|
+
};
|
|
3792
|
+
var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
3793
|
+
ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,
|
|
3794
|
+
ARTIFACT_TYPES.RECEIPT,
|
|
3795
|
+
ARTIFACT_TYPES.NQR_PAYMENT_REQUEST,
|
|
3796
|
+
ARTIFACT_TYPES.PAYMENT_INTENT,
|
|
3797
|
+
ARTIFACT_TYPES.OFFLINE_CLAIM,
|
|
3798
|
+
ARTIFACT_TYPES.SETTLEMENT_RECORD,
|
|
3799
|
+
ARTIFACT_TYPES.REVERSAL_RECORD,
|
|
3800
|
+
ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,
|
|
3801
|
+
ARTIFACT_TYPES.STATEMENT,
|
|
3802
|
+
ARTIFACT_TYPES.PASS,
|
|
3803
|
+
ARTIFACT_TYPES.IDENTITY
|
|
3804
|
+
]);
|
|
3805
|
+
function isKnownArtifactType(t) {
|
|
3806
|
+
return Object.values(ARTIFACT_TYPES).includes(t);
|
|
3807
|
+
}
|
|
3808
|
+
function isHardenedArtifactType(t) {
|
|
3809
|
+
return HARDENED_ARTIFACT_TYPES.has(t);
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
// src/artifacts/codec.ts
|
|
3813
|
+
function createArtifactUri(input) {
|
|
3814
|
+
if (!isKnownArtifactType(input.type)) {
|
|
3815
|
+
throw new FlurArtifactError(
|
|
3816
|
+
`Unknown artifact type: ${input.type}`,
|
|
3817
|
+
"INVALID_TYPE"
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3820
|
+
if (!isHardenedArtifactType(input.type)) {
|
|
3821
|
+
throw new FlurArtifactError(
|
|
3822
|
+
`Artifact type ${input.type} is not yet hardened for emission`,
|
|
3823
|
+
"INVALID_TYPE"
|
|
3824
|
+
);
|
|
3825
|
+
}
|
|
3826
|
+
const schema = ARTIFACT_BODY_SCHEMAS[input.type];
|
|
3827
|
+
const parsedData = schema.parse(input.data);
|
|
3828
|
+
const body = buildArtifactBody({
|
|
3829
|
+
type: input.type,
|
|
3830
|
+
issuer: input.issuer,
|
|
3831
|
+
keyId: input.keyId,
|
|
3832
|
+
data: parsedData,
|
|
3833
|
+
nonce: input.nonce,
|
|
3834
|
+
issuedAtSeconds: input.issuedAtSeconds,
|
|
3835
|
+
expiresAtSeconds: input.expiresAtSeconds
|
|
3836
|
+
});
|
|
3837
|
+
const signed = signArtifact(body, input.privateKey);
|
|
3838
|
+
return { uri: encodeArtifactUri(signed), signed };
|
|
3839
|
+
}
|
|
3840
|
+
function verifyArtifactUri(uri, publicKey, options = {}) {
|
|
3841
|
+
const decoded = decodeArtifactUri(uri);
|
|
3842
|
+
if (!isKnownArtifactType(decoded.type)) {
|
|
3843
|
+
throw new FlurArtifactError(
|
|
3844
|
+
`Unknown artifact type: ${decoded.type}`,
|
|
3845
|
+
"INVALID_TYPE"
|
|
3846
|
+
);
|
|
3847
|
+
}
|
|
3848
|
+
if (!isHardenedArtifactType(decoded.type)) {
|
|
3849
|
+
throw new FlurArtifactError(
|
|
3850
|
+
`Artifact type ${decoded.type} is not yet hardened for verification`,
|
|
3851
|
+
"INVALID_TYPE"
|
|
3852
|
+
);
|
|
3853
|
+
}
|
|
3854
|
+
const schema = ARTIFACT_BODY_SCHEMAS[decoded.type];
|
|
3855
|
+
const dataParsed = schema.safeParse(decoded.body.data);
|
|
3856
|
+
if (!dataParsed.success) {
|
|
3857
|
+
throw new FlurArtifactError(
|
|
3858
|
+
`Artifact body invalid: ${dataParsed.error.message}`,
|
|
3859
|
+
"INVALID_BODY"
|
|
3860
|
+
);
|
|
3861
|
+
}
|
|
3862
|
+
const ok = verifyArtifactSignature(decoded, publicKey, options);
|
|
3863
|
+
if (!ok) {
|
|
3864
|
+
throw new FlurArtifactError(
|
|
3865
|
+
"Artifact signature verification failed",
|
|
3866
|
+
"INVALID_SIGNATURE"
|
|
3867
|
+
);
|
|
3868
|
+
}
|
|
3869
|
+
return {
|
|
3870
|
+
type: decoded.type,
|
|
3871
|
+
body: decoded.body,
|
|
3872
|
+
sig: decoded.sig,
|
|
3873
|
+
decoded
|
|
3874
|
+
};
|
|
3875
|
+
}
|
|
3876
|
+
function createReceiptArtifactUri(input) {
|
|
3877
|
+
return createArtifactUri({
|
|
3878
|
+
...input,
|
|
3879
|
+
type: ARTIFACT_TYPES.RECEIPT
|
|
3880
|
+
});
|
|
3881
|
+
}
|
|
3882
|
+
function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
3883
|
+
return createArtifactUri({
|
|
3884
|
+
...input,
|
|
3885
|
+
type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION
|
|
3886
|
+
});
|
|
3887
|
+
}
|
|
3478
3888
|
export {
|
|
3479
3889
|
ACCOUNT_STATUSES,
|
|
3480
3890
|
ACCOUNT_TYPES,
|
|
3481
3891
|
ADDITIONAL_DATA_SUBFIELD,
|
|
3892
|
+
ARTIFACT_BODY_SCHEMAS,
|
|
3893
|
+
ARTIFACT_TYPES,
|
|
3482
3894
|
AccountMembershipSchema,
|
|
3483
3895
|
AccountSchema,
|
|
3484
3896
|
ApiCredentialPublicSchema,
|
|
3897
|
+
ArtifactHeaderSchema,
|
|
3485
3898
|
COLLECTION_INTENT_STATUSES,
|
|
3486
3899
|
COLLECTION_PAYMENT_STATUSES,
|
|
3487
3900
|
CUSTODIAL_MODES,
|
|
@@ -3506,14 +3919,21 @@ export {
|
|
|
3506
3919
|
EnableOfflineInputSchema,
|
|
3507
3920
|
EnableOfflineResultSchema,
|
|
3508
3921
|
FIELD,
|
|
3922
|
+
FLUR_ARTIFACT_URI_PREFIX,
|
|
3923
|
+
FLUR_ARTIFACT_URI_SCHEME,
|
|
3924
|
+
FLUR_ARTIFACT_VERSION,
|
|
3509
3925
|
FlurApiError,
|
|
3926
|
+
FlurArtifactError,
|
|
3510
3927
|
FlurCapExceededError,
|
|
3511
3928
|
FlurClient,
|
|
3512
3929
|
FlurError,
|
|
3513
3930
|
FlurExpiredError,
|
|
3514
3931
|
FlurReplayError,
|
|
3932
|
+
HARDENED_ARTIFACT_TYPES,
|
|
3933
|
+
IdentityArtifactSchema,
|
|
3515
3934
|
IngestFundingResultSchema,
|
|
3516
3935
|
IssueOACInputSchema,
|
|
3936
|
+
LedgerJournalEntryArtifactSchema,
|
|
3517
3937
|
ListPayoutDestinationsResultSchema,
|
|
3518
3938
|
MEMBERSHIP_ROLES,
|
|
3519
3939
|
MERCHANT_PAYOUT_STATUSES,
|
|
@@ -3524,11 +3944,14 @@ export {
|
|
|
3524
3944
|
NGN_CURRENCY_CODE,
|
|
3525
3945
|
NG_COUNTRY_CODE,
|
|
3526
3946
|
NQRParseError,
|
|
3947
|
+
NqrPaymentRequestArtifactSchema,
|
|
3527
3948
|
OACSchema,
|
|
3528
3949
|
OAC_DEFAULT_CUMULATIVE_KOBO,
|
|
3529
3950
|
OAC_DEFAULT_PER_TX_KOBO,
|
|
3530
3951
|
OAC_DEFAULT_VALIDITY_MS,
|
|
3952
|
+
OfflineClaimArtifactSchema,
|
|
3531
3953
|
OfflineHoldRecordSchema,
|
|
3954
|
+
OfflinePaymentAuthorizationArtifactSchema,
|
|
3532
3955
|
OfflinePaymentAuthorizationSchema,
|
|
3533
3956
|
OfflinePaymentRequestSchema,
|
|
3534
3957
|
OfflineStateResultSchema,
|
|
@@ -3547,10 +3970,12 @@ export {
|
|
|
3547
3970
|
PartnerFundingEventInputSchema,
|
|
3548
3971
|
PartnerFundingSchema,
|
|
3549
3972
|
PartnerProfileSchema,
|
|
3973
|
+
PassArtifactSchema,
|
|
3550
3974
|
PassMetadataSchema,
|
|
3551
3975
|
PassSchema,
|
|
3552
3976
|
PayCollectionInputSchema,
|
|
3553
3977
|
PaymentClaimSchema,
|
|
3978
|
+
PaymentIntentArtifactSchema,
|
|
3554
3979
|
PayoutDestinationSchema,
|
|
3555
3980
|
PayoutEventInputSchema,
|
|
3556
3981
|
ProviderEventInputSchema,
|
|
@@ -3559,22 +3984,29 @@ export {
|
|
|
3559
3984
|
RECEIPT_CHANNELS,
|
|
3560
3985
|
RECEIPT_KINDS,
|
|
3561
3986
|
REPLAY_WINDOW_MS,
|
|
3987
|
+
ReceiptArtifactSchema,
|
|
3562
3988
|
ReceiptPayloadSchema,
|
|
3563
3989
|
ReceiptSchema,
|
|
3564
3990
|
ReconciliationReportSchema,
|
|
3565
3991
|
RecordPayoutEventResultSchema,
|
|
3566
3992
|
RedemptionSchema,
|
|
3567
3993
|
RegisterDeviceKeyInputSchema,
|
|
3994
|
+
ReversalRecordArtifactSchema,
|
|
3568
3995
|
RevokeDeviceKeyInputSchema,
|
|
3569
3996
|
SETTLEMENT_SCHEDULES,
|
|
3570
3997
|
SettleResponseSchema,
|
|
3998
|
+
SettlementRecordArtifactSchema,
|
|
3571
3999
|
SettlementSchema,
|
|
3572
4000
|
SignedConsumerOACSchema,
|
|
4001
|
+
StatementArtifactSchema,
|
|
3573
4002
|
UpsertMerchantProfileInputSchema,
|
|
3574
4003
|
UpsertPartnerProfileInputSchema,
|
|
3575
4004
|
WITHDRAWAL_STATES,
|
|
3576
4005
|
WithdrawalSchema,
|
|
4006
|
+
base64UrlDecode,
|
|
4007
|
+
base64UrlEncode,
|
|
3577
4008
|
bodySha256Hex,
|
|
4009
|
+
buildArtifactBody,
|
|
3578
4010
|
buildAuthorization,
|
|
3579
4011
|
buildOAC,
|
|
3580
4012
|
buildPass,
|
|
@@ -3590,21 +4022,26 @@ export {
|
|
|
3590
4022
|
crc16ccittHex,
|
|
3591
4023
|
createAccountsClient,
|
|
3592
4024
|
createApiCredentialsAdminClient,
|
|
4025
|
+
createArtifactUri,
|
|
3593
4026
|
createCollectionsClient,
|
|
3594
4027
|
createConsumerCollectionsClient,
|
|
3595
4028
|
createConsumerWithdrawalsClient,
|
|
3596
4029
|
createFlurPartnerClient,
|
|
3597
4030
|
createHmacFetch,
|
|
3598
4031
|
createMeOfflineClient,
|
|
4032
|
+
createOfflinePaymentAuthorizationArtifactUri,
|
|
3599
4033
|
createOfflineSettlementsClient,
|
|
3600
4034
|
createPartnerCollectionsClient,
|
|
3601
4035
|
createPartnerFundingClient,
|
|
3602
4036
|
createPartnerProfileAdminClient,
|
|
3603
4037
|
createPassesClient,
|
|
4038
|
+
createReceiptArtifactUri,
|
|
3604
4039
|
createReceiptsClient,
|
|
4040
|
+
decodeArtifactUri,
|
|
3605
4041
|
decodeAuthorizationQR,
|
|
3606
4042
|
decodeBase45,
|
|
3607
4043
|
decodePaymentRequestQR,
|
|
4044
|
+
encodeArtifactUri,
|
|
3608
4045
|
encodeAuthorizationQR,
|
|
3609
4046
|
encodeBase45,
|
|
3610
4047
|
encodeNQR,
|
|
@@ -3614,6 +4051,8 @@ export {
|
|
|
3614
4051
|
generateKeyPair,
|
|
3615
4052
|
generateStaticQR,
|
|
3616
4053
|
init,
|
|
4054
|
+
isHardenedArtifactType,
|
|
4055
|
+
isKnownArtifactType,
|
|
3617
4056
|
isPassWithinValidity,
|
|
3618
4057
|
moneyMinorToNumber,
|
|
3619
4058
|
normalizeE164,
|
|
@@ -3624,6 +4063,7 @@ export {
|
|
|
3624
4063
|
readTLV,
|
|
3625
4064
|
routingHint,
|
|
3626
4065
|
sign,
|
|
4066
|
+
signArtifact,
|
|
3627
4067
|
signAuthorization,
|
|
3628
4068
|
signCanonical,
|
|
3629
4069
|
signOAC,
|
|
@@ -3634,6 +4074,8 @@ export {
|
|
|
3634
4074
|
signRedemption,
|
|
3635
4075
|
signRequestHMAC,
|
|
3636
4076
|
verify,
|
|
4077
|
+
verifyArtifactSignature,
|
|
4078
|
+
verifyArtifactUri,
|
|
3637
4079
|
verifyAuthorization,
|
|
3638
4080
|
verifyCanonical,
|
|
3639
4081
|
verifyOAC,
|