@nokinc-flur/sdk 1.1.3 → 1.1.5

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
@@ -69,6 +69,7 @@ __export(index_exports, {
69
69
  HARDENED_ARTIFACT_TYPES: () => HARDENED_ARTIFACT_TYPES,
70
70
  IdentityArtifactSchema: () => IdentityArtifactSchema,
71
71
  IngestFundingResultSchema: () => IngestFundingResultSchema,
72
+ IssueAccountOacInputSchema: () => IssueAccountOacInputSchema,
72
73
  IssueOACInputSchema: () => IssueOACInputSchema,
73
74
  LedgerJournalEntryArtifactSchema: () => LedgerJournalEntryArtifactSchema,
74
75
  ListPayoutDestinationsResultSchema: () => ListPayoutDestinationsResultSchema,
@@ -86,6 +87,7 @@ __export(index_exports, {
86
87
  OAC_DEFAULT_CUMULATIVE_KOBO: () => OAC_DEFAULT_CUMULATIVE_KOBO,
87
88
  OAC_DEFAULT_PER_TX_KOBO: () => OAC_DEFAULT_PER_TX_KOBO,
88
89
  OAC_DEFAULT_VALIDITY_MS: () => OAC_DEFAULT_VALIDITY_MS,
90
+ OFFLINE_CLAIM_SMS_PREFIX: () => OFFLINE_CLAIM_SMS_PREFIX,
89
91
  OfflineClaimArtifactSchema: () => OfflineClaimArtifactSchema,
90
92
  OfflineHoldRecordSchema: () => OfflineHoldRecordSchema,
91
93
  OfflinePaymentAuthorizationArtifactSchema: () => OfflinePaymentAuthorizationArtifactSchema,
@@ -181,20 +183,21 @@ __export(index_exports, {
181
183
  createPassesClient: () => createPassesClient,
182
184
  createReceiptArtifactUri: () => createReceiptArtifactUri,
183
185
  createReceiptsClient: () => createReceiptsClient,
184
- createSoftwareEd25519Signer: () => createSoftwareEd25519Signer,
185
186
  createSoftwareP256Signer: () => createSoftwareP256Signer,
186
187
  decodeArtifactUri: () => decodeArtifactUri,
187
188
  decodeAuthorizationQR: () => decodeAuthorizationQR,
188
189
  decodeBase45: () => decodeBase45,
190
+ decodeOfflineClaimSmsMessage: () => decodeOfflineClaimSmsMessage,
189
191
  decodePaymentRequestQR: () => decodePaymentRequestQR,
190
192
  encodeArtifactUri: () => encodeArtifactUri,
191
193
  encodeAuthorizationQR: () => encodeAuthorizationQR,
192
194
  encodeBase45: () => encodeBase45,
193
195
  encodeNQR: () => encodeNQR,
196
+ encodeOfflineClaimSmsMessage: () => encodeOfflineClaimSmsMessage,
194
197
  encodePaymentRequestQR: () => encodePaymentRequestQR,
198
+ extractOfflineClaimSmsToken: () => extractOfflineClaimSmsToken,
195
199
  formatAmount: () => formatAmount,
196
200
  generateDynamicQR: () => generateDynamicQR,
197
- generateKeyPair: () => generateKeyPair,
198
201
  generateStaticQR: () => generateStaticQR,
199
202
  init: () => init,
200
203
  isHardenedArtifactType: () => isHardenedArtifactType,
@@ -205,13 +208,10 @@ __export(index_exports, {
205
208
  parseAmountInput: () => parseAmountInput,
206
209
  parseNQR: () => parseNQR,
207
210
  parseQR: () => parseQR,
208
- publicKeyFromPrivate: () => publicKeyFromPrivate,
209
211
  readTLV: () => readTLV,
210
212
  routingHint: () => routingHint,
211
- sign: () => sign,
212
213
  signArtifact: () => signArtifact,
213
214
  signAuthorization: () => signAuthorization,
214
- signCanonical: () => signCanonical,
215
215
  signOAC: () => signOAC,
216
216
  signPartnerRequest: () => signPartnerRequest,
217
217
  signPass: () => signPass,
@@ -219,11 +219,9 @@ __export(index_exports, {
219
219
  signReceipt: () => signReceipt,
220
220
  signRedemption: () => signRedemption,
221
221
  signRequestHMAC: () => signRequestHMAC,
222
- verify: () => verify,
223
222
  verifyArtifactSignature: () => verifyArtifactSignature,
224
223
  verifyArtifactUri: () => verifyArtifactUri,
225
224
  verifyAuthorization: () => verifyAuthorization,
226
- verifyCanonical: () => verifyCanonical,
227
225
  verifyClaimSignature: () => verifyClaimSignature,
228
226
  verifyOAC: () => verifyOAC,
229
227
  verifyPass: () => verifyPass,
@@ -236,203 +234,13 @@ __export(index_exports, {
236
234
  module.exports = __toCommonJS(index_exports);
237
235
 
238
236
  // src/client.ts
239
- var import_zod4 = require("zod");
237
+ var import_zod5 = require("zod");
240
238
 
241
239
  // src/contracts.ts
240
+ var import_zod2 = require("zod");
241
+
242
+ // src/me-offline/client.ts
242
243
  var import_zod = require("zod");
243
- var E164Regex = /^\+[1-9]\d{7,14}$/;
244
- var UuidSchema = import_zod.z.string().uuid();
245
- var IsoDateSchema = import_zod.z.string().datetime({ offset: true });
246
- var CurrencySchema = import_zod.z.string().trim().length(3).transform((value) => value.toUpperCase());
247
- var HealthResponseSchema = import_zod.z.object({
248
- ok: import_zod.z.boolean()
249
- });
250
- var WelcomeResponseSchema = import_zod.z.object({
251
- message: import_zod.z.string()
252
- });
253
- var OnboardingStartRequestSchema = import_zod.z.object({
254
- phoneE164: import_zod.z.string().regex(E164Regex),
255
- appInstanceId: import_zod.z.string().min(3),
256
- platform: import_zod.z.enum(["android", "ios", "web"]),
257
- turnstileToken: import_zod.z.string().min(20).optional(),
258
- appAttestation: import_zod.z.object({
259
- provider: import_zod.z.enum(["android", "ios", "web"]),
260
- token: import_zod.z.string().min(24)
261
- }).optional(),
262
- firstName: import_zod.z.string().trim().min(1).max(80).optional(),
263
- lastName: import_zod.z.string().trim().min(1).max(80).optional()
264
- });
265
- var OnboardingStartResponseSchema = import_zod.z.object({
266
- requestId: import_zod.z.string().min(1),
267
- checkUrl: import_zod.z.string().url().optional(),
268
- expiresInSec: import_zod.z.number().int().positive(),
269
- fallback: import_zod.z.enum(["SILENT_AUTH", "OTP"])
270
- });
271
- var OnboardingCompleteRequestSchema = import_zod.z.object({
272
- requestId: import_zod.z.string().min(1),
273
- code: import_zod.z.string().min(1).max(32),
274
- appInstanceId: import_zod.z.string().min(3),
275
- fingerprintHash: import_zod.z.string().min(3).optional()
276
- });
277
- var OnboardingCompleteResponseSchema = import_zod.z.object({
278
- sessionToken: import_zod.z.string().min(1),
279
- userId: UuidSchema,
280
- restricted: import_zod.z.boolean(),
281
- risk_reasons: import_zod.z.array(
282
- import_zod.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
283
- ),
284
- stepUpRequired: import_zod.z.boolean().optional(),
285
- riskStatus: import_zod.z.enum(["ok", "unavailable"]).optional()
286
- });
287
- var RegisterDeviceRequestSchema = import_zod.z.object({
288
- userId: UuidSchema,
289
- appInstanceId: import_zod.z.string().min(3),
290
- platform: import_zod.z.string().min(2),
291
- model: import_zod.z.string().optional(),
292
- networkSignals: import_zod.z.object({
293
- ip: import_zod.z.string().min(3),
294
- asn: import_zod.z.number().int().optional(),
295
- country: import_zod.z.string().min(2).optional(),
296
- carrier: import_zod.z.string().optional()
297
- })
298
- });
299
- var RegisterDeviceResponseSchema = import_zod.z.object({
300
- deviceId: import_zod.z.string().min(1),
301
- fingerprintHash: import_zod.z.string().min(1),
302
- driftScore: import_zod.z.number(),
303
- trustState: import_zod.z.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
304
- stepUpRequired: import_zod.z.boolean()
305
- });
306
- var AuthRefreshRequestSchema = import_zod.z.object({
307
- userId: UuidSchema,
308
- refreshToken: import_zod.z.string().min(8),
309
- appInstanceId: import_zod.z.string().min(3),
310
- fingerprintHash: import_zod.z.string().min(3)
311
- });
312
- var AuthRefreshResponseSchema = import_zod.z.object({
313
- refreshToken: import_zod.z.string().min(8),
314
- stepUpRequired: import_zod.z.boolean()
315
- });
316
- var AuthLogoutRequestSchema = import_zod.z.object({
317
- userId: UuidSchema,
318
- refreshToken: import_zod.z.string().min(8)
319
- });
320
- var PinSetRequestSchema = import_zod.z.object({
321
- userId: UuidSchema,
322
- pin: import_zod.z.string().regex(/^\d{6}$/)
323
- });
324
- var PinVerifyRequestSchema = import_zod.z.object({
325
- userId: UuidSchema,
326
- pin: import_zod.z.string().regex(/^\d{6}$/)
327
- });
328
- var OkResponseSchema = import_zod.z.object({
329
- ok: import_zod.z.boolean()
330
- });
331
- var RegisterSendDeviceKeyRequestSchema = import_zod.z.object({
332
- userId: UuidSchema,
333
- deviceId: import_zod.z.string().min(3),
334
- publicKey: import_zod.z.string().min(32)
335
- });
336
- var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
337
- var SendChallengeRequestSchema = import_zod.z.object({
338
- userId: UuidSchema,
339
- deviceId: import_zod.z.string().min(3),
340
- purpose: import_zod.z.enum(SEND_AUTH_PURPOSES).optional()
341
- });
342
- var SendChallengeResponseSchema = import_zod.z.object({
343
- challengeId: UuidSchema,
344
- nonce: import_zod.z.string().min(1),
345
- expiresAt: IsoDateSchema
346
- });
347
- var SendVerifyRequestSchema = import_zod.z.object({
348
- userId: UuidSchema,
349
- deviceId: import_zod.z.string().min(3),
350
- challengeId: UuidSchema,
351
- signature: import_zod.z.string().min(16)
352
- });
353
- var SendVerifyResponseSchema = import_zod.z.object({
354
- sendAuthToken: import_zod.z.string().min(16)
355
- });
356
- var ResolveRecipientRequestSchema = import_zod.z.object({
357
- identifier: import_zod.z.string().min(3)
358
- });
359
- var ResolveRecipientResponseSchema = import_zod.z.object({
360
- recipientUserId: UuidSchema,
361
- displayName: import_zod.z.string().min(1),
362
- normalizedIdentifier: import_zod.z.string().regex(E164Regex),
363
- isActive: import_zod.z.boolean()
364
- });
365
- var CreateTransferRequestSchema = import_zod.z.object({
366
- recipientIdentifier: import_zod.z.string().min(3),
367
- amountMinor: import_zod.z.number().int().positive(),
368
- currency: CurrencySchema,
369
- sendAuthToken: import_zod.z.string().min(16)
370
- });
371
- var TransferStatusSchema = import_zod.z.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
372
- var TransferResponseSchema = import_zod.z.object({
373
- transactionId: import_zod.z.string().min(1),
374
- status: TransferStatusSchema,
375
- userStatus: TransferStatusSchema,
376
- recipientName: import_zod.z.string().min(1),
377
- timestamp: IsoDateSchema
378
- });
379
- var DirectionSchema = import_zod.z.enum(["OUTGOING", "INCOMING"]);
380
- var AccountActivityItemSchema = import_zod.z.object({
381
- id: import_zod.z.string().min(1),
382
- type: import_zod.z.string().min(1),
383
- direction: DirectionSchema,
384
- name: import_zod.z.string().min(1),
385
- identifier: import_zod.z.string().min(1),
386
- amountMinor: import_zod.z.number().int(),
387
- currency: CurrencySchema,
388
- status: import_zod.z.string().min(1),
389
- timestamp: IsoDateSchema
390
- });
391
- var AccountSummaryResponseSchema = import_zod.z.object({
392
- /** Authenticated user's stable internal id. */
393
- userId: UuidSchema,
394
- /**
395
- * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
396
- * bank partner. `null` when the user has no partner-allocated account yet.
397
- */
398
- nuban: import_zod.z.string().regex(/^[0-9]{10}$/).nullable(),
399
- balance: import_zod.z.number().int(),
400
- currency: CurrencySchema,
401
- dailySendLimit: import_zod.z.number().int().nonnegative(),
402
- dailySendRemaining: import_zod.z.number().int().nonnegative(),
403
- kycTier: import_zod.z.string().min(1),
404
- kycStatus: import_zod.z.string().min(1),
405
- recentActivity: import_zod.z.array(AccountActivityItemSchema)
406
- });
407
- var TransactionsListResponseSchema = import_zod.z.object({
408
- items: import_zod.z.array(AccountActivityItemSchema),
409
- nextCursor: import_zod.z.string().nullable()
410
- });
411
- var TransactionDetailResponseSchema = import_zod.z.object({
412
- transactionId: import_zod.z.string().min(1),
413
- type: import_zod.z.string().min(1),
414
- direction: DirectionSchema,
415
- counterpartyName: import_zod.z.string().min(1),
416
- counterpartyIdentifier: import_zod.z.string().min(1),
417
- amountMinor: import_zod.z.number().int(),
418
- currency: CurrencySchema,
419
- status: import_zod.z.string().min(1),
420
- timestamp: IsoDateSchema
421
- });
422
- var PushRegisterRequestSchema = import_zod.z.object({
423
- deviceId: import_zod.z.string().min(3),
424
- platform: import_zod.z.enum(["ios", "android", "web"]),
425
- token: import_zod.z.string().min(16)
426
- });
427
- var CreatePayLinkResponseSchema = import_zod.z.object({
428
- token: import_zod.z.string().min(1)
429
- });
430
- var ResolvePayLinkResponseSchema = import_zod.z.object({
431
- recipientUserId: UuidSchema,
432
- displayName: import_zod.z.string().min(1),
433
- normalizedIdentifier: import_zod.z.string().regex(E164Regex),
434
- isActive: import_zod.z.boolean()
435
- });
436
244
 
437
245
  // src/errors.ts
438
246
  var backendErrorCodeSet = /* @__PURE__ */ new Set([
@@ -536,9 +344,556 @@ async function mapToFlurError(res) {
536
344
  });
537
345
  }
538
346
 
347
+ // src/me-offline/client.ts
348
+ var Hex64 = import_zod.z.string().regex(/^[0-9a-f]{64}$/i);
349
+ var Sha256Hex = import_zod.z.string().regex(/^[0-9a-f]{64}$/i);
350
+ var Base64Std = import_zod.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
351
+ var RegisterDeviceKeyInputSchema = import_zod.z.object({
352
+ deviceId: import_zod.z.string().min(1).max(128),
353
+ publicKeyHex: Hex64
354
+ });
355
+ var AttestationSecurityLevelSchema = import_zod.z.enum([
356
+ "STRONGBOX",
357
+ "TEE",
358
+ "SECURE_ENCLAVE",
359
+ "SOFTWARE"
360
+ ]);
361
+ var DeviceKeyAlgSchema = import_zod.z.literal("p256");
362
+ var RegisterDeviceKeyP256InputSchema = import_zod.z.object({
363
+ deviceId: import_zod.z.string().min(1).max(128),
364
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
365
+ publicKeySpkiB64: Base64Std.min(64).max(4096),
366
+ /** Base64 of the server-issued enrollment challenge string. */
367
+ challengeB64: Base64Std.min(8).max(1024),
368
+ /** iOS App Attest payload or Android X.509 Key Attestation chain. */
369
+ attestationChainB64: import_zod.z.array(Base64Std.min(16).max(16384)).min(1).max(16),
370
+ securityLevel: AttestationSecurityLevelSchema
371
+ });
372
+ var P256EnrollmentChallengeInputSchema = import_zod.z.object({
373
+ deviceId: import_zod.z.string().min(1).max(128)
374
+ });
375
+ var P256EnrollmentChallengeResultSchema = import_zod.z.object({
376
+ challenge: import_zod.z.string().min(16),
377
+ expiresAtMs: import_zod.z.number().int().positive()
378
+ });
379
+ var DeviceKeyRecordSchema = import_zod.z.object({
380
+ id: import_zod.z.string().uuid(),
381
+ userId: import_zod.z.string().uuid(),
382
+ deviceId: import_zod.z.string(),
383
+ /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
384
+ alg: DeviceKeyAlgSchema.default("p256"),
385
+ /** Legacy ed25519 hex key. Always null on new records (kept for back-compat reads). */
386
+ publicKeyHex: Hex64.nullable().default(null),
387
+ /** P-256 SubjectPublicKeyInfo DER, base64. Required for new records. */
388
+ publicKeySpkiB64: Base64Std.nullable().default(null),
389
+ securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
390
+ hardwareBacked: import_zod.z.boolean().default(false),
391
+ attestedAtMs: import_zod.z.number().int().nonnegative().nullable().default(null),
392
+ createdAtMs: import_zod.z.number().int().nonnegative(),
393
+ revokedAtMs: import_zod.z.number().int().nonnegative().nullable()
394
+ });
395
+ var ConsumerOACSchema = import_zod.z.object({
396
+ oacId: import_zod.z.string().uuid(),
397
+ issuerId: import_zod.z.string().min(1).max(64),
398
+ userId: import_zod.z.string().uuid(),
399
+ deviceId: import_zod.z.string().min(1).max(128),
400
+ /**
401
+ * Always 'p256'. Required on the wire (backend always emits it).
402
+ * Kept as a literal so input/output infer identically and the schema
403
+ * can be nested inside other response shapes without Zod input/output
404
+ * divergence under tsup DTS bundling.
405
+ */
406
+ alg: import_zod.z.literal("p256"),
407
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
408
+ devicePubkeySpkiB64: Base64Std.min(64).max(4096),
409
+ perTxCapKobo: import_zod.z.number().int().positive(),
410
+ cumulativeCapKobo: import_zod.z.number().int().positive(),
411
+ currency: import_zod.z.string().length(3),
412
+ validFromMs: import_zod.z.number().int().nonnegative(),
413
+ validUntilMs: import_zod.z.number().int().nonnegative(),
414
+ counterSeed: import_zod.z.number().int().nonnegative(),
415
+ issuedAtMs: import_zod.z.number().int().nonnegative()
416
+ });
417
+ var SignedConsumerOACSchema = import_zod.z.object({
418
+ oac: ConsumerOACSchema,
419
+ /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
420
+ issuerSig: Base64Std.min(16).max(2048),
421
+ /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
422
+ issuerPublicKeySpkiB64: Base64Std.min(64).max(4096)
423
+ });
424
+ var OACRecordSchema = SignedConsumerOACSchema.extend({
425
+ currentOfflineSpentKobo: import_zod.z.number().int().nonnegative(),
426
+ status: import_zod.z.enum([
427
+ "active",
428
+ "superseded",
429
+ "expired",
430
+ "revoked",
431
+ "disabling",
432
+ "draining",
433
+ "closed"
434
+ ]),
435
+ supersededAtMs: import_zod.z.number().int().nonnegative().nullable(),
436
+ revokedAtMs: import_zod.z.number().int().nonnegative().nullable(),
437
+ holdId: import_zod.z.string().uuid().nullable().optional()
438
+ });
439
+ var IssueOACInputSchema = import_zod.z.object({
440
+ deviceId: import_zod.z.string().min(1).max(128),
441
+ perTxCapKobo: import_zod.z.number().int().positive().optional(),
442
+ cumulativeCapKobo: import_zod.z.number().int().positive().optional(),
443
+ ttlMs: import_zod.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
444
+ spendableOnlineKobo: import_zod.z.number().int().nonnegative().optional()
445
+ });
446
+ var IssueAccountOacInputSchema = import_zod.z.object({
447
+ deviceId: import_zod.z.string().min(1).max(128),
448
+ perTxCapKobo: import_zod.z.number().int().positive().optional(),
449
+ cumulativeCapKobo: import_zod.z.number().int().positive().optional(),
450
+ ttlMs: import_zod.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional()
451
+ });
452
+ var EnableOfflineInputSchema = import_zod.z.object({
453
+ deviceId: import_zod.z.string().min(1).max(128),
454
+ amountKobo: import_zod.z.number().int().positive(),
455
+ perTxCapKobo: import_zod.z.number().int().positive().optional(),
456
+ ttlMs: import_zod.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
457
+ installId: import_zod.z.string().min(1).max(128),
458
+ partnerId: import_zod.z.string().min(1).max(64).optional()
459
+ });
460
+ var ProvisionOfflineAllowanceInputSchema = EnableOfflineInputSchema;
461
+ var DisableOfflineInputSchema = import_zod.z.object({
462
+ deviceId: import_zod.z.string().min(1).max(128),
463
+ installId: import_zod.z.string().min(1).max(128).optional(),
464
+ claims: import_zod.z.array(import_zod.z.unknown()).max(256).optional()
465
+ });
466
+ var OfflineHoldRecordSchema = import_zod.z.object({
467
+ holdId: import_zod.z.string().uuid(),
468
+ userId: import_zod.z.string().uuid(),
469
+ deviceId: import_zod.z.string(),
470
+ partnerId: import_zod.z.string(),
471
+ adapterKind: import_zod.z.string(),
472
+ externalHoldRef: import_zod.z.string().nullable(),
473
+ amountKobo: import_zod.z.number().int().nonnegative(),
474
+ capturedKobo: import_zod.z.number().int().nonnegative(),
475
+ releasedKobo: import_zod.z.number().int().nonnegative(),
476
+ remainingKobo: import_zod.z.number().int().nonnegative(),
477
+ currency: import_zod.z.string().length(3),
478
+ status: import_zod.z.enum([
479
+ "placing",
480
+ "active",
481
+ "disabling",
482
+ "draining",
483
+ "closed",
484
+ "revoked",
485
+ "failed"
486
+ ]),
487
+ installId: import_zod.z.string().nullable(),
488
+ drainDeadlineMs: import_zod.z.number().int().nonnegative(),
489
+ disableRequestedAtMs: import_zod.z.number().int().nonnegative().nullable(),
490
+ createdAtMs: import_zod.z.number().int().nonnegative(),
491
+ closedAtMs: import_zod.z.number().int().nonnegative().nullable(),
492
+ isTrusted: import_zod.z.boolean().optional()
493
+ });
494
+ var EnableOfflineResultSchema = import_zod.z.object({
495
+ hold: OfflineHoldRecordSchema,
496
+ oac: OACRecordSchema
497
+ });
498
+ var ProvisionOfflineAllowanceResultSchema = EnableOfflineResultSchema;
499
+ var DisableOfflineResultSchema = import_zod.z.object({
500
+ hold: OfflineHoldRecordSchema,
501
+ trusted: import_zod.z.boolean(),
502
+ settledClaims: import_zod.z.number().int().nonnegative()
503
+ });
504
+ var OfflineStatusResultSchema = import_zod.z.object({
505
+ hold: OfflineHoldRecordSchema.nullable(),
506
+ active: OACRecordSchema.nullable()
507
+ });
508
+ var OfflineStateResultSchema = import_zod.z.object({
509
+ active: OACRecordSchema.nullable()
510
+ });
511
+ var ConsumerPaymentClaimSchema = import_zod.z.object({
512
+ /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
513
+ alg: import_zod.z.literal("p256").default("p256"),
514
+ oacId: import_zod.z.string().uuid(),
515
+ encounterId: Sha256Hex.optional(),
516
+ payerUserId: import_zod.z.string().uuid(),
517
+ payeeUserId: import_zod.z.string().uuid(),
518
+ payerDeviceId: import_zod.z.string().min(1).max(128),
519
+ payerNonce: import_zod.z.string().min(8).max(128),
520
+ payeeNonce: import_zod.z.string().min(8).max(128),
521
+ amountKobo: import_zod.z.number().int().positive(),
522
+ currency: import_zod.z.string().length(3).default("NGN"),
523
+ occurredAtMs: import_zod.z.number().int().nonnegative(),
524
+ completedAtMs: import_zod.z.number().int().nonnegative().optional(),
525
+ contextId: import_zod.z.string().max(128).optional(),
526
+ payerPubkeySpkiB64: Base64Std.min(64).max(4096),
527
+ payerSignatureDerB64: Base64Std.min(16).max(2048),
528
+ payeePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),
529
+ payeeSignatureDerB64: Base64Std.min(16).max(2048).optional()
530
+ });
531
+ var ConsumerSettlementSchema = import_zod.z.object({
532
+ settlementId: import_zod.z.string().uuid(),
533
+ settlementKey: Sha256Hex,
534
+ encounterId: Sha256Hex,
535
+ oacId: import_zod.z.string().uuid(),
536
+ payerUserId: import_zod.z.string().uuid(),
537
+ payeeUserId: import_zod.z.string().uuid(),
538
+ amountKobo: import_zod.z.number().int().positive(),
539
+ currency: import_zod.z.string().length(3),
540
+ status: import_zod.z.enum(["SETTLED", "REVIEW"]),
541
+ reviewReason: import_zod.z.string().nullable(),
542
+ ledgerRef: import_zod.z.string().nullable(),
543
+ /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
544
+ issuerSig: Base64Std.min(16).max(2048),
545
+ createdAtMs: import_zod.z.number().int().nonnegative()
546
+ });
547
+ var ConsumerSettleResultSchema = import_zod.z.object({
548
+ settlement: ConsumerSettlementSchema,
549
+ encounterId: Sha256Hex,
550
+ replayed: import_zod.z.boolean()
551
+ });
552
+ var RevokeDeviceKeyInputSchema = import_zod.z.object({
553
+ deviceId: import_zod.z.string().min(1).max(128),
554
+ /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
555
+ sendAuthToken: import_zod.z.string().min(16)
556
+ });
557
+ function createMeOfflineClient(opts) {
558
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
559
+ if (!fetchImpl) {
560
+ throw new Error("createMeOfflineClient: no fetch implementation available");
561
+ }
562
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
563
+ async function call(method, path, body, parser) {
564
+ const init2 = {
565
+ method,
566
+ headers: {
567
+ "content-type": "application/json",
568
+ accept: "application/json"
569
+ }
570
+ };
571
+ if (body !== void 0) init2.body = JSON.stringify(body);
572
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
573
+ const text = await resp.text();
574
+ let raw = void 0;
575
+ if (text) {
576
+ try {
577
+ raw = JSON.parse(text);
578
+ } catch {
579
+ }
580
+ }
581
+ if (!resp.ok) {
582
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
583
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
584
+ throw new FlurApiError(resp.status, code, message, raw);
585
+ }
586
+ return parser(raw);
587
+ }
588
+ const deviceKeyItems = import_zod.z.object({ items: import_zod.z.array(DeviceKeyRecordSchema) });
589
+ return {
590
+ registerDeviceKey: (input) => call(
591
+ "POST",
592
+ "/v1/me/offline/keys",
593
+ RegisterDeviceKeyInputSchema.parse(input),
594
+ (raw) => DeviceKeyRecordSchema.parse(raw)
595
+ ),
596
+ issueP256EnrollmentChallenge: (input) => call(
597
+ "POST",
598
+ "/v1/me/offline/keys/p256/challenge",
599
+ P256EnrollmentChallengeInputSchema.parse(input),
600
+ (raw) => P256EnrollmentChallengeResultSchema.parse(raw)
601
+ ),
602
+ registerDeviceKeyP256: (input) => call(
603
+ "POST",
604
+ "/v1/me/offline/keys/p256",
605
+ RegisterDeviceKeyP256InputSchema.parse(input),
606
+ (raw) => DeviceKeyRecordSchema.parse(raw)
607
+ ),
608
+ listDeviceKeys: () => call(
609
+ "GET",
610
+ "/v1/me/offline/keys",
611
+ void 0,
612
+ (raw) => deviceKeyItems.parse(raw)
613
+ ),
614
+ revokeDeviceKey: (input) => call(
615
+ "POST",
616
+ "/v1/me/offline/keys/revoke",
617
+ RevokeDeviceKeyInputSchema.parse(input),
618
+ () => void 0
619
+ ),
620
+ issueAccountOac: (input) => call(
621
+ "POST",
622
+ "/v1/me/offline/oac",
623
+ IssueAccountOacInputSchema.parse(input),
624
+ (raw) => OACRecordSchema.parse(raw)
625
+ ),
626
+ provisionAllowance: (input) => call(
627
+ "POST",
628
+ "/v1/me/offline/allowance",
629
+ ProvisionOfflineAllowanceInputSchema.parse(input),
630
+ (raw) => ProvisionOfflineAllowanceResultSchema.parse(raw)
631
+ ),
632
+ enable: (input) => call(
633
+ "POST",
634
+ "/v1/me/offline/enable",
635
+ EnableOfflineInputSchema.parse(input),
636
+ (raw) => EnableOfflineResultSchema.parse(raw)
637
+ ),
638
+ refresh: (input) => call(
639
+ "POST",
640
+ "/v1/me/offline/refresh",
641
+ IssueOACInputSchema.parse(input),
642
+ (raw) => OACRecordSchema.parse(raw)
643
+ ),
644
+ disable: (input) => call(
645
+ "POST",
646
+ "/v1/me/offline/disable",
647
+ DisableOfflineInputSchema.parse(input),
648
+ (raw) => DisableOfflineResultSchema.parse(raw)
649
+ ),
650
+ getStatus: (deviceId) => {
651
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
652
+ return call(
653
+ "GET",
654
+ `/v1/me/offline/status${qs}`,
655
+ void 0,
656
+ (raw) => OfflineStatusResultSchema.parse(raw)
657
+ );
658
+ },
659
+ getState: (deviceId) => {
660
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
661
+ return call(
662
+ "GET",
663
+ `/v1/me/offline/state${qs}`,
664
+ void 0,
665
+ (raw) => OfflineStateResultSchema.parse(raw)
666
+ );
667
+ },
668
+ submitClaim: (claim) => call(
669
+ "POST",
670
+ "/v1/me/offline/claims",
671
+ ConsumerPaymentClaimSchema.parse(claim),
672
+ (raw) => ConsumerSettleResultSchema.parse(raw)
673
+ )
674
+ };
675
+ }
676
+
677
+ // src/contracts.ts
678
+ var E164Regex = /^\+[1-9]\d{7,14}$/;
679
+ var UuidSchema = import_zod2.z.string().uuid();
680
+ var IsoDateSchema = import_zod2.z.string().datetime({ offset: true });
681
+ var CurrencySchema = import_zod2.z.string().trim().length(3).transform((value) => value.toUpperCase());
682
+ var HealthResponseSchema = import_zod2.z.object({
683
+ ok: import_zod2.z.boolean()
684
+ });
685
+ var WelcomeResponseSchema = import_zod2.z.object({
686
+ message: import_zod2.z.string()
687
+ });
688
+ var OnboardingStartRequestSchema = import_zod2.z.object({
689
+ phoneE164: import_zod2.z.string().regex(E164Regex),
690
+ appInstanceId: import_zod2.z.string().min(3),
691
+ platform: import_zod2.z.enum(["android", "ios", "web"]),
692
+ turnstileToken: import_zod2.z.string().min(20).optional(),
693
+ appAttestation: import_zod2.z.object({
694
+ provider: import_zod2.z.enum(["android", "ios", "web"]),
695
+ token: import_zod2.z.string().min(24)
696
+ }).optional(),
697
+ firstName: import_zod2.z.string().trim().min(1).max(80).optional(),
698
+ lastName: import_zod2.z.string().trim().min(1).max(80).optional()
699
+ });
700
+ var OnboardingStartResponseSchema = import_zod2.z.object({
701
+ requestId: import_zod2.z.string().min(1),
702
+ checkUrl: import_zod2.z.string().url().optional(),
703
+ expiresInSec: import_zod2.z.number().int().positive(),
704
+ fallback: import_zod2.z.enum(["SILENT_AUTH", "OTP"])
705
+ });
706
+ var OnboardingCompleteRequestSchema = import_zod2.z.object({
707
+ requestId: import_zod2.z.string().min(1),
708
+ code: import_zod2.z.string().min(1).max(32),
709
+ appInstanceId: import_zod2.z.string().min(3),
710
+ fingerprintHash: import_zod2.z.string().min(3).optional()
711
+ });
712
+ var OnboardingCompleteResponseSchema = import_zod2.z.object({
713
+ sessionToken: import_zod2.z.string().min(1),
714
+ userId: UuidSchema,
715
+ restricted: import_zod2.z.boolean(),
716
+ risk_reasons: import_zod2.z.array(
717
+ import_zod2.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
718
+ ),
719
+ stepUpRequired: import_zod2.z.boolean().optional(),
720
+ riskStatus: import_zod2.z.enum(["ok", "unavailable"]).optional()
721
+ });
722
+ var RegisterDeviceRequestSchema = import_zod2.z.object({
723
+ userId: UuidSchema,
724
+ appInstanceId: import_zod2.z.string().min(3),
725
+ platform: import_zod2.z.string().min(2),
726
+ model: import_zod2.z.string().optional(),
727
+ networkSignals: import_zod2.z.object({
728
+ ip: import_zod2.z.string().min(3),
729
+ asn: import_zod2.z.number().int().optional(),
730
+ country: import_zod2.z.string().min(2).optional(),
731
+ carrier: import_zod2.z.string().optional()
732
+ })
733
+ });
734
+ var RegisterDeviceResponseSchema = import_zod2.z.object({
735
+ deviceId: import_zod2.z.string().min(1),
736
+ fingerprintHash: import_zod2.z.string().min(1),
737
+ driftScore: import_zod2.z.number(),
738
+ trustState: import_zod2.z.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
739
+ stepUpRequired: import_zod2.z.boolean()
740
+ });
741
+ var AuthRefreshRequestSchema = import_zod2.z.object({
742
+ userId: UuidSchema,
743
+ refreshToken: import_zod2.z.string().min(8),
744
+ appInstanceId: import_zod2.z.string().min(3),
745
+ fingerprintHash: import_zod2.z.string().min(3)
746
+ });
747
+ var AuthRefreshResponseSchema = import_zod2.z.object({
748
+ refreshToken: import_zod2.z.string().min(8),
749
+ stepUpRequired: import_zod2.z.boolean()
750
+ });
751
+ var AuthLogoutRequestSchema = import_zod2.z.object({
752
+ userId: UuidSchema,
753
+ refreshToken: import_zod2.z.string().min(8)
754
+ });
755
+ var PinSetRequestSchema = import_zod2.z.object({
756
+ userId: UuidSchema,
757
+ pin: import_zod2.z.string().regex(/^\d{6}$/)
758
+ });
759
+ var PinVerifyRequestSchema = import_zod2.z.object({
760
+ userId: UuidSchema,
761
+ pin: import_zod2.z.string().regex(/^\d{6}$/)
762
+ });
763
+ var OkResponseSchema = import_zod2.z.object({
764
+ ok: import_zod2.z.boolean()
765
+ });
766
+ var RegisterSendDeviceKeyRequestSchema = import_zod2.z.object({
767
+ userId: UuidSchema,
768
+ deviceId: import_zod2.z.string().min(3),
769
+ publicKey: import_zod2.z.string().min(32)
770
+ });
771
+ var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
772
+ var SendChallengeRequestSchema = import_zod2.z.object({
773
+ userId: UuidSchema,
774
+ deviceId: import_zod2.z.string().min(3),
775
+ purpose: import_zod2.z.enum(SEND_AUTH_PURPOSES).optional()
776
+ });
777
+ var SendChallengeResponseSchema = import_zod2.z.object({
778
+ challengeId: UuidSchema,
779
+ nonce: import_zod2.z.string().min(1),
780
+ expiresAt: IsoDateSchema
781
+ });
782
+ var SendVerifyRequestSchema = import_zod2.z.object({
783
+ userId: UuidSchema,
784
+ deviceId: import_zod2.z.string().min(3),
785
+ challengeId: UuidSchema,
786
+ signature: import_zod2.z.string().min(16)
787
+ });
788
+ var SendVerifyResponseSchema = import_zod2.z.object({
789
+ sendAuthToken: import_zod2.z.string().min(16)
790
+ });
791
+ var ResolveRecipientRequestSchema = import_zod2.z.object({
792
+ identifier: import_zod2.z.string().min(3)
793
+ });
794
+ var ResolveRecipientResponseSchema = import_zod2.z.object({
795
+ recipientUserId: UuidSchema,
796
+ displayName: import_zod2.z.string().min(1),
797
+ normalizedIdentifier: import_zod2.z.string().regex(E164Regex),
798
+ isActive: import_zod2.z.boolean()
799
+ });
800
+ var CreateTransferRequestSchema = import_zod2.z.object({
801
+ recipientIdentifier: import_zod2.z.string().min(3),
802
+ amountMinor: import_zod2.z.number().int().positive(),
803
+ currency: CurrencySchema,
804
+ sendAuthToken: import_zod2.z.string().min(16)
805
+ });
806
+ var TransferStatusSchema = import_zod2.z.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
807
+ var TransferResponseSchema = import_zod2.z.object({
808
+ transactionId: import_zod2.z.string().min(1),
809
+ status: TransferStatusSchema,
810
+ userStatus: TransferStatusSchema,
811
+ recipientName: import_zod2.z.string().min(1),
812
+ timestamp: IsoDateSchema,
813
+ /**
814
+ * Fresh issuer-signed OACs returned by the backend's post-commit
815
+ * rotation hook on `SETTLED` transfers.
816
+ *
817
+ * In the current backend implementation this hook rotates LEGACY
818
+ * hold-backed OACs only. Account-funded (no-hold) OACs introduced by
819
+ * the unified-pay-rails refactor are NOT rotated here — their
820
+ * cumulative spend counter and main-balance check are enforced at
821
+ * claim submission time via `createTransfer` under the per-sender
822
+ * advisory lock, so a stale no-hold OAC cannot authorise overspending
823
+ * (it can only resolve to REVIEW on submission).
824
+ *
825
+ * Optional: omitted when the sender has no registered hold-backed
826
+ * devices, when the refresh failed (best-effort), or on retry replays
827
+ * that pre-date the refresh. When present, the entries supersede any
828
+ * locally cached OACs for the listed devices; when absent, clients
829
+ * should fall back to `/v1/me/offline/refresh`.
830
+ *
831
+ * Each entry is validated against the canonical `OACRecordSchema`,
832
+ * so consumers can trust the runtime shape matches the static type.
833
+ */
834
+ offlineOacs: OACRecordSchema.array().optional()
835
+ });
836
+ var DirectionSchema = import_zod2.z.enum(["OUTGOING", "INCOMING"]);
837
+ var AccountActivityItemSchema = import_zod2.z.object({
838
+ id: import_zod2.z.string().min(1),
839
+ type: import_zod2.z.string().min(1),
840
+ direction: DirectionSchema,
841
+ name: import_zod2.z.string().min(1),
842
+ identifier: import_zod2.z.string().min(1),
843
+ amountMinor: import_zod2.z.number().int(),
844
+ currency: CurrencySchema,
845
+ status: import_zod2.z.string().min(1),
846
+ timestamp: IsoDateSchema
847
+ });
848
+ var AccountSummaryResponseSchema = import_zod2.z.object({
849
+ /** Authenticated user's stable internal id. */
850
+ userId: UuidSchema,
851
+ /**
852
+ * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
853
+ * bank partner. `null` when the user has no partner-allocated account yet.
854
+ */
855
+ nuban: import_zod2.z.string().regex(/^[0-9]{10}$/).nullable(),
856
+ balance: import_zod2.z.number().int(),
857
+ currency: CurrencySchema,
858
+ dailySendLimit: import_zod2.z.number().int().nonnegative(),
859
+ dailySendRemaining: import_zod2.z.number().int().nonnegative(),
860
+ kycTier: import_zod2.z.string().min(1),
861
+ kycStatus: import_zod2.z.string().min(1),
862
+ recentActivity: import_zod2.z.array(AccountActivityItemSchema)
863
+ });
864
+ var TransactionsListResponseSchema = import_zod2.z.object({
865
+ items: import_zod2.z.array(AccountActivityItemSchema),
866
+ nextCursor: import_zod2.z.string().nullable()
867
+ });
868
+ var TransactionDetailResponseSchema = import_zod2.z.object({
869
+ transactionId: import_zod2.z.string().min(1),
870
+ type: import_zod2.z.string().min(1),
871
+ direction: DirectionSchema,
872
+ counterpartyName: import_zod2.z.string().min(1),
873
+ counterpartyIdentifier: import_zod2.z.string().min(1),
874
+ amountMinor: import_zod2.z.number().int(),
875
+ currency: CurrencySchema,
876
+ status: import_zod2.z.string().min(1),
877
+ timestamp: IsoDateSchema
878
+ });
879
+ var PushRegisterRequestSchema = import_zod2.z.object({
880
+ deviceId: import_zod2.z.string().min(3),
881
+ platform: import_zod2.z.enum(["ios", "android", "web"]),
882
+ token: import_zod2.z.string().min(16)
883
+ });
884
+ var CreatePayLinkResponseSchema = import_zod2.z.object({
885
+ token: import_zod2.z.string().min(1)
886
+ });
887
+ var ResolvePayLinkResponseSchema = import_zod2.z.object({
888
+ recipientUserId: UuidSchema,
889
+ displayName: import_zod2.z.string().min(1),
890
+ normalizedIdentifier: import_zod2.z.string().regex(E164Regex),
891
+ isActive: import_zod2.z.boolean()
892
+ });
893
+
539
894
  // src/primitives.ts
540
- var import_zod2 = require("zod");
541
- var CurrencyCodeSchema = import_zod2.z.string().trim().length(3).transform((value) => value.toUpperCase());
895
+ var import_zod3 = require("zod");
896
+ var CurrencyCodeSchema = import_zod3.z.string().trim().length(3).transform((value) => value.toUpperCase());
542
897
  var currencyFractionDigits = {
543
898
  NGN: 2,
544
899
  USD: 2,
@@ -632,7 +987,7 @@ function moneyMinorToNumber(amountMinor) {
632
987
  }
633
988
 
634
989
  // src/collections/client.ts
635
- var import_zod3 = require("zod");
990
+ var import_zod4 = require("zod");
636
991
  var MERCHANT_PROFILE_STATUSES = [
637
992
  "pending",
638
993
  "active",
@@ -662,172 +1017,172 @@ var MERCHANT_PAYOUT_STATUSES = [
662
1017
  "failed",
663
1018
  "cancelled"
664
1019
  ];
665
- var MoneyKoboSchema = import_zod3.z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
666
- var MetadataSchema = import_zod3.z.record(
667
- import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()])
1020
+ var MoneyKoboSchema = import_zod4.z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
1021
+ var MetadataSchema = import_zod4.z.record(
1022
+ import_zod4.z.union([import_zod4.z.string(), import_zod4.z.number(), import_zod4.z.boolean(), import_zod4.z.null()])
668
1023
  );
669
- var CurrencySchema2 = import_zod3.z.string().trim().length(3).transform((value) => value.toUpperCase());
670
- var ReferenceSchema = import_zod3.z.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
671
- var MerchantProfileSchema = import_zod3.z.object({
672
- accountId: import_zod3.z.string().uuid(),
673
- legalName: import_zod3.z.string(),
674
- tradingName: import_zod3.z.string(),
675
- merchantCategoryCode: import_zod3.z.string().regex(/^\d{4}$/),
676
- nqrMerchantId: import_zod3.z.string(),
677
- settlementBankCode: import_zod3.z.string(),
678
- settlementAccountNumber: import_zod3.z.string(),
679
- settlementAccountName: import_zod3.z.string(),
680
- settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES),
681
- status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES),
682
- offlineEnabled: import_zod3.z.boolean(),
1024
+ var CurrencySchema2 = import_zod4.z.string().trim().length(3).transform((value) => value.toUpperCase());
1025
+ var ReferenceSchema = import_zod4.z.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
1026
+ var MerchantProfileSchema = import_zod4.z.object({
1027
+ accountId: import_zod4.z.string().uuid(),
1028
+ legalName: import_zod4.z.string(),
1029
+ tradingName: import_zod4.z.string(),
1030
+ merchantCategoryCode: import_zod4.z.string().regex(/^\d{4}$/),
1031
+ nqrMerchantId: import_zod4.z.string(),
1032
+ settlementBankCode: import_zod4.z.string(),
1033
+ settlementAccountNumber: import_zod4.z.string(),
1034
+ settlementAccountName: import_zod4.z.string(),
1035
+ settlementSchedule: import_zod4.z.enum(SETTLEMENT_SCHEDULES),
1036
+ status: import_zod4.z.enum(MERCHANT_PROFILE_STATUSES),
1037
+ offlineEnabled: import_zod4.z.boolean(),
683
1038
  perTxLimitKobo: MoneyKoboSchema,
684
1039
  dailyLimitKobo: MoneyKoboSchema,
685
1040
  metadata: MetadataSchema,
686
- createdAtMs: import_zod3.z.number().int().nonnegative(),
687
- updatedAtMs: import_zod3.z.number().int().nonnegative()
1041
+ createdAtMs: import_zod4.z.number().int().nonnegative(),
1042
+ updatedAtMs: import_zod4.z.number().int().nonnegative()
688
1043
  });
689
- var UpsertMerchantProfileInputSchema = import_zod3.z.object({
690
- legalName: import_zod3.z.string().trim().min(1).max(200),
691
- tradingName: import_zod3.z.string().trim().min(1).max(25),
692
- merchantCategoryCode: import_zod3.z.string().trim().regex(/^\d{4}$/),
693
- nqrMerchantId: import_zod3.z.string().trim().min(3).max(64),
694
- settlementBankCode: import_zod3.z.string().trim().min(2).max(16),
695
- settlementAccountNumber: import_zod3.z.string().trim().min(5).max(32),
696
- settlementAccountName: import_zod3.z.string().trim().min(1).max(200),
697
- settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES).optional(),
698
- status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES).optional(),
699
- offlineEnabled: import_zod3.z.boolean().optional(),
1044
+ var UpsertMerchantProfileInputSchema = import_zod4.z.object({
1045
+ legalName: import_zod4.z.string().trim().min(1).max(200),
1046
+ tradingName: import_zod4.z.string().trim().min(1).max(25),
1047
+ merchantCategoryCode: import_zod4.z.string().trim().regex(/^\d{4}$/),
1048
+ nqrMerchantId: import_zod4.z.string().trim().min(3).max(64),
1049
+ settlementBankCode: import_zod4.z.string().trim().min(2).max(16),
1050
+ settlementAccountNumber: import_zod4.z.string().trim().min(5).max(32),
1051
+ settlementAccountName: import_zod4.z.string().trim().min(1).max(200),
1052
+ settlementSchedule: import_zod4.z.enum(SETTLEMENT_SCHEDULES).optional(),
1053
+ status: import_zod4.z.enum(MERCHANT_PROFILE_STATUSES).optional(),
1054
+ offlineEnabled: import_zod4.z.boolean().optional(),
700
1055
  perTxLimitKobo: MoneyKoboSchema.optional(),
701
1056
  dailyLimitKobo: MoneyKoboSchema.optional(),
702
1057
  metadata: MetadataSchema.optional()
703
1058
  });
704
- var CollectionIntentSchema = import_zod3.z.object({
705
- intentId: import_zod3.z.string().uuid(),
706
- accountId: import_zod3.z.string().uuid(),
707
- terminalId: import_zod3.z.string().uuid().nullable(),
708
- reference: import_zod3.z.string(),
709
- amountKobo: import_zod3.z.number().int().positive().nullable(),
710
- currency: import_zod3.z.string().length(3),
711
- status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
712
- description: import_zod3.z.string().nullable(),
713
- nqrPayload: import_zod3.z.string(),
714
- provider: import_zod3.z.string(),
715
- providerReference: import_zod3.z.string().nullable(),
1059
+ var CollectionIntentSchema = import_zod4.z.object({
1060
+ intentId: import_zod4.z.string().uuid(),
1061
+ accountId: import_zod4.z.string().uuid(),
1062
+ terminalId: import_zod4.z.string().uuid().nullable(),
1063
+ reference: import_zod4.z.string(),
1064
+ amountKobo: import_zod4.z.number().int().positive().nullable(),
1065
+ currency: import_zod4.z.string().length(3),
1066
+ status: import_zod4.z.enum(COLLECTION_INTENT_STATUSES),
1067
+ description: import_zod4.z.string().nullable(),
1068
+ nqrPayload: import_zod4.z.string(),
1069
+ provider: import_zod4.z.string(),
1070
+ providerReference: import_zod4.z.string().nullable(),
716
1071
  metadata: MetadataSchema,
717
- expiresAtMs: import_zod3.z.number().int().nonnegative().nullable(),
718
- paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
719
- createdAtMs: import_zod3.z.number().int().nonnegative(),
720
- updatedAtMs: import_zod3.z.number().int().nonnegative()
1072
+ expiresAtMs: import_zod4.z.number().int().nonnegative().nullable(),
1073
+ paidAtMs: import_zod4.z.number().int().nonnegative().nullable(),
1074
+ createdAtMs: import_zod4.z.number().int().nonnegative(),
1075
+ updatedAtMs: import_zod4.z.number().int().nonnegative()
721
1076
  });
722
- var CreateCollectionIntentInputSchema = import_zod3.z.object({
1077
+ var CreateCollectionIntentInputSchema = import_zod4.z.object({
723
1078
  reference: ReferenceSchema.optional(),
724
1079
  amountKobo: MoneyKoboSchema.optional(),
725
1080
  currency: CurrencySchema2.optional(),
726
- terminalId: import_zod3.z.string().uuid().optional(),
727
- terminalLabel: import_zod3.z.string().trim().min(1).max(25).optional(),
728
- merchantCity: import_zod3.z.string().trim().min(1).max(15).optional(),
729
- description: import_zod3.z.string().trim().min(1).max(280).optional(),
730
- expiresAtMs: import_zod3.z.number().int().positive().optional(),
731
- provider: import_zod3.z.string().trim().min(1).max(40).optional(),
1081
+ terminalId: import_zod4.z.string().uuid().optional(),
1082
+ terminalLabel: import_zod4.z.string().trim().min(1).max(25).optional(),
1083
+ merchantCity: import_zod4.z.string().trim().min(1).max(15).optional(),
1084
+ description: import_zod4.z.string().trim().min(1).max(280).optional(),
1085
+ expiresAtMs: import_zod4.z.number().int().positive().optional(),
1086
+ provider: import_zod4.z.string().trim().min(1).max(40).optional(),
732
1087
  metadata: MetadataSchema.optional()
733
1088
  });
734
- var PublicCollectionIntentSchema = import_zod3.z.object({
735
- intentId: import_zod3.z.string().uuid(),
736
- reference: import_zod3.z.string(),
737
- amountKobo: import_zod3.z.number().int().positive().nullable(),
738
- currency: import_zod3.z.string().length(3),
739
- status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
740
- merchantAccountId: import_zod3.z.string().uuid(),
741
- merchantName: import_zod3.z.string(),
742
- merchantCategoryCode: import_zod3.z.string(),
743
- description: import_zod3.z.string().nullable(),
744
- expiresAtMs: import_zod3.z.number().int().nonnegative().nullable()
1089
+ var PublicCollectionIntentSchema = import_zod4.z.object({
1090
+ intentId: import_zod4.z.string().uuid(),
1091
+ reference: import_zod4.z.string(),
1092
+ amountKobo: import_zod4.z.number().int().positive().nullable(),
1093
+ currency: import_zod4.z.string().length(3),
1094
+ status: import_zod4.z.enum(COLLECTION_INTENT_STATUSES),
1095
+ merchantAccountId: import_zod4.z.string().uuid(),
1096
+ merchantName: import_zod4.z.string(),
1097
+ merchantCategoryCode: import_zod4.z.string(),
1098
+ description: import_zod4.z.string().nullable(),
1099
+ expiresAtMs: import_zod4.z.number().int().nonnegative().nullable()
745
1100
  });
746
- var PayCollectionInputSchema = import_zod3.z.object({
1101
+ var PayCollectionInputSchema = import_zod4.z.object({
747
1102
  reference: ReferenceSchema,
748
1103
  amountKobo: MoneyKoboSchema.optional(),
749
1104
  currency: CurrencySchema2.optional(),
750
- idempotencyKey: import_zod3.z.string().trim().min(8).max(160).optional()
1105
+ idempotencyKey: import_zod4.z.string().trim().min(8).max(160).optional()
751
1106
  });
752
- var CollectionPaymentSchema = import_zod3.z.object({
753
- paymentId: import_zod3.z.string().uuid(),
754
- intentId: import_zod3.z.string().uuid(),
755
- accountId: import_zod3.z.string().uuid(),
756
- payerUserId: import_zod3.z.string().uuid().nullable(),
757
- merchantOwnerUserId: import_zod3.z.string().uuid(),
1107
+ var CollectionPaymentSchema = import_zod4.z.object({
1108
+ paymentId: import_zod4.z.string().uuid(),
1109
+ intentId: import_zod4.z.string().uuid(),
1110
+ accountId: import_zod4.z.string().uuid(),
1111
+ payerUserId: import_zod4.z.string().uuid().nullable(),
1112
+ merchantOwnerUserId: import_zod4.z.string().uuid(),
758
1113
  amountKobo: MoneyKoboSchema,
759
- currency: import_zod3.z.string().length(3),
760
- status: import_zod3.z.enum(COLLECTION_PAYMENT_STATUSES),
761
- provider: import_zod3.z.string(),
762
- providerReference: import_zod3.z.string().nullable(),
763
- idempotencyKey: import_zod3.z.string().nullable(),
764
- ledgerRef: import_zod3.z.string(),
765
- failureCode: import_zod3.z.string().nullable(),
766
- failureMessage: import_zod3.z.string().nullable(),
767
- paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
768
- createdAtMs: import_zod3.z.number().int().nonnegative(),
769
- updatedAtMs: import_zod3.z.number().int().nonnegative()
1114
+ currency: import_zod4.z.string().length(3),
1115
+ status: import_zod4.z.enum(COLLECTION_PAYMENT_STATUSES),
1116
+ provider: import_zod4.z.string(),
1117
+ providerReference: import_zod4.z.string().nullable(),
1118
+ idempotencyKey: import_zod4.z.string().nullable(),
1119
+ ledgerRef: import_zod4.z.string(),
1120
+ failureCode: import_zod4.z.string().nullable(),
1121
+ failureMessage: import_zod4.z.string().nullable(),
1122
+ paidAtMs: import_zod4.z.number().int().nonnegative().nullable(),
1123
+ createdAtMs: import_zod4.z.number().int().nonnegative(),
1124
+ updatedAtMs: import_zod4.z.number().int().nonnegative()
770
1125
  });
771
- var CollectionPaymentResultSchema = import_zod3.z.object({
1126
+ var CollectionPaymentResultSchema = import_zod4.z.object({
772
1127
  payment: CollectionPaymentSchema,
773
1128
  intent: CollectionIntentSchema,
774
- receipt: import_zod3.z.unknown().optional(),
775
- replayed: import_zod3.z.boolean()
1129
+ receipt: import_zod4.z.unknown().optional(),
1130
+ replayed: import_zod4.z.boolean()
776
1131
  });
777
- var CollectionReportSummarySchema = import_zod3.z.object({
778
- accountId: import_zod3.z.string().uuid(),
779
- fromMs: import_zod3.z.number().int().nonnegative(),
780
- toMs: import_zod3.z.number().int().nonnegative(),
781
- currency: import_zod3.z.string().length(3),
782
- paidCount: import_zod3.z.number().int().nonnegative(),
783
- paidAmountKobo: import_zod3.z.number().int().nonnegative(),
784
- pendingCount: import_zod3.z.number().int().nonnegative(),
785
- failedCount: import_zod3.z.number().int().nonnegative(),
786
- reversedCount: import_zod3.z.number().int().nonnegative(),
787
- availableBalanceKobo: import_zod3.z.number().int().nonnegative()
1132
+ var CollectionReportSummarySchema = import_zod4.z.object({
1133
+ accountId: import_zod4.z.string().uuid(),
1134
+ fromMs: import_zod4.z.number().int().nonnegative(),
1135
+ toMs: import_zod4.z.number().int().nonnegative(),
1136
+ currency: import_zod4.z.string().length(3),
1137
+ paidCount: import_zod4.z.number().int().nonnegative(),
1138
+ paidAmountKobo: import_zod4.z.number().int().nonnegative(),
1139
+ pendingCount: import_zod4.z.number().int().nonnegative(),
1140
+ failedCount: import_zod4.z.number().int().nonnegative(),
1141
+ reversedCount: import_zod4.z.number().int().nonnegative(),
1142
+ availableBalanceKobo: import_zod4.z.number().int().nonnegative()
788
1143
  });
789
- var CollectionStatementSchema = import_zod3.z.object({
790
- accountId: import_zod3.z.string().uuid(),
791
- year: import_zod3.z.number().int(),
792
- month: import_zod3.z.number().int().min(1).max(12),
793
- currency: import_zod3.z.string().length(3),
794
- totalPaidKobo: import_zod3.z.number().int().nonnegative(),
795
- items: import_zod3.z.array(CollectionPaymentSchema)
1144
+ var CollectionStatementSchema = import_zod4.z.object({
1145
+ accountId: import_zod4.z.string().uuid(),
1146
+ year: import_zod4.z.number().int(),
1147
+ month: import_zod4.z.number().int().min(1).max(12),
1148
+ currency: import_zod4.z.string().length(3),
1149
+ totalPaidKobo: import_zod4.z.number().int().nonnegative(),
1150
+ items: import_zod4.z.array(CollectionPaymentSchema)
796
1151
  });
797
- var CreatePayoutInputSchema = import_zod3.z.object({
1152
+ var CreatePayoutInputSchema = import_zod4.z.object({
798
1153
  amountKobo: MoneyKoboSchema,
799
1154
  currency: CurrencySchema2.optional(),
800
- idempotencyKey: import_zod3.z.string().trim().min(8).max(160)
1155
+ idempotencyKey: import_zod4.z.string().trim().min(8).max(160)
801
1156
  });
802
- var MerchantPayoutSchema = import_zod3.z.object({
803
- payoutId: import_zod3.z.string().uuid(),
804
- accountId: import_zod3.z.string().uuid(),
1157
+ var MerchantPayoutSchema = import_zod4.z.object({
1158
+ payoutId: import_zod4.z.string().uuid(),
1159
+ accountId: import_zod4.z.string().uuid(),
805
1160
  amountKobo: MoneyKoboSchema,
806
- currency: import_zod3.z.string().length(3),
807
- status: import_zod3.z.enum(MERCHANT_PAYOUT_STATUSES),
808
- idempotencyKey: import_zod3.z.string().nullable(),
809
- ledgerRef: import_zod3.z.string(),
810
- providerReference: import_zod3.z.string().nullable(),
811
- requestedByUserId: import_zod3.z.string().uuid().nullable(),
812
- failureCode: import_zod3.z.string().nullable(),
813
- failureMessage: import_zod3.z.string().nullable(),
814
- createdAtMs: import_zod3.z.number().int().nonnegative(),
815
- updatedAtMs: import_zod3.z.number().int().nonnegative()
1161
+ currency: import_zod4.z.string().length(3),
1162
+ status: import_zod4.z.enum(MERCHANT_PAYOUT_STATUSES),
1163
+ idempotencyKey: import_zod4.z.string().nullable(),
1164
+ ledgerRef: import_zod4.z.string(),
1165
+ providerReference: import_zod4.z.string().nullable(),
1166
+ requestedByUserId: import_zod4.z.string().uuid().nullable(),
1167
+ failureCode: import_zod4.z.string().nullable(),
1168
+ failureMessage: import_zod4.z.string().nullable(),
1169
+ createdAtMs: import_zod4.z.number().int().nonnegative(),
1170
+ updatedAtMs: import_zod4.z.number().int().nonnegative()
816
1171
  });
817
- var ProviderEventInputSchema = import_zod3.z.object({
818
- provider: import_zod3.z.string().trim().min(1).max(80),
819
- eventId: import_zod3.z.string().trim().min(1).max(160),
820
- eventType: import_zod3.z.string().trim().min(1).max(120),
821
- payload: import_zod3.z.record(import_zod3.z.unknown()).optional()
1172
+ var ProviderEventInputSchema = import_zod4.z.object({
1173
+ provider: import_zod4.z.string().trim().min(1).max(80),
1174
+ eventId: import_zod4.z.string().trim().min(1).max(160),
1175
+ eventType: import_zod4.z.string().trim().min(1).max(120),
1176
+ payload: import_zod4.z.record(import_zod4.z.unknown()).optional()
822
1177
  });
823
- var ProviderEventRecordSchema = import_zod3.z.object({
824
- id: import_zod3.z.string().uuid(),
825
- provider: import_zod3.z.string(),
826
- eventId: import_zod3.z.string(),
827
- eventType: import_zod3.z.string(),
828
- signatureVerified: import_zod3.z.boolean(),
829
- receivedAtMs: import_zod3.z.number().int().nonnegative(),
830
- processedAtMs: import_zod3.z.number().int().nonnegative().nullable()
1178
+ var ProviderEventRecordSchema = import_zod4.z.object({
1179
+ id: import_zod4.z.string().uuid(),
1180
+ provider: import_zod4.z.string(),
1181
+ eventId: import_zod4.z.string(),
1182
+ eventType: import_zod4.z.string(),
1183
+ signatureVerified: import_zod4.z.boolean(),
1184
+ receivedAtMs: import_zod4.z.number().int().nonnegative(),
1185
+ processedAtMs: import_zod4.z.number().int().nonnegative().nullable()
831
1186
  });
832
1187
  function createCollectionsClient(opts) {
833
1188
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -1342,7 +1697,7 @@ var FlurClient = class {
1342
1697
  try {
1343
1698
  body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
1344
1699
  } catch (err) {
1345
- if (err instanceof import_zod4.z.ZodError) {
1700
+ if (err instanceof import_zod5.z.ZodError) {
1346
1701
  throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
1347
1702
  details: err.flatten()
1348
1703
  });
@@ -1370,7 +1725,7 @@ var FlurClient = class {
1370
1725
  try {
1371
1726
  return responseSchema.parse(payload);
1372
1727
  } catch (err) {
1373
- if (err instanceof import_zod4.z.ZodError) {
1728
+ if (err instanceof import_zod5.z.ZodError) {
1374
1729
  throw new FlurError(
1375
1730
  "SDK contract validation failed",
1376
1731
  "INVALID_REQUEST",
@@ -1800,64 +2155,113 @@ function constantTimeEqual(a, b) {
1800
2155
  return diff === 0;
1801
2156
  }
1802
2157
 
1803
- // src/crypto/ed25519.ts
1804
- var import_ed25519 = require("@noble/curves/ed25519");
1805
- function generateKeyPair() {
1806
- const privateKey = import_ed25519.ed25519.utils.randomPrivateKey();
1807
- const publicKey = import_ed25519.ed25519.getPublicKey(privateKey);
1808
- return { privateKey, publicKey };
2158
+ // src/offline/oac.ts
2159
+ var import_zod6 = require("zod");
2160
+
2161
+ // src/crypto/p256-issuer.ts
2162
+ var import_nist = require("@noble/curves/nist");
2163
+ function bytesToBase64(bytes) {
2164
+ if (typeof Buffer !== "undefined") {
2165
+ return Buffer.from(bytes).toString("base64");
2166
+ }
2167
+ let bin = "";
2168
+ for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
2169
+ return btoa(bin);
1809
2170
  }
1810
- function publicKeyFromPrivate(privateKey) {
1811
- return import_ed25519.ed25519.getPublicKey(privateKey);
2171
+ function base64ToBytes(b64) {
2172
+ if (typeof Buffer !== "undefined") {
2173
+ return new Uint8Array(Buffer.from(b64, "base64"));
2174
+ }
2175
+ const bin = atob(b64);
2176
+ const out = new Uint8Array(bin.length);
2177
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
2178
+ return out;
1812
2179
  }
1813
- function sign(message, privateKey) {
1814
- return import_ed25519.ed25519.sign(message, privateKey);
2180
+ var P256_SPKI_HEADER = new Uint8Array([
2181
+ 48,
2182
+ 89,
2183
+ 48,
2184
+ 19,
2185
+ 6,
2186
+ 7,
2187
+ 42,
2188
+ 134,
2189
+ 72,
2190
+ 206,
2191
+ 61,
2192
+ 2,
2193
+ 1,
2194
+ 6,
2195
+ 8,
2196
+ 42,
2197
+ 134,
2198
+ 72,
2199
+ 206,
2200
+ 61,
2201
+ 3,
2202
+ 1,
2203
+ 7,
2204
+ 3,
2205
+ 66,
2206
+ 0
2207
+ ]);
2208
+ function p256SpkiB64ToRaw(spkiB64) {
2209
+ const spki = base64ToBytes(spkiB64);
2210
+ if (spki.length !== P256_SPKI_HEADER.length + 65) {
2211
+ throw new Error("p256: invalid SPKI length");
2212
+ }
2213
+ for (let i = 0; i < P256_SPKI_HEADER.length; i++) {
2214
+ if (spki[i] !== P256_SPKI_HEADER[i]) {
2215
+ throw new Error("p256: invalid SPKI header");
2216
+ }
2217
+ }
2218
+ return spki.slice(P256_SPKI_HEADER.length);
2219
+ }
2220
+ function signIssuerP256(bytes, issuerPrivateKey) {
2221
+ const sig = import_nist.p256.sign(bytes, issuerPrivateKey, { prehash: true });
2222
+ return bytesToBase64(sig.toBytes("der"));
1815
2223
  }
1816
- function verify(message, signature, publicKey) {
2224
+ function verifyIssuerP256(bytes, signatureB64, issuerPublicKeySpkiB64) {
1817
2225
  try {
1818
- return import_ed25519.ed25519.verify(signature, message, publicKey);
2226
+ const pubRaw = p256SpkiB64ToRaw(issuerPublicKeySpkiB64);
2227
+ const sigBytes = base64ToBytes(signatureB64);
2228
+ return import_nist.p256.verify(sigBytes, bytes, pubRaw, {
2229
+ prehash: true,
2230
+ format: "der"
2231
+ });
1819
2232
  } catch {
1820
2233
  return false;
1821
2234
  }
1822
2235
  }
1823
- function signCanonical(value, privateKey) {
1824
- return sign(canonicalJSONBytes(value), privateKey);
1825
- }
1826
- function verifyCanonical(value, signature, publicKey) {
1827
- return verify(canonicalJSONBytes(value), signature, publicKey);
1828
- }
1829
2236
 
1830
2237
  // src/offline/oac.ts
1831
- var import_zod5 = require("zod");
1832
2238
  var OAC_DEFAULT_PER_TX_KOBO = 5e5;
1833
2239
  var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
1834
2240
  var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
1835
- var HexString = (length) => import_zod5.z.string().regex(
1836
- new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
1837
- `expected ${length}-byte hex string`
1838
- );
1839
- var OACSchema = import_zod5.z.object({
1840
- userId: import_zod5.z.string().min(1),
1841
- deviceId: import_zod5.z.string().min(1),
1842
- devicePublicKey: HexString(32),
1843
- perTxCapKobo: import_zod5.z.number().int().nonnegative(),
1844
- cumulativeCapKobo: import_zod5.z.number().int().nonnegative(),
1845
- validFromMs: import_zod5.z.number().int().nonnegative(),
1846
- validUntilMs: import_zod5.z.number().int().positive(),
1847
- counterSeed: import_zod5.z.number().int().nonnegative(),
1848
- nonce: import_zod5.z.string().min(1),
1849
- issuerSig: HexString(64)
2241
+ var Base64Std2 = import_zod6.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) string");
2242
+ var OACSchema = import_zod6.z.object({
2243
+ userId: import_zod6.z.string().min(1),
2244
+ deviceId: import_zod6.z.string().min(1),
2245
+ /** SubjectPublicKeyInfo DER, base64 (P-256). */
2246
+ devicePublicKey: Base64Std2,
2247
+ perTxCapKobo: import_zod6.z.number().int().nonnegative(),
2248
+ cumulativeCapKobo: import_zod6.z.number().int().nonnegative(),
2249
+ validFromMs: import_zod6.z.number().int().nonnegative(),
2250
+ validUntilMs: import_zod6.z.number().int().positive(),
2251
+ counterSeed: import_zod6.z.number().int().nonnegative(),
2252
+ nonce: import_zod6.z.string().min(1),
2253
+ /** ASN.1 DER ECDSA(SHA-256) signature, base64. */
2254
+ issuerSig: Base64Std2
1850
2255
  }).refine((v) => v.validUntilMs > v.validFromMs, {
1851
2256
  message: "validUntilMs must be greater than validFromMs"
1852
2257
  }).refine((v) => v.perTxCapKobo <= v.cumulativeCapKobo, {
1853
2258
  message: "perTxCapKobo must not exceed cumulativeCapKobo"
1854
2259
  });
1855
2260
  function buildOAC(input) {
1856
- const devicePublicKey = typeof input.devicePublicKey === "string" ? input.devicePublicKey : bytesToHex(input.devicePublicKey);
1857
2261
  return {
1858
2262
  userId: input.userId,
1859
2263
  deviceId: input.deviceId,
1860
- devicePublicKey,
2264
+ devicePublicKey: input.devicePublicKey,
1861
2265
  perTxCapKobo: input.perTxCapKobo ?? OAC_DEFAULT_PER_TX_KOBO,
1862
2266
  cumulativeCapKobo: input.cumulativeCapKobo ?? OAC_DEFAULT_CUMULATIVE_KOBO,
1863
2267
  validFromMs: input.validFromMs,
@@ -1867,36 +2271,25 @@ function buildOAC(input) {
1867
2271
  };
1868
2272
  }
1869
2273
  function signOAC(unsigned, issuerPrivateKey) {
1870
- const issuerSig = bytesToHex(
1871
- sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
2274
+ const issuerSig = signIssuerP256(
2275
+ canonicalJSONBytes(unsigned),
2276
+ issuerPrivateKey
1872
2277
  );
1873
2278
  return { ...unsigned, issuerSig };
1874
2279
  }
1875
- function verifyOAC(oac, issuerPublicKey) {
2280
+ function verifyOAC(oac, issuerPublicKeySpkiB64) {
1876
2281
  try {
1877
2282
  const parsed = OACSchema.parse(oac);
1878
2283
  const { issuerSig, ...unsigned } = parsed;
1879
- return verify(
2284
+ return verifyIssuerP256(
1880
2285
  canonicalJSONBytes(unsigned),
1881
- hexToBytes(issuerSig),
1882
- issuerPublicKey
2286
+ issuerSig,
2287
+ issuerPublicKeySpkiB64
1883
2288
  );
1884
2289
  } catch {
1885
2290
  return false;
1886
2291
  }
1887
2292
  }
1888
- function bytesToHex(b) {
1889
- let s = "";
1890
- for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, "0");
1891
- return s;
1892
- }
1893
- function hexToBytes(s) {
1894
- if (s.length % 2 !== 0) throw new Error("hex: odd length");
1895
- const out = new Uint8Array(s.length / 2);
1896
- for (let i = 0; i < out.length; i++)
1897
- out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16);
1898
- return out;
1899
- }
1900
2293
 
1901
2294
  // src/offline/codec.ts
1902
2295
  var ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
@@ -1952,20 +2345,20 @@ function decodeBase45(s) {
1952
2345
  }
1953
2346
 
1954
2347
  // src/offline/messages.ts
1955
- var import_zod6 = require("zod");
1956
- var HexSig = import_zod6.z.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
1957
- var OfflinePaymentRequestSchema = import_zod6.z.object({
1958
- reference: import_zod6.z.string().min(1),
1959
- amountKobo: import_zod6.z.number().int().positive(),
2348
+ var import_zod7 = require("zod");
2349
+ var Base64Sig = import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) signature");
2350
+ var OfflinePaymentRequestSchema = import_zod7.z.object({
2351
+ reference: import_zod7.z.string().min(1),
2352
+ amountKobo: import_zod7.z.number().int().positive(),
1960
2353
  merchantOAC: OACSchema,
1961
- expiresAtMs: import_zod6.z.number().int().positive(),
1962
- merchantSig: HexSig
2354
+ expiresAtMs: import_zod7.z.number().int().positive(),
2355
+ merchantSig: Base64Sig
1963
2356
  });
1964
- var OfflinePaymentAuthorizationSchema = import_zod6.z.object({
2357
+ var OfflinePaymentAuthorizationSchema = import_zod7.z.object({
1965
2358
  request: OfflinePaymentRequestSchema,
1966
2359
  payerOAC: OACSchema,
1967
- payerCounter: import_zod6.z.number().int().positive(),
1968
- payerSig: HexSig
2360
+ payerCounter: import_zod7.z.number().int().positive(),
2361
+ payerSig: Base64Sig
1969
2362
  });
1970
2363
  function buildPaymentRequest(input) {
1971
2364
  if (!Number.isInteger(input.amountKobo) || input.amountKobo <= 0) {
@@ -1982,27 +2375,28 @@ function buildPaymentRequest(input) {
1982
2375
  };
1983
2376
  }
1984
2377
  function signPaymentRequest(unsigned, merchantDevicePrivateKey) {
1985
- const merchantSig = bytesToHex(
1986
- sign(canonicalJSONBytes(unsigned), merchantDevicePrivateKey)
2378
+ const merchantSig = signIssuerP256(
2379
+ canonicalJSONBytes(unsigned),
2380
+ merchantDevicePrivateKey
1987
2381
  );
1988
2382
  return { ...unsigned, merchantSig };
1989
2383
  }
1990
- function verifyPaymentRequest(req, issuerPublicKey) {
2384
+ function verifyPaymentRequest(req, issuerPublicKeySpkiB64) {
1991
2385
  try {
1992
2386
  const parsed = OfflinePaymentRequestSchema.parse(req);
1993
2387
  const { issuerSig: merchantOacSig, ...merchantOacUnsigned } = parsed.merchantOAC;
1994
- if (!verify(
2388
+ if (!verifyIssuerP256(
1995
2389
  canonicalJSONBytes(merchantOacUnsigned),
1996
- hexToBytes(merchantOacSig),
1997
- issuerPublicKey
2390
+ merchantOacSig,
2391
+ issuerPublicKeySpkiB64
1998
2392
  )) {
1999
2393
  return false;
2000
2394
  }
2001
2395
  const { merchantSig, ...unsigned } = parsed;
2002
- return verify(
2396
+ return verifyIssuerP256(
2003
2397
  canonicalJSONBytes(unsigned),
2004
- hexToBytes(merchantSig),
2005
- hexToBytes(parsed.merchantOAC.devicePublicKey)
2398
+ merchantSig,
2399
+ parsed.merchantOAC.devicePublicKey
2006
2400
  );
2007
2401
  } catch {
2008
2402
  return false;
@@ -2022,28 +2416,30 @@ function buildAuthorization(input) {
2022
2416
  };
2023
2417
  }
2024
2418
  function signAuthorization(unsigned, payerDevicePrivateKey) {
2025
- const payerSig = bytesToHex(
2026
- sign(canonicalJSONBytes(unsigned), payerDevicePrivateKey)
2419
+ const payerSig = signIssuerP256(
2420
+ canonicalJSONBytes(unsigned),
2421
+ payerDevicePrivateKey
2027
2422
  );
2028
2423
  return { ...unsigned, payerSig };
2029
2424
  }
2030
- function verifyAuthorization(auth, issuerPublicKey) {
2425
+ function verifyAuthorization(auth, issuerPublicKeySpkiB64) {
2031
2426
  try {
2032
2427
  const parsed = OfflinePaymentAuthorizationSchema.parse(auth);
2033
- if (!verifyPaymentRequest(parsed.request, issuerPublicKey)) return false;
2428
+ if (!verifyPaymentRequest(parsed.request, issuerPublicKeySpkiB64))
2429
+ return false;
2034
2430
  const { issuerSig: payerOacSig, ...payerOacUnsigned } = parsed.payerOAC;
2035
- if (!verify(
2431
+ if (!verifyIssuerP256(
2036
2432
  canonicalJSONBytes(payerOacUnsigned),
2037
- hexToBytes(payerOacSig),
2038
- issuerPublicKey
2433
+ payerOacSig,
2434
+ issuerPublicKeySpkiB64
2039
2435
  )) {
2040
2436
  return false;
2041
2437
  }
2042
2438
  const { payerSig, ...unsigned } = parsed;
2043
- return verify(
2439
+ return verifyIssuerP256(
2044
2440
  canonicalJSONBytes(unsigned),
2045
- hexToBytes(payerSig),
2046
- hexToBytes(parsed.payerOAC.devicePublicKey)
2441
+ payerSig,
2442
+ parsed.payerOAC.devicePublicKey
2047
2443
  );
2048
2444
  } catch {
2049
2445
  return false;
@@ -2073,56 +2469,60 @@ function decodeAuthorizationQR(s) {
2073
2469
  }
2074
2470
 
2075
2471
  // src/offline/settlements.ts
2076
- var import_zod7 = require("zod");
2472
+ var import_zod8 = require("zod");
2077
2473
  var import_sha256 = require("@noble/hashes/sha256");
2078
2474
  var import_utils = require("@noble/hashes/utils");
2079
- var OfflineTokenSchema = import_zod7.z.object({
2080
- tokenId: import_zod7.z.string().uuid(),
2081
- tokenSerial: import_zod7.z.string(),
2082
- issuerAccountId: import_zod7.z.string().uuid(),
2083
- payerUserId: import_zod7.z.string().uuid(),
2084
- maxAmountKobo: import_zod7.z.number().int().positive(),
2085
- currency: import_zod7.z.string().length(3),
2086
- issuedAtMs: import_zod7.z.number().int().nonnegative(),
2087
- expiresAtMs: import_zod7.z.number().int().nonnegative(),
2088
- issuerSig: import_zod7.z.string()
2475
+ var OfflineTokenSchema = import_zod8.z.object({
2476
+ tokenId: import_zod8.z.string().uuid(),
2477
+ tokenSerial: import_zod8.z.string(),
2478
+ issuerAccountId: import_zod8.z.string().uuid(),
2479
+ payerUserId: import_zod8.z.string().uuid(),
2480
+ maxAmountKobo: import_zod8.z.number().int().positive(),
2481
+ currency: import_zod8.z.string().length(3),
2482
+ issuedAtMs: import_zod8.z.number().int().nonnegative(),
2483
+ expiresAtMs: import_zod8.z.number().int().nonnegative(),
2484
+ issuerSig: import_zod8.z.string()
2089
2485
  });
2090
- var PaymentClaimSchema = import_zod7.z.object({
2091
- encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
2092
- tokenSerial: import_zod7.z.string(),
2093
- payerUserId: import_zod7.z.string().uuid(),
2094
- payeeUserId: import_zod7.z.string().uuid(),
2095
- payerNonce: import_zod7.z.string(),
2096
- payeeNonce: import_zod7.z.string(),
2097
- amountKobo: import_zod7.z.number().int().positive(),
2098
- currency: import_zod7.z.string().length(3).default("NGN"),
2099
- occurredAtMs: import_zod7.z.number().int().nonnegative(),
2100
- completedAtMs: import_zod7.z.number().int().nonnegative().optional(),
2101
- contextId: import_zod7.z.string().optional(),
2102
- payerPubkey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2103
- payerSignature: import_zod7.z.string().regex(/^[0-9a-f]+$/i),
2104
- payeePubkey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
2105
- payeeSignature: import_zod7.z.string().regex(/^[0-9a-f]+$/i).optional()
2486
+ var PaymentClaimSchema = import_zod8.z.object({
2487
+ encounterId: import_zod8.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
2488
+ tokenSerial: import_zod8.z.string(),
2489
+ payerUserId: import_zod8.z.string().uuid(),
2490
+ payeeUserId: import_zod8.z.string().uuid(),
2491
+ payerNonce: import_zod8.z.string(),
2492
+ payeeNonce: import_zod8.z.string(),
2493
+ amountKobo: import_zod8.z.number().int().positive(),
2494
+ currency: import_zod8.z.string().length(3).default("NGN"),
2495
+ occurredAtMs: import_zod8.z.number().int().nonnegative(),
2496
+ completedAtMs: import_zod8.z.number().int().nonnegative().optional(),
2497
+ contextId: import_zod8.z.string().optional(),
2498
+ // Stage 2c: P-256 device keys are now SubjectPublicKeyInfo DER, base64.
2499
+ // Signatures are ASN.1 DER ECDSA(SHA-256), base64. Backwards-incompatible
2500
+ // wire change; the backend has the matching widening in offline-settlements
2501
+ // service + zod schema.
2502
+ payerPubkey: import_zod8.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2503
+ payerSignature: import_zod8.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2504
+ payeePubkey: import_zod8.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional(),
2505
+ payeeSignature: import_zod8.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional()
2106
2506
  });
2107
- var SettlementSchema = import_zod7.z.object({
2108
- settlementId: import_zod7.z.string().uuid(),
2109
- settlementKey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2110
- encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2111
- issuerAccountId: import_zod7.z.string().uuid(),
2112
- tokenSerial: import_zod7.z.string(),
2113
- payerUserId: import_zod7.z.string().uuid(),
2114
- payeeUserId: import_zod7.z.string().uuid(),
2115
- amountKobo: import_zod7.z.number().int().nonnegative(),
2116
- currency: import_zod7.z.string().length(3),
2117
- receiptId: import_zod7.z.string().nullable(),
2118
- status: import_zod7.z.enum(["SETTLED", "REVIEW", "REJECTED"]),
2119
- issuerSig: import_zod7.z.string(),
2120
- createdAtMs: import_zod7.z.number().int().nonnegative()
2507
+ var SettlementSchema = import_zod8.z.object({
2508
+ settlementId: import_zod8.z.string().uuid(),
2509
+ settlementKey: import_zod8.z.string().regex(/^[0-9a-f]{64}$/i),
2510
+ encounterId: import_zod8.z.string().regex(/^[0-9a-f]{64}$/i),
2511
+ issuerAccountId: import_zod8.z.string().uuid(),
2512
+ tokenSerial: import_zod8.z.string(),
2513
+ payerUserId: import_zod8.z.string().uuid(),
2514
+ payeeUserId: import_zod8.z.string().uuid(),
2515
+ amountKobo: import_zod8.z.number().int().nonnegative(),
2516
+ currency: import_zod8.z.string().length(3),
2517
+ receiptId: import_zod8.z.string().nullable(),
2518
+ status: import_zod8.z.enum(["SETTLED", "REVIEW", "REJECTED"]),
2519
+ issuerSig: import_zod8.z.string(),
2520
+ createdAtMs: import_zod8.z.number().int().nonnegative()
2121
2521
  });
2122
- var SettleResponseSchema = import_zod7.z.object({
2522
+ var SettleResponseSchema = import_zod8.z.object({
2123
2523
  settlement: SettlementSchema,
2124
- encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2125
- replayed: import_zod7.z.boolean()
2524
+ encounterId: import_zod8.z.string().regex(/^[0-9a-f]{64}$/i),
2525
+ replayed: import_zod8.z.boolean()
2126
2526
  });
2127
2527
  var ENCOUNTER_DOMAIN = "offline:v1:encounter";
2128
2528
  async function sha256Hex(input) {
@@ -2296,7 +2696,7 @@ function createHmacFetch(opts) {
2296
2696
  }
2297
2697
 
2298
2698
  // src/partner/client.ts
2299
- var import_zod8 = require("zod");
2699
+ var import_zod9 = require("zod");
2300
2700
  var import_sha2563 = require("@noble/hashes/sha256");
2301
2701
  var import_hmac4 = require("@noble/hashes/hmac");
2302
2702
  var import_utils2 = require("@noble/hashes/utils");
@@ -2320,18 +2720,18 @@ var PARTNER_SCOPES = [
2320
2720
  "partner:payout:write",
2321
2721
  "partner:reconciliation:read"
2322
2722
  ];
2323
- var ApiCredentialPublicSchema = import_zod8.z.object({
2324
- id: import_zod8.z.string().uuid(),
2325
- accountId: import_zod8.z.string().uuid(),
2326
- keyId: import_zod8.z.string(),
2327
- scopes: import_zod8.z.array(import_zod8.z.enum(PARTNER_SCOPES)),
2328
- label: import_zod8.z.string().nullable(),
2329
- createdAtMs: import_zod8.z.number().int().nonnegative(),
2330
- lastUsedAtMs: import_zod8.z.number().int().nonnegative().nullable(),
2331
- revokedAtMs: import_zod8.z.number().int().nonnegative().nullable()
2723
+ var ApiCredentialPublicSchema = import_zod9.z.object({
2724
+ id: import_zod9.z.string().uuid(),
2725
+ accountId: import_zod9.z.string().uuid(),
2726
+ keyId: import_zod9.z.string(),
2727
+ scopes: import_zod9.z.array(import_zod9.z.enum(PARTNER_SCOPES)),
2728
+ label: import_zod9.z.string().nullable(),
2729
+ createdAtMs: import_zod9.z.number().int().nonnegative(),
2730
+ lastUsedAtMs: import_zod9.z.number().int().nonnegative().nullable(),
2731
+ revokedAtMs: import_zod9.z.number().int().nonnegative().nullable()
2332
2732
  });
2333
2733
  var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2334
- secret: import_zod8.z.string().min(1)
2734
+ secret: import_zod9.z.string().min(1)
2335
2735
  });
2336
2736
  var enc = new TextEncoder();
2337
2737
  async function sha256Hex2(input) {
@@ -2488,8 +2888,8 @@ function createApiCredentialsAdminClient(opts) {
2488
2888
  }
2489
2889
  return parser(raw);
2490
2890
  }
2491
- const listSchema = import_zod8.z.object({
2492
- items: import_zod8.z.array(ApiCredentialPublicSchema)
2891
+ const listSchema = import_zod9.z.object({
2892
+ items: import_zod9.z.array(ApiCredentialPublicSchema)
2493
2893
  });
2494
2894
  return {
2495
2895
  list: (accountId) => call(
@@ -2514,7 +2914,7 @@ function createApiCredentialsAdminClient(opts) {
2514
2914
  }
2515
2915
 
2516
2916
  // src/passes/pass.ts
2517
- var import_zod9 = require("zod");
2917
+ var import_zod10 = require("zod");
2518
2918
  var PASS_KINDS = [
2519
2919
  "ride-ticket",
2520
2920
  "transit-pass",
@@ -2530,42 +2930,39 @@ var PASS_STATES = [
2530
2930
  "expired",
2531
2931
  "revoked"
2532
2932
  ];
2533
- var HexString2 = (length) => import_zod9.z.string().regex(
2534
- new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
2535
- `expected ${length}-byte hex string`
2536
- );
2537
- var PassMetadataSchema = import_zod9.z.record(
2538
- import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number(), import_zod9.z.boolean(), import_zod9.z.null()])
2933
+ var PassMetadataSchema = import_zod10.z.record(
2934
+ import_zod10.z.union([import_zod10.z.string(), import_zod10.z.number(), import_zod10.z.boolean(), import_zod10.z.null()])
2539
2935
  );
2540
- var PassSchema = import_zod9.z.object({
2541
- passId: import_zod9.z.string().min(1),
2936
+ var PassSchema = import_zod10.z.object({
2937
+ passId: import_zod10.z.string().min(1),
2542
2938
  /** Optional client/template grouping id (server may omit). */
2543
- templateId: import_zod9.z.string().min(1).optional(),
2939
+ templateId: import_zod10.z.string().min(1).optional(),
2544
2940
  /** Optional human-facing holder identity (server may omit). The cryptographic binding
2545
2941
  * is `holderDevicePubkey` below. */
2546
- holderUserId: import_zod9.z.string().min(1).optional(),
2547
- kind: import_zod9.z.enum(PASS_KINDS),
2548
- issuerId: import_zod9.z.string().min(1),
2549
- issuedAtMs: import_zod9.z.number().int().nonnegative(),
2550
- validFromMs: import_zod9.z.number().int().nonnegative(),
2551
- validUntilMs: import_zod9.z.number().int().positive(),
2552
- state: import_zod9.z.enum(PASS_STATES),
2942
+ holderUserId: import_zod10.z.string().min(1).optional(),
2943
+ kind: import_zod10.z.enum(PASS_KINDS),
2944
+ issuerId: import_zod10.z.string().min(1),
2945
+ issuedAtMs: import_zod10.z.number().int().nonnegative(),
2946
+ validFromMs: import_zod10.z.number().int().nonnegative(),
2947
+ validUntilMs: import_zod10.z.number().int().positive(),
2948
+ state: import_zod10.z.enum(PASS_STATES),
2553
2949
  metadata: PassMetadataSchema,
2554
- nonce: import_zod9.z.string().min(1),
2950
+ nonce: import_zod10.z.string().min(1),
2555
2951
  /** Device id this pass is bound to (FK to backend `device_keys`). */
2556
- holderDeviceId: import_zod9.z.string().min(1),
2557
- /** 32-byte hex Ed25519 public key of the bound device. The redemption signature
2558
- * is verified against this key — it is the security-critical binding. */
2559
- holderDevicePubkey: HexString2(32),
2952
+ holderDeviceId: import_zod10.z.string().min(1),
2953
+ /** SubjectPublicKeyInfo DER (P-256) of the bound device, base64. The redemption
2954
+ * signature is verified against this key — it is the security-critical binding. */
2955
+ holderDevicePubkey: import_zod10.z.string().min(64).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2560
2956
  /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
2561
- amountKobo: import_zod9.z.number().int().nonnegative().optional(),
2957
+ amountKobo: import_zod10.z.number().int().nonnegative().optional(),
2562
2958
  /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
2563
- currency: import_zod9.z.string().min(3).max(8),
2959
+ currency: import_zod10.z.string().min(3).max(8),
2564
2960
  /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
2565
- counterSeed: import_zod9.z.number().int().nonnegative(),
2961
+ counterSeed: import_zod10.z.number().int().nonnegative(),
2566
2962
  /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
2567
- cumulativeCapKobo: import_zod9.z.number().int().nonnegative().optional(),
2568
- issuerSig: HexString2(64)
2963
+ cumulativeCapKobo: import_zod10.z.number().int().nonnegative().optional(),
2964
+ /** ASN.1 DER ECDSA P-256 signature, base64. */
2965
+ issuerSig: import_zod10.z.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2569
2966
  }).refine((v) => v.validUntilMs > v.validFromMs, {
2570
2967
  message: "validUntilMs must be greater than validFromMs"
2571
2968
  });
@@ -2598,19 +2995,20 @@ function buildPass(input) {
2598
2995
  return out;
2599
2996
  }
2600
2997
  function signPass(unsigned, issuerPrivateKey) {
2601
- const issuerSig = bytesToHex(
2602
- sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
2998
+ const issuerSig = signIssuerP256(
2999
+ canonicalJSONBytes(unsigned),
3000
+ issuerPrivateKey
2603
3001
  );
2604
3002
  return { ...unsigned, issuerSig };
2605
3003
  }
2606
- function verifyPass(pass, issuerPublicKey) {
3004
+ function verifyPass(pass, issuerPublicKeySpkiB64) {
2607
3005
  try {
2608
3006
  const parsed = PassSchema.parse(pass);
2609
3007
  const { issuerSig, ...unsigned } = parsed;
2610
- return verify(
3008
+ return verifyIssuerP256(
2611
3009
  canonicalJSONBytes(unsigned),
2612
- hexToBytes(issuerSig),
2613
- issuerPublicKey
3010
+ issuerSig,
3011
+ issuerPublicKeySpkiB64
2614
3012
  );
2615
3013
  } catch {
2616
3014
  return false;
@@ -2621,19 +3019,20 @@ function isPassWithinValidity(pass, nowMs) {
2621
3019
  }
2622
3020
 
2623
3021
  // src/passes/redemption.ts
2624
- var import_zod10 = require("zod");
2625
- var HexSig2 = import_zod10.z.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
2626
- var RedemptionSchema = import_zod10.z.object({
3022
+ var import_zod11 = require("zod");
3023
+ var Base64Std3 = import_zod11.z.string().min(16).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (std)");
3024
+ var RedemptionSchema = import_zod11.z.object({
2627
3025
  pass: PassSchema,
2628
- redeemerId: import_zod10.z.string().min(1),
2629
- redeemedAtMs: import_zod10.z.number().int().nonnegative(),
3026
+ redeemerId: import_zod11.z.string().min(1),
3027
+ redeemedAtMs: import_zod11.z.number().int().nonnegative(),
2630
3028
  /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
2631
3029
  * and > the redeemer's lastSeenCounter for this pass. */
2632
- counter: import_zod10.z.number().int().positive(),
3030
+ counter: import_zod11.z.number().int().positive(),
2633
3031
  /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
2634
- amountKobo: import_zod10.z.number().int().nonnegative(),
2635
- nonce: import_zod10.z.string().min(1),
2636
- holderSig: HexSig2
3032
+ amountKobo: import_zod11.z.number().int().nonnegative(),
3033
+ nonce: import_zod11.z.string().min(1),
3034
+ /** ASN.1 DER ECDSA P-256 signature over canonicalJSONBytes(unsigned), base64. */
3035
+ holderSig: Base64Std3
2637
3036
  });
2638
3037
  var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
2639
3038
  function buildRedemption(input) {
@@ -2687,74 +3086,68 @@ function buildRedemption(input) {
2687
3086
  };
2688
3087
  }
2689
3088
  function signRedemption(unsigned, holderDevicePrivateKey) {
2690
- const holderSig = bytesToHex(
2691
- sign(canonicalJSONBytes(unsigned), holderDevicePrivateKey)
3089
+ const holderSig = signIssuerP256(
3090
+ canonicalJSONBytes(unsigned),
3091
+ holderDevicePrivateKey
2692
3092
  );
2693
3093
  return { ...unsigned, holderSig };
2694
3094
  }
2695
- function verifyRedemption(r, issuerPublicKey) {
3095
+ function verifyRedemption(r, issuerPublicKeySpkiB64) {
2696
3096
  try {
2697
3097
  const parsed = RedemptionSchema.parse(r);
2698
3098
  if (parsed.counter <= parsed.pass.counterSeed) return false;
2699
3099
  const { issuerSig, ...passUnsigned } = parsed.pass;
2700
- if (!verify(
3100
+ if (!verifyIssuerP256(
2701
3101
  canonicalJSONBytes(passUnsigned),
2702
- hexToBytes(issuerSig),
2703
- issuerPublicKey
3102
+ issuerSig,
3103
+ issuerPublicKeySpkiB64
2704
3104
  )) {
2705
3105
  return false;
2706
3106
  }
2707
- const holderHex = parsed.pass.holderDevicePubkey;
2708
- if (typeof holderHex !== "string") return false;
3107
+ const holderPub = parsed.pass.holderDevicePubkey;
3108
+ if (typeof holderPub !== "string") return false;
2709
3109
  const { holderSig, ...unsigned } = parsed;
2710
- return verify(
2711
- canonicalJSONBytes(unsigned),
2712
- hexToBytes(holderSig),
2713
- hexToBytes(holderHex)
2714
- );
3110
+ return verifyIssuerP256(canonicalJSONBytes(unsigned), holderSig, holderPub);
2715
3111
  } catch {
2716
3112
  return false;
2717
3113
  }
2718
3114
  }
2719
3115
 
2720
3116
  // src/receipts/receipt.ts
2721
- var import_zod11 = require("zod");
3117
+ var import_zod12 = require("zod");
2722
3118
  var RECEIPT_CHANNELS = ["cash", "pass"];
2723
3119
  var RECEIPT_KINDS = RECEIPT_CHANNELS;
2724
- var HexString3 = (length) => import_zod11.z.string().regex(
2725
- new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
2726
- `expected ${length}-byte hex string`
2727
- );
2728
- var ReceiptPayloadSchema = import_zod11.z.record(
2729
- import_zod11.z.union([import_zod11.z.string(), import_zod11.z.number(), import_zod11.z.boolean(), import_zod11.z.null()])
3120
+ var ReceiptPayloadSchema = import_zod12.z.record(
3121
+ import_zod12.z.union([import_zod12.z.string(), import_zod12.z.number(), import_zod12.z.boolean(), import_zod12.z.null()])
2730
3122
  );
2731
- var ReceiptSchema = import_zod11.z.object({
2732
- receiptId: import_zod11.z.string().min(1),
2733
- channel: import_zod11.z.enum(RECEIPT_CHANNELS),
3123
+ var ReceiptSchema = import_zod12.z.object({
3124
+ receiptId: import_zod12.z.string().min(1),
3125
+ channel: import_zod12.z.enum(RECEIPT_CHANNELS),
2734
3126
  /** Cash-channel: send_intents.id. Required when channel === 'cash'. */
2735
- intentId: import_zod11.z.string().min(1).optional(),
3127
+ intentId: import_zod12.z.string().min(1).optional(),
2736
3128
  /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
2737
- passRedemptionId: import_zod11.z.string().min(1).optional(),
2738
- payerUserId: import_zod11.z.string().min(1),
2739
- payeeUserId: import_zod11.z.string().min(1),
2740
- amountKobo: import_zod11.z.number().int().nonnegative(),
2741
- currency: import_zod11.z.string().min(3).max(8),
2742
- issuedAtMs: import_zod11.z.number().int().nonnegative(),
2743
- issuerId: import_zod11.z.string().min(1),
3129
+ passRedemptionId: import_zod12.z.string().min(1).optional(),
3130
+ payerUserId: import_zod12.z.string().min(1),
3131
+ payeeUserId: import_zod12.z.string().min(1),
3132
+ amountKobo: import_zod12.z.number().int().nonnegative(),
3133
+ currency: import_zod12.z.string().min(3).max(8),
3134
+ issuedAtMs: import_zod12.z.number().int().nonnegative(),
3135
+ issuerId: import_zod12.z.string().min(1),
2744
3136
  payload: ReceiptPayloadSchema,
2745
- issuerSig: HexString3(64)
3137
+ /** ASN.1 DER ECDSA P-256 signature, base64. */
3138
+ issuerSig: import_zod12.z.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2746
3139
  }).superRefine((v, ctx) => {
2747
3140
  if (v.channel === "cash") {
2748
3141
  if (!v.intentId) {
2749
3142
  ctx.addIssue({
2750
- code: import_zod11.z.ZodIssueCode.custom,
3143
+ code: import_zod12.z.ZodIssueCode.custom,
2751
3144
  message: "cash receipts require intentId",
2752
3145
  path: ["intentId"]
2753
3146
  });
2754
3147
  }
2755
3148
  if (v.passRedemptionId) {
2756
3149
  ctx.addIssue({
2757
- code: import_zod11.z.ZodIssueCode.custom,
3150
+ code: import_zod12.z.ZodIssueCode.custom,
2758
3151
  message: "cash receipts must not carry passRedemptionId",
2759
3152
  path: ["passRedemptionId"]
2760
3153
  });
@@ -2762,14 +3155,14 @@ var ReceiptSchema = import_zod11.z.object({
2762
3155
  } else if (v.channel === "pass") {
2763
3156
  if (!v.passRedemptionId) {
2764
3157
  ctx.addIssue({
2765
- code: import_zod11.z.ZodIssueCode.custom,
3158
+ code: import_zod12.z.ZodIssueCode.custom,
2766
3159
  message: "pass receipts require passRedemptionId",
2767
3160
  path: ["passRedemptionId"]
2768
3161
  });
2769
3162
  }
2770
3163
  if (v.intentId) {
2771
3164
  ctx.addIssue({
2772
- code: import_zod11.z.ZodIssueCode.custom,
3165
+ code: import_zod12.z.ZodIssueCode.custom,
2773
3166
  message: "pass receipts must not carry intentId",
2774
3167
  path: ["intentId"]
2775
3168
  });
@@ -2808,19 +3201,20 @@ function buildReceipt(input) {
2808
3201
  return out;
2809
3202
  }
2810
3203
  function signReceipt(unsigned, issuerPrivateKey) {
2811
- const issuerSig = bytesToHex(
2812
- sign(canonicalJSONBytes(unsigned), issuerPrivateKey)
3204
+ const issuerSig = signIssuerP256(
3205
+ canonicalJSONBytes(unsigned),
3206
+ issuerPrivateKey
2813
3207
  );
2814
3208
  return { ...unsigned, issuerSig };
2815
3209
  }
2816
- function verifyReceipt(r, issuerPublicKey) {
3210
+ function verifyReceipt(r, issuerPublicKeySpkiB64) {
2817
3211
  try {
2818
3212
  const parsed = ReceiptSchema.parse(r);
2819
3213
  const { issuerSig, ...unsigned } = parsed;
2820
- return verify(
3214
+ return verifyIssuerP256(
2821
3215
  canonicalJSONBytes(unsigned),
2822
- hexToBytes(issuerSig),
2823
- issuerPublicKey
3216
+ issuerSig,
3217
+ issuerPublicKeySpkiB64
2824
3218
  );
2825
3219
  } catch {
2826
3220
  return false;
@@ -3070,23 +3464,23 @@ function init(opts) {
3070
3464
  }
3071
3465
 
3072
3466
  // src/accounts/client.ts
3073
- var import_zod12 = require("zod");
3467
+ var import_zod13 = require("zod");
3074
3468
  var ACCOUNT_TYPES = ["personal", "business", "partner"];
3075
3469
  var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
3076
3470
  var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
3077
- var AccountSchema = import_zod12.z.object({
3078
- accountId: import_zod12.z.string().uuid(),
3079
- type: import_zod12.z.enum(ACCOUNT_TYPES),
3080
- displayName: import_zod12.z.string().min(1),
3081
- status: import_zod12.z.enum(ACCOUNT_STATUSES),
3082
- ownerUserId: import_zod12.z.string().uuid().nullable(),
3083
- createdAtMs: import_zod12.z.number().int().nonnegative()
3471
+ var AccountSchema = import_zod13.z.object({
3472
+ accountId: import_zod13.z.string().uuid(),
3473
+ type: import_zod13.z.enum(ACCOUNT_TYPES),
3474
+ displayName: import_zod13.z.string().min(1),
3475
+ status: import_zod13.z.enum(ACCOUNT_STATUSES),
3476
+ ownerUserId: import_zod13.z.string().uuid().nullable(),
3477
+ createdAtMs: import_zod13.z.number().int().nonnegative()
3084
3478
  });
3085
- var AccountMembershipSchema = import_zod12.z.object({
3086
- accountId: import_zod12.z.string().uuid(),
3087
- userId: import_zod12.z.string().uuid(),
3088
- role: import_zod12.z.enum(MEMBERSHIP_ROLES),
3089
- createdAtMs: import_zod12.z.number().int().nonnegative()
3479
+ var AccountMembershipSchema = import_zod13.z.object({
3480
+ accountId: import_zod13.z.string().uuid(),
3481
+ userId: import_zod13.z.string().uuid(),
3482
+ role: import_zod13.z.enum(MEMBERSHIP_ROLES),
3483
+ createdAtMs: import_zod13.z.number().int().nonnegative()
3090
3484
  });
3091
3485
  function createAccountsClient(opts) {
3092
3486
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -3119,9 +3513,9 @@ function createAccountsClient(opts) {
3119
3513
  }
3120
3514
  return parser(raw);
3121
3515
  }
3122
- const itemsSchema = import_zod12.z.object({ items: import_zod12.z.array(AccountSchema) });
3123
- const memberItemsSchema = import_zod12.z.object({
3124
- items: import_zod12.z.array(AccountMembershipSchema)
3516
+ const itemsSchema = import_zod13.z.object({ items: import_zod13.z.array(AccountSchema) });
3517
+ const memberItemsSchema = import_zod13.z.object({
3518
+ items: import_zod13.z.array(AccountMembershipSchema)
3125
3519
  });
3126
3520
  return {
3127
3521
  listMyAccounts: () => call(
@@ -3152,345 +3546,8 @@ function createAccountsClient(opts) {
3152
3546
  };
3153
3547
  }
3154
3548
 
3155
- // src/me-offline/client.ts
3156
- var import_zod13 = require("zod");
3157
- var Hex64 = import_zod13.z.string().regex(/^[0-9a-f]{64}$/i);
3158
- var HexAny = import_zod13.z.string().regex(/^[0-9a-f]+$/i);
3159
- var Sha256Hex = import_zod13.z.string().regex(/^[0-9a-f]{64}$/i);
3160
- var Base64Std = import_zod13.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3161
- var RegisterDeviceKeyInputSchema = import_zod13.z.object({
3162
- deviceId: import_zod13.z.string().min(1).max(128),
3163
- publicKeyHex: Hex64
3164
- });
3165
- var AttestationSecurityLevelSchema = import_zod13.z.enum([
3166
- "STRONGBOX",
3167
- "TEE",
3168
- "SECURE_ENCLAVE",
3169
- "SOFTWARE"
3170
- ]);
3171
- var DeviceKeyAlgSchema = import_zod13.z.enum(["ed25519", "p256"]);
3172
- var RegisterDeviceKeyP256InputSchema = import_zod13.z.object({
3173
- deviceId: import_zod13.z.string().min(1).max(128),
3174
- /** P-256 SubjectPublicKeyInfo DER, base64. */
3175
- publicKeySpkiB64: Base64Std.min(64).max(4096),
3176
- /** Base64 of the server-issued enrollment challenge string. */
3177
- challengeB64: Base64Std.min(8).max(1024),
3178
- /** iOS App Attest payload or Android X.509 Key Attestation chain. */
3179
- attestationChainB64: import_zod13.z.array(Base64Std.min(16).max(16384)).min(1).max(16),
3180
- securityLevel: AttestationSecurityLevelSchema
3181
- });
3182
- var P256EnrollmentChallengeInputSchema = import_zod13.z.object({
3183
- deviceId: import_zod13.z.string().min(1).max(128)
3184
- });
3185
- var P256EnrollmentChallengeResultSchema = import_zod13.z.object({
3186
- challenge: import_zod13.z.string().min(16),
3187
- expiresAtMs: import_zod13.z.number().int().positive()
3188
- });
3189
- var DeviceKeyRecordSchema = import_zod13.z.object({
3190
- id: import_zod13.z.string().uuid(),
3191
- userId: import_zod13.z.string().uuid(),
3192
- deviceId: import_zod13.z.string(),
3193
- alg: DeviceKeyAlgSchema.default("ed25519"),
3194
- publicKeyHex: Hex64.nullable().default(null),
3195
- publicKeySpkiB64: Base64Std.nullable().default(null),
3196
- securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
3197
- hardwareBacked: import_zod13.z.boolean().default(false),
3198
- attestedAtMs: import_zod13.z.number().int().nonnegative().nullable().default(null),
3199
- createdAtMs: import_zod13.z.number().int().nonnegative(),
3200
- revokedAtMs: import_zod13.z.number().int().nonnegative().nullable()
3201
- });
3202
- var ConsumerOACSchema = import_zod13.z.object({
3203
- oacId: import_zod13.z.string().uuid(),
3204
- issuerId: import_zod13.z.string().min(1).max(64),
3205
- userId: import_zod13.z.string().uuid(),
3206
- deviceId: import_zod13.z.string().min(1).max(128),
3207
- alg: import_zod13.z.enum(["ed25519", "p256"]).optional(),
3208
- devicePubkeyHex: Hex64.optional(),
3209
- devicePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),
3210
- perTxCapKobo: import_zod13.z.number().int().positive(),
3211
- cumulativeCapKobo: import_zod13.z.number().int().positive(),
3212
- currency: import_zod13.z.string().length(3),
3213
- validFromMs: import_zod13.z.number().int().nonnegative(),
3214
- validUntilMs: import_zod13.z.number().int().nonnegative(),
3215
- counterSeed: import_zod13.z.number().int().nonnegative(),
3216
- issuedAtMs: import_zod13.z.number().int().nonnegative()
3217
- }).refine(
3218
- (o) => {
3219
- const alg = o.alg ?? "ed25519";
3220
- if (alg === "ed25519") {
3221
- return Boolean(o.devicePubkeyHex) && !o.devicePubkeySpkiB64;
3222
- }
3223
- return Boolean(o.devicePubkeySpkiB64) && !o.devicePubkeyHex;
3224
- },
3225
- { message: "OAC device pubkey shape must match alg" }
3226
- );
3227
- var SignedConsumerOACSchema = import_zod13.z.object({
3228
- oac: ConsumerOACSchema,
3229
- issuerSig: HexAny,
3230
- issuerPublicKeyHex: Hex64
3231
- });
3232
- var OACRecordSchema = SignedConsumerOACSchema.extend({
3233
- currentOfflineSpentKobo: import_zod13.z.number().int().nonnegative(),
3234
- status: import_zod13.z.enum([
3235
- "active",
3236
- "superseded",
3237
- "expired",
3238
- "revoked",
3239
- "disabling",
3240
- "draining",
3241
- "closed"
3242
- ]),
3243
- supersededAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3244
- revokedAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3245
- holdId: import_zod13.z.string().uuid().nullable().optional()
3246
- });
3247
- var IssueOACInputSchema = import_zod13.z.object({
3248
- deviceId: import_zod13.z.string().min(1).max(128),
3249
- perTxCapKobo: import_zod13.z.number().int().positive().optional(),
3250
- cumulativeCapKobo: import_zod13.z.number().int().positive().optional(),
3251
- ttlMs: import_zod13.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
3252
- spendableOnlineKobo: import_zod13.z.number().int().nonnegative().optional()
3253
- });
3254
- var EnableOfflineInputSchema = import_zod13.z.object({
3255
- deviceId: import_zod13.z.string().min(1).max(128),
3256
- amountKobo: import_zod13.z.number().int().positive(),
3257
- perTxCapKobo: import_zod13.z.number().int().positive().optional(),
3258
- ttlMs: import_zod13.z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
3259
- installId: import_zod13.z.string().min(1).max(128),
3260
- partnerId: import_zod13.z.string().min(1).max(64).optional()
3261
- });
3262
- var ProvisionOfflineAllowanceInputSchema = EnableOfflineInputSchema;
3263
- var DisableOfflineInputSchema = import_zod13.z.object({
3264
- deviceId: import_zod13.z.string().min(1).max(128),
3265
- installId: import_zod13.z.string().min(1).max(128).optional(),
3266
- claims: import_zod13.z.array(import_zod13.z.unknown()).max(256).optional()
3267
- });
3268
- var OfflineHoldRecordSchema = import_zod13.z.object({
3269
- holdId: import_zod13.z.string().uuid(),
3270
- userId: import_zod13.z.string().uuid(),
3271
- deviceId: import_zod13.z.string(),
3272
- partnerId: import_zod13.z.string(),
3273
- adapterKind: import_zod13.z.string(),
3274
- externalHoldRef: import_zod13.z.string().nullable(),
3275
- amountKobo: import_zod13.z.number().int().nonnegative(),
3276
- capturedKobo: import_zod13.z.number().int().nonnegative(),
3277
- releasedKobo: import_zod13.z.number().int().nonnegative(),
3278
- remainingKobo: import_zod13.z.number().int().nonnegative(),
3279
- currency: import_zod13.z.string().length(3),
3280
- status: import_zod13.z.enum([
3281
- "placing",
3282
- "active",
3283
- "disabling",
3284
- "draining",
3285
- "closed",
3286
- "revoked",
3287
- "failed"
3288
- ]),
3289
- installId: import_zod13.z.string().nullable(),
3290
- drainDeadlineMs: import_zod13.z.number().int().nonnegative(),
3291
- disableRequestedAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3292
- createdAtMs: import_zod13.z.number().int().nonnegative(),
3293
- closedAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3294
- isTrusted: import_zod13.z.boolean().optional()
3295
- });
3296
- var EnableOfflineResultSchema = import_zod13.z.object({
3297
- hold: OfflineHoldRecordSchema,
3298
- oac: OACRecordSchema
3299
- });
3300
- var ProvisionOfflineAllowanceResultSchema = EnableOfflineResultSchema;
3301
- var DisableOfflineResultSchema = import_zod13.z.object({
3302
- hold: OfflineHoldRecordSchema,
3303
- trusted: import_zod13.z.boolean(),
3304
- settledClaims: import_zod13.z.number().int().nonnegative()
3305
- });
3306
- var OfflineStatusResultSchema = import_zod13.z.object({
3307
- hold: OfflineHoldRecordSchema.nullable(),
3308
- active: OACRecordSchema.nullable()
3309
- });
3310
- var OfflineStateResultSchema = import_zod13.z.object({
3311
- active: OACRecordSchema.nullable()
3312
- });
3313
- var ClaimAlgSchema = import_zod13.z.enum(["ed25519", "p256"]);
3314
- var ConsumerPaymentClaimSchema = import_zod13.z.object({
3315
- /** Algorithm discriminator. Omit / 'ed25519' for V1 clients. */
3316
- alg: ClaimAlgSchema.optional(),
3317
- oacId: import_zod13.z.string().uuid(),
3318
- encounterId: Sha256Hex.optional(),
3319
- payerUserId: import_zod13.z.string().uuid(),
3320
- payeeUserId: import_zod13.z.string().uuid(),
3321
- payerDeviceId: import_zod13.z.string().min(1).max(128),
3322
- payerNonce: import_zod13.z.string().min(8).max(128),
3323
- payeeNonce: import_zod13.z.string().min(8).max(128),
3324
- amountKobo: import_zod13.z.number().int().positive(),
3325
- currency: import_zod13.z.string().length(3).default("NGN"),
3326
- occurredAtMs: import_zod13.z.number().int().nonnegative(),
3327
- completedAtMs: import_zod13.z.number().int().nonnegative().optional(),
3328
- contextId: import_zod13.z.string().max(128).optional(),
3329
- // ed25519 path
3330
- payerPubkeyHex: Hex64.optional(),
3331
- payerSignature: HexAny.optional(),
3332
- payeePubkeyHex: Hex64.optional(),
3333
- payeeSignature: HexAny.optional(),
3334
- // p256 path
3335
- payerPubkeySpkiB64: import_zod13.z.string().min(64).max(4096).optional(),
3336
- payerSignatureDerB64: import_zod13.z.string().min(16).max(2048).optional(),
3337
- payeePubkeySpkiB64: import_zod13.z.string().min(64).max(4096).optional(),
3338
- payeeSignatureDerB64: import_zod13.z.string().min(16).max(2048).optional()
3339
- }).refine(
3340
- (c) => {
3341
- const alg = c.alg ?? "ed25519";
3342
- if (alg === "ed25519") {
3343
- return Boolean(c.payerPubkeyHex) && Boolean(c.payerSignature);
3344
- }
3345
- return Boolean(c.payerPubkeySpkiB64) && Boolean(c.payerSignatureDerB64);
3346
- },
3347
- {
3348
- message: "payer key/signature fields must match alg (ed25519: hex; p256: SPKI+DER b64)"
3349
- }
3350
- );
3351
- var ConsumerSettlementSchema = import_zod13.z.object({
3352
- settlementId: import_zod13.z.string().uuid(),
3353
- settlementKey: Sha256Hex,
3354
- encounterId: Sha256Hex,
3355
- oacId: import_zod13.z.string().uuid(),
3356
- payerUserId: import_zod13.z.string().uuid(),
3357
- payeeUserId: import_zod13.z.string().uuid(),
3358
- amountKobo: import_zod13.z.number().int().positive(),
3359
- currency: import_zod13.z.string().length(3),
3360
- status: import_zod13.z.enum(["SETTLED", "REVIEW"]),
3361
- reviewReason: import_zod13.z.string().nullable(),
3362
- ledgerRef: import_zod13.z.string().nullable(),
3363
- issuerSig: HexAny,
3364
- createdAtMs: import_zod13.z.number().int().nonnegative()
3365
- });
3366
- var ConsumerSettleResultSchema = import_zod13.z.object({
3367
- settlement: ConsumerSettlementSchema,
3368
- encounterId: Sha256Hex,
3369
- replayed: import_zod13.z.boolean()
3370
- });
3371
- var RevokeDeviceKeyInputSchema = import_zod13.z.object({
3372
- deviceId: import_zod13.z.string().min(1).max(128),
3373
- /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
3374
- sendAuthToken: import_zod13.z.string().min(16)
3375
- });
3376
- function createMeOfflineClient(opts) {
3377
- const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3378
- if (!fetchImpl) {
3379
- throw new Error("createMeOfflineClient: no fetch implementation available");
3380
- }
3381
- const baseUrl = opts.baseUrl.replace(/\/$/, "");
3382
- async function call(method, path, body, parser) {
3383
- const init2 = {
3384
- method,
3385
- headers: {
3386
- "content-type": "application/json",
3387
- accept: "application/json"
3388
- }
3389
- };
3390
- if (body !== void 0) init2.body = JSON.stringify(body);
3391
- const resp = await fetchImpl(`${baseUrl}${path}`, init2);
3392
- const text = await resp.text();
3393
- let raw = void 0;
3394
- if (text) {
3395
- try {
3396
- raw = JSON.parse(text);
3397
- } catch {
3398
- }
3399
- }
3400
- if (!resp.ok) {
3401
- const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3402
- const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3403
- throw new FlurApiError(resp.status, code, message, raw);
3404
- }
3405
- return parser(raw);
3406
- }
3407
- const deviceKeyItems = import_zod13.z.object({ items: import_zod13.z.array(DeviceKeyRecordSchema) });
3408
- return {
3409
- registerDeviceKey: (input) => call(
3410
- "POST",
3411
- "/v1/me/offline/keys",
3412
- RegisterDeviceKeyInputSchema.parse(input),
3413
- (raw) => DeviceKeyRecordSchema.parse(raw)
3414
- ),
3415
- issueP256EnrollmentChallenge: (input) => call(
3416
- "POST",
3417
- "/v1/me/offline/keys/p256/challenge",
3418
- P256EnrollmentChallengeInputSchema.parse(input),
3419
- (raw) => P256EnrollmentChallengeResultSchema.parse(raw)
3420
- ),
3421
- registerDeviceKeyP256: (input) => call(
3422
- "POST",
3423
- "/v1/me/offline/keys/p256",
3424
- RegisterDeviceKeyP256InputSchema.parse(input),
3425
- (raw) => DeviceKeyRecordSchema.parse(raw)
3426
- ),
3427
- listDeviceKeys: () => call(
3428
- "GET",
3429
- "/v1/me/offline/keys",
3430
- void 0,
3431
- (raw) => deviceKeyItems.parse(raw)
3432
- ),
3433
- revokeDeviceKey: (input) => call(
3434
- "POST",
3435
- "/v1/me/offline/keys/revoke",
3436
- RevokeDeviceKeyInputSchema.parse(input),
3437
- () => void 0
3438
- ),
3439
- provisionAllowance: (input) => call(
3440
- "POST",
3441
- "/v1/me/offline/allowance",
3442
- ProvisionOfflineAllowanceInputSchema.parse(input),
3443
- (raw) => ProvisionOfflineAllowanceResultSchema.parse(raw)
3444
- ),
3445
- enable: (input) => call(
3446
- "POST",
3447
- "/v1/me/offline/enable",
3448
- EnableOfflineInputSchema.parse(input),
3449
- (raw) => EnableOfflineResultSchema.parse(raw)
3450
- ),
3451
- refresh: (input) => call(
3452
- "POST",
3453
- "/v1/me/offline/refresh",
3454
- IssueOACInputSchema.parse(input),
3455
- (raw) => OACRecordSchema.parse(raw)
3456
- ),
3457
- disable: (input) => call(
3458
- "POST",
3459
- "/v1/me/offline/disable",
3460
- DisableOfflineInputSchema.parse(input),
3461
- (raw) => DisableOfflineResultSchema.parse(raw)
3462
- ),
3463
- getStatus: (deviceId) => {
3464
- const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3465
- return call(
3466
- "GET",
3467
- `/v1/me/offline/status${qs}`,
3468
- void 0,
3469
- (raw) => OfflineStatusResultSchema.parse(raw)
3470
- );
3471
- },
3472
- getState: (deviceId) => {
3473
- const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3474
- return call(
3475
- "GET",
3476
- `/v1/me/offline/state${qs}`,
3477
- void 0,
3478
- (raw) => OfflineStateResultSchema.parse(raw)
3479
- );
3480
- },
3481
- submitClaim: (claim) => call(
3482
- "POST",
3483
- "/v1/me/offline/claims",
3484
- ConsumerPaymentClaimSchema.parse(claim),
3485
- (raw) => ConsumerSettleResultSchema.parse(raw)
3486
- )
3487
- };
3488
- }
3489
-
3490
3549
  // src/me-offline/signer.ts
3491
- var import_ed255198 = require("@noble/curves/ed25519");
3492
- var import_nist = require("@noble/curves/nist");
3493
- var import_utils3 = require("@noble/hashes/utils");
3550
+ var import_nist2 = require("@noble/curves/nist");
3494
3551
  var CLAIM_DOMAIN_V2 = "flur:consumer-offline:v2:claim";
3495
3552
  function canonicalClaimSigningPayload(claim) {
3496
3553
  return {
@@ -3512,7 +3569,7 @@ function canonicalClaimSigningPayload(claim) {
3512
3569
  function canonicalClaimSigningBytes(claim) {
3513
3570
  return canonicalJSONBytes(canonicalClaimSigningPayload(claim));
3514
3571
  }
3515
- function bytesToBase64(bytes) {
3572
+ function bytesToBase642(bytes) {
3516
3573
  if (typeof Buffer !== "undefined") {
3517
3574
  return Buffer.from(bytes).toString("base64");
3518
3575
  }
@@ -3520,7 +3577,7 @@ function bytesToBase64(bytes) {
3520
3577
  for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
3521
3578
  return btoa(bin);
3522
3579
  }
3523
- function base64ToBytes(b64) {
3580
+ function base64ToBytes2(b64) {
3524
3581
  if (typeof Buffer !== "undefined") {
3525
3582
  return new Uint8Array(Buffer.from(b64, "base64"));
3526
3583
  }
@@ -3529,7 +3586,7 @@ function base64ToBytes(b64) {
3529
3586
  for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
3530
3587
  return out;
3531
3588
  }
3532
- var P256_SPKI_HEADER = new Uint8Array([
3589
+ var P256_SPKI_HEADER2 = new Uint8Array([
3533
3590
  48,
3534
3591
  89,
3535
3592
  48,
@@ -3561,38 +3618,25 @@ function p256PublicKeyToSpkiB64(rawUncompressed) {
3561
3618
  if (rawUncompressed.length !== 65 || rawUncompressed[0] !== 4) {
3562
3619
  throw new Error("p256: expected 65-byte uncompressed point");
3563
3620
  }
3564
- const out = new Uint8Array(P256_SPKI_HEADER.length + rawUncompressed.length);
3565
- out.set(P256_SPKI_HEADER, 0);
3566
- out.set(rawUncompressed, P256_SPKI_HEADER.length);
3567
- return bytesToBase64(out);
3621
+ const out = new Uint8Array(P256_SPKI_HEADER2.length + rawUncompressed.length);
3622
+ out.set(P256_SPKI_HEADER2, 0);
3623
+ out.set(rawUncompressed, P256_SPKI_HEADER2.length);
3624
+ return bytesToBase642(out);
3568
3625
  }
3569
3626
  function p256SpkiB64ToPublicKey(spkiB64) {
3570
- const spki = base64ToBytes(spkiB64);
3571
- if (spki.length !== P256_SPKI_HEADER.length + 65) {
3627
+ const spki = base64ToBytes2(spkiB64);
3628
+ if (spki.length !== P256_SPKI_HEADER2.length + 65) {
3572
3629
  throw new Error("p256: invalid SPKI length");
3573
3630
  }
3574
- for (let i = 0; i < P256_SPKI_HEADER.length; i++) {
3575
- if (spki[i] !== P256_SPKI_HEADER[i]) {
3631
+ for (let i = 0; i < P256_SPKI_HEADER2.length; i++) {
3632
+ if (spki[i] !== P256_SPKI_HEADER2[i]) {
3576
3633
  throw new Error("p256: invalid SPKI header");
3577
3634
  }
3578
3635
  }
3579
- return spki.slice(P256_SPKI_HEADER.length);
3580
- }
3581
- function createSoftwareEd25519Signer(privateKey) {
3582
- const pub = import_ed255198.ed25519.getPublicKey(privateKey);
3583
- return {
3584
- alg: "ed25519",
3585
- async getPublicKey() {
3586
- return { alg: "ed25519", publicKey: (0, import_utils3.bytesToHex)(pub) };
3587
- },
3588
- async sign(bytes) {
3589
- const sig = import_ed255198.ed25519.sign(bytes, privateKey);
3590
- return { alg: "ed25519", signature: (0, import_utils3.bytesToHex)(sig) };
3591
- }
3592
- };
3636
+ return spki.slice(P256_SPKI_HEADER2.length);
3593
3637
  }
3594
3638
  function createSoftwareP256Signer(privateKey) {
3595
- const raw = import_nist.p256.getPublicKey(privateKey, false);
3639
+ const raw = import_nist2.p256.getPublicKey(privateKey, false);
3596
3640
  const spkiB64 = p256PublicKeyToSpkiB64(raw);
3597
3641
  return {
3598
3642
  alg: "p256",
@@ -3600,35 +3644,87 @@ function createSoftwareP256Signer(privateKey) {
3600
3644
  return { alg: "p256", publicKey: spkiB64 };
3601
3645
  },
3602
3646
  async sign(bytes) {
3603
- const sig = import_nist.p256.sign(bytes, privateKey, { prehash: true });
3647
+ const sig = import_nist2.p256.sign(bytes, privateKey, { prehash: true });
3604
3648
  const der = sig.toBytes("der");
3605
- return { alg: "p256", signature: bytesToBase64(der) };
3649
+ return { alg: "p256", signature: bytesToBase642(der) };
3606
3650
  }
3607
3651
  };
3608
3652
  }
3609
3653
  function verifyClaimSignature(input) {
3610
3654
  try {
3611
- if (input.alg === "ed25519") {
3612
- return import_ed255198.ed25519.verify(
3613
- (0, import_utils3.hexToBytes)(input.signature),
3614
- input.bytes,
3615
- (0, import_utils3.hexToBytes)(input.publicKey)
3616
- );
3617
- }
3618
- if (input.alg === "p256") {
3619
- const sigDer = base64ToBytes(input.signature);
3620
- const pub = p256SpkiB64ToPublicKey(input.publicKey);
3621
- return import_nist.p256.verify(sigDer, input.bytes, pub, {
3622
- prehash: true,
3623
- format: "der"
3624
- });
3625
- }
3626
- return false;
3655
+ if (input.alg !== "p256") return false;
3656
+ const sigDer = base64ToBytes2(input.signature);
3657
+ const pub = p256SpkiB64ToPublicKey(input.publicKey);
3658
+ return import_nist2.p256.verify(sigDer, input.bytes, pub, {
3659
+ prehash: true,
3660
+ format: "der"
3661
+ });
3627
3662
  } catch {
3628
3663
  return false;
3629
3664
  }
3630
3665
  }
3631
3666
 
3667
+ // src/me-offline/sms.ts
3668
+ var OFFLINE_CLAIM_SMS_PREFIX = "FLURC1.";
3669
+ var TOKEN_RE = /(?:^|\s)(FLURC1\.[A-Za-z0-9_-]+={0,2})(?:\s|$)/;
3670
+ function encodeOfflineClaimSmsMessage(claim) {
3671
+ const parsed = ConsumerPaymentClaimSchema.parse(claim);
3672
+ const json = JSON.stringify(parsed);
3673
+ return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf8(json)}`;
3674
+ }
3675
+ function decodeOfflineClaimSmsMessage(message) {
3676
+ const token = extractOfflineClaimSmsToken(message);
3677
+ if (!token) {
3678
+ throw new Error("offline claim SMS token not found");
3679
+ }
3680
+ const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);
3681
+ let raw;
3682
+ try {
3683
+ raw = JSON.parse(base64UrlDecodeUtf8(encoded));
3684
+ } catch {
3685
+ throw new Error("offline claim SMS token is malformed");
3686
+ }
3687
+ const parsed = ConsumerPaymentClaimSchema.safeParse(raw);
3688
+ if (!parsed.success) {
3689
+ throw new Error("offline claim SMS token is invalid");
3690
+ }
3691
+ return parsed.data;
3692
+ }
3693
+ function extractOfflineClaimSmsToken(message) {
3694
+ const trimmed = message.trim();
3695
+ if (trimmed.startsWith(OFFLINE_CLAIM_SMS_PREFIX)) {
3696
+ return trimmed.split(/\s+/, 1)[0] ?? null;
3697
+ }
3698
+ return TOKEN_RE.exec(message)?.[1] ?? null;
3699
+ }
3700
+ function base64UrlEncodeUtf8(input) {
3701
+ const bytes = new TextEncoder().encode(input);
3702
+ let binary = "";
3703
+ for (const byte of bytes) binary += String.fromCharCode(byte);
3704
+ const base64 = typeof btoa === "function" ? btoa(binary) : typeof Buffer !== "undefined" ? Buffer.from(bytes).toString("base64") : void 0;
3705
+ if (!base64) throw new Error("base64 encoder unavailable");
3706
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
3707
+ }
3708
+ function base64UrlDecodeUtf8(input) {
3709
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
3710
+ const padded = base64.padEnd(
3711
+ base64.length + (4 - base64.length % 4) % 4,
3712
+ "="
3713
+ );
3714
+ if (typeof atob === "function") {
3715
+ const binary = atob(padded);
3716
+ const bytes = new Uint8Array(binary.length);
3717
+ for (let index = 0; index < binary.length; index++) {
3718
+ bytes[index] = binary.charCodeAt(index);
3719
+ }
3720
+ return new TextDecoder().decode(bytes);
3721
+ }
3722
+ if (typeof Buffer !== "undefined") {
3723
+ return Buffer.from(padded, "base64").toString("utf8");
3724
+ }
3725
+ throw new Error("base64 decoder unavailable");
3726
+ }
3727
+
3632
3728
  // src/partner-funding/client.ts
3633
3729
  var import_zod14 = require("zod");
3634
3730
  var MinorString = import_zod14.z.string().regex(/^-?\d+$/);
@@ -4004,14 +4100,15 @@ function buildArtifactBody(input) {
4004
4100
  return { ...header, data: input.data };
4005
4101
  }
4006
4102
  function signArtifact(body, privateKey) {
4007
- const sig = bytesToHex(sign(canonicalJSONBytes(body), privateKey));
4103
+ const sig = signIssuerP256(canonicalJSONBytes(body), privateKey);
4008
4104
  return { body, sig };
4009
4105
  }
4010
4106
  function encodeArtifactUri(signed) {
4011
4107
  const bodyBytes = canonicalJSONBytes(signed.body);
4012
4108
  const bodyB64 = base64UrlEncode(bodyBytes);
4013
- const sigB64 = base64UrlEncode(hexToBytes(signed.sig));
4014
- return `${FLUR_ARTIFACT_URI_PREFIX}${signed.body.t}/${bodyB64}.${sigB64}`;
4109
+ const sigBytes = base64UrlDecode(signed.sig);
4110
+ const sigB64Url = base64UrlEncode(sigBytes);
4111
+ return `${FLUR_ARTIFACT_URI_PREFIX}${signed.body.t}/${bodyB64}.${sigB64Url}`;
4015
4112
  }
4016
4113
  function decodeArtifactUri(uri) {
4017
4114
  if (!uri.startsWith(FLUR_ARTIFACT_URI_PREFIX)) {
@@ -4042,9 +4139,9 @@ function decodeArtifactUri(uri) {
4042
4139
  }
4043
4140
  const bodyBytes = base64UrlDecode(payload.slice(0, dot));
4044
4141
  const sigBytes = base64UrlDecode(payload.slice(dot + 1));
4045
- if (sigBytes.length !== 64) {
4142
+ if (sigBytes.length < 64 || sigBytes.length > 80) {
4046
4143
  throw new FlurArtifactError(
4047
- `Signature must be 64 bytes, got ${sigBytes.length}`,
4144
+ `Signature length out of range: ${sigBytes.length}`,
4048
4145
  "INVALID_SIGNATURE"
4049
4146
  );
4050
4147
  }
@@ -4071,17 +4168,26 @@ function decodeArtifactUri(uri) {
4071
4168
  type,
4072
4169
  bodyBytes,
4073
4170
  body: bodyJson,
4074
- sig: bytesToHex(sigBytes)
4171
+ // Encode as standard base64 (not url-safe) for sig field consistency.
4172
+ sig: encodeStdBase64(sigBytes)
4075
4173
  };
4076
4174
  }
4077
- function verifyArtifactSignature(decoded, publicKey, options = {}) {
4175
+ function encodeStdBase64(bytes) {
4176
+ if (typeof Buffer !== "undefined") {
4177
+ return Buffer.from(bytes).toString("base64");
4178
+ }
4179
+ let bin = "";
4180
+ for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
4181
+ return typeof btoa === "function" ? btoa(bin) : "";
4182
+ }
4183
+ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
4078
4184
  if (options.enforceExpiry !== false && decoded.body.exp !== void 0) {
4079
4185
  const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
4080
4186
  if (decoded.body.exp < now) {
4081
4187
  throw new FlurArtifactError("Artifact has expired", "EXPIRED");
4082
4188
  }
4083
4189
  }
4084
- return verify(decoded.bodyBytes, hexToBytes(decoded.sig), publicKey);
4190
+ return verifyIssuerP256(decoded.bodyBytes, decoded.sig, publicKeySpkiB64);
4085
4191
  }
4086
4192
 
4087
4193
  // src/artifacts/types.ts
@@ -4100,7 +4206,7 @@ var ARTIFACT_TYPES = {
4100
4206
  PASS: "pass",
4101
4207
  IDENTITY: "identity"
4102
4208
  };
4103
- var HexString4 = (length) => import_zod16.z.string().regex(
4209
+ var HexString = (length) => import_zod16.z.string().regex(
4104
4210
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
4105
4211
  `expected ${length}-byte hex string`
4106
4212
  );
@@ -4118,7 +4224,7 @@ var ReceiptArtifactSchema = import_zod16.z.object({
4118
4224
  settledAtMs: import_zod16.z.number().int().positive(),
4119
4225
  ledgerTxnId: import_zod16.z.string().min(1).max(64).optional(),
4120
4226
  memo: import_zod16.z.string().max(140).optional(),
4121
- hashChainPrev: HexString4(32).optional()
4227
+ hashChainPrev: HexString(32).optional()
4122
4228
  });
4123
4229
  var ShortId = import_zod16.z.string().min(1).max(64);
4124
4230
  var PositiveInt = import_zod16.z.number().int().positive();
@@ -4200,7 +4306,7 @@ var StatementArtifactSchema = import_zod16.z.object({
4200
4306
  closingBalanceKobo: import_zod16.z.number().int(),
4201
4307
  transactionCount: NonNegativeInt,
4202
4308
  currency: Currency2,
4203
- hashChainPrev: HexString4(32).optional()
4309
+ hashChainPrev: HexString(32).optional()
4204
4310
  }).refine((v) => v.periodEndMs > v.periodStartMs, {
4205
4311
  message: "periodEndMs must be greater than periodStartMs",
4206
4312
  path: ["periodEndMs"]
@@ -4233,7 +4339,7 @@ var IdentityArtifactSchema = import_zod16.z.object({
4233
4339
  "kyc_tier",
4234
4340
  "age_band"
4235
4341
  ]),
4236
- claimValueHash: HexString4(32),
4342
+ claimValueHash: HexString(32),
4237
4343
  attestedAtMs: PositiveInt
4238
4344
  });
4239
4345
  var ARTIFACT_BODY_SCHEMAS = {
@@ -4297,7 +4403,7 @@ function createArtifactUri(input) {
4297
4403
  const signed = signArtifact(body, input.privateKey);
4298
4404
  return { uri: encodeArtifactUri(signed), signed };
4299
4405
  }
4300
- function verifyArtifactUri(uri, publicKey, options = {}) {
4406
+ function verifyArtifactUri(uri, publicKeySpkiB64, options = {}) {
4301
4407
  const decoded = decodeArtifactUri(uri);
4302
4408
  if (!isKnownArtifactType(decoded.type)) {
4303
4409
  throw new FlurArtifactError(
@@ -4319,7 +4425,7 @@ function verifyArtifactUri(uri, publicKey, options = {}) {
4319
4425
  "INVALID_BODY"
4320
4426
  );
4321
4427
  }
4322
- const ok = verifyArtifactSignature(decoded, publicKey, options);
4428
+ const ok = verifyArtifactSignature(decoded, publicKeySpkiB64, options);
4323
4429
  if (!ok) {
4324
4430
  throw new FlurArtifactError(
4325
4431
  "Artifact signature verification failed",
@@ -4396,6 +4502,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4396
4502
  HARDENED_ARTIFACT_TYPES,
4397
4503
  IdentityArtifactSchema,
4398
4504
  IngestFundingResultSchema,
4505
+ IssueAccountOacInputSchema,
4399
4506
  IssueOACInputSchema,
4400
4507
  LedgerJournalEntryArtifactSchema,
4401
4508
  ListPayoutDestinationsResultSchema,
@@ -4413,6 +4520,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4413
4520
  OAC_DEFAULT_CUMULATIVE_KOBO,
4414
4521
  OAC_DEFAULT_PER_TX_KOBO,
4415
4522
  OAC_DEFAULT_VALIDITY_MS,
4523
+ OFFLINE_CLAIM_SMS_PREFIX,
4416
4524
  OfflineClaimArtifactSchema,
4417
4525
  OfflineHoldRecordSchema,
4418
4526
  OfflinePaymentAuthorizationArtifactSchema,
@@ -4508,20 +4616,21 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4508
4616
  createPassesClient,
4509
4617
  createReceiptArtifactUri,
4510
4618
  createReceiptsClient,
4511
- createSoftwareEd25519Signer,
4512
4619
  createSoftwareP256Signer,
4513
4620
  decodeArtifactUri,
4514
4621
  decodeAuthorizationQR,
4515
4622
  decodeBase45,
4623
+ decodeOfflineClaimSmsMessage,
4516
4624
  decodePaymentRequestQR,
4517
4625
  encodeArtifactUri,
4518
4626
  encodeAuthorizationQR,
4519
4627
  encodeBase45,
4520
4628
  encodeNQR,
4629
+ encodeOfflineClaimSmsMessage,
4521
4630
  encodePaymentRequestQR,
4631
+ extractOfflineClaimSmsToken,
4522
4632
  formatAmount,
4523
4633
  generateDynamicQR,
4524
- generateKeyPair,
4525
4634
  generateStaticQR,
4526
4635
  init,
4527
4636
  isHardenedArtifactType,
@@ -4532,13 +4641,10 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4532
4641
  parseAmountInput,
4533
4642
  parseNQR,
4534
4643
  parseQR,
4535
- publicKeyFromPrivate,
4536
4644
  readTLV,
4537
4645
  routingHint,
4538
- sign,
4539
4646
  signArtifact,
4540
4647
  signAuthorization,
4541
- signCanonical,
4542
4648
  signOAC,
4543
4649
  signPartnerRequest,
4544
4650
  signPass,
@@ -4546,11 +4652,9 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4546
4652
  signReceipt,
4547
4653
  signRedemption,
4548
4654
  signRequestHMAC,
4549
- verify,
4550
4655
  verifyArtifactSignature,
4551
4656
  verifyArtifactUri,
4552
4657
  verifyAuthorization,
4553
- verifyCanonical,
4554
4658
  verifyClaimSignature,
4555
4659
  verifyOAC,
4556
4660
  verifyPass,