@nokinc-flur/sdk 1.1.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,201 @@
1
1
  // src/client.ts
2
- import { z as z5 } from "zod";
2
+ import { z as z4 } from "zod";
3
3
 
4
4
  // src/contracts.ts
5
- import { z as z2 } from "zod";
6
-
7
- // src/me-offline/client.ts
8
5
  import { z } from "zod";
6
+ var E164Regex = /^\+[1-9]\d{7,14}$/;
7
+ var UuidSchema = z.string().uuid();
8
+ var IsoDateSchema = z.string().datetime({ offset: true });
9
+ var CurrencySchema = z.string().trim().length(3).transform((value) => value.toUpperCase());
10
+ var HealthResponseSchema = z.object({
11
+ ok: z.boolean()
12
+ });
13
+ var WelcomeResponseSchema = z.object({
14
+ message: z.string()
15
+ });
16
+ var OnboardingStartRequestSchema = z.object({
17
+ phoneE164: z.string().regex(E164Regex),
18
+ appInstanceId: z.string().min(3),
19
+ platform: z.enum(["android", "ios", "web"]),
20
+ turnstileToken: z.string().min(20).optional(),
21
+ appAttestation: z.object({
22
+ provider: z.enum(["android", "ios", "web"]),
23
+ token: z.string().min(24)
24
+ }).optional(),
25
+ firstName: z.string().trim().min(1).max(80).optional(),
26
+ lastName: z.string().trim().min(1).max(80).optional()
27
+ });
28
+ var OnboardingStartResponseSchema = z.object({
29
+ requestId: z.string().min(1),
30
+ checkUrl: z.string().url().optional(),
31
+ expiresInSec: z.number().int().positive(),
32
+ fallback: z.enum(["SILENT_AUTH", "OTP"])
33
+ });
34
+ var OnboardingCompleteRequestSchema = z.object({
35
+ requestId: z.string().min(1),
36
+ code: z.string().min(1).max(32),
37
+ appInstanceId: z.string().min(3),
38
+ fingerprintHash: z.string().min(3).optional()
39
+ });
40
+ var OnboardingCompleteResponseSchema = z.object({
41
+ sessionToken: z.string().min(1),
42
+ userId: UuidSchema,
43
+ restricted: z.boolean(),
44
+ risk_reasons: z.array(
45
+ z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
46
+ ),
47
+ stepUpRequired: z.boolean().optional(),
48
+ riskStatus: z.enum(["ok", "unavailable"]).optional()
49
+ });
50
+ var RegisterDeviceRequestSchema = z.object({
51
+ userId: UuidSchema,
52
+ appInstanceId: z.string().min(3),
53
+ platform: z.string().min(2),
54
+ model: z.string().optional(),
55
+ networkSignals: z.object({
56
+ ip: z.string().min(3),
57
+ asn: z.number().int().optional(),
58
+ country: z.string().min(2).optional(),
59
+ carrier: z.string().optional()
60
+ })
61
+ });
62
+ var RegisterDeviceResponseSchema = z.object({
63
+ deviceId: z.string().min(1),
64
+ fingerprintHash: z.string().min(1),
65
+ driftScore: z.number(),
66
+ trustState: z.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
67
+ stepUpRequired: z.boolean()
68
+ });
69
+ var AuthRefreshRequestSchema = z.object({
70
+ userId: UuidSchema,
71
+ refreshToken: z.string().min(8),
72
+ appInstanceId: z.string().min(3),
73
+ fingerprintHash: z.string().min(3)
74
+ });
75
+ var AuthRefreshResponseSchema = z.object({
76
+ refreshToken: z.string().min(8),
77
+ stepUpRequired: z.boolean()
78
+ });
79
+ var AuthLogoutRequestSchema = z.object({
80
+ userId: UuidSchema,
81
+ refreshToken: z.string().min(8)
82
+ });
83
+ var PinSetRequestSchema = z.object({
84
+ userId: UuidSchema,
85
+ pin: z.string().regex(/^\d{6}$/)
86
+ });
87
+ var PinVerifyRequestSchema = z.object({
88
+ userId: UuidSchema,
89
+ pin: z.string().regex(/^\d{6}$/)
90
+ });
91
+ var OkResponseSchema = z.object({
92
+ ok: z.boolean()
93
+ });
94
+ var RegisterSendDeviceKeyRequestSchema = z.object({
95
+ userId: UuidSchema,
96
+ deviceId: z.string().min(3),
97
+ publicKey: z.string().min(32)
98
+ });
99
+ var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
100
+ var SendChallengeRequestSchema = z.object({
101
+ userId: UuidSchema,
102
+ deviceId: z.string().min(3),
103
+ purpose: z.enum(SEND_AUTH_PURPOSES).optional()
104
+ });
105
+ var SendChallengeResponseSchema = z.object({
106
+ challengeId: UuidSchema,
107
+ nonce: z.string().min(1),
108
+ expiresAt: IsoDateSchema
109
+ });
110
+ var SendVerifyRequestSchema = z.object({
111
+ userId: UuidSchema,
112
+ deviceId: z.string().min(3),
113
+ challengeId: UuidSchema,
114
+ signature: z.string().min(16)
115
+ });
116
+ var SendVerifyResponseSchema = z.object({
117
+ sendAuthToken: z.string().min(16)
118
+ });
119
+ var ResolveRecipientRequestSchema = z.object({
120
+ identifier: z.string().min(3)
121
+ });
122
+ var ResolveRecipientResponseSchema = z.object({
123
+ recipientUserId: UuidSchema,
124
+ displayName: z.string().min(1),
125
+ normalizedIdentifier: z.string().regex(E164Regex),
126
+ isActive: z.boolean()
127
+ });
128
+ var CreateTransferRequestSchema = z.object({
129
+ recipientIdentifier: z.string().min(3),
130
+ amountMinor: z.number().int().positive(),
131
+ currency: CurrencySchema,
132
+ sendAuthToken: z.string().min(16)
133
+ });
134
+ var TransferStatusSchema = z.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
135
+ var TransferResponseSchema = z.object({
136
+ transactionId: z.string().min(1),
137
+ status: TransferStatusSchema,
138
+ userStatus: TransferStatusSchema,
139
+ recipientName: z.string().min(1),
140
+ timestamp: IsoDateSchema
141
+ });
142
+ var DirectionSchema = z.enum(["OUTGOING", "INCOMING"]);
143
+ var AccountActivityItemSchema = z.object({
144
+ id: z.string().min(1),
145
+ type: z.string().min(1),
146
+ direction: DirectionSchema,
147
+ name: z.string().min(1),
148
+ identifier: z.string().min(1),
149
+ amountMinor: z.number().int(),
150
+ currency: CurrencySchema,
151
+ status: z.string().min(1),
152
+ timestamp: IsoDateSchema
153
+ });
154
+ var AccountSummaryResponseSchema = z.object({
155
+ /** Authenticated user's stable internal id. */
156
+ userId: UuidSchema,
157
+ /**
158
+ * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
159
+ * bank partner. `null` when the user has no partner-allocated account yet.
160
+ */
161
+ nuban: z.string().regex(/^[0-9]{10}$/).nullable(),
162
+ balance: z.number().int(),
163
+ currency: CurrencySchema,
164
+ dailySendLimit: z.number().int().nonnegative(),
165
+ dailySendRemaining: z.number().int().nonnegative(),
166
+ kycTier: z.string().min(1),
167
+ kycStatus: z.string().min(1),
168
+ recentActivity: z.array(AccountActivityItemSchema)
169
+ });
170
+ var TransactionsListResponseSchema = z.object({
171
+ items: z.array(AccountActivityItemSchema),
172
+ nextCursor: z.string().nullable()
173
+ });
174
+ var TransactionDetailResponseSchema = z.object({
175
+ transactionId: z.string().min(1),
176
+ type: z.string().min(1),
177
+ direction: DirectionSchema,
178
+ counterpartyName: z.string().min(1),
179
+ counterpartyIdentifier: z.string().min(1),
180
+ amountMinor: z.number().int(),
181
+ currency: CurrencySchema,
182
+ status: z.string().min(1),
183
+ timestamp: IsoDateSchema
184
+ });
185
+ var PushRegisterRequestSchema = z.object({
186
+ deviceId: z.string().min(3),
187
+ platform: z.enum(["ios", "android", "web"]),
188
+ token: z.string().min(16)
189
+ });
190
+ var CreatePayLinkResponseSchema = z.object({
191
+ token: z.string().min(1)
192
+ });
193
+ var ResolvePayLinkResponseSchema = z.object({
194
+ recipientUserId: UuidSchema,
195
+ displayName: z.string().min(1),
196
+ normalizedIdentifier: z.string().regex(E164Regex),
197
+ isActive: z.boolean()
198
+ });
9
199
 
10
200
  // src/errors.ts
11
201
  var backendErrorCodeSet = /* @__PURE__ */ new Set([
@@ -109,556 +299,9 @@ async function mapToFlurError(res) {
109
299
  });
110
300
  }
111
301
 
