@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 CHANGED
@@ -23,9 +23,12 @@ __export(index_exports, {
23
23
  ACCOUNT_STATUSES: () => ACCOUNT_STATUSES,
24
24
  ACCOUNT_TYPES: () => ACCOUNT_TYPES,
25
25
  ADDITIONAL_DATA_SUBFIELD: () => ADDITIONAL_DATA_SUBFIELD,
26
+ ARTIFACT_BODY_SCHEMAS: () => ARTIFACT_BODY_SCHEMAS,
27
+ ARTIFACT_TYPES: () => ARTIFACT_TYPES,
26
28
  AccountMembershipSchema: () => AccountMembershipSchema,
27
29
  AccountSchema: () => AccountSchema,
28
30
  ApiCredentialPublicSchema: () => ApiCredentialPublicSchema,
31
+ ArtifactHeaderSchema: () => ArtifactHeaderSchema,
29
32
  COLLECTION_INTENT_STATUSES: () => COLLECTION_INTENT_STATUSES,
30
33
  COLLECTION_PAYMENT_STATUSES: () => COLLECTION_PAYMENT_STATUSES,
31
34
  CUSTODIAL_MODES: () => CUSTODIAL_MODES,
@@ -50,14 +53,21 @@ __export(index_exports, {
50
53
  EnableOfflineInputSchema: () => EnableOfflineInputSchema,
51
54
  EnableOfflineResultSchema: () => EnableOfflineResultSchema,
52
55
  FIELD: () => FIELD,
56
+ FLUR_ARTIFACT_URI_PREFIX: () => FLUR_ARTIFACT_URI_PREFIX,
57
+ FLUR_ARTIFACT_URI_SCHEME: () => FLUR_ARTIFACT_URI_SCHEME,
58
+ FLUR_ARTIFACT_VERSION: () => FLUR_ARTIFACT_VERSION,
53
59
  FlurApiError: () => FlurApiError,
60
+ FlurArtifactError: () => FlurArtifactError,
54
61
  FlurCapExceededError: () => FlurCapExceededError,
55
62
  FlurClient: () => FlurClient,
56
63
  FlurError: () => FlurError,
57
64
  FlurExpiredError: () => FlurExpiredError,
58
65
  FlurReplayError: () => FlurReplayError,
66
+ HARDENED_ARTIFACT_TYPES: () => HARDENED_ARTIFACT_TYPES,
67
+ IdentityArtifactSchema: () => IdentityArtifactSchema,
59
68
  IngestFundingResultSchema: () => IngestFundingResultSchema,
60
69
  IssueOACInputSchema: () => IssueOACInputSchema,
70
+ LedgerJournalEntryArtifactSchema: () => LedgerJournalEntryArtifactSchema,
61
71
  ListPayoutDestinationsResultSchema: () => ListPayoutDestinationsResultSchema,
62
72
  MEMBERSHIP_ROLES: () => MEMBERSHIP_ROLES,
63
73
  MERCHANT_PAYOUT_STATUSES: () => MERCHANT_PAYOUT_STATUSES,
@@ -68,11 +78,14 @@ __export(index_exports, {
68
78
  NGN_CURRENCY_CODE: () => NGN_CURRENCY_CODE,
69
79
  NG_COUNTRY_CODE: () => NG_COUNTRY_CODE,
70
80
  NQRParseError: () => NQRParseError,
81
+ NqrPaymentRequestArtifactSchema: () => NqrPaymentRequestArtifactSchema,
71
82
  OACSchema: () => OACSchema,
72
83
  OAC_DEFAULT_CUMULATIVE_KOBO: () => OAC_DEFAULT_CUMULATIVE_KOBO,
73
84
  OAC_DEFAULT_PER_TX_KOBO: () => OAC_DEFAULT_PER_TX_KOBO,
74
85
  OAC_DEFAULT_VALIDITY_MS: () => OAC_DEFAULT_VALIDITY_MS,
86
+ OfflineClaimArtifactSchema: () => OfflineClaimArtifactSchema,
75
87
  OfflineHoldRecordSchema: () => OfflineHoldRecordSchema,
88
+ OfflinePaymentAuthorizationArtifactSchema: () => OfflinePaymentAuthorizationArtifactSchema,
76
89
  OfflinePaymentAuthorizationSchema: () => OfflinePaymentAuthorizationSchema,
77
90
  OfflinePaymentRequestSchema: () => OfflinePaymentRequestSchema,
78
91
  OfflineStateResultSchema: () => OfflineStateResultSchema,
@@ -91,10 +104,12 @@ __export(index_exports, {
91
104
  PartnerFundingEventInputSchema: () => PartnerFundingEventInputSchema,
92
105
  PartnerFundingSchema: () => PartnerFundingSchema,
93
106
  PartnerProfileSchema: () => PartnerProfileSchema,
107
+ PassArtifactSchema: () => PassArtifactSchema,
94
108
  PassMetadataSchema: () => PassMetadataSchema,
95
109
  PassSchema: () => PassSchema,
96
110
  PayCollectionInputSchema: () => PayCollectionInputSchema,
97
111
  PaymentClaimSchema: () => PaymentClaimSchema,
112
+ PaymentIntentArtifactSchema: () => PaymentIntentArtifactSchema,
98
113
  PayoutDestinationSchema: () => PayoutDestinationSchema,
99
114
  PayoutEventInputSchema: () => PayoutEventInputSchema,
100
115
  ProviderEventInputSchema: () => ProviderEventInputSchema,
@@ -103,22 +118,29 @@ __export(index_exports, {
103
118
  RECEIPT_CHANNELS: () => RECEIPT_CHANNELS,
104
119
  RECEIPT_KINDS: () => RECEIPT_KINDS,
105
120
  REPLAY_WINDOW_MS: () => REPLAY_WINDOW_MS,
121
+ ReceiptArtifactSchema: () => ReceiptArtifactSchema,
106
122
  ReceiptPayloadSchema: () => ReceiptPayloadSchema,
107
123
  ReceiptSchema: () => ReceiptSchema,
108
124
  ReconciliationReportSchema: () => ReconciliationReportSchema,
109
125
  RecordPayoutEventResultSchema: () => RecordPayoutEventResultSchema,
110
126
  RedemptionSchema: () => RedemptionSchema,
111
127
  RegisterDeviceKeyInputSchema: () => RegisterDeviceKeyInputSchema,
128
+ ReversalRecordArtifactSchema: () => ReversalRecordArtifactSchema,
112
129
  RevokeDeviceKeyInputSchema: () => RevokeDeviceKeyInputSchema,
113
130
  SETTLEMENT_SCHEDULES: () => SETTLEMENT_SCHEDULES,
114
131
  SettleResponseSchema: () => SettleResponseSchema,
132
+ SettlementRecordArtifactSchema: () => SettlementRecordArtifactSchema,
115
133
  SettlementSchema: () => SettlementSchema,
116
134
  SignedConsumerOACSchema: () => SignedConsumerOACSchema,
135
+ StatementArtifactSchema: () => StatementArtifactSchema,
117
136
  UpsertMerchantProfileInputSchema: () => UpsertMerchantProfileInputSchema,
118
137
  UpsertPartnerProfileInputSchema: () => UpsertPartnerProfileInputSchema,
119
138
  WITHDRAWAL_STATES: () => WITHDRAWAL_STATES,
120
139
  WithdrawalSchema: () => WithdrawalSchema,
140
+ base64UrlDecode: () => base64UrlDecode,
141
+ base64UrlEncode: () => base64UrlEncode,
121
142
  bodySha256Hex: () => bodySha256Hex,
143
+ buildArtifactBody: () => buildArtifactBody,
122
144
  buildAuthorization: () => buildAuthorization,
123
145
  buildOAC: () => buildOAC,
124
146
  buildPass: () => buildPass,
@@ -134,21 +156,26 @@ __export(index_exports, {
134
156
  crc16ccittHex: () => crc16ccittHex,
135
157
  createAccountsClient: () => createAccountsClient,
136
158
  createApiCredentialsAdminClient: () => createApiCredentialsAdminClient,
159
+ createArtifactUri: () => createArtifactUri,
137
160
  createCollectionsClient: () => createCollectionsClient,
138
161
  createConsumerCollectionsClient: () => createConsumerCollectionsClient,
139
162
  createConsumerWithdrawalsClient: () => createConsumerWithdrawalsClient,
140
163
  createFlurPartnerClient: () => createFlurPartnerClient,
141
164
  createHmacFetch: () => createHmacFetch,
142
165
  createMeOfflineClient: () => createMeOfflineClient,
166
+ createOfflinePaymentAuthorizationArtifactUri: () => createOfflinePaymentAuthorizationArtifactUri,
143
167
  createOfflineSettlementsClient: () => createOfflineSettlementsClient,
144
168
  createPartnerCollectionsClient: () => createPartnerCollectionsClient,
145
169
  createPartnerFundingClient: () => createPartnerFundingClient,
146
170
  createPartnerProfileAdminClient: () => createPartnerProfileAdminClient,
147
171
  createPassesClient: () => createPassesClient,
172
+ createReceiptArtifactUri: () => createReceiptArtifactUri,
148
173
  createReceiptsClient: () => createReceiptsClient,
174
+ decodeArtifactUri: () => decodeArtifactUri,
149
175
  decodeAuthorizationQR: () => decodeAuthorizationQR,
150
176
  decodeBase45: () => decodeBase45,
151
177
  decodePaymentRequestQR: () => decodePaymentRequestQR,
178
+ encodeArtifactUri: () => encodeArtifactUri,
152
179
  encodeAuthorizationQR: () => encodeAuthorizationQR,
153
180
  encodeBase45: () => encodeBase45,
154
181
  encodeNQR: () => encodeNQR,
@@ -158,6 +185,8 @@ __export(index_exports, {
158
185
  generateKeyPair: () => generateKeyPair,
159
186
  generateStaticQR: () => generateStaticQR,
160
187
  init: () => init,
188
+ isHardenedArtifactType: () => isHardenedArtifactType,
189
+ isKnownArtifactType: () => isKnownArtifactType,
161
190
  isPassWithinValidity: () => isPassWithinValidity,
162
191
  moneyMinorToNumber: () => moneyMinorToNumber,
163
192
  normalizeE164: () => normalizeE164,
@@ -168,6 +197,7 @@ __export(index_exports, {
168
197
  readTLV: () => readTLV,
169
198
  routingHint: () => routingHint,
170
199
  sign: () => sign,
200
+ signArtifact: () => signArtifact,
171
201
  signAuthorization: () => signAuthorization,
172
202
  signCanonical: () => signCanonical,
173
203
  signOAC: () => signOAC,
@@ -178,6 +208,8 @@ __export(index_exports, {
178
208
  signRedemption: () => signRedemption,
179
209
  signRequestHMAC: () => signRequestHMAC,
180
210
  verify: () => verify,
211
+ verifyArtifactSignature: () => verifyArtifactSignature,
212
+ verifyArtifactUri: () => verifyArtifactUri,
181
213
  verifyAuthorization: () => verifyAuthorization,
182
214
  verifyCanonical: () => verifyCanonical,
183
215
  verifyOAC: () => verifyOAC,
@@ -344,6 +376,13 @@ var AccountActivityItemSchema = import_zod.z.object({
344
376
  timestamp: IsoDateSchema
345
377
  });
346
378
  var AccountSummaryResponseSchema = import_zod.z.object({
379
+ /** Authenticated user's stable internal id. */
380
+ userId: UuidSchema,
381
+ /**
382
+ * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
383
+ * bank partner. `null` when the user has no partner-allocated account yet.
384
+ */
385
+ nuban: import_zod.z.string().regex(/^[0-9]{10}$/).nullable(),
347
386
  balance: import_zod.z.number().int(),
348
387
  currency: CurrencySchema,
349
388
  dailySendLimit: import_zod.z.number().int().nonnegative(),
@@ -3667,14 +3706,420 @@ function createPartnerProfileAdminClient(opts) {
3667
3706
  }
3668
3707
  };
3669
3708
  }
3709
+
3710
+ // src/artifacts/envelope.ts
3711
+ var import_zod15 = require("zod");
3712
+ var FLUR_ARTIFACT_URI_SCHEME = "flur";
3713
+ var FLUR_ARTIFACT_VERSION = 1;
3714
+ var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
3715
+ var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
3716
+ var ArtifactHeaderSchema = import_zod15.z.object({
3717
+ v: import_zod15.z.literal(FLUR_ARTIFACT_VERSION),
3718
+ t: import_zod15.z.string().regex(ArtifactTypeRe, "invalid artifact type"),
3719
+ iss: import_zod15.z.string().min(1).max(128),
3720
+ kid: import_zod15.z.string().min(1).max(128),
3721
+ iat: import_zod15.z.number().int().nonnegative(),
3722
+ exp: import_zod15.z.number().int().positive().optional(),
3723
+ nonce: import_zod15.z.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
3724
+ });
3725
+ var FlurArtifactError = class extends Error {
3726
+ constructor(message, code) {
3727
+ super(message);
3728
+ this.code = code;
3729
+ this.name = "FlurArtifactError";
3730
+ }
3731
+ code;
3732
+ };
3733
+ function base64UrlEncode(bytes) {
3734
+ let bin = "";
3735
+ for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
3736
+ const b64 = typeof btoa === "function" ? btoa(bin) : Buffer.from(bytes).toString("base64");
3737
+ return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
3738
+ }
3739
+ function base64UrlDecode(s) {
3740
+ const pad = s.length % 4 === 0 ? "" : "=".repeat(4 - s.length % 4);
3741
+ const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + pad;
3742
+ if (typeof atob === "function") {
3743
+ const bin = atob(b64);
3744
+ const out = new Uint8Array(bin.length);
3745
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
3746
+ return out;
3747
+ }
3748
+ return new Uint8Array(Buffer.from(b64, "base64"));
3749
+ }
3750
+ function buildArtifactBody(input) {
3751
+ if (!ArtifactTypeRe.test(input.type)) {
3752
+ throw new FlurArtifactError(
3753
+ `Invalid artifact type: ${input.type}`,
3754
+ "INVALID_TYPE"
3755
+ );
3756
+ }
3757
+ const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
3758
+ const header = {
3759
+ v: FLUR_ARTIFACT_VERSION,
3760
+ t: input.type,
3761
+ iss: input.issuer,
3762
+ kid: input.keyId,
3763
+ iat,
3764
+ ...input.expiresAtSeconds !== void 0 ? { exp: input.expiresAtSeconds } : {},
3765
+ nonce: input.nonce
3766
+ };
3767
+ ArtifactHeaderSchema.parse(header);
3768
+ return { ...header, data: input.data };
3769
+ }
3770
+ function signArtifact(body, privateKey) {
3771
+ const sig = bytesToHex(sign(canonicalJSONBytes(body), privateKey));
3772
+ return { body, sig };
3773
+ }
3774
+ function encodeArtifactUri(signed) {
3775
+ const bodyBytes = canonicalJSONBytes(signed.body);
3776
+ const bodyB64 = base64UrlEncode(bodyBytes);
3777
+ const sigB64 = base64UrlEncode(hexToBytes(signed.sig));
3778
+ return `${FLUR_ARTIFACT_URI_PREFIX}${signed.body.t}/${bodyB64}.${sigB64}`;
3779
+ }
3780
+ function decodeArtifactUri(uri) {
3781
+ if (!uri.startsWith(FLUR_ARTIFACT_URI_PREFIX)) {
3782
+ throw new FlurArtifactError(
3783
+ `URI does not start with ${FLUR_ARTIFACT_URI_PREFIX}`,
3784
+ "INVALID_URI"
3785
+ );
3786
+ }
3787
+ const rest = uri.slice(FLUR_ARTIFACT_URI_PREFIX.length);
3788
+ const slash = rest.indexOf("/");
3789
+ if (slash <= 0) {
3790
+ throw new FlurArtifactError("Missing artifact type segment", "INVALID_URI");
3791
+ }
3792
+ const type = rest.slice(0, slash);
3793
+ const payload = rest.slice(slash + 1);
3794
+ const dot = payload.indexOf(".");
3795
+ if (dot <= 0 || dot === payload.length - 1) {
3796
+ throw new FlurArtifactError(
3797
+ "Missing body/signature separator",
3798
+ "INVALID_URI"
3799
+ );
3800
+ }
3801
+ if (!ArtifactTypeRe.test(type)) {
3802
+ throw new FlurArtifactError(
3803
+ `Invalid artifact type: ${type}`,
3804
+ "INVALID_TYPE"
3805
+ );
3806
+ }
3807
+ const bodyBytes = base64UrlDecode(payload.slice(0, dot));
3808
+ const sigBytes = base64UrlDecode(payload.slice(dot + 1));
3809
+ if (sigBytes.length !== 64) {
3810
+ throw new FlurArtifactError(
3811
+ `Signature must be 64 bytes, got ${sigBytes.length}`,
3812
+ "INVALID_SIGNATURE"
3813
+ );
3814
+ }
3815
+ let bodyJson;
3816
+ try {
3817
+ bodyJson = JSON.parse(new TextDecoder().decode(bodyBytes));
3818
+ } catch {
3819
+ throw new FlurArtifactError("Body is not valid JSON", "INVALID_BODY");
3820
+ }
3821
+ const headerOnly = ArtifactHeaderSchema.safeParse(bodyJson);
3822
+ if (!headerOnly.success) {
3823
+ throw new FlurArtifactError(
3824
+ `Body header invalid: ${headerOnly.error.message}`,
3825
+ "INVALID_BODY"
3826
+ );
3827
+ }
3828
+ if (headerOnly.data.t !== type) {
3829
+ throw new FlurArtifactError(
3830
+ `URI type ${type} does not match body type ${headerOnly.data.t}`,
3831
+ "TYPE_MISMATCH"
3832
+ );
3833
+ }
3834
+ return {
3835
+ type,
3836
+ bodyBytes,
3837
+ body: bodyJson,
3838
+ sig: bytesToHex(sigBytes)
3839
+ };
3840
+ }
3841
+ function verifyArtifactSignature(decoded, publicKey, options = {}) {
3842
+ if (options.enforceExpiry !== false && decoded.body.exp !== void 0) {
3843
+ const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
3844
+ if (decoded.body.exp < now) {
3845
+ throw new FlurArtifactError("Artifact has expired", "EXPIRED");
3846
+ }
3847
+ }
3848
+ return verify(decoded.bodyBytes, hexToBytes(decoded.sig), publicKey);
3849
+ }
3850
+
3851
+ // src/artifacts/types.ts
3852
+ var import_zod16 = require("zod");
3853
+ var ARTIFACT_TYPES = {
3854
+ OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
3855
+ RECEIPT: "receipt",
3856
+ // --- stubs, schemas to be hardened in follow-ups ---
3857
+ NQR_PAYMENT_REQUEST: "nqr_payment_request",
3858
+ PAYMENT_INTENT: "payment_intent",
3859
+ OFFLINE_CLAIM: "offline_claim",
3860
+ SETTLEMENT_RECORD: "settlement_record",
3861
+ REVERSAL_RECORD: "reversal_record",
3862
+ LEDGER_JOURNAL_ENTRY: "ledger_journal_entry",
3863
+ STATEMENT: "statement",
3864
+ PASS: "pass",
3865
+ IDENTITY: "identity"
3866
+ };
3867
+ var HexString4 = (length) => import_zod16.z.string().regex(
3868
+ new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
3869
+ `expected ${length}-byte hex string`
3870
+ );
3871
+ var OfflinePaymentAuthorizationArtifactSchema = import_zod16.z.object({
3872
+ authorization: OfflinePaymentAuthorizationSchema
3873
+ });
3874
+ var ReceiptArtifactSchema = import_zod16.z.object({
3875
+ receiptId: import_zod16.z.string().min(1).max(64),
3876
+ paymentReference: import_zod16.z.string().min(1).max(64),
3877
+ payerUserId: import_zod16.z.string().min(1).max(64).optional(),
3878
+ payeeUserId: import_zod16.z.string().min(1).max(64),
3879
+ amountKobo: import_zod16.z.number().int().positive(),
3880
+ currency: import_zod16.z.literal("NGN"),
3881
+ channel: import_zod16.z.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
3882
+ settledAtMs: import_zod16.z.number().int().positive(),
3883
+ ledgerTxnId: import_zod16.z.string().min(1).max(64).optional(),
3884
+ memo: import_zod16.z.string().max(140).optional(),
3885
+ hashChainPrev: HexString4(32).optional()
3886
+ });
3887
+ var ShortId = import_zod16.z.string().min(1).max(64);
3888
+ var PositiveInt = import_zod16.z.number().int().positive();
3889
+ var NonNegativeInt = import_zod16.z.number().int().nonnegative();
3890
+ var Currency2 = import_zod16.z.literal("NGN");
3891
+ var Memo = import_zod16.z.string().max(140);
3892
+ var NqrPaymentRequestArtifactSchema = import_zod16.z.object({
3893
+ requestId: ShortId,
3894
+ payeeUserId: ShortId,
3895
+ amountKobo: PositiveInt.optional(),
3896
+ currency: Currency2,
3897
+ memo: Memo.optional(),
3898
+ expiresAtMs: PositiveInt.optional()
3899
+ });
3900
+ var PaymentIntentArtifactSchema = import_zod16.z.object({
3901
+ intentId: ShortId,
3902
+ payerUserId: ShortId,
3903
+ payeeUserId: ShortId,
3904
+ amountKobo: PositiveInt,
3905
+ currency: Currency2,
3906
+ idempotencyKey: ShortId,
3907
+ createdAtMs: PositiveInt
3908
+ });
3909
+ var OfflineClaimArtifactSchema = import_zod16.z.object({
3910
+ claimId: ShortId,
3911
+ authorizationId: ShortId,
3912
+ payeeUserId: ShortId,
3913
+ claimedAmountKobo: PositiveInt,
3914
+ currency: Currency2,
3915
+ claimedAtMs: PositiveInt,
3916
+ paymentReference: ShortId.optional()
3917
+ });
3918
+ var SettlementRecordArtifactSchema = import_zod16.z.object({
3919
+ settlementId: ShortId,
3920
+ ledgerTxnId: ShortId,
3921
+ sourceRefType: import_zod16.z.enum([
3922
+ "offline_authorization",
3923
+ "offline_claim",
3924
+ "transfer",
3925
+ "pay_link"
3926
+ ]),
3927
+ sourceRefId: ShortId,
3928
+ amountKobo: PositiveInt,
3929
+ currency: Currency2,
3930
+ settledAtMs: PositiveInt
3931
+ });
3932
+ var ReversalRecordArtifactSchema = import_zod16.z.object({
3933
+ reversalId: ShortId,
3934
+ originalTxnId: ShortId,
3935
+ amountKobo: PositiveInt,
3936
+ currency: Currency2,
3937
+ reason: import_zod16.z.enum([
3938
+ "user_dispute",
3939
+ "fraud",
3940
+ "duplicate",
3941
+ "admin_correction",
3942
+ "other"
3943
+ ]),
3944
+ reversedAtMs: PositiveInt,
3945
+ memo: Memo.optional()
3946
+ });
3947
+ var LedgerJournalEntryArtifactSchema = import_zod16.z.object({
3948
+ entryId: ShortId,
3949
+ journalId: ShortId,
3950
+ debitAccountId: ShortId,
3951
+ creditAccountId: ShortId,
3952
+ amountKobo: PositiveInt,
3953
+ currency: Currency2,
3954
+ postedAtMs: PositiveInt,
3955
+ refType: ShortId.optional(),
3956
+ refId: ShortId.optional()
3957
+ });
3958
+ var StatementArtifactSchema = import_zod16.z.object({
3959
+ statementId: ShortId,
3960
+ userId: ShortId,
3961
+ periodStartMs: PositiveInt,
3962
+ periodEndMs: PositiveInt,
3963
+ openingBalanceKobo: import_zod16.z.number().int(),
3964
+ closingBalanceKobo: import_zod16.z.number().int(),
3965
+ transactionCount: NonNegativeInt,
3966
+ currency: Currency2,
3967
+ hashChainPrev: HexString4(32).optional()
3968
+ }).refine((v) => v.periodEndMs > v.periodStartMs, {
3969
+ message: "periodEndMs must be greater than periodStartMs",
3970
+ path: ["periodEndMs"]
3971
+ });
3972
+ var PassArtifactSchema = import_zod16.z.object({
3973
+ passId: ShortId,
3974
+ holderId: ShortId,
3975
+ category: import_zod16.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
3976
+ title: import_zod16.z.string().min(1).max(120),
3977
+ validFromMs: PositiveInt,
3978
+ validUntilMs: PositiveInt.optional(),
3979
+ metadata: import_zod16.z.record(
3980
+ import_zod16.z.string().min(1).max(64),
3981
+ import_zod16.z.union([import_zod16.z.string().max(280), import_zod16.z.number(), import_zod16.z.boolean()])
3982
+ ).optional()
3983
+ }).refine(
3984
+ (v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
3985
+ {
3986
+ message: "validUntilMs must be greater than validFromMs",
3987
+ path: ["validUntilMs"]
3988
+ }
3989
+ );
3990
+ var IdentityArtifactSchema = import_zod16.z.object({
3991
+ attestationId: ShortId,
3992
+ subjectId: ShortId,
3993
+ claimType: import_zod16.z.enum([
3994
+ "phone_verified",
3995
+ "email_verified",
3996
+ "bvn_verified",
3997
+ "kyc_tier",
3998
+ "age_band"
3999
+ ]),
4000
+ claimValueHash: HexString4(32),
4001
+ attestedAtMs: PositiveInt
4002
+ });
4003
+ var ARTIFACT_BODY_SCHEMAS = {
4004
+ [ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]: OfflinePaymentAuthorizationArtifactSchema,
4005
+ [ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,
4006
+ [ARTIFACT_TYPES.NQR_PAYMENT_REQUEST]: NqrPaymentRequestArtifactSchema,
4007
+ [ARTIFACT_TYPES.PAYMENT_INTENT]: PaymentIntentArtifactSchema,
4008
+ [ARTIFACT_TYPES.OFFLINE_CLAIM]: OfflineClaimArtifactSchema,
4009
+ [ARTIFACT_TYPES.SETTLEMENT_RECORD]: SettlementRecordArtifactSchema,
4010
+ [ARTIFACT_TYPES.REVERSAL_RECORD]: ReversalRecordArtifactSchema,
4011
+ [ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,
4012
+ [ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,
4013
+ [ARTIFACT_TYPES.PASS]: PassArtifactSchema,
4014
+ [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
4015
+ };
4016
+ var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4017
+ ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,
4018
+ ARTIFACT_TYPES.RECEIPT,
4019
+ ARTIFACT_TYPES.NQR_PAYMENT_REQUEST,
4020
+ ARTIFACT_TYPES.PAYMENT_INTENT,
4021
+ ARTIFACT_TYPES.OFFLINE_CLAIM,
4022
+ ARTIFACT_TYPES.SETTLEMENT_RECORD,
4023
+ ARTIFACT_TYPES.REVERSAL_RECORD,
4024
+ ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,
4025
+ ARTIFACT_TYPES.STATEMENT,
4026
+ ARTIFACT_TYPES.PASS,
4027
+ ARTIFACT_TYPES.IDENTITY
4028
+ ]);
4029
+ function isKnownArtifactType(t) {
4030
+ return Object.values(ARTIFACT_TYPES).includes(t);
4031
+ }
4032
+ function isHardenedArtifactType(t) {
4033
+ return HARDENED_ARTIFACT_TYPES.has(t);
4034
+ }
4035
+
4036
+ // src/artifacts/codec.ts
4037
+ function createArtifactUri(input) {
4038
+ if (!isKnownArtifactType(input.type)) {
4039
+ throw new FlurArtifactError(
4040
+ `Unknown artifact type: ${input.type}`,
4041
+ "INVALID_TYPE"
4042
+ );
4043
+ }
4044
+ if (!isHardenedArtifactType(input.type)) {
4045
+ throw new FlurArtifactError(
4046
+ `Artifact type ${input.type} is not yet hardened for emission`,
4047
+ "INVALID_TYPE"
4048
+ );
4049
+ }
4050
+ const schema = ARTIFACT_BODY_SCHEMAS[input.type];
4051
+ const parsedData = schema.parse(input.data);
4052
+ const body = buildArtifactBody({
4053
+ type: input.type,
4054
+ issuer: input.issuer,
4055
+ keyId: input.keyId,
4056
+ data: parsedData,
4057
+ nonce: input.nonce,
4058
+ issuedAtSeconds: input.issuedAtSeconds,
4059
+ expiresAtSeconds: input.expiresAtSeconds
4060
+ });
4061
+ const signed = signArtifact(body, input.privateKey);
4062
+ return { uri: encodeArtifactUri(signed), signed };
4063
+ }
4064
+ function verifyArtifactUri(uri, publicKey, options = {}) {
4065
+ const decoded = decodeArtifactUri(uri);
4066
+ if (!isKnownArtifactType(decoded.type)) {
4067
+ throw new FlurArtifactError(
4068
+ `Unknown artifact type: ${decoded.type}`,
4069
+ "INVALID_TYPE"
4070
+ );
4071
+ }
4072
+ if (!isHardenedArtifactType(decoded.type)) {
4073
+ throw new FlurArtifactError(
4074
+ `Artifact type ${decoded.type} is not yet hardened for verification`,
4075
+ "INVALID_TYPE"
4076
+ );
4077
+ }
4078
+ const schema = ARTIFACT_BODY_SCHEMAS[decoded.type];
4079
+ const dataParsed = schema.safeParse(decoded.body.data);
4080
+ if (!dataParsed.success) {
4081
+ throw new FlurArtifactError(
4082
+ `Artifact body invalid: ${dataParsed.error.message}`,
4083
+ "INVALID_BODY"
4084
+ );
4085
+ }
4086
+ const ok = verifyArtifactSignature(decoded, publicKey, options);
4087
+ if (!ok) {
4088
+ throw new FlurArtifactError(
4089
+ "Artifact signature verification failed",
4090
+ "INVALID_SIGNATURE"
4091
+ );
4092
+ }
4093
+ return {
4094
+ type: decoded.type,
4095
+ body: decoded.body,
4096
+ sig: decoded.sig,
4097
+ decoded
4098
+ };
4099
+ }
4100
+ function createReceiptArtifactUri(input) {
4101
+ return createArtifactUri({
4102
+ ...input,
4103
+ type: ARTIFACT_TYPES.RECEIPT
4104
+ });
4105
+ }
4106
+ function createOfflinePaymentAuthorizationArtifactUri(input) {
4107
+ return createArtifactUri({
4108
+ ...input,
4109
+ type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION
4110
+ });
4111
+ }
3670
4112
  // Annotate the CommonJS export names for ESM import in node:
3671
4113
  0 && (module.exports = {
3672
4114
  ACCOUNT_STATUSES,
3673
4115
  ACCOUNT_TYPES,
3674
4116
  ADDITIONAL_DATA_SUBFIELD,
4117
+ ARTIFACT_BODY_SCHEMAS,
4118
+ ARTIFACT_TYPES,
3675
4119
  AccountMembershipSchema,
3676
4120
  AccountSchema,
3677
4121
  ApiCredentialPublicSchema,
4122
+ ArtifactHeaderSchema,
3678
4123
  COLLECTION_INTENT_STATUSES,
3679
4124
  COLLECTION_PAYMENT_STATUSES,
3680
4125
  CUSTODIAL_MODES,
@@ -3699,14 +4144,21 @@ function createPartnerProfileAdminClient(opts) {
3699
4144
  EnableOfflineInputSchema,
3700
4145
  EnableOfflineResultSchema,
3701
4146
  FIELD,
4147
+ FLUR_ARTIFACT_URI_PREFIX,
4148
+ FLUR_ARTIFACT_URI_SCHEME,
4149
+ FLUR_ARTIFACT_VERSION,
3702
4150
  FlurApiError,
4151
+ FlurArtifactError,
3703
4152
  FlurCapExceededError,
3704
4153
  FlurClient,
3705
4154
  FlurError,
3706
4155
  FlurExpiredError,
3707
4156
  FlurReplayError,
4157
+ HARDENED_ARTIFACT_TYPES,
4158
+ IdentityArtifactSchema,
3708
4159
  IngestFundingResultSchema,
3709
4160
  IssueOACInputSchema,
4161
+ LedgerJournalEntryArtifactSchema,
3710
4162
  ListPayoutDestinationsResultSchema,
3711
4163
  MEMBERSHIP_ROLES,
3712
4164
  MERCHANT_PAYOUT_STATUSES,
@@ -3717,11 +4169,14 @@ function createPartnerProfileAdminClient(opts) {
3717
4169
  NGN_CURRENCY_CODE,
3718
4170
  NG_COUNTRY_CODE,
3719
4171
  NQRParseError,
4172
+ NqrPaymentRequestArtifactSchema,
3720
4173
  OACSchema,
3721
4174
  OAC_DEFAULT_CUMULATIVE_KOBO,
3722
4175
  OAC_DEFAULT_PER_TX_KOBO,
3723
4176
  OAC_DEFAULT_VALIDITY_MS,
4177
+ OfflineClaimArtifactSchema,
3724
4178
  OfflineHoldRecordSchema,
4179
+ OfflinePaymentAuthorizationArtifactSchema,
3725
4180
  OfflinePaymentAuthorizationSchema,
3726
4181
  OfflinePaymentRequestSchema,
3727
4182
  OfflineStateResultSchema,
@@ -3740,10 +4195,12 @@ function createPartnerProfileAdminClient(opts) {
3740
4195
  PartnerFundingEventInputSchema,
3741
4196
  PartnerFundingSchema,
3742
4197
  PartnerProfileSchema,
4198
+ PassArtifactSchema,
3743
4199
  PassMetadataSchema,
3744
4200
  PassSchema,
3745
4201
  PayCollectionInputSchema,
3746
4202
  PaymentClaimSchema,
4203
+ PaymentIntentArtifactSchema,
3747
4204
  PayoutDestinationSchema,
3748
4205
  PayoutEventInputSchema,
3749
4206
  ProviderEventInputSchema,
@@ -3752,22 +4209,29 @@ function createPartnerProfileAdminClient(opts) {
3752
4209
  RECEIPT_CHANNELS,
3753
4210
  RECEIPT_KINDS,
3754
4211
  REPLAY_WINDOW_MS,
4212
+ ReceiptArtifactSchema,
3755
4213
  ReceiptPayloadSchema,
3756
4214
  ReceiptSchema,
3757
4215
  ReconciliationReportSchema,
3758
4216
  RecordPayoutEventResultSchema,
3759
4217
  RedemptionSchema,
3760
4218
  RegisterDeviceKeyInputSchema,
4219
+ ReversalRecordArtifactSchema,
3761
4220
  RevokeDeviceKeyInputSchema,
3762
4221
  SETTLEMENT_SCHEDULES,
3763
4222
  SettleResponseSchema,
4223
+ SettlementRecordArtifactSchema,
3764
4224
  SettlementSchema,
3765
4225
  SignedConsumerOACSchema,
4226
+ StatementArtifactSchema,
3766
4227
  UpsertMerchantProfileInputSchema,
3767
4228
  UpsertPartnerProfileInputSchema,
3768
4229
  WITHDRAWAL_STATES,
3769
4230
  WithdrawalSchema,
4231
+ base64UrlDecode,
4232
+ base64UrlEncode,
3770
4233
  bodySha256Hex,
4234
+ buildArtifactBody,
3771
4235
  buildAuthorization,
3772
4236
  buildOAC,
3773
4237
  buildPass,
@@ -3783,21 +4247,26 @@ function createPartnerProfileAdminClient(opts) {
3783
4247
  crc16ccittHex,
3784
4248
  createAccountsClient,
3785
4249
  createApiCredentialsAdminClient,
4250
+ createArtifactUri,
3786
4251
  createCollectionsClient,
3787
4252
  createConsumerCollectionsClient,
3788
4253
  createConsumerWithdrawalsClient,
3789
4254
  createFlurPartnerClient,
3790
4255
  createHmacFetch,
3791
4256
  createMeOfflineClient,
4257
+ createOfflinePaymentAuthorizationArtifactUri,
3792
4258
  createOfflineSettlementsClient,
3793
4259
  createPartnerCollectionsClient,
3794
4260
  createPartnerFundingClient,
3795
4261
  createPartnerProfileAdminClient,
3796
4262
  createPassesClient,
4263
+ createReceiptArtifactUri,
3797
4264
  createReceiptsClient,
4265
+ decodeArtifactUri,
3798
4266
  decodeAuthorizationQR,
3799
4267
  decodeBase45,
3800
4268
  decodePaymentRequestQR,
4269
+ encodeArtifactUri,
3801
4270
  encodeAuthorizationQR,
3802
4271
  encodeBase45,
3803
4272
  encodeNQR,
@@ -3807,6 +4276,8 @@ function createPartnerProfileAdminClient(opts) {
3807
4276
  generateKeyPair,
3808
4277
  generateStaticQR,
3809
4278
  init,
4279
+ isHardenedArtifactType,
4280
+ isKnownArtifactType,
3810
4281
  isPassWithinValidity,
3811
4282
  moneyMinorToNumber,
3812
4283
  normalizeE164,
@@ -3817,6 +4288,7 @@ function createPartnerProfileAdminClient(opts) {
3817
4288
  readTLV,
3818
4289
  routingHint,
3819
4290
  sign,
4291
+ signArtifact,
3820
4292
  signAuthorization,
3821
4293
  signCanonical,
3822
4294
  signOAC,
@@ -3827,6 +4299,8 @@ function createPartnerProfileAdminClient(opts) {
3827
4299
  signRedemption,
3828
4300
  signRequestHMAC,
3829
4301
  verify,
4302
+ verifyArtifactSignature,
4303
+ verifyArtifactUri,
3830
4304
  verifyAuthorization,
3831
4305
  verifyCanonical,
3832
4306
  verifyOAC,