@nokinc-flur/sdk 2.2.0 → 2.4.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 CHANGED
@@ -44,6 +44,8 @@ __export(index_exports, {
44
44
  CLAIM_DOMAIN_V2: () => CLAIM_DOMAIN_V2,
45
45
  COLLECTION_INTENT_STATUSES: () => COLLECTION_INTENT_STATUSES,
46
46
  COLLECTION_PAYMENT_STATUSES: () => COLLECTION_PAYMENT_STATUSES,
47
+ CONSUMER_OAC_DOMAIN: () => CONSUMER_OAC_DOMAIN,
48
+ CONSUMER_OAC_QR_PREFIX: () => CONSUMER_OAC_QR_PREFIX,
47
49
  CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS: () => CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
48
50
  CONSUMER_PAYMENT_REQUEST_DOMAIN: () => CONSUMER_PAYMENT_REQUEST_DOMAIN,
49
51
  CONSUMER_SETTLEMENT_DOMAIN: () => CONSUMER_SETTLEMENT_DOMAIN,
@@ -82,6 +84,8 @@ __export(index_exports, {
82
84
  IdentityArtifactSchema: () => IdentityArtifactSchema,
83
85
  IngestFundingResultSchema: () => IngestFundingResultSchema,
84
86
  IssueAccountOacInputSchema: () => IssueAccountOacInputSchema,
87
+ IssuerTrustBundleSchema: () => IssuerTrustBundleSchema,
88
+ IssuerTrustKeySchema: () => IssuerTrustKeySchema,
85
89
  LedgerJournalEntryArtifactSchema: () => LedgerJournalEntryArtifactSchema,
86
90
  ListPayoutDestinationsResultSchema: () => ListPayoutDestinationsResultSchema,
87
91
  MEMBERSHIP_ROLES: () => MEMBERSHIP_ROLES,
@@ -105,6 +109,7 @@ __export(index_exports, {
105
109
  OFFLINE_SMS_SETTLE_SIGNATURE_BYTES: () => OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
106
110
  OFFLINE_SMS_SETTLE_TOKEN_BYTES: () => OFFLINE_SMS_SETTLE_TOKEN_BYTES,
107
111
  OFFLINE_SMS_SETTLE_VERSION: () => OFFLINE_SMS_SETTLE_VERSION,
112
+ OacPresentmentRequestSchema: () => OacPresentmentRequestSchema,
108
113
  OfflineClaimArtifactSchema: () => OfflineClaimArtifactSchema,
109
114
  OfflinePaymentAuthorizationArtifactSchema: () => OfflinePaymentAuthorizationArtifactSchema,
110
115
  OfflinePaymentAuthorizationSchema: () => OfflinePaymentAuthorizationSchema,
@@ -122,9 +127,6 @@ __export(index_exports, {
122
127
  PASS_STATES: () => PASS_STATES,
123
128
  PAYLOAD_FORMAT_INDICATOR_VALUE: () => PAYLOAD_FORMAT_INDICATOR_VALUE,
124
129
  PAYOUT_DESTINATION_STATUSES: () => PAYOUT_DESTINATION_STATUSES,
125
- PAY_CARD_DEFAULT_TTL_MS: () => PAY_CARD_DEFAULT_TTL_MS,
126
- PAY_CARD_REFRESH_THRESHOLD_MS: () => PAY_CARD_REFRESH_THRESHOLD_MS,
127
- PAY_CARD_URI_PREFIX: () => PAY_CARD_URI_PREFIX,
128
130
  POINT_OF_INITIATION: () => POINT_OF_INITIATION,
129
131
  PartnerFundingEventInputSchema: () => PartnerFundingEventInputSchema,
130
132
  PartnerFundingSchema: () => PartnerFundingSchema,
@@ -132,7 +134,6 @@ __export(index_exports, {
132
134
  PassArtifactSchema: () => PassArtifactSchema,
133
135
  PassMetadataSchema: () => PassMetadataSchema,
134
136
  PassSchema: () => PassSchema,
135
- PayCardArtifactSchema: () => PayCardArtifactSchema,
136
137
  PayCollectionInputSchema: () => PayCollectionInputSchema,
137
138
  PaymentClaimSchema: () => PaymentClaimSchema,
138
139
  PaymentIntentArtifactSchema: () => PaymentIntentArtifactSchema,
@@ -171,7 +172,6 @@ __export(index_exports, {
171
172
  buildConsumerPaymentRequest: () => buildConsumerPaymentRequest,
172
173
  buildOAC: () => buildOAC,
173
174
  buildPass: () => buildPass,
174
- buildPayCardSigningInput: () => buildPayCardSigningInput,
175
175
  buildPaymentRequest: () => buildPaymentRequest,
176
176
  buildReceipt: () => buildReceipt,
177
177
  buildRedemption: () => buildRedemption,
@@ -185,6 +185,7 @@ __export(index_exports, {
185
185
  computeConsumerClaimEncounterId: () => computeConsumerClaimEncounterId,
186
186
  computeEncounterId: () => computeEncounterId,
187
187
  constantTimeEqual: () => constantTimeEqual,
188
+ consumerOacSigningPayload: () => consumerOacSigningPayload,
188
189
  consumerPaymentRequestSigningBytes: () => consumerPaymentRequestSigningBytes,
189
190
  consumerPaymentRequestSigningPayload: () => consumerPaymentRequestSigningPayload,
190
191
  consumerSettlementSigningPayload: () => consumerSettlementSigningPayload,
@@ -205,23 +206,24 @@ __export(index_exports, {
205
206
  createPartnerFundingClient: () => createPartnerFundingClient,
206
207
  createPartnerProfileAdminClient: () => createPartnerProfileAdminClient,
207
208
  createPassesClient: () => createPassesClient,
208
- createPayCardArtifactUri: () => createPayCardArtifactUri,
209
209
  createReceiptArtifactUri: () => createReceiptArtifactUri,
210
210
  createReceiptsClient: () => createReceiptsClient,
211
211
  createSoftwareP256Signer: () => createSoftwareP256Signer,
212
212
  decodeArtifactUri: () => decodeArtifactUri,
213
213
  decodeAuthorizationQR: () => decodeAuthorizationQR,
214
214
  decodeBase45: () => decodeBase45,
215
+ decodeConsumerOacRequest: () => decodeConsumerOacRequest,
215
216
  decodeConsumerSettlementReceiptQR: () => decodeConsumerSettlementReceiptQR,
216
217
  decodeOfflineClaimSmsMessage: () => decodeOfflineClaimSmsMessage,
217
218
  decodeOfflineSmsSettleToken: () => decodeOfflineSmsSettleToken,
218
- decodePayCardArtifact: () => decodePayCardArtifact,
219
219
  decodePaymentRequestQR: () => decodePaymentRequestQR,
220
+ decodeUnverifiedConsumerOacQR: () => decodeUnverifiedConsumerOacQR,
220
221
  decodeUnverifiedConsumerSettlementReceiptQR: () => decodeUnverifiedConsumerSettlementReceiptQR,
221
222
  derToRawP256Signature: () => derToRawP256Signature,
222
223
  encodeArtifactUri: () => encodeArtifactUri,
223
224
  encodeAuthorizationQR: () => encodeAuthorizationQR,
224
225
  encodeBase45: () => encodeBase45,
226
+ encodeConsumerOacQR: () => encodeConsumerOacQR,
225
227
  encodeConsumerSettlementReceiptQR: () => encodeConsumerSettlementReceiptQR,
226
228
  encodeNQR: () => encodeNQR,
227
229
  encodeOfflineClaimSmsMessage: () => encodeOfflineClaimSmsMessage,
@@ -233,12 +235,11 @@ __export(index_exports, {
233
235
  generateDynamicQR: () => generateDynamicQR,
234
236
  generateStaticQR: () => generateStaticQR,
235
237
  init: () => init,
236
- inspectPayCardFreshness: () => inspectPayCardFreshness,
238
+ isConsumerOacQR: () => isConsumerOacQR,
237
239
  isConsumerPaymentRequestExpired: () => isConsumerPaymentRequestExpired,
238
240
  isHardenedArtifactType: () => isHardenedArtifactType,
239
241
  isKnownArtifactType: () => isKnownArtifactType,
240
242
  isPassWithinValidity: () => isPassWithinValidity,
241
- isPayCardArtifactUri: () => isPayCardArtifactUri,
242
243
  moneyMinorToNumber: () => moneyMinorToNumber,
243
244
  normalizeE164: () => normalizeE164,
244
245
  parseAmountInput: () => parseAmountInput,
@@ -264,9 +265,9 @@ __export(index_exports, {
264
265
  verifyConsumerSettlement: () => verifyConsumerSettlement,
265
266
  verifyConsumerSettlementReceiptQR: () => verifyConsumerSettlementReceiptQR,
266
267
  verifyOAC: () => verifyOAC,
268
+ verifyOacOffline: () => verifyOacOffline,
267
269
  verifyOfflineSmsSettleToken: () => verifyOfflineSmsSettleToken,
268
270
  verifyPass: () => verifyPass,
269
- verifyPayCardArtifact: () => verifyPayCardArtifact,
270
271
  verifyPaymentRequest: () => verifyPaymentRequest,
271
272
  verifyReceipt: () => verifyReceipt,
272
273
  verifyRedemption: () => verifyRedemption,
@@ -3238,7 +3239,17 @@ var Base64Std3 = import_zod13.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3238
3239
  var ClaimNonce = import_zod13.z.string().min(8).max(128).refine((value) => !value.includes("|"), {
3239
3240
  message: "nonce must not contain |"
3240
3241
  });
3241
- var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
3242
+ var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24;
3243
+ var IssuerTrustKeySchema = import_zod13.z.object({
3244
+ issuerId: import_zod13.z.string().min(1).max(128),
3245
+ alg: import_zod13.z.literal("p256"),
3246
+ publicKeySpkiB64: Base64Std3.min(64).max(4096),
3247
+ notBeforeMs: import_zod13.z.number().int().nonnegative().optional(),
3248
+ notAfterMs: import_zod13.z.number().int().positive().optional()
3249
+ });
3250
+ var IssuerTrustBundleSchema = import_zod13.z.object({
3251
+ keys: import_zod13.z.array(IssuerTrustKeySchema).min(1)
3252
+ });
3242
3253
  var CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1e3 * 60 * 60 * 24;
3243
3254
  var AttestationSecurityLevelSchema = import_zod13.z.enum([
3244
3255
  "STRONGBOX",
@@ -3292,13 +3303,28 @@ var ConsumerOACSchema = import_zod13.z.object({
3292
3303
  alg: import_zod13.z.literal("p256"),
3293
3304
  /** P-256 SubjectPublicKeyInfo DER, base64. */
3294
3305
  devicePubkeySpkiB64: Base64Std3.min(64).max(4096),
3295
- perTxCapKobo: import_zod13.z.number().int().positive(),
3296
- cumulativeCapKobo: import_zod13.z.number().int().positive(),
3306
+ /**
3307
+ * Per-transaction / cumulative offline spend ceilings. Zero is valid and
3308
+ * denotes an identity-only OAC: the credential proves who the holder is and
3309
+ * binds their device key for offline-verifiable first contact, but carries
3310
+ * no offline spend authority (every claim against it routes to REVIEW).
3311
+ * Issued to zero-balance wallets so they can still be paid offline.
3312
+ */
3313
+ perTxCapKobo: import_zod13.z.number().int().nonnegative(),
3314
+ cumulativeCapKobo: import_zod13.z.number().int().nonnegative(),
3297
3315
  currency: import_zod13.z.string().length(3),
3298
3316
  validFromMs: import_zod13.z.number().int().nonnegative(),
3299
3317
  validUntilMs: import_zod13.z.number().int().nonnegative(),
3300
3318
  counterSeed: import_zod13.z.number().int().nonnegative(),
3301
- issuedAtMs: import_zod13.z.number().int().nonnegative()
3319
+ issuedAtMs: import_zod13.z.number().int().nonnegative(),
3320
+ /**
3321
+ * Issuer-attested identity folded into the OAC so a single signed
3322
+ * credential serves both Tier B offline-verifiable identity and offline
3323
+ * spend authority. Verified offline against a pinned issuer key; the
3324
+ * backend remains authoritative at settlement.
3325
+ */
3326
+ phoneE164: import_zod13.z.string().regex(/^\+[1-9]\d{7,14}$/),
3327
+ displayName: import_zod13.z.string().min(1).max(64)
3302
3328
  });
3303
3329
  var SignedConsumerOACSchema = import_zod13.z.object({
3304
3330
  oac: ConsumerOACSchema,
@@ -3466,6 +3492,12 @@ function createMeOfflineClient(opts) {
3466
3492
  `/v1/me/offline/settlements/${encodeURIComponent(idOrKey)}`,
3467
3493
  void 0,
3468
3494
  (raw) => ConsumerSettlementSchema.parse(raw)
3495
+ ),
3496
+ getIssuerKeys: () => call(
3497
+ "GET",
3498
+ "/v1/issuer/keys",
3499
+ void 0,
3500
+ (raw) => IssuerTrustBundleSchema.parse(raw)
3469
3501
  )
3470
3502
  };
3471
3503
  }
@@ -3826,13 +3858,130 @@ function base64UrlDecodeUtf8(input) {
3826
3858
  throw new Error("base64 decoder unavailable");
3827
3859
  }
3828
3860
 
3861
+ // src/me-offline/oac.ts
3862
+ var import_zod15 = require("zod");
3863
+ var CONSUMER_OAC_DOMAIN = "flur:consumer-offline:v1:oac";
3864
+ function consumerOacSigningPayload(oac) {
3865
+ return { domain: CONSUMER_OAC_DOMAIN, ...oac };
3866
+ }
3867
+ function verifyOacOffline(signed, trustedKeys, options = {}) {
3868
+ const parsed = SignedConsumerOACSchema.safeParse(signed);
3869
+ if (!parsed.success) return { ok: false, reason: "malformed" };
3870
+ const oacParsed = ConsumerOACSchema.safeParse(parsed.data.oac);
3871
+ if (!oacParsed.success) return { ok: false, reason: "malformed" };
3872
+ const oac = oacParsed.data;
3873
+ const nowMs = options.nowMs ?? Date.now();
3874
+ const pinned = trustedKeys.filter(
3875
+ (k) => k.issuerId === oac.issuerId && (k.notBeforeMs === void 0 || nowMs >= k.notBeforeMs) && (k.notAfterMs === void 0 || nowMs <= k.notAfterMs)
3876
+ );
3877
+ if (pinned.length === 0) return { ok: false, reason: "untrusted_issuer" };
3878
+ const signingBytes = canonicalJSONBytes(consumerOacSigningPayload(oac));
3879
+ const signatureOk = pinned.some(
3880
+ (k) => verifyIssuerP256(signingBytes, parsed.data.issuerSig, k.publicKeySpkiB64)
3881
+ );
3882
+ if (!signatureOk) return { ok: false, reason: "signature_invalid" };
3883
+ if (oac.validUntilMs - oac.validFromMs > ACCOUNT_FUNDED_OAC_MAX_TTL_MS) {
3884
+ return { ok: false, reason: "window_too_long" };
3885
+ }
3886
+ if (nowMs < oac.validFromMs) return { ok: false, reason: "not_yet_valid" };
3887
+ if (nowMs >= oac.validUntilMs) return { ok: false, reason: "expired" };
3888
+ return {
3889
+ ok: true,
3890
+ oac,
3891
+ identity: {
3892
+ oacId: oac.oacId,
3893
+ issuerId: oac.issuerId,
3894
+ userId: oac.userId,
3895
+ phoneE164: oac.phoneE164,
3896
+ displayName: oac.displayName,
3897
+ devicePubkeySpkiB64: oac.devicePubkeySpkiB64
3898
+ }
3899
+ };
3900
+ }
3901
+ var CONSUMER_OAC_QR_PREFIX = "FLUROAC1.";
3902
+ function isConsumerOacQR(value) {
3903
+ return value.startsWith(CONSUMER_OAC_QR_PREFIX);
3904
+ }
3905
+ var OacPresentmentRequestSchema = import_zod15.z.object({
3906
+ /** Requested amount in minor units (kobo). */
3907
+ amountMinor: import_zod15.z.number().int().positive().max(1e12).optional(),
3908
+ /** Purpose/intent code (mirrors the NIBSS intent vocabulary). */
3909
+ intent: import_zod15.z.string().min(1).max(32).optional(),
3910
+ /** Free-text reference / note. */
3911
+ reference: import_zod15.z.string().min(1).max(64).optional()
3912
+ }).strict();
3913
+ function encodeConsumerOacQR(signed, request) {
3914
+ const parsed = SignedConsumerOACSchema.parse(signed);
3915
+ const base = `${CONSUMER_OAC_QR_PREFIX}${base64UrlEncodeUtf82(JSON.stringify(parsed))}`;
3916
+ if (request === void 0) return base;
3917
+ const parsedRequest = OacPresentmentRequestSchema.parse(request);
3918
+ if (Object.keys(parsedRequest).length === 0) return base;
3919
+ return `${base}.${base64UrlEncodeUtf82(JSON.stringify(parsedRequest))}`;
3920
+ }
3921
+ function decodeUnverifiedConsumerOacQR(value) {
3922
+ if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) {
3923
+ throw new Error("not a Flur consumer OAC QR");
3924
+ }
3925
+ const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);
3926
+ const encoded = remainder.split(".", 1)[0];
3927
+ let raw;
3928
+ try {
3929
+ raw = JSON.parse(base64UrlDecodeUtf82(encoded));
3930
+ } catch {
3931
+ throw new Error("consumer OAC QR is malformed");
3932
+ }
3933
+ return SignedConsumerOACSchema.parse(raw);
3934
+ }
3935
+ function decodeConsumerOacRequest(value) {
3936
+ if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) return null;
3937
+ const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);
3938
+ const dot = remainder.indexOf(".");
3939
+ if (dot < 0) return null;
3940
+ const suffix = remainder.slice(dot + 1);
3941
+ if (suffix.length === 0) return null;
3942
+ try {
3943
+ const raw = JSON.parse(base64UrlDecodeUtf82(suffix));
3944
+ const parsed = OacPresentmentRequestSchema.safeParse(raw);
3945
+ return parsed.success ? parsed.data : null;
3946
+ } catch {
3947
+ return null;
3948
+ }
3949
+ }
3950
+ function base64UrlEncodeUtf82(input) {
3951
+ const bytes = new TextEncoder().encode(input);
3952
+ let binary = "";
3953
+ for (const byte of bytes) binary += String.fromCharCode(byte);
3954
+ const base64 = typeof btoa === "function" ? btoa(binary) : typeof Buffer !== "undefined" ? Buffer.from(bytes).toString("base64") : void 0;
3955
+ if (!base64) throw new Error("base64 encoder unavailable");
3956
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
3957
+ }
3958
+ function base64UrlDecodeUtf82(input) {
3959
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
3960
+ const padded = base64.padEnd(
3961
+ base64.length + (4 - base64.length % 4) % 4,
3962
+ "="
3963
+ );
3964
+ if (typeof atob === "function") {
3965
+ const binary = atob(padded);
3966
+ const bytes = new Uint8Array(binary.length);
3967
+ for (let index = 0; index < binary.length; index++) {
3968
+ bytes[index] = binary.charCodeAt(index);
3969
+ }
3970
+ return new TextDecoder().decode(bytes);
3971
+ }
3972
+ if (typeof Buffer !== "undefined") {
3973
+ return Buffer.from(padded, "base64").toString("utf8");
3974
+ }
3975
+ throw new Error("base64 decoder unavailable");
3976
+ }
3977
+
3829
3978
  // src/me-offline/sms.ts
3830
3979
  var import_nist3 = require("@noble/curves/nist");
3831
3980
  var OFFLINE_CLAIM_SMS_PREFIX = "FLURC1.";
3832
3981
  var CLAIM_TOKEN_RE = /(?:^|\s)(FLURC1\.[A-Za-z0-9_-]+={0,2})(?:\s|$)/;
3833
3982
  function encodeOfflineClaimSmsMessage(claim) {
3834
3983
  const parsed = ConsumerPaymentClaimSchema.parse(claim);
3835
- return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf82(
3984
+ return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf83(
3836
3985
  JSON.stringify(parsed)
3837
3986
  )}`;
3838
3987
  }
@@ -3842,7 +3991,7 @@ function decodeOfflineClaimSmsMessage(message) {
3842
3991
  const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);
3843
3992
  let raw;
3844
3993
  try {
3845
- raw = JSON.parse(base64UrlDecodeUtf82(encoded));
3994
+ raw = JSON.parse(base64UrlDecodeUtf83(encoded));
3846
3995
  } catch {
3847
3996
  throw new Error("offline claim QR token is malformed");
3848
3997
  }
@@ -4068,10 +4217,10 @@ function bytesToBase64Url(bytes) {
4068
4217
  }
4069
4218
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
4070
4219
  }
4071
- function base64UrlEncodeUtf82(input) {
4220
+ function base64UrlEncodeUtf83(input) {
4072
4221
  return bytesToBase64Url(utf8(input));
4073
4222
  }
4074
- function base64UrlDecodeUtf82(input) {
4223
+ function base64UrlDecodeUtf83(input) {
4075
4224
  return new TextDecoder().decode(base64UrlToBytes(input));
4076
4225
  }
4077
4226
  function base64UrlToBytes(input) {
@@ -4093,14 +4242,14 @@ function base64UrlToBytes(input) {
4093
4242
  }
4094
4243
 
4095
4244
  // src/partner-funding/client.ts
4096
- var import_zod15 = require("zod");
4097
- var MinorString = import_zod15.z.string().regex(/^-?\d+$/);
4098
- var PositiveMinor = import_zod15.z.union([
4099
- import_zod15.z.number().int().positive(),
4100
- import_zod15.z.string().regex(/^[1-9]\d{0,18}$/)
4245
+ var import_zod16 = require("zod");
4246
+ var MinorString = import_zod16.z.string().regex(/^-?\d+$/);
4247
+ var PositiveMinor = import_zod16.z.union([
4248
+ import_zod16.z.number().int().positive(),
4249
+ import_zod16.z.string().regex(/^[1-9]\d{0,18}$/)
4101
4250
  ]);
4102
- var Currency = import_zod15.z.string().trim().length(3).transform((v) => v.toUpperCase());
4103
- var Metadata = import_zod15.z.record(import_zod15.z.unknown());
4251
+ var Currency = import_zod16.z.string().trim().length(3).transform((v) => v.toUpperCase());
4252
+ var Metadata = import_zod16.z.record(import_zod16.z.unknown());
4104
4253
  var PARTNER_KINDS = ["bank", "merchant"];
4105
4254
  var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
4106
4255
  var PARTNER_PROFILE_STATUSES = [
@@ -4127,126 +4276,126 @@ var WITHDRAWAL_STATES = [
4127
4276
  "failed",
4128
4277
  "reversed"
4129
4278
  ];
4130
- var PartnerProfileSchema = import_zod15.z.object({
4131
- partnerAccountId: import_zod15.z.string().uuid(),
4132
- kind: import_zod15.z.enum(PARTNER_KINDS),
4133
- custodialMode: import_zod15.z.enum(CUSTODIAL_MODES),
4134
- displayName: import_zod15.z.string(),
4135
- bankCode: import_zod15.z.string().nullable(),
4136
- poolAccountNumber: import_zod15.z.string().nullable(),
4137
- status: import_zod15.z.enum(PARTNER_PROFILE_STATUSES),
4279
+ var PartnerProfileSchema = import_zod16.z.object({
4280
+ partnerAccountId: import_zod16.z.string().uuid(),
4281
+ kind: import_zod16.z.enum(PARTNER_KINDS),
4282
+ custodialMode: import_zod16.z.enum(CUSTODIAL_MODES),
4283
+ displayName: import_zod16.z.string(),
4284
+ bankCode: import_zod16.z.string().nullable(),
4285
+ poolAccountNumber: import_zod16.z.string().nullable(),
4286
+ status: import_zod16.z.enum(PARTNER_PROFILE_STATUSES),
4138
4287
  metadata: Metadata,
4139
- createdAtMs: import_zod15.z.number().int().nonnegative(),
4140
- updatedAtMs: import_zod15.z.number().int().nonnegative()
4288
+ createdAtMs: import_zod16.z.number().int().nonnegative(),
4289
+ updatedAtMs: import_zod16.z.number().int().nonnegative()
4141
4290
  });
4142
- var UpsertPartnerProfileInputSchema = import_zod15.z.object({
4143
- kind: import_zod15.z.enum(PARTNER_KINDS),
4144
- custodialMode: import_zod15.z.enum(CUSTODIAL_MODES),
4145
- displayName: import_zod15.z.string().trim().min(1).max(200),
4146
- bankCode: import_zod15.z.string().trim().min(1).max(64).optional(),
4147
- poolAccountNumber: import_zod15.z.string().trim().min(1).max(64).optional(),
4291
+ var UpsertPartnerProfileInputSchema = import_zod16.z.object({
4292
+ kind: import_zod16.z.enum(PARTNER_KINDS),
4293
+ custodialMode: import_zod16.z.enum(CUSTODIAL_MODES),
4294
+ displayName: import_zod16.z.string().trim().min(1).max(200),
4295
+ bankCode: import_zod16.z.string().trim().min(1).max(64).optional(),
4296
+ poolAccountNumber: import_zod16.z.string().trim().min(1).max(64).optional(),
4148
4297
  metadata: Metadata.optional()
4149
4298
  });
4150
- var PartnerFundingEventInputSchema = import_zod15.z.object({
4151
- externalRef: import_zod15.z.string().trim().min(8).max(128),
4152
- direction: import_zod15.z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
4153
- userId: import_zod15.z.string().uuid().optional(),
4154
- accountId: import_zod15.z.string().uuid().optional(),
4299
+ var PartnerFundingEventInputSchema = import_zod16.z.object({
4300
+ externalRef: import_zod16.z.string().trim().min(8).max(128),
4301
+ direction: import_zod16.z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
4302
+ userId: import_zod16.z.string().uuid().optional(),
4303
+ accountId: import_zod16.z.string().uuid().optional(),
4155
4304
  amountMinor: PositiveMinor,
4156
4305
  currency: Currency,
4157
- fundingSource: import_zod15.z.string().trim().min(1).max(64).optional(),
4306
+ fundingSource: import_zod16.z.string().trim().min(1).max(64).optional(),
4158
4307
  providerMetadata: Metadata.optional()
4159
4308
  });
4160
- var PartnerFundingSchema = import_zod15.z.object({
4161
- fundingId: import_zod15.z.string().uuid(),
4162
- partnerId: import_zod15.z.string().uuid(),
4163
- accountId: import_zod15.z.string().uuid(),
4164
- userId: import_zod15.z.string().uuid().nullable(),
4165
- direction: import_zod15.z.enum(PARTNER_FUNDING_DIRECTIONS),
4166
- currency: import_zod15.z.string(),
4309
+ var PartnerFundingSchema = import_zod16.z.object({
4310
+ fundingId: import_zod16.z.string().uuid(),
4311
+ partnerId: import_zod16.z.string().uuid(),
4312
+ accountId: import_zod16.z.string().uuid(),
4313
+ userId: import_zod16.z.string().uuid().nullable(),
4314
+ direction: import_zod16.z.enum(PARTNER_FUNDING_DIRECTIONS),
4315
+ currency: import_zod16.z.string(),
4167
4316
  amountMinor: MinorString,
4168
- externalRef: import_zod15.z.string(),
4169
- status: import_zod15.z.enum(PARTNER_FUNDING_STATUSES),
4170
- fundingSource: import_zod15.z.string(),
4171
- ledgerRef: import_zod15.z.string(),
4317
+ externalRef: import_zod16.z.string(),
4318
+ status: import_zod16.z.enum(PARTNER_FUNDING_STATUSES),
4319
+ fundingSource: import_zod16.z.string(),
4320
+ ledgerRef: import_zod16.z.string(),
4172
4321
  providerMetadata: Metadata,
4173
- createdAtMs: import_zod15.z.number().int().nonnegative(),
4174
- updatedAtMs: import_zod15.z.number().int().nonnegative()
4322
+ createdAtMs: import_zod16.z.number().int().nonnegative(),
4323
+ updatedAtMs: import_zod16.z.number().int().nonnegative()
4175
4324
  });
4176
- var IngestFundingResultSchema = import_zod15.z.object({
4325
+ var IngestFundingResultSchema = import_zod16.z.object({
4177
4326
  funding: PartnerFundingSchema,
4178
- replayed: import_zod15.z.boolean()
4327
+ replayed: import_zod16.z.boolean()
4179
4328
  });
4180
- var PayoutDestinationSchema = import_zod15.z.object({
4181
- destinationId: import_zod15.z.string().uuid(),
4182
- accountId: import_zod15.z.string().uuid(),
4183
- partnerId: import_zod15.z.string().uuid(),
4184
- bankCode: import_zod15.z.string(),
4185
- accountNumber: import_zod15.z.string(),
4186
- accountName: import_zod15.z.string(),
4187
- status: import_zod15.z.enum(PAYOUT_DESTINATION_STATUSES),
4188
- verifiedAtMs: import_zod15.z.number().int().nonnegative().nullable(),
4329
+ var PayoutDestinationSchema = import_zod16.z.object({
4330
+ destinationId: import_zod16.z.string().uuid(),
4331
+ accountId: import_zod16.z.string().uuid(),
4332
+ partnerId: import_zod16.z.string().uuid(),
4333
+ bankCode: import_zod16.z.string(),
4334
+ accountNumber: import_zod16.z.string(),
4335
+ accountName: import_zod16.z.string(),
4336
+ status: import_zod16.z.enum(PAYOUT_DESTINATION_STATUSES),
4337
+ verifiedAtMs: import_zod16.z.number().int().nonnegative().nullable(),
4189
4338
  metadata: Metadata,
4190
- createdAtMs: import_zod15.z.number().int().nonnegative(),
4191
- updatedAtMs: import_zod15.z.number().int().nonnegative()
4339
+ createdAtMs: import_zod16.z.number().int().nonnegative(),
4340
+ updatedAtMs: import_zod16.z.number().int().nonnegative()
4192
4341
  });
4193
- var CreatePayoutDestinationInputSchema = import_zod15.z.object({
4194
- partnerId: import_zod15.z.string().uuid(),
4195
- bankCode: import_zod15.z.string().trim().min(1).max(32),
4196
- accountNumber: import_zod15.z.string().trim().min(4).max(64),
4197
- accountName: import_zod15.z.string().trim().min(1).max(200),
4342
+ var CreatePayoutDestinationInputSchema = import_zod16.z.object({
4343
+ partnerId: import_zod16.z.string().uuid(),
4344
+ bankCode: import_zod16.z.string().trim().min(1).max(32),
4345
+ accountNumber: import_zod16.z.string().trim().min(4).max(64),
4346
+ accountName: import_zod16.z.string().trim().min(1).max(200),
4198
4347
  metadata: Metadata.optional()
4199
4348
  });
4200
- var ListPayoutDestinationsResultSchema = import_zod15.z.object({
4201
- items: import_zod15.z.array(PayoutDestinationSchema)
4349
+ var ListPayoutDestinationsResultSchema = import_zod16.z.object({
4350
+ items: import_zod16.z.array(PayoutDestinationSchema)
4202
4351
  });
4203
- var WithdrawalSchema = import_zod15.z.object({
4204
- withdrawalId: import_zod15.z.string().uuid(),
4205
- accountId: import_zod15.z.string().uuid(),
4206
- userId: import_zod15.z.string().uuid(),
4207
- partnerId: import_zod15.z.string().uuid(),
4208
- destinationId: import_zod15.z.string().uuid(),
4209
- currency: import_zod15.z.string(),
4352
+ var WithdrawalSchema = import_zod16.z.object({
4353
+ withdrawalId: import_zod16.z.string().uuid(),
4354
+ accountId: import_zod16.z.string().uuid(),
4355
+ userId: import_zod16.z.string().uuid(),
4356
+ partnerId: import_zod16.z.string().uuid(),
4357
+ destinationId: import_zod16.z.string().uuid(),
4358
+ currency: import_zod16.z.string(),
4210
4359
  amountMinor: MinorString,
4211
- state: import_zod15.z.enum(WITHDRAWAL_STATES),
4212
- idempotencyKey: import_zod15.z.string(),
4213
- providerRef: import_zod15.z.string().nullable(),
4214
- lastError: import_zod15.z.string().nullable(),
4215
- ledgerRef: import_zod15.z.string(),
4216
- reverseLedgerRef: import_zod15.z.string().nullable(),
4360
+ state: import_zod16.z.enum(WITHDRAWAL_STATES),
4361
+ idempotencyKey: import_zod16.z.string(),
4362
+ providerRef: import_zod16.z.string().nullable(),
4363
+ lastError: import_zod16.z.string().nullable(),
4364
+ ledgerRef: import_zod16.z.string(),
4365
+ reverseLedgerRef: import_zod16.z.string().nullable(),
4217
4366
  metadata: Metadata,
4218
- createdAtMs: import_zod15.z.number().int().nonnegative(),
4219
- updatedAtMs: import_zod15.z.number().int().nonnegative()
4367
+ createdAtMs: import_zod16.z.number().int().nonnegative(),
4368
+ updatedAtMs: import_zod16.z.number().int().nonnegative()
4220
4369
  });
4221
- var CreateWithdrawalInputSchema = import_zod15.z.object({
4222
- destinationId: import_zod15.z.string().uuid(),
4370
+ var CreateWithdrawalInputSchema = import_zod16.z.object({
4371
+ destinationId: import_zod16.z.string().uuid(),
4223
4372
  amountMinor: PositiveMinor,
4224
4373
  currency: Currency,
4225
- idempotencyKey: import_zod15.z.string().trim().min(8).max(128),
4374
+ idempotencyKey: import_zod16.z.string().trim().min(8).max(128),
4226
4375
  metadata: Metadata.optional()
4227
4376
  });
4228
- var CreateWithdrawalResultSchema = import_zod15.z.object({
4377
+ var CreateWithdrawalResultSchema = import_zod16.z.object({
4229
4378
  withdrawal: WithdrawalSchema,
4230
- replayed: import_zod15.z.boolean()
4379
+ replayed: import_zod16.z.boolean()
4231
4380
  });
4232
- var PayoutEventInputSchema = import_zod15.z.object({
4233
- externalRef: import_zod15.z.string().trim().min(8).max(128),
4234
- withdrawalId: import_zod15.z.string().uuid().optional(),
4235
- state: import_zod15.z.enum(["submitted", "processing", "paid", "failed"]),
4236
- providerRef: import_zod15.z.string().trim().min(1).max(128).optional(),
4237
- failureCode: import_zod15.z.string().trim().max(64).optional(),
4238
- failureMessage: import_zod15.z.string().trim().max(512).optional(),
4381
+ var PayoutEventInputSchema = import_zod16.z.object({
4382
+ externalRef: import_zod16.z.string().trim().min(8).max(128),
4383
+ withdrawalId: import_zod16.z.string().uuid().optional(),
4384
+ state: import_zod16.z.enum(["submitted", "processing", "paid", "failed"]),
4385
+ providerRef: import_zod16.z.string().trim().min(1).max(128).optional(),
4386
+ failureCode: import_zod16.z.string().trim().max(64).optional(),
4387
+ failureMessage: import_zod16.z.string().trim().max(512).optional(),
4239
4388
  providerMetadata: Metadata.optional()
4240
4389
  });
4241
- var RecordPayoutEventResultSchema = import_zod15.z.object({
4390
+ var RecordPayoutEventResultSchema = import_zod16.z.object({
4242
4391
  withdrawal: WithdrawalSchema,
4243
- replayed: import_zod15.z.boolean()
4392
+ replayed: import_zod16.z.boolean()
4244
4393
  });
4245
- var ReconciliationReportSchema = import_zod15.z.object({
4246
- partnerId: import_zod15.z.string().uuid(),
4247
- currency: import_zod15.z.string(),
4248
- fromMs: import_zod15.z.number().int().nonnegative(),
4249
- toMs: import_zod15.z.number().int().nonnegative(),
4394
+ var ReconciliationReportSchema = import_zod16.z.object({
4395
+ partnerId: import_zod16.z.string().uuid(),
4396
+ currency: import_zod16.z.string(),
4397
+ fromMs: import_zod16.z.number().int().nonnegative(),
4398
+ toMs: import_zod16.z.number().int().nonnegative(),
4250
4399
  fundingsCreditMinor: MinorString,
4251
4400
  fundingsDebitMinor: MinorString,
4252
4401
  withdrawalsPaidMinor: MinorString,
@@ -4255,7 +4404,7 @@ var ReconciliationReportSchema = import_zod15.z.object({
4255
4404
  expectedReserveBalanceMinor: MinorString,
4256
4405
  actualReserveBalanceMinor: MinorString,
4257
4406
  imbalanceMinor: MinorString,
4258
- generatedAtMs: import_zod15.z.number().int().nonnegative()
4407
+ generatedAtMs: import_zod16.z.number().int().nonnegative()
4259
4408
  });
4260
4409
  function createPartnerFundingClient(partner) {
4261
4410
  return {
@@ -4407,19 +4556,19 @@ function createPartnerProfileAdminClient(opts) {
4407
4556
  }
4408
4557
 
4409
4558
  // src/artifacts/envelope.ts
4410
- var import_zod16 = require("zod");
4559
+ var import_zod17 = require("zod");
4411
4560
  var FLUR_ARTIFACT_URI_SCHEME = "flur";
4412
4561
  var FLUR_ARTIFACT_VERSION = 1;
4413
4562
  var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
4414
4563
  var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
4415
- var ArtifactHeaderSchema = import_zod16.z.object({
4416
- v: import_zod16.z.literal(FLUR_ARTIFACT_VERSION),
4417
- t: import_zod16.z.string().regex(ArtifactTypeRe, "invalid artifact type"),
4418
- iss: import_zod16.z.string().min(1).max(128),
4419
- kid: import_zod16.z.string().min(1).max(128),
4420
- iat: import_zod16.z.number().int().nonnegative(),
4421
- exp: import_zod16.z.number().int().positive().optional(),
4422
- nonce: import_zod16.z.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
4564
+ var ArtifactHeaderSchema = import_zod17.z.object({
4565
+ v: import_zod17.z.literal(FLUR_ARTIFACT_VERSION),
4566
+ t: import_zod17.z.string().regex(ArtifactTypeRe, "invalid artifact type"),
4567
+ iss: import_zod17.z.string().min(1).max(128),
4568
+ kid: import_zod17.z.string().min(1).max(128),
4569
+ iat: import_zod17.z.number().int().nonnegative(),
4570
+ exp: import_zod17.z.number().int().positive().optional(),
4571
+ nonce: import_zod17.z.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
4423
4572
  });
4424
4573
  var FlurArtifactError = class extends Error {
4425
4574
  constructor(message, code) {
@@ -4558,7 +4707,7 @@ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
4558
4707
  }
4559
4708
 
4560
4709
  // src/artifacts/types.ts
4561
- var import_zod17 = require("zod");
4710
+ var import_zod18 = require("zod");
4562
4711
  var ARTIFACT_TYPES = {
4563
4712
  OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
4564
4713
  RECEIPT: "receipt",
@@ -4571,37 +4720,34 @@ var ARTIFACT_TYPES = {
4571
4720
  LEDGER_JOURNAL_ENTRY: "ledger_journal_entry",
4572
4721
  STATEMENT: "statement",
4573
4722
  PASS: "pass",
4574
- IDENTITY: "identity",
4575
- // Tier B: holder-signed identity attestation for offline trust. The
4576
- // envelope.iat / envelope.exp express the card's canonical lifetime.
4577
- PAY_CARD: "pay_card"
4723
+ IDENTITY: "identity"
4578
4724
  };
4579
- var HexString = (length) => import_zod17.z.string().regex(
4725
+ var HexString = (length) => import_zod18.z.string().regex(
4580
4726
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
4581
4727
  `expected ${length}-byte hex string`
4582
4728
  );
4583
- var OfflinePaymentAuthorizationArtifactSchema = import_zod17.z.object({
4729
+ var OfflinePaymentAuthorizationArtifactSchema = import_zod18.z.object({
4584
4730
  authorization: OfflinePaymentAuthorizationSchema
4585
4731
  });
4586
- var ReceiptArtifactSchema = import_zod17.z.object({
4587
- receiptId: import_zod17.z.string().min(1).max(64),
4588
- paymentReference: import_zod17.z.string().min(1).max(64),
4589
- payerUserId: import_zod17.z.string().min(1).max(64).optional(),
4590
- payeeUserId: import_zod17.z.string().min(1).max(64),
4591
- amountKobo: import_zod17.z.number().int().positive(),
4592
- currency: import_zod17.z.literal("NGN"),
4593
- channel: import_zod17.z.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
4594
- settledAtMs: import_zod17.z.number().int().positive(),
4595
- ledgerTxnId: import_zod17.z.string().min(1).max(64).optional(),
4596
- memo: import_zod17.z.string().max(140).optional(),
4732
+ var ReceiptArtifactSchema = import_zod18.z.object({
4733
+ receiptId: import_zod18.z.string().min(1).max(64),
4734
+ paymentReference: import_zod18.z.string().min(1).max(64),
4735
+ payerUserId: import_zod18.z.string().min(1).max(64).optional(),
4736
+ payeeUserId: import_zod18.z.string().min(1).max(64),
4737
+ amountKobo: import_zod18.z.number().int().positive(),
4738
+ currency: import_zod18.z.literal("NGN"),
4739
+ channel: import_zod18.z.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
4740
+ settledAtMs: import_zod18.z.number().int().positive(),
4741
+ ledgerTxnId: import_zod18.z.string().min(1).max(64).optional(),
4742
+ memo: import_zod18.z.string().max(140).optional(),
4597
4743
  hashChainPrev: HexString(32).optional()
4598
4744
  });
4599
- var ShortId = import_zod17.z.string().min(1).max(64);
4600
- var PositiveInt = import_zod17.z.number().int().positive();
4601
- var NonNegativeInt = import_zod17.z.number().int().nonnegative();
4602
- var Currency2 = import_zod17.z.literal("NGN");
4603
- var Memo = import_zod17.z.string().max(140);
4604
- var NqrPaymentRequestArtifactSchema = import_zod17.z.object({
4745
+ var ShortId = import_zod18.z.string().min(1).max(64);
4746
+ var PositiveInt = import_zod18.z.number().int().positive();
4747
+ var NonNegativeInt = import_zod18.z.number().int().nonnegative();
4748
+ var Currency2 = import_zod18.z.literal("NGN");
4749
+ var Memo = import_zod18.z.string().max(140);
4750
+ var NqrPaymentRequestArtifactSchema = import_zod18.z.object({
4605
4751
  requestId: ShortId,
4606
4752
  payeeUserId: ShortId,
4607
4753
  amountKobo: PositiveInt.optional(),
@@ -4609,7 +4755,7 @@ var NqrPaymentRequestArtifactSchema = import_zod17.z.object({
4609
4755
  memo: Memo.optional(),
4610
4756
  expiresAtMs: PositiveInt.optional()
4611
4757
  });
4612
- var PaymentIntentArtifactSchema = import_zod17.z.object({
4758
+ var PaymentIntentArtifactSchema = import_zod18.z.object({
4613
4759
  intentId: ShortId,
4614
4760
  payerUserId: ShortId,
4615
4761
  payeeUserId: ShortId,
@@ -4618,7 +4764,7 @@ var PaymentIntentArtifactSchema = import_zod17.z.object({
4618
4764
  idempotencyKey: ShortId,
4619
4765
  createdAtMs: PositiveInt
4620
4766
  });
4621
- var OfflineClaimArtifactSchema = import_zod17.z.object({
4767
+ var OfflineClaimArtifactSchema = import_zod18.z.object({
4622
4768
  claimId: ShortId,
4623
4769
  authorizationId: ShortId,
4624
4770
  payeeUserId: ShortId,
@@ -4627,10 +4773,10 @@ var OfflineClaimArtifactSchema = import_zod17.z.object({
4627
4773
  claimedAtMs: PositiveInt,
4628
4774
  paymentReference: ShortId.optional()
4629
4775
  });
4630
- var SettlementRecordArtifactSchema = import_zod17.z.object({
4776
+ var SettlementRecordArtifactSchema = import_zod18.z.object({
4631
4777
  settlementId: ShortId,
4632
4778
  ledgerTxnId: ShortId,
4633
- sourceRefType: import_zod17.z.enum([
4779
+ sourceRefType: import_zod18.z.enum([
4634
4780
  "offline_authorization",
4635
4781
  "offline_claim",
4636
4782
  "transfer",
@@ -4641,12 +4787,12 @@ var SettlementRecordArtifactSchema = import_zod17.z.object({
4641
4787
  currency: Currency2,
4642
4788
  settledAtMs: PositiveInt
4643
4789
  });
4644
- var ReversalRecordArtifactSchema = import_zod17.z.object({
4790
+ var ReversalRecordArtifactSchema = import_zod18.z.object({
4645
4791
  reversalId: ShortId,
4646
4792
  originalTxnId: ShortId,
4647
4793
  amountKobo: PositiveInt,
4648
4794
  currency: Currency2,
4649
- reason: import_zod17.z.enum([
4795
+ reason: import_zod18.z.enum([
4650
4796
  "user_dispute",
4651
4797
  "fraud",
4652
4798
  "duplicate",
@@ -4656,7 +4802,7 @@ var ReversalRecordArtifactSchema = import_zod17.z.object({
4656
4802
  reversedAtMs: PositiveInt,
4657
4803
  memo: Memo.optional()
4658
4804
  });
4659
- var LedgerJournalEntryArtifactSchema = import_zod17.z.object({
4805
+ var LedgerJournalEntryArtifactSchema = import_zod18.z.object({
4660
4806
  entryId: ShortId,
4661
4807
  journalId: ShortId,
4662
4808
  debitAccountId: ShortId,
@@ -4667,13 +4813,13 @@ var LedgerJournalEntryArtifactSchema = import_zod17.z.object({
4667
4813
  refType: ShortId.optional(),
4668
4814
  refId: ShortId.optional()
4669
4815
  });
4670
- var StatementArtifactSchema = import_zod17.z.object({
4816
+ var StatementArtifactSchema = import_zod18.z.object({
4671
4817
  statementId: ShortId,
4672
4818
  userId: ShortId,
4673
4819
  periodStartMs: PositiveInt,
4674
4820
  periodEndMs: PositiveInt,
4675
- openingBalanceKobo: import_zod17.z.number().int(),
4676
- closingBalanceKobo: import_zod17.z.number().int(),
4821
+ openingBalanceKobo: import_zod18.z.number().int(),
4822
+ closingBalanceKobo: import_zod18.z.number().int(),
4677
4823
  transactionCount: NonNegativeInt,
4678
4824
  currency: Currency2,
4679
4825
  hashChainPrev: HexString(32).optional()
@@ -4681,16 +4827,16 @@ var StatementArtifactSchema = import_zod17.z.object({
4681
4827
  message: "periodEndMs must be greater than periodStartMs",
4682
4828
  path: ["periodEndMs"]
4683
4829
  });
4684
- var PassArtifactSchema = import_zod17.z.object({
4830
+ var PassArtifactSchema = import_zod18.z.object({
4685
4831
  passId: ShortId,
4686
4832
  holderId: ShortId,
4687
- category: import_zod17.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
4688
- title: import_zod17.z.string().min(1).max(120),
4833
+ category: import_zod18.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
4834
+ title: import_zod18.z.string().min(1).max(120),
4689
4835
  validFromMs: PositiveInt,
4690
4836
  validUntilMs: PositiveInt.optional(),
4691
- metadata: import_zod17.z.record(
4692
- import_zod17.z.string().min(1).max(64),
4693
- import_zod17.z.union([import_zod17.z.string().max(280), import_zod17.z.number(), import_zod17.z.boolean()])
4837
+ metadata: import_zod18.z.record(
4838
+ import_zod18.z.string().min(1).max(64),
4839
+ import_zod18.z.union([import_zod18.z.string().max(280), import_zod18.z.number(), import_zod18.z.boolean()])
4694
4840
  ).optional()
4695
4841
  }).refine(
4696
4842
  (v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
@@ -4699,10 +4845,10 @@ var PassArtifactSchema = import_zod17.z.object({
4699
4845
  path: ["validUntilMs"]
4700
4846
  }
4701
4847
  );
4702
- var IdentityArtifactSchema = import_zod17.z.object({
4848
+ var IdentityArtifactSchema = import_zod18.z.object({
4703
4849
  attestationId: ShortId,
4704
4850
  subjectId: ShortId,
4705
- claimType: import_zod17.z.enum([
4851
+ claimType: import_zod18.z.enum([
4706
4852
  "phone_verified",
4707
4853
  "email_verified",
4708
4854
  "bvn_verified",
@@ -4712,12 +4858,6 @@ var IdentityArtifactSchema = import_zod17.z.object({
4712
4858
  claimValueHash: HexString(32),
4713
4859
  attestedAtMs: PositiveInt
4714
4860
  });
4715
- var PayCardArtifactSchema = import_zod17.z.object({
4716
- userId: ShortId,
4717
- phoneE164: import_zod17.z.string().regex(/^\+[1-9]\d{7,14}$/, "phoneE164 must be normalised E.164"),
4718
- displayName: import_zod17.z.string().min(1).max(64),
4719
- devicePubKeySpkiB64: import_zod17.z.string().min(64).max(256).regex(/^[A-Za-z0-9+/]+=*$/, "devicePubKeySpkiB64 must be standard base64")
4720
- });
4721
4861
  var ARTIFACT_BODY_SCHEMAS = {
4722
4862
  [ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]: OfflinePaymentAuthorizationArtifactSchema,
4723
4863
  [ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,
@@ -4729,8 +4869,7 @@ var ARTIFACT_BODY_SCHEMAS = {
4729
4869
  [ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,
4730
4870
  [ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,
4731
4871
  [ARTIFACT_TYPES.PASS]: PassArtifactSchema,
4732
- [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema,
4733
- [ARTIFACT_TYPES.PAY_CARD]: PayCardArtifactSchema
4872
+ [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
4734
4873
  };
4735
4874
  var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4736
4875
  ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,
@@ -4743,8 +4882,7 @@ var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4743
4882
  ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,
4744
4883
  ARTIFACT_TYPES.STATEMENT,
4745
4884
  ARTIFACT_TYPES.PASS,
4746
- ARTIFACT_TYPES.IDENTITY,
4747
- ARTIFACT_TYPES.PAY_CARD
4885
+ ARTIFACT_TYPES.IDENTITY
4748
4886
  ]);
4749
4887
  function isKnownArtifactType(t) {
4750
4888
  return Object.values(ARTIFACT_TYPES).includes(t);
@@ -4829,130 +4967,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4829
4967
  type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION
4830
4968
  });
4831
4969
  }
4832
-
4833
- // src/artifacts/paycard.ts
4834
- var PAY_CARD_DEFAULT_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
4835
- var PAY_CARD_REFRESH_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1e3;
4836
- var PAY_CARD_URI_PREFIX = `${FLUR_ARTIFACT_URI_PREFIX}${ARTIFACT_TYPES.PAY_CARD}/`;
4837
- function createPayCardArtifactUri(input) {
4838
- if (input.data.userId !== input.issuer) {
4839
- throw new FlurArtifactError(
4840
- "pay_card.data.userId must equal envelope issuer",
4841
- "INVALID_BODY"
4842
- );
4843
- }
4844
- const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
4845
- const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
4846
- return createArtifactUri({
4847
- type: ARTIFACT_TYPES.PAY_CARD,
4848
- issuer: input.issuer,
4849
- keyId: input.keyId,
4850
- privateKey: input.privateKey,
4851
- nonce: input.nonce,
4852
- issuedAtSeconds: iat,
4853
- expiresAtSeconds: exp,
4854
- data: input.data
4855
- });
4856
- }
4857
- function isPayCardArtifactUri(uri) {
4858
- return typeof uri === "string" && uri.startsWith(PAY_CARD_URI_PREFIX);
4859
- }
4860
- function decodePayCardArtifact(uri) {
4861
- if (!isPayCardArtifactUri(uri)) {
4862
- throw new FlurArtifactError(
4863
- `URI does not start with ${PAY_CARD_URI_PREFIX}`,
4864
- "INVALID_URI"
4865
- );
4866
- }
4867
- const decoded = decodeArtifactUri(uri);
4868
- if (decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
4869
- throw new FlurArtifactError(
4870
- `Expected pay_card, got ${decoded.type}`,
4871
- "TYPE_MISMATCH"
4872
- );
4873
- }
4874
- const parsed = PayCardArtifactSchema.safeParse(decoded.body.data);
4875
- if (!parsed.success) {
4876
- throw new FlurArtifactError(
4877
- `pay_card body invalid: ${parsed.error.message}`,
4878
- "INVALID_BODY"
4879
- );
4880
- }
4881
- if (parsed.data.userId !== decoded.body.iss) {
4882
- throw new FlurArtifactError(
4883
- "pay_card.data.userId must equal envelope issuer",
4884
- "INVALID_BODY"
4885
- );
4886
- }
4887
- return {
4888
- body: {
4889
- ...decoded.body,
4890
- data: parsed.data
4891
- },
4892
- sig: decoded.sig,
4893
- decoded
4894
- };
4895
- }
4896
- function verifyPayCardArtifact(uri, publicKeySpkiB64, options = {}) {
4897
- if (!isPayCardArtifactUri(uri)) {
4898
- throw new FlurArtifactError(
4899
- `URI does not start with ${PAY_CARD_URI_PREFIX}`,
4900
- "INVALID_URI"
4901
- );
4902
- }
4903
- const verified = verifyArtifactUri(
4904
- uri,
4905
- publicKeySpkiB64,
4906
- options
4907
- );
4908
- if (verified.decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
4909
- throw new FlurArtifactError(
4910
- `Expected pay_card, got ${verified.decoded.type}`,
4911
- "TYPE_MISMATCH"
4912
- );
4913
- }
4914
- if (verified.body.data.userId !== verified.body.iss) {
4915
- throw new FlurArtifactError(
4916
- "pay_card.data.userId must equal envelope issuer",
4917
- "INVALID_BODY"
4918
- );
4919
- }
4920
- return {
4921
- body: verified.body,
4922
- sig: verified.sig,
4923
- decoded: verified.decoded
4924
- };
4925
- }
4926
- function inspectPayCardFreshness(decoded, nowMs = Date.now()) {
4927
- const exp = decoded.body.exp;
4928
- if (exp === void 0) return "no_expiry";
4929
- const remainingMs = exp * 1e3 - nowMs;
4930
- if (remainingMs <= 0) return "expired";
4931
- if (remainingMs <= PAY_CARD_REFRESH_THRESHOLD_MS)
4932
- return "refresh_recommended";
4933
- return "fresh";
4934
- }
4935
- function buildPayCardSigningInput(input) {
4936
- if (input.data.userId !== input.issuer) {
4937
- throw new FlurArtifactError(
4938
- "pay_card.data.userId must equal envelope issuer",
4939
- "INVALID_BODY"
4940
- );
4941
- }
4942
- const parsedData = PayCardArtifactSchema.parse(input.data);
4943
- const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
4944
- const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
4945
- const body = buildArtifactBody({
4946
- type: ARTIFACT_TYPES.PAY_CARD,
4947
- issuer: input.issuer,
4948
- keyId: input.keyId,
4949
- data: parsedData,
4950
- nonce: input.nonce,
4951
- issuedAtSeconds: iat,
4952
- expiresAtSeconds: exp
4953
- });
4954
- return { body, bodyBytes: canonicalJSONBytes(body) };
4955
- }
4956
4970
  // Annotate the CommonJS export names for ESM import in node:
4957
4971
  0 && (module.exports = {
4958
4972
  ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
@@ -4969,6 +4983,8 @@ function buildPayCardSigningInput(input) {
4969
4983
  CLAIM_DOMAIN_V2,
4970
4984
  COLLECTION_INTENT_STATUSES,
4971
4985
  COLLECTION_PAYMENT_STATUSES,
4986
+ CONSUMER_OAC_DOMAIN,
4987
+ CONSUMER_OAC_QR_PREFIX,
4972
4988
  CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
4973
4989
  CONSUMER_PAYMENT_REQUEST_DOMAIN,
4974
4990
  CONSUMER_SETTLEMENT_DOMAIN,
@@ -5007,6 +5023,8 @@ function buildPayCardSigningInput(input) {
5007
5023
  IdentityArtifactSchema,
5008
5024
  IngestFundingResultSchema,
5009
5025
  IssueAccountOacInputSchema,
5026
+ IssuerTrustBundleSchema,
5027
+ IssuerTrustKeySchema,
5010
5028
  LedgerJournalEntryArtifactSchema,
5011
5029
  ListPayoutDestinationsResultSchema,
5012
5030
  MEMBERSHIP_ROLES,
@@ -5030,6 +5048,7 @@ function buildPayCardSigningInput(input) {
5030
5048
  OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
5031
5049
  OFFLINE_SMS_SETTLE_TOKEN_BYTES,
5032
5050
  OFFLINE_SMS_SETTLE_VERSION,
5051
+ OacPresentmentRequestSchema,
5033
5052
  OfflineClaimArtifactSchema,
5034
5053
  OfflinePaymentAuthorizationArtifactSchema,
5035
5054
  OfflinePaymentAuthorizationSchema,
@@ -5047,9 +5066,6 @@ function buildPayCardSigningInput(input) {
5047
5066
  PASS_STATES,
5048
5067
  PAYLOAD_FORMAT_INDICATOR_VALUE,
5049
5068
  PAYOUT_DESTINATION_STATUSES,
5050
- PAY_CARD_DEFAULT_TTL_MS,
5051
- PAY_CARD_REFRESH_THRESHOLD_MS,
5052
- PAY_CARD_URI_PREFIX,
5053
5069
  POINT_OF_INITIATION,
5054
5070
  PartnerFundingEventInputSchema,
5055
5071
  PartnerFundingSchema,
@@ -5057,7 +5073,6 @@ function buildPayCardSigningInput(input) {
5057
5073
  PassArtifactSchema,
5058
5074
  PassMetadataSchema,
5059
5075
  PassSchema,
5060
- PayCardArtifactSchema,
5061
5076
  PayCollectionInputSchema,
5062
5077
  PaymentClaimSchema,
5063
5078
  PaymentIntentArtifactSchema,
@@ -5096,7 +5111,6 @@ function buildPayCardSigningInput(input) {
5096
5111
  buildConsumerPaymentRequest,
5097
5112
  buildOAC,
5098
5113
  buildPass,
5099
- buildPayCardSigningInput,
5100
5114
  buildPaymentRequest,
5101
5115
  buildReceipt,
5102
5116
  buildRedemption,
@@ -5110,6 +5124,7 @@ function buildPayCardSigningInput(input) {
5110
5124
  computeConsumerClaimEncounterId,
5111
5125
  computeEncounterId,
5112
5126
  constantTimeEqual,
5127
+ consumerOacSigningPayload,
5113
5128
  consumerPaymentRequestSigningBytes,
5114
5129
  consumerPaymentRequestSigningPayload,
5115
5130
  consumerSettlementSigningPayload,
@@ -5130,23 +5145,24 @@ function buildPayCardSigningInput(input) {
5130
5145
  createPartnerFundingClient,
5131
5146
  createPartnerProfileAdminClient,
5132
5147
  createPassesClient,
5133
- createPayCardArtifactUri,
5134
5148
  createReceiptArtifactUri,
5135
5149
  createReceiptsClient,
5136
5150
  createSoftwareP256Signer,
5137
5151
  decodeArtifactUri,
5138
5152
  decodeAuthorizationQR,
5139
5153
  decodeBase45,
5154
+ decodeConsumerOacRequest,
5140
5155
  decodeConsumerSettlementReceiptQR,
5141
5156
  decodeOfflineClaimSmsMessage,
5142
5157
  decodeOfflineSmsSettleToken,
5143
- decodePayCardArtifact,
5144
5158
  decodePaymentRequestQR,
5159
+ decodeUnverifiedConsumerOacQR,
5145
5160
  decodeUnverifiedConsumerSettlementReceiptQR,
5146
5161
  derToRawP256Signature,
5147
5162
  encodeArtifactUri,
5148
5163
  encodeAuthorizationQR,
5149
5164
  encodeBase45,
5165
+ encodeConsumerOacQR,
5150
5166
  encodeConsumerSettlementReceiptQR,
5151
5167
  encodeNQR,
5152
5168
  encodeOfflineClaimSmsMessage,
@@ -5158,12 +5174,11 @@ function buildPayCardSigningInput(input) {
5158
5174
  generateDynamicQR,
5159
5175
  generateStaticQR,
5160
5176
  init,
5161
- inspectPayCardFreshness,
5177
+ isConsumerOacQR,
5162
5178
  isConsumerPaymentRequestExpired,
5163
5179
  isHardenedArtifactType,
5164
5180
  isKnownArtifactType,
5165
5181
  isPassWithinValidity,
5166
- isPayCardArtifactUri,
5167
5182
  moneyMinorToNumber,
5168
5183
  normalizeE164,
5169
5184
  parseAmountInput,
@@ -5189,9 +5204,9 @@ function buildPayCardSigningInput(input) {
5189
5204
  verifyConsumerSettlement,
5190
5205
  verifyConsumerSettlementReceiptQR,
5191
5206
  verifyOAC,
5207
+ verifyOacOffline,
5192
5208
  verifyOfflineSmsSettleToken,
5193
5209
  verifyPass,
5194
- verifyPayCardArtifact,
5195
5210
  verifyPaymentRequest,
5196
5211
  verifyReceipt,
5197
5212
  verifyRedemption,