112
- // src/me-offline/client.ts
113
- var Hex64 = z.string().regex(/^[0-9a-f]{64}$/i);
114
- var Sha256Hex = z.string().regex(/^[0-9a-f]{64}$/i);
115
- var Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
116
- var RegisterDeviceKeyInputSchema = z.object({
117
- deviceId: z.string().min(1).max(128),
118
- publicKeyHex: Hex64
119
- });
120
- var AttestationSecurityLevelSchema = z.enum([
121
- "STRONGBOX",
122
- "TEE",
123
- "SECURE_ENCLAVE",
124
- "SOFTWARE"
125
- ]);
126
- var DeviceKeyAlgSchema = z.literal("p256");
127
- var RegisterDeviceKeyP256InputSchema = z.object({
128
- deviceId: z.string().min(1).max(128),
129
- /** P-256 SubjectPublicKeyInfo DER, base64. */
130
- publicKeySpkiB64: Base64Std.min(64).max(4096),
131
- /** Base64 of the server-issued enrollment challenge string. */
132
- challengeB64: Base64Std.min(8).max(1024),
133
- /** iOS App Attest payload or Android X.509 Key Attestation chain. */
134
- attestationChainB64: z.array(Base64Std.min(16).max(16384)).min(1).max(16),
135
- securityLevel: AttestationSecurityLevelSchema
136
- });
137
- var P256EnrollmentChallengeInputSchema = z.object({
138
- deviceId: z.string().min(1).max(128)
139
- });
140
- var P256EnrollmentChallengeResultSchema = z.object({
141
- challenge: z.string().min(16),
142
- expiresAtMs: z.number().int().positive()
143
- });
144
- var DeviceKeyRecordSchema = z.object({
145
- id: z.string().uuid(),
146
- userId: z.string().uuid(),
147
- deviceId: z.string(),
148
- /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
149
- alg: DeviceKeyAlgSchema.default("p256"),
150
- /** Legacy ed25519 hex key. Always null on new records (kept for back-compat reads). */
151
- publicKeyHex: Hex64.nullable().default(null),
152
- /** P-256 SubjectPublicKeyInfo DER, base64. Required for new records. */
153
- publicKeySpkiB64: Base64Std.nullable().default(null),
154
- securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
155
- hardwareBacked: z.boolean().default(false),
156
- attestedAtMs: z.number().int().nonnegative().nullable().default(null),
157
- createdAtMs: z.number().int().nonnegative(),
158
- revokedAtMs: z.number().int().nonnegative().nullable()
159
- });
160
- var ConsumerOACSchema = z.object({
161
- oacId: z.string().uuid(),
162
- issuerId: z.string().min(1).max(64),
163
- userId: z.string().uuid(),
164
- deviceId: z.string().min(1).max(128),
165
- /**
166
- * Always 'p256'. Required on the wire (backend always emits it).
167
- * Kept as a literal so input/output infer identically and the schema
168
- * can be nested inside other response shapes without Zod input/output
169
- * divergence under tsup DTS bundling.
170
- */
171
- alg: z.literal("p256"),
172
- /** P-256 SubjectPublicKeyInfo DER, base64. */
173
- devicePubkeySpkiB64: Base64Std.min(64).max(4096),
174
- perTxCapKobo: z.number().int().positive(),
175
- cumulativeCapKobo: z.number().int().positive(),
176
- currency: z.string().length(3),
177
- validFromMs: z.number().int().nonnegative(),
178
- validUntilMs: z.number().int().nonnegative(),
179
- counterSeed: z.number().int().nonnegative(),
180
- issuedAtMs: z.number().int().nonnegative()
181
- });
182
- var SignedConsumerOACSchema = z.object({
183
- oac: ConsumerOACSchema,
184
- /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
185
- issuerSig: Base64Std.min(16).max(2048),
186
- /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
187
- issuerPublicKeySpkiB64: Base64Std.min(64).max(4096)
188
- });
189
- var OACRecordSchema = SignedConsumerOACSchema.extend({
190
- currentOfflineSpentKobo: z.number().int().nonnegative(),
191
- status: z.enum([
192
- "active",
193
- "superseded",
194
- "expired",
195
- "revoked",
196
- "disabling",
197
- "draining",
198
- "closed"
199
- ]),
200
- supersededAtMs: z.number().int().nonnegative().nullable(),
201
- revokedAtMs: z.number().int().nonnegative().nullable(),
202
- holdId: z.string().uuid().nullable().optional()
203
- });
204
- var IssueOACInputSchema = z.object({
205
- deviceId: z.string().min(1).max(128),
206
- perTxCapKobo: z.number().int().positive().optional(),
207
- cumulativeCapKobo: z.number().int().positive().optional(),
208
- ttlMs: z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
209
- spendableOnlineKobo: z.number().int().nonnegative().optional()
210
- });
211
- var IssueAccountOacInputSchema = z.object({
212
- deviceId: z.string().min(1).max(128),
213
- perTxCapKobo: z.number().int().positive().optional(),
214
- cumulativeCapKobo: z.number().int().positive().optional(),
215
- ttlMs: z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional()
216
- });
217
- var EnableOfflineInputSchema = z.object({
218
- deviceId: z.string().min(1).max(128),
219
- amountKobo: z.number().int().positive(),
220
- perTxCapKobo: z.number().int().positive().optional(),
221
- ttlMs: z.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
222
- installId: z.string().min(1).max(128),
223
- partnerId: z.string().min(1).max(64).optional()
224
- });
225
- var ProvisionOfflineAllowanceInputSchema = EnableOfflineInputSchema;
226
- var DisableOfflineInputSchema = z.object({
227
- deviceId: z.string().min(1).max(128),
228
- installId: z.string().min(1).max(128).optional(),
229
- claims: z.array(z.unknown()).max(256).optional()
230
- });
231
- var OfflineHoldRecordSchema = z.object({
232
- holdId: z.string().uuid(),
233
- userId: z.string().uuid(),
234
- deviceId: z.string(),
235
- partnerId: z.string(),
236
- adapterKind: z.string(),
237
- externalHoldRef: z.string().nullable(),
238
- amountKobo: z.number().int().nonnegative(),
239
- capturedKobo: z.number().int().nonnegative(),
240
- releasedKobo: z.number().int().nonnegative(),
241
- remainingKobo: z.number().int().nonnegative(),
242
- currency: z.string().length(3),
243
- status: z.enum([
244
- "placing",
245
- "active",
246
- "disabling",
247
- "draining",
248
- "closed",
249
- "revoked",
250
- "failed"
251
- ]),
252
- installId: z.string().nullable(),
253
- drainDeadlineMs: z.number().int().nonnegative(),
254
- disableRequestedAtMs: z.number().int().nonnegative().nullable(),
255
- createdAtMs: z.number().int().nonnegative(),
256
- closedAtMs: z.number().int().nonnegative().nullable(),
257
- isTrusted: z.boolean().optional()
258
- });
259
- var EnableOfflineResultSchema = z.object({
260
- hold: OfflineHoldRecordSchema,
261
- oac: OACRecordSchema
262
- });
263
- var ProvisionOfflineAllowanceResultSchema = EnableOfflineResultSchema;
264
- var DisableOfflineResultSchema = z.object({
265
- hold: OfflineHoldRecordSchema,
266
- trusted: z.boolean(),
267
- settledClaims: z.number().int().nonnegative()
268
- });
269
- var OfflineStatusResultSchema = z.object({
270
- hold: OfflineHoldRecordSchema.nullable(),
271
- active: OACRecordSchema.nullable()
272
- });
273
- var OfflineStateResultSchema = z.object({
274
- active: OACRecordSchema.nullable()
275
- });
276
- var ConsumerPaymentClaimSchema = z.object({
277
- /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
278
- alg: z.literal("p256").default("p256"),
279
- oacId: z.string().uuid(),
280
- encounterId: Sha256Hex.optional(),
281
- payerUserId: z.string().uuid(),
282
- payeeUserId: z.string().uuid(),
283
- payerDeviceId: z.string().min(1).max(128),
284
- payerNonce: z.string().min(8).max(128),
285
- payeeNonce: z.string().min(8).max(128),
286
- amountKobo: z.number().int().positive(),
287
- currency: z.string().length(3).default("NGN"),
288
- occurredAtMs: z.number().int().nonnegative(),
289
- completedAtMs: z.number().int().nonnegative().optional(),
290
- contextId: z.string().max(128).optional(),
291
- payerPubkeySpkiB64: Base64Std.min(64).max(4096),
292
- payerSignatureDerB64: Base64Std.min(16).max(2048),
293
- payeePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),
294
- payeeSignatureDerB64: Base64Std.min(16).max(2048).optional()
295
- });
296
- var ConsumerSettlementSchema = z.object({
297
- settlementId: z.string().uuid(),
298
- settlementKey: Sha256Hex,
299
- encounterId: Sha256Hex,
300
- oacId: z.string().uuid(),
301
- payerUserId: z.string().uuid(),
302
- payeeUserId: z.string().uuid(),
303
- amountKobo: z.number().int().positive(),
304
- currency: z.string().length(3),
305
- status: z.enum(["SETTLED", "REVIEW"]),
306
- reviewReason: z.string().nullable(),
307
- ledgerRef: z.string().nullable(),
308
- /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
309
- issuerSig: Base64Std.min(16).max(2048),
310
- createdAtMs: z.number().int().nonnegative()
311
- });
312
- var ConsumerSettleResultSchema = z.object({
313
- settlement: ConsumerSettlementSchema,
314
- encounterId: Sha256Hex,
315
- replayed: z.boolean()
316
- });
317
- var RevokeDeviceKeyInputSchema = z.object({
318
- deviceId: z.string().min(1).max(128),
319
- /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
320
- sendAuthToken: z.string().min(16)
321
- });
322
- function createMeOfflineClient(opts) {
323
- const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
324
- if (!fetchImpl) {
325
- throw new Error("createMeOfflineClient: no fetch implementation available");
326
- }
327
- const baseUrl = opts.baseUrl.replace(/\/$/, "");
328
- async function call(method, path, body, parser) {
329
- const init2 = {
330
- method,
331
- headers: {
332
- "content-type": "application/json",
333
- accept: "application/json"
334
- }
335
- };
336
- if (body !== void 0) init2.body = JSON.stringify(body);
337
- const resp = await fetchImpl(`${baseUrl}${path}`, init2);
338
- const text = await resp.text();
339
- let raw = void 0;
340
- if (text) {
341
- try {
342
- raw = JSON.parse(text);
343
- } catch {
344
- }
345
- }
346
- if (!resp.ok) {
347
- const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
348
- const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
349
- throw new FlurApiError(resp.status, code, message, raw);
350
- }
351
- return parser(raw);
352
- }
353
- const deviceKeyItems = z.object({ items: z.array(DeviceKeyRecordSchema) });
354
- return {
355
- registerDeviceKey: (input) => call(
356
- "POST",
357
- "/v1/me/offline/keys",
358
- RegisterDeviceKeyInputSchema.parse(input),
359
- (raw) => DeviceKeyRecordSchema.parse(raw)
360
- ),
361
- issueP256EnrollmentChallenge: (input) => call(
362
- "POST",
363
- "/v1/me/offline/keys/p256/challenge",
364
- P256EnrollmentChallengeInputSchema.parse(input),
365
- (raw) => P256EnrollmentChallengeResultSchema.parse(raw)
366
- ),
367
- registerDeviceKeyP256: (input) => call(
368
- "POST",
369
- "/v1/me/offline/keys/p256",
370
- RegisterDeviceKeyP256InputSchema.parse(input),
371
- (raw) => DeviceKeyRecordSchema.parse(raw)
372
- ),
373
- listDeviceKeys: () => call(
374
- "GET",
375
- "/v1/me/offline/keys",
376
- void 0,
377
- (raw) => deviceKeyItems.parse(raw)
378
- ),
379
- revokeDeviceKey: (input) => call(
380
- "POST",
381
- "/v1/me/offline/keys/revoke",
382
- RevokeDeviceKeyInputSchema.parse(input),
383
- () => void 0
384
- ),
385
- issueAccountOac: (input) => call(
386
- "POST",
387
- "/v1/me/offline/oac",
388
- IssueAccountOacInputSchema.parse(input),
389
- (raw) => OACRecordSchema.parse(raw)
390
- ),
391
- provisionAllowance: (input) => call(
392
- "POST",
393
- "/v1/me/offline/allowance",
394
- ProvisionOfflineAllowanceInputSchema.parse(input),
395
- (raw) => ProvisionOfflineAllowanceResultSchema.parse(raw)
396
- ),
397
- enable: (input) => call(
398
- "POST",
399
- "/v1/me/offline/enable",
400
- EnableOfflineInputSchema.parse(input),
401
- (raw) => EnableOfflineResultSchema.parse(raw)
402
- ),
403
- refresh: (input) => call(
404
- "POST",
405
- "/v1/me/offline/refresh",
406
- IssueOACInputSchema.parse(input),
407
- (raw) => OACRecordSchema.parse(raw)
408
- ),
409
- disable: (input) => call(
410
- "POST",
411
- "/v1/me/offline/disable",
412
- DisableOfflineInputSchema.parse(input),
413
- (raw) => DisableOfflineResultSchema.parse(raw)
414
- ),
415
- getStatus: (deviceId) => {
416
- const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
417
- return call(
418
- "GET",
419
- `/v1/me/offline/status${qs}`,
420
- void 0,
421
- (raw) => OfflineStatusResultSchema.parse(raw)
422
- );
423
- },
424
- getState: (deviceId) => {
425
- const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
426
- return call(
427
- "GET",
428
- `/v1/me/offline/state${qs}`,
429
- void 0,
430
- (raw) => OfflineStateResultSchema.parse(raw)
431
- );
432
- },
433
- submitClaim: (claim) => call(
434
- "POST",
435
- "/v1/me/offline/claims",
436
- ConsumerPaymentClaimSchema.parse(claim),
437
- (raw) => ConsumerSettleResultSchema.parse(raw)
438
- )
439
- };
440
- }
441
-
442
- // src/contracts.ts
443
- var E164Regex = /^\+[1-9]\d{7,14}$/;
444
- var UuidSchema = z2.string().uuid();
445
- var IsoDateSchema = z2.string().datetime({ offset: true });
446
- var CurrencySchema = z2.string().trim().length(3).transform((value) => value.toUpperCase());
447
- var HealthResponseSchema = z2.object({
448
- ok: z2.boolean()
449
- });
450
- var WelcomeResponseSchema = z2.object({
451
- message: z2.string()
452
- });
453
- var OnboardingStartRequestSchema = z2.object({
454
- phoneE164: z2.string().regex(E164Regex),
455
- appInstanceId: z2.string().min(3),
456
- platform: z2.enum(["android", "ios", "web"]),
457
- turnstileToken: z2.string().min(20).optional(),
458
- appAttestation: z2.object({
459
- provider: z2.enum(["android", "ios", "web"]),
460
- token: z2.string().min(24)
461
- }).optional(),
462
- firstName: z2.string().trim().min(1).max(80).optional(),
463
- lastName: z2.string().trim().min(1).max(80).optional()
464
- });
465
- var OnboardingStartResponseSchema = z2.object({
466
- requestId: z2.string().min(1),
467
- checkUrl: z2.string().url().optional(),
468
- expiresInSec: z2.number().int().positive(),
469
- fallback: z2.enum(["SILENT_AUTH", "OTP"])
470
- });
471
- var OnboardingCompleteRequestSchema = z2.object({
472
- requestId: z2.string().min(1),
473
- code: z2.string().min(1).max(32),
474
- appInstanceId: z2.string().min(3),
475
- fingerprintHash: z2.string().min(3).optional()
476
- });
477
- var OnboardingCompleteResponseSchema = z2.object({
478
- sessionToken: z2.string().min(1),
479
- userId: UuidSchema,
480
- restricted: z2.boolean(),
481
- risk_reasons: z2.array(
482
- z2.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
483
- ),
484
- stepUpRequired: z2.boolean().optional(),
485
- riskStatus: z2.enum(["ok", "unavailable"]).optional()
486
- });
487
- var RegisterDeviceRequestSchema = z2.object({
488
- userId: UuidSchema,
489
- appInstanceId: z2.string().min(3),
490
- platform: z2.string().min(2),
491
- model: z2.string().optional(),
492
- networkSignals: z2.object({
493
- ip: z2.string().min(3),
494
- asn: z2.number().int().optional(),
495
- country: z2.string().min(2).optional(),
496
- carrier: z2.string().optional()
497
- })
498
- });
499
- var RegisterDeviceResponseSchema = z2.object({
500
- deviceId: z2.string().min(1),
501
- fingerprintHash: z2.string().min(1),
502
- driftScore: z2.number(),
503
- trustState: z2.enum(["TRUSTED_PRIMARY", "TRUSTED_SECONDARY", "UNVERIFIED"]),
504
- stepUpRequired: z2.boolean()
505
- });
506
- var AuthRefreshRequestSchema = z2.object({
507
- userId: UuidSchema,
508
- refreshToken: z2.string().min(8),
509
- appInstanceId: z2.string().min(3),
510
- fingerprintHash: z2.string().min(3)
511
- });
512
- var AuthRefreshResponseSchema = z2.object({
513
- refreshToken: z2.string().min(8),
514
- stepUpRequired: z2.boolean()
515
- });
516
- var AuthLogoutRequestSchema = z2.object({
517
- userId: UuidSchema,
518
- refreshToken: z2.string().min(8)
519
- });
520
- var PinSetRequestSchema = z2.object({
521
- userId: UuidSchema,
522
- pin: z2.string().regex(/^\d{6}$/)
523
- });
524
- var PinVerifyRequestSchema = z2.object({
525
- userId: UuidSchema,
526
- pin: z2.string().regex(/^\d{6}$/)
527
- });
528
- var OkResponseSchema = z2.object({
529
- ok: z2.boolean()
530
- });
531
- var RegisterSendDeviceKeyRequestSchema = z2.object({
532
- userId: UuidSchema,
533
- deviceId: z2.string().min(3),
534
- publicKey: z2.string().min(32)
535
- });
536
- var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
537
- var SendChallengeRequestSchema = z2.object({
538
- userId: UuidSchema,
539
- deviceId: z2.string().min(3),
540
- purpose: z2.enum(SEND_AUTH_PURPOSES).optional()
541
- });
542
- var SendChallengeResponseSchema = z2.object({
543
- challengeId: UuidSchema,
544
- nonce: z2.string().min(1),
545
- expiresAt: IsoDateSchema
546
- });
547
- var SendVerifyRequestSchema = z2.object({
548
- userId: UuidSchema,
549
- deviceId: z2.string().min(3),
550
- challengeId: UuidSchema,
551
- signature: z2.string().min(16)
552
- });
553
- var SendVerifyResponseSchema = z2.object({
554
- sendAuthToken: z2.string().min(16)
555
- });
556
- var ResolveRecipientRequestSchema = z2.object({
557
- identifier: z2.string().min(3)
558
- });
559
- var ResolveRecipientResponseSchema = z2.object({
560
- recipientUserId: UuidSchema,
561
- displayName: z2.string().min(1),
562
- normalizedIdentifier: z2.string().regex(E164Regex),
563
- isActive: z2.boolean()
564
- });
565
- var CreateTransferRequestSchema = z2.object({
566
- recipientIdentifier: z2.string().min(3),
567
- amountMinor: z2.number().int().positive(),
568
- currency: CurrencySchema,
569
- sendAuthToken: z2.string().min(16)
570
- });
571
- var TransferStatusSchema = z2.enum(["SETTLED", "PENDING_REVIEW", "DECLINED"]);
572
- var TransferResponseSchema = z2.object({
573
- transactionId: z2.string().min(1),
574
- status: TransferStatusSchema,
575
- userStatus: TransferStatusSchema,
576
- recipientName: z2.string().min(1),
577
- timestamp: IsoDateSchema,
578
- /**
579
- * Fresh issuer-signed OACs returned by the backend's post-commit
580
- * rotation hook on `SETTLED` transfers.
581
- *
582
- * In the current backend implementation this hook rotates LEGACY
583
- * hold-backed OACs only. Account-funded (no-hold) OACs introduced by
584
- * the unified-pay-rails refactor are NOT rotated here — their
585
- * cumulative spend counter and main-balance check are enforced at
586
- * claim submission time via `createTransfer` under the per-sender
587
- * advisory lock, so a stale no-hold OAC cannot authorise overspending
588
- * (it can only resolve to REVIEW on submission).
589
- *
590
- * Optional: omitted when the sender has no registered hold-backed
591
- * devices, when the refresh failed (best-effort), or on retry replays
592
- * that pre-date the refresh. When present, the entries supersede any
593
- * locally cached OACs for the listed devices; when absent, clients
594
- * should fall back to `/v1/me/offline/refresh`.
595
- *
596
- * Each entry is validated against the canonical `OACRecordSchema`,
597
- * so consumers can trust the runtime shape matches the static type.
598
- */
599
- offlineOacs: OACRecordSchema.array().optional()
600
- });
601
- var DirectionSchema = z2.enum(["OUTGOING", "INCOMING"]);
602
- var AccountActivityItemSchema = z2.object({
603
- id: z2.string().min(1),
604
- type: z2.string().min(1),
605
- direction: DirectionSchema,
606
- name: z2.string().min(1),
607
- identifier: z2.string().min(1),
608
- amountMinor: z2.number().int(),
609
- currency: CurrencySchema,
610
- status: z2.string().min(1),
611
- timestamp: IsoDateSchema
612
- });
613
- var AccountSummaryResponseSchema = z2.object({
614
- /** Authenticated user's stable internal id. */
615
- userId: UuidSchema,
616
- /**
617
- * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the
618
- * bank partner. `null` when the user has no partner-allocated account yet.
619
- */
620
- nuban: z2.string().regex(/^[0-9]{10}$/).nullable(),
621
- balance: z2.number().int(),
622
- currency: CurrencySchema,
623
- dailySendLimit: z2.number().int().nonnegative(),
624
- dailySendRemaining: z2.number().int().nonnegative(),
625
- kycTier: z2.string().min(1),
626
- kycStatus: z2.string().min(1),
627
- recentActivity: z2.array(AccountActivityItemSchema)
628
- });
629
- var TransactionsListResponseSchema = z2.object({
630
- items: z2.array(AccountActivityItemSchema),
631
- nextCursor: z2.string().nullable()
632
- });
633
- var TransactionDetailResponseSchema = z2.object({
634
- transactionId: z2.string().min(1),
635
- type: z2.string().min(1),
636
- direction: DirectionSchema,
637
- counterpartyName: z2.string().min(1),
638
- counterpartyIdentifier: z2.string().min(1),
639
- amountMinor: z2.number().int(),
640
- currency: CurrencySchema,
641
- status: z2.string().min(1),
642
- timestamp: IsoDateSchema
643
- });
644
- var PushRegisterRequestSchema = z2.object({
645
- deviceId: z2.string().min(3),
646
- platform: z2.enum(["ios", "android", "web"]),
647
- token: z2.string().min(16)
648
- });
649
- var CreatePayLinkResponseSchema = z2.object({
650
- token: z2.string().min(1)
651
- });
652
- var ResolvePayLinkResponseSchema = z2.object({
653
- recipientUserId: UuidSchema,
654
- displayName: z2.string().min(1),
655
- normalizedIdentifier: z2.string().regex(E164Regex),
656
- isActive: z2.boolean()
657
- });
658
-
659
302
  // src/primitives.ts
