@nokinc-flur/sdk 1.1.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,11 +17,20 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ ACCOUNT_FUNDED_OAC_MAX_TTL_MS: () => ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
23
34
  ACCOUNT_STATUSES: () => ACCOUNT_STATUSES,
24
35
  ACCOUNT_TYPES: () => ACCOUNT_TYPES,
25
36
  ADDITIONAL_DATA_SUBFIELD: () => ADDITIONAL_DATA_SUBFIELD,
@@ -33,6 +44,10 @@ __export(index_exports, {
33
44
  CLAIM_DOMAIN_V2: () => CLAIM_DOMAIN_V2,
34
45
  COLLECTION_INTENT_STATUSES: () => COLLECTION_INTENT_STATUSES,
35
46
  COLLECTION_PAYMENT_STATUSES: () => COLLECTION_PAYMENT_STATUSES,
47
+ CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS: () => CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
48
+ CONSUMER_PAYMENT_REQUEST_DOMAIN: () => CONSUMER_PAYMENT_REQUEST_DOMAIN,
49
+ CONSUMER_SETTLEMENT_DOMAIN: () => CONSUMER_SETTLEMENT_DOMAIN,
50
+ CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX: () => CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX,
36
51
  CUSTODIAL_MODES: () => CUSTODIAL_MODES,
37
52
  CollectionIntentSchema: () => CollectionIntentSchema,
38
53
  CollectionPaymentResultSchema: () => CollectionPaymentResultSchema,
@@ -42,6 +57,7 @@ __export(index_exports, {
42
57
  ConsumerOACRecordSchema: () => OACRecordSchema,
43
58
  ConsumerOACSchema: () => ConsumerOACSchema,
44
59
  ConsumerPaymentClaimSchema: () => ConsumerPaymentClaimSchema,
60
+ ConsumerPaymentRequestEnvelopeSchema: () => ConsumerPaymentRequestEnvelopeSchema,
45
61
  ConsumerSettleResultSchema: () => ConsumerSettleResultSchema,
46
62
  ConsumerSettlementSchema: () => ConsumerSettlementSchema,
47
63
  CreateCollectionIntentInputSchema: () => CreateCollectionIntentInputSchema,
@@ -51,10 +67,6 @@ __export(index_exports, {
51
67
  CreateWithdrawalResultSchema: () => CreateWithdrawalResultSchema,
52
68
  DeviceKeyAlgSchema: () => DeviceKeyAlgSchema,
53
69
  DeviceKeyRecordSchema: () => DeviceKeyRecordSchema,
54
- DisableOfflineInputSchema: () => DisableOfflineInputSchema,
55
- DisableOfflineResultSchema: () => DisableOfflineResultSchema,
56
- EnableOfflineInputSchema: () => EnableOfflineInputSchema,
57
- EnableOfflineResultSchema: () => EnableOfflineResultSchema,
58
70
  FIELD: () => FIELD,
59
71
  FLUR_ARTIFACT_URI_PREFIX: () => FLUR_ARTIFACT_URI_PREFIX,
60
72
  FLUR_ARTIFACT_URI_SCHEME: () => FLUR_ARTIFACT_URI_SCHEME,
@@ -70,7 +82,6 @@ __export(index_exports, {
70
82
  IdentityArtifactSchema: () => IdentityArtifactSchema,
71
83
  IngestFundingResultSchema: () => IngestFundingResultSchema,
72
84
  IssueAccountOacInputSchema: () => IssueAccountOacInputSchema,
73
- IssueOACInputSchema: () => IssueOACInputSchema,
74
85
  LedgerJournalEntryArtifactSchema: () => LedgerJournalEntryArtifactSchema,
75
86
  ListPayoutDestinationsResultSchema: () => ListPayoutDestinationsResultSchema,
76
87
  MEMBERSHIP_ROLES: () => MEMBERSHIP_ROLES,
@@ -88,12 +99,16 @@ __export(index_exports, {
88
99
  OAC_DEFAULT_PER_TX_KOBO: () => OAC_DEFAULT_PER_TX_KOBO,
89
100
  OAC_DEFAULT_VALIDITY_MS: () => OAC_DEFAULT_VALIDITY_MS,
90
101
  OFFLINE_CLAIM_SMS_PREFIX: () => OFFLINE_CLAIM_SMS_PREFIX,
102
+ OFFLINE_SMS_SETTLE_DOMAIN: () => OFFLINE_SMS_SETTLE_DOMAIN,
103
+ OFFLINE_SMS_SETTLE_HEADER_BYTES: () => OFFLINE_SMS_SETTLE_HEADER_BYTES,
104
+ OFFLINE_SMS_SETTLE_PREFIX: () => OFFLINE_SMS_SETTLE_PREFIX,
105
+ OFFLINE_SMS_SETTLE_SIGNATURE_BYTES: () => OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
106
+ OFFLINE_SMS_SETTLE_TOKEN_BYTES: () => OFFLINE_SMS_SETTLE_TOKEN_BYTES,
107
+ OFFLINE_SMS_SETTLE_VERSION: () => OFFLINE_SMS_SETTLE_VERSION,
91
108
  OfflineClaimArtifactSchema: () => OfflineClaimArtifactSchema,
92
- OfflineHoldRecordSchema: () => OfflineHoldRecordSchema,
93
109
  OfflinePaymentAuthorizationArtifactSchema: () => OfflinePaymentAuthorizationArtifactSchema,
94
110
  OfflinePaymentAuthorizationSchema: () => OfflinePaymentAuthorizationSchema,
95
111
  OfflinePaymentRequestSchema: () => OfflinePaymentRequestSchema,
96
- OfflineStateResultSchema: () => OfflineStateResultSchema,
97
112
  OfflineStatusResultSchema: () => OfflineStatusResultSchema,
98
113
  OfflineTokenSchema: () => OfflineTokenSchema,
99
114
  P256EnrollmentChallengeInputSchema: () => P256EnrollmentChallengeInputSchema,
@@ -121,8 +136,6 @@ __export(index_exports, {
121
136
  PayoutEventInputSchema: () => PayoutEventInputSchema,
122
137
  ProviderEventInputSchema: () => ProviderEventInputSchema,
123
138
  ProviderEventRecordSchema: () => ProviderEventRecordSchema,
124
- ProvisionOfflineAllowanceInputSchema: () => ProvisionOfflineAllowanceInputSchema,
125
- ProvisionOfflineAllowanceResultSchema: () => ProvisionOfflineAllowanceResultSchema,
126
139
  PublicCollectionIntentSchema: () => PublicCollectionIntentSchema,
127
140
  RECEIPT_CHANNELS: () => RECEIPT_CHANNELS,
128
141
  RECEIPT_KINDS: () => RECEIPT_KINDS,
@@ -133,7 +146,6 @@ __export(index_exports, {
133
146
  ReconciliationReportSchema: () => ReconciliationReportSchema,
134
147
  RecordPayoutEventResultSchema: () => RecordPayoutEventResultSchema,
135
148
  RedemptionSchema: () => RedemptionSchema,
136
- RegisterDeviceKeyInputSchema: () => RegisterDeviceKeyInputSchema,
137
149
  RegisterDeviceKeyP256InputSchema: () => RegisterDeviceKeyP256InputSchema,
138
150
  ReversalRecordArtifactSchema: () => ReversalRecordArtifactSchema,
139
151
  RevokeDeviceKeyInputSchema: () => RevokeDeviceKeyInputSchema,
@@ -152,18 +164,25 @@ __export(index_exports, {
152
164
  bodySha256Hex: () => bodySha256Hex,
153
165
  buildArtifactBody: () => buildArtifactBody,
154
166
  buildAuthorization: () => buildAuthorization,
167
+ buildConsumerPaymentRequest: () => buildConsumerPaymentRequest,
155
168
  buildOAC: () => buildOAC,
156
169
  buildPass: () => buildPass,
157
170
  buildPaymentRequest: () => buildPaymentRequest,
158
171
  buildReceipt: () => buildReceipt,
159
172
  buildRedemption: () => buildRedemption,
173
+ buildSmsSettleHeader: () => buildSmsSettleHeader,
174
+ buildSmsSettleSignedBytes: () => domainTag,
160
175
  canonicalClaimSigningBytes: () => canonicalClaimSigningBytes,
161
176
  canonicalClaimSigningPayload: () => canonicalClaimSigningPayload,
162
177
  canonicalJSONBytes: () => canonicalJSONBytes,
163
178
  canonicalJSONStringify: () => canonicalJSONStringify,
164
179
  canonicalRequestString: () => canonicalRequestString,
180
+ computeConsumerClaimEncounterId: () => computeConsumerClaimEncounterId,
165
181
  computeEncounterId: () => computeEncounterId,
166
182
  constantTimeEqual: () => constantTimeEqual,
183
+ consumerPaymentRequestSigningBytes: () => consumerPaymentRequestSigningBytes,
184
+ consumerPaymentRequestSigningPayload: () => consumerPaymentRequestSigningPayload,
185
+ consumerSettlementSigningPayload: () => consumerSettlementSigningPayload,
167
186
  crc16ccitt: () => crc16ccitt,
168
187
  crc16ccittHex: () => crc16ccittHex,
169
188
  createAccountsClient: () => createAccountsClient,
@@ -187,19 +206,27 @@ __export(index_exports, {
187
206
  decodeArtifactUri: () => decodeArtifactUri,
188
207
  decodeAuthorizationQR: () => decodeAuthorizationQR,
189
208
  decodeBase45: () => decodeBase45,
209
+ decodeConsumerSettlementReceiptQR: () => decodeConsumerSettlementReceiptQR,
190
210
  decodeOfflineClaimSmsMessage: () => decodeOfflineClaimSmsMessage,
211
+ decodeOfflineSmsSettleToken: () => decodeOfflineSmsSettleToken,
191
212
  decodePaymentRequestQR: () => decodePaymentRequestQR,
213
+ decodeUnverifiedConsumerSettlementReceiptQR: () => decodeUnverifiedConsumerSettlementReceiptQR,
214
+ derToRawP256Signature: () => derToRawP256Signature,
192
215
  encodeArtifactUri: () => encodeArtifactUri,
193
216
  encodeAuthorizationQR: () => encodeAuthorizationQR,
194
217
  encodeBase45: () => encodeBase45,
218
+ encodeConsumerSettlementReceiptQR: () => encodeConsumerSettlementReceiptQR,
195
219
  encodeNQR: () => encodeNQR,
196
220
  encodeOfflineClaimSmsMessage: () => encodeOfflineClaimSmsMessage,
221
+ encodeOfflineSmsSettleToken: () => encodeOfflineSmsSettleToken,
197
222
  encodePaymentRequestQR: () => encodePaymentRequestQR,
198
223
  extractOfflineClaimSmsToken: () => extractOfflineClaimSmsToken,
224
+ extractOfflineSmsSettleToken: () => extractOfflineSmsSettleToken,
199
225
  formatAmount: () => formatAmount,
200
226
  generateDynamicQR: () => generateDynamicQR,
201
227
  generateStaticQR: () => generateStaticQR,
202
228
  init: () => init,
229
+ isConsumerPaymentRequestExpired: () => isConsumerPaymentRequestExpired,
203
230
  isHardenedArtifactType: () => isHardenedArtifactType,
204
231
  isKnownArtifactType: () => isKnownArtifactType,
205
232
  isPassWithinValidity: () => isPassWithinValidity,
@@ -212,6 +239,7 @@ __export(index_exports, {
212
239
  routingHint: () => routingHint,
213
240
  signArtifact: () => signArtifact,
214
241
  signAuthorization: () => signAuthorization,
242
+ signConsumerPaymentRequest: () => signConsumerPaymentRequest,
215
243
  signOAC: () => signOAC,
216
244
  signPartnerRequest: () => signPartnerRequest,
217
245
  signPass: () => signPass,
@@ -223,7 +251,11 @@ __export(index_exports, {
223
251
  verifyArtifactUri: () => verifyArtifactUri,
224
252
  verifyAuthorization: () => verifyAuthorization,
225
253
  verifyClaimSignature: () => verifyClaimSignature,
254
+ verifyConsumerPaymentRequest: () => verifyConsumerPaymentRequest,
255
+ verifyConsumerSettlement: () => verifyConsumerSettlement,
256
+ verifyConsumerSettlementReceiptQR: () => verifyConsumerSettlementReceiptQR,
226
257
  verifyOAC: () => verifyOAC,
258
+ verifyOfflineSmsSettleToken: () => verifyOfflineSmsSettleToken,
227
259
  verifyPass: () => verifyPass,
228
260
  verifyPaymentRequest: () => verifyPaymentRequest,
229
261
  verifyReceipt: () => verifyReceipt,
@@ -234,13 +266,203 @@ __export(index_exports, {
234
266
  module.exports = __toCommonJS(index_exports);
235
267
 
236
268
  // src/client.ts
237
- var import_zod5 = require("zod");
269
+ var import_zod4 = require("zod");
238
270
 
239
271
  // src/contracts.ts
240
- var import_zod2 = require("zod");
241
-
242
- // src/me-offline/client.ts
243
272
  var import_zod = require("zod");
273
+ var E164Regex = /^\+[1-9]\d{7,14}$/;
274
+ var UuidSchema = import_zod.z.string().uuid();
275
+ var IsoDateSchema = import_zod.z.string().datetime({ offset: true });
276
+ var CurrencySchema = import_zod.z.string().trim().length(3).transform((value) => value.toUpperCase());
277
+ var HealthResponseSchema = import_zod.z.object({
278
+ ok: import_zod.z.boolean()
279
+ });
280
+ var WelcomeResponseSchema = import_zod.z.object({
281
+ message: import_zod.z.string()
282
+ });
283
+ var OnboardingStartRequestSchema = import_zod.z.object({
284
+ phoneE164: import_zod.z.string().regex(E164Regex),
285
+ appInstanceId: import_zod.z.string().min(3),
286
+ platform: import_zod.z.enum(["android", "ios", "web"]),
287
+ turnstileToken: import_zod.z.string().min(20).optional(),
288
+ appAttestation: import_zod.z.object({
289
+ provider: import_zod.z.enum(["android", "ios", "web"]),
290
+ token: import_zod.z.string().min(24)
291
+ }).optional(),
292
+ firstName: import_zod.z.string().trim().min(1).max(80).optional(),
293
+ lastName: import_zod.z.string().trim().min(1).max(80).optional()
294
+ });
295
+ var OnboardingStartResponseSchema = import_zod.z.object({
296
+ requestId: import_zod.z.string().min(1),
297
+ checkUrl: import_zod.z.string().url().optional(),
298
+ expiresInSec: import_zod.z.number().int().positive(),
299
+ fallback: import_zod.z.enum(["SILENT_AUTH", "OTP"])
300
+ });
301
+ var OnboardingCompleteRequestSchema = import_zod.z.object({
302
+ requestId: import_zod.z.string().min(1),
303
+ code: import_zod.z.string().min(1).max(32),
304
+ appInstanceId: import_zod.z.string().min(3),
305
+ fingerprintHash: import_zod.z.string().min(3).optional()
306
+ });
307
+ var OnboardingCompleteResponseSchema = import_zod.z.object({
308
+ sessionToken: import_zod.z.string().min(1),
309
+ userId: UuidSchema,
310
+ restricted: import_zod.z.boolean(),
311
+ risk_reasons: import_zod.z.array(
312
+ import_zod.z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
313
+ ),
314
+ stepUpRequired: import_zod.z.boolean().optional(),
315
+ riskStatus: import_zod.z.enum(["ok", "unavailable"]).optional()
316
+ });
317
+ var RegisterDeviceRequestSchema = import_zod.z.object({
318
+ userId: UuidSchema,
319
+ appInstanceId: import_zod.z.string().min(3),
320
+ platform: import_zod.z.string().min(2),
321
+ model: import_zod.z.string().optional(),
322
+ networkSignals: import_zod.z.object({
323
+ ip: import_zod.z.string().min(3),
324
+ asn: import_zod.z.number().int().optional(),
325
+ country: import_zod.z.string().min(2).optional(),
326
+ carrier: import_zod.z.string().optional()
327
+ })
328
+ });
329
+ var RegisterDeviceResponseSchema = import_zod.z.object({
330
+ deviceId: import_zod.z.string().min(1),
331
+ fingerprintHash: import_zod.z.string().min(1),
332
+ driftScore: import_zod.z.number(),
333
+ trustState: import_zod.z.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
334
+ stepUpRequired: import_zod.z.boolean()
335
+ });
336
+ var AuthRefreshRequestSchema = import_zod.z.object({
337
+ userId: UuidSchema,
338
+ refreshToken: import_zod.z.string().min(8),
339
+ appInstanceId: import_zod.z.string().min(3),
340
+ fingerprintHash: import_zod.z.string().min(3)
341
+ });
342
+ var AuthRefreshResponseSchema = import_zod.z.object({
343
+ refreshToken: import_zod.z.string().min(8),
344
+ stepUpRequired: import_zod.z.boolean()
345
+ });
346
+ var AuthLogoutRequestSchema = import_zod.z.object({
347
+ userId: UuidSchema,
348
+ refreshToken: import_zod.z.string().min(8)
349
+ });
350
+ var PinSetRequestSchema = import_zod.z.object({
351
+ userId: UuidSchema,
352
+ pin: import_zod.z.string().regex(/^\d{6}$/)
353
+ });
354
+ var PinVerifyRequestSchema = import_zod.z.object({
355
+ userId: UuidSchema,
356
+ pin: import_zod.z.string().regex(/^\d{6}$/)
357
+ });
358
+ var OkResponseSchema = import_zod.z.object({
359
+ ok: import_zod.z.boolean()
360
+ });
361
+ var RegisterSendDeviceKeyRequestSchema = import_zod.z.object({
362
+ userId: UuidSchema,
363
+ deviceId: import_zod.z.string().min(3),
364
+ publicKey: import_zod.z.string().min(32)
365
+ });
366
+ var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
367
+ var SendChallengeRequestSchema = import_zod.z.object({
368
+ userId: UuidSchema,
369
+ deviceId: import_zod.z.string().min(3),
370
+ purpose: import_zod.z.enum(SEND_AUTH_PURPOSES).optional()
371
+ });
372
+ var SendChallengeResponseSchema = import_zod.z.object({
373
+ challengeId: UuidSchema,
374
+ nonce: import_zod.z.string().min(1),
375
+ expiresAt: IsoDateSchema
376
+ });
377
+ var SendVerifyRequestSchema = import_zod.z.object({
378
+ userId: UuidSchema,
379
+ deviceId: import_zod.z.string().min(3),
380
+ challengeId: UuidSchema,
381
+ signature: import_zod.z.string().min(16)
382
+ });
383
+ var SendVerifyResponseSchema = import_zod.z.object({
384
+ sendAuthToken: import_zod.z.string().min(16)
385
+ });
386
+ var ResolveRecipientRequestSchema = import_zod.z.object({
387
+ identifier: import_zod.z.string().min(3)
388
+ });
389
+ var ResolveRecipientResponseSchema = import_zod.z.object({
390
+ recipientUserId: UuidSchema,
391
+ displayName: import_zod.z.string().min(1),
392
+ normalizedIdentifier: import_zod.z.string().regex(E164Regex),
393
+ isActive: import_zod.z.boolean()
394
+ });
395
+ var CreateTransferRequestSchema = import_zod.z.object({
396
+ recipientIdentifier: import_zod.z.string().min(3),
397
+ amountMinor: import_zod.z.number().int().positive(),
398
+ currency: CurrencySchema,
399
+ sendAuthToken: import_zod.z.string().min(16)
400
+ });
401
+ var TransferStatusSchema = import_zod.z.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
402
+ var TransferResponseSchema = import_zod.z.object({
403
+ transactionId: import_zod.z.string().min(1),
404
+ status: TransferStatusSchema,
405
+ userStatus: TransferStatusSchema,
406
+ recipientName: import_zod.z.string().min(1),
407
+ timestamp: IsoDateSchema
408
+ });
409
+ var DirectionSchema = import_zod.z.enum(["OUTGOING", "INCOMING"]);
410
+ var AccountActivityItemSchema = import_zod.z.object({
411
+ id: import_zod.z.string().min(1),
412
+ type: import_zod.z.string().min(1),
413
+ direction: DirectionSchema,
414
+ name: import_zod.z.string().min(1),
415
+ identifier: import_zod.z.string().min(1),
416
+ amountMinor: import_zod.z.number().int(),
417
+ currency: CurrencySchema,
418
+ status: import_zod.z.string().min(1),
419
+ timestamp: IsoDateSchema
420
+ });
421
+ var AccountSummaryResponseSchema = import_zod.z.object({
422
+ /** Authenticated user's stable internal id. */
423
+ userId: UuidSchema,
424
+ /**
425
+ * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
426
+ * bank partner. `null` when the user has no partner-allocated account yet.
427
+ */
428
+ nuban: import_zod.z.string().regex(/^[0-9]{10}$/).nullable(),
429
+ balance: import_zod.z.number().int(),
430
+ currency: CurrencySchema,
431
+ dailySendLimit: import_zod.z.number().int().nonnegative(),
432
+ dailySendRemaining: import_zod.z.number().int().nonnegative(),
433
+ kycTier: import_zod.z.string().min(1),
434
+ kycStatus: import_zod.z.string().min(1),
435
+ recentActivity: import_zod.z.array(AccountActivityItemSchema)
436
+ });
437
+ var TransactionsListResponseSchema = import_zod.z.object({
438
+ items: import_zod.z.array(AccountActivityItemSchema),
439
+ nextCursor: import_zod.z.string().nullable()
440
+ });
441
+ var TransactionDetailResponseSchema = import_zod.z.object({
442
+ transactionId: import_zod.z.string().min(1),
443
+ type: import_zod.z.string().min(1),
444
+ direction: DirectionSchema,
445
+ counterpartyName: import_zod.z.string().min(1),
446
+ counterpartyIdentifier: import_zod.z.string().min(1),
447
+ amountMinor: import_zod.z.number().int(),
448
+ currency: CurrencySchema,
449
+ status: import_zod.z.string().min(1),
450
+ timestamp: IsoDateSchema
451
+ });
452
+ var PushRegisterRequestSchema = import_zod.z.object({
453
+ deviceId: import_zod.z.string().min(3),
454
+ platform: import_zod.z.enum(["ios", "android", "web"]),
455
+ token: import_zod.z.string().min(16)
456
+ });
457
+ var CreatePayLinkResponseSchema = import_zod.z.object({
458
+ token: import_zod.z.string().min(1)
459
+ });
460
+ var ResolvePayLinkResponseSchema = import_zod.z.object({
461
+ recipientUserId: UuidSchema,
462
+ displayName: import_zod.z.string().min(1),
463
+ normalizedIdentifier: import_zod.z.string().regex(E164Regex),
464
+ isActive: import_zod.z.boolean()
465
+ });
244
466
 
245
467
  // src/errors.ts
246
468
  var backendErrorCodeSet = /* @__PURE__ */ new Set([
@@ -344,556 +566,9 @@ async function mapToFlurError(res) {
344
566
  });
345
567
  }
346
568
 
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
-
894
569
  // src/primitives.ts
895
- var import_zod3 = require("zod");
896
- var CurrencyCodeSchema = import_zod3.z.string().trim().length(3).transform((value) => value.toUpperCase());
570
+ var import_zod2 = require("zod");
571
+ var CurrencyCodeSchema = import_zod2.z.string().trim().length(3).transform((value) => value.toUpperCase());
897
572
  var currencyFractionDigits = {
898
573
  NGN: 2,
899
574
  USD: 2,
@@ -987,7 +662,7 @@ function moneyMinorToNumber(amountMinor) {
987
662
  }
988
663
 
989
664
  // src/collections/client.ts
990
- var import_zod4 = require("zod");
665
+ var import_zod3 = require("zod");
991
666
  var MERCHANT_PROFILE_STATUSES = [
992
667
  "pending",
993
668
  "active",
@@ -1017,172 +692,172 @@ var MERCHANT_PAYOUT_STATUSES = [
1017
692
  "failed",
1018
693
  "cancelled"
1019
694
  ];
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()])
695
+ var MoneyKoboSchema = import_zod3.z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
696
+ var MetadataSchema = import_zod3.z.record(
697
+ import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()])
1023
698
  );
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(),
699
+ var CurrencySchema2 = import_zod3.z.string().trim().length(3).transform((value) => value.toUpperCase());
700
+ var ReferenceSchema = import_zod3.z.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
701
+ var MerchantProfileSchema = import_zod3.z.object({
702
+ accountId: import_zod3.z.string().uuid(),
703
+ legalName: import_zod3.z.string(),
704
+ tradingName: import_zod3.z.string(),
705
+ merchantCategoryCode: import_zod3.z.string().regex(/^\d{4}$/),
706
+ nqrMerchantId: import_zod3.z.string(),
707
+ settlementBankCode: import_zod3.z.string(),
708
+ settlementAccountNumber: import_zod3.z.string(),
709
+ settlementAccountName: import_zod3.z.string(),
710
+ settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES),
711
+ status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES),
712
+ offlineEnabled: import_zod3.z.boolean(),
1038
713
  perTxLimitKobo: MoneyKoboSchema,
1039
714
  dailyLimitKobo: MoneyKoboSchema,
1040
715
  metadata: MetadataSchema,
1041
- createdAtMs: import_zod4.z.number().int().nonnegative(),
1042
- updatedAtMs: import_zod4.z.number().int().nonnegative()
716
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
717
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
1043
718
  });
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(),
719
+ var UpsertMerchantProfileInputSchema = import_zod3.z.object({
720
+ legalName: import_zod3.z.string().trim().min(1).max(200),
721
+ tradingName: import_zod3.z.string().trim().min(1).max(25),
722
+ merchantCategoryCode: import_zod3.z.string().trim().regex(/^\d{4}$/),
723
+ nqrMerchantId: import_zod3.z.string().trim().min(3).max(64),
724
+ settlementBankCode: import_zod3.z.string().trim().min(2).max(16),
725
+ settlementAccountNumber: import_zod3.z.string().trim().min(5).max(32),
726
+ settlementAccountName: import_zod3.z.string().trim().min(1).max(200),
727
+ settlementSchedule: import_zod3.z.enum(SETTLEMENT_SCHEDULES).optional(),
728
+ status: import_zod3.z.enum(MERCHANT_PROFILE_STATUSES).optional(),
729
+ offlineEnabled: import_zod3.z.boolean().optional(),
1055
730
  perTxLimitKobo: MoneyKoboSchema.optional(),
1056
731
  dailyLimitKobo: MoneyKoboSchema.optional(),
1057
732
  metadata: MetadataSchema.optional()
1058
733
  });
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(),
734
+ var CollectionIntentSchema = import_zod3.z.object({
735
+ intentId: import_zod3.z.string().uuid(),
736
+ accountId: import_zod3.z.string().uuid(),
737
+ terminalId: import_zod3.z.string().uuid().nullable(),
738
+ reference: import_zod3.z.string(),
739
+ amountKobo: import_zod3.z.number().int().positive().nullable(),
740
+ currency: import_zod3.z.string().length(3),
741
+ status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
742
+ description: import_zod3.z.string().nullable(),
743
+ nqrPayload: import_zod3.z.string(),
744
+ provider: import_zod3.z.string(),
745
+ providerReference: import_zod3.z.string().nullable(),
1071
746
  metadata: MetadataSchema,
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()
747
+ expiresAtMs: import_zod3.z.number().int().nonnegative().nullable(),
748
+ paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
749
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
750
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
1076
751
  });
1077
- var CreateCollectionIntentInputSchema = import_zod4.z.object({
752
+ var CreateCollectionIntentInputSchema = import_zod3.z.object({
1078
753
  reference: ReferenceSchema.optional(),
1079
754
  amountKobo: MoneyKoboSchema.optional(),
1080
755
  currency: CurrencySchema2.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(),
756
+ terminalId: import_zod3.z.string().uuid().optional(),
757
+ terminalLabel: import_zod3.z.string().trim().min(1).max(25).optional(),
758
+ merchantCity: import_zod3.z.string().trim().min(1).max(15).optional(),
759
+ description: import_zod3.z.string().trim().min(1).max(280).optional(),
760
+ expiresAtMs: import_zod3.z.number().int().positive().optional(),
761
+ provider: import_zod3.z.string().trim().min(1).max(40).optional(),
1087
762
  metadata: MetadataSchema.optional()
1088
763
  });
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()
764
+ var PublicCollectionIntentSchema = import_zod3.z.object({
765
+ intentId: import_zod3.z.string().uuid(),
766
+ reference: import_zod3.z.string(),
767
+ amountKobo: import_zod3.z.number().int().positive().nullable(),
768
+ currency: import_zod3.z.string().length(3),
769
+ status: import_zod3.z.enum(COLLECTION_INTENT_STATUSES),
770
+ merchantAccountId: import_zod3.z.string().uuid(),
771
+ merchantName: import_zod3.z.string(),
772
+ merchantCategoryCode: import_zod3.z.string(),
773
+ description: import_zod3.z.string().nullable(),
774
+ expiresAtMs: import_zod3.z.number().int().nonnegative().nullable()
1100
775
  });
1101
- var PayCollectionInputSchema = import_zod4.z.object({
776
+ var PayCollectionInputSchema = import_zod3.z.object({
1102
777
  reference: ReferenceSchema,
1103
778
  amountKobo: MoneyKoboSchema.optional(),
1104
779
  currency: CurrencySchema2.optional(),
1105
- idempotencyKey: import_zod4.z.string().trim().min(8).max(160).optional()
780
+ idempotencyKey: import_zod3.z.string().trim().min(8).max(160).optional()
1106
781
  });
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(),
782
+ var CollectionPaymentSchema = import_zod3.z.object({
783
+ paymentId: import_zod3.z.string().uuid(),
784
+ intentId: import_zod3.z.string().uuid(),
785
+ accountId: import_zod3.z.string().uuid(),
786
+ payerUserId: import_zod3.z.string().uuid().nullable(),
787
+ merchantOwnerUserId: import_zod3.z.string().uuid(),
1113
788
  amountKobo: MoneyKoboSchema,
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()
789
+ currency: import_zod3.z.string().length(3),
790
+ status: import_zod3.z.enum(COLLECTION_PAYMENT_STATUSES),
791
+ provider: import_zod3.z.string(),
792
+ providerReference: import_zod3.z.string().nullable(),
793
+ idempotencyKey: import_zod3.z.string().nullable(),
794
+ ledgerRef: import_zod3.z.string(),
795
+ failureCode: import_zod3.z.string().nullable(),
796
+ failureMessage: import_zod3.z.string().nullable(),
797
+ paidAtMs: import_zod3.z.number().int().nonnegative().nullable(),
798
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
799
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
1125
800
  });
1126
- var CollectionPaymentResultSchema = import_zod4.z.object({
801
+ var CollectionPaymentResultSchema = import_zod3.z.object({
1127
802
  payment: CollectionPaymentSchema,
1128
803
  intent: CollectionIntentSchema,
1129
- receipt: import_zod4.z.unknown().optional(),
1130
- replayed: import_zod4.z.boolean()
804
+ receipt: import_zod3.z.unknown().optional(),
805
+ replayed: import_zod3.z.boolean()
1131
806
  });
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()
807
+ var CollectionReportSummarySchema = import_zod3.z.object({
808
+ accountId: import_zod3.z.string().uuid(),
809
+ fromMs: import_zod3.z.number().int().nonnegative(),
810
+ toMs: import_zod3.z.number().int().nonnegative(),
811
+ currency: import_zod3.z.string().length(3),
812
+ paidCount: import_zod3.z.number().int().nonnegative(),
813
+ paidAmountKobo: import_zod3.z.number().int().nonnegative(),
814
+ pendingCount: import_zod3.z.number().int().nonnegative(),
815
+ failedCount: import_zod3.z.number().int().nonnegative(),
816
+ reversedCount: import_zod3.z.number().int().nonnegative(),
817
+ availableBalanceKobo: import_zod3.z.number().int().nonnegative()
1143
818
  });
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)
819
+ var CollectionStatementSchema = import_zod3.z.object({
820
+ accountId: import_zod3.z.string().uuid(),
821
+ year: import_zod3.z.number().int(),
822
+ month: import_zod3.z.number().int().min(1).max(12),
823
+ currency: import_zod3.z.string().length(3),
824
+ totalPaidKobo: import_zod3.z.number().int().nonnegative(),
825
+ items: import_zod3.z.array(CollectionPaymentSchema)
1151
826
  });
1152
- var CreatePayoutInputSchema = import_zod4.z.object({
827
+ var CreatePayoutInputSchema = import_zod3.z.object({
1153
828
  amountKobo: MoneyKoboSchema,
1154
829
  currency: CurrencySchema2.optional(),
1155
- idempotencyKey: import_zod4.z.string().trim().min(8).max(160)
830
+ idempotencyKey: import_zod3.z.string().trim().min(8).max(160)
1156
831
  });
1157
- var MerchantPayoutSchema = import_zod4.z.object({
1158
- payoutId: import_zod4.z.string().uuid(),
1159
- accountId: import_zod4.z.string().uuid(),
832
+ var MerchantPayoutSchema = import_zod3.z.object({
833
+ payoutId: import_zod3.z.string().uuid(),
834
+ accountId: import_zod3.z.string().uuid(),
1160
835
  amountKobo: MoneyKoboSchema,
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()
836
+ currency: import_zod3.z.string().length(3),
837
+ status: import_zod3.z.enum(MERCHANT_PAYOUT_STATUSES),
838
+ idempotencyKey: import_zod3.z.string().nullable(),
839
+ ledgerRef: import_zod3.z.string(),
840
+ providerReference: import_zod3.z.string().nullable(),
841
+ requestedByUserId: import_zod3.z.string().uuid().nullable(),
842
+ failureCode: import_zod3.z.string().nullable(),
843
+ failureMessage: import_zod3.z.string().nullable(),
844
+ createdAtMs: import_zod3.z.number().int().nonnegative(),
845
+ updatedAtMs: import_zod3.z.number().int().nonnegative()
1171
846
  });
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()
847
+ var ProviderEventInputSchema = import_zod3.z.object({
848
+ provider: import_zod3.z.string().trim().min(1).max(80),
849
+ eventId: import_zod3.z.string().trim().min(1).max(160),
850
+ eventType: import_zod3.z.string().trim().min(1).max(120),
851
+ payload: import_zod3.z.record(import_zod3.z.unknown()).optional()
1177
852
  });
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()
853
+ var ProviderEventRecordSchema = import_zod3.z.object({
854
+ id: import_zod3.z.string().uuid(),
855
+ provider: import_zod3.z.string(),
856
+ eventId: import_zod3.z.string(),
857
+ eventType: import_zod3.z.string(),
858
+ signatureVerified: import_zod3.z.boolean(),
859
+ receivedAtMs: import_zod3.z.number().int().nonnegative(),
860
+ processedAtMs: import_zod3.z.number().int().nonnegative().nullable()
1186
861
  });
1187
862
  function createCollectionsClient(opts) {
1188
863
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -1697,7 +1372,7 @@ var FlurClient = class {
1697
1372
  try {
1698
1373
  body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
1699
1374
  } catch (err) {
1700
- if (err instanceof import_zod5.z.ZodError) {
1375
+ if (err instanceof import_zod4.z.ZodError) {
1701
1376
  throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
1702
1377
  details: err.flatten()
1703
1378
  });
@@ -1725,7 +1400,7 @@ var FlurClient = class {
1725
1400
  try {
1726
1401
  return responseSchema.parse(payload);
1727
1402
  } catch (err) {
1728
- if (err instanceof import_zod5.z.ZodError) {
1403
+ if (err instanceof import_zod4.z.ZodError) {
1729
1404
  throw new FlurError(
1730
1405
  "SDK contract validation failed",
1731
1406
  "INVALID_REQUEST",
@@ -2156,7 +1831,7 @@ function constantTimeEqual(a, b) {
2156
1831
  }
2157
1832
 
2158
1833
  // src/offline/oac.ts
2159
- var import_zod6 = require("zod");
1834
+ var import_zod5 = require("zod");
2160
1835
 
2161
1836
  // src/crypto/p256-issuer.ts
2162
1837
  var import_nist = require("@noble/curves/nist");
@@ -2238,20 +1913,20 @@ function verifyIssuerP256(bytes, signatureB64, issuerPublicKeySpkiB64) {
2238
1913
  var OAC_DEFAULT_PER_TX_KOBO = 5e5;
2239
1914
  var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
2240
1915
  var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
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),
1916
+ var Base64Std = import_zod5.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) string");
1917
+ var OACSchema = import_zod5.z.object({
1918
+ userId: import_zod5.z.string().min(1),
1919
+ deviceId: import_zod5.z.string().min(1),
2245
1920
  /** 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),
1921
+ devicePublicKey: Base64Std,
1922
+ perTxCapKobo: import_zod5.z.number().int().nonnegative(),
1923
+ cumulativeCapKobo: import_zod5.z.number().int().nonnegative(),
1924
+ validFromMs: import_zod5.z.number().int().nonnegative(),
1925
+ validUntilMs: import_zod5.z.number().int().positive(),
1926
+ counterSeed: import_zod5.z.number().int().nonnegative(),
1927
+ nonce: import_zod5.z.string().min(1),
2253
1928
  /** ASN.1 DER ECDSA(SHA-256) signature, base64. */
2254
- issuerSig: Base64Std2
1929
+ issuerSig: Base64Std
2255
1930
  }).refine((v) => v.validUntilMs > v.validFromMs, {
2256
1931
  message: "validUntilMs must be greater than validFromMs"
2257
1932
  }).refine((v) => v.perTxCapKobo <= v.cumulativeCapKobo, {
@@ -2345,19 +2020,19 @@ function decodeBase45(s) {
2345
2020
  }
2346
2021
 
2347
2022
  // src/offline/messages.ts
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(),
2023
+ var import_zod6 = require("zod");
2024
+ var Base64Sig = import_zod6.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) signature");
2025
+ var OfflinePaymentRequestSchema = import_zod6.z.object({
2026
+ reference: import_zod6.z.string().min(1),
2027
+ amountKobo: import_zod6.z.number().int().positive(),
2353
2028
  merchantOAC: OACSchema,
2354
- expiresAtMs: import_zod7.z.number().int().positive(),
2029
+ expiresAtMs: import_zod6.z.number().int().positive(),
2355
2030
  merchantSig: Base64Sig
2356
2031
  });
2357
- var OfflinePaymentAuthorizationSchema = import_zod7.z.object({
2032
+ var OfflinePaymentAuthorizationSchema = import_zod6.z.object({
2358
2033
  request: OfflinePaymentRequestSchema,
2359
2034
  payerOAC: OACSchema,
2360
- payerCounter: import_zod7.z.number().int().positive(),
2035
+ payerCounter: import_zod6.z.number().int().positive(),
2361
2036
  payerSig: Base64Sig
2362
2037
  });
2363
2038
  function buildPaymentRequest(input) {
@@ -2469,60 +2144,60 @@ function decodeAuthorizationQR(s) {
2469
2144
  }
2470
2145
 
2471
2146
  // src/offline/settlements.ts
2472
- var import_zod8 = require("zod");
2147
+ var import_zod7 = require("zod");
2473
2148
  var import_sha256 = require("@noble/hashes/sha256");
2474
2149
  var import_utils = require("@noble/hashes/utils");
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()
2150
+ var OfflineTokenSchema = import_zod7.z.object({
2151
+ tokenId: import_zod7.z.string().uuid(),
2152
+ tokenSerial: import_zod7.z.string(),
2153
+ issuerAccountId: import_zod7.z.string().uuid(),
2154
+ payerUserId: import_zod7.z.string().uuid(),
2155
+ maxAmountKobo: import_zod7.z.number().int().positive(),
2156
+ currency: import_zod7.z.string().length(3),
2157
+ issuedAtMs: import_zod7.z.number().int().nonnegative(),
2158
+ expiresAtMs: import_zod7.z.number().int().nonnegative(),
2159
+ issuerSig: import_zod7.z.string()
2485
2160
  });
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(),
2161
+ var PaymentClaimSchema = import_zod7.z.object({
2162
+ encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i).optional(),
2163
+ tokenSerial: import_zod7.z.string(),
2164
+ payerUserId: import_zod7.z.string().uuid(),
2165
+ payeeUserId: import_zod7.z.string().uuid(),
2166
+ payerNonce: import_zod7.z.string(),
2167
+ payeeNonce: import_zod7.z.string(),
2168
+ amountKobo: import_zod7.z.number().int().positive(),
2169
+ currency: import_zod7.z.string().length(3).default("NGN"),
2170
+ occurredAtMs: import_zod7.z.number().int().nonnegative(),
2171
+ completedAtMs: import_zod7.z.number().int().nonnegative().optional(),
2172
+ contextId: import_zod7.z.string().optional(),
2498
2173
  // Stage 2c: P-256 device keys are now SubjectPublicKeyInfo DER, base64.
2499
2174
  // Signatures are ASN.1 DER ECDSA(SHA-256), base64. Backwards-incompatible
2500
2175
  // wire change; the backend has the matching widening in offline-settlements
2501
2176
  // 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()
2177
+ payerPubkey: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2178
+ payerSignature: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2179
+ payeePubkey: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional(),
2180
+ payeeSignature: import_zod7.z.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional()
2506
2181
  });
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()
2182
+ var SettlementSchema = import_zod7.z.object({
2183
+ settlementId: import_zod7.z.string().uuid(),
2184
+ settlementKey: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2185
+ encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2186
+ issuerAccountId: import_zod7.z.string().uuid(),
2187
+ tokenSerial: import_zod7.z.string(),
2188
+ payerUserId: import_zod7.z.string().uuid(),
2189
+ payeeUserId: import_zod7.z.string().uuid(),
2190
+ amountKobo: import_zod7.z.number().int().nonnegative(),
2191
+ currency: import_zod7.z.string().length(3),
2192
+ receiptId: import_zod7.z.string().nullable(),
2193
+ status: import_zod7.z.enum(["SETTLED", "REVIEW", "REJECTED"]),
2194
+ issuerSig: import_zod7.z.string(),
2195
+ createdAtMs: import_zod7.z.number().int().nonnegative()
2521
2196
  });
2522
- var SettleResponseSchema = import_zod8.z.object({
2197
+ var SettleResponseSchema = import_zod7.z.object({
2523
2198
  settlement: SettlementSchema,
2524
- encounterId: import_zod8.z.string().regex(/^[0-9a-f]{64}$/i),
2525
- replayed: import_zod8.z.boolean()
2199
+ encounterId: import_zod7.z.string().regex(/^[0-9a-f]{64}$/i),
2200
+ replayed: import_zod7.z.boolean()
2526
2201
  });
2527
2202
  var ENCOUNTER_DOMAIN = "offline:v1:encounter";
2528
2203
  async function sha256Hex(input) {
@@ -2696,7 +2371,7 @@ function createHmacFetch(opts) {
2696
2371
  }
2697
2372
 
2698
2373
  // src/partner/client.ts
2699
- var import_zod9 = require("zod");
2374
+ var import_zod8 = require("zod");
2700
2375
  var import_sha2563 = require("@noble/hashes/sha256");
2701
2376
  var import_hmac4 = require("@noble/hashes/hmac");
2702
2377
  var import_utils2 = require("@noble/hashes/utils");
@@ -2720,18 +2395,18 @@ var PARTNER_SCOPES = [
2720
2395
  "partner:payout:write",
2721
2396
  "partner:reconciliation:read"
2722
2397
  ];
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()
2398
+ var ApiCredentialPublicSchema = import_zod8.z.object({
2399
+ id: import_zod8.z.string().uuid(),
2400
+ accountId: import_zod8.z.string().uuid(),
2401
+ keyId: import_zod8.z.string(),
2402
+ scopes: import_zod8.z.array(import_zod8.z.enum(PARTNER_SCOPES)),
2403
+ label: import_zod8.z.string().nullable(),
2404
+ createdAtMs: import_zod8.z.number().int().nonnegative(),
2405
+ lastUsedAtMs: import_zod8.z.number().int().nonnegative().nullable(),
2406
+ revokedAtMs: import_zod8.z.number().int().nonnegative().nullable()
2732
2407
  });
2733
2408
  var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2734
- secret: import_zod9.z.string().min(1)
2409
+ secret: import_zod8.z.string().min(1)
2735
2410
  });
2736
2411
  var enc = new TextEncoder();
2737
2412
  async function sha256Hex2(input) {
@@ -2888,8 +2563,8 @@ function createApiCredentialsAdminClient(opts) {
2888
2563
  }
2889
2564
  return parser(raw);
2890
2565
  }
2891
- const listSchema = import_zod9.z.object({
2892
- items: import_zod9.z.array(ApiCredentialPublicSchema)
2566
+ const listSchema = import_zod8.z.object({
2567
+ items: import_zod8.z.array(ApiCredentialPublicSchema)
2893
2568
  });
2894
2569
  return {
2895
2570
  list: (accountId) => call(
@@ -2914,7 +2589,7 @@ function createApiCredentialsAdminClient(opts) {
2914
2589
  }
2915
2590
 
2916
2591
  // src/passes/pass.ts
2917
- var import_zod10 = require("zod");
2592
+ var import_zod9 = require("zod");
2918
2593
  var PASS_KINDS = [
2919
2594
  "ride-ticket",
2920
2595
  "transit-pass",
@@ -2930,39 +2605,39 @@ var PASS_STATES = [
2930
2605
  "expired",
2931
2606
  "revoked"
2932
2607
  ];
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()])
2608
+ var PassMetadataSchema = import_zod9.z.record(
2609
+ import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number(), import_zod9.z.boolean(), import_zod9.z.null()])
2935
2610
  );
2936
- var PassSchema = import_zod10.z.object({
2937
- passId: import_zod10.z.string().min(1),
2611
+ var PassSchema = import_zod9.z.object({
2612
+ passId: import_zod9.z.string().min(1),
2938
2613
  /** Optional client/template grouping id (server may omit). */
2939
- templateId: import_zod10.z.string().min(1).optional(),
2614
+ templateId: import_zod9.z.string().min(1).optional(),
2940
2615
  /** Optional human-facing holder identity (server may omit). The cryptographic binding
2941
2616
  * is `holderDevicePubkey` below. */
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),
2617
+ holderUserId: import_zod9.z.string().min(1).optional(),
2618
+ kind: import_zod9.z.enum(PASS_KINDS),
2619
+ issuerId: import_zod9.z.string().min(1),
2620
+ issuedAtMs: import_zod9.z.number().int().nonnegative(),
2621
+ validFromMs: import_zod9.z.number().int().nonnegative(),
2622
+ validUntilMs: import_zod9.z.number().int().positive(),
2623
+ state: import_zod9.z.enum(PASS_STATES),
2949
2624
  metadata: PassMetadataSchema,
2950
- nonce: import_zod10.z.string().min(1),
2625
+ nonce: import_zod9.z.string().min(1),
2951
2626
  /** Device id this pass is bound to (FK to backend `device_keys`). */
2952
- holderDeviceId: import_zod10.z.string().min(1),
2627
+ holderDeviceId: import_zod9.z.string().min(1),
2953
2628
  /** SubjectPublicKeyInfo DER (P-256) of the bound device, base64. The redemption
2954
2629
  * 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}$/),
2630
+ holderDevicePubkey: import_zod9.z.string().min(64).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2956
2631
  /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
2957
- amountKobo: import_zod10.z.number().int().nonnegative().optional(),
2632
+ amountKobo: import_zod9.z.number().int().nonnegative().optional(),
2958
2633
  /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
2959
- currency: import_zod10.z.string().min(3).max(8),
2634
+ currency: import_zod9.z.string().min(3).max(8),
2960
2635
  /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
2961
- counterSeed: import_zod10.z.number().int().nonnegative(),
2636
+ counterSeed: import_zod9.z.number().int().nonnegative(),
2962
2637
  /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
2963
- cumulativeCapKobo: import_zod10.z.number().int().nonnegative().optional(),
2638
+ cumulativeCapKobo: import_zod9.z.number().int().nonnegative().optional(),
2964
2639
  /** 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}$/)
2640
+ issuerSig: import_zod9.z.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2966
2641
  }).refine((v) => v.validUntilMs > v.validFromMs, {
2967
2642
  message: "validUntilMs must be greater than validFromMs"
2968
2643
  });
@@ -3019,20 +2694,20 @@ function isPassWithinValidity(pass, nowMs) {
3019
2694
  }
3020
2695
 
3021
2696
  // src/passes/redemption.ts
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({
2697
+ var import_zod10 = require("zod");
2698
+ var Base64Std2 = import_zod10.z.string().min(16).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (std)");
2699
+ var RedemptionSchema = import_zod10.z.object({
3025
2700
  pass: PassSchema,
3026
- redeemerId: import_zod11.z.string().min(1),
3027
- redeemedAtMs: import_zod11.z.number().int().nonnegative(),
2701
+ redeemerId: import_zod10.z.string().min(1),
2702
+ redeemedAtMs: import_zod10.z.number().int().nonnegative(),
3028
2703
  /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
3029
2704
  * and > the redeemer's lastSeenCounter for this pass. */
3030
- counter: import_zod11.z.number().int().positive(),
2705
+ counter: import_zod10.z.number().int().positive(),
3031
2706
  /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
3032
- amountKobo: import_zod11.z.number().int().nonnegative(),
3033
- nonce: import_zod11.z.string().min(1),
2707
+ amountKobo: import_zod10.z.number().int().nonnegative(),
2708
+ nonce: import_zod10.z.string().min(1),
3034
2709
  /** ASN.1 DER ECDSA P-256 signature over canonicalJSONBytes(unsigned), base64. */
3035
- holderSig: Base64Std3
2710
+ holderSig: Base64Std2
3036
2711
  });
3037
2712
  var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
3038
2713
  function buildRedemption(input) {
@@ -3114,40 +2789,40 @@ function verifyRedemption(r, issuerPublicKeySpkiB64) {
3114
2789
  }
3115
2790
 
3116
2791
  // src/receipts/receipt.ts
3117
- var import_zod12 = require("zod");
2792
+ var import_zod11 = require("zod");
3118
2793
  var RECEIPT_CHANNELS = ["cash", "pass"];
3119
2794
  var RECEIPT_KINDS = RECEIPT_CHANNELS;
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()])
2795
+ var ReceiptPayloadSchema = import_zod11.z.record(
2796
+ import_zod11.z.union([import_zod11.z.string(), import_zod11.z.number(), import_zod11.z.boolean(), import_zod11.z.null()])
3122
2797
  );
3123
- var ReceiptSchema = import_zod12.z.object({
3124
- receiptId: import_zod12.z.string().min(1),
3125
- channel: import_zod12.z.enum(RECEIPT_CHANNELS),
2798
+ var ReceiptSchema = import_zod11.z.object({
2799
+ receiptId: import_zod11.z.string().min(1),
2800
+ channel: import_zod11.z.enum(RECEIPT_CHANNELS),
3126
2801
  /** Cash-channel: send_intents.id. Required when channel === 'cash'. */
3127
- intentId: import_zod12.z.string().min(1).optional(),
2802
+ intentId: import_zod11.z.string().min(1).optional(),
3128
2803
  /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
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),
2804
+ passRedemptionId: import_zod11.z.string().min(1).optional(),
2805
+ payerUserId: import_zod11.z.string().min(1),
2806
+ payeeUserId: import_zod11.z.string().min(1),
2807
+ amountKobo: import_zod11.z.number().int().nonnegative(),
2808
+ currency: import_zod11.z.string().min(3).max(8),
2809
+ issuedAtMs: import_zod11.z.number().int().nonnegative(),
2810
+ issuerId: import_zod11.z.string().min(1),
3136
2811
  payload: ReceiptPayloadSchema,
3137
2812
  /** 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}$/)
2813
+ issuerSig: import_zod11.z.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
3139
2814
  }).superRefine((v, ctx) => {
3140
2815
  if (v.channel === "cash") {
3141
2816
  if (!v.intentId) {
3142
2817
  ctx.addIssue({
3143
- code: import_zod12.z.ZodIssueCode.custom,
2818
+ code: import_zod11.z.ZodIssueCode.custom,
3144
2819
  message: "cash receipts require intentId",
3145
2820
  path: ["intentId"]
3146
2821
  });
3147
2822
  }
3148
2823
  if (v.passRedemptionId) {
3149
2824
  ctx.addIssue({
3150
- code: import_zod12.z.ZodIssueCode.custom,
2825
+ code: import_zod11.z.ZodIssueCode.custom,
3151
2826
  message: "cash receipts must not carry passRedemptionId",
3152
2827
  path: ["passRedemptionId"]
3153
2828
  });
@@ -3155,14 +2830,14 @@ var ReceiptSchema = import_zod12.z.object({
3155
2830
  } else if (v.channel === "pass") {
3156
2831
  if (!v.passRedemptionId) {
3157
2832
  ctx.addIssue({
3158
- code: import_zod12.z.ZodIssueCode.custom,
2833
+ code: import_zod11.z.ZodIssueCode.custom,
3159
2834
  message: "pass receipts require passRedemptionId",
3160
2835
  path: ["passRedemptionId"]
3161
2836
  });
3162
2837
  }
3163
2838
  if (v.intentId) {
3164
2839
  ctx.addIssue({
3165
- code: import_zod12.z.ZodIssueCode.custom,
2840
+ code: import_zod11.z.ZodIssueCode.custom,
3166
2841
  message: "pass receipts must not carry intentId",
3167
2842
  path: ["intentId"]
3168
2843
  });
@@ -3464,28 +3139,244 @@ function init(opts) {
3464
3139
  }
3465
3140
 
3466
3141
  // src/accounts/client.ts
3467
- var import_zod13 = require("zod");
3142
+ var import_zod12 = require("zod");
3468
3143
  var ACCOUNT_TYPES = ["personal", "business", "partner"];
3469
3144
  var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
3470
3145
  var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
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()
3146
+ var AccountSchema = import_zod12.z.object({
3147
+ accountId: import_zod12.z.string().uuid(),
3148
+ type: import_zod12.z.enum(ACCOUNT_TYPES),
3149
+ displayName: import_zod12.z.string().min(1),
3150
+ status: import_zod12.z.enum(ACCOUNT_STATUSES),
3151
+ ownerUserId: import_zod12.z.string().uuid().nullable(),
3152
+ createdAtMs: import_zod12.z.number().int().nonnegative()
3153
+ });
3154
+ var AccountMembershipSchema = import_zod12.z.object({
3155
+ accountId: import_zod12.z.string().uuid(),
3156
+ userId: import_zod12.z.string().uuid(),
3157
+ role: import_zod12.z.enum(MEMBERSHIP_ROLES),
3158
+ createdAtMs: import_zod12.z.number().int().nonnegative()
3159
+ });
3160
+ function createAccountsClient(opts) {
3161
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3162
+ if (!fetchImpl) {
3163
+ throw new Error("createAccountsClient: no fetch implementation available");
3164
+ }
3165
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
3166
+ async function call(method, path, body, parser) {
3167
+ const init2 = {
3168
+ method,
3169
+ headers: {
3170
+ "content-type": "application/json",
3171
+ accept: "application/json"
3172
+ }
3173
+ };
3174
+ if (body !== void 0) init2.body = JSON.stringify(body);
3175
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
3176
+ const text = await resp.text();
3177
+ let raw = void 0;
3178
+ if (text) {
3179
+ try {
3180
+ raw = JSON.parse(text);
3181
+ } catch {
3182
+ }
3183
+ }
3184
+ if (!resp.ok) {
3185
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3186
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3187
+ throw new FlurApiError(resp.status, code, message, raw);
3188
+ }
3189
+ return parser(raw);
3190
+ }
3191
+ const itemsSchema = import_zod12.z.object({ items: import_zod12.z.array(AccountSchema) });
3192
+ const memberItemsSchema = import_zod12.z.object({
3193
+ items: import_zod12.z.array(AccountMembershipSchema)
3194
+ });
3195
+ return {
3196
+ listMyAccounts: () => call(
3197
+ "GET",
3198
+ "/v1/accounts/me",
3199
+ void 0,
3200
+ (raw) => itemsSchema.parse(raw)
3201
+ ),
3202
+ getAccount: (accountId) => call(
3203
+ "GET",
3204
+ `/v1/accounts/${encodeURIComponent(accountId)}`,
3205
+ void 0,
3206
+ (raw) => AccountSchema.parse(raw)
3207
+ ),
3208
+ listMembers: (accountId) => call(
3209
+ "GET",
3210
+ `/v1/accounts/${encodeURIComponent(accountId)}/members`,
3211
+ void 0,
3212
+ (raw) => memberItemsSchema.parse(raw)
3213
+ ),
3214
+ createBusinessAccount: (input) => call("POST", "/v1/accounts", input, (raw) => AccountSchema.parse(raw)),
3215
+ addMember: (accountId, input) => call(
3216
+ "POST",
3217
+ `/v1/accounts/${encodeURIComponent(accountId)}/members`,
3218
+ input,
3219
+ (raw) => AccountMembershipSchema.parse(raw)
3220
+ )
3221
+ };
3222
+ }
3223
+
3224
+ // src/me-offline/client.ts
3225
+ var import_zod13 = require("zod");
3226
+ var Sha256Hex = import_zod13.z.string().regex(/^[0-9a-f]{64}$/);
3227
+ var Base64Std3 = import_zod13.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3228
+ var ClaimNonce = import_zod13.z.string().min(8).max(128).refine((value) => !value.includes("|"), {
3229
+ message: "nonce must not contain |"
3230
+ });
3231
+ var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
3232
+ var CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1e3 * 60 * 60 * 24;
3233
+ var AttestationSecurityLevelSchema = import_zod13.z.enum([
3234
+ "STRONGBOX",
3235
+ "TEE",
3236
+ "SECURE_ENCLAVE",
3237
+ "SOFTWARE"
3238
+ ]);
3239
+ var DeviceKeyAlgSchema = import_zod13.z.literal("p256");
3240
+ var RegisterDeviceKeyP256InputSchema = import_zod13.z.object({
3241
+ deviceId: import_zod13.z.string().min(1).max(128),
3242
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
3243
+ publicKeySpkiB64: Base64Std3.min(64).max(4096),
3244
+ /** Base64 of the server-issued enrollment challenge string. */
3245
+ challengeB64: Base64Std3.min(8).max(1024),
3246
+ /** iOS App Attest payload or Android X.509 Key Attestation chain. */
3247
+ attestationChainB64: import_zod13.z.array(Base64Std3.min(16).max(16384)).min(1).max(16),
3248
+ securityLevel: AttestationSecurityLevelSchema
3249
+ });
3250
+ var P256EnrollmentChallengeInputSchema = import_zod13.z.object({
3251
+ deviceId: import_zod13.z.string().min(1).max(128)
3252
+ });
3253
+ var P256EnrollmentChallengeResultSchema = import_zod13.z.object({
3254
+ challenge: import_zod13.z.string().min(16),
3255
+ expiresAtMs: import_zod13.z.number().int().positive()
3256
+ });
3257
+ var DeviceKeyRecordSchema = import_zod13.z.object({
3258
+ id: import_zod13.z.string().uuid(),
3259
+ userId: import_zod13.z.string().uuid(),
3260
+ deviceId: import_zod13.z.string(),
3261
+ /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
3262
+ alg: DeviceKeyAlgSchema.default("p256"),
3263
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
3264
+ publicKeySpkiB64: Base64Std3.nullable().default(null),
3265
+ securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
3266
+ hardwareBacked: import_zod13.z.boolean().default(false),
3267
+ attestedAtMs: import_zod13.z.number().int().nonnegative().nullable().default(null),
3268
+ createdAtMs: import_zod13.z.number().int().nonnegative(),
3269
+ revokedAtMs: import_zod13.z.number().int().nonnegative().nullable()
3270
+ });
3271
+ var ConsumerOACSchema = import_zod13.z.object({
3272
+ oacId: import_zod13.z.string().uuid(),
3273
+ issuerId: import_zod13.z.string().min(1).max(64),
3274
+ userId: import_zod13.z.string().uuid(),
3275
+ deviceId: import_zod13.z.string().min(1).max(128),
3276
+ /**
3277
+ * Always 'p256'. Required on the wire (backend always emits it).
3278
+ * Kept as a literal so input/output infer identically and the schema
3279
+ * can be nested inside other response shapes without Zod input/output
3280
+ * divergence under tsup DTS bundling.
3281
+ */
3282
+ alg: import_zod13.z.literal("p256"),
3283
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
3284
+ devicePubkeySpkiB64: Base64Std3.min(64).max(4096),
3285
+ perTxCapKobo: import_zod13.z.number().int().positive(),
3286
+ cumulativeCapKobo: import_zod13.z.number().int().positive(),
3287
+ currency: import_zod13.z.string().length(3),
3288
+ validFromMs: import_zod13.z.number().int().nonnegative(),
3289
+ validUntilMs: import_zod13.z.number().int().nonnegative(),
3290
+ counterSeed: import_zod13.z.number().int().nonnegative(),
3291
+ issuedAtMs: import_zod13.z.number().int().nonnegative()
3292
+ });
3293
+ var SignedConsumerOACSchema = import_zod13.z.object({
3294
+ oac: ConsumerOACSchema,
3295
+ /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
3296
+ issuerSig: Base64Std3.min(16).max(2048),
3297
+ /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
3298
+ issuerPublicKeySpkiB64: Base64Std3.min(64).max(4096)
3478
3299
  });
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()
3300
+ var OACRecordSchema = SignedConsumerOACSchema.extend({
3301
+ currentOfflineSpentKobo: import_zod13.z.number().int().nonnegative(),
3302
+ status: import_zod13.z.enum(["active", "superseded", "expired", "revoked"]),
3303
+ supersededAtMs: import_zod13.z.number().int().nonnegative().nullable(),
3304
+ revokedAtMs: import_zod13.z.number().int().nonnegative().nullable()
3484
3305
  });
3485
- function createAccountsClient(opts) {
3306
+ var IssueAccountOacInputSchema = import_zod13.z.object({
3307
+ deviceId: import_zod13.z.string().min(1).max(128),
3308
+ perTxCapKobo: import_zod13.z.number().int().positive().optional(),
3309
+ cumulativeCapKobo: import_zod13.z.number().int().positive().optional(),
3310
+ ttlMs: import_zod13.z.number().int().min(6e4).max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS).optional()
3311
+ });
3312
+ var OfflineStatusResultSchema = import_zod13.z.object({
3313
+ active: OACRecordSchema.nullable()
3314
+ });
3315
+ var ConsumerPaymentClaimSchema = import_zod13.z.object({
3316
+ /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
3317
+ alg: import_zod13.z.literal("p256").default("p256"),
3318
+ oacId: import_zod13.z.string().uuid(),
3319
+ encounterId: Sha256Hex.optional(),
3320
+ payerUserId: import_zod13.z.string().uuid(),
3321
+ payeeUserId: import_zod13.z.string().uuid(),
3322
+ payerDeviceId: import_zod13.z.string().min(1).max(128),
3323
+ payerNonce: ClaimNonce,
3324
+ payeeNonce: ClaimNonce,
3325
+ amountKobo: import_zod13.z.number().int().positive(),
3326
+ currency: import_zod13.z.string().length(3).default("NGN"),
3327
+ occurredAtMs: import_zod13.z.number().int().nonnegative(),
3328
+ completedAtMs: import_zod13.z.number().int().nonnegative().optional(),
3329
+ contextId: import_zod13.z.string().max(128).optional(),
3330
+ requestId: import_zod13.z.string().uuid().optional(),
3331
+ requestMode: import_zod13.z.enum(["fixed", "editable"]).optional(),
3332
+ requestTakerUserId: import_zod13.z.string().uuid().optional(),
3333
+ requestAmountKobo: import_zod13.z.number().int().positive().optional(),
3334
+ requestCurrency: import_zod13.z.string().length(3).optional(),
3335
+ requestReference: import_zod13.z.string().max(128).nullable().optional(),
3336
+ requestCreatedAtMs: import_zod13.z.number().int().nonnegative().optional(),
3337
+ requestExpiresAtMs: import_zod13.z.number().int().positive().optional(),
3338
+ requestNonce: import_zod13.z.string().min(8).max(128).optional(),
3339
+ requestTakerDeviceId: import_zod13.z.string().min(1).max(128).nullable().optional(),
3340
+ requestTakerPubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
3341
+ requestTakerSignatureDerB64: Base64Std3.min(16).max(2048).optional(),
3342
+ payerPubkeySpkiB64: Base64Std3.min(64).max(4096),
3343
+ payerSignatureDerB64: Base64Std3.min(16).max(2048),
3344
+ payeePubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
3345
+ payeeSignatureDerB64: Base64Std3.min(16).max(2048).optional()
3346
+ });
3347
+ var ConsumerSettlementSchema = import_zod13.z.object({
3348
+ settlementId: import_zod13.z.string().uuid(),
3349
+ settlementKey: Sha256Hex,
3350
+ encounterId: Sha256Hex,
3351
+ oacId: import_zod13.z.string().uuid(),
3352
+ payerUserId: import_zod13.z.string().uuid(),
3353
+ payeeUserId: import_zod13.z.string().uuid(),
3354
+ amountKobo: import_zod13.z.number().int().positive(),
3355
+ currency: import_zod13.z.string().length(3),
3356
+ status: import_zod13.z.enum(["SETTLED", "REVIEW"]),
3357
+ reviewReason: import_zod13.z.string().nullable(),
3358
+ ledgerRef: import_zod13.z.string().nullable(),
3359
+ /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
3360
+ issuerSig: Base64Std3.min(16).max(2048),
3361
+ /** Canonical millisecond timestamp signed into the settlement receipt. */
3362
+ issuedAtMs: import_zod13.z.number().int().nonnegative(),
3363
+ /** Compatibility alias for API consumers that predate issuedAtMs. */
3364
+ createdAtMs: import_zod13.z.number().int().nonnegative().optional()
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) {
3486
3377
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3487
3378
  if (!fetchImpl) {
3488
- throw new Error("createAccountsClient: no fetch implementation available");
3379
+ throw new Error("createMeOfflineClient: no fetch implementation available");
3489
3380
  }
3490
3381
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
3491
3382
  async function call(method, path, body, parser) {
@@ -3513,42 +3404,67 @@ function createAccountsClient(opts) {
3513
3404
  }
3514
3405
  return parser(raw);
3515
3406
  }
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)
3519
- });
3407
+ const deviceKeyItems = import_zod13.z.object({ items: import_zod13.z.array(DeviceKeyRecordSchema) });
3520
3408
  return {
3521
- listMyAccounts: () => call(
3522
- "GET",
3523
- "/v1/accounts/me",
3524
- void 0,
3525
- (raw) => itemsSchema.parse(raw)
3409
+ issueP256EnrollmentChallenge: (input) => call(
3410
+ "POST",
3411
+ "/v1/me/offline/keys/p256/challenge",
3412
+ P256EnrollmentChallengeInputSchema.parse(input),
3413
+ (raw) => P256EnrollmentChallengeResultSchema.parse(raw)
3526
3414
  ),
3527
- getAccount: (accountId) => call(
3528
- "GET",
3529
- `/v1/accounts/${encodeURIComponent(accountId)}`,
3530
- void 0,
3531
- (raw) => AccountSchema.parse(raw)
3415
+ registerDeviceKeyP256: (input) => call(
3416
+ "POST",
3417
+ "/v1/me/offline/keys/p256",
3418
+ RegisterDeviceKeyP256InputSchema.parse(input),
3419
+ (raw) => DeviceKeyRecordSchema.parse(raw)
3532
3420
  ),
3533
- listMembers: (accountId) => call(
3421
+ listDeviceKeys: () => call(
3534
3422
  "GET",
3535
- `/v1/accounts/${encodeURIComponent(accountId)}/members`,
3423
+ "/v1/me/offline/keys",
3536
3424
  void 0,
3537
- (raw) => memberItemsSchema.parse(raw)
3425
+ (raw) => deviceKeyItems.parse(raw)
3538
3426
  ),
3539
- createBusinessAccount: (input) => call("POST", "/v1/accounts", input, (raw) => AccountSchema.parse(raw)),
3540
- addMember: (accountId, input) => call(
3427
+ revokeDeviceKey: (input) => call(
3541
3428
  "POST",
3542
- `/v1/accounts/${encodeURIComponent(accountId)}/members`,
3543
- input,
3544
- (raw) => AccountMembershipSchema.parse(raw)
3429
+ "/v1/me/offline/keys/revoke",
3430
+ RevokeDeviceKeyInputSchema.parse(input),
3431
+ () => void 0
3432
+ ),
3433
+ issueAccountOac: (input) => call(
3434
+ "POST",
3435
+ "/v1/me/offline/oac",
3436
+ IssueAccountOacInputSchema.parse(input),
3437
+ (raw) => OACRecordSchema.parse(raw)
3438
+ ),
3439
+ getStatus: (deviceId) => {
3440
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3441
+ return call(
3442
+ "GET",
3443
+ `/v1/me/offline/status${qs}`,
3444
+ void 0,
3445
+ (raw) => OfflineStatusResultSchema.parse(raw)
3446
+ );
3447
+ },
3448
+ submitClaim: (claim) => call(
3449
+ "POST",
3450
+ "/v1/me/offline/claims",
3451
+ ConsumerPaymentClaimSchema.parse(claim),
3452
+ (raw) => ConsumerSettleResultSchema.parse(raw)
3453
+ ),
3454
+ getSettlement: (idOrKey) => call(
3455
+ "GET",
3456
+ `/v1/me/offline/settlements/${encodeURIComponent(idOrKey)}`,
3457
+ void 0,
3458
+ (raw) => ConsumerSettlementSchema.parse(raw)
3545
3459
  )
3546
3460
  };
3547
3461
  }
3548
3462
 
3549
3463
  // src/me-offline/signer.ts
3550
3464
  var import_nist2 = require("@noble/curves/nist");
3465
+ var import_sha2 = require("@noble/hashes/sha2");
3551
3466
  var CLAIM_DOMAIN_V2 = "flur:consumer-offline:v2:claim";
3467
+ var ENCOUNTER_DOMAIN2 = "flur:consumer-offline:v1:encounter";
3552
3468
  function canonicalClaimSigningPayload(claim) {
3553
3469
  return {
3554
3470
  domain: CLAIM_DOMAIN_V2,
@@ -3569,6 +3485,27 @@ function canonicalClaimSigningPayload(claim) {
3569
3485
  function canonicalClaimSigningBytes(claim) {
3570
3486
  return canonicalJSONBytes(canonicalClaimSigningPayload(claim));
3571
3487
  }
3488
+ function computeConsumerClaimEncounterId(input) {
3489
+ const material = `${ENCOUNTER_DOMAIN2}|${[
3490
+ assertEncounterPart("oacId", input.oacId),
3491
+ assertEncounterPart("payerUserId", input.payerUserId),
3492
+ assertEncounterPart("payeeUserId", input.payeeUserId),
3493
+ assertEncounterPart("payerNonce", input.payerNonce),
3494
+ assertEncounterPart("payeeNonce", input.payeeNonce)
3495
+ ].join("|")}`;
3496
+ return bytesToHex5((0, import_sha2.sha256)(new TextEncoder().encode(material)));
3497
+ }
3498
+ function assertEncounterPart(field, value) {
3499
+ if (value.includes("|")) {
3500
+ throw new Error(`consumer encounter id ${field} must not contain |`);
3501
+ }
3502
+ return value;
3503
+ }
3504
+ function bytesToHex5(bytes) {
3505
+ let out = "";
3506
+ for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
3507
+ return out;
3508
+ }
3572
3509
  function bytesToBase642(bytes) {
3573
3510
  if (typeof Buffer !== "undefined") {
3574
3511
  return Buffer.from(bytes).toString("base64");
@@ -3664,38 +3601,192 @@ function verifyClaimSignature(input) {
3664
3601
  }
3665
3602
  }
3666
3603
 
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)}`;
3604
+ // src/me-offline/request.ts
3605
+ var import_zod14 = require("zod");
3606
+ var Base64Std4 = import_zod14.z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
3607
+ var CONSUMER_PAYMENT_REQUEST_DOMAIN = "flur:consumer-offline:v1:request";
3608
+ var ConsumerPaymentRequestEnvelopeSchema = import_zod14.z.object({
3609
+ requestId: import_zod14.z.string().uuid(),
3610
+ mode: import_zod14.z.enum(["fixed", "editable"]),
3611
+ takerUserId: import_zod14.z.string().uuid(),
3612
+ amountKobo: import_zod14.z.number().int().positive(),
3613
+ currency: import_zod14.z.string().length(3).default("NGN"),
3614
+ reference: import_zod14.z.string().max(128).nullable().default(null),
3615
+ createdAtMs: import_zod14.z.number().int().nonnegative(),
3616
+ expiresAtMs: import_zod14.z.number().int().positive(),
3617
+ nonce: import_zod14.z.string().min(8).max(128),
3618
+ takerDeviceId: import_zod14.z.string().min(1).max(128).nullable().default(null),
3619
+ takerPubkeySpkiB64: Base64Std4.min(64).max(4096).optional(),
3620
+ takerSignatureDerB64: Base64Std4.min(16).max(2048).optional()
3621
+ }).superRefine((value, ctx) => {
3622
+ if (value.expiresAtMs <= value.createdAtMs) {
3623
+ ctx.addIssue({
3624
+ code: import_zod14.z.ZodIssueCode.custom,
3625
+ path: ["expiresAtMs"],
3626
+ message: "expiresAtMs must be greater than createdAtMs"
3627
+ });
3628
+ }
3629
+ const hasSignature = Boolean(
3630
+ value.takerPubkeySpkiB64 || value.takerSignatureDerB64
3631
+ );
3632
+ if (value.mode === "fixed" || hasSignature) {
3633
+ if (!value.takerDeviceId) {
3634
+ ctx.addIssue({
3635
+ code: import_zod14.z.ZodIssueCode.custom,
3636
+ path: ["takerDeviceId"],
3637
+ message: "signed requests require takerDeviceId"
3638
+ });
3639
+ }
3640
+ if (!value.takerPubkeySpkiB64) {
3641
+ ctx.addIssue({
3642
+ code: import_zod14.z.ZodIssueCode.custom,
3643
+ path: ["takerPubkeySpkiB64"],
3644
+ message: "signed requests require takerPubkeySpkiB64"
3645
+ });
3646
+ }
3647
+ if (!value.takerSignatureDerB64) {
3648
+ ctx.addIssue({
3649
+ code: import_zod14.z.ZodIssueCode.custom,
3650
+ path: ["takerSignatureDerB64"],
3651
+ message: "signed requests require takerSignatureDerB64"
3652
+ });
3653
+ }
3654
+ }
3655
+ });
3656
+ function buildConsumerPaymentRequest(input) {
3657
+ const unsigned = {
3658
+ requestId: input.requestId,
3659
+ mode: input.mode,
3660
+ takerUserId: input.takerUserId,
3661
+ amountKobo: input.amountKobo,
3662
+ currency: input.currency ?? "NGN",
3663
+ reference: input.reference ?? null,
3664
+ createdAtMs: input.createdAtMs,
3665
+ expiresAtMs: input.expiresAtMs,
3666
+ nonce: input.nonce,
3667
+ takerDeviceId: input.takerDeviceId ?? null
3668
+ };
3669
+ if (unsigned.mode === "fixed" && !unsigned.takerDeviceId) {
3670
+ throw new Error("fixed requests require takerDeviceId");
3671
+ }
3672
+ if (unsigned.expiresAtMs <= unsigned.createdAtMs) {
3673
+ throw new Error("expiresAtMs must be greater than createdAtMs");
3674
+ }
3675
+ return unsigned;
3674
3676
  }
3675
- function decodeOfflineClaimSmsMessage(message) {
3676
- const token = extractOfflineClaimSmsToken(message);
3677
- if (!token) {
3678
- throw new Error("offline claim SMS token not found");
3677
+ function consumerPaymentRequestSigningPayload(request) {
3678
+ return {
3679
+ domain: CONSUMER_PAYMENT_REQUEST_DOMAIN,
3680
+ version: 1,
3681
+ requestId: request.requestId,
3682
+ mode: request.mode,
3683
+ takerUserId: request.takerUserId,
3684
+ amountKobo: request.amountKobo,
3685
+ currency: request.currency,
3686
+ reference: request.reference ?? null,
3687
+ createdAtMs: request.createdAtMs,
3688
+ expiresAtMs: request.expiresAtMs,
3689
+ nonce: request.nonce,
3690
+ takerDeviceId: request.takerDeviceId ?? null
3691
+ };
3692
+ }
3693
+ function consumerPaymentRequestSigningBytes(request) {
3694
+ return canonicalJSONBytes(consumerPaymentRequestSigningPayload(request));
3695
+ }
3696
+ async function signConsumerPaymentRequest(unsigned, signer) {
3697
+ if (signer.alg !== "p256") {
3698
+ throw new Error("consumer payment requests require p256 signer");
3679
3699
  }
3680
- const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);
3700
+ const publicKey = await signer.getPublicKey();
3701
+ if (publicKey.alg !== "p256") {
3702
+ throw new Error("consumer payment requests require p256 public key");
3703
+ }
3704
+ const signature = await signer.sign(
3705
+ consumerPaymentRequestSigningBytes(unsigned)
3706
+ );
3707
+ return ConsumerPaymentRequestEnvelopeSchema.parse({
3708
+ ...unsigned,
3709
+ takerPubkeySpkiB64: publicKey.publicKey,
3710
+ takerSignatureDerB64: signature.signature
3711
+ });
3712
+ }
3713
+ function verifyConsumerPaymentRequest(request) {
3714
+ const parsed = ConsumerPaymentRequestEnvelopeSchema.safeParse(request);
3715
+ if (!parsed.success) return false;
3716
+ const value = parsed.data;
3717
+ if (!value.takerPubkeySpkiB64 || !value.takerSignatureDerB64) return false;
3718
+ return verifyClaimSignature({
3719
+ alg: "p256",
3720
+ bytes: consumerPaymentRequestSigningBytes(value),
3721
+ signature: value.takerSignatureDerB64,
3722
+ publicKey: value.takerPubkeySpkiB64
3723
+ });
3724
+ }
3725
+ function isConsumerPaymentRequestExpired(request, nowMs = Date.now()) {
3726
+ const parsed = ConsumerPaymentRequestEnvelopeSchema.parse(request);
3727
+ return parsed.expiresAtMs <= nowMs;
3728
+ }
3729
+
3730
+ // src/me-offline/settlement.ts
3731
+ var CONSUMER_SETTLEMENT_DOMAIN = "flur:consumer-offline:v1:settlement";
3732
+ var CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX = "FLURSR1.";
3733
+ function consumerSettlementSigningPayload(settlement) {
3734
+ return {
3735
+ domain: CONSUMER_SETTLEMENT_DOMAIN,
3736
+ settlementId: settlement.settlementId,
3737
+ settlementKey: settlement.settlementKey,
3738
+ encounterId: settlement.encounterId,
3739
+ oacId: settlement.oacId,
3740
+ payerUserId: settlement.payerUserId,
3741
+ payeeUserId: settlement.payeeUserId,
3742
+ amountKobo: settlement.amountKobo,
3743
+ currency: settlement.currency,
3744
+ status: settlement.status,
3745
+ reviewReason: settlement.reviewReason,
3746
+ ledgerRef: settlement.ledgerRef,
3747
+ issuedAtMs: settlement.issuedAtMs
3748
+ };
3749
+ }
3750
+ function verifyConsumerSettlement(settlement, issuerPublicKeySpkiB64) {
3751
+ const parsed = ConsumerSettlementSchema.safeParse(settlement);
3752
+ if (!parsed.success) return false;
3753
+ return verifyIssuerP256(
3754
+ canonicalJSONBytes(consumerSettlementSigningPayload(parsed.data)),
3755
+ parsed.data.issuerSig,
3756
+ issuerPublicKeySpkiB64
3757
+ );
3758
+ }
3759
+ function encodeConsumerSettlementReceiptQR(settlement) {
3760
+ const parsed = ConsumerSettlementSchema.parse(settlement);
3761
+ return `${CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX}${base64UrlEncodeUtf8(
3762
+ JSON.stringify(parsed)
3763
+ )}`;
3764
+ }
3765
+ function decodeUnverifiedConsumerSettlementReceiptQR(value) {
3766
+ if (!value.startsWith(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX)) {
3767
+ throw new Error("not a Flur consumer settlement receipt QR");
3768
+ }
3769
+ const encoded = value.slice(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX.length);
3681
3770
  let raw;
3682
3771
  try {
3683
3772
  raw = JSON.parse(base64UrlDecodeUtf8(encoded));
3684
3773
  } catch {
3685
- throw new Error("offline claim SMS token is malformed");
3774
+ throw new Error("consumer settlement receipt QR is malformed");
3686
3775
  }
3687
- const parsed = ConsumerPaymentClaimSchema.safeParse(raw);
3688
- if (!parsed.success) {
3689
- throw new Error("offline claim SMS token is invalid");
3776
+ return ConsumerSettlementSchema.parse(raw);
3777
+ }
3778
+ function verifyConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64) {
3779
+ const settlement = decodeUnverifiedConsumerSettlementReceiptQR(value);
3780
+ if (!verifyConsumerSettlement(settlement, issuerPublicKeySpkiB64)) {
3781
+ throw new Error("consumer settlement receipt QR signature invalid");
3690
3782
  }
3691
- return parsed.data;
3783
+ return settlement;
3692
3784
  }
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;
3785
+ function decodeConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64) {
3786
+ if (!issuerPublicKeySpkiB64) {
3787
+ return decodeUnverifiedConsumerSettlementReceiptQR(value);
3697
3788
  }
3698
- return TOKEN_RE.exec(message)?.[1] ?? null;
3789
+ return verifyConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64);
3699
3790
  }
3700
3791
  function base64UrlEncodeUtf8(input) {
3701
3792
  const bytes = new TextEncoder().encode(input);
@@ -3725,15 +3816,281 @@ function base64UrlDecodeUtf8(input) {
3725
3816
  throw new Error("base64 decoder unavailable");
3726
3817
  }
3727
3818
 
3819
+ // src/me-offline/sms.ts
3820
+ var import_nist3 = require("@noble/curves/nist");
3821
+ var OFFLINE_CLAIM_SMS_PREFIX = "FLURC1.";
3822
+ var CLAIM_TOKEN_RE = /(?:^|\s)(FLURC1\.[A-Za-z0-9_-]+={0,2})(?:\s|$)/;
3823
+ function encodeOfflineClaimSmsMessage(claim) {
3824
+ const parsed = ConsumerPaymentClaimSchema.parse(claim);
3825
+ return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf82(
3826
+ JSON.stringify(parsed)
3827
+ )}`;
3828
+ }
3829
+ function decodeOfflineClaimSmsMessage(message) {
3830
+ const token = extractOfflineClaimSmsToken(message);
3831
+ if (!token) throw new Error("offline claim QR token not found");
3832
+ const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);
3833
+ let raw;
3834
+ try {
3835
+ raw = JSON.parse(base64UrlDecodeUtf82(encoded));
3836
+ } catch {
3837
+ throw new Error("offline claim QR token is malformed");
3838
+ }
3839
+ const parsed = ConsumerPaymentClaimSchema.safeParse(raw);
3840
+ if (!parsed.success) throw new Error("offline claim QR token is invalid");
3841
+ return parsed.data;
3842
+ }
3843
+ function extractOfflineClaimSmsToken(message) {
3844
+ const trimmed = message.trim();
3845
+ if (trimmed.startsWith(OFFLINE_CLAIM_SMS_PREFIX)) {
3846
+ return trimmed.split(/\s+/, 1)[0] ?? null;
3847
+ }
3848
+ return CLAIM_TOKEN_RE.exec(message)?.[1] ?? null;
3849
+ }
3850
+ var OFFLINE_SMS_SETTLE_PREFIX = "FLURA1.";
3851
+ var OFFLINE_SMS_SETTLE_DOMAIN = "flur:consumer-offline:v1:attest";
3852
+ var OFFLINE_SMS_SETTLE_TOKEN_BYTES = 112;
3853
+ var OFFLINE_SMS_SETTLE_HEADER_BYTES = 48;
3854
+ var OFFLINE_SMS_SETTLE_SIGNATURE_BYTES = 64;
3855
+ var OFFLINE_SMS_SETTLE_VERSION = 1;
3856
+ var TOKEN_RE = /(?:^|[\s,;:()<>"'])(FLURA1\.[A-Za-z0-9_-]{150})/;
3857
+ async function encodeOfflineSmsSettleToken(input, signer) {
3858
+ const header = await buildSmsSettleHeader(input);
3859
+ const sig = await signer.signRaw(domainTag(header));
3860
+ if (sig.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {
3861
+ throw new Error(
3862
+ `FLURA1: signer returned ${sig.length}-byte sig; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`
3863
+ );
3864
+ }
3865
+ const out = new Uint8Array(OFFLINE_SMS_SETTLE_TOKEN_BYTES);
3866
+ out.set(header, 0);
3867
+ out.set(sig, OFFLINE_SMS_SETTLE_HEADER_BYTES);
3868
+ return `${OFFLINE_SMS_SETTLE_PREFIX}${bytesToBase64Url(out)}`;
3869
+ }
3870
+ async function buildSmsSettleHeader(input) {
3871
+ assertSafeUint64(input.amountKobo, "amountKobo");
3872
+ if (input.amountKobo <= 0) {
3873
+ throw new Error("FLURA1: amountKobo must be greater than zero");
3874
+ }
3875
+ assertSafeUint48(input.occurredAtMs, "occurredAtMs");
3876
+ const encounterPrefix = (await sha2565(utf8(input.encounterId))).slice(0, 16);
3877
+ const payerPrefix = uuidToBytes(input.payerUserId).slice(0, 8);
3878
+ const payeePrefix = uuidToBytes(input.payeeUserId).slice(0, 8);
3879
+ const header = new Uint8Array(OFFLINE_SMS_SETTLE_HEADER_BYTES);
3880
+ const dv = new DataView(header.buffer);
3881
+ header[0] = OFFLINE_SMS_SETTLE_VERSION;
3882
+ header[1] = 0;
3883
+ header.set(encounterPrefix, 2);
3884
+ header.set(payerPrefix, 18);
3885
+ header.set(payeePrefix, 26);
3886
+ writeUint64BE(dv, 34, input.amountKobo);
3887
+ writeUint48BE(dv, 42, input.occurredAtMs);
3888
+ return header;
3889
+ }
3890
+ function domainTag(header) {
3891
+ if (header.length !== OFFLINE_SMS_SETTLE_HEADER_BYTES) {
3892
+ throw new Error(
3893
+ `FLURA1: header must be ${OFFLINE_SMS_SETTLE_HEADER_BYTES} bytes`
3894
+ );
3895
+ }
3896
+ const domain = utf8(OFFLINE_SMS_SETTLE_DOMAIN);
3897
+ const out = new Uint8Array(domain.length + header.length);
3898
+ out.set(domain, 0);
3899
+ out.set(header, domain.length);
3900
+ return out;
3901
+ }
3902
+ function decodeOfflineSmsSettleToken(message) {
3903
+ const token = extractOfflineSmsSettleToken(message);
3904
+ if (!token) throw new Error("FLURA1: token not found");
3905
+ const encoded = token.slice(OFFLINE_SMS_SETTLE_PREFIX.length);
3906
+ let bytes;
3907
+ try {
3908
+ bytes = base64UrlToBytes(encoded);
3909
+ } catch {
3910
+ throw new Error("FLURA1: token base64url is malformed");
3911
+ }
3912
+ if (bytesToBase64Url(bytes) !== encoded) {
3913
+ throw new Error("FLURA1: token base64url is malformed");
3914
+ }
3915
+ if (bytes.length !== OFFLINE_SMS_SETTLE_TOKEN_BYTES) {
3916
+ throw new Error(
3917
+ `FLURA1: expected ${OFFLINE_SMS_SETTLE_TOKEN_BYTES} bytes, got ${bytes.length}`
3918
+ );
3919
+ }
3920
+ const version = bytes[0];
3921
+ const flags = bytes[1];
3922
+ if (version !== OFFLINE_SMS_SETTLE_VERSION) {
3923
+ throw new Error(`FLURA1: unsupported version ${version}`);
3924
+ }
3925
+ if (flags !== 0) {
3926
+ throw new Error(`FLURA1: reserved flags must be 0, got ${flags}`);
3927
+ }
3928
+ const header = bytes.slice(0, OFFLINE_SMS_SETTLE_HEADER_BYTES);
3929
+ const signature = bytes.slice(OFFLINE_SMS_SETTLE_HEADER_BYTES);
3930
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
3931
+ const amountKobo = readUint64BE(dv, 34);
3932
+ if (amountKobo <= 0) {
3933
+ throw new Error("FLURA1: amountKobo must be greater than zero");
3934
+ }
3935
+ return {
3936
+ version,
3937
+ flags,
3938
+ encounterIdPrefixHex: bytesToHex6(bytes.slice(2, 18)),
3939
+ payerUserIdPrefixHex: bytesToHex6(bytes.slice(18, 26)),
3940
+ payeeUserIdPrefixHex: bytesToHex6(bytes.slice(26, 34)),
3941
+ amountKobo,
3942
+ occurredAtMs: readUint48BE(dv, 42),
3943
+ signature,
3944
+ header,
3945
+ signedBytes: domainTag(header)
3946
+ };
3947
+ }
3948
+ function extractOfflineSmsSettleToken(message) {
3949
+ const trimmed = message.trim();
3950
+ if (trimmed.startsWith(OFFLINE_SMS_SETTLE_PREFIX)) {
3951
+ return trimmed.split(/\s+/, 1)[0] ?? null;
3952
+ }
3953
+ return TOKEN_RE.exec(message)?.[1] ?? null;
3954
+ }
3955
+ function verifyOfflineSmsSettleToken(decoded, payerPubkeySpkiB64) {
3956
+ try {
3957
+ const pubRaw = p256SpkiB64ToRaw(payerPubkeySpkiB64);
3958
+ return import_nist3.p256.verify(decoded.signature, decoded.signedBytes, pubRaw, {
3959
+ prehash: true,
3960
+ format: "compact"
3961
+ });
3962
+ } catch {
3963
+ return false;
3964
+ }
3965
+ }
3966
+ function derToRawP256Signature(derBytes) {
3967
+ const sig = import_nist3.p256.Signature.fromBytes(derBytes, "der");
3968
+ const raw = sig.toBytes("compact");
3969
+ if (raw.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {
3970
+ throw new Error(
3971
+ `FLURA1: DER\u2192raw produced ${raw.length} bytes; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`
3972
+ );
3973
+ }
3974
+ return raw;
3975
+ }
3976
+ function utf8(s) {
3977
+ return new TextEncoder().encode(s);
3978
+ }
3979
+ async function sha2565(bytes) {
3980
+ const subtle = typeof globalThis !== "undefined" && globalThis.crypto?.subtle || void 0;
3981
+ if (subtle) {
3982
+ const digest = await subtle.digest("SHA-256", bytes);
3983
+ return new Uint8Array(digest);
3984
+ }
3985
+ const { sha256: nobleSha256 } = await import("@noble/hashes/sha2");
3986
+ return nobleSha256(bytes);
3987
+ }
3988
+ function uuidToBytes(uuid) {
3989
+ const hex = uuid.replace(/-/g, "").toLowerCase();
3990
+ if (hex.length !== 32 || !/^[0-9a-f]{32}$/.test(hex)) {
3991
+ throw new Error(`FLURA1: invalid UUID: ${uuid}`);
3992
+ }
3993
+ const out = new Uint8Array(16);
3994
+ for (let i = 0; i < 16; i++) {
3995
+ out[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
3996
+ }
3997
+ return out;
3998
+ }
3999
+ function assertSafeUint64(value, field) {
4000
+ if (!Number.isInteger(value) || value < 0) {
4001
+ throw new Error(`FLURA1: ${field} must be a non-negative integer`);
4002
+ }
4003
+ if (value > Number.MAX_SAFE_INTEGER) {
4004
+ throw new Error(`FLURA1: ${field} exceeds Number.MAX_SAFE_INTEGER`);
4005
+ }
4006
+ }
4007
+ function assertSafeUint48(value, field) {
4008
+ assertSafeUint64(value, field);
4009
+ if (value > 281474976710655) {
4010
+ throw new Error(`FLURA1: ${field} exceeds uint48 range`);
4011
+ }
4012
+ }
4013
+ function writeUint64BE(dv, offset, value) {
4014
+ const high = Math.floor(value / 4294967296);
4015
+ const low = value >>> 0;
4016
+ dv.setUint32(offset, high, false);
4017
+ dv.setUint32(offset + 4, low, false);
4018
+ }
4019
+ function readUint64BE(dv, offset) {
4020
+ const high = dv.getUint32(offset, false);
4021
+ const low = dv.getUint32(offset + 4, false);
4022
+ if (high > 2097151) {
4023
+ throw new Error("FLURA1: amountKobo exceeds Number.MAX_SAFE_INTEGER");
4024
+ }
4025
+ return high * 4294967296 + low;
4026
+ }
4027
+ function writeUint48BE(dv, offset, value) {
4028
+ const high = Math.floor(value / 65536);
4029
+ const low = value & 65535;
4030
+ dv.setUint32(offset, high, false);
4031
+ dv.setUint16(offset + 4, low, false);
4032
+ }
4033
+ function readUint48BE(dv, offset) {
4034
+ const high = dv.getUint32(offset, false);
4035
+ const low = dv.getUint16(offset + 4, false);
4036
+ return high * 65536 + low;
4037
+ }
4038
+ function bytesToHex6(bytes) {
4039
+ let out = "";
4040
+ for (let i = 0; i < bytes.length; i++) {
4041
+ out += bytes[i].toString(16).padStart(2, "0");
4042
+ }
4043
+ return out;
4044
+ }
4045
+ function bytesToBase64Url(bytes) {
4046
+ let base64;
4047
+ if (typeof Buffer !== "undefined") {
4048
+ base64 = Buffer.from(bytes).toString("base64");
4049
+ } else {
4050
+ let binary = "";
4051
+ for (let i = 0; i < bytes.length; i++) {
4052
+ binary += String.fromCharCode(bytes[i]);
4053
+ }
4054
+ if (typeof btoa !== "function") {
4055
+ throw new Error("FLURA1: base64 encoder unavailable");
4056
+ }
4057
+ base64 = btoa(binary);
4058
+ }
4059
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
4060
+ }
4061
+ function base64UrlEncodeUtf82(input) {
4062
+ return bytesToBase64Url(utf8(input));
4063
+ }
4064
+ function base64UrlDecodeUtf82(input) {
4065
+ return new TextDecoder().decode(base64UrlToBytes(input));
4066
+ }
4067
+ function base64UrlToBytes(input) {
4068
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
4069
+ const padded = base64.padEnd(
4070
+ base64.length + (4 - base64.length % 4) % 4,
4071
+ "="
4072
+ );
4073
+ if (typeof Buffer !== "undefined") {
4074
+ return new Uint8Array(Buffer.from(padded, "base64"));
4075
+ }
4076
+ if (typeof atob !== "function") {
4077
+ throw new Error("FLURA1: base64 decoder unavailable");
4078
+ }
4079
+ const binary = atob(padded);
4080
+ const out = new Uint8Array(binary.length);
4081
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
4082
+ return out;
4083
+ }
4084
+
3728
4085
  // src/partner-funding/client.ts
3729
- var import_zod14 = require("zod");
3730
- var MinorString = import_zod14.z.string().regex(/^-?\d+$/);
3731
- var PositiveMinor = import_zod14.z.union([
3732
- import_zod14.z.number().int().positive(),
3733
- import_zod14.z.string().regex(/^[1-9]\d{0,18}$/)
4086
+ var import_zod15 = require("zod");
4087
+ var MinorString = import_zod15.z.string().regex(/^-?\d+$/);
4088
+ var PositiveMinor = import_zod15.z.union([
4089
+ import_zod15.z.number().int().positive(),
4090
+ import_zod15.z.string().regex(/^[1-9]\d{0,18}$/)
3734
4091
  ]);
3735
- var Currency = import_zod14.z.string().trim().length(3).transform((v) => v.toUpperCase());
3736
- var Metadata = import_zod14.z.record(import_zod14.z.unknown());
4092
+ var Currency = import_zod15.z.string().trim().length(3).transform((v) => v.toUpperCase());
4093
+ var Metadata = import_zod15.z.record(import_zod15.z.unknown());
3737
4094
  var PARTNER_KINDS = ["bank", "merchant"];
3738
4095
  var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
3739
4096
  var PARTNER_PROFILE_STATUSES = [
@@ -3760,126 +4117,126 @@ var WITHDRAWAL_STATES = [
3760
4117
  "failed",
3761
4118
  "reversed"
3762
4119
  ];
3763
- var PartnerProfileSchema = import_zod14.z.object({
3764
- partnerAccountId: import_zod14.z.string().uuid(),
3765
- kind: import_zod14.z.enum(PARTNER_KINDS),
3766
- custodialMode: import_zod14.z.enum(CUSTODIAL_MODES),
3767
- displayName: import_zod14.z.string(),
3768
- bankCode: import_zod14.z.string().nullable(),
3769
- poolAccountNumber: import_zod14.z.string().nullable(),
3770
- status: import_zod14.z.enum(PARTNER_PROFILE_STATUSES),
4120
+ var PartnerProfileSchema = import_zod15.z.object({
4121
+ partnerAccountId: import_zod15.z.string().uuid(),
4122
+ kind: import_zod15.z.enum(PARTNER_KINDS),
4123
+ custodialMode: import_zod15.z.enum(CUSTODIAL_MODES),
4124
+ displayName: import_zod15.z.string(),
4125
+ bankCode: import_zod15.z.string().nullable(),
4126
+ poolAccountNumber: import_zod15.z.string().nullable(),
4127
+ status: import_zod15.z.enum(PARTNER_PROFILE_STATUSES),
3771
4128
  metadata: Metadata,
3772
- createdAtMs: import_zod14.z.number().int().nonnegative(),
3773
- updatedAtMs: import_zod14.z.number().int().nonnegative()
4129
+ createdAtMs: import_zod15.z.number().int().nonnegative(),
4130
+ updatedAtMs: import_zod15.z.number().int().nonnegative()
3774
4131
  });
3775
- var UpsertPartnerProfileInputSchema = import_zod14.z.object({
3776
- kind: import_zod14.z.enum(PARTNER_KINDS),
3777
- custodialMode: import_zod14.z.enum(CUSTODIAL_MODES),
3778
- displayName: import_zod14.z.string().trim().min(1).max(200),
3779
- bankCode: import_zod14.z.string().trim().min(1).max(64).optional(),
3780
- poolAccountNumber: import_zod14.z.string().trim().min(1).max(64).optional(),
4132
+ var UpsertPartnerProfileInputSchema = import_zod15.z.object({
4133
+ kind: import_zod15.z.enum(PARTNER_KINDS),
4134
+ custodialMode: import_zod15.z.enum(CUSTODIAL_MODES),
4135
+ displayName: import_zod15.z.string().trim().min(1).max(200),
4136
+ bankCode: import_zod15.z.string().trim().min(1).max(64).optional(),
4137
+ poolAccountNumber: import_zod15.z.string().trim().min(1).max(64).optional(),
3781
4138
  metadata: Metadata.optional()
3782
4139
  });
3783
- var PartnerFundingEventInputSchema = import_zod14.z.object({
3784
- externalRef: import_zod14.z.string().trim().min(8).max(128),
3785
- direction: import_zod14.z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
3786
- userId: import_zod14.z.string().uuid().optional(),
3787
- accountId: import_zod14.z.string().uuid().optional(),
4140
+ var PartnerFundingEventInputSchema = import_zod15.z.object({
4141
+ externalRef: import_zod15.z.string().trim().min(8).max(128),
4142
+ direction: import_zod15.z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
4143
+ userId: import_zod15.z.string().uuid().optional(),
4144
+ accountId: import_zod15.z.string().uuid().optional(),
3788
4145
  amountMinor: PositiveMinor,
3789
4146
  currency: Currency,
3790
- fundingSource: import_zod14.z.string().trim().min(1).max(64).optional(),
4147
+ fundingSource: import_zod15.z.string().trim().min(1).max(64).optional(),
3791
4148
  providerMetadata: Metadata.optional()
3792
4149
  });
3793
- var PartnerFundingSchema = import_zod14.z.object({
3794
- fundingId: import_zod14.z.string().uuid(),
3795
- partnerId: import_zod14.z.string().uuid(),
3796
- accountId: import_zod14.z.string().uuid(),
3797
- userId: import_zod14.z.string().uuid().nullable(),
3798
- direction: import_zod14.z.enum(PARTNER_FUNDING_DIRECTIONS),
3799
- currency: import_zod14.z.string(),
4150
+ var PartnerFundingSchema = import_zod15.z.object({
4151
+ fundingId: import_zod15.z.string().uuid(),
4152
+ partnerId: import_zod15.z.string().uuid(),
4153
+ accountId: import_zod15.z.string().uuid(),
4154
+ userId: import_zod15.z.string().uuid().nullable(),
4155
+ direction: import_zod15.z.enum(PARTNER_FUNDING_DIRECTIONS),
4156
+ currency: import_zod15.z.string(),
3800
4157
  amountMinor: MinorString,
3801
- externalRef: import_zod14.z.string(),
3802
- status: import_zod14.z.enum(PARTNER_FUNDING_STATUSES),
3803
- fundingSource: import_zod14.z.string(),
3804
- ledgerRef: import_zod14.z.string(),
4158
+ externalRef: import_zod15.z.string(),
4159
+ status: import_zod15.z.enum(PARTNER_FUNDING_STATUSES),
4160
+ fundingSource: import_zod15.z.string(),
4161
+ ledgerRef: import_zod15.z.string(),
3805
4162
  providerMetadata: Metadata,
3806
- createdAtMs: import_zod14.z.number().int().nonnegative(),
3807
- updatedAtMs: import_zod14.z.number().int().nonnegative()
4163
+ createdAtMs: import_zod15.z.number().int().nonnegative(),
4164
+ updatedAtMs: import_zod15.z.number().int().nonnegative()
3808
4165
  });
3809
- var IngestFundingResultSchema = import_zod14.z.object({
4166
+ var IngestFundingResultSchema = import_zod15.z.object({
3810
4167
  funding: PartnerFundingSchema,
3811
- replayed: import_zod14.z.boolean()
4168
+ replayed: import_zod15.z.boolean()
3812
4169
  });
3813
- var PayoutDestinationSchema = import_zod14.z.object({
3814
- destinationId: import_zod14.z.string().uuid(),
3815
- accountId: import_zod14.z.string().uuid(),
3816
- partnerId: import_zod14.z.string().uuid(),
3817
- bankCode: import_zod14.z.string(),
3818
- accountNumber: import_zod14.z.string(),
3819
- accountName: import_zod14.z.string(),
3820
- status: import_zod14.z.enum(PAYOUT_DESTINATION_STATUSES),
3821
- verifiedAtMs: import_zod14.z.number().int().nonnegative().nullable(),
4170
+ var PayoutDestinationSchema = import_zod15.z.object({
4171
+ destinationId: import_zod15.z.string().uuid(),
4172
+ accountId: import_zod15.z.string().uuid(),
4173
+ partnerId: import_zod15.z.string().uuid(),
4174
+ bankCode: import_zod15.z.string(),
4175
+ accountNumber: import_zod15.z.string(),
4176
+ accountName: import_zod15.z.string(),
4177
+ status: import_zod15.z.enum(PAYOUT_DESTINATION_STATUSES),
4178
+ verifiedAtMs: import_zod15.z.number().int().nonnegative().nullable(),
3822
4179
  metadata: Metadata,
3823
- createdAtMs: import_zod14.z.number().int().nonnegative(),
3824
- updatedAtMs: import_zod14.z.number().int().nonnegative()
4180
+ createdAtMs: import_zod15.z.number().int().nonnegative(),
4181
+ updatedAtMs: import_zod15.z.number().int().nonnegative()
3825
4182
  });
3826
- var CreatePayoutDestinationInputSchema = import_zod14.z.object({
3827
- partnerId: import_zod14.z.string().uuid(),
3828
- bankCode: import_zod14.z.string().trim().min(1).max(32),
3829
- accountNumber: import_zod14.z.string().trim().min(4).max(64),
3830
- accountName: import_zod14.z.string().trim().min(1).max(200),
4183
+ var CreatePayoutDestinationInputSchema = import_zod15.z.object({
4184
+ partnerId: import_zod15.z.string().uuid(),
4185
+ bankCode: import_zod15.z.string().trim().min(1).max(32),
4186
+ accountNumber: import_zod15.z.string().trim().min(4).max(64),
4187
+ accountName: import_zod15.z.string().trim().min(1).max(200),
3831
4188
  metadata: Metadata.optional()
3832
4189
  });
3833
- var ListPayoutDestinationsResultSchema = import_zod14.z.object({
3834
- items: import_zod14.z.array(PayoutDestinationSchema)
4190
+ var ListPayoutDestinationsResultSchema = import_zod15.z.object({
4191
+ items: import_zod15.z.array(PayoutDestinationSchema)
3835
4192
  });
3836
- var WithdrawalSchema = import_zod14.z.object({
3837
- withdrawalId: import_zod14.z.string().uuid(),
3838
- accountId: import_zod14.z.string().uuid(),
3839
- userId: import_zod14.z.string().uuid(),
3840
- partnerId: import_zod14.z.string().uuid(),
3841
- destinationId: import_zod14.z.string().uuid(),
3842
- currency: import_zod14.z.string(),
4193
+ var WithdrawalSchema = import_zod15.z.object({
4194
+ withdrawalId: import_zod15.z.string().uuid(),
4195
+ accountId: import_zod15.z.string().uuid(),
4196
+ userId: import_zod15.z.string().uuid(),
4197
+ partnerId: import_zod15.z.string().uuid(),
4198
+ destinationId: import_zod15.z.string().uuid(),
4199
+ currency: import_zod15.z.string(),
3843
4200
  amountMinor: MinorString,
3844
- state: import_zod14.z.enum(WITHDRAWAL_STATES),
3845
- idempotencyKey: import_zod14.z.string(),
3846
- providerRef: import_zod14.z.string().nullable(),
3847
- lastError: import_zod14.z.string().nullable(),
3848
- ledgerRef: import_zod14.z.string(),
3849
- reverseLedgerRef: import_zod14.z.string().nullable(),
4201
+ state: import_zod15.z.enum(WITHDRAWAL_STATES),
4202
+ idempotencyKey: import_zod15.z.string(),
4203
+ providerRef: import_zod15.z.string().nullable(),
4204
+ lastError: import_zod15.z.string().nullable(),
4205
+ ledgerRef: import_zod15.z.string(),
4206
+ reverseLedgerRef: import_zod15.z.string().nullable(),
3850
4207
  metadata: Metadata,
3851
- createdAtMs: import_zod14.z.number().int().nonnegative(),
3852
- updatedAtMs: import_zod14.z.number().int().nonnegative()
4208
+ createdAtMs: import_zod15.z.number().int().nonnegative(),
4209
+ updatedAtMs: import_zod15.z.number().int().nonnegative()
3853
4210
  });
3854
- var CreateWithdrawalInputSchema = import_zod14.z.object({
3855
- destinationId: import_zod14.z.string().uuid(),
4211
+ var CreateWithdrawalInputSchema = import_zod15.z.object({
4212
+ destinationId: import_zod15.z.string().uuid(),
3856
4213
  amountMinor: PositiveMinor,
3857
4214
  currency: Currency,
3858
- idempotencyKey: import_zod14.z.string().trim().min(8).max(128),
4215
+ idempotencyKey: import_zod15.z.string().trim().min(8).max(128),
3859
4216
  metadata: Metadata.optional()
3860
4217
  });
3861
- var CreateWithdrawalResultSchema = import_zod14.z.object({
4218
+ var CreateWithdrawalResultSchema = import_zod15.z.object({
3862
4219
  withdrawal: WithdrawalSchema,
3863
- replayed: import_zod14.z.boolean()
4220
+ replayed: import_zod15.z.boolean()
3864
4221
  });
3865
- var PayoutEventInputSchema = import_zod14.z.object({
3866
- externalRef: import_zod14.z.string().trim().min(8).max(128),
3867
- withdrawalId: import_zod14.z.string().uuid().optional(),
3868
- state: import_zod14.z.enum(["submitted", "processing", "paid", "failed"]),
3869
- providerRef: import_zod14.z.string().trim().min(1).max(128).optional(),
3870
- failureCode: import_zod14.z.string().trim().max(64).optional(),
3871
- failureMessage: import_zod14.z.string().trim().max(512).optional(),
4222
+ var PayoutEventInputSchema = import_zod15.z.object({
4223
+ externalRef: import_zod15.z.string().trim().min(8).max(128),
4224
+ withdrawalId: import_zod15.z.string().uuid().optional(),
4225
+ state: import_zod15.z.enum(["submitted", "processing", "paid", "failed"]),
4226
+ providerRef: import_zod15.z.string().trim().min(1).max(128).optional(),
4227
+ failureCode: import_zod15.z.string().trim().max(64).optional(),
4228
+ failureMessage: import_zod15.z.string().trim().max(512).optional(),
3872
4229
  providerMetadata: Metadata.optional()
3873
4230
  });
3874
- var RecordPayoutEventResultSchema = import_zod14.z.object({
4231
+ var RecordPayoutEventResultSchema = import_zod15.z.object({
3875
4232
  withdrawal: WithdrawalSchema,
3876
- replayed: import_zod14.z.boolean()
4233
+ replayed: import_zod15.z.boolean()
3877
4234
  });
3878
- var ReconciliationReportSchema = import_zod14.z.object({
3879
- partnerId: import_zod14.z.string().uuid(),
3880
- currency: import_zod14.z.string(),
3881
- fromMs: import_zod14.z.number().int().nonnegative(),
3882
- toMs: import_zod14.z.number().int().nonnegative(),
4235
+ var ReconciliationReportSchema = import_zod15.z.object({
4236
+ partnerId: import_zod15.z.string().uuid(),
4237
+ currency: import_zod15.z.string(),
4238
+ fromMs: import_zod15.z.number().int().nonnegative(),
4239
+ toMs: import_zod15.z.number().int().nonnegative(),
3883
4240
  fundingsCreditMinor: MinorString,
3884
4241
  fundingsDebitMinor: MinorString,
3885
4242
  withdrawalsPaidMinor: MinorString,
@@ -3888,7 +4245,7 @@ var ReconciliationReportSchema = import_zod14.z.object({
3888
4245
  expectedReserveBalanceMinor: MinorString,
3889
4246
  actualReserveBalanceMinor: MinorString,
3890
4247
  imbalanceMinor: MinorString,
3891
- generatedAtMs: import_zod14.z.number().int().nonnegative()
4248
+ generatedAtMs: import_zod15.z.number().int().nonnegative()
3892
4249
  });
3893
4250
  function createPartnerFundingClient(partner) {
3894
4251
  return {
@@ -4040,19 +4397,19 @@ function createPartnerProfileAdminClient(opts) {
4040
4397
  }
4041
4398
 
4042
4399
  // src/artifacts/envelope.ts
4043
- var import_zod15 = require("zod");
4400
+ var import_zod16 = require("zod");
4044
4401
  var FLUR_ARTIFACT_URI_SCHEME = "flur";
4045
4402
  var FLUR_ARTIFACT_VERSION = 1;
4046
4403
  var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
4047
4404
  var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
4048
- var ArtifactHeaderSchema = import_zod15.z.object({
4049
- v: import_zod15.z.literal(FLUR_ARTIFACT_VERSION),
4050
- t: import_zod15.z.string().regex(ArtifactTypeRe, "invalid artifact type"),
4051
- iss: import_zod15.z.string().min(1).max(128),
4052
- kid: import_zod15.z.string().min(1).max(128),
4053
- iat: import_zod15.z.number().int().nonnegative(),
4054
- exp: import_zod15.z.number().int().positive().optional(),
4055
- nonce: import_zod15.z.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
4405
+ var ArtifactHeaderSchema = import_zod16.z.object({
4406
+ v: import_zod16.z.literal(FLUR_ARTIFACT_VERSION),
4407
+ t: import_zod16.z.string().regex(ArtifactTypeRe, "invalid artifact type"),
4408
+ iss: import_zod16.z.string().min(1).max(128),
4409
+ kid: import_zod16.z.string().min(1).max(128),
4410
+ iat: import_zod16.z.number().int().nonnegative(),
4411
+ exp: import_zod16.z.number().int().positive().optional(),
4412
+ nonce: import_zod16.z.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
4056
4413
  });
4057
4414
  var FlurArtifactError = class extends Error {
4058
4415
  constructor(message, code) {
@@ -4191,7 +4548,7 @@ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
4191
4548
  }
4192
4549
 
4193
4550
  // src/artifacts/types.ts
4194
- var import_zod16 = require("zod");
4551
+ var import_zod17 = require("zod");
4195
4552
  var ARTIFACT_TYPES = {
4196
4553
  OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
4197
4554
  RECEIPT: "receipt",
@@ -4206,32 +4563,32 @@ var ARTIFACT_TYPES = {
4206
4563
  PASS: "pass",
4207
4564
  IDENTITY: "identity"
4208
4565
  };
4209
- var HexString = (length) => import_zod16.z.string().regex(
4566
+ var HexString = (length) => import_zod17.z.string().regex(
4210
4567
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
4211
4568
  `expected ${length}-byte hex string`
4212
4569
  );
4213
- var OfflinePaymentAuthorizationArtifactSchema = import_zod16.z.object({
4570
+ var OfflinePaymentAuthorizationArtifactSchema = import_zod17.z.object({
4214
4571
  authorization: OfflinePaymentAuthorizationSchema
4215
4572
  });
4216
- var ReceiptArtifactSchema = import_zod16.z.object({
4217
- receiptId: import_zod16.z.string().min(1).max(64),
4218
- paymentReference: import_zod16.z.string().min(1).max(64),
4219
- payerUserId: import_zod16.z.string().min(1).max(64).optional(),
4220
- payeeUserId: import_zod16.z.string().min(1).max(64),
4221
- amountKobo: import_zod16.z.number().int().positive(),
4222
- currency: import_zod16.z.literal("NGN"),
4223
- channel: import_zod16.z.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
4224
- settledAtMs: import_zod16.z.number().int().positive(),
4225
- ledgerTxnId: import_zod16.z.string().min(1).max(64).optional(),
4226
- memo: import_zod16.z.string().max(140).optional(),
4573
+ var ReceiptArtifactSchema = import_zod17.z.object({
4574
+ receiptId: import_zod17.z.string().min(1).max(64),
4575
+ paymentReference: import_zod17.z.string().min(1).max(64),
4576
+ payerUserId: import_zod17.z.string().min(1).max(64).optional(),
4577
+ payeeUserId: import_zod17.z.string().min(1).max(64),
4578
+ amountKobo: import_zod17.z.number().int().positive(),
4579
+ currency: import_zod17.z.literal("NGN"),
4580
+ channel: import_zod17.z.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
4581
+ settledAtMs: import_zod17.z.number().int().positive(),
4582
+ ledgerTxnId: import_zod17.z.string().min(1).max(64).optional(),
4583
+ memo: import_zod17.z.string().max(140).optional(),
4227
4584
  hashChainPrev: HexString(32).optional()
4228
4585
  });
4229
- var ShortId = import_zod16.z.string().min(1).max(64);
4230
- var PositiveInt = import_zod16.z.number().int().positive();
4231
- var NonNegativeInt = import_zod16.z.number().int().nonnegative();
4232
- var Currency2 = import_zod16.z.literal("NGN");
4233
- var Memo = import_zod16.z.string().max(140);
4234
- var NqrPaymentRequestArtifactSchema = import_zod16.z.object({
4586
+ var ShortId = import_zod17.z.string().min(1).max(64);
4587
+ var PositiveInt = import_zod17.z.number().int().positive();
4588
+ var NonNegativeInt = import_zod17.z.number().int().nonnegative();
4589
+ var Currency2 = import_zod17.z.literal("NGN");
4590
+ var Memo = import_zod17.z.string().max(140);
4591
+ var NqrPaymentRequestArtifactSchema = import_zod17.z.object({
4235
4592
  requestId: ShortId,
4236
4593
  payeeUserId: ShortId,
4237
4594
  amountKobo: PositiveInt.optional(),
@@ -4239,7 +4596,7 @@ var NqrPaymentRequestArtifactSchema = import_zod16.z.object({
4239
4596
  memo: Memo.optional(),
4240
4597
  expiresAtMs: PositiveInt.optional()
4241
4598
  });
4242
- var PaymentIntentArtifactSchema = import_zod16.z.object({
4599
+ var PaymentIntentArtifactSchema = import_zod17.z.object({
4243
4600
  intentId: ShortId,
4244
4601
  payerUserId: ShortId,
4245
4602
  payeeUserId: ShortId,
@@ -4248,7 +4605,7 @@ var PaymentIntentArtifactSchema = import_zod16.z.object({
4248
4605
  idempotencyKey: ShortId,
4249
4606
  createdAtMs: PositiveInt
4250
4607
  });
4251
- var OfflineClaimArtifactSchema = import_zod16.z.object({
4608
+ var OfflineClaimArtifactSchema = import_zod17.z.object({
4252
4609
  claimId: ShortId,
4253
4610
  authorizationId: ShortId,
4254
4611
  payeeUserId: ShortId,
@@ -4257,10 +4614,10 @@ var OfflineClaimArtifactSchema = import_zod16.z.object({
4257
4614
  claimedAtMs: PositiveInt,
4258
4615
  paymentReference: ShortId.optional()
4259
4616
  });
4260
- var SettlementRecordArtifactSchema = import_zod16.z.object({
4617
+ var SettlementRecordArtifactSchema = import_zod17.z.object({
4261
4618
  settlementId: ShortId,
4262
4619
  ledgerTxnId: ShortId,
4263
- sourceRefType: import_zod16.z.enum([
4620
+ sourceRefType: import_zod17.z.enum([
4264
4621
  "offline_authorization",
4265
4622
  "offline_claim",
4266
4623
  "transfer",
@@ -4271,12 +4628,12 @@ var SettlementRecordArtifactSchema = import_zod16.z.object({
4271
4628
  currency: Currency2,
4272
4629
  settledAtMs: PositiveInt
4273
4630
  });
4274
- var ReversalRecordArtifactSchema = import_zod16.z.object({
4631
+ var ReversalRecordArtifactSchema = import_zod17.z.object({
4275
4632
  reversalId: ShortId,
4276
4633
  originalTxnId: ShortId,
4277
4634
  amountKobo: PositiveInt,
4278
4635
  currency: Currency2,
4279
- reason: import_zod16.z.enum([
4636
+ reason: import_zod17.z.enum([
4280
4637
  "user_dispute",
4281
4638
  "fraud",
4282
4639
  "duplicate",
@@ -4286,7 +4643,7 @@ var ReversalRecordArtifactSchema = import_zod16.z.object({
4286
4643
  reversedAtMs: PositiveInt,
4287
4644
  memo: Memo.optional()
4288
4645
  });
4289
- var LedgerJournalEntryArtifactSchema = import_zod16.z.object({
4646
+ var LedgerJournalEntryArtifactSchema = import_zod17.z.object({
4290
4647
  entryId: ShortId,
4291
4648
  journalId: ShortId,
4292
4649
  debitAccountId: ShortId,
@@ -4297,13 +4654,13 @@ var LedgerJournalEntryArtifactSchema = import_zod16.z.object({
4297
4654
  refType: ShortId.optional(),
4298
4655
  refId: ShortId.optional()
4299
4656
  });
4300
- var StatementArtifactSchema = import_zod16.z.object({
4657
+ var StatementArtifactSchema = import_zod17.z.object({
4301
4658
  statementId: ShortId,
4302
4659
  userId: ShortId,
4303
4660
  periodStartMs: PositiveInt,
4304
4661
  periodEndMs: PositiveInt,
4305
- openingBalanceKobo: import_zod16.z.number().int(),
4306
- closingBalanceKobo: import_zod16.z.number().int(),
4662
+ openingBalanceKobo: import_zod17.z.number().int(),
4663
+ closingBalanceKobo: import_zod17.z.number().int(),
4307
4664
  transactionCount: NonNegativeInt,
4308
4665
  currency: Currency2,
4309
4666
  hashChainPrev: HexString(32).optional()
@@ -4311,16 +4668,16 @@ var StatementArtifactSchema = import_zod16.z.object({
4311
4668
  message: "periodEndMs must be greater than periodStartMs",
4312
4669
  path: ["periodEndMs"]
4313
4670
  });
4314
- var PassArtifactSchema = import_zod16.z.object({
4671
+ var PassArtifactSchema = import_zod17.z.object({
4315
4672
  passId: ShortId,
4316
4673
  holderId: ShortId,
4317
- category: import_zod16.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
4318
- title: import_zod16.z.string().min(1).max(120),
4674
+ category: import_zod17.z.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
4675
+ title: import_zod17.z.string().min(1).max(120),
4319
4676
  validFromMs: PositiveInt,
4320
4677
  validUntilMs: PositiveInt.optional(),
4321
- metadata: import_zod16.z.record(
4322
- import_zod16.z.string().min(1).max(64),
4323
- import_zod16.z.union([import_zod16.z.string().max(280), import_zod16.z.number(), import_zod16.z.boolean()])
4678
+ metadata: import_zod17.z.record(
4679
+ import_zod17.z.string().min(1).max(64),
4680
+ import_zod17.z.union([import_zod17.z.string().max(280), import_zod17.z.number(), import_zod17.z.boolean()])
4324
4681
  ).optional()
4325
4682
  }).refine(
4326
4683
  (v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
@@ -4329,10 +4686,10 @@ var PassArtifactSchema = import_zod16.z.object({
4329
4686
  path: ["validUntilMs"]
4330
4687
  }
4331
4688
  );
4332
- var IdentityArtifactSchema = import_zod16.z.object({
4689
+ var IdentityArtifactSchema = import_zod17.z.object({
4333
4690
  attestationId: ShortId,
4334
4691
  subjectId: ShortId,
4335
- claimType: import_zod16.z.enum([
4692
+ claimType: import_zod17.z.enum([
4336
4693
  "phone_verified",
4337
4694
  "email_verified",
4338
4695
  "bvn_verified",
@@ -4453,6 +4810,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4453
4810
  }
4454
4811
  // Annotate the CommonJS export names for ESM import in node:
4455
4812
  0 && (module.exports = {
4813
+ ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
4456
4814
  ACCOUNT_STATUSES,
4457
4815
  ACCOUNT_TYPES,
4458
4816
  ADDITIONAL_DATA_SUBFIELD,
@@ -4466,6 +4824,10 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4466
4824
  CLAIM_DOMAIN_V2,
4467
4825
  COLLECTION_INTENT_STATUSES,
4468
4826
  COLLECTION_PAYMENT_STATUSES,
4827
+ CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
4828
+ CONSUMER_PAYMENT_REQUEST_DOMAIN,
4829
+ CONSUMER_SETTLEMENT_DOMAIN,
4830
+ CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX,
4469
4831
  CUSTODIAL_MODES,
4470
4832
  CollectionIntentSchema,
4471
4833
  CollectionPaymentResultSchema,
@@ -4475,6 +4837,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4475
4837
  ConsumerOACRecordSchema,
4476
4838
  ConsumerOACSchema,
4477
4839
  ConsumerPaymentClaimSchema,
4840
+ ConsumerPaymentRequestEnvelopeSchema,
4478
4841
  ConsumerSettleResultSchema,
4479
4842
  ConsumerSettlementSchema,
4480
4843
  CreateCollectionIntentInputSchema,
@@ -4484,10 +4847,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4484
4847
  CreateWithdrawalResultSchema,
4485
4848
  DeviceKeyAlgSchema,
4486
4849
  DeviceKeyRecordSchema,
4487
- DisableOfflineInputSchema,
4488
- DisableOfflineResultSchema,
4489
- EnableOfflineInputSchema,
4490
- EnableOfflineResultSchema,
4491
4850
  FIELD,
4492
4851
  FLUR_ARTIFACT_URI_PREFIX,
4493
4852
  FLUR_ARTIFACT_URI_SCHEME,
@@ -4503,7 +4862,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4503
4862
  IdentityArtifactSchema,
4504
4863
  IngestFundingResultSchema,
4505
4864
  IssueAccountOacInputSchema,
4506
- IssueOACInputSchema,
4507
4865
  LedgerJournalEntryArtifactSchema,
4508
4866
  ListPayoutDestinationsResultSchema,
4509
4867
  MEMBERSHIP_ROLES,
@@ -4521,12 +4879,16 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4521
4879
  OAC_DEFAULT_PER_TX_KOBO,
4522
4880
  OAC_DEFAULT_VALIDITY_MS,
4523
4881
  OFFLINE_CLAIM_SMS_PREFIX,
4882
+ OFFLINE_SMS_SETTLE_DOMAIN,
4883
+ OFFLINE_SMS_SETTLE_HEADER_BYTES,
4884
+ OFFLINE_SMS_SETTLE_PREFIX,
4885
+ OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
4886
+ OFFLINE_SMS_SETTLE_TOKEN_BYTES,
4887
+ OFFLINE_SMS_SETTLE_VERSION,
4524
4888
  OfflineClaimArtifactSchema,
4525
- OfflineHoldRecordSchema,
4526
4889
  OfflinePaymentAuthorizationArtifactSchema,
4527
4890
  OfflinePaymentAuthorizationSchema,
4528
4891
  OfflinePaymentRequestSchema,
4529
- OfflineStateResultSchema,
4530
4892
  OfflineStatusResultSchema,
4531
4893
  OfflineTokenSchema,
4532
4894
  P256EnrollmentChallengeInputSchema,
@@ -4554,8 +4916,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4554
4916
  PayoutEventInputSchema,
4555
4917
  ProviderEventInputSchema,
4556
4918
  ProviderEventRecordSchema,
4557
- ProvisionOfflineAllowanceInputSchema,
4558
- ProvisionOfflineAllowanceResultSchema,
4559
4919
  PublicCollectionIntentSchema,
4560
4920
  RECEIPT_CHANNELS,
4561
4921
  RECEIPT_KINDS,
@@ -4566,7 +4926,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4566
4926
  ReconciliationReportSchema,
4567
4927
  RecordPayoutEventResultSchema,
4568
4928
  RedemptionSchema,
4569
- RegisterDeviceKeyInputSchema,
4570
4929
  RegisterDeviceKeyP256InputSchema,
4571
4930
  ReversalRecordArtifactSchema,
4572
4931
  RevokeDeviceKeyInputSchema,
@@ -4585,18 +4944,25 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4585
4944
  bodySha256Hex,
4586
4945
  buildArtifactBody,
4587
4946
  buildAuthorization,
4947
+ buildConsumerPaymentRequest,
4588
4948
  buildOAC,
4589
4949
  buildPass,
4590
4950
  buildPaymentRequest,
4591
4951
  buildReceipt,
4592
4952
  buildRedemption,
4953
+ buildSmsSettleHeader,
4954
+ buildSmsSettleSignedBytes,
4593
4955
  canonicalClaimSigningBytes,
4594
4956
  canonicalClaimSigningPayload,
4595
4957
  canonicalJSONBytes,
4596
4958
  canonicalJSONStringify,
4597
4959
  canonicalRequestString,
4960
+ computeConsumerClaimEncounterId,
4598
4961
  computeEncounterId,
4599
4962
  constantTimeEqual,
4963
+ consumerPaymentRequestSigningBytes,
4964
+ consumerPaymentRequestSigningPayload,
4965
+ consumerSettlementSigningPayload,
4600
4966
  crc16ccitt,
4601
4967
  crc16ccittHex,
4602
4968
  createAccountsClient,
@@ -4620,19 +4986,27 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4620
4986
  decodeArtifactUri,
4621
4987
  decodeAuthorizationQR,
4622
4988
  decodeBase45,
4989
+ decodeConsumerSettlementReceiptQR,
4623
4990
  decodeOfflineClaimSmsMessage,
4991
+ decodeOfflineSmsSettleToken,
4624
4992
  decodePaymentRequestQR,
4993
+ decodeUnverifiedConsumerSettlementReceiptQR,
4994
+ derToRawP256Signature,
4625
4995
  encodeArtifactUri,
4626
4996
  encodeAuthorizationQR,
4627
4997
  encodeBase45,
4998
+ encodeConsumerSettlementReceiptQR,
4628
4999
  encodeNQR,
4629
5000
  encodeOfflineClaimSmsMessage,
5001
+ encodeOfflineSmsSettleToken,
4630
5002
  encodePaymentRequestQR,
4631
5003
  extractOfflineClaimSmsToken,
5004
+ extractOfflineSmsSettleToken,
4632
5005
  formatAmount,
4633
5006
  generateDynamicQR,
4634
5007
  generateStaticQR,
4635
5008
  init,
5009
+ isConsumerPaymentRequestExpired,
4636
5010
  isHardenedArtifactType,
4637
5011
  isKnownArtifactType,
4638
5012
  isPassWithinValidity,
@@ -4645,6 +5019,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4645
5019
  routingHint,
4646
5020
  signArtifact,
4647
5021
  signAuthorization,
5022
+ signConsumerPaymentRequest,
4648
5023
  signOAC,
4649
5024
  signPartnerRequest,
4650
5025
  signPass,
@@ -4656,7 +5031,11 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4656
5031
  verifyArtifactUri,
4657
5032
  verifyAuthorization,
4658
5033
  verifyClaimSignature,
5034
+ verifyConsumerPaymentRequest,
5035
+ verifyConsumerSettlement,
5036
+ verifyConsumerSettlementReceiptQR,
4659
5037
  verifyOAC,
5038
+ verifyOfflineSmsSettleToken,
4660
5039
  verifyPass,
4661
5040
  verifyPaymentRequest,
4662
5041
  verifyReceipt,