@nokinc-flur/sdk 2.3.0 → 2.5.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.js CHANGED
@@ -2955,76 +2955,142 @@ function createAccountsClient(opts) {
2955
2955
  }
2956
2956
 
2957
2957
  // src/me-offline/client.ts
2958
+ import { z as z14 } from "zod";
2959
+
2960
+ // src/me-offline/revocation.ts
2958
2961
  import { z as z13 } from "zod";
2959
- var Sha256Hex = z13.string().regex(/^[0-9a-f]{64}$/);
2960
2962
  var Base64Std3 = z13.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
2961
- var ClaimNonce = z13.string().min(8).max(128).refine((value) => !value.includes("|"), {
2963
+ var CONSUMER_REVOCATION_DOMAIN = "flur:consumer-offline:v1:revocation";
2964
+ var REVOCATION_LIST_MAX_ENTRIES = 1e5;
2965
+ var RevocationListSchema = z13.object({
2966
+ issuerId: z13.string().min(1).max(64),
2967
+ /**
2968
+ * Monotonic snapshot counter. A device MUST NOT replace a pinned list with
2969
+ * one carrying a lower sequence — this defeats a downgrade/rollback attack
2970
+ * that replays an older list to resurrect a revoked credential.
2971
+ */
2972
+ sequence: z13.number().int().nonnegative(),
2973
+ issuedAtMs: z13.number().int().nonnegative(),
2974
+ /**
2975
+ * Freshness bound. After this instant the list is considered stale and the
2976
+ * verifier treats it as untrustworthy (fail-closed), forcing a re-pin.
2977
+ * Optional so the issuer may publish a list without a hard expiry.
2978
+ */
2979
+ notAfterMs: z13.number().int().positive().optional(),
2980
+ /** OAC ids that are revoked AND not yet past their own validity window. */
2981
+ revokedOacIds: z13.array(z13.string().uuid()).max(REVOCATION_LIST_MAX_ENTRIES)
2982
+ });
2983
+ var SignedRevocationListSchema = z13.object({
2984
+ list: RevocationListSchema,
2985
+ /** ASN.1 DER ECDSA P-256 issuer signature over the signing payload, base64. */
2986
+ issuerSig: Base64Std3.min(16).max(2048),
2987
+ /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
2988
+ issuerPublicKeySpkiB64: Base64Std3.min(64).max(4096)
2989
+ });
2990
+ function revocationListSigningPayload(list) {
2991
+ const payload = {
2992
+ domain: CONSUMER_REVOCATION_DOMAIN,
2993
+ issuerId: list.issuerId,
2994
+ sequence: list.sequence,
2995
+ issuedAtMs: list.issuedAtMs,
2996
+ revokedOacIds: list.revokedOacIds
2997
+ };
2998
+ if (list.notAfterMs !== void 0) payload.notAfterMs = list.notAfterMs;
2999
+ return payload;
3000
+ }
3001
+ function verifyRevocationList(signed, trustedKeys, options = {}) {
3002
+ const parsed = SignedRevocationListSchema.safeParse(signed);
3003
+ if (!parsed.success) return { ok: false, reason: "malformed" };
3004
+ const list = parsed.data.list;
3005
+ const nowMs = options.nowMs ?? Date.now();
3006
+ const pinned = trustedKeys.filter(
3007
+ (k) => k.issuerId === list.issuerId && (k.notBeforeMs === void 0 || nowMs >= k.notBeforeMs) && (k.notAfterMs === void 0 || nowMs <= k.notAfterMs)
3008
+ );
3009
+ if (pinned.length === 0) return { ok: false, reason: "untrusted_issuer" };
3010
+ const signingBytes = canonicalJSONBytes(revocationListSigningPayload(list));
3011
+ const signatureOk = pinned.some(
3012
+ (k) => verifyIssuerP256(signingBytes, parsed.data.issuerSig, k.publicKeySpkiB64)
3013
+ );
3014
+ if (!signatureOk) return { ok: false, reason: "signature_invalid" };
3015
+ if (list.notAfterMs !== void 0 && nowMs > list.notAfterMs) {
3016
+ return { ok: false, reason: "stale" };
3017
+ }
3018
+ return { ok: true, list, revokedOacIds: new Set(list.revokedOacIds) };
3019
+ }
3020
+ function isOacRevoked(oacId, revokedOacIds) {
3021
+ return revokedOacIds.has(oacId);
3022
+ }
3023
+
3024
+ // src/me-offline/client.ts
3025
+ var Sha256Hex = z14.string().regex(/^[0-9a-f]{64}$/);
3026
+ var Base64Std4 = z14.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3027
+ var ClaimNonce = z14.string().min(8).max(128).refine((value) => !value.includes("|"), {
2962
3028
  message: "nonce must not contain |"
2963
3029
  });
2964
3030
  var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24;
2965
- var IssuerTrustKeySchema = z13.object({
2966
- issuerId: z13.string().min(1).max(128),
2967
- alg: z13.literal("p256"),
2968
- publicKeySpkiB64: Base64Std3.min(64).max(4096),
2969
- notBeforeMs: z13.number().int().nonnegative().optional(),
2970
- notAfterMs: z13.number().int().positive().optional()
3031
+ var IssuerTrustKeySchema = z14.object({
3032
+ issuerId: z14.string().min(1).max(128),
3033
+ alg: z14.literal("p256"),
3034
+ publicKeySpkiB64: Base64Std4.min(64).max(4096),
3035
+ notBeforeMs: z14.number().int().nonnegative().optional(),
3036
+ notAfterMs: z14.number().int().positive().optional()
2971
3037
  });
2972
- var IssuerTrustBundleSchema = z13.object({
2973
- keys: z13.array(IssuerTrustKeySchema).min(1)
3038
+ var IssuerTrustBundleSchema = z14.object({
3039
+ keys: z14.array(IssuerTrustKeySchema).min(1)
2974
3040
  });
2975
3041
  var CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1e3 * 60 * 60 * 24;
2976
- var AttestationSecurityLevelSchema = z13.enum([
3042
+ var AttestationSecurityLevelSchema = z14.enum([
2977
3043
  "STRONGBOX",
2978
3044
  "TEE",
2979
3045
  "SECURE_ENCLAVE",
2980
3046
  "SOFTWARE"
2981
3047
  ]);
2982
- var DeviceKeyAlgSchema = z13.literal("p256");
2983
- var RegisterDeviceKeyP256InputSchema = z13.object({
2984
- deviceId: z13.string().min(1).max(128),
3048
+ var DeviceKeyAlgSchema = z14.literal("p256");
3049
+ var RegisterDeviceKeyP256InputSchema = z14.object({
3050
+ deviceId: z14.string().min(1).max(128),
2985
3051
  /** P-256 SubjectPublicKeyInfo DER, base64. */
2986
- publicKeySpkiB64: Base64Std3.min(64).max(4096),
3052
+ publicKeySpkiB64: Base64Std4.min(64).max(4096),
2987
3053
  /** Base64 of the server-issued enrollment challenge string. */
2988
- challengeB64: Base64Std3.min(8).max(1024),
3054
+ challengeB64: Base64Std4.min(8).max(1024),
2989
3055
  /** iOS App Attest payload or Android X.509 Key Attestation chain. */
2990
- attestationChainB64: z13.array(Base64Std3.min(16).max(16384)).min(1).max(16),
3056
+ attestationChainB64: z14.array(Base64Std4.min(16).max(16384)).min(1).max(16),
2991
3057
  securityLevel: AttestationSecurityLevelSchema
2992
3058
  });
2993
- var P256EnrollmentChallengeInputSchema = z13.object({
2994
- deviceId: z13.string().min(1).max(128)
3059
+ var P256EnrollmentChallengeInputSchema = z14.object({
3060
+ deviceId: z14.string().min(1).max(128)
2995
3061
  });
2996
- var P256EnrollmentChallengeResultSchema = z13.object({
2997
- challenge: z13.string().min(16),
2998
- expiresAtMs: z13.number().int().positive()
3062
+ var P256EnrollmentChallengeResultSchema = z14.object({
3063
+ challenge: z14.string().min(16),
3064
+ expiresAtMs: z14.number().int().positive()
2999
3065
  });
3000
- var DeviceKeyRecordSchema = z13.object({
3001
- id: z13.string().uuid(),
3002
- userId: z13.string().uuid(),
3003
- deviceId: z13.string(),
3066
+ var DeviceKeyRecordSchema = z14.object({
3067
+ id: z14.string().uuid(),
3068
+ userId: z14.string().uuid(),
3069
+ deviceId: z14.string(),
3004
3070
  /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
3005
3071
  alg: DeviceKeyAlgSchema.default("p256"),
3006
3072
  /** P-256 SubjectPublicKeyInfo DER, base64. */
3007
- publicKeySpkiB64: Base64Std3.nullable().default(null),
3073
+ publicKeySpkiB64: Base64Std4.nullable().default(null),
3008
3074
  securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
3009
- hardwareBacked: z13.boolean().default(false),
3010
- attestedAtMs: z13.number().int().nonnegative().nullable().default(null),
3011
- createdAtMs: z13.number().int().nonnegative(),
3012
- revokedAtMs: z13.number().int().nonnegative().nullable()
3075
+ hardwareBacked: z14.boolean().default(false),
3076
+ attestedAtMs: z14.number().int().nonnegative().nullable().default(null),
3077
+ createdAtMs: z14.number().int().nonnegative(),
3078
+ revokedAtMs: z14.number().int().nonnegative().nullable()
3013
3079
  });
3014
- var ConsumerOACSchema = z13.object({
3015
- oacId: z13.string().uuid(),
3016
- issuerId: z13.string().min(1).max(64),
3017
- userId: z13.string().uuid(),
3018
- deviceId: z13.string().min(1).max(128),
3080
+ var ConsumerOACSchema = z14.object({
3081
+ oacId: z14.string().uuid(),
3082
+ issuerId: z14.string().min(1).max(64),
3083
+ userId: z14.string().uuid(),
3084
+ deviceId: z14.string().min(1).max(128),
3019
3085
  /**
3020
3086
  * Always 'p256'. Required on the wire (backend always emits it).
3021
3087
  * Kept as a literal so input/output infer identically and the schema
3022
3088
  * can be nested inside other response shapes without Zod input/output
3023
3089
  * divergence under tsup DTS bundling.
3024
3090
  */
3025
- alg: z13.literal("p256"),
3091
+ alg: z14.literal("p256"),
3026
3092
  /** P-256 SubjectPublicKeyInfo DER, base64. */
3027
- devicePubkeySpkiB64: Base64Std3.min(64).max(4096),
3093
+ devicePubkeySpkiB64: Base64Std4.min(64).max(4096),
3028
3094
  /**
3029
3095
  * Per-transaction / cumulative offline spend ceilings. Zero is valid and
3030
3096
  * denotes an identity-only OAC: the credential proves who the holder is and
@@ -3032,104 +3098,104 @@ var ConsumerOACSchema = z13.object({
3032
3098
  * no offline spend authority (every claim against it routes to REVIEW).
3033
3099
  * Issued to zero-balance wallets so they can still be paid offline.
3034
3100
  */
3035
- perTxCapKobo: z13.number().int().nonnegative(),
3036
- cumulativeCapKobo: z13.number().int().nonnegative(),
3037
- currency: z13.string().length(3),
3038
- validFromMs: z13.number().int().nonnegative(),
3039
- validUntilMs: z13.number().int().nonnegative(),
3040
- counterSeed: z13.number().int().nonnegative(),
3041
- issuedAtMs: z13.number().int().nonnegative(),
3101
+ perTxCapKobo: z14.number().int().nonnegative(),
3102
+ cumulativeCapKobo: z14.number().int().nonnegative(),
3103
+ currency: z14.string().length(3),
3104
+ validFromMs: z14.number().int().nonnegative(),
3105
+ validUntilMs: z14.number().int().nonnegative(),
3106
+ counterSeed: z14.number().int().nonnegative(),
3107
+ issuedAtMs: z14.number().int().nonnegative(),
3042
3108
  /**
3043
3109
  * Issuer-attested identity folded into the OAC so a single signed
3044
3110
  * credential serves both Tier B offline-verifiable identity and offline
3045
3111
  * spend authority. Verified offline against a pinned issuer key; the
3046
3112
  * backend remains authoritative at settlement.
3047
3113
  */
3048
- phoneE164: z13.string().regex(/^\+[1-9]\d{7,14}$/),
3049
- displayName: z13.string().min(1).max(64)
3114
+ phoneE164: z14.string().regex(/^\+[1-9]\d{7,14}$/),
3115
+ displayName: z14.string().min(1).max(64)
3050
3116
  });
3051
- var SignedConsumerOACSchema = z13.object({
3117
+ var SignedConsumerOACSchema = z14.object({
3052
3118
  oac: ConsumerOACSchema,
3053
3119
  /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
3054
- issuerSig: Base64Std3.min(16).max(2048),
3120
+ issuerSig: Base64Std4.min(16).max(2048),
3055
3121
  /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
3056
- issuerPublicKeySpkiB64: Base64Std3.min(64).max(4096)
3122
+ issuerPublicKeySpkiB64: Base64Std4.min(64).max(4096)
3057
3123
  });
3058
3124
  var OACRecordSchema = SignedConsumerOACSchema.extend({
3059
- currentOfflineSpentKobo: z13.number().int().nonnegative(),
3060
- status: z13.enum(["active", "superseded", "expired", "revoked"]),
3061
- supersededAtMs: z13.number().int().nonnegative().nullable(),
3062
- revokedAtMs: z13.number().int().nonnegative().nullable()
3125
+ currentOfflineSpentKobo: z14.number().int().nonnegative(),
3126
+ status: z14.enum(["active", "superseded", "expired", "revoked"]),
3127
+ supersededAtMs: z14.number().int().nonnegative().nullable(),
3128
+ revokedAtMs: z14.number().int().nonnegative().nullable()
3063
3129
  });
3064
- var IssueAccountOacInputSchema = z13.object({
3065
- deviceId: z13.string().min(1).max(128),
3066
- perTxCapKobo: z13.number().int().positive().optional(),
3067
- cumulativeCapKobo: z13.number().int().positive().optional(),
3068
- ttlMs: z13.number().int().min(6e4).max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS).optional()
3130
+ var IssueAccountOacInputSchema = z14.object({
3131
+ deviceId: z14.string().min(1).max(128),
3132
+ perTxCapKobo: z14.number().int().positive().optional(),
3133
+ cumulativeCapKobo: z14.number().int().positive().optional(),
3134
+ ttlMs: z14.number().int().min(6e4).max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS).optional()
3069
3135
  });
3070
- var OfflineStatusResultSchema = z13.object({
3136
+ var OfflineStatusResultSchema = z14.object({
3071
3137
  active: OACRecordSchema.nullable()
3072
3138
  });
3073
- var ConsumerPaymentClaimSchema = z13.object({
3139
+ var ConsumerPaymentClaimSchema = z14.object({
3074
3140
  /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
3075
- alg: z13.literal("p256").default("p256"),
3076
- oacId: z13.string().uuid(),
3141
+ alg: z14.literal("p256").default("p256"),
3142
+ oacId: z14.string().uuid(),
3077
3143
  encounterId: Sha256Hex.optional(),
3078
- payerUserId: z13.string().uuid(),
3079
- payeeUserId: z13.string().uuid(),
3080
- payerDeviceId: z13.string().min(1).max(128),
3144
+ payerUserId: z14.string().uuid(),
3145
+ payeeUserId: z14.string().uuid(),
3146
+ payerDeviceId: z14.string().min(1).max(128),
3081
3147
  payerNonce: ClaimNonce,
3082
3148
  payeeNonce: ClaimNonce,
3083
- amountKobo: z13.number().int().positive(),
3084
- currency: z13.string().length(3).default("NGN"),
3085
- occurredAtMs: z13.number().int().nonnegative(),
3086
- completedAtMs: z13.number().int().nonnegative().optional(),
3087
- contextId: z13.string().max(128).optional(),
3088
- requestId: z13.string().uuid().optional(),
3089
- requestMode: z13.enum(["fixed", "editable"]).optional(),
3090
- requestTakerUserId: z13.string().uuid().optional(),
3091
- requestAmountKobo: z13.number().int().positive().optional(),
3092
- requestCurrency: z13.string().length(3).optional(),
3093
- requestReference: z13.string().max(128).nullable().optional(),
3094
- requestCreatedAtMs: z13.number().int().nonnegative().optional(),
3095
- requestExpiresAtMs: z13.number().int().positive().optional(),
3096
- requestNonce: z13.string().min(8).max(128).optional(),
3097
- requestTakerDeviceId: z13.string().min(1).max(128).nullable().optional(),
3098
- requestTakerPubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
3099
- requestTakerSignatureDerB64: Base64Std3.min(16).max(2048).optional(),
3100
- payerPubkeySpkiB64: Base64Std3.min(64).max(4096),
3101
- payerSignatureDerB64: Base64Std3.min(16).max(2048),
3102
- payeePubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
3103
- payeeSignatureDerB64: Base64Std3.min(16).max(2048).optional()
3149
+ amountKobo: z14.number().int().positive(),
3150
+ currency: z14.string().length(3).default("NGN"),
3151
+ occurredAtMs: z14.number().int().nonnegative(),
3152
+ completedAtMs: z14.number().int().nonnegative().optional(),
3153
+ contextId: z14.string().max(128).optional(),
3154
+ requestId: z14.string().uuid().optional(),
3155
+ requestMode: z14.enum(["fixed", "editable"]).optional(),
3156
+ requestTakerUserId: z14.string().uuid().optional(),
3157
+ requestAmountKobo: z14.number().int().positive().optional(),
3158
+ requestCurrency: z14.string().length(3).optional(),
3159
+ requestReference: z14.string().max(128).nullable().optional(),
3160
+ requestCreatedAtMs: z14.number().int().nonnegative().optional(),
3161
+ requestExpiresAtMs: z14.number().int().positive().optional(),
3162
+ requestNonce: z14.string().min(8).max(128).optional(),
3163
+ requestTakerDeviceId: z14.string().min(1).max(128).nullable().optional(),
3164
+ requestTakerPubkeySpkiB64: Base64Std4.min(64).max(4096).optional(),
3165
+ requestTakerSignatureDerB64: Base64Std4.min(16).max(2048).optional(),
3166
+ payerPubkeySpkiB64: Base64Std4.min(64).max(4096),
3167
+ payerSignatureDerB64: Base64Std4.min(16).max(2048),
3168
+ payeePubkeySpkiB64: Base64Std4.min(64).max(4096).optional(),
3169
+ payeeSignatureDerB64: Base64Std4.min(16).max(2048).optional()
3104
3170
  });
3105
- var ConsumerSettlementSchema = z13.object({
3106
- settlementId: z13.string().uuid(),
3171
+ var ConsumerSettlementSchema = z14.object({
3172
+ settlementId: z14.string().uuid(),
3107
3173
  settlementKey: Sha256Hex,
3108
3174
  encounterId: Sha256Hex,
3109
- oacId: z13.string().uuid(),
3110
- payerUserId: z13.string().uuid(),
3111
- payeeUserId: z13.string().uuid(),
3112
- amountKobo: z13.number().int().positive(),
3113
- currency: z13.string().length(3),
3114
- status: z13.enum(["SETTLED", "REVIEW"]),
3115
- reviewReason: z13.string().nullable(),
3116
- ledgerRef: z13.string().nullable(),
3175
+ oacId: z14.string().uuid(),
3176
+ payerUserId: z14.string().uuid(),
3177
+ payeeUserId: z14.string().uuid(),
3178
+ amountKobo: z14.number().int().positive(),
3179
+ currency: z14.string().length(3),
3180
+ status: z14.enum(["SETTLED", "REVIEW"]),
3181
+ reviewReason: z14.string().nullable(),
3182
+ ledgerRef: z14.string().nullable(),
3117
3183
  /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
3118
- issuerSig: Base64Std3.min(16).max(2048),
3184
+ issuerSig: Base64Std4.min(16).max(2048),
3119
3185
  /** Canonical millisecond timestamp signed into the settlement receipt. */
3120
- issuedAtMs: z13.number().int().nonnegative(),
3186
+ issuedAtMs: z14.number().int().nonnegative(),
3121
3187
  /** Compatibility alias for API consumers that predate issuedAtMs. */
3122
- createdAtMs: z13.number().int().nonnegative().optional()
3188
+ createdAtMs: z14.number().int().nonnegative().optional()
3123
3189
  });
3124
- var ConsumerSettleResultSchema = z13.object({
3190
+ var ConsumerSettleResultSchema = z14.object({
3125
3191
  settlement: ConsumerSettlementSchema,
3126
3192
  encounterId: Sha256Hex,
3127
- replayed: z13.boolean()
3193
+ replayed: z14.boolean()
3128
3194
  });
3129
- var RevokeDeviceKeyInputSchema = z13.object({
3130
- deviceId: z13.string().min(1).max(128),
3195
+ var RevokeDeviceKeyInputSchema = z14.object({
3196
+ deviceId: z14.string().min(1).max(128),
3131
3197
  /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
3132
- sendAuthToken: z13.string().min(16)
3198
+ sendAuthToken: z14.string().min(16)
3133
3199
  });
3134
3200
  function createMeOfflineClient(opts) {
3135
3201
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -3162,7 +3228,7 @@ function createMeOfflineClient(opts) {
3162
3228
  }
3163
3229
  return parser(raw);
3164
3230
  }
3165
- const deviceKeyItems = z13.object({ items: z13.array(DeviceKeyRecordSchema) });
3231
+ const deviceKeyItems = z14.object({ items: z14.array(DeviceKeyRecordSchema) });
3166
3232
  return {
3167
3233
  issueP256EnrollmentChallenge: (input) => call(
3168
3234
  "POST",
@@ -3220,6 +3286,12 @@ function createMeOfflineClient(opts) {
3220
3286
  "/v1/issuer/keys",
3221
3287
  void 0,
3222
3288
  (raw) => IssuerTrustBundleSchema.parse(raw)
3289
+ ),
3290
+ getRevocations: () => call(
3291
+ "GET",
3292
+ "/v1/issuer/revocations",
3293
+ void 0,
3294
+ (raw) => SignedRevocationListSchema.parse(raw)
3223
3295
  )
3224
3296
  };
3225
3297
  }
@@ -3366,26 +3438,26 @@ function verifyClaimSignature(input) {
3366
3438
  }
3367
3439
 
3368
3440
  // src/me-offline/request.ts
3369
- import { z as z14 } from "zod";
3370
- var Base64Std4 = z14.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3441
+ import { z as z15 } from "zod";
3442
+ var Base64Std5 = z15.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3371
3443
  var CONSUMER_PAYMENT_REQUEST_DOMAIN = "flur:consumer-offline:v1:request";
3372
- var ConsumerPaymentRequestEnvelopeSchema = z14.object({
3373
- requestId: z14.string().uuid(),
3374
- mode: z14.enum(["fixed", "editable"]),
3375
- takerUserId: z14.string().uuid(),
3376
- amountKobo: z14.number().int().positive(),
3377
- currency: z14.string().length(3).default("NGN"),
3378
- reference: z14.string().max(128).nullable().default(null),
3379
- createdAtMs: z14.number().int().nonnegative(),
3380
- expiresAtMs: z14.number().int().positive(),
3381
- nonce: z14.string().min(8).max(128),
3382
- takerDeviceId: z14.string().min(1).max(128).nullable().default(null),
3383
- takerPubkeySpkiB64: Base64Std4.min(64).max(4096).optional(),
3384
- takerSignatureDerB64: Base64Std4.min(16).max(2048).optional()
3444
+ var ConsumerPaymentRequestEnvelopeSchema = z15.object({
3445
+ requestId: z15.string().uuid(),
3446
+ mode: z15.enum(["fixed", "editable"]),
3447
+ takerUserId: z15.string().uuid(),
3448
+ amountKobo: z15.number().int().positive(),
3449
+ currency: z15.string().length(3).default("NGN"),
3450
+ reference: z15.string().max(128).nullable().default(null),
3451
+ createdAtMs: z15.number().int().nonnegative(),
3452
+ expiresAtMs: z15.number().int().positive(),
3453
+ nonce: z15.string().min(8).max(128),
3454
+ takerDeviceId: z15.string().min(1).max(128).nullable().default(null),
3455
+ takerPubkeySpkiB64: Base64Std5.min(64).max(4096).optional(),
3456
+ takerSignatureDerB64: Base64Std5.min(16).max(2048).optional()
3385
3457
  }).superRefine((value, ctx) => {
3386
3458
  if (value.expiresAtMs <= value.createdAtMs) {
3387
3459
  ctx.addIssue({
3388
- code: z14.ZodIssueCode.custom,
3460
+ code: z15.ZodIssueCode.custom,
3389
3461
  path: ["expiresAtMs"],
3390
3462
  message: "expiresAtMs must be greater than createdAtMs"
3391
3463
  });
@@ -3396,21 +3468,21 @@ var ConsumerPaymentRequestEnvelopeSchema = z14.object({
3396
3468
  if (value.mode === "fixed" || hasSignature) {
3397
3469
  if (!value.takerDeviceId) {
3398
3470
  ctx.addIssue({
3399
- code: z14.ZodIssueCode.custom,
3471
+ code: z15.ZodIssueCode.custom,
3400
3472
  path: ["takerDeviceId"],
3401
3473
  message: "signed requests require takerDeviceId"
3402
3474
  });
3403
3475
  }
3404
3476
  if (!value.takerPubkeySpkiB64) {
3405
3477
  ctx.addIssue({
3406
- code: z14.ZodIssueCode.custom,
3478
+ code: z15.ZodIssueCode.custom,
3407
3479
  path: ["takerPubkeySpkiB64"],
3408
3480
  message: "signed requests require takerPubkeySpkiB64"
3409
3481
  });
3410
3482
  }
3411
3483
  if (!value.takerSignatureDerB64) {
3412
3484
  ctx.addIssue({
3413
- code: z14.ZodIssueCode.custom,
3485
+ code: z15.ZodIssueCode.custom,
3414
3486
  path: ["takerSignatureDerB64"],
3415
3487
  message: "signed requests require takerSignatureDerB64"
3416
3488
  });
@@ -3581,6 +3653,7 @@ function base64UrlDecodeUtf8(input) {
3581
3653
  }
3582
3654
 
3583
3655
  // src/me-offline/oac.ts
3656
+ import { z as z16 } from "zod";
3584
3657
  var CONSUMER_OAC_DOMAIN = "flur:consumer-offline:v1:oac";
3585
3658
  function consumerOacSigningPayload(oac) {
3586
3659
  return { domain: CONSUMER_OAC_DOMAIN, ...oac };
@@ -3606,6 +3679,9 @@ function verifyOacOffline(signed, trustedKeys, options = {}) {
3606
3679
  }
3607
3680
  if (nowMs < oac.validFromMs) return { ok: false, reason: "not_yet_valid" };
3608
3681
  if (nowMs >= oac.validUntilMs) return { ok: false, reason: "expired" };
3682
+ if (options.revokedOacIds?.has(oac.oacId)) {
3683
+ return { ok: false, reason: "revoked" };
3684
+ }
3609
3685
  return {
3610
3686
  ok: true,
3611
3687
  oac,
@@ -3623,15 +3699,28 @@ var CONSUMER_OAC_QR_PREFIX = "FLUROAC1.";
3623
3699
  function isConsumerOacQR(value) {
3624
3700
  return value.startsWith(CONSUMER_OAC_QR_PREFIX);
3625
3701
  }
3626
- function encodeConsumerOacQR(signed) {
3702
+ var OacPresentmentRequestSchema = z16.object({
3703
+ /** Requested amount in minor units (kobo). */
3704
+ amountMinor: z16.number().int().positive().max(1e12).optional(),
3705
+ /** Purpose/intent code (mirrors the NIBSS intent vocabulary). */
3706
+ intent: z16.string().min(1).max(32).optional(),
3707
+ /** Free-text reference / note. */
3708
+ reference: z16.string().min(1).max(64).optional()
3709
+ }).strict();
3710
+ function encodeConsumerOacQR(signed, request) {
3627
3711
  const parsed = SignedConsumerOACSchema.parse(signed);
3628
- return `${CONSUMER_OAC_QR_PREFIX}${base64UrlEncodeUtf82(JSON.stringify(parsed))}`;
3712
+ const base = `${CONSUMER_OAC_QR_PREFIX}${base64UrlEncodeUtf82(JSON.stringify(parsed))}`;
3713
+ if (request === void 0) return base;
3714
+ const parsedRequest = OacPresentmentRequestSchema.parse(request);
3715
+ if (Object.keys(parsedRequest).length === 0) return base;
3716
+ return `${base}.${base64UrlEncodeUtf82(JSON.stringify(parsedRequest))}`;
3629
3717
  }
3630
3718
  function decodeUnverifiedConsumerOacQR(value) {
3631
3719
  if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) {
3632
3720
  throw new Error("not a Flur consumer OAC QR");
3633
3721
  }
3634
- const encoded = value.slice(CONSUMER_OAC_QR_PREFIX.length);
3722
+ const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);
3723
+ const encoded = remainder.split(".", 1)[0];
3635
3724
  let raw;
3636
3725
  try {
3637
3726
  raw = JSON.parse(base64UrlDecodeUtf82(encoded));
@@ -3640,6 +3729,21 @@ function decodeUnverifiedConsumerOacQR(value) {
3640
3729
  }
3641
3730
  return SignedConsumerOACSchema.parse(raw);
3642
3731
  }
3732
+ function decodeConsumerOacRequest(value) {
3733
+ if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) return null;
3734
+ const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);
3735
+ const dot = remainder.indexOf(".");
3736
+ if (dot < 0) return null;
3737
+ const suffix = remainder.slice(dot + 1);
3738
+ if (suffix.length === 0) return null;
3739
+ try {
3740
+ const raw = JSON.parse(base64UrlDecodeUtf82(suffix));
3741
+ const parsed = OacPresentmentRequestSchema.safeParse(raw);
3742
+ return parsed.success ? parsed.data : null;
3743
+ } catch {
3744
+ return null;
3745
+ }
3746
+ }
3643
3747
  function base64UrlEncodeUtf82(input) {
3644
3748
  const bytes = new TextEncoder().encode(input);
3645
3749
  let binary = "";
@@ -3935,14 +4039,14 @@ function base64UrlToBytes(input) {
3935
4039
  }
3936
4040
 
3937
4041
  // src/partner-funding/client.ts
3938
- import { z as z15 } from "zod";
3939
- var MinorString = z15.string().regex(/^-?\d+$/);
3940
- var PositiveMinor = z15.union([
3941
- z15.number().int().positive(),
3942
- z15.string().regex(/^[1-9]\d{0,18}$/)
4042
+ import { z as z17 } from "zod";
4043
+ var MinorString = z17.string().regex(/^-?\d+$/);
4044
+ var PositiveMinor = z17.union([
4045
+ z17.number().int().positive(),
4046
+ z17.string().regex(/^[1-9]\d{0,18}$/)
3943
4047
  ]);
3944
- var Currency = z15.string().trim().length(3).transform((v) => v.toUpperCase());
3945
- var Metadata = z15.record(z15.unknown());
4048
+ var Currency = z17.string().trim().length(3).transform((v) => v.toUpperCase());
4049
+ var Metadata = z17.record(z17.unknown());
3946
4050
  var PARTNER_KINDS = ["bank", "merchant"];
3947
4051
  var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
3948
4052
  var PARTNER_PROFILE_STATUSES = [
@@ -3969,126 +4073,126 @@ var WITHDRAWAL_STATES = [
3969
4073
  "failed",
3970
4074
  "reversed"
3971
4075
  ];
3972
- var PartnerProfileSchema = z15.object({
3973
- partnerAccountId: z15.string().uuid(),
3974
- kind: z15.enum(PARTNER_KINDS),
3975
- custodialMode: z15.enum(CUSTODIAL_MODES),
3976
- displayName: z15.string(),
3977
- bankCode: z15.string().nullable(),
3978
- poolAccountNumber: z15.string().nullable(),
3979
- status: z15.enum(PARTNER_PROFILE_STATUSES),
4076
+ var PartnerProfileSchema = z17.object({
4077
+ partnerAccountId: z17.string().uuid(),
4078
+ kind: z17.enum(PARTNER_KINDS),
4079
+ custodialMode: z17.enum(CUSTODIAL_MODES),
4080
+ displayName: z17.string(),
4081
+ bankCode: z17.string().nullable(),
4082
+ poolAccountNumber: z17.string().nullable(),
4083
+ status: z17.enum(PARTNER_PROFILE_STATUSES),
3980
4084
  metadata: Metadata,
3981
- createdAtMs: z15.number().int().nonnegative(),
3982
- updatedAtMs: z15.number().int().nonnegative()
4085
+ createdAtMs: z17.number().int().nonnegative(),
4086
+ updatedAtMs: z17.number().int().nonnegative()
3983
4087
  });
3984
- var UpsertPartnerProfileInputSchema = z15.object({
3985
- kind: z15.enum(PARTNER_KINDS),
3986
- custodialMode: z15.enum(CUSTODIAL_MODES),
3987
- displayName: z15.string().trim().min(1).max(200),
3988
- bankCode: z15.string().trim().min(1).max(64).optional(),
3989
- poolAccountNumber: z15.string().trim().min(1).max(64).optional(),
4088
+ var UpsertPartnerProfileInputSchema = z17.object({
4089
+ kind: z17.enum(PARTNER_KINDS),
4090
+ custodialMode: z17.enum(CUSTODIAL_MODES),
4091
+ displayName: z17.string().trim().min(1).max(200),
4092
+ bankCode: z17.string().trim().min(1).max(64).optional(),
4093
+ poolAccountNumber: z17.string().trim().min(1).max(64).optional(),
3990
4094
  metadata: Metadata.optional()
3991
4095
  });
3992
- var PartnerFundingEventInputSchema = z15.object({
3993
- externalRef: z15.string().trim().min(8).max(128),
3994
- direction: z15.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
3995
- userId: z15.string().uuid().optional(),
3996
- accountId: z15.string().uuid().optional(),
4096
+ var PartnerFundingEventInputSchema = z17.object({
4097
+ externalRef: z17.string().trim().min(8).max(128),
4098
+ direction: z17.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
4099
+ userId: z17.string().uuid().optional(),
4100
+ accountId: z17.string().uuid().optional(),
3997
4101
  amountMinor: PositiveMinor,
3998
4102
  currency: Currency,
3999
- fundingSource: z15.string().trim().min(1).max(64).optional(),
4103
+ fundingSource: z17.string().trim().min(1).max(64).optional(),
4000
4104
  providerMetadata: Metadata.optional()
4001
4105
  });
4002
- var PartnerFundingSchema = z15.object({
4003
- fundingId: z15.string().uuid(),
4004
- partnerId: z15.string().uuid(),
4005
- accountId: z15.string().uuid(),
4006
- userId: z15.string().uuid().nullable(),
4007
- direction: z15.enum(PARTNER_FUNDING_DIRECTIONS),
4008
- currency: z15.string(),
4106
+ var PartnerFundingSchema = z17.object({
4107
+ fundingId: z17.string().uuid(),
4108
+ partnerId: z17.string().uuid(),
4109
+ accountId: z17.string().uuid(),
4110
+ userId: z17.string().uuid().nullable(),
4111
+ direction: z17.enum(PARTNER_FUNDING_DIRECTIONS),
4112
+ currency: z17.string(),
4009
4113
  amountMinor: MinorString,
4010
- externalRef: z15.string(),
4011
- status: z15.enum(PARTNER_FUNDING_STATUSES),
4012
- fundingSource: z15.string(),
4013
- ledgerRef: z15.string(),
4114
+ externalRef: z17.string(),
4115
+ status: z17.enum(PARTNER_FUNDING_STATUSES),
4116
+ fundingSource: z17.string(),
4117
+ ledgerRef: z17.string(),
4014
4118
  providerMetadata: Metadata,
4015
- createdAtMs: z15.number().int().nonnegative(),
4016
- updatedAtMs: z15.number().int().nonnegative()
4119
+ createdAtMs: z17.number().int().nonnegative(),
4120
+ updatedAtMs: z17.number().int().nonnegative()
4017
4121
  });
4018
- var IngestFundingResultSchema = z15.object({
4122
+ var IngestFundingResultSchema = z17.object({
4019
4123
  funding: PartnerFundingSchema,
4020
- replayed: z15.boolean()
4124
+ replayed: z17.boolean()
4021
4125
  });
4022
- var PayoutDestinationSchema = z15.object({
4023
- destinationId: z15.string().uuid(),
4024
- accountId: z15.string().uuid(),
4025
- partnerId: z15.string().uuid(),
4026
- bankCode: z15.string(),
4027
- accountNumber: z15.string(),
4028
- accountName: z15.string(),
4029
- status: z15.enum(PAYOUT_DESTINATION_STATUSES),
4030
- verifiedAtMs: z15.number().int().nonnegative().nullable(),
4126
+ var PayoutDestinationSchema = z17.object({
4127
+ destinationId: z17.string().uuid(),
4128
+ accountId: z17.string().uuid(),
4129
+ partnerId: z17.string().uuid(),
4130
+ bankCode: z17.string(),
4131
+ accountNumber: z17.string(),
4132
+ accountName: z17.string(),
4133
+ status: z17.enum(PAYOUT_DESTINATION_STATUSES),
4134
+ verifiedAtMs: z17.number().int().nonnegative().nullable(),
4031
4135
  metadata: Metadata,
4032
- createdAtMs: z15.number().int().nonnegative(),
4033
- updatedAtMs: z15.number().int().nonnegative()
4136
+ createdAtMs: z17.number().int().nonnegative(),
4137
+ updatedAtMs: z17.number().int().nonnegative()
4034
4138
  });
4035
- var CreatePayoutDestinationInputSchema = z15.object({
4036
- partnerId: z15.string().uuid(),
4037
- bankCode: z15.string().trim().min(1).max(32),
4038
- accountNumber: z15.string().trim().min(4).max(64),
4039
- accountName: z15.string().trim().min(1).max(200),
4139
+ var CreatePayoutDestinationInputSchema = z17.object({
4140
+ partnerId: z17.string().uuid(),
4141
+ bankCode: z17.string().trim().min(1).max(32),
4142
+ accountNumber: z17.string().trim().min(4).max(64),
4143
+ accountName: z17.string().trim().min(1).max(200),
4040
4144
  metadata: Metadata.optional()
4041
4145
  });
4042
- var ListPayoutDestinationsResultSchema = z15.object({
4043
- items: z15.array(PayoutDestinationSchema)
4146
+ var ListPayoutDestinationsResultSchema = z17.object({
4147
+ items: z17.array(PayoutDestinationSchema)
4044
4148
  });
4045
- var WithdrawalSchema = z15.object({
4046
- withdrawalId: z15.string().uuid(),
4047
- accountId: z15.string().uuid(),
4048
- userId: z15.string().uuid(),
4049
- partnerId: z15.string().uuid(),
4050
- destinationId: z15.string().uuid(),
4051
- currency: z15.string(),
4149
+ var WithdrawalSchema = z17.object({
4150
+ withdrawalId: z17.string().uuid(),
4151
+ accountId: z17.string().uuid(),
4152
+ userId: z17.string().uuid(),
4153
+ partnerId: z17.string().uuid(),
4154
+ destinationId: z17.string().uuid(),
4155
+ currency: z17.string(),
4052
4156
  amountMinor: MinorString,
4053
- state: z15.enum(WITHDRAWAL_STATES),
4054
- idempotencyKey: z15.string(),
4055
- providerRef: z15.string().nullable(),
4056
- lastError: z15.string().nullable(),
4057
- ledgerRef: z15.string(),
4058
- reverseLedgerRef: z15.string().nullable(),
4157
+ state: z17.enum(WITHDRAWAL_STATES),
4158
+ idempotencyKey: z17.string(),
4159
+ providerRef: z17.string().nullable(),
4160
+ lastError: z17.string().nullable(),
4161
+ ledgerRef: z17.string(),
4162
+ reverseLedgerRef: z17.string().nullable(),
4059
4163
  metadata: Metadata,
4060
- createdAtMs: z15.number().int().nonnegative(),
4061
- updatedAtMs: z15.number().int().nonnegative()
4164
+ createdAtMs: z17.number().int().nonnegative(),
4165
+ updatedAtMs: z17.number().int().nonnegative()
4062
4166
  });
4063
- var CreateWithdrawalInputSchema = z15.object({
4064
- destinationId: z15.string().uuid(),
4167
+ var CreateWithdrawalInputSchema = z17.object({
4168
+ destinationId: z17.string().uuid(),
4065
4169
  amountMinor: PositiveMinor,
4066
4170
  currency: Currency,
4067
- idempotencyKey: z15.string().trim().min(8).max(128),
4171
+ idempotencyKey: z17.string().trim().min(8).max(128),
4068
4172
  metadata: Metadata.optional()
4069
4173
  });
4070
- var CreateWithdrawalResultSchema = z15.object({
4174
+ var CreateWithdrawalResultSchema = z17.object({
4071
4175
  withdrawal: WithdrawalSchema,
4072
- replayed: z15.boolean()
4176
+ replayed: z17.boolean()
4073
4177
  });
4074
- var PayoutEventInputSchema = z15.object({
4075
- externalRef: z15.string().trim().min(8).max(128),
4076
- withdrawalId: z15.string().uuid().optional(),
4077
- state: z15.enum(["submitted", "processing", "paid", "failed"]),
4078
- providerRef: z15.string().trim().min(1).max(128).optional(),
4079
- failureCode: z15.string().trim().max(64).optional(),
4080
- failureMessage: z15.string().trim().max(512).optional(),
4178
+ var PayoutEventInputSchema = z17.object({
4179
+ externalRef: z17.string().trim().min(8).max(128),
4180
+ withdrawalId: z17.string().uuid().optional(),
4181
+ state: z17.enum(["submitted", "processing", "paid", "failed"]),
4182
+ providerRef: z17.string().trim().min(1).max(128).optional(),
4183
+ failureCode: z17.string().trim().max(64).optional(),
4184
+ failureMessage: z17.string().trim().max(512).optional(),
4081
4185
  providerMetadata: Metadata.optional()
4082
4186
  });
4083
- var RecordPayoutEventResultSchema = z15.object({
4187
+ var RecordPayoutEventResultSchema = z17.object({
4084
4188
  withdrawal: WithdrawalSchema,
4085
- replayed: z15.boolean()
4189
+ replayed: z17.boolean()
4086
4190
  });
4087
- var ReconciliationReportSchema = z15.object({
4088
- partnerId: z15.string().uuid(),
4089
- currency: z15.string(),
4090
- fromMs: z15.number().int().nonnegative(),
4091
- toMs: z15.number().int().nonnegative(),
4191
+ var ReconciliationReportSchema = z17.object({
4192
+ partnerId: z17.string().uuid(),
4193
+ currency: z17.string(),
4194
+ fromMs: z17.number().int().nonnegative(),
4195
+ toMs: z17.number().int().nonnegative(),
4092
4196
  fundingsCreditMinor: MinorString,
4093
4197
  fundingsDebitMinor: MinorString,
4094
4198
  withdrawalsPaidMinor: MinorString,
@@ -4097,7 +4201,7 @@ var ReconciliationReportSchema = z15.object({
4097
4201
  expectedReserveBalanceMinor: MinorString,
4098
4202
  actualReserveBalanceMinor: MinorString,
4099
4203
  imbalanceMinor: MinorString,
4100
- generatedAtMs: z15.number().int().nonnegative()
4204
+ generatedAtMs: z17.number().int().nonnegative()
4101
4205
  });
4102
4206
  function createPartnerFundingClient(partner) {
4103
4207
  return {
@@ -4249,19 +4353,19 @@ function createPartnerProfileAdminClient(opts) {
4249
4353
  }
4250
4354
 
4251
4355
  // src/artifacts/envelope.ts
4252
- import { z as z16 } from "zod";
4356
+ import { z as z18 } from "zod";
4253
4357
  var FLUR_ARTIFACT_URI_SCHEME = "flur";
4254
4358
  var FLUR_ARTIFACT_VERSION = 1;
4255
4359
  var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
4256
4360
  var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
4257
- var ArtifactHeaderSchema = z16.object({
4258
- v: z16.literal(FLUR_ARTIFACT_VERSION),
4259
- t: z16.string().regex(ArtifactTypeRe, "invalid artifact type"),
4260
- iss: z16.string().min(1).max(128),
4261
- kid: z16.string().min(1).max(128),
4262
- iat: z16.number().int().nonnegative(),
4263
- exp: z16.number().int().positive().optional(),
4264
- nonce: z16.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
4361
+ var ArtifactHeaderSchema = z18.object({
4362
+ v: z18.literal(FLUR_ARTIFACT_VERSION),
4363
+ t: z18.string().regex(ArtifactTypeRe, "invalid artifact type"),
4364
+ iss: z18.string().min(1).max(128),
4365
+ kid: z18.string().min(1).max(128),
4366
+ iat: z18.number().int().nonnegative(),
4367
+ exp: z18.number().int().positive().optional(),
4368
+ nonce: z18.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
4265
4369
  });
4266
4370
  var FlurArtifactError = class extends Error {
4267
4371
  constructor(message, code) {
@@ -4400,7 +4504,7 @@ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
4400
4504
  }
4401
4505
 
4402
4506
  // src/artifacts/types.ts
4403
- import { z as z17 } from "zod";
4507
+ import { z as z19 } from "zod";
4404
4508
  var ARTIFACT_TYPES = {
4405
4509
  OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
4406
4510
  RECEIPT: "receipt",
@@ -4413,37 +4517,34 @@ var ARTIFACT_TYPES = {
4413
4517
  LEDGER_JOURNAL_ENTRY: "ledger_journal_entry",
4414
4518
  STATEMENT: "statement",
4415
4519
  PASS: "pass",
4416
- IDENTITY: "identity",
4417
- // Tier B: holder-signed identity attestation for offline trust. The
4418
- // envelope.iat / envelope.exp express the card's canonical lifetime.
4419
- PAY_CARD: "pay_card"
4520
+ IDENTITY: "identity"
4420
4521
  };
4421
- var HexString = (length) => z17.string().regex(
4522
+ var HexString = (length) => z19.string().regex(
4422
4523
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
4423
4524
  `expected ${length}-byte hex string`
4424
4525
  );
4425
- var OfflinePaymentAuthorizationArtifactSchema = z17.object({
4526
+ var OfflinePaymentAuthorizationArtifactSchema = z19.object({
4426
4527
  authorization: OfflinePaymentAuthorizationSchema
4427
4528
  });
4428
- var ReceiptArtifactSchema = z17.object({
4429
- receiptId: z17.string().min(1).max(64),
4430
- paymentReference: z17.string().min(1).max(64),
4431
- payerUserId: z17.string().min(1).max(64).optional(),
4432
- payeeUserId: z17.string().min(1).max(64),
4433
- amountKobo: z17.number().int().positive(),
4434
- currency: z17.literal("NGN"),
4435
- channel: z17.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
4436
- settledAtMs: z17.number().int().positive(),
4437
- ledgerTxnId: z17.string().min(1).max(64).optional(),
4438
- memo: z17.string().max(140).optional(),
4529
+ var ReceiptArtifactSchema = z19.object({
4530
+ receiptId: z19.string().min(1).max(64),
4531
+ paymentReference: z19.string().min(1).max(64),
4532
+ payerUserId: z19.string().min(1).max(64).optional(),
4533
+ payeeUserId: z19.string().min(1).max(64),
4534
+ amountKobo: z19.number().int().positive(),
4535
+ currency: z19.literal("NGN"),
4536
+ channel: z19.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
4537
+ settledAtMs: z19.number().int().positive(),
4538
+ ledgerTxnId: z19.string().min(1).max(64).optional(),
4539
+ memo: z19.string().max(140).optional(),
4439
4540
  hashChainPrev: HexString(32).optional()
4440
4541
  });
4441
- var ShortId = z17.string().min(1).max(64);
4442
- var PositiveInt = z17.number().int().positive();
4443
- var NonNegativeInt = z17.number().int().nonnegative();
4444
- var Currency2 = z17.literal("NGN");
4445
- var Memo = z17.string().max(140);
4446
- var NqrPaymentRequestArtifactSchema = z17.object({
4542
+ var ShortId = z19.string().min(1).max(64);
4543
+ var PositiveInt = z19.number().int().positive();
4544
+ var NonNegativeInt = z19.number().int().nonnegative();
4545
+ var Currency2 = z19.literal("NGN");
4546
+ var Memo = z19.string().max(140);
4547
+ var NqrPaymentRequestArtifactSchema = z19.object({
4447
4548
  requestId: ShortId,
4448
4549
  payeeUserId: ShortId,
4449
4550
  amountKobo: PositiveInt.optional(),
@@ -4451,7 +4552,7 @@ var NqrPaymentRequestArtifactSchema = z17.object({
4451
4552
  memo: Memo.optional(),
4452
4553
  expiresAtMs: PositiveInt.optional()
4453
4554
  });
4454
- var PaymentIntentArtifactSchema = z17.object({
4555
+ var PaymentIntentArtifactSchema = z19.object({
4455
4556
  intentId: ShortId,
4456
4557
  payerUserId: ShortId,
4457
4558
  payeeUserId: ShortId,
@@ -4460,7 +4561,7 @@ var PaymentIntentArtifactSchema = z17.object({
4460
4561
  idempotencyKey: ShortId,
4461
4562
  createdAtMs: PositiveInt
4462
4563
  });
4463
- var OfflineClaimArtifactSchema = z17.object({
4564
+ var OfflineClaimArtifactSchema = z19.object({
4464
4565
  claimId: ShortId,
4465
4566
  authorizationId: ShortId,
4466
4567
  payeeUserId: ShortId,
@@ -4469,10 +4570,10 @@ var OfflineClaimArtifactSchema = z17.object({
4469
4570
  claimedAtMs: PositiveInt,
4470
4571
  paymentReference: ShortId.optional()
4471
4572
  });
4472
- var SettlementRecordArtifactSchema = z17.object({
4573
+ var SettlementRecordArtifactSchema = z19.object({
4473
4574
  settlementId: ShortId,
4474
4575
  ledgerTxnId: ShortId,
4475
- sourceRefType: z17.enum([
4576
+ sourceRefType: z19.enum([
4476
4577
  "offline_authorization",
4477
4578
  "offline_claim",
4478
4579
  "transfer",
@@ -4483,12 +4584,12 @@ var SettlementRecordArtifactSchema = z17.object({
4483
4584
  currency: Currency2,
4484
4585
  settledAtMs: PositiveInt
4485
4586
  });
4486
- var ReversalRecordArtifactSchema = z17.object({
4587
+ var ReversalRecordArtifactSchema = z19.object({
4487
4588
  reversalId: ShortId,
4488
4589
  originalTxnId: ShortId,
4489
4590
  amountKobo: PositiveInt,
4490
4591
  currency: Currency2,
4491
- reason: z17.enum([
4592
+ reason: z19.enum([
4492
4593
  "user_dispute",
4493
4594
  "fraud",
4494
4595
  "duplicate",
@@ -4498,7 +4599,7 @@ var ReversalRecordArtifactSchema = z17.object({
4498
4599
  reversedAtMs: PositiveInt,
4499
4600
  memo: Memo.optional()
4500
4601
  });
4501
- var LedgerJournalEntryArtifactSchema = z17.object({
4602
+ var LedgerJournalEntryArtifactSchema = z19.object({
4502
4603
  entryId: ShortId,
4503
4604
  journalId: ShortId,
4504
4605
  debitAccountId: ShortId,
@@ -4509,13 +4610,13 @@ var LedgerJournalEntryArtifactSchema = z17.object({
4509
4610
  refType: ShortId.optional(),
4510
4611
  refId: ShortId.optional()
4511
4612
  });
4512
- var StatementArtifactSchema = z17.object({
4613
+ var StatementArtifactSchema = z19.object({
4513
4614
  statementId: ShortId,
4514
4615
  userId: ShortId,
4515
4616
  periodStartMs: PositiveInt,
4516
4617
  periodEndMs: PositiveInt,
4517
- openingBalanceKobo: z17.number().int(),
4518
- closingBalanceKobo: z17.number().int(),
4618
+ openingBalanceKobo: z19.number().int(),
4619
+ closingBalanceKobo: z19.number().int(),
4519
4620
  transactionCount: NonNegativeInt,
4520
4621
  currency: Currency2,
4521
4622
  hashChainPrev: HexString(32).optional()
@@ -4523,16 +4624,16 @@ var StatementArtifactSchema = z17.object({
4523
4624
  message: "periodEndMs must be greater than periodStartMs",
4524
4625
  path: ["periodEndMs"]
4525
4626
  });
4526
- var PassArtifactSchema = z17.object({
4627
+ var PassArtifactSchema = z19.object({
4527
4628
  passId: ShortId,
4528
4629
  holderId: ShortId,
4529
- category: z17.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
4530
- title: z17.string().min(1).max(120),
4630
+ category: z19.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
4631
+ title: z19.string().min(1).max(120),
4531
4632
  validFromMs: PositiveInt,
4532
4633
  validUntilMs: PositiveInt.optional(),
4533
- metadata: z17.record(
4534
- z17.string().min(1).max(64),
4535
- z17.union([z17.string().max(280), z17.number(), z17.boolean()])
4634
+ metadata: z19.record(
4635
+ z19.string().min(1).max(64),
4636
+ z19.union([z19.string().max(280), z19.number(), z19.boolean()])
4536
4637
  ).optional()
4537
4638
  }).refine(
4538
4639
  (v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
@@ -4541,10 +4642,10 @@ var PassArtifactSchema = z17.object({
4541
4642
  path: ["validUntilMs"]
4542
4643
  }
4543
4644
  );
4544
- var IdentityArtifactSchema = z17.object({
4645
+ var IdentityArtifactSchema = z19.object({
4545
4646
  attestationId: ShortId,
4546
4647
  subjectId: ShortId,
4547
- claimType: z17.enum([
4648
+ claimType: z19.enum([
4548
4649
  "phone_verified",
4549
4650
  "email_verified",
4550
4651
  "bvn_verified",
@@ -4554,12 +4655,6 @@ var IdentityArtifactSchema = z17.object({
4554
4655
  claimValueHash: HexString(32),
4555
4656
  attestedAtMs: PositiveInt
4556
4657
  });
4557
- var PayCardArtifactSchema = z17.object({
4558
- userId: ShortId,
4559
- phoneE164: z17.string().regex(/^\+[1-9]\d{7,14}$/, "phoneE164 must be normalised E.164"),
4560
- displayName: z17.string().min(1).max(64),
4561
- devicePubKeySpkiB64: z17.string().min(64).max(256).regex(/^[A-Za-z0-9+/]+=*$/, "devicePubKeySpkiB64 must be standard base64")
4562
- });
4563
4658
  var ARTIFACT_BODY_SCHEMAS = {
4564
4659
  [ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]: OfflinePaymentAuthorizationArtifactSchema,
4565
4660
  [ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,
@@ -4571,8 +4666,7 @@ var ARTIFACT_BODY_SCHEMAS = {
4571
4666
  [ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,
4572
4667
  [ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,
4573
4668
  [ARTIFACT_TYPES.PASS]: PassArtifactSchema,
4574
- [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema,
4575
- [ARTIFACT_TYPES.PAY_CARD]: PayCardArtifactSchema
4669
+ [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
4576
4670
  };
4577
4671
  var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4578
4672
  ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,
@@ -4585,8 +4679,7 @@ var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4585
4679
  ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,
4586
4680
  ARTIFACT_TYPES.STATEMENT,
4587
4681
  ARTIFACT_TYPES.PASS,
4588
- ARTIFACT_TYPES.IDENTITY,
4589
- ARTIFACT_TYPES.PAY_CARD
4682
+ ARTIFACT_TYPES.IDENTITY
4590
4683
  ]);
4591
4684
  function isKnownArtifactType(t) {
4592
4685
  return Object.values(ARTIFACT_TYPES).includes(t);
@@ -4671,130 +4764,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4671
4764
  type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION
4672
4765
  });
4673
4766
  }
4674
-
4675
- // src/artifacts/paycard.ts
4676
- var PAY_CARD_DEFAULT_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
4677
- var PAY_CARD_REFRESH_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1e3;
4678
- var PAY_CARD_URI_PREFIX = `${FLUR_ARTIFACT_URI_PREFIX}${ARTIFACT_TYPES.PAY_CARD}/`;
4679
- function createPayCardArtifactUri(input) {
4680
- if (input.data.userId !== input.issuer) {
4681
- throw new FlurArtifactError(
4682
- "pay_card.data.userId must equal envelope issuer",
4683
- "INVALID_BODY"
4684
- );
4685
- }
4686
- const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
4687
- const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
4688
- return createArtifactUri({
4689
- type: ARTIFACT_TYPES.PAY_CARD,
4690
- issuer: input.issuer,
4691
- keyId: input.keyId,
4692
- privateKey: input.privateKey,
4693
- nonce: input.nonce,
4694
- issuedAtSeconds: iat,
4695
- expiresAtSeconds: exp,
4696
- data: input.data
4697
- });
4698
- }
4699
- function isPayCardArtifactUri(uri) {
4700
- return typeof uri === "string" && uri.startsWith(PAY_CARD_URI_PREFIX);
4701
- }
4702
- function decodePayCardArtifact(uri) {
4703
- if (!isPayCardArtifactUri(uri)) {
4704
- throw new FlurArtifactError(
4705
- `URI does not start with ${PAY_CARD_URI_PREFIX}`,
4706
- "INVALID_URI"
4707
- );
4708
- }
4709
- const decoded = decodeArtifactUri(uri);
4710
- if (decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
4711
- throw new FlurArtifactError(
4712
- `Expected pay_card, got ${decoded.type}`,
4713
- "TYPE_MISMATCH"
4714
- );
4715
- }
4716
- const parsed = PayCardArtifactSchema.safeParse(decoded.body.data);
4717
- if (!parsed.success) {
4718
- throw new FlurArtifactError(
4719
- `pay_card body invalid: ${parsed.error.message}`,
4720
- "INVALID_BODY"
4721
- );
4722
- }
4723
- if (parsed.data.userId !== decoded.body.iss) {
4724
- throw new FlurArtifactError(
4725
- "pay_card.data.userId must equal envelope issuer",
4726
- "INVALID_BODY"
4727
- );
4728
- }
4729
- return {
4730
- body: {
4731
- ...decoded.body,
4732
- data: parsed.data
4733
- },
4734
- sig: decoded.sig,
4735
- decoded
4736
- };
4737
- }
4738
- function verifyPayCardArtifact(uri, publicKeySpkiB64, options = {}) {
4739
- if (!isPayCardArtifactUri(uri)) {
4740
- throw new FlurArtifactError(
4741
- `URI does not start with ${PAY_CARD_URI_PREFIX}`,
4742
- "INVALID_URI"
4743
- );
4744
- }
4745
- const verified = verifyArtifactUri(
4746
- uri,
4747
- publicKeySpkiB64,
4748
- options
4749
- );
4750
- if (verified.decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
4751
- throw new FlurArtifactError(
4752
- `Expected pay_card, got ${verified.decoded.type}`,
4753
- "TYPE_MISMATCH"
4754
- );
4755
- }
4756
- if (verified.body.data.userId !== verified.body.iss) {
4757
- throw new FlurArtifactError(
4758
- "pay_card.data.userId must equal envelope issuer",
4759
- "INVALID_BODY"
4760
- );
4761
- }
4762
- return {
4763
- body: verified.body,
4764
- sig: verified.sig,
4765
- decoded: verified.decoded
4766
- };
4767
- }
4768
- function inspectPayCardFreshness(decoded, nowMs = Date.now()) {
4769
- const exp = decoded.body.exp;
4770
- if (exp === void 0) return "no_expiry";
4771
- const remainingMs = exp * 1e3 - nowMs;
4772
- if (remainingMs <= 0) return "expired";
4773
- if (remainingMs <= PAY_CARD_REFRESH_THRESHOLD_MS)
4774
- return "refresh_recommended";
4775
- return "fresh";
4776
- }
4777
- function buildPayCardSigningInput(input) {
4778
- if (input.data.userId !== input.issuer) {
4779
- throw new FlurArtifactError(
4780
- "pay_card.data.userId must equal envelope issuer",
4781
- "INVALID_BODY"
4782
- );
4783
- }
4784
- const parsedData = PayCardArtifactSchema.parse(input.data);
4785
- const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
4786
- const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
4787
- const body = buildArtifactBody({
4788
- type: ARTIFACT_TYPES.PAY_CARD,
4789
- issuer: input.issuer,
4790
- keyId: input.keyId,
4791
- data: parsedData,
4792
- nonce: input.nonce,
4793
- issuedAtSeconds: iat,
4794
- expiresAtSeconds: exp
4795
- });
4796
- return { body, bodyBytes: canonicalJSONBytes(body) };
4797
- }
4798
4767
  export {
4799
4768
  ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
4800
4769
  ACCOUNT_STATUSES,
@@ -4814,6 +4783,7 @@ export {
4814
4783
  CONSUMER_OAC_QR_PREFIX,
4815
4784
  CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
4816
4785
  CONSUMER_PAYMENT_REQUEST_DOMAIN,
4786
+ CONSUMER_REVOCATION_DOMAIN,
4817
4787
  CONSUMER_SETTLEMENT_DOMAIN,
4818
4788
  CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX,
4819
4789
  CUSTODIAL_MODES,
@@ -4875,6 +4845,7 @@ export {
4875
4845
  OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
4876
4846
  OFFLINE_SMS_SETTLE_TOKEN_BYTES,
4877
4847
  OFFLINE_SMS_SETTLE_VERSION,
4848
+ OacPresentmentRequestSchema,
4878
4849
  OfflineClaimArtifactSchema,
4879
4850
  OfflinePaymentAuthorizationArtifactSchema,
4880
4851
  OfflinePaymentAuthorizationSchema,
@@ -4892,9 +4863,6 @@ export {
4892
4863
  PASS_STATES,
4893
4864
  PAYLOAD_FORMAT_INDICATOR_VALUE,
4894
4865
  PAYOUT_DESTINATION_STATUSES,
4895
- PAY_CARD_DEFAULT_TTL_MS,
4896
- PAY_CARD_REFRESH_THRESHOLD_MS,
4897
- PAY_CARD_URI_PREFIX,
4898
4866
  POINT_OF_INITIATION,
4899
4867
  PartnerFundingEventInputSchema,
4900
4868
  PartnerFundingSchema,
@@ -4902,7 +4870,6 @@ export {
4902
4870
  PassArtifactSchema,
4903
4871
  PassMetadataSchema,
4904
4872
  PassSchema,
4905
- PayCardArtifactSchema,
4906
4873
  PayCollectionInputSchema,
4907
4874
  PaymentClaimSchema,
4908
4875
  PaymentIntentArtifactSchema,
@@ -4914,6 +4881,7 @@ export {
4914
4881
  RECEIPT_CHANNELS,
4915
4882
  RECEIPT_KINDS,
4916
4883
  REPLAY_WINDOW_MS,
4884
+ REVOCATION_LIST_MAX_ENTRIES,
4917
4885
  ReceiptArtifactSchema,
4918
4886
  ReceiptPayloadSchema,
4919
4887
  ReceiptSchema,
@@ -4922,12 +4890,14 @@ export {
4922
4890
  RedemptionSchema,
4923
4891
  RegisterDeviceKeyP256InputSchema,
4924
4892
  ReversalRecordArtifactSchema,
4893
+ RevocationListSchema,
4925
4894
  RevokeDeviceKeyInputSchema,
4926
4895
  SETTLEMENT_SCHEDULES,
4927
4896
  SettleResponseSchema,
4928
4897
  SettlementRecordArtifactSchema,
4929
4898
  SettlementSchema,
4930
4899
  SignedConsumerOACSchema,
4900
+ SignedRevocationListSchema,
4931
4901
  StatementArtifactSchema,
4932
4902
  UpsertMerchantProfileInputSchema,
4933
4903
  UpsertPartnerProfileInputSchema,
@@ -4941,7 +4911,6 @@ export {
4941
4911
  buildConsumerPaymentRequest,
4942
4912
  buildOAC,
4943
4913
  buildPass,
4944
- buildPayCardSigningInput,
4945
4914
  buildPaymentRequest,
4946
4915
  buildReceipt,
4947
4916
  buildRedemption,
@@ -4976,17 +4945,16 @@ export {
4976
4945
  createPartnerFundingClient,
4977
4946
  createPartnerProfileAdminClient,
4978
4947
  createPassesClient,
4979
- createPayCardArtifactUri,
4980
4948
  createReceiptArtifactUri,
4981
4949
  createReceiptsClient,
4982
4950
  createSoftwareP256Signer,
4983
4951
  decodeArtifactUri,
4984
4952
  decodeAuthorizationQR,
4985
4953
  decodeBase45,
4954
+ decodeConsumerOacRequest,
4986
4955
  decodeConsumerSettlementReceiptQR,
4987
4956
  decodeOfflineClaimSmsMessage,
4988
4957
  decodeOfflineSmsSettleToken,
4989
- decodePayCardArtifact,
4990
4958
  decodePaymentRequestQR,
4991
4959
  decodeUnverifiedConsumerOacQR,
4992
4960
  decodeUnverifiedConsumerSettlementReceiptQR,
@@ -5006,19 +4974,19 @@ export {
5006
4974
  generateDynamicQR,
5007
4975
  generateStaticQR,
5008
4976
  init,
5009
- inspectPayCardFreshness,
5010
4977
  isConsumerOacQR,
5011
4978
  isConsumerPaymentRequestExpired,
5012
4979
  isHardenedArtifactType,
5013
4980
  isKnownArtifactType,
4981
+ isOacRevoked,
5014
4982
  isPassWithinValidity,
5015
- isPayCardArtifactUri,
5016
4983
  moneyMinorToNumber,
5017
4984
  normalizeE164,
5018
4985
  parseAmountInput,
5019
4986
  parseNQR,
5020
4987
  parseQR,
5021
4988
  readTLV,
4989
+ revocationListSigningPayload,
5022
4990
  routingHint,
5023
4991
  signArtifact,
5024
4992
  signAuthorization,
@@ -5041,11 +5009,11 @@ export {
5041
5009
  verifyOacOffline,
5042
5010
  verifyOfflineSmsSettleToken,
5043
5011
  verifyPass,
5044
- verifyPayCardArtifact,
5045
5012
  verifyPaymentRequest,
5046
5013
  verifyReceipt,
5047
5014
  verifyRedemption,
5048
5015
  verifyRequestHMAC,
5016
+ verifyRevocationList,
5049
5017
  writeTLV
5050
5018
  };
5051
5019
  //# sourceMappingURL=index.js.map