660
- import { z as z3 } from "zod";
661
- var CurrencyCodeSchema = z3.string().trim().length(3).transform((value) => value.toUpperCase());
303
+ import { z as z2 } from "zod";
304
+ var CurrencyCodeSchema = z2.string().trim().length(3).transform((value) => value.toUpperCase());
662
305
  var currencyFractionDigits = {
663
306
  NGN: 2,
664
307
  USD: 2,
@@ -752,7 +395,7 @@ function moneyMinorToNumber(amountMinor) {
752
395
  }
753
396
 
754
397
  // src/collections/client.ts
755
- import { z as z4 } from "zod";
398
+ import { z as z3 } from "zod";
756
399
  var MERCHANT_PROFILE_STATUSES = [
757
400
  "pending",
758
401
  "active",
@@ -782,172 +425,172 @@ var MERCHANT_PAYOUT_STATUSES = [
782
425
  "failed",
783
426
  "cancelled"
784
427
  ];
785
- var MoneyKoboSchema = z4.number().int().positive().max(Number.MAX_SAFE_INTEGER);
786
- var MetadataSchema = z4.record(
787
- z4.union([z4.string(), z4.number(), z4.boolean(), z4.null()])
428
+ var MoneyKoboSchema = z3.number().int().positive().max(Number.MAX_SAFE_INTEGER);
429
+ var MetadataSchema = z3.record(
430
+ z3.union([z3.string(), z3.number(), z3.boolean(), z3.null()])
788
431
  );
789
- var CurrencySchema2 = z4.string().trim().length(3).transform((value) => value.toUpperCase());
790
- var ReferenceSchema = z4.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
791
- var MerchantProfileSchema = z4.object({
792
- accountId: z4.string().uuid(),
793
- legalName: z4.string(),
794
- tradingName: z4.string(),
795
- merchantCategoryCode: z4.string().regex(/^\d{4}$/),
796
- nqrMerchantId: z4.string(),
797
- settlementBankCode: z4.string(),
798
- settlementAccountNumber: z4.string(),
799
- settlementAccountName: z4.string(),
800
- settlementSchedule: z4.enum(SETTLEMENT_SCHEDULES),
801
- status: z4.enum(MERCHANT_PROFILE_STATUSES),
802
- offlineEnabled: z4.boolean(),
432
+ var CurrencySchema2 = z3.string().trim().length(3).transform((value) => value.toUpperCase());
433
+ var ReferenceSchema = z3.string().trim().min(6).max(128).regex(/^[A-Za-z0-9._:-]+$/);
434
+ var MerchantProfileSchema = z3.object({
435
+ accountId: z3.string().uuid(),
436
+ legalName: z3.string(),
437
+ tradingName: z3.string(),
438
+ merchantCategoryCode: z3.string().regex(/^\d{4}$/),
439
+ nqrMerchantId: z3.string(),
440
+ settlementBankCode: z3.string(),
441
+ settlementAccountNumber: z3.string(),
442
+ settlementAccountName: z3.string(),
443
+ settlementSchedule: z3.enum(SETTLEMENT_SCHEDULES),
444
+ status: z3.enum(MERCHANT_PROFILE_STATUSES),
445
+ offlineEnabled: z3.boolean(),
803
446
  perTxLimitKobo: MoneyKoboSchema,
804
447
  dailyLimitKobo: MoneyKoboSchema,
805
448
  metadata: MetadataSchema,
806
- createdAtMs: z4.number().int().nonnegative(),
807
- updatedAtMs: z4.number().int().nonnegative()
449
+ createdAtMs: z3.number().int().nonnegative(),
450
+ updatedAtMs: z3.number().int().nonnegative()
808
451
  });
809
- var UpsertMerchantProfileInputSchema = z4.object({
810
- legalName: z4.string().trim().min(1).max(200),
811
- tradingName: z4.string().trim().min(1).max(25),
812
- merchantCategoryCode: z4.string().trim().regex(/^\d{4}$/),
813
- nqrMerchantId: z4.string().trim().min(3).max(64),
814
- settlementBankCode: z4.string().trim().min(2).max(16),
815
- settlementAccountNumber: z4.string().trim().min(5).max(32),
816
- settlementAccountName: z4.string().trim().min(1).max(200),
817
- settlementSchedule: z4.enum(SETTLEMENT_SCHEDULES).optional(),
818
- status: z4.enum(MERCHANT_PROFILE_STATUSES).optional(),
819
- offlineEnabled: z4.boolean().optional(),
452
+ var UpsertMerchantProfileInputSchema = z3.object({
453
+ legalName: z3.string().trim().min(1).max(200),
454
+ tradingName: z3.string().trim().min(1).max(25),
455
+ merchantCategoryCode: z3.string().trim().regex(/^\d{4}$/),
456
+ nqrMerchantId: z3.string().trim().min(3).max(64),
457
+ settlementBankCode: z3.string().trim().min(2).max(16),
458
+ settlementAccountNumber: z3.string().trim().min(5).max(32),
459
+ settlementAccountName: z3.string().trim().min(1).max(200),
460
+ settlementSchedule: z3.enum(SETTLEMENT_SCHEDULES).optional(),
461
+ status: z3.enum(MERCHANT_PROFILE_STATUSES).optional(),
462
+ offlineEnabled: z3.boolean().optional(),
820
463
  perTxLimitKobo: MoneyKoboSchema.optional(),
821
464
  dailyLimitKobo: MoneyKoboSchema.optional(),
822
465
  metadata: MetadataSchema.optional()
823
466
  });
824
- var CollectionIntentSchema = z4.object({
825
- intentId: z4.string().uuid(),
826
- accountId: z4.string().uuid(),
827
- terminalId: z4.string().uuid().nullable(),
828
- reference: z4.string(),
829
- amountKobo: z4.number().int().positive().nullable(),
830
- currency: z4.string().length(3),
831
- status: z4.enum(COLLECTION_INTENT_STATUSES),
832
- description: z4.string().nullable(),
833
- nqrPayload: z4.string(),
834
- provider: z4.string(),
835
- providerReference: z4.string().nullable(),
467
+ var CollectionIntentSchema = z3.object({
468
+ intentId: z3.string().uuid(),
469
+ accountId: z3.string().uuid(),
470
+ terminalId: z3.string().uuid().nullable(),
471
+ reference: z3.string(),
472
+ amountKobo: z3.number().int().positive().nullable(),
473
+ currency: z3.string().length(3),
474
+ status: z3.enum(COLLECTION_INTENT_STATUSES),
475
+ description: z3.string().nullable(),
476
+ nqrPayload: z3.string(),
477
+ provider: z3.string(),
478
+ providerReference: z3.string().nullable(),
836
479
  metadata: MetadataSchema,
837
- expiresAtMs: z4.number().int().nonnegative().nullable(),
838
- paidAtMs: z4.number().int().nonnegative().nullable(),
839
- createdAtMs: z4.number().int().nonnegative(),
840
- updatedAtMs: z4.number().int().nonnegative()
480
+ expiresAtMs: z3.number().int().nonnegative().nullable(),
481
+ paidAtMs: z3.number().int().nonnegative().nullable(),
482
+ createdAtMs: z3.number().int().nonnegative(),
483
+ updatedAtMs: z3.number().int().nonnegative()
841
484
  });
842
- var CreateCollectionIntentInputSchema = z4.object({
485
+ var CreateCollectionIntentInputSchema = z3.object({
843
486
  reference: ReferenceSchema.optional(),
844
487
  amountKobo: MoneyKoboSchema.optional(),
845
488
  currency: CurrencySchema2.optional(),
846
- terminalId: z4.string().uuid().optional(),
847
- terminalLabel: z4.string().trim().min(1).max(25).optional(),
848
- merchantCity: z4.string().trim().min(1).max(15).optional(),
849
- description: z4.string().trim().min(1).max(280).optional(),
850
- expiresAtMs: z4.number().int().positive().optional(),
851
- provider: z4.string().trim().min(1).max(40).optional(),
489
+ terminalId: z3.string().uuid().optional(),
490
+ terminalLabel: z3.string().trim().min(1).max(25).optional(),
491
+ merchantCity: z3.string().trim().min(1).max(15).optional(),
492
+ description: z3.string().trim().min(1).max(280).optional(),
493
+ expiresAtMs: z3.number().int().positive().optional(),
494
+ provider: z3.string().trim().min(1).max(40).optional(),
852
495
  metadata: MetadataSchema.optional()
853
496
  });
854
- var PublicCollectionIntentSchema = z4.object({
855
- intentId: z4.string().uuid(),
856
- reference: z4.string(),
857
- amountKobo: z4.number().int().positive().nullable(),
858
- currency: z4.string().length(3),
859
- status: z4.enum(COLLECTION_INTENT_STATUSES),
860
- merchantAccountId: z4.string().uuid(),
861
- merchantName: z4.string(),
862
- merchantCategoryCode: z4.string(),
863
- description: z4.string().nullable(),
864
- expiresAtMs: z4.number().int().nonnegative().nullable()
497
+ var PublicCollectionIntentSchema = z3.object({
498
+ intentId: z3.string().uuid(),
499
+ reference: z3.string(),
500
+ amountKobo: z3.number().int().positive().nullable(),
501
+ currency: z3.string().length(3),
502
+ status: z3.enum(COLLECTION_INTENT_STATUSES),
503
+ merchantAccountId: z3.string().uuid(),
504
+ merchantName: z3.string(),
505
+ merchantCategoryCode: z3.string(),
506
+ description: z3.string().nullable(),
507
+ expiresAtMs: z3.number().int().nonnegative().nullable()
865
508
  });
866
- var PayCollectionInputSchema = z4.object({
509
+ var PayCollectionInputSchema = z3.object({
867
510
  reference: ReferenceSchema,
868
511
  amountKobo: MoneyKoboSchema.optional(),
869
512
  currency: CurrencySchema2.optional(),
870
- idempotencyKey: z4.string().trim().min(8).max(160).optional()
513
+ idempotencyKey: z3.string().trim().min(8).max(160).optional()
871
514
  });
872
- var CollectionPaymentSchema = z4.object({
873
- paymentId: z4.string().uuid(),
874
- intentId: z4.string().uuid(),
875
- accountId: z4.string().uuid(),
876
- payerUserId: z4.string().uuid().nullable(),
877
- merchantOwnerUserId: z4.string().uuid(),
515
+ var CollectionPaymentSchema = z3.object({
516
+ paymentId: z3.string().uuid(),
517
+ intentId: z3.string().uuid(),
518
+ accountId: z3.string().uuid(),
519
+ payerUserId: z3.string().uuid().nullable(),
520
+ merchantOwnerUserId: z3.string().uuid(),
878
521
  amountKobo: MoneyKoboSchema,
879
- currency: z4.string().length(3),
880
- status: z4.enum(COLLECTION_PAYMENT_STATUSES),
881
- provider: z4.string(),
882
- providerReference: z4.string().nullable(),
883
- idempotencyKey: z4.string().nullable(),
884
- ledgerRef: z4.string(),
885
- failureCode: z4.string().nullable(),
886
- failureMessage: z4.string().nullable(),
887
- paidAtMs: z4.number().int().nonnegative().nullable(),
888
- createdAtMs: z4.number().int().nonnegative(),
889
- updatedAtMs: z4.number().int().nonnegative()
522
+ currency: z3.string().length(3),
523
+ status: z3.enum(COLLECTION_PAYMENT_STATUSES),
524
+ provider: z3.string(),
525
+ providerReference: z3.string().nullable(),
526
+ idempotencyKey: z3.string().nullable(),
527
+ ledgerRef: z3.string(),
528
+ failureCode: z3.string().nullable(),
529
+ failureMessage: z3.string().nullable(),
530
+ paidAtMs: z3.number().int().nonnegative().nullable(),
531
+ createdAtMs: z3.number().int().nonnegative(),
532
+ updatedAtMs: z3.number().int().nonnegative()
890
533
  });
891
- var CollectionPaymentResultSchema = z4.object({
534
+ var CollectionPaymentResultSchema = z3.object({
892
535
  payment: CollectionPaymentSchema,
893
536
  intent: CollectionIntentSchema,
894
- receipt: z4.unknown().optional(),
895
- replayed: z4.boolean()
537
+ receipt: z3.unknown().optional(),
538
+ replayed: z3.boolean()
896
539
  });
897
- var CollectionReportSummarySchema = z4.object({
898
- accountId: z4.string().uuid(),
899
- fromMs: z4.number().int().nonnegative(),
900
- toMs: z4.number().int().nonnegative(),
901
- currency: z4.string().length(3),
902
- paidCount: z4.number().int().nonnegative(),
903
- paidAmountKobo: z4.number().int().nonnegative(),
904
- pendingCount: z4.number().int().nonnegative(),
905
- failedCount: z4.number().int().nonnegative(),
906
- reversedCount: z4.number().int().nonnegative(),
907
- availableBalanceKobo: z4.number().int().nonnegative()
540
+ var CollectionReportSummarySchema = z3.object({
541
+ accountId: z3.string().uuid(),
542
+ fromMs: z3.number().int().nonnegative(),
543
+ toMs: z3.number().int().nonnegative(),
544
+ currency: z3.string().length(3),
545
+ paidCount: z3.number().int().nonnegative(),
546
+ paidAmountKobo: z3.number().int().nonnegative(),
547
+ pendingCount: z3.number().int().nonnegative(),
548
+ failedCount: z3.number().int().nonnegative(),
549
+ reversedCount: z3.number().int().nonnegative(),
550
+ availableBalanceKobo: z3.number().int().nonnegative()
908
551
  });
909
- var CollectionStatementSchema = z4.object({
910
- accountId: z4.string().uuid(),
911
- year: z4.number().int(),
912
- month: z4.number().int().min(1).max(12),
913
- currency: z4.string().length(3),
914
- totalPaidKobo: z4.number().int().nonnegative(),
915
- items: z4.array(CollectionPaymentSchema)
552
+ var CollectionStatementSchema = z3.object({
553
+ accountId: z3.string().uuid(),
554
+ year: z3.number().int(),
555
+ month: z3.number().int().min(1).max(12),
556
+ currency: z3.string().length(3),
557
+ totalPaidKobo: z3.number().int().nonnegative(),
558
+ items: z3.array(CollectionPaymentSchema)
916
559
  });
917
- var CreatePayoutInputSchema = z4.object({
560
+ var CreatePayoutInputSchema = z3.object({
918
561
  amountKobo: MoneyKoboSchema,
919
562
  currency: CurrencySchema2.optional(),
920
- idempotencyKey: z4.string().trim().min(8).max(160)
563
+ idempotencyKey: z3.string().trim().min(8).max(160)
921
564
  });
922
- var MerchantPayoutSchema = z4.object({
923
- payoutId: z4.string().uuid(),
924
- accountId: z4.string().uuid(),
565
+ var MerchantPayoutSchema = z3.object({
566
+ payoutId: z3.string().uuid(),
567
+ accountId: z3.string().uuid(),
925
568
  amountKobo: MoneyKoboSchema,
926
- currency: z4.string().length(3),
927
- status: z4.enum(MERCHANT_PAYOUT_STATUSES),
928
- idempotencyKey: z4.string().nullable(),
929
- ledgerRef: z4.string(),
930
- providerReference: z4.string().nullable(),
931
- requestedByUserId: z4.string().uuid().nullable(),
932
- failureCode: z4.string().nullable(),
933
- failureMessage: z4.string().nullable(),
934
- createdAtMs: z4.number().int().nonnegative(),
935
- updatedAtMs: z4.number().int().nonnegative()
569
+ currency: z3.string().length(3),
570
+ status: z3.enum(MERCHANT_PAYOUT_STATUSES),
571
+ idempotencyKey: z3.string().nullable(),
572
+ ledgerRef: z3.string(),
573
+ providerReference: z3.string().nullable(),
574
+ requestedByUserId: z3.string().uuid().nullable(),
575
+ failureCode: z3.string().nullable(),
576
+ failureMessage: z3.string().nullable(),
577
+ createdAtMs: z3.number().int().nonnegative(),
578
+ updatedAtMs: z3.number().int().nonnegative()
936
579
  });
937
- var ProviderEventInputSchema = z4.object({
938
- provider: z4.string().trim().min(1).max(80),
939
- eventId: z4.string().trim().min(1).max(160),
940
- eventType: z4.string().trim().min(1).max(120),
941
- payload: z4.record(z4.unknown()).optional()
580
+ var ProviderEventInputSchema = z3.object({
581
+ provider: z3.string().trim().min(1).max(80),
582
+ eventId: z3.string().trim().min(1).max(160),
583
+ eventType: z3.string().trim().min(1).max(120),
584
+ payload: z3.record(z3.unknown()).optional()
942
585
  });
943
- var ProviderEventRecordSchema = z4.object({
944
- id: z4.string().uuid(),
945
- provider: z4.string(),
946
- eventId: z4.string(),
947
- eventType: z4.string(),
948
- signatureVerified: z4.boolean(),
949
- receivedAtMs: z4.number().int().nonnegative(),
950
- processedAtMs: z4.number().int().nonnegative().nullable()
586
+ var ProviderEventRecordSchema = z3.object({
587
+ id: z3.string().uuid(),
588
+ provider: z3.string(),
589
+ eventId: z3.string(),
590
+ eventType: z3.string(),
591
+ signatureVerified: z3.boolean(),
592
+ receivedAtMs: z3.number().int().nonnegative(),
593
+ processedAtMs: z3.number().int().nonnegative().nullable()
951
594
  });
952
595
  function createCollectionsClient(opts) {
953
596
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -1462,7 +1105,7 @@ var FlurClient = class {
1462
1105
  try {
1463
1106
  body = requestSchema ? JSON.stringify(requestSchema.parse(input)) : init2.body;
1464
1107
  } catch (err) {
1465
- if (err instanceof z5.ZodError) {
1108
+ if (err instanceof z4.ZodError) {
1466
1109
  throw new FlurError("Invalid request payload", "INVALID_REQUEST", {
1467
1110
  details: err.flatten()
1468
1111
  });
@@ -1490,7 +1133,7 @@ var FlurClient = class {
1490
1133
  try {
1491
1134
  return responseSchema.parse(payload);
1492
1135
  } catch (err) {
1493
- if (err instanceof z5.ZodError) {
1136
+ if (err instanceof z4.ZodError) {
1494
1137
  throw new FlurError(
1495
1138
  "SDK contract validation failed",
1496
1139
  "INVALID_REQUEST",
@@ -1921,7 +1564,7 @@ function constantTimeEqual(a, b) {
1921
1564
  }
1922
1565
 
1923
1566
  // src/offline/oac.ts
1924
- import { z as z6 } from "zod";
1567
+ import { z as z5 } from "zod";
1925
1568
 
1926
1569
  // src/crypto/p256-issuer.ts
1927
1570
  import { p256 } from "@noble/curves/nist";
@@ -2003,20 +1646,20 @@ function verifyIssuerP256(bytes, signatureB64, issuerPublicKeySpkiB64) {
2003
1646
  var OAC_DEFAULT_PER_TX_KOBO = 5e5;
2004
1647
  var OAC_DEFAULT_CUMULATIVE_KOBO = 2e6;
2005
1648
  var OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1e3;
2006
- var Base64Std2 = z6.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) string");
2007
- var OACSchema = z6.object({
2008
- userId: z6.string().min(1),
2009
- deviceId: z6.string().min(1),
1649
+ var Base64Std = z5.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) string");
1650
+ var OACSchema = z5.object({
1651
+ userId: z5.string().min(1),
1652
+ deviceId: z5.string().min(1),
2010
1653
  /** SubjectPublicKeyInfo DER, base64 (P-256). */
2011
- devicePublicKey: Base64Std2,
2012
- perTxCapKobo: z6.number().int().nonnegative(),
2013
- cumulativeCapKobo: z6.number().int().nonnegative(),
2014
- validFromMs: z6.number().int().nonnegative(),
2015
- validUntilMs: z6.number().int().positive(),
2016
- counterSeed: z6.number().int().nonnegative(),
2017
- nonce: z6.string().min(1),
1654
+ devicePublicKey: Base64Std,
1655
+ perTxCapKobo: z5.number().int().nonnegative(),
1656
+ cumulativeCapKobo: z5.number().int().nonnegative(),
1657
+ validFromMs: z5.number().int().nonnegative(),
1658
+ validUntilMs: z5.number().int().positive(),
1659
+ counterSeed: z5.number().int().nonnegative(),
1660
+ nonce: z5.string().min(1),
2018
1661
  /** ASN.1 DER ECDSA(SHA-256) signature, base64. */
2019
- issuerSig: Base64Std2
1662
+ issuerSig: Base64Std
2020
1663
  }).refine((v) => v.validUntilMs > v.validFromMs, {
2021
1664
  message: "validUntilMs must be greater than validFromMs"
2022
1665
  }).refine((v) => v.perTxCapKobo <= v.cumulativeCapKobo, {
@@ -2110,19 +1753,19 @@ function decodeBase45(s) {
2110
1753
  }
2111
1754
 
2112
1755
  // src/offline/messages.ts
2113
- import { z as z7 } from "zod";
2114
- var Base64Sig = z7.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) signature");
2115
- var OfflinePaymentRequestSchema = z7.object({
2116
- reference: z7.string().min(1),
2117
- amountKobo: z7.number().int().positive(),
1756
+ import { z as z6 } from "zod";
1757
+ var Base64Sig = z6.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (standard) signature");
1758
+ var OfflinePaymentRequestSchema = z6.object({
1759
+ reference: z6.string().min(1),
1760
+ amountKobo: z6.number().int().positive(),
2118
1761
  merchantOAC: OACSchema,
2119
- expiresAtMs: z7.number().int().positive(),
1762
+ expiresAtMs: z6.number().int().positive(),
2120
1763
  merchantSig: Base64Sig
2121
1764
  });
2122
- var OfflinePaymentAuthorizationSchema = z7.object({
1765
+ var OfflinePaymentAuthorizationSchema = z6.object({
2123
1766
  request: OfflinePaymentRequestSchema,
2124
1767
  payerOAC: OACSchema,
2125
- payerCounter: z7.number().int().positive(),
1768
+ payerCounter: z6.number().int().positive(),
2126
1769
  payerSig: Base64Sig
2127
1770
  });
2128
1771
  function buildPaymentRequest(input) {
@@ -2234,60 +1877,60 @@ function decodeAuthorizationQR(s) {
2234
1877
  }
2235
1878
 
2236
1879
  // src/offline/settlements.ts
2237
- import { z as z8 } from "zod";
1880
+ import { z as z7 } from "zod";
2238
1881
  import { sha256 } from "@noble/hashes/sha256";
2239
1882
  import { bytesToHex } from "@noble/hashes/utils";
2240
- var OfflineTokenSchema = z8.object({
2241
- tokenId: z8.string().uuid(),
2242
- tokenSerial: z8.string(),
2243
- issuerAccountId: z8.string().uuid(),
2244
- payerUserId: z8.string().uuid(),
2245
- maxAmountKobo: z8.number().int().positive(),
2246
- currency: z8.string().length(3),
2247
- issuedAtMs: z8.number().int().nonnegative(),
2248
- expiresAtMs: z8.number().int().nonnegative(),
2249
- issuerSig: z8.string()
1883
+ var OfflineTokenSchema = z7.object({
1884
+ tokenId: z7.string().uuid(),
1885
+ tokenSerial: z7.string(),
1886
+ issuerAccountId: z7.string().uuid(),
1887
+ payerUserId: z7.string().uuid(),
1888
+ maxAmountKobo: z7.number().int().positive(),
1889
+ currency: z7.string().length(3),
1890
+ issuedAtMs: z7.number().int().nonnegative(),
1891
+ expiresAtMs: z7.number().int().nonnegative(),
1892
+ issuerSig: z7.string()
2250
1893
  });
2251
- var PaymentClaimSchema = z8.object({
2252
- encounterId: z8.string().regex(/^[0-9a-f]{64}$/i).optional(),
2253
- tokenSerial: z8.string(),
2254
- payerUserId: z8.string().uuid(),
2255
- payeeUserId: z8.string().uuid(),
2256
- payerNonce: z8.string(),
2257
- payeeNonce: z8.string(),
2258
- amountKobo: z8.number().int().positive(),
2259
- currency: z8.string().length(3).default("NGN"),
2260
- occurredAtMs: z8.number().int().nonnegative(),
2261
- completedAtMs: z8.number().int().nonnegative().optional(),
2262
- contextId: z8.string().optional(),
1894
+ var PaymentClaimSchema = z7.object({
1895
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i).optional(),
1896
+ tokenSerial: z7.string(),
1897
+ payerUserId: z7.string().uuid(),
1898
+ payeeUserId: z7.string().uuid(),
1899
+ payerNonce: z7.string(),
1900
+ payeeNonce: z7.string(),
1901
+ amountKobo: z7.number().int().positive(),
1902
+ currency: z7.string().length(3).default("NGN"),
1903
+ occurredAtMs: z7.number().int().nonnegative(),
1904
+ completedAtMs: z7.number().int().nonnegative().optional(),
1905
+ contextId: z7.string().optional(),
2263
1906
  // Stage 2c: P-256 device keys are now SubjectPublicKeyInfo DER, base64.
2264
1907
  // Signatures are ASN.1 DER ECDSA(SHA-256), base64. Backwards-incompatible
2265
1908
  // wire change; the backend has the matching widening in offline-settlements
2266
1909
  // service + zod schema.
2267
- payerPubkey: z8.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2268
- payerSignature: z8.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2269
- payeePubkey: z8.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional(),
2270
- payeeSignature: z8.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional()
1910
+ payerPubkey: z7.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
1911
+ payerSignature: z7.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
1912
+ payeePubkey: z7.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional(),
1913
+ payeeSignature: z7.string().min(16).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/).optional()
2271
1914
  });
2272
- var SettlementSchema = z8.object({
2273
- settlementId: z8.string().uuid(),
2274
- settlementKey: z8.string().regex(/^[0-9a-f]{64}$/i),
2275
- encounterId: z8.string().regex(/^[0-9a-f]{64}$/i),
2276
- issuerAccountId: z8.string().uuid(),
2277
- tokenSerial: z8.string(),
2278
- payerUserId: z8.string().uuid(),
2279
- payeeUserId: z8.string().uuid(),
2280
- amountKobo: z8.number().int().nonnegative(),
2281
- currency: z8.string().length(3),
2282
- receiptId: z8.string().nullable(),
2283
- status: z8.enum(["SETTLED", "REVIEW", "REJECTED"]),
2284
- issuerSig: z8.string(),
2285
- createdAtMs: z8.number().int().nonnegative()
1915
+ var SettlementSchema = z7.object({
1916
+ settlementId: z7.string().uuid(),
1917
+ settlementKey: z7.string().regex(/^[0-9a-f]{64}$/i),
1918
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i),
1919
+ issuerAccountId: z7.string().uuid(),
1920
+ tokenSerial: z7.string(),
1921
+ payerUserId: z7.string().uuid(),
1922
+ payeeUserId: z7.string().uuid(),
1923
+ amountKobo: z7.number().int().nonnegative(),
1924
+ currency: z7.string().length(3),
1925
+ receiptId: z7.string().nullable(),
1926
+ status: z7.enum(["SETTLED", "REVIEW", "REJECTED"]),
1927
+ issuerSig: z7.string(),
1928
+ createdAtMs: z7.number().int().nonnegative()
2286
1929
  });
2287
- var SettleResponseSchema = z8.object({
1930
+ var SettleResponseSchema = z7.object({
2288
1931
  settlement: SettlementSchema,
2289
- encounterId: z8.string().regex(/^[0-9a-f]{64}$/i),
2290
- replayed: z8.boolean()
1932
+ encounterId: z7.string().regex(/^[0-9a-f]{64}$/i),
1933
+ replayed: z7.boolean()
2291
1934
  });
2292
1935
  var ENCOUNTER_DOMAIN = "offline:v1:encounter";
2293
1936
  async function sha256Hex(input) {
@@ -2461,7 +2104,7 @@ function createHmacFetch(opts) {
2461
2104
  }
2462
2105
 
2463
2106
  // src/partner/client.ts
2464
- import { z as z9 } from "zod";
2107
+ import { z as z8 } from "zod";
2465
2108
  import { sha256 as sha2563 } from "@noble/hashes/sha256";
2466
2109
  import { hmac as hmac2 } from "@noble/hashes/hmac";
2467
2110
  import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils";
@@ -2485,18 +2128,18 @@ var PARTNER_SCOPES = [
2485
2128
  "partner:payout:write",
2486
2129
  "partner:reconciliation:read"
2487
2130
  ];
2488
- var ApiCredentialPublicSchema = z9.object({
2489
- id: z9.string().uuid(),
2490
- accountId: z9.string().uuid(),
2491
- keyId: z9.string(),
2492
- scopes: z9.array(z9.enum(PARTNER_SCOPES)),
2493
- label: z9.string().nullable(),
2494
- createdAtMs: z9.number().int().nonnegative(),
2495
- lastUsedAtMs: z9.number().int().nonnegative().nullable(),
2496
- revokedAtMs: z9.number().int().nonnegative().nullable()
2131
+ var ApiCredentialPublicSchema = z8.object({
2132
+ id: z8.string().uuid(),
2133
+ accountId: z8.string().uuid(),
2134
+ keyId: z8.string(),
2135
+ scopes: z8.array(z8.enum(PARTNER_SCOPES)),
2136
+ label: z8.string().nullable(),
2137
+ createdAtMs: z8.number().int().nonnegative(),
2138
+ lastUsedAtMs: z8.number().int().nonnegative().nullable(),
2139
+ revokedAtMs: z8.number().int().nonnegative().nullable()
2497
2140
  });
2498
2141
  var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
2499
- secret: z9.string().min(1)
2142
+ secret: z8.string().min(1)
2500
2143
  });
2501
2144
  var enc = new TextEncoder();
2502
2145
  async function sha256Hex2(input) {
@@ -2653,8 +2296,8 @@ function createApiCredentialsAdminClient(opts) {
2653
2296
  }
2654
2297
  return parser(raw);
2655
2298
  }
2656
- const listSchema = z9.object({
2657
- items: z9.array(ApiCredentialPublicSchema)
2299
+ const listSchema = z8.object({
2300
+ items: z8.array(ApiCredentialPublicSchema)
2658
2301
  });
2659
2302
  return {
2660
2303
  list: (accountId) => call(
@@ -2679,7 +2322,7 @@ function createApiCredentialsAdminClient(opts) {
2679
2322
  }
2680
2323
 
2681
2324
  // src/passes/pass.ts
2682
- import { z as z10 } from "zod";
2325
+ import { z as z9 } from "zod";
2683
2326
  var PASS_KINDS = [
2684
2327
  "ride-ticket",
2685
2328
  "transit-pass",
@@ -2695,39 +2338,39 @@ var PASS_STATES = [
2695
2338
  "expired",
2696
2339
  "revoked"
2697
2340
  ];
2698
- var PassMetadataSchema = z10.record(
2699
- z10.union([z10.string(), z10.number(), z10.boolean(), z10.null()])
2341
+ var PassMetadataSchema = z9.record(
2342
+ z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
2700
2343
  );
2701
- var PassSchema = z10.object({
2702
- passId: z10.string().min(1),
2344
+ var PassSchema = z9.object({
2345
+ passId: z9.string().min(1),
2703
2346
  /** Optional client/template grouping id (server may omit). */
2704
- templateId: z10.string().min(1).optional(),
2347
+ templateId: z9.string().min(1).optional(),
2705
2348
  /** Optional human-facing holder identity (server may omit). The cryptographic binding
2706
2349
  * is `holderDevicePubkey` below. */
2707
- holderUserId: z10.string().min(1).optional(),
2708
- kind: z10.enum(PASS_KINDS),
2709
- issuerId: z10.string().min(1),
2710
- issuedAtMs: z10.number().int().nonnegative(),
2711
- validFromMs: z10.number().int().nonnegative(),
2712
- validUntilMs: z10.number().int().positive(),
2713
- state: z10.enum(PASS_STATES),
2350
+ holderUserId: z9.string().min(1).optional(),
2351
+ kind: z9.enum(PASS_KINDS),
2352
+ issuerId: z9.string().min(1),
2353
+ issuedAtMs: z9.number().int().nonnegative(),
2354
+ validFromMs: z9.number().int().nonnegative(),
2355
+ validUntilMs: z9.number().int().positive(),
2356
+ state: z9.enum(PASS_STATES),
2714
2357
  metadata: PassMetadataSchema,
2715
- nonce: z10.string().min(1),
2358
+ nonce: z9.string().min(1),
2716
2359
  /** Device id this pass is bound to (FK to backend `device_keys`). */
2717
- holderDeviceId: z10.string().min(1),
2360
+ holderDeviceId: z9.string().min(1),
2718
2361
  /** SubjectPublicKeyInfo DER (P-256) of the bound device, base64. The redemption
2719
2362
  * signature is verified against this key — it is the security-critical binding. */
2720
- holderDevicePubkey: z10.string().min(64).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2363
+ holderDevicePubkey: z9.string().min(64).max(4096).regex(/^[A-Za-z0-9+/]+={0,2}$/),
2721
2364
  /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
2722
- amountKobo: z10.number().int().nonnegative().optional(),
2365
+ amountKobo: z9.number().int().nonnegative().optional(),
2723
2366
  /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
2724
- currency: z10.string().min(3).max(8),
2367
+ currency: z9.string().min(3).max(8),
2725
2368
  /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
2726
- counterSeed: z10.number().int().nonnegative(),
2369
+ counterSeed: z9.number().int().nonnegative(),
2727
2370
  /** Optional cumulative spend cap in kobo across all redemptions of this pass. */
2728
- cumulativeCapKobo: z10.number().int().nonnegative().optional(),
2371
+ cumulativeCapKobo: z9.number().int().nonnegative().optional(),
2729
2372
  /** ASN.1 DER ECDSA P-256 signature, base64. */
2730
- issuerSig: z10.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2373
+ issuerSig: z9.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2731
2374
  }).refine((v) => v.validUntilMs > v.validFromMs, {
2732
2375
  message: "validUntilMs must be greater than validFromMs"
2733
2376
  });
@@ -2784,20 +2427,20 @@ function isPassWithinValidity(pass, nowMs) {
2784
2427
  }
2785
2428
 
2786
2429
  // src/passes/redemption.ts
2787
- import { z as z11 } from "zod";
2788
- var Base64Std3 = z11.string().min(16).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (std)");
2789
- var RedemptionSchema = z11.object({
2430
+ import { z as z10 } from "zod";
2431
+ var Base64Std2 = z10.string().min(16).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/, "expected base64 (std)");
2432
+ var RedemptionSchema = z10.object({
2790
2433
  pass: PassSchema,
2791
- redeemerId: z11.string().min(1),
2792
- redeemedAtMs: z11.number().int().nonnegative(),
2434
+ redeemerId: z10.string().min(1),
2435
+ redeemedAtMs: z10.number().int().nonnegative(),
2793
2436
  /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
2794
2437
  * and > the redeemer's lastSeenCounter for this pass. */
2795
- counter: z11.number().int().positive(),
2438
+ counter: z10.number().int().positive(),
2796
2439
  /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
2797
- amountKobo: z11.number().int().nonnegative(),
2798
- nonce: z11.string().min(1),
2440
+ amountKobo: z10.number().int().nonnegative(),
2441
+ nonce: z10.string().min(1),
2799
2442
  /** ASN.1 DER ECDSA P-256 signature over canonicalJSONBytes(unsigned), base64. */
2800
- holderSig: Base64Std3
2443
+ holderSig: Base64Std2
2801
2444
  });
2802
2445
  var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
2803
2446
  function buildRedemption(input) {
@@ -2879,40 +2522,40 @@ function verifyRedemption(r, issuerPublicKeySpkiB64) {
2879
2522
  }
2880
2523
 
2881
2524
  // src/receipts/receipt.ts
2882
- import { z as z12 } from "zod";
2525
+ import { z as z11 } from "zod";
2883
2526
  var RECEIPT_CHANNELS = ["cash", "pass"];
2884
2527
  var RECEIPT_KINDS = RECEIPT_CHANNELS;
2885
- var ReceiptPayloadSchema = z12.record(
2886
- z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()])
2528
+ var ReceiptPayloadSchema = z11.record(
2529
+ z11.union([z11.string(), z11.number(), z11.boolean(), z11.null()])
2887
2530
  );
2888
- var ReceiptSchema = z12.object({
2889
- receiptId: z12.string().min(1),
2890
- channel: z12.enum(RECEIPT_CHANNELS),
2531
+ var ReceiptSchema = z11.object({
2532
+ receiptId: z11.string().min(1),
2533
+ channel: z11.enum(RECEIPT_CHANNELS),
2891
2534
  /** Cash-channel: send_intents.id. Required when channel === 'cash'. */
2892
- intentId: z12.string().min(1).optional(),
2535
+ intentId: z11.string().min(1).optional(),
2893
2536
  /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
2894
- passRedemptionId: z12.string().min(1).optional(),
2895
- payerUserId: z12.string().min(1),
2896
- payeeUserId: z12.string().min(1),
2897
- amountKobo: z12.number().int().nonnegative(),
2898
- currency: z12.string().min(3).max(8),
2899
- issuedAtMs: z12.number().int().nonnegative(),
2900
- issuerId: z12.string().min(1),
2537
+ passRedemptionId: z11.string().min(1).optional(),
2538
+ payerUserId: z11.string().min(1),
2539
+ payeeUserId: z11.string().min(1),
2540
+ amountKobo: z11.number().int().nonnegative(),
2541
+ currency: z11.string().min(3).max(8),
2542
+ issuedAtMs: z11.number().int().nonnegative(),
2543
+ issuerId: z11.string().min(1),
2901
2544
  payload: ReceiptPayloadSchema,
2902
2545
  /** ASN.1 DER ECDSA P-256 signature, base64. */
2903
- issuerSig: z12.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2546
+ issuerSig: z11.string().min(64).max(2048).regex(/^[A-Za-z0-9+/]+={0,2}$/)
2904
2547
  }).superRefine((v, ctx) => {
2905
2548
  if (v.channel === "cash") {
2906
2549
  if (!v.intentId) {
2907
2550
  ctx.addIssue({
2908
- code: z12.ZodIssueCode.custom,
2551
+ code: z11.ZodIssueCode.custom,
2909
2552
  message: "cash receipts require intentId",
2910
2553
  path: ["intentId"]
2911
2554
  });
2912
2555
  }
2913
2556
  if (v.passRedemptionId) {
2914
2557
  ctx.addIssue({
2915
- code: z12.ZodIssueCode.custom,
2558
+ code: z11.ZodIssueCode.custom,
2916
2559
  message: "cash receipts must not carry passRedemptionId",
2917
2560
  path: ["passRedemptionId"]
2918
2561
  });
@@ -2920,14 +2563,14 @@ var ReceiptSchema = z12.object({
2920
2563
  } else if (v.channel === "pass") {
2921
2564
  if (!v.passRedemptionId) {
2922
2565
  ctx.addIssue({
2923
- code: z12.ZodIssueCode.custom,
2566
+ code: z11.ZodIssueCode.custom,
2924
2567
  message: "pass receipts require passRedemptionId",
2925
2568
  path: ["passRedemptionId"]
2926
2569
  });
2927
2570
  }
2928
2571
  if (v.intentId) {
2929
2572
  ctx.addIssue({
2930
- code: z12.ZodIssueCode.custom,
2573
+ code: z11.ZodIssueCode.custom,
2931
2574
  message: "pass receipts must not carry intentId",
2932
2575
  path: ["intentId"]
2933
2576
  });
@@ -3229,23 +2872,23 @@ function init(opts) {
3229
2872
  }
3230
2873
 
3231
2874
  // src/accounts/client.ts
3232
- import { z as z13 } from "zod";
2875
+ import { z as z12 } from "zod";
3233
2876
  var ACCOUNT_TYPES = ["personal", "business", "partner"];
3234
2877
  var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
3235
2878
  var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
3236
- var AccountSchema = z13.object({
3237
- accountId: z13.string().uuid(),
3238
- type: z13.enum(ACCOUNT_TYPES),
3239
- displayName: z13.string().min(1),
3240
- status: z13.enum(ACCOUNT_STATUSES),
3241
- ownerUserId: z13.string().uuid().nullable(),
3242
- createdAtMs: z13.number().int().nonnegative()
2879
+ var AccountSchema = z12.object({
2880
+ accountId: z12.string().uuid(),
2881
+ type: z12.enum(ACCOUNT_TYPES),
2882
+ displayName: z12.string().min(1),
2883
+ status: z12.enum(ACCOUNT_STATUSES),
2884
+ ownerUserId: z12.string().uuid().nullable(),
2885
+ createdAtMs: z12.number().int().nonnegative()
3243
2886
  });
3244
- var AccountMembershipSchema = z13.object({
3245
- accountId: z13.string().uuid(),
3246
- userId: z13.string().uuid(),
3247
- role: z13.enum(MEMBERSHIP_ROLES),
3248
- createdAtMs: z13.number().int().nonnegative()
2887
+ var AccountMembershipSchema = z12.object({
2888
+ accountId: z12.string().uuid(),
2889
+ userId: z12.string().uuid(),
2890
+ role: z12.enum(MEMBERSHIP_ROLES),
2891
+ createdAtMs: z12.number().int().nonnegative()
3249
2892
  });
3250
2893
  function createAccountsClient(opts) {
3251
2894
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
@@ -3278,9 +2921,9 @@ function createAccountsClient(opts) {
3278
2921
  }
3279
2922
  return parser(raw);
3280
2923
  }
3281
- const itemsSchema = z13.object({ items: z13.array(AccountSchema) });
3282
- const memberItemsSchema = z13.object({
3283
- items: z13.array(AccountMembershipSchema)
2924
+ const itemsSchema = z12.object({ items: z12.array(AccountSchema) });
2925
+ const memberItemsSchema = z12.object({
2926
+ items: z12.array(AccountMembershipSchema)
3284
2927
  });
3285
2928
  return {
3286
2929
  listMyAccounts: () => call(
@@ -3311,6 +2954,221 @@ function createAccountsClient(opts) {
3311
2954
  };
3312
2955
  }
3313
2956
 
2957
+ // src/me-offline/client.ts
2958
+ import { z as z13 } from "zod";
2959
+ var Sha256Hex = z13.string().regex(/^[0-9a-f]{64}$/);
2960
+ var Base64Std3 = z13.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
2961
+ var ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
2962
+ var CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1e3 * 60 * 60 * 24;
2963
+ var AttestationSecurityLevelSchema = z13.enum([
2964
+ "STRONGBOX",
2965
+ "TEE",
2966
+ "SECURE_ENCLAVE",
2967
+ "SOFTWARE"
2968
+ ]);
2969
+ var DeviceKeyAlgSchema = z13.literal("p256");
2970
+ var RegisterDeviceKeyP256InputSchema = z13.object({
2971
+ deviceId: z13.string().min(1).max(128),
2972
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
2973
+ publicKeySpkiB64: Base64Std3.min(64).max(4096),
2974
+ /** Base64 of the server-issued enrollment challenge string. */
2975
+ challengeB64: Base64Std3.min(8).max(1024),
2976
+ /** iOS App Attest payload or Android X.509 Key Attestation chain. */
2977
+ attestationChainB64: z13.array(Base64Std3.min(16).max(16384)).min(1).max(16),
2978
+ securityLevel: AttestationSecurityLevelSchema
2979
+ });
2980
+ var P256EnrollmentChallengeInputSchema = z13.object({
2981
+ deviceId: z13.string().min(1).max(128)
2982
+ });
2983
+ var P256EnrollmentChallengeResultSchema = z13.object({
2984
+ challenge: z13.string().min(16),
2985
+ expiresAtMs: z13.number().int().positive()
2986
+ });
2987
+ var DeviceKeyRecordSchema = z13.object({
2988
+ id: z13.string().uuid(),
2989
+ userId: z13.string().uuid(),
2990
+ deviceId: z13.string(),
2991
+ /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */
2992
+ alg: DeviceKeyAlgSchema.default("p256"),
2993
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
2994
+ publicKeySpkiB64: Base64Std3.nullable().default(null),
2995
+ securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
2996
+ hardwareBacked: z13.boolean().default(false),
2997
+ attestedAtMs: z13.number().int().nonnegative().nullable().default(null),
2998
+ createdAtMs: z13.number().int().nonnegative(),
2999
+ revokedAtMs: z13.number().int().nonnegative().nullable()
3000
+ });
3001
+ var ConsumerOACSchema = z13.object({
3002
+ oacId: z13.string().uuid(),
3003
+ issuerId: z13.string().min(1).max(64),
3004
+ userId: z13.string().uuid(),
3005
+ deviceId: z13.string().min(1).max(128),
3006
+ /**
3007
+ * Always 'p256'. Required on the wire (backend always emits it).
3008
+ * Kept as a literal so input/output infer identically and the schema
3009
+ * can be nested inside other response shapes without Zod input/output
3010
+ * divergence under tsup DTS bundling.
3011
+ */
3012
+ alg: z13.literal("p256"),
3013
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
3014
+ devicePubkeySpkiB64: Base64Std3.min(64).max(4096),
3015
+ perTxCapKobo: z13.number().int().positive(),
3016
+ cumulativeCapKobo: z13.number().int().positive(),
3017
+ currency: z13.string().length(3),
3018
+ validFromMs: z13.number().int().nonnegative(),
3019
+ validUntilMs: z13.number().int().nonnegative(),
3020
+ counterSeed: z13.number().int().nonnegative(),
3021
+ issuedAtMs: z13.number().int().nonnegative()
3022
+ });
3023
+ var SignedConsumerOACSchema = z13.object({
3024
+ oac: ConsumerOACSchema,
3025
+ /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
3026
+ issuerSig: Base64Std3.min(16).max(2048),
3027
+ /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */
3028
+ issuerPublicKeySpkiB64: Base64Std3.min(64).max(4096)
3029
+ });
3030
+ var OACRecordSchema = SignedConsumerOACSchema.extend({
3031
+ currentOfflineSpentKobo: z13.number().int().nonnegative(),
3032
+ status: z13.enum(["active", "superseded", "expired", "revoked"]),
3033
+ supersededAtMs: z13.number().int().nonnegative().nullable(),
3034
+ revokedAtMs: z13.number().int().nonnegative().nullable()
3035
+ });
3036
+ var IssueAccountOacInputSchema = z13.object({
3037
+ deviceId: z13.string().min(1).max(128),
3038
+ perTxCapKobo: z13.number().int().positive().optional(),
3039
+ cumulativeCapKobo: z13.number().int().positive().optional(),
3040
+ ttlMs: z13.number().int().min(6e4).max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS).optional()
3041
+ });
3042
+ var OfflineStatusResultSchema = z13.object({
3043
+ active: OACRecordSchema.nullable()
3044
+ });
3045
+ var ConsumerPaymentClaimSchema = z13.object({
3046
+ /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */
3047
+ alg: z13.literal("p256").default("p256"),
3048
+ oacId: z13.string().uuid(),
3049
+ encounterId: Sha256Hex.optional(),
3050
+ payerUserId: z13.string().uuid(),
3051
+ payeeUserId: z13.string().uuid(),
3052
+ payerDeviceId: z13.string().min(1).max(128),
3053
+ payerNonce: z13.string().min(8).max(128),
3054
+ payeeNonce: z13.string().min(8).max(128),
3055
+ amountKobo: z13.number().int().positive(),
3056
+ currency: z13.string().length(3).default("NGN"),
3057
+ occurredAtMs: z13.number().int().nonnegative(),
3058
+ completedAtMs: z13.number().int().nonnegative().optional(),
3059
+ contextId: z13.string().max(128).optional(),
3060
+ payerPubkeySpkiB64: Base64Std3.min(64).max(4096),
3061
+ payerSignatureDerB64: Base64Std3.min(16).max(2048),
3062
+ payeePubkeySpkiB64: Base64Std3.min(64).max(4096).optional(),
3063
+ payeeSignatureDerB64: Base64Std3.min(16).max(2048).optional()
3064
+ });
3065
+ var ConsumerSettlementSchema = z13.object({
3066
+ settlementId: z13.string().uuid(),
3067
+ settlementKey: Sha256Hex,
3068
+ encounterId: Sha256Hex,
3069
+ oacId: z13.string().uuid(),
3070
+ payerUserId: z13.string().uuid(),
3071
+ payeeUserId: z13.string().uuid(),
3072
+ amountKobo: z13.number().int().positive(),
3073
+ currency: z13.string().length(3),
3074
+ status: z13.enum(["SETTLED", "REVIEW"]),
3075
+ reviewReason: z13.string().nullable(),
3076
+ ledgerRef: z13.string().nullable(),
3077
+ /** ASN.1 DER ECDSA P-256 issuer signature, base64. */
3078
+ issuerSig: Base64Std3.min(16).max(2048),
3079
+ createdAtMs: z13.number().int().nonnegative()
3080
+ });
3081
+ var ConsumerSettleResultSchema = z13.object({
3082
+ settlement: ConsumerSettlementSchema,
3083
+ encounterId: Sha256Hex,
3084
+ replayed: z13.boolean()
3085
+ });
3086
+ var RevokeDeviceKeyInputSchema = z13.object({
3087
+ deviceId: z13.string().min(1).max(128),
3088
+ /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
3089
+ sendAuthToken: z13.string().min(16)
3090
+ });
3091
+ function createMeOfflineClient(opts) {
3092
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3093
+ if (!fetchImpl) {
3094
+ throw new Error("createMeOfflineClient: no fetch implementation available");
3095
+ }
3096
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
3097
+ async function call(method, path, body, parser) {
3098
+ const init2 = {
3099
+ method,
3100
+ headers: {
3101
+ "content-type": "application/json",
3102
+ accept: "application/json"
3103
+ }
3104
+ };
3105
+ if (body !== void 0) init2.body = JSON.stringify(body);
3106
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
3107
+ const text = await resp.text();
3108
+ let raw = void 0;
3109
+ if (text) {
3110
+ try {
3111
+ raw = JSON.parse(text);
3112
+ } catch {
3113
+ }
3114
+ }
3115
+ if (!resp.ok) {
3116
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
3117
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
3118
+ throw new FlurApiError(resp.status, code, message, raw);
3119
+ }
3120
+ return parser(raw);
3121
+ }
3122
+ const deviceKeyItems = z13.object({ items: z13.array(DeviceKeyRecordSchema) });
3123
+ return {
3124
+ issueP256EnrollmentChallenge: (input) => call(
3125
+ "POST",
3126
+ "/v1/me/offline/keys/p256/challenge",
3127
+ P256EnrollmentChallengeInputSchema.parse(input),
3128
+ (raw) => P256EnrollmentChallengeResultSchema.parse(raw)
3129
+ ),
3130
+ registerDeviceKeyP256: (input) => call(
3131
+ "POST",
3132
+ "/v1/me/offline/keys/p256",
3133
+ RegisterDeviceKeyP256InputSchema.parse(input),
3134
+ (raw) => DeviceKeyRecordSchema.parse(raw)
3135
+ ),
3136
+ listDeviceKeys: () => call(
3137
+ "GET",
3138
+ "/v1/me/offline/keys",
3139
+ void 0,
3140
+ (raw) => deviceKeyItems.parse(raw)
3141
+ ),
3142
+ revokeDeviceKey: (input) => call(
3143
+ "POST",
3144
+ "/v1/me/offline/keys/revoke",
3145
+ RevokeDeviceKeyInputSchema.parse(input),
3146
+ () => void 0
3147
+ ),
3148
+ issueAccountOac: (input) => call(
3149
+ "POST",
3150
+ "/v1/me/offline/oac",
3151
+ IssueAccountOacInputSchema.parse(input),
3152
+ (raw) => OACRecordSchema.parse(raw)
3153
+ ),
3154
+ getStatus: (deviceId) => {
3155
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
3156
+ return call(
3157
+ "GET",
3158
+ `/v1/me/offline/status${qs}`,
3159
+ void 0,
3160
+ (raw) => OfflineStatusResultSchema.parse(raw)
3161
+ );
3162
+ },
3163
+ submitClaim: (claim) => call(
3164
+ "POST",
3165
+ "/v1/me/offline/claims",
3166
+ ConsumerPaymentClaimSchema.parse(claim),
3167
+ (raw) => ConsumerSettleResultSchema.parse(raw)
3168
+ )
3169
+ };
3170
+ }
3171
+
3314
3172
  // src/me-offline/signer.ts
3315
3173
  import { p256 as p2562 } from "@noble/curves/nist";
3316
3174
  var CLAIM_DOMAIN_V2 = "flur:consumer-offline:v2:claim";
@@ -4217,6 +4075,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4217
4075
  });
4218
4076
  }
4219
4077
  export {
4078
+ ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
4220
4079
  ACCOUNT_STATUSES,
4221
4080
  ACCOUNT_TYPES,
4222
4081
  ADDITIONAL_DATA_SUBFIELD,
@@ -4230,6 +4089,7 @@ export {
4230
4089
  CLAIM_DOMAIN_V2,
4231
4090
  COLLECTION_INTENT_STATUSES,
4232
4091
  COLLECTION_PAYMENT_STATUSES,
4092
+ CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS,
4233
4093
  CUSTODIAL_MODES,
4234
4094
  CollectionIntentSchema,
4235
4095
  CollectionPaymentResultSchema,
@@ -4248,10 +4108,6 @@ export {
4248
4108
  CreateWithdrawalResultSchema,
4249
4109
  DeviceKeyAlgSchema,
4250
4110
  DeviceKeyRecordSchema,
4251
- DisableOfflineInputSchema,
4252
- DisableOfflineResultSchema,
4253
- EnableOfflineInputSchema,
4254
- EnableOfflineResultSchema,
4255
4111
  FIELD,
4256
4112
  FLUR_ARTIFACT_URI_PREFIX,
4257
4113
  FLUR_ARTIFACT_URI_SCHEME,
@@ -4267,7 +4123,6 @@ export {
4267
4123
  IdentityArtifactSchema,
4268
4124
  IngestFundingResultSchema,
4269
4125
  IssueAccountOacInputSchema,
4270
- IssueOACInputSchema,
4271
4126
  LedgerJournalEntryArtifactSchema,
4272
4127
  ListPayoutDestinationsResultSchema,
4273
4128
  MEMBERSHIP_ROLES,
@@ -4286,11 +4141,9 @@ export {
4286
4141
  OAC_DEFAULT_VALIDITY_MS,
4287
4142
  OFFLINE_CLAIM_SMS_PREFIX,
4288
4143
  OfflineClaimArtifactSchema,
4289
- OfflineHoldRecordSchema,
4290
4144
  OfflinePaymentAuthorizationArtifactSchema,
4291
4145
  OfflinePaymentAuthorizationSchema,
4292
4146
  OfflinePaymentRequestSchema,
4293
- OfflineStateResultSchema,
4294
4147
  OfflineStatusResultSchema,
4295
4148
  OfflineTokenSchema,
4296
4149
  P256EnrollmentChallengeInputSchema,
@@ -4318,8 +4171,6 @@ export {
4318
4171
  PayoutEventInputSchema,
4319
4172
  ProviderEventInputSchema,
4320
4173
  ProviderEventRecordSchema,
4321
- ProvisionOfflineAllowanceInputSchema,
4322
- ProvisionOfflineAllowanceResultSchema,
4323
4174
  PublicCollectionIntentSchema,
4324
4175
  RECEIPT_CHANNELS,
4325
4176
  RECEIPT_KINDS,
@@ -4330,7 +4181,6 @@ export {
4330
4181
  ReconciliationReportSchema,
4331
4182
  RecordPayoutEventResultSchema,
4332
4183
  RedemptionSchema,
4333
- RegisterDeviceKeyInputSchema,
4334
4184
  RegisterDeviceKeyP256InputSchema,
4335
4185
  ReversalRecordArtifactSchema,
4336
4186
  RevokeDeviceKeyInputSchema,