@nokinc-flur/sdk 2.5.0 → 3.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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/contracts.ts","../src/errors.ts","../src/primitives.ts","../src/collections/client.ts","../src/nqr/fields.ts","../src/nqr/crc16.ts","../src/nqr/tlv.ts","../src/nqr/encoder.ts","../src/nqr/parser.ts","../src/nqr/routing.ts","../src/crypto/canonical.ts","../src/crypto/ct.ts","../src/offline/oac.ts","../src/crypto/p256-issuer.ts","../src/offline/codec.ts","../src/offline/messages.ts","../src/offline/settlements.ts","../src/auth/hmac.ts","../src/auth/middleware.ts","../src/partner/client.ts","../src/passes/pass.ts","../src/passes/redemption.ts","../src/receipts/receipt.ts","../src/passes/client.ts","../src/receipts/client.ts","../src/client/flur.ts","../src/accounts/client.ts","../src/me-offline/client.ts","../src/me-offline/revocation.ts","../src/me-offline/signer.ts","../src/me-offline/request.ts","../src/me-offline/settlement.ts","../src/me-offline/oac.ts","../src/me-offline/sms.ts","../src/partner-funding/client.ts","../src/artifacts/envelope.ts","../src/artifacts/types.ts","../src/artifacts/codec.ts"],"sourcesContent":["import { z, type ZodType } from 'zod';\nimport {\n AccountSummaryResponseSchema,\n AuthLogoutRequestSchema,\n AuthRefreshRequestSchema,\n AuthRefreshResponseSchema,\n CreatePayLinkResponseSchema,\n CreateTransferRequestSchema,\n E164Regex,\n HealthResponseSchema,\n OkResponseSchema,\n OnboardingCompleteRequestSchema,\n OnboardingCompleteResponseSchema,\n OnboardingStartRequestSchema,\n OnboardingStartResponseSchema,\n PinSetRequestSchema,\n PinVerifyRequestSchema,\n PushRegisterRequestSchema,\n RegisterDeviceRequestSchema,\n RegisterDeviceResponseSchema,\n RegisterSendDeviceKeyRequestSchema,\n ResolvePayLinkResponseSchema,\n ResolveRecipientRequestSchema,\n ResolveRecipientResponseSchema,\n SendChallengeRequestSchema,\n SendChallengeResponseSchema,\n SendVerifyRequestSchema,\n SendVerifyResponseSchema,\n TransactionDetailResponseSchema,\n TransactionsListResponseSchema,\n TransferResponseSchema,\n WelcomeResponseSchema,\n} from './contracts.js';\nimport { FlurError, mapToFlurError } from './errors.js';\nimport { type Money, moneyMinorToNumber, normalizeE164 } from './primitives.js';\nimport {\n CollectionPaymentResultSchema,\n PayCollectionInputSchema,\n PublicCollectionIntentSchema,\n type CollectionPaymentResult,\n type PayCollectionInput as CollectionPayInput,\n type PublicCollectionIntent,\n} from './collections/index.js';\n\nexport type FlurClientOptions = {\n baseUrl: string;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n getExtraHeaders?: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n};\n\nexport type OnboardingFallback = 'SILENT_AUTH' | 'OTP';\n\nexport type OnboardingStartInput = {\n phoneE164: string;\n appInstanceId: string;\n platform: 'android' | 'ios' | 'web';\n turnstileToken?: string;\n appAttestation?: {\n provider: 'android' | 'ios' | 'web';\n token: string;\n };\n firstName?: string;\n lastName?: string;\n};\n\nexport type OnboardingStartResponse = {\n requestId: string;\n checkUrl?: string;\n expiresInSec: number;\n fallback: OnboardingFallback;\n};\n\nexport type OnboardingRiskReason =\n | 'SIM_SWAP_RECENT'\n | 'ROAMING'\n | 'CARRIER_CHANGED';\n\nexport type OnboardingCompleteInput = {\n requestId: string;\n code: string;\n appInstanceId: string;\n fingerprintHash?: string;\n};\n\nexport type OnboardingCompleteResponse = {\n sessionToken: string;\n userId: string;\n restricted: boolean;\n risk_reasons: OnboardingRiskReason[];\n stepUpRequired?: boolean;\n riskStatus?: 'ok' | 'unavailable';\n};\n\nexport type RegisterDeviceInput = {\n userId: string;\n appInstanceId: string;\n platform: string;\n model?: string;\n networkSignals: {\n ip: string;\n asn?: number;\n country?: string;\n carrier?: string;\n };\n};\n\nexport type DeviceTrustState =\n | 'TRUSTED_PRIMARY'\n | 'TRUSTED_SECONDARY'\n | 'UNVERIFIED';\n\nexport type RegisterDeviceResponse = {\n deviceId: string;\n fingerprintHash: string;\n driftScore: number;\n trustState: DeviceTrustState;\n stepUpRequired: boolean;\n};\n\nexport type AuthRefreshInput = {\n userId: string;\n refreshToken: string;\n appInstanceId: string;\n fingerprintHash: string;\n};\n\nexport type AuthRefreshResponse = {\n refreshToken: string;\n stepUpRequired: boolean;\n};\n\nexport type AuthLogoutInput = {\n userId: string;\n refreshToken: string;\n};\n\nexport type PinSetInput = {\n userId: string;\n pin: string;\n};\n\nexport type PinVerifyInput = {\n userId: string;\n pin: string;\n};\n\nexport type RegisterSendDeviceKeyInput = {\n userId: string;\n deviceId: string;\n publicKey: string;\n};\n\nexport type SendChallengeInput = {\n userId: string;\n deviceId: string;\n /** Optional step-up purpose. Backend defaults to 'send_money'. */\n purpose?: 'send_money' | 'offline_revoke';\n};\n\nexport type SendChallengeResponse = {\n challengeId: string;\n nonce: string;\n expiresAt: string;\n};\n\nexport type SendVerifyInput = {\n userId: string;\n deviceId: string;\n challengeId: string;\n signature: string;\n};\n\nexport type SendVerifyResponse = {\n sendAuthToken: string;\n};\n\nexport type RecipientResolveInput = {\n identifier: string;\n};\n\nexport type RecipientResolveResponse = {\n recipientUserId: string;\n displayName: string;\n normalizedIdentifier: string;\n isActive: boolean;\n};\n\nexport type TransferInput = {\n recipientIdentifier: string;\n amountMinor: number;\n currency: string;\n sendAuthToken: string;\n};\n\nexport type TransferStatus = 'SETTLED' | 'PENDING_REVIEW' | 'DECLINED';\n\n/**\n * Successful response from `POST /api/v1/transfers`. Derived directly\n * from the canonical Zod schema so the static type and the runtime\n * parser stay in lockstep with the backend response.\n */\nexport type TransferResponse = z.infer<typeof TransferResponseSchema>;\n\nexport type TransactionDirection = 'OUTGOING' | 'INCOMING';\n\nexport type AccountActivityItem = {\n id: string;\n type: string;\n direction: TransactionDirection;\n name: string;\n identifier: string;\n amountMinor: number;\n currency: string;\n status: string;\n timestamp: string;\n};\n\nexport type AccountSummaryResponse = {\n userId: string;\n nuban: string | null;\n balance: number;\n currency: string;\n dailySendLimit: number;\n dailySendRemaining: number;\n kycTier: string;\n kycStatus: string;\n recentActivity: AccountActivityItem[];\n};\n\nexport type TransactionsListResponse = {\n items: AccountActivityItem[];\n nextCursor: string | null;\n};\n\nexport type TransactionDetailResponse = {\n transactionId: string;\n type: string;\n direction: TransactionDirection;\n counterpartyName: string;\n counterpartyIdentifier: string;\n amountMinor: number;\n currency: string;\n status: string;\n timestamp: string;\n};\n\nexport type PushPlatform = 'ios' | 'android' | 'web';\n\nexport type PushRegisterInput = {\n deviceId: string;\n platform: PushPlatform;\n token: string;\n};\n\nexport type CreatePayLinkResponse = {\n token: string;\n};\n\nexport type ResolvePayLinkResponse = {\n recipientUserId: string;\n displayName: string;\n normalizedIdentifier: string;\n isActive: boolean;\n};\n\nexport type AuthorizedOptions = {\n accessToken: string;\n};\n\nexport type CreateTransferOptions = AuthorizedOptions & {\n deviceId: string;\n idempotencyKey: string;\n};\n\nexport type ListTransactionsOptions = AuthorizedOptions & {\n cursor?: string;\n limit?: number;\n};\n\nexport type BiometricSigner = {\n getOrCreateKeyPair(deviceId: string): Promise<string>;\n sign(payload: string): Promise<string>;\n};\n\nexport type SendMoneyInput = {\n recipientIdentifier: string;\n money: Money;\n sendAuthToken: string;\n idempotencyKey?: string;\n defaultCountry?: string;\n};\n\nexport type SendMoneyOptions = AuthorizedOptions & {\n deviceId: string;\n};\n\nexport type ResolveCollectionOptions = AuthorizedOptions;\n\nexport type PayCollectionOptions = AuthorizedOptions & {\n idempotencyKey?: string;\n};\n\nexport type ResolveCollectionResponse = PublicCollectionIntent;\nexport type PayCollectionResponse = CollectionPaymentResult;\n\nexport type AuthorizeSendWithBiometricInput = {\n userId: string;\n deviceId: string;\n accessToken: string;\n signer: BiometricSigner;\n};\n\nexport class FlurClient {\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly getExtraHeaders?: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n\n constructor(opts: FlurClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.fetchImpl = opts.fetchImpl ?? fetch;\n this.timeoutMs = opts.timeoutMs ?? 10_000;\n this.getExtraHeaders = opts.getExtraHeaders;\n }\n\n async health(): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/health',\n { method: 'GET' },\n undefined,\n HealthResponseSchema,\n );\n }\n\n async welcome(): Promise<{ message: string }> {\n return this.requestJson(\n '/welcome',\n { method: 'GET' },\n undefined,\n WelcomeResponseSchema,\n );\n }\n\n async onboardingStart(\n input: OnboardingStartInput,\n ): Promise<OnboardingStartResponse> {\n return this.requestJson(\n '/v1/onboarding/start',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n },\n OnboardingStartRequestSchema,\n OnboardingStartResponseSchema,\n input,\n );\n }\n\n async onboardingComplete(\n input: OnboardingCompleteInput,\n ): Promise<OnboardingCompleteResponse> {\n return this.requestJson(\n '/v1/onboarding/complete',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n },\n OnboardingCompleteRequestSchema,\n OnboardingCompleteResponseSchema,\n input,\n );\n }\n\n async registerDevice(\n input: RegisterDeviceInput,\n options: AuthorizedOptions,\n ): Promise<RegisterDeviceResponse> {\n return this.requestJson(\n '/v1/devices/register',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n RegisterDeviceRequestSchema,\n RegisterDeviceResponseSchema,\n input,\n );\n }\n\n async authRefresh(input: AuthRefreshInput): Promise<AuthRefreshResponse> {\n return this.requestJson(\n '/v1/auth/refresh',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n },\n AuthRefreshRequestSchema,\n AuthRefreshResponseSchema,\n input,\n );\n }\n\n async authLogout(\n input: AuthLogoutInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/v1/auth/logout',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n AuthLogoutRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async pinSet(\n input: PinSetInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/v1/auth/pin/set',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n PinSetRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async pinVerify(\n input: PinVerifyInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/v1/auth/pin/verify',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n PinVerifyRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async registerSendDeviceKey(\n input: RegisterSendDeviceKeyInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/api/v1/auth/send/device-key',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n RegisterSendDeviceKeyRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async createSendChallenge(\n input: SendChallengeInput,\n options: AuthorizedOptions,\n ): Promise<SendChallengeResponse> {\n return this.requestJson(\n '/api/v1/auth/send/challenge',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n SendChallengeRequestSchema,\n SendChallengeResponseSchema,\n input,\n );\n }\n\n async verifySendChallenge(\n input: SendVerifyInput,\n options: AuthorizedOptions,\n ): Promise<SendVerifyResponse> {\n return this.requestJson(\n '/api/v1/auth/send/verify',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n SendVerifyRequestSchema,\n SendVerifyResponseSchema,\n input,\n );\n }\n\n async registerBiometricDeviceKey(input: {\n userId: string;\n deviceId: string;\n accessToken: string;\n signer: BiometricSigner;\n }): Promise<{ ok: boolean }> {\n const publicKey = await input.signer.getOrCreateKeyPair(input.deviceId);\n return this.registerSendDeviceKey(\n {\n userId: input.userId,\n deviceId: input.deviceId,\n publicKey,\n },\n { accessToken: input.accessToken },\n );\n }\n\n async authorizeSendWithBiometric(\n input: AuthorizeSendWithBiometricInput,\n ): Promise<SendVerifyResponse> {\n const challenge = await this.createSendChallenge(\n {\n userId: input.userId,\n deviceId: input.deviceId,\n },\n { accessToken: input.accessToken },\n );\n\n const signature = await input.signer.sign(challenge.nonce);\n return this.verifySendChallenge(\n {\n userId: input.userId,\n deviceId: input.deviceId,\n challengeId: challenge.challengeId,\n signature,\n },\n { accessToken: input.accessToken },\n );\n }\n\n async resolveRecipient(\n input: RecipientResolveInput,\n options: AuthorizedOptions,\n ): Promise<RecipientResolveResponse> {\n return this.requestJson(\n '/api/v1/recipients/resolve',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n ResolveRecipientRequestSchema,\n ResolveRecipientResponseSchema,\n input,\n );\n }\n\n async createTransfer(\n input: TransferInput,\n options: CreateTransferOptions,\n ): Promise<TransferResponse> {\n return this.requestJson(\n '/api/v1/transfers',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n 'x-device-id': options.deviceId,\n 'x-idempotency-key': options.idempotencyKey,\n },\n },\n CreateTransferRequestSchema,\n TransferResponseSchema,\n input,\n );\n }\n\n async sendMoney(\n input: SendMoneyInput,\n options: SendMoneyOptions,\n ): Promise<TransferResponse> {\n const normalizedRecipient = E164Regex.test(input.recipientIdentifier)\n ? input.recipientIdentifier\n : normalizeE164(input.recipientIdentifier, input.defaultCountry);\n\n const idempotencyKey = input.idempotencyKey ?? getSecureRandomUuid();\n return this.createTransfer(\n {\n recipientIdentifier: normalizedRecipient,\n amountMinor: moneyMinorToNumber(input.money.amountMinor),\n currency: input.money.currency,\n sendAuthToken: input.sendAuthToken,\n },\n {\n accessToken: options.accessToken,\n deviceId: options.deviceId,\n idempotencyKey,\n },\n );\n }\n\n async resolveCollection(\n reference: string,\n options: ResolveCollectionOptions,\n ): Promise<ResolveCollectionResponse> {\n return this.requestJson(\n `/v1/collections/resolve/${encodeURIComponent(reference)}`,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n PublicCollectionIntentSchema,\n );\n }\n\n async payCollection(\n input: CollectionPayInput,\n options: PayCollectionOptions,\n ): Promise<PayCollectionResponse> {\n const idempotencyKey =\n input.idempotencyKey ?? options.idempotencyKey ?? getSecureRandomUuid();\n return this.requestJson(\n '/v1/collections/pay',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n 'x-idempotency-key': idempotencyKey,\n },\n },\n PayCollectionInputSchema,\n CollectionPaymentResultSchema,\n { ...input, idempotencyKey },\n );\n }\n\n async accountSummary(\n options: AuthorizedOptions,\n ): Promise<AccountSummaryResponse> {\n return this.requestJson(\n '/api/v1/account/summary',\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n AccountSummaryResponseSchema,\n );\n }\n\n async listTransactions(\n options: ListTransactionsOptions,\n ): Promise<TransactionsListResponse> {\n const query = new URLSearchParams();\n if (\n typeof options.cursor === 'string' &&\n options.cursor.trim().length > 0\n ) {\n query.set('cursor', options.cursor);\n }\n if (typeof options.limit === 'number') {\n query.set('limit', String(options.limit));\n }\n\n const path =\n query.size > 0\n ? `/api/v1/transactions?${query.toString()}`\n : '/api/v1/transactions';\n return this.requestJson(\n path,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n TransactionsListResponseSchema,\n );\n }\n\n async transactionDetail(\n transactionId: string,\n options: AuthorizedOptions,\n ): Promise<TransactionDetailResponse> {\n const encodedId = encodeURIComponent(transactionId);\n return this.requestJson(\n `/api/v1/transactions/${encodedId}`,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n TransactionDetailResponseSchema,\n );\n }\n\n async registerPushToken(\n input: PushRegisterInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/api/v1/push/register',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n PushRegisterRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async createPayLink(\n options: AuthorizedOptions,\n ): Promise<CreatePayLinkResponse> {\n return this.requestJson(\n '/api/v1/pay-links',\n {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n CreatePayLinkResponseSchema,\n );\n }\n\n async resolvePayLink(\n token: string,\n options: AuthorizedOptions,\n ): Promise<ResolvePayLinkResponse> {\n const encodedToken = encodeURIComponent(token);\n return this.requestJson(\n `/api/v1/pay-links/${encodedToken}`,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n ResolvePayLinkResponseSchema,\n );\n }\n\n private async requestJson<TInput, TOutput>(\n path: string,\n init: RequestInit,\n requestSchema?: ZodType<TInput>,\n responseSchema?: ZodType<TOutput>,\n input?: TInput,\n ): Promise<TOutput> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const t = setTimeout(() => controller.abort(), this.timeoutMs);\n let body = init.body;\n try {\n body = requestSchema\n ? JSON.stringify(requestSchema.parse(input))\n : init.body;\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new FlurError('Invalid request payload', 'INVALID_REQUEST', {\n details: err.flatten(),\n });\n }\n throw err;\n }\n\n try {\n let extraHeaders: Record<string, string> = {};\n if (this.getExtraHeaders) {\n extraHeaders = await this.getExtraHeaders();\n }\n\n const finalHeaders = {\n ...init.headers,\n ...extraHeaders,\n };\n\n const res = await this.fetchImpl(url, {\n ...init,\n headers: finalHeaders,\n body,\n signal: controller.signal,\n });\n if (!res.ok) throw await mapToFlurError(res);\n const payload = (await res.json()) as unknown;\n if (!responseSchema) return payload as TOutput;\n try {\n return responseSchema.parse(payload);\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new FlurError(\n 'SDK contract validation failed',\n 'INVALID_REQUEST',\n {\n details: err.flatten(),\n },\n );\n }\n throw err;\n }\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new FlurError('Request timed out', 'TIMEOUT');\n }\n if (err instanceof FlurError) throw err;\n throw new FlurError('Network error', 'NETWORK_ERROR', {\n details: String(err),\n });\n } finally {\n clearTimeout(t);\n }\n }\n}\n\nfunction getSecureRandomUuid(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID();\n }\n throw new FlurError(\n 'Secure UUID generator unavailable; provide idempotencyKey',\n 'INVALID_REQUEST',\n );\n}\n","import { z } from 'zod';\n\nexport const E164Regex = /^\\+[1-9]\\d{7,14}$/;\n\nconst UuidSchema = z.string().uuid();\nconst IsoDateSchema = z.string().datetime({ offset: true });\nconst CurrencySchema = z\n .string()\n .trim()\n .length(3)\n .transform((value) => value.toUpperCase());\n\nexport const HealthResponseSchema = z.object({\n ok: z.boolean(),\n});\n\nexport const WelcomeResponseSchema = z.object({\n message: z.string(),\n});\n\nexport const OnboardingStartRequestSchema = z.object({\n phoneE164: z.string().regex(E164Regex),\n appInstanceId: z.string().min(3),\n platform: z.enum(['android', 'ios', 'web']),\n turnstileToken: z.string().min(20).optional(),\n appAttestation: z\n .object({\n provider: z.enum(['android', 'ios', 'web']),\n token: z.string().min(24),\n })\n .optional(),\n firstName: z.string().trim().min(1).max(80).optional(),\n lastName: z.string().trim().min(1).max(80).optional(),\n});\n\nexport const OnboardingStartResponseSchema = z.object({\n requestId: z.string().min(1),\n checkUrl: z.string().url().optional(),\n expiresInSec: z.number().int().positive(),\n fallback: z.enum(['SILENT_AUTH', 'OTP']),\n});\n\nexport const OnboardingCompleteRequestSchema = z.object({\n requestId: z.string().min(1),\n code: z.string().min(1).max(32),\n appInstanceId: z.string().min(3),\n fingerprintHash: z.string().min(3).optional(),\n});\n\nexport const OnboardingCompleteResponseSchema = z.object({\n sessionToken: z.string().min(1),\n userId: UuidSchema,\n restricted: z.boolean(),\n risk_reasons: z.array(\n z.enum(['SIM_SWAP_RECENT', 'ROAMING', 'CARRIER_CHANGED']),\n ),\n stepUpRequired: z.boolean().optional(),\n riskStatus: z.enum(['ok', 'unavailable']).optional(),\n});\n\nexport const RegisterDeviceRequestSchema = z.object({\n userId: UuidSchema,\n appInstanceId: z.string().min(3),\n platform: z.string().min(2),\n model: z.string().optional(),\n networkSignals: z.object({\n ip: z.string().min(3),\n asn: z.number().int().optional(),\n country: z.string().min(2).optional(),\n carrier: z.string().optional(),\n }),\n});\n\nexport const RegisterDeviceResponseSchema = z.object({\n deviceId: z.string().min(1),\n fingerprintHash: z.string().min(1),\n driftScore: z.number(),\n trustState: z.enum(['TRUSTED_PRIMARY', 'TRUSTED_SECONDARY', 'UNVERIFIED']),\n stepUpRequired: z.boolean(),\n});\n\nexport const AuthRefreshRequestSchema = z.object({\n userId: UuidSchema,\n refreshToken: z.string().min(8),\n appInstanceId: z.string().min(3),\n fingerprintHash: z.string().min(3),\n});\n\nexport const AuthRefreshResponseSchema = z.object({\n refreshToken: z.string().min(8),\n stepUpRequired: z.boolean(),\n});\n\nexport const AuthLogoutRequestSchema = z.object({\n userId: UuidSchema,\n refreshToken: z.string().min(8),\n});\n\nexport const PinSetRequestSchema = z.object({\n userId: UuidSchema,\n pin: z.string().regex(/^\\d{6}$/),\n});\n\nexport const PinVerifyRequestSchema = z.object({\n userId: UuidSchema,\n pin: z.string().regex(/^\\d{6}$/),\n});\n\nexport const OkResponseSchema = z.object({\n ok: z.boolean(),\n});\n\nexport const RegisterSendDeviceKeyRequestSchema = z.object({\n userId: UuidSchema,\n deviceId: z.string().min(3),\n publicKey: z.string().min(32),\n});\n\n/**\n * Supported step-up purposes for /api/v1/auth/send/challenge.\n * Mirrors `SUPPORTED_SEND_AUTH_PURPOSES` in flur-backend/src/routes/auth.ts.\n * Defaults to 'send_money' server-side when omitted.\n */\nexport const SEND_AUTH_PURPOSES = ['send_money', 'offline_revoke'] as const;\nexport type SendAuthPurpose = (typeof SEND_AUTH_PURPOSES)[number];\n\nexport const SendChallengeRequestSchema = z.object({\n userId: UuidSchema,\n deviceId: z.string().min(3),\n purpose: z.enum(SEND_AUTH_PURPOSES).optional(),\n});\n\nexport const SendChallengeResponseSchema = z.object({\n challengeId: UuidSchema,\n nonce: z.string().min(1),\n expiresAt: IsoDateSchema,\n});\n\nexport const SendVerifyRequestSchema = z.object({\n userId: UuidSchema,\n deviceId: z.string().min(3),\n challengeId: UuidSchema,\n signature: z.string().min(16),\n});\n\nexport const SendVerifyResponseSchema = z.object({\n sendAuthToken: z.string().min(16),\n});\n\nexport const ResolveRecipientRequestSchema = z.object({\n identifier: z.string().min(3),\n});\n\nexport const ResolveRecipientResponseSchema = z.object({\n recipientUserId: UuidSchema,\n displayName: z.string().min(1),\n normalizedIdentifier: z.string().regex(E164Regex),\n isActive: z.boolean(),\n});\n\nexport const CreateTransferRequestSchema = z.object({\n recipientIdentifier: z.string().min(3),\n amountMinor: z.number().int().positive(),\n currency: CurrencySchema,\n sendAuthToken: z.string().min(16),\n});\n\nconst TransferStatusSchema = z.enum(['SETTLED', 'PENDING_REVIEW', 'DECLINED']);\n\nexport const TransferResponseSchema = z.object({\n transactionId: z.string().min(1),\n status: TransferStatusSchema,\n userStatus: TransferStatusSchema,\n recipientName: z.string().min(1),\n timestamp: IsoDateSchema,\n});\n\nconst DirectionSchema = z.enum(['OUTGOING', 'INCOMING']);\n\nexport const AccountActivityItemSchema = z.object({\n id: z.string().min(1),\n type: z.string().min(1),\n direction: DirectionSchema,\n name: z.string().min(1),\n identifier: z.string().min(1),\n amountMinor: z.number().int(),\n currency: CurrencySchema,\n status: z.string().min(1),\n timestamp: IsoDateSchema,\n});\n\nexport const AccountSummaryResponseSchema = z.object({\n /** Authenticated user's stable internal id. */\n userId: UuidSchema,\n /**\n * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the\n * bank partner. `null` when the user has no partner-allocated account yet.\n */\n nuban: z\n .string()\n .regex(/^[0-9]{10}$/)\n .nullable(),\n balance: z.number().int(),\n currency: CurrencySchema,\n dailySendLimit: z.number().int().nonnegative(),\n dailySendRemaining: z.number().int().nonnegative(),\n kycTier: z.string().min(1),\n kycStatus: z.string().min(1),\n recentActivity: z.array(AccountActivityItemSchema),\n});\n\nexport const TransactionsListResponseSchema = z.object({\n items: z.array(AccountActivityItemSchema),\n nextCursor: z.string().nullable(),\n});\n\nexport const TransactionDetailResponseSchema = z.object({\n transactionId: z.string().min(1),\n type: z.string().min(1),\n direction: DirectionSchema,\n counterpartyName: z.string().min(1),\n counterpartyIdentifier: z.string().min(1),\n amountMinor: z.number().int(),\n currency: CurrencySchema,\n status: z.string().min(1),\n timestamp: IsoDateSchema,\n});\n\nexport const PushRegisterRequestSchema = z.object({\n deviceId: z.string().min(3),\n platform: z.enum(['ios', 'android', 'web']),\n token: z.string().min(16),\n});\n\nexport const CreatePayLinkResponseSchema = z.object({\n token: z.string().min(1),\n});\n\nexport const ResolvePayLinkResponseSchema = z.object({\n recipientUserId: UuidSchema,\n displayName: z.string().min(1),\n normalizedIdentifier: z.string().regex(E164Regex),\n isActive: z.boolean(),\n});\n","export type FlurErrorCode =\r\n | 'NETWORK_ERROR'\r\n | 'HTTP_ERROR'\r\n | 'TIMEOUT'\r\n | 'UNKNOWN'\r\n | 'UNAUTHORIZED'\r\n | 'INVALID_REQUEST'\r\n | 'RATE_LIMITED'\r\n | 'NOT_FOUND'\r\n | 'USER_NOT_FOUND'\r\n | 'TOKEN_REPLAYED'\r\n | 'SESSION_MISMATCH'\r\n | 'PIN_INVALID'\r\n | 'PIN_LOCKED'\r\n | 'PIN_NOT_SET'\r\n | 'STEP_UP_REQUIRED'\r\n | 'DEVICE_KEY_NOT_REGISTERED'\r\n | 'CHALLENGE_INVALID'\r\n | 'CHALLENGE_EXPIRED'\r\n | 'DEVICE_KEY_REVOKED'\r\n | 'SIGNATURE_INVALID'\r\n | 'INVALID_RECIPIENT'\r\n | 'SEND_AUTH_INVALID'\r\n | 'IDEMPOTENCY_KEY_CONFLICT'\r\n | 'IDEMPOTENCY_IN_PROGRESS'\r\n | 'CANNOT_SEND_TO_SELF'\r\n | 'INSUFFICIENT_FUNDS';\r\n\r\nconst backendErrorCodeSet: ReadonlySet<FlurErrorCode> = new Set([\r\n 'UNAUTHORIZED',\r\n 'INVALID_REQUEST',\r\n 'RATE_LIMITED',\r\n 'NOT_FOUND',\r\n 'USER_NOT_FOUND',\r\n 'TOKEN_REPLAYED',\r\n 'SESSION_MISMATCH',\r\n 'PIN_INVALID',\r\n 'PIN_LOCKED',\r\n 'PIN_NOT_SET',\r\n 'STEP_UP_REQUIRED',\r\n 'DEVICE_KEY_NOT_REGISTERED',\r\n 'CHALLENGE_INVALID',\r\n 'CHALLENGE_EXPIRED',\r\n 'DEVICE_KEY_REVOKED',\r\n 'SIGNATURE_INVALID',\r\n 'INVALID_RECIPIENT',\r\n 'SEND_AUTH_INVALID',\r\n 'IDEMPOTENCY_KEY_CONFLICT',\r\n 'IDEMPOTENCY_IN_PROGRESS',\r\n 'CANNOT_SEND_TO_SELF',\r\n 'INSUFFICIENT_FUNDS',\r\n]);\r\n\r\nexport class FlurError extends Error {\r\n public readonly code: FlurErrorCode;\r\n public readonly status?: number;\r\n public readonly details?: unknown;\r\n public readonly reqId?: string | null;\r\n\r\n constructor(\r\n message: string,\r\n code: FlurErrorCode,\r\n opts?: { status?: number; details?: unknown; reqId?: string | null },\r\n ) {\r\n super(message);\r\n this.name = 'FlurError';\r\n this.code = code;\r\n this.status = opts?.status;\r\n this.details = opts?.details;\r\n this.reqId = opts?.reqId;\r\n }\r\n}\r\n\r\n/**\r\n * Generic API error thrown by HTTP clients in `flur.passes` / `flur.receipts`\r\n * for non-2xx responses. Lives at the SDK root so bounded-context modules\r\n * (passes, receipts) never cross-import each other.\r\n */\r\nexport class FlurApiError extends Error {\r\n constructor(\r\n public readonly status: number,\r\n public readonly code: string,\r\n message: string,\r\n public readonly raw?: unknown,\r\n ) {\r\n super(message);\r\n this.name = 'FlurApiError';\r\n }\r\n}\r\n\r\n/** Thrown by `buildRedemption` when the pass is past its `validUntilMs`. */\r\nexport class FlurExpiredError extends Error {\r\n public readonly code = 'PASS_EXPIRED' as const;\r\n constructor(message = 'pass is expired') {\r\n super(message);\r\n this.name = 'FlurExpiredError';\r\n }\r\n}\r\n\r\n/** Thrown by `buildRedemption` when `counter` is not strictly greater than the\r\n * caller-supplied `lastSeenCounter` (replay / out-of-order redemption attempt). */\r\nexport class FlurReplayError extends Error {\r\n public readonly code = 'PASS_REPLAY' as const;\r\n constructor(message = 'redemption counter is not strictly increasing') {\r\n super(message);\r\n this.name = 'FlurReplayError';\r\n }\r\n}\r\n\r\n/** Thrown by `buildRedemption` when this redemption would breach the pass's\r\n * `cumulativeCapKobo` given the caller-supplied `cumulativeUsedKobo`. */\r\nexport class FlurCapExceededError extends Error {\r\n public readonly code = 'PASS_CAP_EXCEEDED' as const;\r\n constructor(message = 'redemption exceeds cumulative cap') {\r\n super(message);\r\n this.name = 'FlurCapExceededError';\r\n }\r\n}\r\n\r\nexport async function mapToFlurError(res: Response): Promise<FlurError> {\r\n const reqId = res.headers.get('x-request-id');\r\n let details: unknown = undefined;\r\n let mappedCode: FlurErrorCode = 'HTTP_ERROR';\r\n let mappedMessage = `HTTP ${res.status}`;\r\n try {\r\n const ct = res.headers.get('content-type') ?? '';\r\n details = ct.includes('application/json')\r\n ? await res.json()\r\n : await res.text();\r\n if (details && typeof details === 'object') {\r\n const candidateCode = (details as { code?: unknown }).code;\r\n const candidateMessage = (\r\n details as { message?: unknown; error?: unknown }\r\n ).message;\r\n const fallbackMessage = (details as { error?: unknown }).error;\r\n\r\n if (\r\n typeof candidateCode === 'string' &&\r\n backendErrorCodeSet.has(candidateCode as FlurErrorCode)\r\n ) {\r\n mappedCode = candidateCode as FlurErrorCode;\r\n }\r\n\r\n if (typeof candidateMessage === 'string' && candidateMessage.length > 0) {\r\n mappedMessage = candidateMessage;\r\n } else if (\r\n typeof fallbackMessage === 'string' &&\r\n fallbackMessage.length > 0\r\n ) {\r\n mappedMessage = fallbackMessage;\r\n }\r\n }\r\n } catch {\r\n // ignore parse issues\r\n }\r\n return new FlurError(mappedMessage, mappedCode, {\r\n status: res.status,\r\n details,\r\n reqId,\r\n });\r\n}\r\n","import { z } from \"zod\";\r\nimport { FlurError } from \"./errors.js\";\r\nimport { E164Regex } from \"./contracts.js\";\r\n\r\nexport type Money = {\r\n amountMinor: bigint;\r\n currency: string;\r\n};\r\n\r\nconst CurrencyCodeSchema = z.string().trim().length(3).transform((value) => value.toUpperCase());\r\n\r\nconst currencyFractionDigits: Record<string, number> = {\r\n NGN: 2,\r\n USD: 2,\r\n EUR: 2,\r\n GBP: 2,\r\n CAD: 2,\r\n JPY: 0,\r\n};\r\n\r\nfunction getFractionDigits(currency: string): number {\r\n return currencyFractionDigits[currency] ?? 2;\r\n}\r\n\r\nexport function parseAmountInput(value: string, currency: string): Money {\r\n const normalizedCurrency = CurrencyCodeSchema.parse(currency);\r\n const raw = value.trim();\r\n\r\n if (!/^\\d+(\\.\\d+)?$/.test(raw)) {\r\n throw new FlurError(\"Invalid amount format\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const [whole, fraction = \"\"] = raw.split(\".\");\r\n const fractionDigits = getFractionDigits(normalizedCurrency);\r\n\r\n if (fraction.length > fractionDigits) {\r\n throw new FlurError(\"Too many decimal places for currency\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const paddedFraction = fraction.padEnd(fractionDigits, \"0\");\r\n const minorAsString = `${whole}${paddedFraction}`.replace(/^0+(\\d)/, \"$1\") || \"0\";\r\n const amountMinor = BigInt(minorAsString);\r\n\r\n if (amountMinor < 0n) {\r\n throw new FlurError(\"Amount cannot be negative\", \"INVALID_REQUEST\");\r\n }\r\n\r\n return {\r\n amountMinor,\r\n currency: normalizedCurrency,\r\n };\r\n}\r\n\r\nexport function formatAmount(amountMinor: bigint, currency: string): string {\r\n const normalizedCurrency = CurrencyCodeSchema.parse(currency);\r\n if (amountMinor < 0n) {\r\n throw new FlurError(\"Amount cannot be negative\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const fractionDigits = getFractionDigits(normalizedCurrency);\r\n if (fractionDigits === 0) {\r\n return amountMinor.toString();\r\n }\r\n\r\n const divisor = 10n ** BigInt(fractionDigits);\r\n const whole = amountMinor / divisor;\r\n const fraction = (amountMinor % divisor).toString().padStart(fractionDigits, \"0\");\r\n return `${whole.toString()}.${fraction}`;\r\n}\r\n\r\nconst defaultCountryDialingCode: Record<string, string> = {\r\n NG: \"234\",\r\n US: \"1\",\r\n CA: \"1\",\r\n GB: \"44\",\r\n};\r\n\r\nexport function normalizeE164(input: string, defaultCountry?: string): string {\r\n const trimmed = input.trim();\r\n\r\n if (trimmed.startsWith(\"+\")) {\r\n if (!E164Regex.test(trimmed)) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n return trimmed;\r\n }\r\n\r\n const digits = trimmed.replace(/\\D/g, \"\");\r\n if (digits.length === 0) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n\r\n if (digits.startsWith(\"00\")) {\r\n const candidate = `+${digits.slice(2)}`;\r\n if (!E164Regex.test(candidate)) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n return candidate;\r\n }\r\n\r\n const normalizedCountry = defaultCountry?.trim().toUpperCase();\r\n const countryCode = normalizedCountry ? defaultCountryDialingCode[normalizedCountry] : undefined;\r\n if (!countryCode) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const localDigits = digits.startsWith(\"0\") ? digits.slice(1) : digits;\r\n const candidate = `+${countryCode}${localDigits}`;\r\n if (!E164Regex.test(candidate)) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n return candidate;\r\n}\r\n\r\nexport function moneyMinorToNumber(amountMinor: bigint): number {\r\n const asNumber = Number(amountMinor);\r\n if (!Number.isSafeInteger(asNumber)) {\r\n throw new FlurError(\"Amount exceeds safe integer range\", \"INVALID_REQUEST\");\r\n }\r\n return asNumber;\r\n}\r\n","import { z } from 'zod';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport const MERCHANT_PROFILE_STATUSES = [\r\n 'pending',\r\n 'active',\r\n 'suspended',\r\n 'closed',\r\n] as const;\r\nexport const SETTLEMENT_SCHEDULES = ['manual', 'daily', 't1'] as const;\r\nexport const COLLECTION_INTENT_STATUSES = [\r\n 'created',\r\n 'pending',\r\n 'paid',\r\n 'expired',\r\n 'cancelled',\r\n 'failed',\r\n 'reversed',\r\n] as const;\r\nexport const COLLECTION_PAYMENT_STATUSES = [\r\n 'pending',\r\n 'paid',\r\n 'failed',\r\n 'reversed',\r\n] as const;\r\nexport const MERCHANT_PAYOUT_STATUSES = [\r\n 'requested',\r\n 'processing',\r\n 'paid',\r\n 'failed',\r\n 'cancelled',\r\n] as const;\r\n\r\nconst MoneyKoboSchema = z\r\n .number()\r\n .int()\r\n .positive()\r\n .max(Number.MAX_SAFE_INTEGER);\r\nconst MetadataSchema = z.record(\r\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\r\n);\r\nconst CurrencySchema = z\r\n .string()\r\n .trim()\r\n .length(3)\r\n .transform((value) => value.toUpperCase());\r\nconst ReferenceSchema = z\r\n .string()\r\n .trim()\r\n .min(6)\r\n .max(128)\r\n .regex(/^[A-Za-z0-9._:-]+$/);\r\n\r\nexport const MerchantProfileSchema = z.object({\r\n accountId: z.string().uuid(),\r\n legalName: z.string(),\r\n tradingName: z.string(),\r\n merchantCategoryCode: z.string().regex(/^\\d{4}$/),\r\n nqrMerchantId: z.string(),\r\n settlementBankCode: z.string(),\r\n settlementAccountNumber: z.string(),\r\n settlementAccountName: z.string(),\r\n settlementSchedule: z.enum(SETTLEMENT_SCHEDULES),\r\n status: z.enum(MERCHANT_PROFILE_STATUSES),\r\n offlineEnabled: z.boolean(),\r\n perTxLimitKobo: MoneyKoboSchema,\r\n dailyLimitKobo: MoneyKoboSchema,\r\n metadata: MetadataSchema,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type MerchantProfile = z.infer<typeof MerchantProfileSchema>;\r\n\r\nexport const UpsertMerchantProfileInputSchema = z.object({\r\n legalName: z.string().trim().min(1).max(200),\r\n tradingName: z.string().trim().min(1).max(25),\r\n merchantCategoryCode: z\r\n .string()\r\n .trim()\r\n .regex(/^\\d{4}$/),\r\n nqrMerchantId: z.string().trim().min(3).max(64),\r\n settlementBankCode: z.string().trim().min(2).max(16),\r\n settlementAccountNumber: z.string().trim().min(5).max(32),\r\n settlementAccountName: z.string().trim().min(1).max(200),\r\n settlementSchedule: z.enum(SETTLEMENT_SCHEDULES).optional(),\r\n status: z.enum(MERCHANT_PROFILE_STATUSES).optional(),\r\n offlineEnabled: z.boolean().optional(),\r\n perTxLimitKobo: MoneyKoboSchema.optional(),\r\n dailyLimitKobo: MoneyKoboSchema.optional(),\r\n metadata: MetadataSchema.optional(),\r\n});\r\nexport type UpsertMerchantProfileInput = z.infer<\r\n typeof UpsertMerchantProfileInputSchema\r\n>;\r\n\r\nexport const CollectionIntentSchema = z.object({\r\n intentId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n terminalId: z.string().uuid().nullable(),\r\n reference: z.string(),\r\n amountKobo: z.number().int().positive().nullable(),\r\n currency: z.string().length(3),\r\n status: z.enum(COLLECTION_INTENT_STATUSES),\r\n description: z.string().nullable(),\r\n nqrPayload: z.string(),\r\n provider: z.string(),\r\n providerReference: z.string().nullable(),\r\n metadata: MetadataSchema,\r\n expiresAtMs: z.number().int().nonnegative().nullable(),\r\n paidAtMs: z.number().int().nonnegative().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type CollectionIntent = z.infer<typeof CollectionIntentSchema>;\r\n\r\nexport const CreateCollectionIntentInputSchema = z.object({\r\n reference: ReferenceSchema.optional(),\r\n amountKobo: MoneyKoboSchema.optional(),\r\n currency: CurrencySchema.optional(),\r\n terminalId: z.string().uuid().optional(),\r\n terminalLabel: z.string().trim().min(1).max(25).optional(),\r\n merchantCity: z.string().trim().min(1).max(15).optional(),\r\n description: z.string().trim().min(1).max(280).optional(),\r\n expiresAtMs: z.number().int().positive().optional(),\r\n provider: z.string().trim().min(1).max(40).optional(),\r\n metadata: MetadataSchema.optional(),\r\n});\r\nexport type CreateCollectionIntentInput = z.infer<\r\n typeof CreateCollectionIntentInputSchema\r\n>;\r\n\r\nexport const PublicCollectionIntentSchema = z.object({\r\n intentId: z.string().uuid(),\r\n reference: z.string(),\r\n amountKobo: z.number().int().positive().nullable(),\r\n currency: z.string().length(3),\r\n status: z.enum(COLLECTION_INTENT_STATUSES),\r\n merchantAccountId: z.string().uuid(),\r\n merchantName: z.string(),\r\n merchantCategoryCode: z.string(),\r\n description: z.string().nullable(),\r\n expiresAtMs: z.number().int().nonnegative().nullable(),\r\n});\r\nexport type PublicCollectionIntent = z.infer<\r\n typeof PublicCollectionIntentSchema\r\n>;\r\n\r\nexport const PayCollectionInputSchema = z.object({\r\n reference: ReferenceSchema,\r\n amountKobo: MoneyKoboSchema.optional(),\r\n currency: CurrencySchema.optional(),\r\n idempotencyKey: z.string().trim().min(8).max(160).optional(),\r\n});\r\nexport type PayCollectionInput = z.infer<typeof PayCollectionInputSchema>;\r\n\r\nexport const CollectionPaymentSchema = z.object({\r\n paymentId: z.string().uuid(),\r\n intentId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n payerUserId: z.string().uuid().nullable(),\r\n merchantOwnerUserId: z.string().uuid(),\r\n amountKobo: MoneyKoboSchema,\r\n currency: z.string().length(3),\r\n status: z.enum(COLLECTION_PAYMENT_STATUSES),\r\n provider: z.string(),\r\n providerReference: z.string().nullable(),\r\n idempotencyKey: z.string().nullable(),\r\n ledgerRef: z.string(),\r\n failureCode: z.string().nullable(),\r\n failureMessage: z.string().nullable(),\r\n paidAtMs: z.number().int().nonnegative().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type CollectionPayment = z.infer<typeof CollectionPaymentSchema>;\r\n\r\nexport const CollectionPaymentResultSchema = z.object({\r\n payment: CollectionPaymentSchema,\r\n intent: CollectionIntentSchema,\r\n receipt: z.unknown().optional(),\r\n replayed: z.boolean(),\r\n});\r\nexport type CollectionPaymentResult = z.infer<\r\n typeof CollectionPaymentResultSchema\r\n>;\r\n\r\nexport const CollectionReportSummarySchema = z.object({\r\n accountId: z.string().uuid(),\r\n fromMs: z.number().int().nonnegative(),\r\n toMs: z.number().int().nonnegative(),\r\n currency: z.string().length(3),\r\n paidCount: z.number().int().nonnegative(),\r\n paidAmountKobo: z.number().int().nonnegative(),\r\n pendingCount: z.number().int().nonnegative(),\r\n failedCount: z.number().int().nonnegative(),\r\n reversedCount: z.number().int().nonnegative(),\r\n availableBalanceKobo: z.number().int().nonnegative(),\r\n});\r\nexport type CollectionReportSummary = z.infer<\r\n typeof CollectionReportSummarySchema\r\n>;\r\n\r\nexport const CollectionStatementSchema = z.object({\r\n accountId: z.string().uuid(),\r\n year: z.number().int(),\r\n month: z.number().int().min(1).max(12),\r\n currency: z.string().length(3),\r\n totalPaidKobo: z.number().int().nonnegative(),\r\n items: z.array(CollectionPaymentSchema),\r\n});\r\nexport type CollectionStatement = z.infer<typeof CollectionStatementSchema>;\r\n\r\nexport const CreatePayoutInputSchema = z.object({\r\n amountKobo: MoneyKoboSchema,\r\n currency: CurrencySchema.optional(),\r\n idempotencyKey: z.string().trim().min(8).max(160),\r\n});\r\nexport type CreatePayoutInput = z.infer<typeof CreatePayoutInputSchema>;\r\n\r\nexport const MerchantPayoutSchema = z.object({\r\n payoutId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n amountKobo: MoneyKoboSchema,\r\n currency: z.string().length(3),\r\n status: z.enum(MERCHANT_PAYOUT_STATUSES),\r\n idempotencyKey: z.string().nullable(),\r\n ledgerRef: z.string(),\r\n providerReference: z.string().nullable(),\r\n requestedByUserId: z.string().uuid().nullable(),\r\n failureCode: z.string().nullable(),\r\n failureMessage: z.string().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type MerchantPayout = z.infer<typeof MerchantPayoutSchema>;\r\n\r\nexport const ProviderEventInputSchema = z.object({\r\n provider: z.string().trim().min(1).max(80),\r\n eventId: z.string().trim().min(1).max(160),\r\n eventType: z.string().trim().min(1).max(120),\r\n payload: z.record(z.unknown()).optional(),\r\n});\r\nexport type ProviderEventInput = z.infer<typeof ProviderEventInputSchema>;\r\n\r\nexport const ProviderEventRecordSchema = z.object({\r\n id: z.string().uuid(),\r\n provider: z.string(),\r\n eventId: z.string(),\r\n eventType: z.string(),\r\n signatureVerified: z.boolean(),\r\n receivedAtMs: z.number().int().nonnegative(),\r\n processedAtMs: z.number().int().nonnegative().nullable(),\r\n});\r\nexport type ProviderEventRecord = z.infer<typeof ProviderEventRecordSchema>;\r\n\r\nexport type CollectionsClientOptions = {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type CollectionsClient = {\r\n upsertMerchantProfile: (\r\n accountId: string,\r\n input: UpsertMerchantProfileInput,\r\n ) => Promise<MerchantProfile>;\r\n getMerchantProfile: (accountId: string) => Promise<MerchantProfile>;\r\n createIntent: (\r\n input: CreateCollectionIntentInput,\r\n ) => Promise<CollectionIntent>;\r\n getIntent: (intentId: string) => Promise<CollectionIntent>;\r\n resolveIntent: (reference: string) => Promise<PublicCollectionIntent>;\r\n pay: (input: PayCollectionInput) => Promise<CollectionPaymentResult>;\r\n reportSummary: (input: {\r\n fromMs: number;\r\n toMs: number;\r\n currency?: string;\r\n }) => Promise<CollectionReportSummary>;\r\n monthlyStatement: (input: {\r\n year: number;\r\n month: number;\r\n currency?: string;\r\n }) => Promise<CollectionStatement>;\r\n createPayout: (input: CreatePayoutInput) => Promise<MerchantPayout>;\r\n getPayout: (payoutId: string) => Promise<MerchantPayout>;\r\n recordProviderEvent: (\r\n input: ProviderEventInput,\r\n ) => Promise<ProviderEventRecord>;\r\n};\r\n\r\nexport type PartnerCollectionsClient = Pick<\r\n CollectionsClient,\r\n | 'createIntent'\r\n | 'getIntent'\r\n | 'reportSummary'\r\n | 'monthlyStatement'\r\n | 'createPayout'\r\n | 'getPayout'\r\n | 'recordProviderEvent'\r\n>;\r\n\r\nexport type ConsumerCollectionsClient = Pick<\r\n CollectionsClient,\r\n 'resolveIntent' | 'pay'\r\n>;\r\n\r\nexport function createCollectionsClient(\r\n opts: CollectionsClientOptions,\r\n): CollectionsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createCollectionsClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: { accept: 'application/json' },\r\n };\r\n if (body !== undefined) {\r\n init.body = JSON.stringify(body);\r\n init.headers = { ...init.headers, 'content-type': 'application/json' };\r\n }\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n raw = text;\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n return {\r\n upsertMerchantProfile: (accountId, input) =>\r\n call(\r\n 'PUT',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,\r\n UpsertMerchantProfileInputSchema.parse(input),\r\n (raw) => MerchantProfileSchema.parse(raw),\r\n ),\r\n getMerchantProfile: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,\r\n undefined,\r\n (raw) => MerchantProfileSchema.parse(raw),\r\n ),\r\n createIntent: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/intents',\r\n CreateCollectionIntentInputSchema.parse(input),\r\n (raw) => CollectionIntentSchema.parse(raw),\r\n ),\r\n getIntent: (intentId) =>\r\n call(\r\n 'GET',\r\n `/v1/collections/intents/${encodeURIComponent(intentId)}`,\r\n undefined,\r\n (raw) => CollectionIntentSchema.parse(raw),\r\n ),\r\n resolveIntent: (reference) =>\r\n call(\r\n 'GET',\r\n `/v1/collections/resolve/${encodeURIComponent(reference)}`,\r\n undefined,\r\n (raw) => PublicCollectionIntentSchema.parse(raw),\r\n ),\r\n pay: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/pay',\r\n PayCollectionInputSchema.parse(input),\r\n (raw) => CollectionPaymentResultSchema.parse(raw),\r\n ),\r\n reportSummary: (input) => {\r\n const qs = new URLSearchParams({\r\n fromMs: String(input.fromMs),\r\n toMs: String(input.toMs),\r\n });\r\n if (input.currency) qs.set('currency', input.currency);\r\n return call(\r\n 'GET',\r\n `/v1/collections/reports/summary?${qs.toString()}`,\r\n undefined,\r\n (raw) => CollectionReportSummarySchema.parse(raw),\r\n );\r\n },\r\n monthlyStatement: (input) => {\r\n const qs = new URLSearchParams({\r\n year: String(input.year),\r\n month: String(input.month),\r\n });\r\n if (input.currency) qs.set('currency', input.currency);\r\n return call(\r\n 'GET',\r\n `/v1/collections/statements/monthly?${qs.toString()}`,\r\n undefined,\r\n (raw) => CollectionStatementSchema.parse(raw),\r\n );\r\n },\r\n createPayout: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/payouts',\r\n CreatePayoutInputSchema.parse(input),\r\n (raw) => MerchantPayoutSchema.parse(raw),\r\n ),\r\n getPayout: (payoutId) =>\r\n call(\r\n 'GET',\r\n `/v1/collections/payouts/${encodeURIComponent(payoutId)}`,\r\n undefined,\r\n (raw) => MerchantPayoutSchema.parse(raw),\r\n ),\r\n recordProviderEvent: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/provider-events',\r\n ProviderEventInputSchema.parse(input),\r\n (raw) => ProviderEventRecordSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n\r\nexport function createPartnerCollectionsClient(\r\n opts: CollectionsClientOptions,\r\n): PartnerCollectionsClient {\r\n const client = createCollectionsClient(opts);\r\n return {\r\n createIntent: client.createIntent,\r\n getIntent: client.getIntent,\r\n reportSummary: client.reportSummary,\r\n monthlyStatement: client.monthlyStatement,\r\n createPayout: client.createPayout,\r\n getPayout: client.getPayout,\r\n recordProviderEvent: client.recordProviderEvent,\r\n };\r\n}\r\n\r\nexport function createConsumerCollectionsClient(\r\n opts: CollectionsClientOptions,\r\n): ConsumerCollectionsClient {\r\n const client = createCollectionsClient(opts);\r\n return {\r\n resolveIntent: client.resolveIntent,\r\n pay: client.pay,\r\n };\r\n}\r\n","/**\r\n * EMV / NQR Merchant-Presented top-level field IDs.\r\n * See EMVCo MPM v1.1 §4 and NIBSS NQR specification.\r\n */\r\nexport const FIELD = {\r\n PAYLOAD_FORMAT_INDICATOR: '00',\r\n POINT_OF_INITIATION: '01',\r\n // 02..51 — Merchant Account Information templates (issuer-specific)\r\n MERCHANT_CATEGORY_CODE: '52',\r\n TRANSACTION_CURRENCY: '53',\r\n TRANSACTION_AMOUNT: '54',\r\n TIP_OR_CONVENIENCE_INDICATOR: '55',\r\n VALUE_CONVENIENCE_FEE_FIXED: '56',\r\n VALUE_CONVENIENCE_FEE_PERCENT: '57',\r\n COUNTRY_CODE: '58',\r\n MERCHANT_NAME: '59',\r\n MERCHANT_CITY: '60',\r\n POSTAL_CODE: '61',\r\n ADDITIONAL_DATA_FIELD: '62',\r\n CRC: '63',\r\n MERCHANT_INFO_LANGUAGE: '64',\r\n // 80..99 — Unreserved Templates\r\n} as const;\r\n\r\nexport const ADDITIONAL_DATA_SUBFIELD = {\r\n BILL_NUMBER: '01',\r\n MOBILE_NUMBER: '02',\r\n STORE_LABEL: '03',\r\n LOYALTY_NUMBER: '04',\r\n REFERENCE_LABEL: '05',\r\n CUSTOMER_LABEL: '06',\r\n TERMINAL_LABEL: '07',\r\n PURPOSE_OF_TRANSACTION: '08',\r\n} as const;\r\n\r\nexport const POINT_OF_INITIATION = {\r\n STATIC: '11',\r\n DYNAMIC: '12',\r\n} as const;\r\n\r\nexport const PAYLOAD_FORMAT_INDICATOR_VALUE = '01';\r\nexport const NGN_CURRENCY_CODE = '566';\r\nexport const NG_COUNTRY_CODE = 'NG';\r\nexport const CRC_TAG_PREFIX = '6304'; // tag 63 + length 04\r\n","/**\r\n * CRC-16/CCITT-FALSE — polynomial 0x1021, initial 0xFFFF, no reflection,\r\n * no XOR-out. Specified by EMVCo MPM for tag 63 (CRC).\r\n */\r\nexport function crc16ccitt(bytes: Uint8Array): number {\r\n let crc = 0xffff;\r\n for (let i = 0; i < bytes.length; i++) {\r\n crc ^= bytes[i] << 8;\r\n for (let j = 0; j < 8; j++) {\r\n if (crc & 0x8000) {\r\n crc = (crc << 1) ^ 0x1021;\r\n } else {\r\n crc <<= 1;\r\n }\r\n crc &= 0xffff;\r\n }\r\n }\r\n return crc;\r\n}\r\n\r\nexport function crc16ccittHex(bytes: Uint8Array): string {\r\n return crc16ccitt(bytes).toString(16).toUpperCase().padStart(4, '0');\r\n}\r\n","/**\r\n * EMV TLV (Tag-Length-Value) primitives.\r\n * - Tag is 2 ASCII digits.\r\n * - Length is 2 ASCII digits (00..99).\r\n * - Value is up to 99 ASCII characters.\r\n */\r\n\r\nexport type TLVField = { tag: string; value: string };\r\n\r\nexport function writeTLV(tag: string, value: string): string {\r\n if (!/^\\d{2}$/.test(tag)) {\r\n throw new Error(`TLV: tag must be 2 digits, got \"${tag}\"`);\r\n }\r\n if (value.length > 99) {\r\n throw new Error(\r\n `TLV: value for tag ${tag} exceeds 99 chars (${value.length})`,\r\n );\r\n }\r\n const len = value.length.toString().padStart(2, '0');\r\n return `${tag}${len}${value}`;\r\n}\r\n\r\nexport function readTLV(buf: string): TLVField[] {\r\n const out: TLVField[] = [];\r\n let i = 0;\r\n while (i < buf.length) {\r\n if (i + 4 > buf.length) {\r\n throw new Error(`TLV: truncated header at offset ${i}`);\r\n }\r\n const tag = buf.slice(i, i + 2);\r\n const lenStr = buf.slice(i + 2, i + 4);\r\n if (!/^\\d{2}$/.test(tag)) {\r\n throw new Error(`TLV: bad tag \"${tag}\" at offset ${i}`);\r\n }\r\n if (!/^\\d{2}$/.test(lenStr)) {\r\n throw new Error(`TLV: bad length \"${lenStr}\" at offset ${i + 2}`);\r\n }\r\n const len = parseInt(lenStr, 10);\r\n const valStart = i + 4;\r\n const valEnd = valStart + len;\r\n if (valEnd > buf.length) {\r\n throw new Error(\r\n `TLV: truncated value for tag ${tag} at offset ${valStart}`,\r\n );\r\n }\r\n out.push({ tag, value: buf.slice(valStart, valEnd) });\r\n i = valEnd;\r\n }\r\n return out;\r\n}\r\n","import {\r\n ADDITIONAL_DATA_SUBFIELD,\r\n CRC_TAG_PREFIX,\r\n FIELD,\r\n NGN_CURRENCY_CODE,\r\n NG_COUNTRY_CODE,\r\n PAYLOAD_FORMAT_INDICATOR_VALUE,\r\n POINT_OF_INITIATION,\r\n} from './fields.js';\r\nimport { crc16ccittHex } from './crc16.js';\r\nimport { writeTLV } from './tlv.js';\r\nimport type {\r\n AdditionalData,\r\n MerchantAccountInfo,\r\n NQRPayloadInput,\r\n} from './types.js';\r\n\r\nconst ASCII_PRINTABLE = /^[\\x20-\\x7E]*$/;\r\n\r\n/** Build the inner content of a Merchant Account Information template. */\r\nfunction buildMAIValue(mai: MerchantAccountInfo): string {\r\n if (!/^(0[2-9]|[1-4]\\d|5[0-1])$/.test(mai.tag)) {\r\n throw new Error(\r\n `encodeNQR: merchantAccountInfo.tag must be in 02..51, got \"${mai.tag}\"`,\r\n );\r\n }\r\n let out = '';\r\n for (const c of mai.children) {\r\n out += writeTLV(c.tag, c.value);\r\n }\r\n return out;\r\n}\r\n\r\nfunction buildAdditionalDataValue(ad: AdditionalData): string {\r\n let out = '';\r\n const map: Array<[keyof AdditionalData, string]> = [\r\n ['billNumber', ADDITIONAL_DATA_SUBFIELD.BILL_NUMBER],\r\n ['mobileNumber', ADDITIONAL_DATA_SUBFIELD.MOBILE_NUMBER],\r\n ['storeLabel', ADDITIONAL_DATA_SUBFIELD.STORE_LABEL],\r\n ['loyaltyNumber', ADDITIONAL_DATA_SUBFIELD.LOYALTY_NUMBER],\r\n ['referenceLabel', ADDITIONAL_DATA_SUBFIELD.REFERENCE_LABEL],\r\n ['customerLabel', ADDITIONAL_DATA_SUBFIELD.CUSTOMER_LABEL],\r\n ['terminalLabel', ADDITIONAL_DATA_SUBFIELD.TERMINAL_LABEL],\r\n ['purposeOfTransaction', ADDITIONAL_DATA_SUBFIELD.PURPOSE_OF_TRANSACTION],\r\n ];\r\n for (const [k, t] of map) {\r\n const v = ad[k];\r\n if (v !== undefined) {\r\n out += writeTLV(t, v);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nfunction assertAscii(name: string, v: string): void {\r\n if (!ASCII_PRINTABLE.test(v)) {\r\n throw new Error(\r\n `encodeNQR: ${name} contains non-printable-ASCII characters`,\r\n );\r\n }\r\n}\r\n\r\nfunction assertMaxLen(name: string, v: string, max: number): void {\r\n if (v.length > max) {\r\n throw new Error(`encodeNQR: ${name} length ${v.length} exceeds max ${max}`);\r\n }\r\n}\r\n\r\nfunction assertMCC(mcc: string): void {\r\n if (!/^\\d{4}$/.test(mcc)) {\r\n throw new Error(\r\n `encodeNQR: merchantCategoryCode must be 4 digits, got \"${mcc}\"`,\r\n );\r\n }\r\n}\r\n\r\nfunction assertAmount(amt: string): void {\r\n // Up to 13 chars per EMV; decimal fraction separator is \".\"\r\n if (!/^\\d{1,10}(\\.\\d{1,2})?$/.test(amt)) {\r\n throw new Error(\r\n `encodeNQR: transactionAmount must match /^\\\\d{1,10}(\\\\.\\\\d{1,2})?$/, got \"${amt}\"`,\r\n );\r\n }\r\n if (amt.length > 13) {\r\n throw new Error(\r\n `encodeNQR: transactionAmount length ${amt.length} exceeds 13`,\r\n );\r\n }\r\n}\r\n\r\nexport function encodeNQR(input: NQRPayloadInput): string {\r\n assertMCC(input.merchantCategoryCode);\r\n assertAscii('merchantName', input.merchantName);\r\n assertMaxLen('merchantName', input.merchantName, 25);\r\n assertAscii('merchantCity', input.merchantCity);\r\n assertMaxLen('merchantCity', input.merchantCity, 15);\r\n if (input.postalCode !== undefined) {\r\n assertAscii('postalCode', input.postalCode);\r\n assertMaxLen('postalCode', input.postalCode, 10);\r\n }\r\n if (input.transactionAmount !== undefined) {\r\n assertAmount(input.transactionAmount);\r\n }\r\n if (\r\n input.pointOfInitiation === 'dynamic' &&\r\n input.transactionAmount === undefined\r\n ) {\r\n // amount is optional even for dynamic per spec, but warn-by-throw kept for now.\r\n // Allow undefined: some dynamic flows fill the amount in real-time. No throw.\r\n }\r\n\r\n let out = '';\r\n out += writeTLV(\r\n FIELD.PAYLOAD_FORMAT_INDICATOR,\r\n PAYLOAD_FORMAT_INDICATOR_VALUE,\r\n );\r\n out += writeTLV(\r\n FIELD.POINT_OF_INITIATION,\r\n input.pointOfInitiation === 'dynamic'\r\n ? POINT_OF_INITIATION.DYNAMIC\r\n : POINT_OF_INITIATION.STATIC,\r\n );\r\n out += writeTLV(\r\n input.merchantAccountInfo.tag,\r\n buildMAIValue(input.merchantAccountInfo),\r\n );\r\n out += writeTLV(FIELD.MERCHANT_CATEGORY_CODE, input.merchantCategoryCode);\r\n out += writeTLV(FIELD.TRANSACTION_CURRENCY, NGN_CURRENCY_CODE);\r\n if (input.transactionAmount !== undefined) {\r\n out += writeTLV(FIELD.TRANSACTION_AMOUNT, input.transactionAmount);\r\n }\r\n out += writeTLV(FIELD.COUNTRY_CODE, NG_COUNTRY_CODE);\r\n out += writeTLV(FIELD.MERCHANT_NAME, input.merchantName);\r\n out += writeTLV(FIELD.MERCHANT_CITY, input.merchantCity);\r\n if (input.postalCode !== undefined) {\r\n out += writeTLV(FIELD.POSTAL_CODE, input.postalCode);\r\n }\r\n if (input.additionalData) {\r\n const adfValue = buildAdditionalDataValue(input.additionalData);\r\n if (adfValue.length > 0) {\r\n out += writeTLV(FIELD.ADDITIONAL_DATA_FIELD, adfValue);\r\n }\r\n }\r\n\r\n // CRC over everything including \"6304\" header.\r\n out += CRC_TAG_PREFIX;\r\n const crc = crc16ccittHex(new TextEncoder().encode(out));\r\n out += crc;\r\n return out;\r\n}\r\n","import {\r\n CRC_TAG_PREFIX,\r\n FIELD,\r\n NGN_CURRENCY_CODE,\r\n NG_COUNTRY_CODE,\r\n} from './fields.js';\r\nimport { crc16ccittHex } from './crc16.js';\r\nimport { readTLV } from './tlv.js';\r\nimport type {\r\n AdditionalData,\r\n MerchantAccountInfo,\r\n ParsedNQR,\r\n} from './types.js';\r\n\r\nexport class NQRParseError extends Error {\r\n readonly path: string;\r\n constructor(message: string, path = '') {\r\n super(message);\r\n this.name = 'NQRParseError';\r\n this.path = path;\r\n }\r\n}\r\n\r\nexport function parseNQR(payload: string): ParsedNQR {\r\n if (payload.length < 8) {\r\n throw new NQRParseError(`payload too short (${payload.length} chars)`);\r\n }\r\n // CRC validation: last 4 chars are CRC; preceding 4 must be \"6304\".\r\n const crcTagAndLen = payload.slice(-8, -4);\r\n const crcValue = payload.slice(-4);\r\n if (crcTagAndLen !== CRC_TAG_PREFIX) {\r\n throw new NQRParseError(\r\n `CRC tag prefix not found (expected \"6304\" at end)`,\r\n );\r\n }\r\n const beforeCrc = payload.slice(0, -4);\r\n const expectedCrc = crc16ccittHex(new TextEncoder().encode(beforeCrc));\r\n if (expectedCrc !== crcValue.toUpperCase()) {\r\n throw new NQRParseError(\r\n `CRC mismatch: payload says ${crcValue}, computed ${expectedCrc}`,\r\n '63',\r\n );\r\n }\r\n\r\n // Parse top-level TLV (excluding the trailing CRC field).\r\n const topBuf = payload.slice(0, -8);\r\n const top = readTLV(topBuf);\r\n\r\n const get = (tag: string): string | undefined =>\r\n top.find((f) => f.tag === tag)?.value;\r\n\r\n const pfi = get(FIELD.PAYLOAD_FORMAT_INDICATOR);\r\n if (pfi !== '01')\r\n throw new NQRParseError(\r\n `payloadFormatIndicator must be \"01\", got \"${pfi}\"`,\r\n '00',\r\n );\r\n\r\n const poiRaw = get(FIELD.POINT_OF_INITIATION);\r\n const pointOfInitiation: ParsedNQR['pointOfInitiation'] =\r\n poiRaw === '11' ? 'static' : poiRaw === '12' ? 'dynamic' : 'unknown';\r\n\r\n const currency = get(FIELD.TRANSACTION_CURRENCY);\r\n if (currency !== NGN_CURRENCY_CODE) {\r\n throw new NQRParseError(\r\n `unsupported currency \"${currency}\" (expected ${NGN_CURRENCY_CODE})`,\r\n '53',\r\n );\r\n }\r\n const country = get(FIELD.COUNTRY_CODE);\r\n if (country !== NG_COUNTRY_CODE) {\r\n throw new NQRParseError(\r\n `unsupported country \"${country}\" (expected ${NG_COUNTRY_CODE})`,\r\n '58',\r\n );\r\n }\r\n\r\n const mcc = get(FIELD.MERCHANT_CATEGORY_CODE);\r\n if (!mcc) throw new NQRParseError('merchantCategoryCode missing', '52');\r\n const merchantName = get(FIELD.MERCHANT_NAME) ?? '';\r\n const merchantCity = get(FIELD.MERCHANT_CITY) ?? '';\r\n const transactionAmount = get(FIELD.TRANSACTION_AMOUNT);\r\n const postalCode = get(FIELD.POSTAL_CODE);\r\n\r\n // Merchant Account Information templates: tags 02..51.\r\n const mais: MerchantAccountInfo[] = [];\r\n for (const f of top) {\r\n const n = parseInt(f.tag, 10);\r\n if (n >= 2 && n <= 51) {\r\n const children = readTLV(f.value).map((c) => ({\r\n tag: c.tag,\r\n value: c.value,\r\n }));\r\n mais.push({ tag: f.tag, children });\r\n }\r\n }\r\n\r\n // Additional Data Field (62).\r\n let additionalData: AdditionalData | undefined;\r\n const adfRaw = get(FIELD.ADDITIONAL_DATA_FIELD);\r\n if (adfRaw !== undefined) {\r\n additionalData = {};\r\n for (const c of readTLV(adfRaw)) {\r\n switch (c.tag) {\r\n case '01':\r\n additionalData.billNumber = c.value;\r\n break;\r\n case '02':\r\n additionalData.mobileNumber = c.value;\r\n break;\r\n case '03':\r\n additionalData.storeLabel = c.value;\r\n break;\r\n case '04':\r\n additionalData.loyaltyNumber = c.value;\r\n break;\r\n case '05':\r\n additionalData.referenceLabel = c.value;\r\n break;\r\n case '06':\r\n additionalData.customerLabel = c.value;\r\n break;\r\n case '07':\r\n additionalData.terminalLabel = c.value;\r\n break;\r\n case '08':\r\n additionalData.purposeOfTransaction = c.value;\r\n break;\r\n // unknown sub-tags ignored (forward-compat).\r\n }\r\n }\r\n }\r\n\r\n return {\r\n payloadFormatIndicator: pfi,\r\n pointOfInitiation,\r\n merchantAccountInfo: mais,\r\n merchantCategoryCode: mcc,\r\n transactionCurrency: currency,\r\n transactionAmount,\r\n countryCode: country,\r\n merchantName,\r\n merchantCity,\r\n postalCode,\r\n additionalData,\r\n flurReference: additionalData?.referenceLabel?.startsWith('FL-')\r\n ? additionalData.referenceLabel\r\n : undefined,\r\n raw: payload,\r\n };\r\n}\r\n","import type { ParsedNQR } from './types.js';\r\n\r\nexport type RoutingHint = 'flur-onus' | 'nibss' | 'unknown';\r\n\r\n/**\r\n * Decide whether a parsed NQR payload should be routed on-us through Flur\r\n * (because it carries a Flur reference label) or sent through standard NIBSS.\r\n */\r\nexport function routingHint(parsed: ParsedNQR): RoutingHint {\r\n if (parsed.flurReference && parsed.flurReference.startsWith('FL-')) {\r\n return 'flur-onus';\r\n }\r\n if (parsed.merchantAccountInfo.length > 0) return 'nibss';\r\n return 'unknown';\r\n}\r\n","/**\r\n * Deterministic JSON serialization for cryptographic signing.\r\n *\r\n * Rules:\r\n * - Object keys sorted lexicographically (recursively).\r\n * - Arrays preserve order.\r\n * - undefined / NaN / Infinity / bigint / function / symbol are rejected.\r\n * Signatures must be unambiguous; ambiguous values are bugs.\r\n */\r\nexport function canonicalJSONStringify(value: unknown): string {\r\n return stringify(value);\r\n}\r\n\r\nexport function canonicalJSONBytes(value: unknown): Uint8Array {\r\n return new TextEncoder().encode(canonicalJSONStringify(value));\r\n}\r\n\r\nfunction stringify(v: unknown): string {\r\n if (v === null) return 'null';\r\n const t = typeof v;\r\n if (t === 'string') return JSON.stringify(v);\r\n if (t === 'boolean') return v ? 'true' : 'false';\r\n if (t === 'number') {\r\n if (!Number.isFinite(v as number)) {\r\n throw new Error('canonicalJSON: non-finite number not allowed');\r\n }\r\n return JSON.stringify(v);\r\n }\r\n if (\r\n t === 'bigint' ||\r\n t === 'function' ||\r\n t === 'symbol' ||\r\n t === 'undefined'\r\n ) {\r\n throw new Error(`canonicalJSON: unsupported value type ${t}`);\r\n }\r\n if (Array.isArray(v)) {\r\n const parts: string[] = [];\r\n for (const item of v) parts.push(stringify(item));\r\n return '[' + parts.join(',') + ']';\r\n }\r\n if (t === 'object') {\r\n const obj = v as Record<string, unknown>;\r\n const keys = Object.keys(obj).sort();\r\n const parts: string[] = [];\r\n for (const k of keys) {\r\n const val = obj[k];\r\n if (val === undefined) {\r\n throw new Error(`canonicalJSON: undefined value at key \"${k}\"`);\r\n }\r\n parts.push(JSON.stringify(k) + ':' + stringify(val));\r\n }\r\n return '{' + parts.join(',') + '}';\r\n }\r\n throw new Error(`canonicalJSON: unsupported value type ${t}`);\r\n}\r\n","/**\r\n * Constant-time equality for byte arrays. Returns false fast on length\r\n * mismatch (length is not secret); compares byte-wise without short-circuit\r\n * for equal-length inputs.\r\n */\r\nexport function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {\r\n if (a.length !== b.length) return false;\r\n let diff = 0;\r\n for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];\r\n return diff === 0;\r\n}\r\n","/**\r\n * Offline Authorization Certificate (OAC) — P-256 edition (Stage 2c).\r\n *\r\n * Previous wire format used raw 32-byte Ed25519 hex device keys and 64-byte\r\n * hex Ed25519 signatures. The cutover keeps the JSON field names but moves\r\n * to base64:\r\n * - `devicePublicKey` : SubjectPublicKeyInfo DER, base64 (P-256, ~124 chars).\r\n * - `issuerSig` : ASN.1 DER ECDSA(SHA-256) signature, base64 (~96 chars).\r\n *\r\n * `issuerPrivateKey` is a raw 32-byte P-256 scalar (Uint8Array) — same shape as\r\n * the SDK's other P-256 helpers. `issuerPublicKey` (for verification) is now a\r\n * base64 SPKI DER string, matching the rest of the migrated SDK surface.\r\n */\r\nimport { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\n\r\nexport const OAC_DEFAULT_PER_TX_KOBO = 500_000;\r\nexport const OAC_DEFAULT_CUMULATIVE_KOBO = 2_000_000;\r\nexport const OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1000;\r\n\r\n// Wide enough for SPKI public keys (~124 chars) and DER signatures (~96 chars).\r\nconst Base64Std = z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/, 'expected base64 (standard) string');\r\n\r\nexport const OACSchema = z\r\n .object({\r\n userId: z.string().min(1),\r\n deviceId: z.string().min(1),\r\n /** SubjectPublicKeyInfo DER, base64 (P-256). */\r\n devicePublicKey: Base64Std,\r\n perTxCapKobo: z.number().int().nonnegative(),\r\n cumulativeCapKobo: z.number().int().nonnegative(),\r\n validFromMs: z.number().int().nonnegative(),\r\n validUntilMs: z.number().int().positive(),\r\n counterSeed: z.number().int().nonnegative(),\r\n nonce: z.string().min(1),\r\n /** ASN.1 DER ECDSA(SHA-256) signature, base64. */\r\n issuerSig: Base64Std,\r\n })\r\n .refine((v) => v.validUntilMs > v.validFromMs, {\r\n message: 'validUntilMs must be greater than validFromMs',\r\n })\r\n .refine((v) => v.perTxCapKobo <= v.cumulativeCapKobo, {\r\n message: 'perTxCapKobo must not exceed cumulativeCapKobo',\r\n });\r\n\r\nexport type OAC = z.infer<typeof OACSchema>;\r\nexport type UnsignedOAC = Omit<OAC, 'issuerSig'>;\r\n\r\nexport function buildOAC(input: {\r\n userId: string;\r\n deviceId: string;\r\n /** SPKI DER base64 string (P-256). */\r\n devicePublicKey: string;\r\n perTxCapKobo?: number;\r\n cumulativeCapKobo?: number;\r\n validFromMs: number;\r\n validUntilMs: number;\r\n counterSeed?: number;\r\n nonce: string;\r\n}): UnsignedOAC {\r\n return {\r\n userId: input.userId,\r\n deviceId: input.deviceId,\r\n devicePublicKey: input.devicePublicKey,\r\n perTxCapKobo: input.perTxCapKobo ?? OAC_DEFAULT_PER_TX_KOBO,\r\n cumulativeCapKobo: input.cumulativeCapKobo ?? OAC_DEFAULT_CUMULATIVE_KOBO,\r\n validFromMs: input.validFromMs,\r\n validUntilMs: input.validUntilMs,\r\n counterSeed: input.counterSeed ?? 0,\r\n nonce: input.nonce,\r\n };\r\n}\r\n\r\nexport function signOAC(\r\n unsigned: UnsignedOAC,\r\n issuerPrivateKey: Uint8Array,\r\n): OAC {\r\n const issuerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerPrivateKey,\r\n );\r\n return { ...unsigned, issuerSig };\r\n}\r\n\r\nexport function verifyOAC(oac: OAC, issuerPublicKeySpkiB64: string): boolean {\r\n try {\r\n const parsed = OACSchema.parse(oac);\r\n const { issuerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-exported small byte helpers — kept for QR/codec callers; they are not\r\n// part of the OAC contract any more.\r\nexport function bytesToHex(b: Uint8Array): string {\r\n let s = '';\r\n for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, '0');\r\n return s;\r\n}\r\n\r\nexport function hexToBytes(s: string): Uint8Array {\r\n if (s.length % 2 !== 0) throw new Error('hex: odd length');\r\n const out = new Uint8Array(s.length / 2);\r\n for (let i = 0; i < out.length; i++)\r\n out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16);\r\n return out;\r\n}\r\n","/**\r\n * P-256 (ECDSA over secp256r1) issuer signing helpers for SDK-side\r\n * sign/verify of artefacts (passes, receipts).\r\n *\r\n * Wire format matches the backend (`flur-backend/src/crypto/issuer-p256.ts`)\r\n * and the mobile native secure-signer modules:\r\n * - private key: raw 32-byte P-256 secret (matches `@noble/curves/nist`).\r\n * - public key: SubjectPublicKeyInfo DER, base64 (on-wire form).\r\n * - signature: ASN.1 DER ECDSA, base64.\r\n * - hash: SHA-256 (consumed internally via `{ prehash: true }`).\r\n *\r\n * `signPass` / `signReceipt` typically only run in tests and trusted\r\n * server-side integrators; mobile consumers only verify.\r\n */\r\n\r\nimport { p256 } from '@noble/curves/nist';\r\n\r\n// ─────────────────────────── byte/base64 utils ───────────────────────────\r\n\r\nfunction bytesToBase64(bytes: Uint8Array): string {\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(bytes).toString('base64');\r\n }\r\n let bin = '';\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]!);\r\n // eslint-disable-next-line no-undef\r\n return btoa(bin);\r\n}\r\n\r\nfunction base64ToBytes(b64: string): Uint8Array {\r\n if (typeof Buffer !== 'undefined') {\r\n return new Uint8Array(Buffer.from(b64, 'base64'));\r\n }\r\n // eslint-disable-next-line no-undef\r\n const bin = atob(b64);\r\n const out = new Uint8Array(bin.length);\r\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\r\n return out;\r\n}\r\n\r\n// ─────────────────────────── SPKI <-> raw helpers ────────────────────────\r\n//\r\n// @noble/curves emits the raw X9.62 uncompressed point (0x04 || X || Y).\r\n// SubjectPublicKeyInfo DER wraps that with a fixed 26-byte ASN.1 header for\r\n// P-256. Strip/wrap to convert.\r\n\r\nconst P256_SPKI_HEADER = new Uint8Array([\r\n 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,\r\n 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,\r\n]);\r\n\r\nexport function p256SpkiB64ToRaw(spkiB64: string): Uint8Array {\r\n const spki = base64ToBytes(spkiB64);\r\n if (spki.length !== P256_SPKI_HEADER.length + 65) {\r\n throw new Error('p256: invalid SPKI length');\r\n }\r\n for (let i = 0; i < P256_SPKI_HEADER.length; i++) {\r\n if (spki[i] !== P256_SPKI_HEADER[i]) {\r\n throw new Error('p256: invalid SPKI header');\r\n }\r\n }\r\n return spki.slice(P256_SPKI_HEADER.length);\r\n}\r\n\r\nexport function p256RawToSpkiB64(rawUncompressed: Uint8Array): string {\r\n if (rawUncompressed.length !== 65 || rawUncompressed[0] !== 0x04) {\r\n throw new Error('p256: expected 65-byte uncompressed point');\r\n }\r\n const out = new Uint8Array(P256_SPKI_HEADER.length + rawUncompressed.length);\r\n out.set(P256_SPKI_HEADER, 0);\r\n out.set(rawUncompressed, P256_SPKI_HEADER.length);\r\n return bytesToBase64(out);\r\n}\r\n\r\n// ─────────────────────────── sign / verify ───────────────────────────\r\n\r\n/**\r\n * Sign a byte array with a raw 32-byte P-256 private key.\r\n * Returns ASN.1 DER ECDSA signature, base64.\r\n */\r\nexport function signIssuerP256(\r\n bytes: Uint8Array,\r\n issuerPrivateKey: Uint8Array,\r\n): string {\r\n const sig = p256.sign(bytes, issuerPrivateKey, { prehash: true });\r\n return bytesToBase64(sig.toBytes('der'));\r\n}\r\n\r\n/**\r\n * Verify a base64 DER ECDSA P-256 signature against the issuer's SPKI DER\r\n * public key (base64). Returns `false` on any decoding/verification failure.\r\n */\r\nexport function verifyIssuerP256(\r\n bytes: Uint8Array,\r\n signatureB64: string,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const pubRaw = p256SpkiB64ToRaw(issuerPublicKeySpkiB64);\r\n const sigBytes = base64ToBytes(signatureB64);\r\n return p256.verify(sigBytes, bytes, pubRaw, {\r\n prehash: true,\r\n format: 'der',\r\n });\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","// RFC 9285 base45 encoder/decoder.\r\nconst ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';\r\nconst REVERSE: Record<string, number> = {};\r\nfor (let i = 0; i < ALPHABET.length; i++) REVERSE[ALPHABET[i]] = i;\r\n\r\nexport function encodeBase45(bytes: Uint8Array): string {\r\n let out = '';\r\n let i = 0;\r\n for (; i + 1 < bytes.length; i += 2) {\r\n const x = (bytes[i] << 8) | bytes[i + 1];\r\n const e = Math.floor(x / (45 * 45));\r\n const d = Math.floor((x % (45 * 45)) / 45);\r\n const c = x % 45;\r\n out += ALPHABET[c] + ALPHABET[d] + ALPHABET[e];\r\n }\r\n if (i < bytes.length) {\r\n const x = bytes[i];\r\n const d = Math.floor(x / 45);\r\n const c = x % 45;\r\n out += ALPHABET[c] + ALPHABET[d];\r\n }\r\n return out;\r\n}\r\n\r\nexport function decodeBase45(s: string): Uint8Array {\r\n if (s.length === 0) return new Uint8Array(0);\r\n const fullChunks = Math.floor(s.length / 3);\r\n const tail = s.length - fullChunks * 3;\r\n if (tail === 1) throw new Error('base45: invalid length');\r\n const out = new Uint8Array(fullChunks * 2 + (tail === 2 ? 1 : 0));\r\n let oi = 0;\r\n for (let i = 0; i < fullChunks; i++) {\r\n const c = REVERSE[s[i * 3]];\r\n const d = REVERSE[s[i * 3 + 1]];\r\n const e = REVERSE[s[i * 3 + 2]];\r\n if (c === undefined || d === undefined || e === undefined) {\r\n throw new Error('base45: invalid character');\r\n }\r\n const x = c + 45 * d + 45 * 45 * e;\r\n if (x > 0xffff) throw new Error('base45: chunk overflow');\r\n out[oi++] = (x >> 8) & 0xff;\r\n out[oi++] = x & 0xff;\r\n }\r\n if (tail === 2) {\r\n const c = REVERSE[s[fullChunks * 3]];\r\n const d = REVERSE[s[fullChunks * 3 + 1]];\r\n if (c === undefined || d === undefined)\r\n throw new Error('base45: invalid character');\r\n const x = c + 45 * d;\r\n if (x > 0xff) throw new Error('base45: tail overflow');\r\n out[oi++] = x & 0xff;\r\n }\r\n return out;\r\n}\r\n","/**\r\n * Offline payment messages — P-256 edition (Stage 2c).\r\n *\r\n * Wire-shape change vs. the previous Ed25519 hex format:\r\n * - `merchantSig`, `payerSig` : ASN.1 DER ECDSA(SHA-256) signature, base64.\r\n * - device signing keys are passed as raw 32-byte P-256 scalars (Uint8Array);\r\n * issuer-side verification arguments use SPKI DER base64 strings.\r\n *\r\n * Note: `verifyPaymentRequest` and `verifyAuthorization` take the *issuer*\r\n * public key (SPKI b64) — they re-verify the merchant/payer OAC against the\r\n * issuer, then verify the merchant/payer signature against the device key\r\n * embedded in their OAC.\r\n */\r\nimport { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\nimport { OACSchema, type OAC } from './oac.js';\r\nimport { encodeBase45, decodeBase45 } from './codec.js';\r\n\r\nconst Base64Sig = z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/, 'expected base64 (standard) signature');\r\n\r\nexport const OfflinePaymentRequestSchema = z.object({\r\n reference: z.string().min(1),\r\n amountKobo: z.number().int().positive(),\r\n merchantOAC: OACSchema,\r\n expiresAtMs: z.number().int().positive(),\r\n merchantSig: Base64Sig,\r\n});\r\nexport type OfflinePaymentRequest = z.infer<typeof OfflinePaymentRequestSchema>;\r\nexport type UnsignedOfflinePaymentRequest = Omit<\r\n OfflinePaymentRequest,\r\n 'merchantSig'\r\n>;\r\n\r\nexport const OfflinePaymentAuthorizationSchema = z.object({\r\n request: OfflinePaymentRequestSchema,\r\n payerOAC: OACSchema,\r\n payerCounter: z.number().int().positive(),\r\n payerSig: Base64Sig,\r\n});\r\nexport type OfflinePaymentAuthorization = z.infer<\r\n typeof OfflinePaymentAuthorizationSchema\r\n>;\r\nexport type UnsignedOfflinePaymentAuthorization = Omit<\r\n OfflinePaymentAuthorization,\r\n 'payerSig'\r\n>;\r\n\r\nexport function buildPaymentRequest(input: {\r\n reference: string;\r\n amountKobo: number;\r\n merchantOAC: OAC;\r\n expiresAtMs: number;\r\n}): UnsignedOfflinePaymentRequest {\r\n if (!Number.isInteger(input.amountKobo) || input.amountKobo <= 0) {\r\n throw new Error('amountKobo must be a positive integer');\r\n }\r\n if (input.amountKobo > input.merchantOAC.perTxCapKobo) {\r\n throw new Error('amountKobo exceeds merchant OAC perTxCapKobo');\r\n }\r\n return {\r\n reference: input.reference,\r\n amountKobo: input.amountKobo,\r\n merchantOAC: input.merchantOAC,\r\n expiresAtMs: input.expiresAtMs,\r\n };\r\n}\r\n\r\nexport function signPaymentRequest(\r\n unsigned: UnsignedOfflinePaymentRequest,\r\n merchantDevicePrivateKey: Uint8Array,\r\n): OfflinePaymentRequest {\r\n const merchantSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n merchantDevicePrivateKey,\r\n );\r\n return { ...unsigned, merchantSig };\r\n}\r\n\r\nexport function verifyPaymentRequest(\r\n req: OfflinePaymentRequest,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = OfflinePaymentRequestSchema.parse(req);\r\n // 1. Issuer must have signed the merchant OAC.\r\n const { issuerSig: merchantOacSig, ...merchantOacUnsigned } =\r\n parsed.merchantOAC;\r\n if (\r\n !verifyIssuerP256(\r\n canonicalJSONBytes(merchantOacUnsigned),\r\n merchantOacSig,\r\n issuerPublicKeySpkiB64,\r\n )\r\n ) {\r\n return false;\r\n }\r\n // 2. The merchant's device key (in the OAC) must have signed this request.\r\n const { merchantSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n merchantSig,\r\n parsed.merchantOAC.devicePublicKey,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function buildAuthorization(input: {\r\n request: OfflinePaymentRequest;\r\n payerOAC: OAC;\r\n payerCounter: number;\r\n}): UnsignedOfflinePaymentAuthorization {\r\n if (!Number.isInteger(input.payerCounter) || input.payerCounter <= 0) {\r\n throw new Error('payerCounter must be a positive integer');\r\n }\r\n if (input.request.amountKobo > input.payerOAC.perTxCapKobo) {\r\n throw new Error('amountKobo exceeds payer OAC perTxCapKobo');\r\n }\r\n return {\r\n request: input.request,\r\n payerOAC: input.payerOAC,\r\n payerCounter: input.payerCounter,\r\n };\r\n}\r\n\r\nexport function signAuthorization(\r\n unsigned: UnsignedOfflinePaymentAuthorization,\r\n payerDevicePrivateKey: Uint8Array,\r\n): OfflinePaymentAuthorization {\r\n const payerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n payerDevicePrivateKey,\r\n );\r\n return { ...unsigned, payerSig };\r\n}\r\n\r\nexport function verifyAuthorization(\r\n auth: OfflinePaymentAuthorization,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = OfflinePaymentAuthorizationSchema.parse(auth);\r\n if (!verifyPaymentRequest(parsed.request, issuerPublicKeySpkiB64))\r\n return false;\r\n // Issuer must have signed the payer OAC.\r\n const { issuerSig: payerOacSig, ...payerOacUnsigned } = parsed.payerOAC;\r\n if (\r\n !verifyIssuerP256(\r\n canonicalJSONBytes(payerOacUnsigned),\r\n payerOacSig,\r\n issuerPublicKeySpkiB64,\r\n )\r\n ) {\r\n return false;\r\n }\r\n // Payer device key must have signed this authorization.\r\n const { payerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n payerSig,\r\n parsed.payerOAC.devicePublicKey,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function encodePaymentRequestQR(req: OfflinePaymentRequest): string {\r\n const json = JSON.stringify(req);\r\n return 'FLUR1:' + encodeBase45(new TextEncoder().encode(json));\r\n}\r\n\r\nexport function decodePaymentRequestQR(s: string): OfflinePaymentRequest {\r\n if (!s.startsWith('FLUR1:'))\r\n throw new Error('not a Flur offline payment request QR');\r\n const bytes = decodeBase45(s.slice('FLUR1:'.length));\r\n const json = new TextDecoder().decode(bytes);\r\n return OfflinePaymentRequestSchema.parse(JSON.parse(json));\r\n}\r\n\r\nexport function encodeAuthorizationQR(\r\n auth: OfflinePaymentAuthorization,\r\n): string {\r\n const json = JSON.stringify(auth);\r\n return 'FLUR2:' + encodeBase45(new TextEncoder().encode(json));\r\n}\r\n\r\nexport function decodeAuthorizationQR(s: string): OfflinePaymentAuthorization {\r\n if (!s.startsWith('FLUR2:'))\r\n throw new Error('not a Flur offline authorization QR');\r\n const bytes = decodeBase45(s.slice('FLUR2:'.length));\r\n const json = new TextDecoder().decode(bytes);\r\n return OfflinePaymentAuthorizationSchema.parse(JSON.parse(json));\r\n}\r\n","/**\r\n * Offline settlement SDK helpers.\r\n *\r\n * The SDK does not \"pay\" offline — it produces signed `PaymentClaim`s and posts\r\n * them to `/v1/offline/settlements`. The backend enforces \"paid once\" via\r\n * UNIQUE(settlement_key) and UNIQUE(token_serial).\r\n */\r\nimport { z } from 'zod';\r\nimport type { FlurPartnerClient } from '../partner/client.js';\r\n\r\n// ───────────────────────────── schemas ─────────────────────────────\r\n\r\nexport const OfflineTokenSchema = z.object({\r\n tokenId: z.string().uuid(),\r\n tokenSerial: z.string(),\r\n issuerAccountId: z.string().uuid(),\r\n payerUserId: z.string().uuid(),\r\n maxAmountKobo: z.number().int().positive(),\r\n currency: z.string().length(3),\r\n issuedAtMs: z.number().int().nonnegative(),\r\n expiresAtMs: z.number().int().nonnegative(),\r\n issuerSig: z.string(),\r\n});\r\nexport type OfflineToken = z.infer<typeof OfflineTokenSchema>;\r\n\r\nexport const PaymentClaimSchema = z.object({\r\n encounterId: z\r\n .string()\r\n .regex(/^[0-9a-f]{64}$/i)\r\n .optional(),\r\n tokenSerial: z.string(),\r\n payerUserId: z.string().uuid(),\r\n payeeUserId: z.string().uuid(),\r\n payerNonce: z.string(),\r\n payeeNonce: z.string(),\r\n amountKobo: z.number().int().positive(),\r\n currency: z.string().length(3).default('NGN'),\r\n occurredAtMs: z.number().int().nonnegative(),\r\n completedAtMs: z.number().int().nonnegative().optional(),\r\n contextId: z.string().optional(),\r\n // Stage 2c: P-256 device keys are now SubjectPublicKeyInfo DER, base64.\r\n // Signatures are ASN.1 DER ECDSA(SHA-256), base64. Backwards-incompatible\r\n // wire change; the backend has the matching widening in offline-settlements\r\n // service + zod schema.\r\n payerPubkey: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n payerSignature: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n payeePubkey: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/)\r\n .optional(),\r\n payeeSignature: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/)\r\n .optional(),\r\n});\r\nexport type PaymentClaim = z.infer<typeof PaymentClaimSchema>;\r\n\r\nexport const SettlementSchema = z.object({\r\n settlementId: z.string().uuid(),\r\n settlementKey: z.string().regex(/^[0-9a-f]{64}$/i),\r\n encounterId: z.string().regex(/^[0-9a-f]{64}$/i),\r\n issuerAccountId: z.string().uuid(),\r\n tokenSerial: z.string(),\r\n payerUserId: z.string().uuid(),\r\n payeeUserId: z.string().uuid(),\r\n amountKobo: z.number().int().nonnegative(),\r\n currency: z.string().length(3),\r\n receiptId: z.string().nullable(),\r\n status: z.enum(['SETTLED', 'REVIEW', 'REJECTED']),\r\n issuerSig: z.string(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type Settlement = z.infer<typeof SettlementSchema>;\r\n\r\nexport const SettleResponseSchema = z.object({\r\n settlement: SettlementSchema,\r\n encounterId: z.string().regex(/^[0-9a-f]{64}$/i),\r\n replayed: z.boolean(),\r\n});\r\nexport type SettleResponse = z.infer<typeof SettleResponseSchema>;\r\n\r\n// ───────────────────────────── deterministic ids ─────────────────────────────\r\n\r\nimport { sha256 } from '@noble/hashes/sha256';\r\nimport { bytesToHex } from '@noble/hashes/utils';\r\n\r\nconst ENCOUNTER_DOMAIN = 'offline:v1:encounter';\r\n\r\n/** SHA-256 hex helper. Pure-JS via @noble/hashes — works in Node, browser, and React Native. */\r\nasync function sha256Hex(input: string): Promise<string> {\r\n return bytesToHex(sha256(new TextEncoder().encode(input)));\r\n}\r\n\r\n/**\r\n * Compute the deterministic encounterId. Both parties produce the same value;\r\n * the backend enforces it.\r\n */\r\nexport async function computeEncounterId(input: {\r\n payerUserId: string;\r\n payeeUserId: string;\r\n payerNonce: string;\r\n payeeNonce: string;\r\n tokenSerial: string;\r\n}): Promise<string> {\r\n return sha256Hex(\r\n ENCOUNTER_DOMAIN +\r\n '|' +\r\n [\r\n input.payerUserId,\r\n input.payeeUserId,\r\n input.payerNonce,\r\n input.payeeNonce,\r\n input.tokenSerial,\r\n ].join('|'),\r\n );\r\n}\r\n\r\n// ───────────────────────────── client ─────────────────────────────\r\n\r\nexport type IssueOfflineTokenInput = {\r\n /** Optional client-supplied serial (must be unique). */\r\n tokenSerial?: string;\r\n payerUserId: string;\r\n maxAmountKobo: number;\r\n currency?: string;\r\n ttlMs: number;\r\n};\r\n\r\nexport type FlurOfflineSettlementsClient = {\r\n /** Partner-only: pre-issue a bounded offline settlement token. */\r\n issueOfflineToken: (input: IssueOfflineTokenInput) => Promise<OfflineToken>;\r\n /** Get a token by serial (partner-scoped). */\r\n getOfflineToken: (tokenSerial: string) => Promise<OfflineToken>;\r\n /** Atomically settle a signed payment claim (idempotent). */\r\n settle: (claim: PaymentClaim) => Promise<SettleResponse>;\r\n /** Fetch a stored settlement by id or settlement_key. */\r\n getSettlement: (idOrKey: string) => Promise<Settlement>;\r\n /** List queued conflict/review items (partner-scoped). */\r\n listConflicts: () => Promise<{ items: unknown[] }>;\r\n};\r\n\r\nexport function createOfflineSettlementsClient(\r\n partner: FlurPartnerClient,\r\n): FlurOfflineSettlementsClient {\r\n return {\r\n issueOfflineToken: (input) =>\r\n partner.request<OfflineToken>({\r\n method: 'POST',\r\n path: '/v1/offline/tokens',\r\n body: {\r\n payerUserId: input.payerUserId,\r\n maxAmountKobo: input.maxAmountKobo,\r\n currency: input.currency ?? 'NGN',\r\n ttlMs: input.ttlMs,\r\n ...(input.tokenSerial ? { tokenSerial: input.tokenSerial } : {}),\r\n },\r\n }),\r\n getOfflineToken: (serial) =>\r\n partner.request<OfflineToken>({\r\n method: 'GET',\r\n path: `/v1/offline/tokens/${encodeURIComponent(serial)}`,\r\n }),\r\n settle: (claim) =>\r\n partner.request<SettleResponse>({\r\n method: 'POST',\r\n path: '/v1/offline/settlements',\r\n body: claim,\r\n }),\r\n getSettlement: (id) =>\r\n partner.request<Settlement>({\r\n method: 'GET',\r\n path: `/v1/offline/settlements/${encodeURIComponent(id)}`,\r\n }),\r\n listConflicts: () =>\r\n partner.request<{ items: unknown[] }>({\r\n method: 'GET',\r\n path: '/v1/offline/conflicts',\r\n }),\r\n };\r\n}\r\n","import { hmac } from '@noble/hashes/hmac';\r\nimport { sha256 } from '@noble/hashes/sha256';\r\n\r\nfunction bytesToHex(b: Uint8Array): string {\r\n let s = '';\r\n for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, '0');\r\n return s;\r\n}\r\n\r\nfunction constantTimeStringEqual(a: string, b: string): boolean {\r\n if (a.length !== b.length) return false;\r\n let diff = 0;\r\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n return diff === 0;\r\n}\r\n\r\nexport function bodySha256Hex(body: string): string {\r\n return bytesToHex(sha256(new TextEncoder().encode(body)));\r\n}\r\n\r\nexport function canonicalRequestString(input: {\r\n method: string;\r\n path: string;\r\n timestamp: string;\r\n nonce: string;\r\n body: string;\r\n}): string {\r\n return [\r\n input.method.toUpperCase(),\r\n input.path,\r\n input.timestamp,\r\n input.nonce,\r\n bodySha256Hex(input.body),\r\n ].join('\\n');\r\n}\r\n\r\nexport function signRequestHMAC(input: {\r\n method: string;\r\n path: string;\r\n timestamp: string;\r\n nonce: string;\r\n body: string;\r\n apiSecret: string;\r\n}): string {\r\n return bytesToHex(\r\n hmac(sha256, input.apiSecret, canonicalRequestString(input)),\r\n );\r\n}\r\n\r\nexport function verifyRequestHMAC(input: {\r\n method: string;\r\n path: string;\r\n timestamp: string;\r\n nonce: string;\r\n body: string;\r\n apiSecret: string;\r\n signature: string;\r\n}): boolean {\r\n const expected = signRequestHMAC(input);\r\n return constantTimeStringEqual(expected, input.signature.toLowerCase());\r\n}\r\n","import { signRequestHMAC } from './hmac.js';\r\n\r\nexport const REPLAY_WINDOW_MS = 5 * 60 * 1000;\r\n\r\n/**\r\n * Server may signal clock skew in this header (RFC3339 or epoch seconds/ms).\r\n * The HMAC client uses it to perform a single bounded retry on 401.\r\n */\r\nexport const SERVER_TIME_HEADER = 'x-flur-server-time';\r\n\r\nexport type HmacFetchOptions = {\r\n apiKey: string;\r\n apiSecret: string;\r\n fetchImpl?: typeof fetch;\r\n nowMs?: () => number;\r\n nonceFn?: () => string;\r\n /** Optional scope claim forwarded as `X-Flur-Scope` (comma-joined). Backend remains authoritative. */\r\n scope?: readonly string[];\r\n};\r\n\r\n/** Generate a 128-bit nonce as hex. CSPRNG-only — throws if unavailable. */\r\nfunction defaultNonce(): string {\r\n const c = globalThis.crypto;\r\n if (typeof c?.randomUUID === 'function') return c.randomUUID();\r\n if (typeof c?.getRandomValues !== 'function') {\r\n throw new Error(\r\n 'Flur SDK: no CSPRNG available (globalThis.crypto.getRandomValues missing). ' +\r\n 'Refusing to fall back to Math.random for HMAC nonce generation.',\r\n );\r\n }\r\n const arr = new Uint8Array(16);\r\n c.getRandomValues(arr);\r\n let s = '';\r\n for (let i = 0; i < arr.length; i++)\r\n s += arr[i].toString(16).padStart(2, '0');\r\n return s;\r\n}\r\n\r\nfunction assertCSPRNG(): void {\r\n const c = globalThis.crypto;\r\n if (\r\n typeof c?.getRandomValues !== 'function' &&\r\n typeof c?.randomUUID !== 'function'\r\n ) {\r\n throw new Error(\r\n 'Flur SDK: no CSPRNG available (globalThis.crypto missing). ' +\r\n 'Initialize on a runtime that provides Web Crypto (Node 19+, modern browsers, RN 0.74+).',\r\n );\r\n }\r\n}\r\n\r\n/** Parse a server-time hint as either epoch (s or ms) or RFC3339; returns ms or null. */\r\nfunction parseServerTimeMs(value: string | null): number | null {\r\n if (!value) return null;\r\n const trimmed = value.trim();\r\n if (/^\\d+$/.test(trimmed)) {\r\n const n = Number(trimmed);\r\n return n < 1e12 ? n * 1000 : n; // seconds vs ms heuristic\r\n }\r\n const t = Date.parse(trimmed);\r\n return Number.isFinite(t) ? t : null;\r\n}\r\n\r\nexport function createHmacFetch(opts: HmacFetchOptions): typeof fetch {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl)\r\n throw new Error('createHmacFetch: no fetch implementation available');\r\n if (!opts.nonceFn) assertCSPRNG(); // fail-fast unless caller injected a nonce source\r\n\r\n const nowMs = opts.nowMs ?? (() => Date.now());\r\n const nonceFn = opts.nonceFn ?? defaultNonce;\r\n const scopeHeader =\r\n opts.scope && opts.scope.length > 0 ? opts.scope.join(',') : undefined;\r\n\r\n async function signAndSend(\r\n req: Request,\r\n skewOffsetMs: number,\r\n ): Promise<Response> {\r\n // Clone first so the caller can keep using `req` (e.g., for a retry).\r\n const cloned = req.clone();\r\n const url = new URL(cloned.url);\r\n const path = url.pathname + url.search;\r\n const method = cloned.method.toUpperCase();\r\n const bodyText =\r\n method === 'GET' || method === 'HEAD' ? '' : await cloned.clone().text();\r\n const timestamp = Math.floor((nowMs() + skewOffsetMs) / 1000).toString();\r\n const nonce = nonceFn();\r\n const signature = signRequestHMAC({\r\n method,\r\n path,\r\n timestamp,\r\n nonce,\r\n body: bodyText,\r\n apiSecret: opts.apiSecret,\r\n });\r\n const headers = new Headers(cloned.headers);\r\n headers.set('x-flur-key', opts.apiKey);\r\n headers.set('x-flur-timestamp', timestamp);\r\n headers.set('x-flur-nonce', nonce);\r\n headers.set('x-flur-signature', signature);\r\n if (scopeHeader) headers.set('x-flur-scope', scopeHeader);\r\n const signed = new Request(cloned, { headers });\r\n return fetchImpl(signed);\r\n }\r\n\r\n return (async (input: RequestInfo | URL, init?: RequestInit) => {\r\n const req = input instanceof Request ? input : new Request(input, init);\r\n let resp = await signAndSend(req, 0);\r\n\r\n if (resp.status === 401) {\r\n const serverTimeMs = parseServerTimeMs(\r\n resp.headers.get(SERVER_TIME_HEADER),\r\n );\r\n if (serverTimeMs !== null) {\r\n const skew = serverTimeMs - nowMs();\r\n if (Math.abs(skew) > 0) {\r\n // Bounded single retry with corrected timestamp.\r\n resp = await signAndSend(req, skew);\r\n }\r\n }\r\n }\r\n return resp;\r\n }) as typeof fetch;\r\n}\r\n","import { z } from 'zod';\r\nimport { sha256 } from '@noble/hashes/sha256';\r\nimport { hmac } from '@noble/hashes/hmac';\r\nimport { bytesToHex } from '@noble/hashes/utils';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport const PARTNER_SCOPES = [\r\n 'passes:write',\r\n 'passes:read',\r\n 'passes:redeem',\r\n 'receipts:write',\r\n 'receipts:read',\r\n 'offline:issue',\r\n 'offline:settle',\r\n 'offline:read',\r\n 'collections:write',\r\n 'collections:read',\r\n 'collections:pay',\r\n 'collections:webhook',\r\n 'reports:read',\r\n 'payouts:write',\r\n 'payouts:read',\r\n 'partner:funding:write',\r\n 'partner:payout:write',\r\n 'partner:reconciliation:read',\r\n] as const;\r\nexport type PartnerScope = (typeof PARTNER_SCOPES)[number];\r\n\r\nexport const ApiCredentialPublicSchema = z.object({\r\n id: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n keyId: z.string(),\r\n scopes: z.array(z.enum(PARTNER_SCOPES)),\r\n label: z.string().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n lastUsedAtMs: z.number().int().nonnegative().nullable(),\r\n revokedAtMs: z.number().int().nonnegative().nullable(),\r\n});\r\nexport type ApiCredentialPublic = z.infer<typeof ApiCredentialPublicSchema>;\r\n\r\nexport const MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({\r\n secret: z.string().min(1),\r\n});\r\nexport type MintedApiCredential = z.infer<typeof MintedApiCredentialSchema>;\r\n\r\nexport type PartnerClientOptions = {\r\n baseUrl: string;\r\n /** Stable account id of the partner; included for observability only. */\r\n accountId?: string;\r\n /** Public key id from the mint response (e.g. flur_pk_...). */\r\n keyId: string;\r\n /** Plaintext secret from the mint response (e.g. flur_sk_...). */\r\n secret: string;\r\n fetchImpl?: typeof fetch;\r\n /** Override clock for tests. Returns ms. */\r\n nowMs?: () => number;\r\n /** Override nonce generator for tests. */\r\n nonce?: () => string;\r\n /** Optional scope claim forwarded as X-Flur-Scope; backend credentials remain authoritative. */\r\n scope?: readonly PartnerScope[];\r\n};\r\n\r\nconst enc = new TextEncoder();\r\n\r\nasync function sha256Hex(input: string | Uint8Array): Promise<string> {\r\n const data = typeof input === 'string' ? enc.encode(input) : input;\r\n return bytesToHex(sha256(data));\r\n}\r\n\r\nasync function hmacSha256Hex(keyHex: string, message: string): Promise<string> {\r\n // The server stores `secret_hash` as the hex string of sha256(secret) and\r\n // uses Node `createHmac('sha256', secret_hash)`, which treats the hex\r\n // STRING as raw UTF-8 bytes for the HMAC key. We do the same here.\r\n return bytesToHex(hmac(sha256, enc.encode(keyHex), enc.encode(message)));\r\n}\r\n\r\nfunction defaultNonce(): string {\r\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\r\n if (c?.randomUUID) return c.randomUUID();\r\n return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;\r\n}\r\n\r\n/**\r\n * Build the canonical signing string. Must mirror the server.\r\n */\r\nfunction canonical(params: {\r\n method: string;\r\n path: string;\r\n ts: string;\r\n nonce: string;\r\n bodyHash: string;\r\n}): string {\r\n return [\r\n params.method.toUpperCase(),\r\n params.path,\r\n params.ts,\r\n params.nonce,\r\n params.bodyHash,\r\n ].join('\\n');\r\n}\r\n\r\nexport type PartnerSignResult = {\r\n authorization: string;\r\n ts: string;\r\n nonce: string;\r\n bodyHash: string;\r\n};\r\n\r\nexport async function signPartnerRequest(params: {\r\n keyId: string;\r\n secret: string;\r\n method: string;\r\n path: string;\r\n body?: string | Uint8Array;\r\n nowMs?: number;\r\n nonce?: string;\r\n}): Promise<PartnerSignResult> {\r\n const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1000));\r\n const nonce = params.nonce ?? defaultNonce();\r\n const bodyData =\r\n typeof params.body === 'string'\r\n ? enc.encode(params.body)\r\n : (params.body ?? new Uint8Array());\r\n const bodyHash = await sha256Hex(bodyData);\r\n const message = canonical({\r\n method: params.method,\r\n path: params.path,\r\n ts,\r\n nonce,\r\n bodyHash,\r\n });\r\n const signingKey = await sha256Hex(params.secret);\r\n const sig = await hmacSha256Hex(signingKey, message);\r\n return {\r\n authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,\r\n ts,\r\n nonce,\r\n bodyHash,\r\n };\r\n}\r\n\r\nexport type FlurPartnerClient = {\r\n /** Make a signed request. Resolves to parsed JSON or throws FlurApiError. */\r\n request: <T = unknown>(opts: {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n body?: unknown;\r\n }) => Promise<T>;\r\n /** Returns a fetch-compatible function with auto-signing. */\r\n fetch: typeof fetch;\r\n};\r\n\r\nexport function createFlurPartnerClient(\r\n opts: PartnerClientOptions,\r\n): FlurPartnerClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createFlurPartnerClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n const scopeHeader = normalizeScopeHeader(opts.scope);\r\n\r\n async function makeSignedInit(\r\n method: string,\r\n path: string,\r\n body?: string,\r\n ): Promise<RequestInit> {\r\n const sig = await signPartnerRequest({\r\n keyId: opts.keyId,\r\n secret: opts.secret,\r\n method,\r\n path,\r\n body: body ?? '',\r\n nowMs: opts.nowMs?.(),\r\n nonce: opts.nonce?.(),\r\n });\r\n const headers: Record<string, string> = {\r\n authorization: sig.authorization,\r\n accept: 'application/json',\r\n };\r\n if (scopeHeader) headers['x-flur-scope'] = scopeHeader;\r\n if (body !== undefined) headers['content-type'] = 'application/json';\r\n const init: RequestInit = { method, headers };\r\n if (body !== undefined) init.body = body;\r\n return init;\r\n }\r\n\r\n async function request<T>(opts2: {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n body?: unknown;\r\n }): Promise<T> {\r\n const bodyStr =\r\n opts2.body === undefined ? undefined : JSON.stringify(opts2.body);\r\n const init = await makeSignedInit(opts2.method, opts2.path, bodyStr);\r\n const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return raw as T;\r\n }\r\n\r\n const fetchLike: typeof fetch = async (input, init) => {\r\n const url = typeof input === 'string' ? input : (input as URL).toString();\r\n const u = new URL(url, baseUrl);\r\n const path = `${u.pathname}${u.search}`;\r\n const method = (init?.method ?? 'GET').toUpperCase();\r\n let bodyStr: string | undefined;\r\n if (init?.body) {\r\n bodyStr =\r\n typeof init.body === 'string'\r\n ? init.body\r\n : (init.body as { toString(): string }).toString();\r\n }\r\n const signed = await makeSignedInit(method, path, bodyStr);\r\n return fetchImpl(`${baseUrl}${path}`, {\r\n ...init,\r\n ...signed,\r\n headers: {\r\n ...(init?.headers as Record<string, string>),\r\n ...(signed.headers as Record<string, string>),\r\n },\r\n });\r\n };\r\n\r\n return { request, fetch: fetchLike };\r\n}\r\n\r\nfunction normalizeScopeHeader(\r\n scope: readonly PartnerScope[] | undefined,\r\n): string | undefined {\r\n if (!scope || scope.length === 0) return undefined;\r\n const unique = Array.from(new Set(scope));\r\n for (const item of unique) {\r\n if (!(PARTNER_SCOPES as readonly string[]).includes(item)) {\r\n throw new Error(`unsupported partner scope: ${item}`);\r\n }\r\n }\r\n return unique.join(' ');\r\n}\r\n\r\n/**\r\n * SDK helper for partner credential management endpoints. Uses an arbitrary\r\n * fetchImpl (typically a session-authenticated fetch) — not the partner HMAC.\r\n */\r\nexport type ApiCredentialsAdminClient = {\r\n list: (accountId: string) => Promise<{ items: ApiCredentialPublic[] }>;\r\n mint: (\r\n accountId: string,\r\n input: { scopes: PartnerScope[]; label?: string | null },\r\n ) => Promise<MintedApiCredential>;\r\n revoke: (\r\n accountId: string,\r\n credentialId: string,\r\n ) => Promise<ApiCredentialPublic>;\r\n};\r\n\r\nexport function createApiCredentialsAdminClient(opts: {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n}): ApiCredentialsAdminClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createApiCredentialsAdminClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n const listSchema = z.object({\r\n items: z.array(ApiCredentialPublicSchema),\r\n });\r\n\r\n return {\r\n list: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${accountId}/api-credentials`,\r\n undefined,\r\n (raw) => listSchema.parse(raw),\r\n ),\r\n mint: (accountId, input) =>\r\n call('POST', `/v1/accounts/${accountId}/api-credentials`, input, (raw) =>\r\n MintedApiCredentialSchema.parse(raw),\r\n ),\r\n revoke: (accountId, credentialId) =>\r\n call(\r\n 'DELETE',\r\n `/v1/accounts/${accountId}/api-credentials/${credentialId}`,\r\n undefined,\r\n (raw) => ApiCredentialPublicSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\n\r\nexport const PASS_KINDS = [\r\n 'ride-ticket',\r\n 'transit-pass',\r\n 'event-ticket',\r\n 'voucher',\r\n 'loyalty',\r\n 'receipt-link',\r\n] as const;\r\nexport type PassKind = (typeof PASS_KINDS)[number];\r\n\r\nexport const PASS_STATES = [\r\n 'issued',\r\n 'active',\r\n 'redeemed',\r\n 'expired',\r\n 'revoked',\r\n] as const;\r\nexport type PassState = (typeof PASS_STATES)[number];\r\n\r\n/** JSON-serialisable metadata payload — bounded to keep QR/offline encodings tractable. */\r\nexport const PassMetadataSchema = z.record(\r\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\r\n);\r\nexport type PassMetadata = z.infer<typeof PassMetadataSchema>;\r\n\r\nexport const PassSchema = z\r\n .object({\r\n passId: z.string().min(1),\r\n /** Optional client/template grouping id (server may omit). */\r\n templateId: z.string().min(1).optional(),\r\n /** Optional human-facing holder identity (server may omit). The cryptographic binding\r\n * is `holderDevicePubkey` below. */\r\n holderUserId: z.string().min(1).optional(),\r\n kind: z.enum(PASS_KINDS),\r\n issuerId: z.string().min(1),\r\n issuedAtMs: z.number().int().nonnegative(),\r\n validFromMs: z.number().int().nonnegative(),\r\n validUntilMs: z.number().int().positive(),\r\n state: z.enum(PASS_STATES),\r\n metadata: PassMetadataSchema,\r\n nonce: z.string().min(1),\r\n /** Device id this pass is bound to (FK to backend `device_keys`). */\r\n holderDeviceId: z.string().min(1),\r\n /** SubjectPublicKeyInfo DER (P-256) of the bound device, base64. The redemption\r\n * signature is verified against this key — it is the security-critical binding. */\r\n holderDevicePubkey: z\r\n .string()\r\n .min(64)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */\r\n amountKobo: z.number().int().nonnegative().optional(),\r\n /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */\r\n currency: z.string().min(3).max(8),\r\n /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */\r\n counterSeed: z.number().int().nonnegative(),\r\n /** Optional cumulative spend cap in kobo across all redemptions of this pass. */\r\n cumulativeCapKobo: z.number().int().nonnegative().optional(),\r\n /** ASN.1 DER ECDSA P-256 signature, base64. */\r\n issuerSig: z\r\n .string()\r\n .min(64)\r\n .max(2048)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n })\r\n .refine((v) => v.validUntilMs > v.validFromMs, {\r\n message: 'validUntilMs must be greater than validFromMs',\r\n });\r\n\r\nexport type Pass = z.infer<typeof PassSchema>;\r\nexport type UnsignedPass = Omit<Pass, 'issuerSig'>;\r\n\r\nexport type BuildPassInput = {\r\n passId: string;\r\n templateId?: string;\r\n holderUserId?: string;\r\n kind: PassKind;\r\n issuerId: string;\r\n issuedAtMs: number;\r\n validFromMs: number;\r\n validUntilMs: number;\r\n state: PassState;\r\n metadata: PassMetadata;\r\n nonce: string;\r\n holderDeviceId: string;\r\n holderDevicePubkey: string;\r\n amountKobo?: number;\r\n currency?: string;\r\n counterSeed: number;\r\n cumulativeCapKobo?: number;\r\n};\r\n\r\nexport function buildPass(input: BuildPassInput): UnsignedPass {\r\n if (input.validUntilMs <= input.validFromMs) {\r\n throw new Error('validUntilMs must be greater than validFromMs');\r\n }\r\n const out: UnsignedPass = {\r\n passId: input.passId,\r\n kind: input.kind,\r\n issuerId: input.issuerId,\r\n issuedAtMs: input.issuedAtMs,\r\n validFromMs: input.validFromMs,\r\n validUntilMs: input.validUntilMs,\r\n state: input.state,\r\n metadata: input.metadata,\r\n nonce: input.nonce,\r\n holderDeviceId: input.holderDeviceId,\r\n holderDevicePubkey: input.holderDevicePubkey,\r\n currency: input.currency ?? 'NGN',\r\n counterSeed: input.counterSeed,\r\n };\r\n if (typeof input.templateId === 'string') out.templateId = input.templateId;\r\n if (typeof input.holderUserId === 'string')\r\n out.holderUserId = input.holderUserId;\r\n if (typeof input.amountKobo === 'number') out.amountKobo = input.amountKobo;\r\n if (typeof input.cumulativeCapKobo === 'number') {\r\n out.cumulativeCapKobo = input.cumulativeCapKobo;\r\n }\r\n return out;\r\n}\r\n\r\nexport function signPass(\r\n unsigned: UnsignedPass,\r\n issuerPrivateKey: Uint8Array,\r\n): Pass {\r\n const issuerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerPrivateKey,\r\n );\r\n return { ...unsigned, issuerSig };\r\n}\r\n\r\nexport function verifyPass(\r\n pass: Pass,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = PassSchema.parse(pass);\r\n const { issuerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Validity window check is done separately from signature verification so callers can\r\n * decide their clock-skew tolerance.\r\n */\r\nexport function isPassWithinValidity(pass: Pass, nowMs: number): boolean {\r\n return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport {\r\n signIssuerP256 as signP256,\r\n verifyIssuerP256 as verifyP256,\r\n} from '../crypto/p256-issuer.js';\r\nimport { PassSchema, type Pass } from './pass.js';\r\nimport {\r\n FlurExpiredError,\r\n FlurReplayError,\r\n FlurCapExceededError,\r\n} from '../errors.js';\r\n\r\nconst Base64Std = z\r\n .string()\r\n .min(16)\r\n .max(2048)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/, 'expected base64 (std)');\r\n\r\nexport const RedemptionSchema = z.object({\r\n pass: PassSchema,\r\n redeemerId: z.string().min(1),\r\n redeemedAtMs: z.number().int().nonnegative(),\r\n /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed\r\n * and > the redeemer's lastSeenCounter for this pass. */\r\n counter: z.number().int().positive(),\r\n /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */\r\n amountKobo: z.number().int().nonnegative(),\r\n nonce: z.string().min(1),\r\n /** ASN.1 DER ECDSA P-256 signature over canonicalJSONBytes(unsigned), base64. */\r\n holderSig: Base64Std,\r\n});\r\nexport type Redemption = z.infer<typeof RedemptionSchema>;\r\nexport type UnsignedRedemption = Omit<Redemption, 'holderSig'>;\r\n\r\nexport type BuildRedemptionInput = {\r\n pass: Pass;\r\n redeemerId: string;\r\n redeemedAtMs: number;\r\n counter: number;\r\n amountKobo?: number;\r\n nonce: string;\r\n /** Optional local clock — if supplied, fail-fast against pass.validUntilMs. */\r\n nowMs?: number;\r\n /** Last counter the holder has seen for this pass (default: pass.counterSeed). */\r\n lastSeenCounter?: number;\r\n /** Total kobo already redeemed against this pass (default: 0). Used with pass.cumulativeCapKobo. */\r\n cumulativeUsedKobo?: number;\r\n};\r\n\r\nconst REDEEMABLE_STATES = new Set(['issued', 'active']);\r\n\r\nexport function buildRedemption(\r\n input: BuildRedemptionInput,\r\n): UnsignedRedemption {\r\n if (!REDEEMABLE_STATES.has(input.pass.state)) {\r\n throw new Error(`pass not in redeemable state: ${input.pass.state}`);\r\n }\r\n if (input.redeemedAtMs < input.pass.validFromMs) {\r\n throw new Error('redeemedAtMs is before pass validFromMs');\r\n }\r\n if (input.redeemedAtMs >= input.pass.validUntilMs) {\r\n throw new FlurExpiredError(\r\n `pass ${input.pass.passId} expired at ${input.pass.validUntilMs}`,\r\n );\r\n }\r\n // Wall-clock expiry check (offline-safe; backend remains authoritative).\r\n const now =\r\n typeof input.nowMs === 'number' ? input.nowMs : input.redeemedAtMs;\r\n if (now >= input.pass.validUntilMs) {\r\n throw new FlurExpiredError(\r\n `pass ${input.pass.passId} expired at ${input.pass.validUntilMs}`,\r\n );\r\n }\r\n if (!input.pass.holderDevicePubkey) {\r\n throw new Error(\r\n 'pass.holderDevicePubkey is required to build a redemption',\r\n );\r\n }\r\n\r\n // Counter monotonicity: must exceed both seed and any locally-known prior counter.\r\n const lastSeen = Math.max(\r\n input.pass.counterSeed,\r\n typeof input.lastSeenCounter === 'number' ? input.lastSeenCounter : 0,\r\n );\r\n if (input.counter <= lastSeen) {\r\n throw new FlurReplayError(\r\n `redemption counter ${input.counter} must be > lastSeenCounter ${lastSeen}`,\r\n );\r\n }\r\n\r\n const amount = input.amountKobo ?? 0;\r\n\r\n // Cumulative cap (when set on the pass): used + this <= cap.\r\n if (typeof input.pass.cumulativeCapKobo === 'number') {\r\n const used = input.cumulativeUsedKobo ?? 0;\r\n if (used + amount > input.pass.cumulativeCapKobo) {\r\n throw new FlurCapExceededError(\r\n `pass ${input.pass.passId} cap ${input.pass.cumulativeCapKobo} would be exceeded (used ${used} + ${amount})`,\r\n );\r\n }\r\n }\r\n\r\n return {\r\n pass: input.pass,\r\n redeemerId: input.redeemerId,\r\n redeemedAtMs: input.redeemedAtMs,\r\n counter: input.counter,\r\n amountKobo: amount,\r\n nonce: input.nonce,\r\n };\r\n}\r\n\r\nexport function signRedemption(\r\n unsigned: UnsignedRedemption,\r\n holderDevicePrivateKey: Uint8Array,\r\n): Redemption {\r\n const holderSig = signP256(\r\n canonicalJSONBytes(unsigned),\r\n holderDevicePrivateKey,\r\n );\r\n return { ...unsigned, holderSig };\r\n}\r\n\r\n/**\r\n * Verifies, in order:\r\n * 1. The pass itself is signed by the issuer.\r\n * 2. The pass binds a `holderDevicePubkey` (top-level, security-critical).\r\n * 3. The redemption is signed by that bound device key.\r\n * 4. The redemption counter is strictly greater than pass.counterSeed.\r\n */\r\nexport function verifyRedemption(\r\n r: Redemption,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = RedemptionSchema.parse(r);\r\n if (parsed.counter <= parsed.pass.counterSeed) return false;\r\n const { issuerSig, ...passUnsigned } = parsed.pass;\r\n if (\r\n !verifyP256(\r\n canonicalJSONBytes(passUnsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n )\r\n ) {\r\n return false;\r\n }\r\n const holderPub = parsed.pass.holderDevicePubkey;\r\n if (typeof holderPub !== 'string') return false;\r\n const { holderSig, ...unsigned } = parsed;\r\n return verifyP256(canonicalJSONBytes(unsigned), holderSig, holderPub);\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\n\r\nexport const RECEIPT_CHANNELS = ['cash', 'pass'] as const;\r\nexport type ReceiptChannel = (typeof RECEIPT_CHANNELS)[number];\r\n\r\n/** @deprecated use {@link RECEIPT_CHANNELS}. Will be removed before 1.0. */\r\nexport const RECEIPT_KINDS = RECEIPT_CHANNELS;\r\n/** @deprecated use {@link ReceiptChannel}. */\r\nexport type ReceiptKind = ReceiptChannel;\r\n\r\n/** Free-form payload reserved for channel-specific extras (e.g. memo, intent metadata).\r\n * Top-level fields below are the security-relevant facts and must not be duplicated here. */\r\nexport const ReceiptPayloadSchema = z.record(\r\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\r\n);\r\nexport type ReceiptPayload = z.infer<typeof ReceiptPayloadSchema>;\r\n\r\n/** BE-20 wire schema: channel + exactly one of `intentId` (cash) or `passRedemptionId` (pass). */\r\nexport const ReceiptSchema = z\r\n .object({\r\n receiptId: z.string().min(1),\r\n channel: z.enum(RECEIPT_CHANNELS),\r\n /** Cash-channel: send_intents.id. Required when channel === 'cash'. */\r\n intentId: z.string().min(1).optional(),\r\n /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */\r\n passRedemptionId: z.string().min(1).optional(),\r\n payerUserId: z.string().min(1),\r\n payeeUserId: z.string().min(1),\r\n amountKobo: z.number().int().nonnegative(),\r\n currency: z.string().min(3).max(8),\r\n issuedAtMs: z.number().int().nonnegative(),\r\n issuerId: z.string().min(1),\r\n payload: ReceiptPayloadSchema,\r\n /** ASN.1 DER ECDSA P-256 signature, base64. */\r\n issuerSig: z\r\n .string()\r\n .min(64)\r\n .max(2048)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n })\r\n .superRefine((v, ctx) => {\r\n if (v.channel === 'cash') {\r\n if (!v.intentId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'cash receipts require intentId',\r\n path: ['intentId'],\r\n });\r\n }\r\n if (v.passRedemptionId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'cash receipts must not carry passRedemptionId',\r\n path: ['passRedemptionId'],\r\n });\r\n }\r\n } else if (v.channel === 'pass') {\r\n if (!v.passRedemptionId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'pass receipts require passRedemptionId',\r\n path: ['passRedemptionId'],\r\n });\r\n }\r\n if (v.intentId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'pass receipts must not carry intentId',\r\n path: ['intentId'],\r\n });\r\n }\r\n }\r\n });\r\nexport type Receipt = z.infer<typeof ReceiptSchema>;\r\nexport type UnsignedReceipt = Omit<Receipt, 'issuerSig'>;\r\n\r\nexport type BuildReceiptInput = {\r\n receiptId: string;\r\n channel: ReceiptChannel;\r\n intentId?: string;\r\n passRedemptionId?: string;\r\n payerUserId: string;\r\n payeeUserId: string;\r\n amountKobo: number;\r\n currency: string;\r\n issuedAtMs: number;\r\n issuerId: string;\r\n payload?: ReceiptPayload;\r\n};\r\n\r\nexport function buildReceipt(input: BuildReceiptInput): UnsignedReceipt {\r\n if (input.channel === 'cash') {\r\n if (!input.intentId) {\r\n throw new Error('cash receipts require intentId');\r\n }\r\n if (input.passRedemptionId) {\r\n throw new Error('cash receipts must not carry passRedemptionId');\r\n }\r\n } else {\r\n if (!input.passRedemptionId) {\r\n throw new Error('pass receipts require passRedemptionId');\r\n }\r\n if (input.intentId) {\r\n throw new Error('pass receipts must not carry intentId');\r\n }\r\n }\r\n const out: UnsignedReceipt = {\r\n receiptId: input.receiptId,\r\n channel: input.channel,\r\n payerUserId: input.payerUserId,\r\n payeeUserId: input.payeeUserId,\r\n amountKobo: input.amountKobo,\r\n currency: input.currency,\r\n issuedAtMs: input.issuedAtMs,\r\n issuerId: input.issuerId,\r\n payload: input.payload ?? {},\r\n };\r\n if (input.intentId) out.intentId = input.intentId;\r\n if (input.passRedemptionId) out.passRedemptionId = input.passRedemptionId;\r\n return out;\r\n}\r\n\r\nexport function signReceipt(\r\n unsigned: UnsignedReceipt,\r\n issuerPrivateKey: Uint8Array,\r\n): Receipt {\r\n const issuerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerPrivateKey,\r\n );\r\n return { ...unsigned, issuerSig };\r\n}\r\n\r\nexport function verifyReceipt(\r\n r: Receipt,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = ReceiptSchema.parse(r);\r\n const { issuerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","import {\r\n PassSchema,\r\n verifyPass as verifyPassFn,\r\n type Pass,\r\n type PassKind,\r\n type PassMetadata,\r\n type PassState,\r\n} from './pass.js';\r\nimport { RedemptionSchema, type Redemption } from './redemption.js';\r\nimport {\r\n ReceiptSchema,\r\n type ReceiptPayload,\r\n type Receipt,\r\n} from '../receipts/receipt.js';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\n// Re-export so existing `from \"./client.js\"` imports keep working.\r\nexport { FlurApiError };\r\n\r\nexport type PassesClientOptions = {\r\n baseUrl: string;\r\n /** Pre-configured fetch (typically `createHmacFetch(...)`). Falls back to global fetch. */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type IssuePassInput = {\r\n /** Device this pass is bound to. Required (BE-19). */\r\n holderDeviceId: string;\r\n /** P-256 SubjectPublicKeyInfo DER public key (base64) of the bound device. Required (BE-19). */\r\n holderDevicePubkey: string;\r\n /** Pass kind (server may default for templated flows). */\r\n kind: PassKind;\r\n /** Optional fixed amount for monetary passes (kobo). */\r\n amountKobo?: number;\r\n /** Optional cumulative spend cap in kobo across all redemptions. */\r\n cumulativeCapKobo?: number;\r\n validFromMs: number;\r\n validUntilMs: number;\r\n metadata?: PassMetadata;\r\n /** Optional template grouping id (server may emit one if omitted). */\r\n templateId?: string;\r\n /** Optional human-facing holder identity. */\r\n holderUserId?: string;\r\n /** Optional client-supplied id for idempotency / retries. */\r\n passId?: string;\r\n};\r\n\r\nexport type ListPassesInput = {\r\n holderDeviceId?: string;\r\n holderUserId?: string;\r\n state?: PassState;\r\n kind?: PassKind;\r\n templateId?: string;\r\n limit?: number;\r\n cursor?: string;\r\n};\r\n\r\nexport type ListPassesResponse = {\r\n items: Pass[];\r\n nextCursor: string | null;\r\n};\r\n\r\nexport type RevokePassInput = {\r\n reason: string;\r\n};\r\n\r\nexport type RedeemPassResponse = {\r\n pass: Pass;\r\n redemptionId: string;\r\n};\r\n\r\nexport type AtomicRedeemReceiptInput = {\r\n payeeUserId: string;\r\n payload?: ReceiptPayload;\r\n receiptId?: string;\r\n};\r\n\r\nexport type AtomicRedeemResponse = {\r\n pass: Pass;\r\n redemptionId: string;\r\n receipt: Receipt;\r\n};\r\n\r\nexport type PassesClient = {\r\n issuePass: (input: IssuePassInput) => Promise<Pass>;\r\n listPasses: (input: ListPassesInput) => Promise<ListPassesResponse>;\r\n getPass: (passId: string) => Promise<Pass>;\r\n redeemPassDetailed: (\r\n passId: string,\r\n redemption: Redemption,\r\n ) => Promise<RedeemPassResponse>;\r\n redeemPass: (passId: string, redemption: Redemption) => Promise<Pass>;\r\n redeemPassWithReceipt: (\r\n passId: string,\r\n redemption: Redemption,\r\n receipt: AtomicRedeemReceiptInput,\r\n ) => Promise<AtomicRedeemResponse>;\r\n revokePass: (passId: string, input: RevokePassInput) => Promise<Pass>;\r\n /** Local P-256 ECDSA verification of a pass envelope under the supplied issuer SPKI base64 key. */\r\n verifyPass: (pass: Pass, issuerPublicKeySpkiB64: string) => boolean;\r\n};\r\n\r\nexport function createPassesClient(opts: PassesClientOptions): PassesClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl)\r\n throw new Error('createPassesClient: no fetch implementation available');\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown = undefined;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON error body\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n (raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : undefined) ?? `http_${resp.status}`;\r\n const message =\r\n (raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : undefined) ?? `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n return {\r\n issuePass: (input) =>\r\n call('POST', '/v1/passes', input, (raw) => PassSchema.parse(raw)),\r\n\r\n listPasses: (input) => {\r\n const qs = new URLSearchParams();\r\n if (input.holderDeviceId) qs.set('holderDeviceId', input.holderDeviceId);\r\n if (input.holderUserId) qs.set('holderUserId', input.holderUserId);\r\n if (input.state) qs.set('state', input.state);\r\n if (input.kind) qs.set('kind', input.kind);\r\n if (input.templateId) qs.set('templateId', input.templateId);\r\n if (typeof input.limit === 'number') qs.set('limit', String(input.limit));\r\n if (input.cursor) qs.set('cursor', input.cursor);\r\n const path = `/v1/passes${qs.size > 0 ? `?${qs.toString()}` : ''}`;\r\n return call('GET', path, undefined, (raw) => {\r\n const obj = raw as { items?: unknown; nextCursor?: unknown };\r\n const items = (obj.items as unknown[]).map((it) =>\r\n PassSchema.parse(it),\r\n );\r\n const nextCursor =\r\n typeof obj.nextCursor === 'string' ? obj.nextCursor : null;\r\n return { items, nextCursor };\r\n });\r\n },\r\n\r\n getPass: (passId) =>\r\n call(\r\n 'GET',\r\n `/v1/passes/${encodeURIComponent(passId)}`,\r\n undefined,\r\n (raw) => PassSchema.parse(raw),\r\n ),\r\n\r\n redeemPass: (passId, redemption) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/redeem`,\r\n RedemptionSchema.parse(redemption),\r\n (raw) => {\r\n const obj = raw as { redemptionId?: unknown };\r\n return {\r\n pass: PassSchema.parse(raw),\r\n redemptionId:\r\n typeof obj.redemptionId === 'string' ? obj.redemptionId : '',\r\n };\r\n },\r\n ).then((result) => result.pass),\r\n\r\n redeemPassDetailed: (passId, redemption) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/redeem`,\r\n RedemptionSchema.parse(redemption),\r\n (raw) => {\r\n const obj = raw as { redemptionId?: unknown };\r\n return {\r\n pass: PassSchema.parse(raw),\r\n redemptionId:\r\n typeof obj.redemptionId === 'string' ? obj.redemptionId : '',\r\n };\r\n },\r\n ),\r\n\r\n redeemPassWithReceipt: (passId, redemption, receipt) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/redeem-with-receipt`,\r\n {\r\n redemption: RedemptionSchema.parse(redemption),\r\n receipt,\r\n },\r\n (raw) => {\r\n const obj = raw as {\r\n pass?: unknown;\r\n redemptionId?: unknown;\r\n receipt?: unknown;\r\n };\r\n return {\r\n pass: PassSchema.parse(obj.pass),\r\n redemptionId:\r\n typeof obj.redemptionId === 'string' ? obj.redemptionId : '',\r\n receipt: ReceiptSchema.parse(obj.receipt),\r\n };\r\n },\r\n ),\r\n\r\n revokePass: (passId, input) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/revoke`,\r\n input,\r\n (raw) => PassSchema.parse(raw),\r\n ),\r\n\r\n verifyPass: (pass, issuerPublicKey) => verifyPassFn(pass, issuerPublicKey),\r\n };\r\n}\r\n","import {\r\n ReceiptSchema,\r\n verifyReceipt as verifyReceiptFn,\r\n type Receipt,\r\n type ReceiptChannel,\r\n type ReceiptPayload,\r\n} from './receipt.js';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport type ReceiptsClientOptions = {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type IssueReceiptInput = {\r\n channel: ReceiptChannel;\r\n /** Required for cash channel; FK to send_intents.id. */\r\n intentId?: string;\r\n /** Required for pass channel; FK to pass_redemptions.id. */\r\n passRedemptionId?: string;\r\n payerUserId: string;\r\n payeeUserId: string;\r\n amountKobo: number;\r\n currency: string;\r\n payload?: ReceiptPayload;\r\n /** Optional client-supplied id for idempotency / retries. */\r\n receiptId?: string;\r\n};\r\n\r\nexport type ListReceiptsInput = {\r\n /** Filter by either side of the receipt. Server scopes by caller identity. */\r\n payerUserId?: string;\r\n payeeUserId?: string;\r\n channel?: ReceiptChannel;\r\n limit?: number;\r\n cursor?: string;\r\n};\r\n\r\nexport type ListReceiptsResponse = {\r\n items: Receipt[];\r\n nextCursor: string | null;\r\n};\r\n\r\nexport type ReceiptsClient = {\r\n issueReceipt: (input: IssueReceiptInput) => Promise<Receipt>;\r\n /** Alias of `getById`, matches addendum surface. */\r\n getReceipt: (receiptId: string) => Promise<Receipt>;\r\n getById: (receiptId: string) => Promise<Receipt>;\r\n /** Look up a cash-channel receipt by its originating intentId. */\r\n getByIntentId: (intentId: string) => Promise<Receipt>;\r\n /** Look up a pass-channel receipt by its originating passRedemptionId. */\r\n getByPassRedemptionId: (passRedemptionId: string) => Promise<Receipt>;\r\n listForUser: (input: ListReceiptsInput) => Promise<ListReceiptsResponse>;\r\n /** Local P-256 ECDSA verification of a receipt envelope under the supplied issuer SPKI base64 key. */\r\n verifyReceipt: (receipt: Receipt, issuerPublicKeySpkiB64: string) => boolean;\r\n};\r\n\r\nexport function createReceiptsClient(\r\n opts: ReceiptsClientOptions,\r\n): ReceiptsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl)\r\n throw new Error('createReceiptsClient: no fetch implementation available');\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown = undefined;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // ignore non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n const getById: ReceiptsClient['getById'] = (receiptId) =>\r\n call(\r\n 'GET',\r\n `/v1/receipts/${encodeURIComponent(receiptId)}`,\r\n undefined,\r\n (raw) => ReceiptSchema.parse(raw),\r\n );\r\n\r\n return {\r\n issueReceipt: (input) =>\r\n call('POST', '/v1/receipts', input, (raw) => ReceiptSchema.parse(raw)),\r\n\r\n getReceipt: getById,\r\n getById,\r\n\r\n getByIntentId: (intentId) =>\r\n call(\r\n 'GET',\r\n `/v1/receipts/by-intent/${encodeURIComponent(intentId)}`,\r\n undefined,\r\n (raw) => ReceiptSchema.parse(raw),\r\n ),\r\n\r\n getByPassRedemptionId: (passRedemptionId) =>\r\n call(\r\n 'GET',\r\n `/v1/receipts/by-pass-redemption/${encodeURIComponent(passRedemptionId)}`,\r\n undefined,\r\n (raw) => ReceiptSchema.parse(raw),\r\n ),\r\n\r\n listForUser: (input) => {\r\n const qs = new URLSearchParams();\r\n if (input.payerUserId) qs.set('payerUserId', input.payerUserId);\r\n if (input.payeeUserId) qs.set('payeeUserId', input.payeeUserId);\r\n if (input.channel) qs.set('channel', input.channel);\r\n if (typeof input.limit === 'number') qs.set('limit', String(input.limit));\r\n if (input.cursor) qs.set('cursor', input.cursor);\r\n const path = `/v1/receipts${qs.size > 0 ? `?${qs.toString()}` : ''}`;\r\n return call('GET', path, undefined, (raw) => {\r\n const obj = raw as { items?: unknown; nextCursor?: unknown };\r\n const items = (obj.items as unknown[]).map((it) =>\r\n ReceiptSchema.parse(it),\r\n );\r\n const nextCursor =\r\n typeof obj.nextCursor === 'string' ? obj.nextCursor : null;\r\n return { items, nextCursor };\r\n });\r\n },\r\n\r\n verifyReceipt: (receipt, issuerPublicKey) =>\r\n verifyReceiptFn(receipt, issuerPublicKey),\r\n };\r\n}\r\n","import {\r\n encodeNQR,\r\n parseNQR,\r\n type NQRPayloadInput,\r\n type ParsedNQR,\r\n} from '../nqr/index.js';\r\nimport { createFlurPartnerClient } from '../partner/index.js';\r\nimport type { PartnerScope } from '../partner/index.js';\r\nimport { createPassesClient, type PassesClient } from '../passes/index.js';\r\nimport {\r\n createReceiptsClient,\r\n type ReceiptsClient,\r\n} from '../receipts/index.js';\r\nimport {\r\n createPartnerCollectionsClient,\r\n type PartnerCollectionsClient,\r\n} from '../collections/index.js';\r\n\r\nexport type FlurInitOptions = {\r\n apiKey: string;\r\n apiSecret: string;\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n /** When true, all QR generation is performed locally without any network call. */\r\n offlineMode?: boolean;\r\n /** Optional scope claim forwarded as `X-Flur-Scope`. Backend credentials remain authoritative. */\r\n scope?: readonly PartnerScope[];\r\n};\r\n\r\nexport type FlurPaymentEvent = {\r\n type: string;\r\n reference?: string;\r\n [k: string]: unknown;\r\n};\r\n\r\nexport type SubscribeOptions = {\r\n reference: string;\r\n onEvent: (event: FlurPaymentEvent) => void;\r\n onError?: (err: unknown) => void;\r\n};\r\n\r\nexport function generateStaticQR(\r\n input: Omit<NQRPayloadInput, 'pointOfInitiation'>,\r\n): string {\r\n return encodeNQR({ ...input, pointOfInitiation: 'static' });\r\n}\r\n\r\nexport function generateDynamicQR(\r\n input: Omit<NQRPayloadInput, 'pointOfInitiation'>,\r\n): string {\r\n return encodeNQR({ ...input, pointOfInitiation: 'dynamic' });\r\n}\r\n\r\nexport function parseQR(payload: string): ParsedNQR {\r\n return parseNQR(payload);\r\n}\r\n\r\nexport type CashNamespace = {\r\n generateStaticQR: typeof generateStaticQR;\r\n generateDynamicQR: typeof generateDynamicQR;\r\n parseQR: typeof parseQR;\r\n subscribeToPayments: (opts: SubscribeOptions) => () => void;\r\n};\r\n\r\nexport type FlurHandle = CashNamespace & {\r\n /** Cash / money: NQR generation, payment subscriptions, transfers (future). */\r\n cash: CashNamespace;\r\n /** Collections: merchant NQR intents, reports, statements, payouts. */\r\n collections: PartnerCollectionsClient;\r\n /** Passes: tickets, vouchers, loyalty, transit. */\r\n passes: PassesClient;\r\n /** Receipts: signed, immutable views over cash + pass events. */\r\n receipts: ReceiptsClient;\r\n};\r\n\r\nexport function init(opts: FlurInitOptions): FlurHandle {\r\n const partner = createFlurPartnerClient({\r\n baseUrl: opts.baseUrl,\r\n keyId: opts.apiKey,\r\n secret: opts.apiSecret,\r\n fetchImpl: opts.fetchImpl,\r\n scope: opts.scope,\r\n });\r\n const signedFetch = partner.fetch;\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n function subscribeToPayments(s: SubscribeOptions) {\r\n let cancelled = false;\r\n\r\n queueMicrotask(() => {\r\n if (cancelled) return;\r\n s.onError?.(\r\n new Error(\r\n 'cash.subscribeToPayments is not available on this backend release; use collections reports or provider webhooks for payment status.',\r\n ),\r\n );\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }\r\n\r\n const cash: CashNamespace = {\r\n generateStaticQR,\r\n generateDynamicQR,\r\n parseQR,\r\n subscribeToPayments,\r\n };\r\n\r\n const passes = createPassesClient({ baseUrl, fetchImpl: signedFetch });\r\n const receipts = createReceiptsClient({ baseUrl, fetchImpl: signedFetch });\r\n const collections = createPartnerCollectionsClient({\r\n baseUrl,\r\n fetchImpl: signedFetch,\r\n });\r\n\r\n return {\r\n // top-level back-compat surface\r\n generateStaticQR,\r\n generateDynamicQR,\r\n parseQR,\r\n subscribeToPayments,\r\n // namespaces\r\n cash,\r\n collections,\r\n passes,\r\n receipts,\r\n };\r\n}\r\n","import { z } from 'zod';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport const ACCOUNT_TYPES = ['personal', 'business', 'partner'] as const;\r\nexport type AccountType = (typeof ACCOUNT_TYPES)[number];\r\n\r\nexport const ACCOUNT_STATUSES = ['active', 'suspended', 'closed'] as const;\r\nexport type AccountStatus = (typeof ACCOUNT_STATUSES)[number];\r\n\r\nexport const MEMBERSHIP_ROLES = ['owner', 'admin', 'driver', 'staff'] as const;\r\nexport type MembershipRole = (typeof MEMBERSHIP_ROLES)[number];\r\n\r\nexport const AccountSchema = z.object({\r\n accountId: z.string().uuid(),\r\n type: z.enum(ACCOUNT_TYPES),\r\n displayName: z.string().min(1),\r\n status: z.enum(ACCOUNT_STATUSES),\r\n ownerUserId: z.string().uuid().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type Account = z.infer<typeof AccountSchema>;\r\n\r\nexport const AccountMembershipSchema = z.object({\r\n accountId: z.string().uuid(),\r\n userId: z.string().uuid(),\r\n role: z.enum(MEMBERSHIP_ROLES),\r\n createdAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type AccountMembership = z.infer<typeof AccountMembershipSchema>;\r\n\r\nexport type AccountsClientOptions = {\r\n baseUrl: string;\r\n /** Pre-configured fetch (e.g. with a session bearer or partner HMAC). */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type CreateBusinessAccountInput = {\r\n displayName: string;\r\n type?: 'business' | 'partner';\r\n};\r\n\r\nexport type AddMemberInput = {\r\n userId: string;\r\n role: MembershipRole;\r\n};\r\n\r\nexport type AccountsClient = {\r\n listMyAccounts: () => Promise<{ items: Account[] }>;\r\n getAccount: (accountId: string) => Promise<Account>;\r\n listMembers: (accountId: string) => Promise<{ items: AccountMembership[] }>;\r\n createBusinessAccount: (\r\n input: CreateBusinessAccountInput,\r\n ) => Promise<Account>;\r\n addMember: (\r\n accountId: string,\r\n input: AddMemberInput,\r\n ) => Promise<AccountMembership>;\r\n};\r\n\r\nexport function createAccountsClient(\r\n opts: AccountsClientOptions,\r\n): AccountsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error('createAccountsClient: no fetch implementation available');\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown = undefined;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n const itemsSchema = z.object({ items: z.array(AccountSchema) });\r\n const memberItemsSchema = z.object({\r\n items: z.array(AccountMembershipSchema),\r\n });\r\n\r\n return {\r\n listMyAccounts: () =>\r\n call('GET', '/v1/accounts/me', undefined, (raw) =>\r\n itemsSchema.parse(raw),\r\n ),\r\n getAccount: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${encodeURIComponent(accountId)}`,\r\n undefined,\r\n (raw) => AccountSchema.parse(raw),\r\n ),\r\n listMembers: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/members`,\r\n undefined,\r\n (raw) => memberItemsSchema.parse(raw),\r\n ),\r\n createBusinessAccount: (input) =>\r\n call('POST', '/v1/accounts', input, (raw) => AccountSchema.parse(raw)),\r\n addMember: (accountId, input) =>\r\n call(\r\n 'POST',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/members`,\r\n input,\r\n (raw) => AccountMembershipSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n","/**\n * Consumer-side Offline Collect SDK client.\n *\n * Wraps the backend `/v1/me/offline/*` routes (session-bearer auth ONLY —\n * NOT partner HMAC). These power the payer authorization side of Flur Offline Collect:\n * - register/list/revoke device signing keys\n * - issue account-funded Offline Authorization Certificates (OACs)\n * - read offline status (active OAC)\n * - submit a signed offline collection claim for settlement\n *\n * Schemas mirror `flur-backend/src/offline-consumer/types.ts`.\n */\nimport { z } from 'zod';\nimport { FlurApiError } from '../errors.js';\nimport {\n SignedRevocationListSchema,\n type SignedRevocationList,\n} from './revocation.js';\n\n// ───────────────────────────── shared regex ─────────────────────────────\n\nconst Sha256Hex = z.string().regex(/^[0-9a-f]{64}$/);\nconst Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);\nconst ClaimNonce = z\n .string()\n .min(8)\n .max(128)\n .refine((value) => !value.includes('|'), {\n message: 'nonce must not contain |',\n });\n\n/**\n * Hard upper bound on an account-funded OAC's validity window (24h). The OAC\n * is a *rolling* 24h credential: a device that comes online at any point\n * proactively reissues a fresh 24h window, while a device that stays offline\n * beyond 24h loses spend authority (short TTL is the revocation-propagation\n * mechanism). The offline verifier rejects any window longer than this.\n */\nexport const ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1000 * 60 * 60 * 24;\n\n/**\n * Pinned issuer trust-bundle entry returned by `GET /v1/issuer/keys`. Devices\n * pin these public keys and verify unified OACs OFFLINE against them — never\n * against the key embedded in the credential. The shape is a superset of\n * `TrustedIssuerKey` so it can be passed straight to `verifyOacOffline`.\n */\nexport const IssuerTrustKeySchema = z.object({\n issuerId: z.string().min(1).max(128),\n alg: z.literal('p256'),\n publicKeySpkiB64: Base64Std.min(64).max(4096),\n notBeforeMs: z.number().int().nonnegative().optional(),\n notAfterMs: z.number().int().positive().optional(),\n});\nexport type IssuerTrustKey = z.infer<typeof IssuerTrustKeySchema>;\n\nexport const IssuerTrustBundleSchema = z.object({\n keys: z.array(IssuerTrustKeySchema).min(1),\n});\nexport type IssuerTrustBundle = z.infer<typeof IssuerTrustBundleSchema>;\n\n/**\n * Counterparty claim-submission grace after `oac.validUntilMs`. Claims\n * signed while the OAC was valid may still be relayed within this window\n * and the backend will settle them (cumulative cap and revocation still\n * apply). Mobile outbox / queue logic MUST honor this grace before pruning\n * a queued claim — otherwise legitimate offline payments are silently\n * dropped between OAC expiry and the backend grace boundary.\n *\n * Mirrors `CONSUMER_OFFLINE_DEFAULTS.claimSubmitGraceMs` in\n * `flur-backend/src/offline-consumer/service.ts`.\n */\nexport const CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1000 * 60 * 60 * 24;\n\n// ───────────────────────────── device key ─────────────────────────────\n\nexport const AttestationSecurityLevelSchema = z.enum([\n 'STRONGBOX',\n 'TEE',\n 'SECURE_ENCLAVE',\n 'SOFTWARE',\n]);\nexport type AttestationSecurityLevel = z.infer<\n typeof AttestationSecurityLevelSchema\n>;\n\nexport const DeviceKeyAlgSchema = z.literal('p256');\nexport type DeviceKeyAlg = z.infer<typeof DeviceKeyAlgSchema>;\n\nexport const RegisterDeviceKeyP256InputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n /** P-256 SubjectPublicKeyInfo DER, base64. */\n publicKeySpkiB64: Base64Std.min(64).max(4096),\n /** Base64 of the server-issued enrollment challenge string. */\n challengeB64: Base64Std.min(8).max(1024),\n /** iOS App Attest payload or Android X.509 Key Attestation chain. */\n attestationChainB64: z.array(Base64Std.min(16).max(16_384)).min(1).max(16),\n securityLevel: AttestationSecurityLevelSchema,\n});\nexport type RegisterDeviceKeyP256Input = z.infer<\n typeof RegisterDeviceKeyP256InputSchema\n>;\n\nexport const P256EnrollmentChallengeInputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n});\nexport type P256EnrollmentChallengeInput = z.infer<\n typeof P256EnrollmentChallengeInputSchema\n>;\n\nexport const P256EnrollmentChallengeResultSchema = z.object({\n challenge: z.string().min(16),\n expiresAtMs: z.number().int().positive(),\n});\nexport type P256EnrollmentChallengeResult = z.infer<\n typeof P256EnrollmentChallengeResultSchema\n>;\n\nexport const DeviceKeyRecordSchema = z.object({\n id: z.string().uuid(),\n userId: z.string().uuid(),\n deviceId: z.string(),\n /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */\n alg: DeviceKeyAlgSchema.default('p256'),\n /** P-256 SubjectPublicKeyInfo DER, base64. */\n publicKeySpkiB64: Base64Std.nullable().default(null),\n securityLevel: AttestationSecurityLevelSchema.nullable().default(null),\n hardwareBacked: z.boolean().default(false),\n attestedAtMs: z.number().int().nonnegative().nullable().default(null),\n createdAtMs: z.number().int().nonnegative(),\n revokedAtMs: z.number().int().nonnegative().nullable(),\n});\nexport type DeviceKeyRecord = z.infer<typeof DeviceKeyRecordSchema>;\n\n// ───────────────────────────── OAC ─────────────────────────────\n//\n// OAC v2 binds a P-256 hardware-backed device key. The consumer offline\n// rail is P-256 only.\nexport const ConsumerOACSchema = z.object({\n oacId: z.string().uuid(),\n issuerId: z.string().min(1).max(64),\n userId: z.string().uuid(),\n deviceId: z.string().min(1).max(128),\n /**\n * Always 'p256'. Required on the wire (backend always emits it).\n * Kept as a literal so input/output infer identically and the schema\n * can be nested inside other response shapes without Zod input/output\n * divergence under tsup DTS bundling.\n */\n alg: z.literal('p256'),\n /** P-256 SubjectPublicKeyInfo DER, base64. */\n devicePubkeySpkiB64: Base64Std.min(64).max(4096),\n /**\n * Per-transaction / cumulative offline spend ceilings. Zero is valid and\n * denotes an identity-only OAC: the credential proves who the holder is and\n * binds their device key for offline-verifiable first contact, but carries\n * no offline spend authority (every claim against it routes to REVIEW).\n * Issued to zero-balance wallets so they can still be paid offline.\n */\n perTxCapKobo: z.number().int().nonnegative(),\n cumulativeCapKobo: z.number().int().nonnegative(),\n currency: z.string().length(3),\n validFromMs: z.number().int().nonnegative(),\n validUntilMs: z.number().int().nonnegative(),\n counterSeed: z.number().int().nonnegative(),\n issuedAtMs: z.number().int().nonnegative(),\n /**\n * Issuer-attested identity folded into the OAC so a single signed\n * credential serves both Tier B offline-verifiable identity and offline\n * spend authority. Verified offline against a pinned issuer key; the\n * backend remains authoritative at settlement.\n */\n phoneE164: z.string().regex(/^\\+[1-9]\\d{7,14}$/),\n displayName: z.string().min(1).max(64),\n});\nexport type ConsumerOAC = z.infer<typeof ConsumerOACSchema>;\n\nexport const SignedConsumerOACSchema = z.object({\n oac: ConsumerOACSchema,\n /** ASN.1 DER ECDSA P-256 issuer signature, base64. */\n issuerSig: Base64Std.min(16).max(2048),\n /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */\n issuerPublicKeySpkiB64: Base64Std.min(64).max(4096),\n});\nexport type SignedConsumerOAC = z.infer<typeof SignedConsumerOACSchema>;\n\nexport const OACRecordSchema = SignedConsumerOACSchema.extend({\n currentOfflineSpentKobo: z.number().int().nonnegative(),\n status: z.enum(['active', 'superseded', 'expired', 'revoked']),\n supersededAtMs: z.number().int().nonnegative().nullable(),\n revokedAtMs: z.number().int().nonnegative().nullable(),\n});\nexport type OACRecord = z.infer<typeof OACRecordSchema>;\n\n/**\n * Inputs for issuing an account-funded OAC.\n *\n * Mirrors the backend `POST /v1/me/offline/oac` route. No funds are\n * pre-reserved; offline claims settle by debiting the payer's main\n * wallet at submission time via the canonical transfer primitive. Claims\n * signed during the OAC validity window may be submitted during the server's\n * bounded grace window; devices should refresh this credential when online.\n */\nexport const IssueAccountOacInputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n perTxCapKobo: z.number().int().positive().optional(),\n cumulativeCapKobo: z.number().int().positive().optional(),\n ttlMs: z\n .number()\n .int()\n .min(60_000)\n .max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS)\n .optional(),\n});\nexport type IssueAccountOacInput = z.infer<typeof IssueAccountOacInputSchema>;\n\n// ───────────────────────────── status ─────────────────────────────\n\nexport const OfflineStatusResultSchema = z.object({\n active: OACRecordSchema.nullable(),\n});\nexport type OfflineStatusResult = z.infer<typeof OfflineStatusResultSchema>;\n\n// ───────────────────────────── payment claim ─────────────────────────────\n//\n// The consumer offline payment rail is P-256 ONLY. Device signatures are\n// produced by `flur-secure-signer` (iOS Secure Enclave / Android StrongBox)\n// over the canonical bytes built by `canonicalClaimSigningBytes`\n// (domain `flur:consumer-offline:v2:claim`). Backend verification is shared\n// via `verifyClaimSignature` from `@nokinc-flur/sdk`.\n//\n// Wire format:\n// - publicKey: SubjectPublicKeyInfo DER, base64.\n// - signature: ASN.1 DER ECDSA signature, base64.\n//\n// Legacy ed25519 claims are no longer accepted at this boundary.\n\nexport const ConsumerPaymentClaimSchema = z.object({\n /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */\n alg: z.literal('p256').default('p256'),\n oacId: z.string().uuid(),\n encounterId: Sha256Hex.optional(),\n payerUserId: z.string().uuid(),\n payeeUserId: z.string().uuid(),\n payerDeviceId: z.string().min(1).max(128),\n payerNonce: ClaimNonce,\n payeeNonce: ClaimNonce,\n amountKobo: z.number().int().positive(),\n currency: z.string().length(3).default('NGN'),\n occurredAtMs: z.number().int().nonnegative(),\n completedAtMs: z.number().int().nonnegative().optional(),\n contextId: z.string().max(128).optional(),\n\n requestId: z.string().uuid().optional(),\n requestMode: z.enum(['fixed', 'editable']).optional(),\n requestTakerUserId: z.string().uuid().optional(),\n requestAmountKobo: z.number().int().positive().optional(),\n requestCurrency: z.string().length(3).optional(),\n requestReference: z.string().max(128).nullable().optional(),\n requestCreatedAtMs: z.number().int().nonnegative().optional(),\n requestExpiresAtMs: z.number().int().positive().optional(),\n requestNonce: z.string().min(8).max(128).optional(),\n requestTakerDeviceId: z.string().min(1).max(128).nullable().optional(),\n requestTakerPubkeySpkiB64: Base64Std.min(64).max(4096).optional(),\n requestTakerSignatureDerB64: Base64Std.min(16).max(2048).optional(),\n\n payerPubkeySpkiB64: Base64Std.min(64).max(4096),\n payerSignatureDerB64: Base64Std.min(16).max(2048),\n payeePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),\n payeeSignatureDerB64: Base64Std.min(16).max(2048).optional(),\n});\nexport type ConsumerPaymentClaim = z.infer<typeof ConsumerPaymentClaimSchema>;\n\nexport const ConsumerSettlementSchema = z.object({\n settlementId: z.string().uuid(),\n settlementKey: Sha256Hex,\n encounterId: Sha256Hex,\n oacId: z.string().uuid(),\n payerUserId: z.string().uuid(),\n payeeUserId: z.string().uuid(),\n amountKobo: z.number().int().positive(),\n currency: z.string().length(3),\n status: z.enum(['SETTLED', 'REVIEW']),\n reviewReason: z.string().nullable(),\n ledgerRef: z.string().nullable(),\n /** ASN.1 DER ECDSA P-256 issuer signature, base64. */\n issuerSig: Base64Std.min(16).max(2048),\n /** Canonical millisecond timestamp signed into the settlement receipt. */\n issuedAtMs: z.number().int().nonnegative(),\n /** Compatibility alias for API consumers that predate issuedAtMs. */\n createdAtMs: z.number().int().nonnegative().optional(),\n});\nexport type ConsumerSettlement = z.infer<typeof ConsumerSettlementSchema>;\n\nexport const ConsumerSettleResultSchema = z.object({\n settlement: ConsumerSettlementSchema,\n encounterId: Sha256Hex,\n replayed: z.boolean(),\n});\nexport type ConsumerSettleResult = z.infer<typeof ConsumerSettleResultSchema>;\n\n// ───────────────────────────── revoke ─────────────────────────────\n\nexport const RevokeDeviceKeyInputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */\n sendAuthToken: z.string().min(16),\n});\nexport type RevokeDeviceKeyInput = z.infer<typeof RevokeDeviceKeyInputSchema>;\n\n// ───────────────────────────── client ─────────────────────────────\n\nexport type MeOfflineClientOptions = {\n baseUrl: string;\n /** Pre-configured fetch (session bearer attached upstream). */\n fetchImpl?: typeof fetch;\n};\n\nexport type MeOfflineClient = {\n issueP256EnrollmentChallenge: (\n input: P256EnrollmentChallengeInput,\n ) => Promise<P256EnrollmentChallengeResult>;\n registerDeviceKeyP256: (\n input: RegisterDeviceKeyP256Input,\n ) => Promise<DeviceKeyRecord>;\n listDeviceKeys: () => Promise<{ items: DeviceKeyRecord[] }>;\n revokeDeviceKey: (input: RevokeDeviceKeyInput) => Promise<void>;\n /** Issue an account-funded OAC for this device. */\n issueAccountOac: (input: IssueAccountOacInput) => Promise<OACRecord>;\n getStatus: (deviceId?: string) => Promise<OfflineStatusResult>;\n submitClaim: (claim: ConsumerPaymentClaim) => Promise<ConsumerSettleResult>;\n getSettlement: (idOrKey: string) => Promise<ConsumerSettlement>;\n /** Fetch the public pinned issuer trust bundle (`GET /v1/issuer/keys`). */\n getIssuerKeys: () => Promise<IssuerTrustBundle>;\n /**\n * Fetch the issuer-signed OAC revocation status-list\n * (`GET /v1/issuer/revocations`). Pinned and checked offline alongside the\n * issuer trust bundle to bound the revocation window below the OAC TTL.\n */\n getRevocations: () => Promise<SignedRevocationList>;\n};\n\nexport function createMeOfflineClient(\n opts: MeOfflineClientOptions,\n): MeOfflineClient {\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new Error('createMeOfflineClient: no fetch implementation available');\n }\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\n\n async function call<T>(\n method: string,\n path: string,\n body: unknown,\n parser: (raw: unknown) => T,\n ): Promise<T> {\n const init: RequestInit = {\n method,\n headers: {\n 'content-type': 'application/json',\n accept: 'application/json',\n },\n };\n if (body !== undefined) init.body = JSON.stringify(body);\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\n const text = await resp.text();\n let raw: unknown = undefined;\n if (text) {\n try {\n raw = JSON.parse(text);\n } catch {\n // non-JSON\n }\n }\n if (!resp.ok) {\n const code =\n raw &&\n typeof raw === 'object' &&\n 'code' in raw &&\n typeof (raw as { code: unknown }).code === 'string'\n ? (raw as { code: string }).code\n : `http_${resp.status}`;\n const message =\n raw &&\n typeof raw === 'object' &&\n 'message' in raw &&\n typeof (raw as { message: unknown }).message === 'string'\n ? (raw as { message: string }).message\n : `request failed with status ${resp.status}`;\n throw new FlurApiError(resp.status, code, message, raw);\n }\n return parser(raw);\n }\n\n const deviceKeyItems = z.object({ items: z.array(DeviceKeyRecordSchema) });\n\n return {\n issueP256EnrollmentChallenge: (input) =>\n call(\n 'POST',\n '/v1/me/offline/keys/p256/challenge',\n P256EnrollmentChallengeInputSchema.parse(input),\n (raw) => P256EnrollmentChallengeResultSchema.parse(raw),\n ),\n registerDeviceKeyP256: (input) =>\n call(\n 'POST',\n '/v1/me/offline/keys/p256',\n RegisterDeviceKeyP256InputSchema.parse(input),\n (raw) => DeviceKeyRecordSchema.parse(raw),\n ),\n listDeviceKeys: () =>\n call('GET', '/v1/me/offline/keys', undefined, (raw) =>\n deviceKeyItems.parse(raw),\n ),\n revokeDeviceKey: (input) =>\n call(\n 'POST',\n '/v1/me/offline/keys/revoke',\n RevokeDeviceKeyInputSchema.parse(input),\n () => undefined,\n ),\n issueAccountOac: (input) =>\n call(\n 'POST',\n '/v1/me/offline/oac',\n IssueAccountOacInputSchema.parse(input),\n (raw) => OACRecordSchema.parse(raw),\n ),\n getStatus: (deviceId) => {\n const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : '';\n return call('GET', `/v1/me/offline/status${qs}`, undefined, (raw) =>\n OfflineStatusResultSchema.parse(raw),\n );\n },\n submitClaim: (claim) =>\n call(\n 'POST',\n '/v1/me/offline/claims',\n ConsumerPaymentClaimSchema.parse(claim),\n (raw) => ConsumerSettleResultSchema.parse(raw),\n ),\n getSettlement: (idOrKey) =>\n call(\n 'GET',\n `/v1/me/offline/settlements/${encodeURIComponent(idOrKey)}`,\n undefined,\n (raw) => ConsumerSettlementSchema.parse(raw),\n ),\n getIssuerKeys: () =>\n call('GET', '/v1/issuer/keys', undefined, (raw) =>\n IssuerTrustBundleSchema.parse(raw),\n ),\n getRevocations: () =>\n call('GET', '/v1/issuer/revocations', undefined, (raw) =>\n SignedRevocationListSchema.parse(raw),\n ),\n };\n}\n","/**\n * OAC revocation status-list — offline verification.\n *\n * Short OAC TTL (24h, rolling) is the BASELINE revocation-propagation\n * mechanism: a revoked user cannot refresh, so their credential lapses within\n * the issuance window. The revocation status-list shrinks that window from\n * \"up to 24h\" to \"time since the device last pinned a fresh list\": the issuer\n * publishes a signed list of OAC IDs that are revoked AND not yet expired, and\n * the offline verifier rejects any scanned OAC whose id appears in it.\n *\n * The list is naturally bounded: an OAC that lapses on its own TTL drops off\n * the list (expiry already covers it), so the published set only ever carries\n * revocations from roughly the last 24h.\n *\n * Trust model mirrors the OAC itself: the list is issuer-signed and verified\n * OFFLINE against the SAME pinned issuer trust bundle (`GET /v1/issuer/keys`),\n * never the key embedded in the payload. A `sequence` makes the list\n * monotonic so a device never accepts an older snapshot over a newer one.\n */\nimport { z } from 'zod';\n\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { verifyIssuerP256 } from '../crypto/p256-issuer.js';\nimport type { TrustedIssuerKey } from './oac.js';\n\nconst Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);\n\n/**\n * Domain tag bound into the revocation-list issuer signature. MUST match\n * `REVOCATION_DOMAIN` in `flur-backend/src/offline-consumer/service.ts`.\n */\nexport const CONSUMER_REVOCATION_DOMAIN =\n 'flur:consumer-offline:v1:revocation' as const;\n\n/**\n * Hard cap on the number of revoked ids in a single list. Because the list\n * only carries unexpired revocations (~24h window), this bounds the payload\n * while comfortably exceeding any realistic revocation rate.\n */\nexport const REVOCATION_LIST_MAX_ENTRIES = 100_000;\n\nexport const RevocationListSchema = z.object({\n issuerId: z.string().min(1).max(64),\n /**\n * Monotonic snapshot counter. A device MUST NOT replace a pinned list with\n * one carrying a lower sequence — this defeats a downgrade/rollback attack\n * that replays an older list to resurrect a revoked credential.\n */\n sequence: z.number().int().nonnegative(),\n issuedAtMs: z.number().int().nonnegative(),\n /**\n * Freshness bound. After this instant the list is considered stale and the\n * verifier treats it as untrustworthy (fail-closed), forcing a re-pin.\n * Optional so the issuer may publish a list without a hard expiry.\n */\n notAfterMs: z.number().int().positive().optional(),\n /** OAC ids that are revoked AND not yet past their own validity window. */\n revokedOacIds: z.array(z.string().uuid()).max(REVOCATION_LIST_MAX_ENTRIES),\n});\nexport type RevocationList = z.infer<typeof RevocationListSchema>;\n\nexport const SignedRevocationListSchema = z.object({\n list: RevocationListSchema,\n /** ASN.1 DER ECDSA P-256 issuer signature over the signing payload, base64. */\n issuerSig: Base64Std.min(16).max(2048),\n /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */\n issuerPublicKeySpkiB64: Base64Std.min(64).max(4096),\n});\nexport type SignedRevocationList = z.infer<typeof SignedRevocationListSchema>;\n\nexport type VerifyRevocationListResult =\n | { ok: true; list: RevocationList; revokedOacIds: ReadonlySet<string> }\n | {\n ok: false;\n reason: 'malformed' | 'untrusted_issuer' | 'signature_invalid' | 'stale';\n };\n\nexport interface VerifyRevocationListOptions {\n /** Override the wall clock; defaults to `Date.now()`. */\n nowMs?: number;\n}\n\n/**\n * Canonical revocation-list payload (domain-bound) the issuer signs.\n *\n * Cross-implementation contract (MUST match the backend signer byte-for-byte):\n * optional fields with no value are OMITTED from the signed object, never\n * emitted as `null` or `undefined`. `canonicalJSONBytes` rejects `undefined`\n * object values outright, so building the payload explicitly (rather than\n * spreading a `list` that may carry an explicit `notAfterMs: undefined`) keeps\n * verification total — it can never throw on a well-typed list — and keeps the\n * signed bytes identical whether `notAfterMs` was absent or explicitly unset.\n */\nexport function revocationListSigningPayload(\n list: RevocationList,\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n domain: CONSUMER_REVOCATION_DOMAIN,\n issuerId: list.issuerId,\n sequence: list.sequence,\n issuedAtMs: list.issuedAtMs,\n revokedOacIds: list.revokedOacIds,\n };\n if (list.notAfterMs !== undefined) payload.notAfterMs = list.notAfterMs;\n return payload;\n}\n\n/**\n * Verify a signed revocation list offline against pinned issuer keys.\n *\n * Security invariants (identical to `verifyOacOffline`):\n * - The signature is checked against the PINNED key for `list.issuerId`,\n * never the payload-embedded key.\n * - The pinned key's own validity window is enforced.\n * - A list past `notAfterMs` fails closed (`stale`) so a long-offline device\n * cannot keep trusting a frozen snapshot forever.\n *\n * Note: rollback protection via `sequence` is intentionally NOT enforced here\n * (verification is stateless). The caller persisting the pinned list MUST\n * reject any replacement whose `sequence` is lower than the pinned one.\n */\nexport function verifyRevocationList(\n signed: SignedRevocationList,\n trustedKeys: readonly TrustedIssuerKey[],\n options: VerifyRevocationListOptions = {},\n): VerifyRevocationListResult {\n const parsed = SignedRevocationListSchema.safeParse(signed);\n if (!parsed.success) return { ok: false, reason: 'malformed' };\n const list = parsed.data.list;\n const nowMs = options.nowMs ?? Date.now();\n\n const pinned = trustedKeys.filter(\n (k) =>\n k.issuerId === list.issuerId &&\n (k.notBeforeMs === undefined || nowMs >= k.notBeforeMs) &&\n (k.notAfterMs === undefined || nowMs <= k.notAfterMs),\n );\n if (pinned.length === 0) return { ok: false, reason: 'untrusted_issuer' };\n\n const signingBytes = canonicalJSONBytes(revocationListSigningPayload(list));\n const signatureOk = pinned.some((k) =>\n verifyIssuerP256(signingBytes, parsed.data.issuerSig, k.publicKeySpkiB64),\n );\n if (!signatureOk) return { ok: false, reason: 'signature_invalid' };\n\n if (list.notAfterMs !== undefined && nowMs > list.notAfterMs) {\n return { ok: false, reason: 'stale' };\n }\n\n return { ok: true, list, revokedOacIds: new Set(list.revokedOacIds) };\n}\n\n/** True iff `oacId` appears in a verified revocation set. */\nexport function isOacRevoked(\n oacId: string,\n revokedOacIds: ReadonlySet<string>,\n): boolean {\n return revokedOacIds.has(oacId);\n}\n","/**\n * Offline-claim signer abstraction for Flur.\n *\n * Why this exists:\n * - Mobile clients sign payment claims with a hardware-backed P-256 key\n * (iOS Secure Enclave / Android Keystore StrongBox). Native modules\n * implement that custody, not this file.\n * - Server-side partners, test harnesses, and custodied integrators need a\n * *software* P-256 signer with the same surface so the SDK contract is\n * uniform.\n * - Both producers and verifiers (consumer mobile, partner backend, Flur\n * backend) must agree byte-for-byte on what gets signed. That's the job\n * of `canonicalClaimSigningPayload` / `canonicalClaimSigningBytes`.\n *\n * Wire format (P-256, hardware-backed):\n * - Public key: SubjectPublicKeyInfo DER, base64. Same format the\n * Apple/Android native modules return.\n * - Signature: ASN.1 DER ECDSA(SHA-256) signature, base64.\n *\n * Domain separation:\n * - V2 payload binds `alg='p256'` and is tagged with `CLAIM_DOMAIN_V2`.\n * The legacy ed25519 V1 path has been removed; the migration to P-256\n * is final.\n */\n\nimport { p256 } from '@noble/curves/nist';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\n\n// ─────────────────────────── domain ───────────────────────────\n\n/**\n * V2 canonical claim domain. Must match the backend's V2 verifier exactly.\n * Bumped from `flur:consumer-offline:v1:claim` so a payer's V2 hardware\n * signature is non-replayable against a legacy V1 verifier and vice-versa.\n */\nexport const CLAIM_DOMAIN_V2 = 'flur:consumer-offline:v2:claim' as const;\nconst ENCOUNTER_DOMAIN = 'flur:consumer-offline:v1:encounter';\n\n// ─────────────────────────── types ───────────────────────────\n\nexport type OfflineClaimAlgorithm = 'p256';\n\n/**\n * Inputs the SDK accepts to build canonical signing bytes.\n *\n * Optional fields default to `null` inside the canonical payload, so callers\n * that omit them still produce stable, deterministic bytes.\n */\nexport interface CanonicalClaimInput {\n alg: OfflineClaimAlgorithm;\n oacId: string;\n payerUserId: string;\n payeeUserId: string;\n payerDeviceId: string;\n payerNonce: string;\n payeeNonce: string;\n amountKobo: number;\n currency: string;\n occurredAtMs: number;\n completedAtMs?: number | null;\n contextId?: string | null;\n}\n\n/** Public key + signature pair from a signer. */\nexport interface SignerPublicKey {\n alg: OfflineClaimAlgorithm;\n /** SubjectPublicKeyInfo DER, base64. */\n publicKey: string;\n}\n\nexport interface ClaimSignature {\n alg: OfflineClaimAlgorithm;\n /** ASN.1 DER ECDSA(SHA-256) signature, base64. */\n signature: string;\n}\n\n/** Abstract signer interface. Software and native impls both honour this. */\nexport interface OfflineClaimSigner {\n readonly alg: OfflineClaimAlgorithm;\n getPublicKey(): Promise<SignerPublicKey>;\n sign(bytes: Uint8Array): Promise<ClaimSignature>;\n}\n\n// ─────────────────────────── canonical payload ───────────────────────────\n\n/**\n * The exact object that gets canonical-JSON-encoded and signed.\n *\n * Key ordering doesn't matter for the *output* because `canonicalJSONBytes`\n * sorts keys lexicographically — but the field SET and value normalization\n * must match the backend verifier byte-for-byte. Treat this function as the\n * cryptographic contract.\n */\nexport function canonicalClaimSigningPayload(claim: CanonicalClaimInput): {\n domain: typeof CLAIM_DOMAIN_V2;\n alg: OfflineClaimAlgorithm;\n oacId: string;\n payerUserId: string;\n payeeUserId: string;\n payerDeviceId: string;\n payerNonce: string;\n payeeNonce: string;\n amountKobo: number;\n currency: string;\n occurredAtMs: number;\n completedAtMs: number | null;\n contextId: string | null;\n} {\n return {\n domain: CLAIM_DOMAIN_V2,\n alg: claim.alg,\n oacId: claim.oacId,\n payerUserId: claim.payerUserId,\n payeeUserId: claim.payeeUserId,\n payerDeviceId: claim.payerDeviceId,\n payerNonce: claim.payerNonce,\n payeeNonce: claim.payeeNonce,\n amountKobo: claim.amountKobo,\n currency: claim.currency,\n occurredAtMs: claim.occurredAtMs,\n completedAtMs: claim.completedAtMs ?? null,\n contextId: claim.contextId ?? null,\n };\n}\n\n/** Bytes the signer must operate on. */\nexport function canonicalClaimSigningBytes(\n claim: CanonicalClaimInput,\n): Uint8Array {\n return canonicalJSONBytes(canonicalClaimSigningPayload(claim));\n}\n\n/** Deterministic encounter id used by backend settlement dedupe. */\nexport function computeConsumerClaimEncounterId(input: {\n oacId: string;\n payerUserId: string;\n payeeUserId: string;\n payerNonce: string;\n payeeNonce: string;\n}): string {\n const material = `${ENCOUNTER_DOMAIN}|${[\n assertEncounterPart('oacId', input.oacId),\n assertEncounterPart('payerUserId', input.payerUserId),\n assertEncounterPart('payeeUserId', input.payeeUserId),\n assertEncounterPart('payerNonce', input.payerNonce),\n assertEncounterPart('payeeNonce', input.payeeNonce),\n ].join('|')}`;\n return bytesToHex(sha256(new TextEncoder().encode(material)));\n}\n\nfunction assertEncounterPart(field: string, value: string): string {\n if (value.includes('|')) {\n throw new Error(`consumer encounter id ${field} must not contain |`);\n }\n return value;\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let out = '';\n for (const byte of bytes) out += byte.toString(16).padStart(2, '0');\n return out;\n}\n\n// ─────────────────────────── base64 ───────────────────────────\n//\n// Tiny base64 helpers that work in Node 18+ and all browsers without\n// pulling a new dep. We only need standard (not URL-safe) base64.\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n let bin = '';\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]!);\n // btoa is available in browsers and Node ≥ 16.\n return btoa(bin);\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(b64, 'base64'));\n }\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n// ─────────────────────────── P-256 SPKI helpers ───────────────────────────\n//\n// @noble/curves emits the raw X9.62 uncompressed point (0x04 || X || Y, 65\n// bytes). The backend ingests SubjectPublicKeyInfo DER (the same wrapper the\n// Android Keystore and iOS Secure Enclave native modules return). We wrap\n// and unwrap with the fixed P-256 SPKI header so the wire format is uniform\n// regardless of which signer produced it.\n\nconst P256_SPKI_HEADER = new Uint8Array([\n 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,\n 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,\n]);\n\nfunction p256PublicKeyToSpkiB64(rawUncompressed: Uint8Array): string {\n if (rawUncompressed.length !== 65 || rawUncompressed[0] !== 0x04) {\n throw new Error('p256: expected 65-byte uncompressed point');\n }\n const out = new Uint8Array(P256_SPKI_HEADER.length + rawUncompressed.length);\n out.set(P256_SPKI_HEADER, 0);\n out.set(rawUncompressed, P256_SPKI_HEADER.length);\n return bytesToBase64(out);\n}\n\nfunction p256SpkiB64ToPublicKey(spkiB64: string): Uint8Array {\n const spki = base64ToBytes(spkiB64);\n // Validate the header (cheap correctness check; full ASN.1 parse not needed\n // for a fixed key type).\n if (spki.length !== P256_SPKI_HEADER.length + 65) {\n throw new Error('p256: invalid SPKI length');\n }\n for (let i = 0; i < P256_SPKI_HEADER.length; i++) {\n if (spki[i] !== P256_SPKI_HEADER[i]) {\n throw new Error('p256: invalid SPKI header');\n }\n }\n return spki.slice(P256_SPKI_HEADER.length);\n}\n\n// ─────────────────────────── software signer ───────────────────────────\n\n/**\n * Software P-256 signer. Useful for:\n * - test harnesses\n * - Node integrators that issue claims server-side (custodied wallets)\n * - simulators where Secure Enclave / StrongBox is unavailable\n *\n * The hardware-backed equivalent (mobile) implements the same interface\n * but defers key storage and signing to the OS secure element.\n */\nexport function createSoftwareP256Signer(\n privateKey: Uint8Array,\n): OfflineClaimSigner {\n // Uncompressed point: 0x04 || X(32) || Y(32) — matches what Apple/Android\n // raw public-key APIs emit before SPKI wrapping.\n const raw = p256.getPublicKey(privateKey, false);\n const spkiB64 = p256PublicKeyToSpkiB64(raw);\n\n return {\n alg: 'p256',\n async getPublicKey() {\n return { alg: 'p256', publicKey: spkiB64 };\n },\n async sign(bytes: Uint8Array) {\n // The backend (and the native modules) compute SHA-256 internally; for\n // wire interop we sign the SHA-256 hash of the canonical bytes here.\n // `prehash: true` keeps that pattern consistent across software and\n // hardware paths.\n const sig = p256.sign(bytes, privateKey, { prehash: true });\n // ECDSA DER encoding — the Apple/Android native signers also return\n // DER, so the wire format is identical regardless of producer.\n const der = sig.toBytes('der');\n return { alg: 'p256', signature: bytesToBase64(der) };\n },\n };\n}\n\n// ─────────────────────────── verification ───────────────────────────\n\nexport interface VerifyClaimSignatureInput {\n alg: OfflineClaimAlgorithm;\n bytes: Uint8Array;\n signature: string;\n publicKey: string;\n}\n\n/**\n * Verifier the backend, partners, and self-checks all share. Returns a plain\n * boolean — callers should treat `false` and thrown errors uniformly as\n * \"not authenticated\".\n */\nexport function verifyClaimSignature(\n input: VerifyClaimSignatureInput,\n): boolean {\n try {\n if (input.alg !== 'p256') return false;\n const sigDer = base64ToBytes(input.signature);\n const pub = p256SpkiB64ToPublicKey(input.publicKey);\n return p256.verify(sigDer, input.bytes, pub, {\n prehash: true,\n format: 'der',\n });\n } catch {\n return false;\n }\n}\n","import { z } from 'zod';\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { type OfflineClaimSigner, verifyClaimSignature } from './signer.js';\n\nconst Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);\n\nexport const CONSUMER_PAYMENT_REQUEST_DOMAIN =\n 'flur:consumer-offline:v1:request' as const;\n\nexport const ConsumerPaymentRequestEnvelopeSchema = z\n .object({\n requestId: z.string().uuid(),\n mode: z.enum(['fixed', 'editable']),\n takerUserId: z.string().uuid(),\n amountKobo: z.number().int().positive(),\n currency: z.string().length(3).default('NGN'),\n reference: z.string().max(128).nullable().default(null),\n createdAtMs: z.number().int().nonnegative(),\n expiresAtMs: z.number().int().positive(),\n nonce: z.string().min(8).max(128),\n takerDeviceId: z.string().min(1).max(128).nullable().default(null),\n takerPubkeySpkiB64: Base64Std.min(64).max(4096).optional(),\n takerSignatureDerB64: Base64Std.min(16).max(2048).optional(),\n })\n .superRefine((value, ctx) => {\n if (value.expiresAtMs <= value.createdAtMs) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['expiresAtMs'],\n message: 'expiresAtMs must be greater than createdAtMs',\n });\n }\n const hasSignature = Boolean(\n value.takerPubkeySpkiB64 || value.takerSignatureDerB64,\n );\n if (value.mode === 'fixed' || hasSignature) {\n if (!value.takerDeviceId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['takerDeviceId'],\n message: 'signed requests require takerDeviceId',\n });\n }\n if (!value.takerPubkeySpkiB64) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['takerPubkeySpkiB64'],\n message: 'signed requests require takerPubkeySpkiB64',\n });\n }\n if (!value.takerSignatureDerB64) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['takerSignatureDerB64'],\n message: 'signed requests require takerSignatureDerB64',\n });\n }\n }\n });\n\nexport type ConsumerPaymentRequestEnvelope = z.infer<\n typeof ConsumerPaymentRequestEnvelopeSchema\n>;\n\nexport type UnsignedConsumerPaymentRequest = Omit<\n ConsumerPaymentRequestEnvelope,\n 'takerPubkeySpkiB64' | 'takerSignatureDerB64'\n>;\n\nexport function buildConsumerPaymentRequest(input: {\n requestId: string;\n mode: 'fixed' | 'editable';\n takerUserId: string;\n amountKobo: number;\n currency?: string;\n reference?: string | null;\n createdAtMs: number;\n expiresAtMs: number;\n nonce: string;\n takerDeviceId?: string | null;\n}): UnsignedConsumerPaymentRequest {\n const unsigned = {\n requestId: input.requestId,\n mode: input.mode,\n takerUserId: input.takerUserId,\n amountKobo: input.amountKobo,\n currency: input.currency ?? 'NGN',\n reference: input.reference ?? null,\n createdAtMs: input.createdAtMs,\n expiresAtMs: input.expiresAtMs,\n nonce: input.nonce,\n takerDeviceId: input.takerDeviceId ?? null,\n };\n if (unsigned.mode === 'fixed' && !unsigned.takerDeviceId) {\n throw new Error('fixed requests require takerDeviceId');\n }\n if (unsigned.expiresAtMs <= unsigned.createdAtMs) {\n throw new Error('expiresAtMs must be greater than createdAtMs');\n }\n return unsigned;\n}\n\nexport function consumerPaymentRequestSigningPayload(\n request: UnsignedConsumerPaymentRequest | ConsumerPaymentRequestEnvelope,\n) {\n return {\n domain: CONSUMER_PAYMENT_REQUEST_DOMAIN,\n version: 1,\n requestId: request.requestId,\n mode: request.mode,\n takerUserId: request.takerUserId,\n amountKobo: request.amountKobo,\n currency: request.currency,\n reference: request.reference ?? null,\n createdAtMs: request.createdAtMs,\n expiresAtMs: request.expiresAtMs,\n nonce: request.nonce,\n takerDeviceId: request.takerDeviceId ?? null,\n };\n}\n\nexport function consumerPaymentRequestSigningBytes(\n request: UnsignedConsumerPaymentRequest | ConsumerPaymentRequestEnvelope,\n): Uint8Array {\n return canonicalJSONBytes(consumerPaymentRequestSigningPayload(request));\n}\n\nexport async function signConsumerPaymentRequest(\n unsigned: UnsignedConsumerPaymentRequest,\n signer: OfflineClaimSigner,\n): Promise<ConsumerPaymentRequestEnvelope> {\n if (signer.alg !== 'p256') {\n throw new Error('consumer payment requests require p256 signer');\n }\n const publicKey = await signer.getPublicKey();\n if (publicKey.alg !== 'p256') {\n throw new Error('consumer payment requests require p256 public key');\n }\n const signature = await signer.sign(\n consumerPaymentRequestSigningBytes(unsigned),\n );\n return ConsumerPaymentRequestEnvelopeSchema.parse({\n ...unsigned,\n takerPubkeySpkiB64: publicKey.publicKey,\n takerSignatureDerB64: signature.signature,\n });\n}\n\nexport function verifyConsumerPaymentRequest(\n request: ConsumerPaymentRequestEnvelope,\n): boolean {\n const parsed = ConsumerPaymentRequestEnvelopeSchema.safeParse(request);\n if (!parsed.success) return false;\n const value = parsed.data;\n if (!value.takerPubkeySpkiB64 || !value.takerSignatureDerB64) return false;\n return verifyClaimSignature({\n alg: 'p256',\n bytes: consumerPaymentRequestSigningBytes(value),\n signature: value.takerSignatureDerB64,\n publicKey: value.takerPubkeySpkiB64,\n });\n}\n\nexport function isConsumerPaymentRequestExpired(\n request: ConsumerPaymentRequestEnvelope,\n nowMs = Date.now(),\n): boolean {\n const parsed = ConsumerPaymentRequestEnvelopeSchema.parse(request);\n return parsed.expiresAtMs <= nowMs;\n}\n","import { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { verifyIssuerP256 } from '../crypto/p256-issuer.js';\nimport { ConsumerSettlementSchema, type ConsumerSettlement } from './client.js';\n\nexport const CONSUMER_SETTLEMENT_DOMAIN =\n 'flur:consumer-offline:v1:settlement' as const;\n\nexport const CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX = 'FLURSR1.' as const;\n\nexport function consumerSettlementSigningPayload(\n settlement: ConsumerSettlement,\n) {\n return {\n domain: CONSUMER_SETTLEMENT_DOMAIN,\n settlementId: settlement.settlementId,\n settlementKey: settlement.settlementKey,\n encounterId: settlement.encounterId,\n oacId: settlement.oacId,\n payerUserId: settlement.payerUserId,\n payeeUserId: settlement.payeeUserId,\n amountKobo: settlement.amountKobo,\n currency: settlement.currency,\n status: settlement.status,\n reviewReason: settlement.reviewReason,\n ledgerRef: settlement.ledgerRef,\n issuedAtMs: settlement.issuedAtMs,\n };\n}\n\nexport function verifyConsumerSettlement(\n settlement: ConsumerSettlement,\n issuerPublicKeySpkiB64: string,\n): boolean {\n const parsed = ConsumerSettlementSchema.safeParse(settlement);\n if (!parsed.success) return false;\n return verifyIssuerP256(\n canonicalJSONBytes(consumerSettlementSigningPayload(parsed.data)),\n parsed.data.issuerSig,\n issuerPublicKeySpkiB64,\n );\n}\n\nexport function encodeConsumerSettlementReceiptQR(\n settlement: ConsumerSettlement,\n): string {\n const parsed = ConsumerSettlementSchema.parse(settlement);\n return `${CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX}${base64UrlEncodeUtf8(\n JSON.stringify(parsed),\n )}`;\n}\n\nexport function decodeUnverifiedConsumerSettlementReceiptQR(\n value: string,\n): ConsumerSettlement {\n if (!value.startsWith(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX)) {\n throw new Error('not a Flur consumer settlement receipt QR');\n }\n const encoded = value.slice(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX.length);\n let raw: unknown;\n try {\n raw = JSON.parse(base64UrlDecodeUtf8(encoded));\n } catch {\n throw new Error('consumer settlement receipt QR is malformed');\n }\n return ConsumerSettlementSchema.parse(raw);\n}\n\nexport function verifyConsumerSettlementReceiptQR(\n value: string,\n issuerPublicKeySpkiB64: string,\n): ConsumerSettlement {\n const settlement = decodeUnverifiedConsumerSettlementReceiptQR(value);\n if (!verifyConsumerSettlement(settlement, issuerPublicKeySpkiB64)) {\n throw new Error('consumer settlement receipt QR signature invalid');\n }\n return settlement;\n}\n\n/**\n * @deprecated One-argument decode is unverified and exists only for 2.x\n * source compatibility. Prefer `verifyConsumerSettlementReceiptQR(value,\n * issuerPublicKeySpkiB64)` or pass the issuer key as the second argument.\n */\nexport function decodeConsumerSettlementReceiptQR(\n value: string,\n): ConsumerSettlement;\nexport function decodeConsumerSettlementReceiptQR(\n value: string,\n issuerPublicKeySpkiB64: string,\n): ConsumerSettlement;\nexport function decodeConsumerSettlementReceiptQR(\n value: string,\n issuerPublicKeySpkiB64?: string,\n): ConsumerSettlement {\n if (!issuerPublicKeySpkiB64) {\n return decodeUnverifiedConsumerSettlementReceiptQR(value);\n }\n return verifyConsumerSettlementReceiptQR(value, issuerPublicKeySpkiB64);\n}\n\nfunction base64UrlEncodeUtf8(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n const base64 =\n typeof btoa === 'function'\n ? btoa(binary)\n : typeof Buffer !== 'undefined'\n ? Buffer.from(bytes).toString('base64')\n : undefined;\n if (!base64) throw new Error('base64 encoder unavailable');\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction base64UrlDecodeUtf8(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n '=',\n );\n if (typeof atob === 'function') {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index++) {\n bytes[index] = binary.charCodeAt(index);\n }\n return new TextDecoder().decode(bytes);\n }\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(padded, 'base64').toString('utf8');\n }\n throw new Error('base64 decoder unavailable');\n}\n","/**\n * Offline verification of the unified Offline Authorization Certificate (OAC).\n *\n * The OAC is issuer-signed and folds identity (phoneE164, displayName, bound\n * device key) into the same credential that carries offline spend authority.\n * This lets two users who meet for the first time recognise and pay each\n * other WITHOUT a network round-trip: the verifier checks the issuer\n * signature against a *pinned* trusted issuer key (a Trust Bundle refreshed\n * whenever the device is online), never the key embedded in the credential.\n *\n * Trust model:\n * - Provisional offline authorization, authoritative online settlement.\n * A successful offline verify proves the credential was issued by Flur\n * and is within its validity window; the backend still re-checks\n * revocation, balance, and caps at settlement. Short OAC TTL is the\n * revocation-propagation mechanism — a revoked user cannot refresh and\n * their OAC expires within the issuance TTL.\n *\n * Wire format mirrors `flur-backend/src/offline-consumer/service.ts`\n * (`oacSigningPayload`): the issuer signs `canonicalJSONBytes({ domain, ...oac })`\n * with its P-256 key. Adding fields to `ConsumerOAC` automatically includes\n * them in the signed bytes, so identity is covered without a new domain.\n */\nimport { z } from 'zod';\n\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { verifyIssuerP256 } from '../crypto/p256-issuer.js';\nimport {\n ACCOUNT_FUNDED_OAC_MAX_TTL_MS,\n ConsumerOACSchema,\n SignedConsumerOACSchema,\n type ConsumerOAC,\n type SignedConsumerOAC,\n} from './client.js';\n\n/**\n * Domain tag bound into the OAC issuer signature. MUST match\n * `OAC_DOMAIN` in `flur-backend/src/offline-consumer/service.ts`.\n */\nexport const CONSUMER_OAC_DOMAIN = 'flur:consumer-offline:v1:oac' as const;\n\n/**\n * A pinned issuer key the device trusts for offline OAC verification.\n * Sourced from the backend Trust Bundle (`GET /v1/issuer/keys`) and cached\n * on-device. `notBeforeMs` / `notAfterMs` bound the key's own validity so a\n * rotated-out key cannot be used to verify a freshly minted credential.\n */\nexport interface TrustedIssuerKey {\n issuerId: string;\n /** Issuer P-256 public key as SubjectPublicKeyInfo DER, base64. */\n publicKeySpkiB64: string;\n notBeforeMs?: number;\n notAfterMs?: number;\n}\n\n/** Identity surfaced to the caller after a successful offline verify. */\nexport interface OacOfflineIdentity {\n oacId: string;\n issuerId: string;\n userId: string;\n phoneE164: string;\n displayName: string;\n /** Holder's bound device key; lets the caller verify receipts offline. */\n devicePubkeySpkiB64: string;\n}\n\nexport type VerifyOacOfflineResult =\n | { ok: true; oac: ConsumerOAC; identity: OacOfflineIdentity }\n | {\n ok: false;\n reason:\n | 'malformed'\n | 'untrusted_issuer'\n | 'signature_invalid'\n | 'window_too_long'\n | 'not_yet_valid'\n | 'expired'\n | 'revoked';\n };\n\nexport interface VerifyOacOfflineOptions {\n /** Override the wall clock; defaults to `Date.now()`. */\n nowMs?: number;\n /**\n * Verified revoked-OAC id set from a pinned revocation status-list (see\n * `verifyRevocationList`). When supplied, an otherwise-valid OAC whose\n * `oacId` is present is rejected with reason `'revoked'`. Omitting this\n * preserves the TTL-only revocation baseline.\n */\n revokedOacIds?: ReadonlySet<string>;\n}\n\n/** Canonical OAC payload (domain-bound) the backend issuer signs. */\nexport function consumerOacSigningPayload(oac: ConsumerOAC) {\n return { domain: CONSUMER_OAC_DOMAIN, ...oac };\n}\n\n/**\n * Verify a signed OAC offline against a pinned set of trusted issuer keys.\n *\n * Security invariants:\n * - The signature is checked against the PINNED key for `oac.issuerId`,\n * never the credential-embedded `issuerPublicKeySpkiB64`. An attacker who\n * forges an OAC with their own key (and a matching embedded key) fails\n * because their key is not pinned.\n * - The pinned key's own validity window is enforced.\n * - The OAC validity window is enforced (`validFromMs <= now < validUntilMs`).\n */\nexport function verifyOacOffline(\n signed: SignedConsumerOAC,\n trustedKeys: readonly TrustedIssuerKey[],\n options: VerifyOacOfflineOptions = {},\n): VerifyOacOfflineResult {\n const parsed = SignedConsumerOACSchema.safeParse(signed);\n if (!parsed.success) return { ok: false, reason: 'malformed' };\n const oacParsed = ConsumerOACSchema.safeParse(parsed.data.oac);\n if (!oacParsed.success) return { ok: false, reason: 'malformed' };\n const oac = oacParsed.data;\n const nowMs = options.nowMs ?? Date.now();\n\n const pinned = trustedKeys.filter(\n (k) =>\n k.issuerId === oac.issuerId &&\n (k.notBeforeMs === undefined || nowMs >= k.notBeforeMs) &&\n (k.notAfterMs === undefined || nowMs <= k.notAfterMs),\n );\n if (pinned.length === 0) return { ok: false, reason: 'untrusted_issuer' };\n\n const signingBytes = canonicalJSONBytes(consumerOacSigningPayload(oac));\n const signatureOk = pinned.some((k) =>\n verifyIssuerP256(signingBytes, parsed.data.issuerSig, k.publicKeySpkiB64),\n );\n if (!signatureOk) return { ok: false, reason: 'signature_invalid' };\n\n // Defense-in-depth: reject any credential whose validity window exceeds the\n // bounded max TTL even if signed by a trusted issuer. Short OAC TTL is the\n // revocation-propagation mechanism, so an over-long window — however it was\n // minted — must never verify offline.\n if (oac.validUntilMs - oac.validFromMs > ACCOUNT_FUNDED_OAC_MAX_TTL_MS) {\n return { ok: false, reason: 'window_too_long' };\n }\n\n if (nowMs < oac.validFromMs) return { ok: false, reason: 'not_yet_valid' };\n if (nowMs >= oac.validUntilMs) return { ok: false, reason: 'expired' };\n\n // Revocation status-list check: bounds the trust window below the OAC TTL.\n if (options.revokedOacIds?.has(oac.oacId)) {\n return { ok: false, reason: 'revoked' };\n }\n\n return {\n ok: true,\n oac,\n identity: {\n oacId: oac.oacId,\n issuerId: oac.issuerId,\n userId: oac.userId,\n phoneE164: oac.phoneE164,\n displayName: oac.displayName,\n devicePubkeySpkiB64: oac.devicePubkeySpkiB64,\n },\n };\n}\n\n/**\n * QR prefix for a presented unified OAC. A holder shows this QR to be paid\n * and/or identified offline; the scanner decodes it and calls\n * `verifyOacOffline` against its pinned trust bundle. Distinct from the\n * settlement-receipt (`FLURSR1.`) and pay-card prefixes so the scanner can\n * dispatch by prefix without ambiguity.\n */\nexport const CONSUMER_OAC_QR_PREFIX = 'FLUROAC1.' as const;\n\n/** True iff `value` looks like a presented OAC QR payload. */\nexport function isConsumerOacQR(value: string): boolean {\n return value.startsWith(CONSUMER_OAC_QR_PREFIX);\n}\n\n/**\n * Advisory \"pay me\" request a holder may attach to a presented OAC pay code:\n * an amount, a purpose/intent, and a free-text reference. This rides as an\n * UNSIGNED suffix on the QR (see {@link encodeConsumerOacQR}) — it is never\n * part of the issuer-signed credential and carries no authority. The payer's\n * app treats it purely as a prefill hint and always confirms the amount,\n * exactly as with a NIBSS dynamic QR.\n */\nexport const OacPresentmentRequestSchema = z\n .object({\n /** Requested amount in minor units (kobo). */\n amountMinor: z.number().int().positive().max(1_000_000_000_000).optional(),\n /** Purpose/intent code (mirrors the NIBSS intent vocabulary). */\n intent: z.string().min(1).max(32).optional(),\n /** Free-text reference / note. */\n reference: z.string().min(1).max(64).optional(),\n })\n .strict();\nexport type OacPresentmentRequest = z.infer<typeof OacPresentmentRequestSchema>;\n\n/**\n * Encode a signed OAC as a scannable QR payload. The envelope is validated\n * before encoding so a malformed credential can never be presented.\n *\n * An optional advisory {@link OacPresentmentRequest} is appended as a\n * dot-separated, base64url-encoded suffix:\n * `FLUROAC1.<base64url(signed)>.<base64url(request)>`\n * The signed segment is byte-identical with or without the suffix, so the\n * credential's verifiability is unaffected. An empty request adds no suffix.\n */\nexport function encodeConsumerOacQR(\n signed: SignedConsumerOAC,\n request?: OacPresentmentRequest,\n): string {\n const parsed = SignedConsumerOACSchema.parse(signed);\n const base = `${CONSUMER_OAC_QR_PREFIX}${base64UrlEncodeUtf8(JSON.stringify(parsed))}`;\n if (request === undefined) return base;\n const parsedRequest = OacPresentmentRequestSchema.parse(request);\n if (Object.keys(parsedRequest).length === 0) return base;\n return `${base}.${base64UrlEncodeUtf8(JSON.stringify(parsedRequest))}`;\n}\n\n/**\n * Decode (WITHOUT verifying) a presented OAC QR back into a signed envelope.\n * Any advisory request suffix is ignored here — use\n * {@link decodeConsumerOacRequest} to read it. The caller MUST pass the result\n * to `verifyOacOffline` against pinned keys before trusting any field —\n * decoding proves nothing about authenticity.\n */\nexport function decodeUnverifiedConsumerOacQR(\n value: string,\n): SignedConsumerOAC {\n if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) {\n throw new Error('not a Flur consumer OAC QR');\n }\n const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);\n // The base64url alphabet excludes '.', so the first segment is the signed\n // credential and anything after the first dot is the advisory suffix.\n const encoded = remainder.split('.', 1)[0];\n let raw: unknown;\n try {\n raw = JSON.parse(base64UrlDecodeUtf8(encoded));\n } catch {\n throw new Error('consumer OAC QR is malformed');\n }\n return SignedConsumerOACSchema.parse(raw);\n}\n\n/**\n * Read the advisory {@link OacPresentmentRequest} from a presented OAC QR, or\n * `null` if absent/malformed. This is purely a prefill hint and is NEVER\n * authoritative — a malformed suffix is treated as \"no request\" and never\n * throws, so a bad suffix can never block a verifiable credential.\n */\nexport function decodeConsumerOacRequest(\n value: string,\n): OacPresentmentRequest | null {\n if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) return null;\n const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);\n const dot = remainder.indexOf('.');\n if (dot < 0) return null;\n const suffix = remainder.slice(dot + 1);\n if (suffix.length === 0) return null;\n try {\n const raw = JSON.parse(base64UrlDecodeUtf8(suffix));\n const parsed = OacPresentmentRequestSchema.safeParse(raw);\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n}\n\nfunction base64UrlEncodeUtf8(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n const base64 =\n typeof btoa === 'function'\n ? btoa(binary)\n : typeof Buffer !== 'undefined'\n ? Buffer.from(bytes).toString('base64')\n : undefined;\n if (!base64) throw new Error('base64 encoder unavailable');\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction base64UrlDecodeUtf8(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n '=',\n );\n if (typeof atob === 'function') {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index++) {\n bytes[index] = binary.charCodeAt(index);\n }\n return new TextDecoder().decode(bytes);\n }\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(padded, 'base64').toString('utf8');\n }\n throw new Error('base64 decoder unavailable');\n}\n","/**\n * FLURA1 — single-SMS consumer-offline settle token.\n *\n * Why this exists:\n * - The legacy `FLURC1.` codec packed the entire dual-party-signed\n * `ConsumerPaymentClaim` JSON into a base64url SMS, which (a) overran\n * the 160-char GSM-7 single-SMS budget for any non-trivial claim and\n * (b) leaked enough state through the carrier to allow a hostile relay\n * to replay the claim out-of-band.\n * - Text-banking rails in the real world (737-SMS, M-Pesa STK applet)\n * settle from a much smaller payload, but they substitute MSISDN trust\n * + tiny daily limits for cryptographic auth. We can do strictly better\n * because we already have hardware-backed P-256 device keys.\n *\n * FLURA1 wire (112 bytes, signed by the payer's hardware key):\n *\n * off len field\n * 0 1 version 0x01\n * 1 1 flags reserved, must be 0x00\n * 2 16 encounterId prefix first 16 of sha256(encounterId)\n * 18 8 payer userId prefix first 8 bytes of UUID binary\n * 26 8 payee userId prefix first 8 bytes of UUID binary\n * 34 8 amountKobo uint64 big-endian\n * 42 6 occurredAtMs uint48 big-endian\n * 48 64 signature raw ECDSA-P256 r‖s (32 + 32)\n *\n * Signing input is `FLURA1_DOMAIN ‖ bytes[0..47]` (31 + 48 = 79 bytes),\n * SHA-256-prehashed inside `p256.sign`. Currency is the platform invariant\n * NGN and never travels on the wire. The backend resolves full UUIDs from\n * the 8-byte prefixes (collision probability < 1e-12 at our scale; the\n * backend rejects ambiguous matches).\n *\n * Wire encoding: `FLURA1.<base64url(112 bytes)>` = 7 + 150 = 157 chars,\n * fits one GSM-7 SMS with 3 chars to spare.\n *\n * This payload is enough to *settle* unilaterally — the payer's signature\n * is the authority, the OAC active at `occurredAtMs` is the limit. The\n * payee can dispute the amount in person; the ledger move is final once\n * verified, just like cash.\n */\n\nimport { p256 } from '@noble/curves/nist';\nimport { p256SpkiB64ToRaw } from '../crypto/p256-issuer.js';\nimport {\n ConsumerPaymentClaimSchema,\n type ConsumerPaymentClaim,\n} from './client.js';\n\n// ─────────────────────────── public constants ───────────────────────────\n\n/**\n * Full-claim QR envelope used for authenticated app-to-app relay. This is\n * intentionally NOT the carrier-SMS settle rail: the JSON claim can exceed\n * a single SMS and must not be sent to the provider webhook. Mobile keeps\n * this for QR/paste flows that submit to `/v1/me/offline/claims`.\n */\nexport const OFFLINE_CLAIM_SMS_PREFIX = 'FLURC1.' as const;\n\nconst CLAIM_TOKEN_RE = /(?:^|\\s)(FLURC1\\.[A-Za-z0-9_-]+={0,2})(?:\\s|$)/;\n\nexport function encodeOfflineClaimSmsMessage(\n claim: ConsumerPaymentClaim,\n): string {\n const parsed = ConsumerPaymentClaimSchema.parse(claim);\n return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf8(\n JSON.stringify(parsed),\n )}`;\n}\n\nexport function decodeOfflineClaimSmsMessage(\n message: string,\n): ConsumerPaymentClaim {\n const token = extractOfflineClaimSmsToken(message);\n if (!token) throw new Error('offline claim QR token not found');\n const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);\n let raw: unknown;\n try {\n raw = JSON.parse(base64UrlDecodeUtf8(encoded));\n } catch {\n throw new Error('offline claim QR token is malformed');\n }\n const parsed = ConsumerPaymentClaimSchema.safeParse(raw);\n if (!parsed.success) throw new Error('offline claim QR token is invalid');\n return parsed.data;\n}\n\nexport function extractOfflineClaimSmsToken(message: string): string | null {\n const trimmed = message.trim();\n if (trimmed.startsWith(OFFLINE_CLAIM_SMS_PREFIX)) {\n return trimmed.split(/\\s+/, 1)[0] ?? null;\n }\n return CLAIM_TOKEN_RE.exec(message)?.[1] ?? null;\n}\n\nexport const OFFLINE_SMS_SETTLE_PREFIX = 'FLURA1.' as const;\n\n/** Domain string prepended to the 48-byte header before signing/verifying. */\nexport const OFFLINE_SMS_SETTLE_DOMAIN =\n 'flur:consumer-offline:v1:attest' as const;\n\n/** Fixed total binary length, in bytes. */\nexport const OFFLINE_SMS_SETTLE_TOKEN_BYTES = 112 as const;\n\n/** Length of the signed prefix (everything except the 64-byte signature). */\nexport const OFFLINE_SMS_SETTLE_HEADER_BYTES = 48 as const;\n\n/** Length of the raw P-256 r‖s signature appended after the header. */\nexport const OFFLINE_SMS_SETTLE_SIGNATURE_BYTES = 64 as const;\n\n/** Wire version supported by this codec. */\nexport const OFFLINE_SMS_SETTLE_VERSION = 0x01 as const;\n\n/** Matches FLURA1 tokens embedded in arbitrary SMS body text. */\nconst TOKEN_RE = /(?:^|[\\s,;:()<>\"'])(FLURA1\\.[A-Za-z0-9_-]{150})/;\n\n// ─────────────────────────── public types ───────────────────────────\n\n/**\n * Inputs the caller supplies when building a FLURA1 token. All identifier\n * fields are full hex/UUID strings; this codec computes prefixes.\n */\nexport interface OfflineSmsSettleInput {\n /** Opaque encounter identifier — same value the claim uses. */\n encounterId: string;\n /** Full payer user UUID (string form, e.g. `8c...-...-...-...-...`). */\n payerUserId: string;\n /** Full payee user UUID (string form). */\n payeeUserId: string;\n amountKobo: number;\n occurredAtMs: number;\n}\n\n/**\n * Decoded view of a FLURA1 token. Field prefixes are returned as hex\n * strings; raw byte arrays are exposed for callers that need them\n * (signature verification, audit storage).\n */\nexport interface DecodedOfflineSmsSettleToken {\n version: number;\n flags: number;\n encounterIdPrefixHex: string;\n payerUserIdPrefixHex: string;\n payeeUserIdPrefixHex: string;\n amountKobo: number;\n occurredAtMs: number;\n /** Raw 64-byte ECDSA-P256 r‖s signature. */\n signature: Uint8Array;\n /** 48-byte signed header (`bytes[0..47]`). */\n header: Uint8Array;\n /** 79-byte domain-tagged buffer that was actually fed into `p256.verify`. */\n signedBytes: Uint8Array;\n}\n\n/**\n * Minimal signer surface accepted by `encodeOfflineSmsSettleToken`. Returns\n * raw 64-byte r‖s ECDSA-P256. Hardware signers that natively emit DER must\n * convert before calling this codec — see `derToRawP256Signature`.\n */\nexport interface OfflineSmsSettleSigner {\n signRaw(bytes: Uint8Array): Promise<Uint8Array>;\n}\n\n// ─────────────────────────── encode ───────────────────────────\n\nexport async function encodeOfflineSmsSettleToken(\n input: OfflineSmsSettleInput,\n signer: OfflineSmsSettleSigner,\n): Promise<string> {\n const header = await buildSmsSettleHeader(input);\n const sig = await signer.signRaw(domainTag(header));\n if (sig.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {\n throw new Error(\n `FLURA1: signer returned ${sig.length}-byte sig; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`,\n );\n }\n const out = new Uint8Array(OFFLINE_SMS_SETTLE_TOKEN_BYTES);\n out.set(header, 0);\n out.set(sig, OFFLINE_SMS_SETTLE_HEADER_BYTES);\n return `${OFFLINE_SMS_SETTLE_PREFIX}${bytesToBase64Url(out)}`;\n}\n\n/**\n * Build the 48-byte signed header for the given input. Exposed so callers\n * that own the signing primitive directly (e.g. a native Secure Enclave\n * bridge that emits DER) can compute the bytes-to-sign without going\n * through `OfflineSmsSettleSigner`.\n */\nexport async function buildSmsSettleHeader(\n input: OfflineSmsSettleInput,\n): Promise<Uint8Array> {\n assertSafeUint64(input.amountKobo, 'amountKobo');\n if (input.amountKobo <= 0) {\n throw new Error('FLURA1: amountKobo must be greater than zero');\n }\n assertSafeUint48(input.occurredAtMs, 'occurredAtMs');\n const encounterPrefix = (await sha256(utf8(input.encounterId))).slice(0, 16);\n const payerPrefix = uuidToBytes(input.payerUserId).slice(0, 8);\n const payeePrefix = uuidToBytes(input.payeeUserId).slice(0, 8);\n\n const header = new Uint8Array(OFFLINE_SMS_SETTLE_HEADER_BYTES);\n const dv = new DataView(header.buffer);\n header[0] = OFFLINE_SMS_SETTLE_VERSION;\n header[1] = 0x00; // flags\n header.set(encounterPrefix, 2);\n header.set(payerPrefix, 18);\n header.set(payeePrefix, 26);\n writeUint64BE(dv, 34, input.amountKobo);\n writeUint48BE(dv, 42, input.occurredAtMs);\n return header;\n}\n\n/**\n * Bytes a signer must operate on: `OFFLINE_SMS_SETTLE_DOMAIN ‖ header`.\n * Exposed for hardware bridges that own the signing call themselves.\n */\nexport function domainTag(header: Uint8Array): Uint8Array {\n if (header.length !== OFFLINE_SMS_SETTLE_HEADER_BYTES) {\n throw new Error(\n `FLURA1: header must be ${OFFLINE_SMS_SETTLE_HEADER_BYTES} bytes`,\n );\n }\n const domain = utf8(OFFLINE_SMS_SETTLE_DOMAIN);\n const out = new Uint8Array(domain.length + header.length);\n out.set(domain, 0);\n out.set(header, domain.length);\n return out;\n}\n\n// ─────────────────────────── decode ───────────────────────────\n\nexport function decodeOfflineSmsSettleToken(\n message: string,\n): DecodedOfflineSmsSettleToken {\n const token = extractOfflineSmsSettleToken(message);\n if (!token) throw new Error('FLURA1: token not found');\n const encoded = token.slice(OFFLINE_SMS_SETTLE_PREFIX.length);\n let bytes: Uint8Array;\n try {\n bytes = base64UrlToBytes(encoded);\n } catch {\n throw new Error('FLURA1: token base64url is malformed');\n }\n if (bytesToBase64Url(bytes) !== encoded) {\n throw new Error('FLURA1: token base64url is malformed');\n }\n if (bytes.length !== OFFLINE_SMS_SETTLE_TOKEN_BYTES) {\n throw new Error(\n `FLURA1: expected ${OFFLINE_SMS_SETTLE_TOKEN_BYTES} bytes, got ${bytes.length}`,\n );\n }\n const version = bytes[0]!;\n const flags = bytes[1]!;\n if (version !== OFFLINE_SMS_SETTLE_VERSION) {\n throw new Error(`FLURA1: unsupported version ${version}`);\n }\n if (flags !== 0x00) {\n throw new Error(`FLURA1: reserved flags must be 0, got ${flags}`);\n }\n const header = bytes.slice(0, OFFLINE_SMS_SETTLE_HEADER_BYTES);\n const signature = bytes.slice(OFFLINE_SMS_SETTLE_HEADER_BYTES);\n const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const amountKobo = readUint64BE(dv, 34);\n if (amountKobo <= 0) {\n throw new Error('FLURA1: amountKobo must be greater than zero');\n }\n return {\n version,\n flags,\n encounterIdPrefixHex: bytesToHex(bytes.slice(2, 18)),\n payerUserIdPrefixHex: bytesToHex(bytes.slice(18, 26)),\n payeeUserIdPrefixHex: bytesToHex(bytes.slice(26, 34)),\n amountKobo,\n occurredAtMs: readUint48BE(dv, 42),\n signature,\n header,\n signedBytes: domainTag(header),\n };\n}\n\nexport function extractOfflineSmsSettleToken(message: string): string | null {\n const trimmed = message.trim();\n if (trimmed.startsWith(OFFLINE_SMS_SETTLE_PREFIX)) {\n return trimmed.split(/\\s+/, 1)[0] ?? null;\n }\n return TOKEN_RE.exec(message)?.[1] ?? null;\n}\n\n// ─────────────────────────── verify ───────────────────────────\n\n/**\n * Verify a decoded FLURA1 token against a candidate payer SPKI public key.\n * Returns `false` (never throws) on any signature or key-decode failure so\n * callers can iterate a candidate set safely.\n */\nexport function verifyOfflineSmsSettleToken(\n decoded: DecodedOfflineSmsSettleToken,\n payerPubkeySpkiB64: string,\n): boolean {\n try {\n const pubRaw = p256SpkiB64ToRaw(payerPubkeySpkiB64);\n return p256.verify(decoded.signature, decoded.signedBytes, pubRaw, {\n prehash: true,\n format: 'compact',\n });\n } catch {\n return false;\n }\n}\n\n// ─────────────────────────── DER ↔ raw helper ───────────────────────────\n\n/**\n * Convert an ASN.1 DER ECDSA-P256 signature (the format every hardware\n * Secure-Enclave / Keystore bridge in this codebase emits) into the\n * 64-byte raw r‖s form that FLURA1 carries on the wire.\n *\n * Throws on any DER parse failure or out-of-range coordinate.\n */\nexport function derToRawP256Signature(derBytes: Uint8Array): Uint8Array {\n const sig = p256.Signature.fromBytes(derBytes, 'der');\n const raw = sig.toBytes('compact');\n if (raw.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {\n throw new Error(\n `FLURA1: DER→raw produced ${raw.length} bytes; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`,\n );\n }\n return raw;\n}\n\n// ─────────────────────────── byte/format utils ───────────────────────────\n//\n// All helpers here are local to FLURA1 — they do not allocate beyond what\n// the codec needs and are safe in RN / browser / Node without polyfills.\n\nfunction utf8(s: string): Uint8Array {\n return new TextEncoder().encode(s);\n}\n\nasync function sha256(bytes: Uint8Array): Promise<Uint8Array> {\n // Prefer Web Crypto where available (RN Hermes since Expo SDK 51 ships\n // it, browsers always, Node ≥ 20). Fall back to @noble/hashes only if\n // the platform truly lacks SubtleCrypto.\n const subtle =\n (typeof globalThis !== 'undefined' && globalThis.crypto?.subtle) ||\n undefined;\n if (subtle) {\n const digest = await subtle.digest('SHA-256', bytes);\n return new Uint8Array(digest);\n }\n // Lazy import to avoid pulling the dep into bundles that never need it.\n const { sha256: nobleSha256 } = await import('@noble/hashes/sha2');\n return nobleSha256(bytes);\n}\n\nfunction uuidToBytes(uuid: string): Uint8Array {\n // Accept the canonical 8-4-4-4-12 form. Any other shape is a programmer\n // error and fails loudly — these IDs come from a server-issued source.\n const hex = uuid.replace(/-/g, '').toLowerCase();\n if (hex.length !== 32 || !/^[0-9a-f]{32}$/.test(hex)) {\n throw new Error(`FLURA1: invalid UUID: ${uuid}`);\n }\n const out = new Uint8Array(16);\n for (let i = 0; i < 16; i++) {\n out[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nfunction assertSafeUint64(value: number, field: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`FLURA1: ${field} must be a non-negative integer`);\n }\n if (value > Number.MAX_SAFE_INTEGER) {\n throw new Error(`FLURA1: ${field} exceeds Number.MAX_SAFE_INTEGER`);\n }\n}\n\nfunction assertSafeUint48(value: number, field: string): void {\n assertSafeUint64(value, field);\n if (value > 0xffffffffffff) {\n throw new Error(`FLURA1: ${field} exceeds uint48 range`);\n }\n}\n\nfunction writeUint64BE(dv: DataView, offset: number, value: number): void {\n // JS Number is safe to 2^53−1, well below uint64 max; we split into two\n // 32-bit words rather than depend on BigInt for RN/Hermes parity.\n const high = Math.floor(value / 0x100000000);\n const low = value >>> 0;\n dv.setUint32(offset, high, false);\n dv.setUint32(offset + 4, low, false);\n}\n\nfunction readUint64BE(dv: DataView, offset: number): number {\n const high = dv.getUint32(offset, false);\n const low = dv.getUint32(offset + 4, false);\n if (high > 0x001fffff) {\n throw new Error('FLURA1: amountKobo exceeds Number.MAX_SAFE_INTEGER');\n }\n return high * 0x100000000 + low;\n}\n\nfunction writeUint48BE(dv: DataView, offset: number, value: number): void {\n const high = Math.floor(value / 0x10000);\n const low = value & 0xffff;\n dv.setUint32(offset, high, false);\n dv.setUint16(offset + 4, low, false);\n}\n\nfunction readUint48BE(dv: DataView, offset: number): number {\n const high = dv.getUint32(offset, false);\n const low = dv.getUint16(offset + 4, false);\n return high * 0x10000 + low;\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n out += bytes[i]!.toString(16).padStart(2, '0');\n }\n return out;\n}\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let base64: string;\n if (typeof Buffer !== 'undefined') {\n base64 = Buffer.from(bytes).toString('base64');\n } else {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n if (typeof btoa !== 'function') {\n throw new Error('FLURA1: base64 encoder unavailable');\n }\n base64 = btoa(binary);\n }\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction base64UrlEncodeUtf8(input: string): string {\n return bytesToBase64Url(utf8(input));\n}\n\nfunction base64UrlDecodeUtf8(input: string): string {\n return new TextDecoder().decode(base64UrlToBytes(input));\n}\n\nfunction base64UrlToBytes(input: string): Uint8Array {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n '=',\n );\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(padded, 'base64'));\n }\n if (typeof atob !== 'function') {\n throw new Error('FLURA1: base64 decoder unavailable');\n }\n const binary = atob(padded);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n return out;\n}\n","/**\r\n * Partner-funded wallet rails SDK.\r\n *\r\n * Provides two clients:\r\n * - `createPartnerFundingClient(partnerClient)` — uses partner HMAC for\r\n * the bank/merchant partner endpoints (funding webhook, payout events,\r\n * daily reconciliation). The caller MUST have minted credentials with\r\n * the appropriate scopes (`partner:funding:write`, `partner:payout:write`,\r\n * `partner:reconciliation:read`).\r\n * - `createConsumerWithdrawalsClient(opts)` — session-bearer auth for the\r\n * consumer endpoints (linked payout destinations, withdrawals).\r\n *\r\n * Schemas mirror `flur-backend/src/partner-funding/types.ts`. Money is\r\n * always represented in MINOR units (e.g. kobo for NGN). BIGINT-bearing\r\n * response fields are serialized as integer strings to avoid JS number\r\n * precision issues; reserve balances and imbalances may be signed.\r\n */\r\nimport { z } from 'zod';\r\nimport type { FlurPartnerClient } from '../partner/client.js';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\n// ───────────────────────────── shared ─────────────────────────────\r\n\r\nconst MinorString = z.string().regex(/^-?\\d+$/);\r\nconst PositiveMinor = z.union([\r\n z.number().int().positive(),\r\n z.string().regex(/^[1-9]\\d{0,18}$/),\r\n]);\r\nconst Currency = z\r\n .string()\r\n .trim()\r\n .length(3)\r\n .transform((v) => v.toUpperCase());\r\nconst Metadata = z.record(z.unknown());\r\n\r\nexport const PARTNER_KINDS = ['bank', 'merchant'] as const;\r\nexport type PartnerKind = (typeof PARTNER_KINDS)[number];\r\n\r\nexport const CUSTODIAL_MODES = ['agent_of_bank', 'flur_virtual_pool'] as const;\r\nexport type CustodialMode = (typeof CUSTODIAL_MODES)[number];\r\n\r\nexport const PARTNER_PROFILE_STATUSES = [\r\n 'active',\r\n 'suspended',\r\n 'closed',\r\n] as const;\r\nexport type PartnerProfileStatus = (typeof PARTNER_PROFILE_STATUSES)[number];\r\n\r\nexport const PARTNER_FUNDING_DIRECTIONS = ['credit', 'debit'] as const;\r\nexport type PartnerFundingDirection =\r\n (typeof PARTNER_FUNDING_DIRECTIONS)[number];\r\n\r\nexport const PARTNER_FUNDING_STATUSES = [\r\n 'pending',\r\n 'posted',\r\n 'failed',\r\n] as const;\r\nexport type PartnerFundingStatus = (typeof PARTNER_FUNDING_STATUSES)[number];\r\n\r\nexport const PAYOUT_DESTINATION_STATUSES = [\r\n 'pending',\r\n 'verified',\r\n 'disabled',\r\n] as const;\r\nexport type PayoutDestinationStatus =\r\n (typeof PAYOUT_DESTINATION_STATUSES)[number];\r\n\r\nexport const WITHDRAWAL_STATES = [\r\n 'requested',\r\n 'submitted',\r\n 'processing',\r\n 'paid',\r\n 'failed',\r\n 'reversed',\r\n] as const;\r\nexport type WithdrawalState = (typeof WITHDRAWAL_STATES)[number];\r\n\r\n// ───────────────────────────── profile ─────────────────────────────\r\n\r\nexport const PartnerProfileSchema = z.object({\r\n partnerAccountId: z.string().uuid(),\r\n kind: z.enum(PARTNER_KINDS),\r\n custodialMode: z.enum(CUSTODIAL_MODES),\r\n displayName: z.string(),\r\n bankCode: z.string().nullable(),\r\n poolAccountNumber: z.string().nullable(),\r\n status: z.enum(PARTNER_PROFILE_STATUSES),\r\n metadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type PartnerProfile = z.infer<typeof PartnerProfileSchema>;\r\n\r\nexport const UpsertPartnerProfileInputSchema = z.object({\r\n kind: z.enum(PARTNER_KINDS),\r\n custodialMode: z.enum(CUSTODIAL_MODES),\r\n displayName: z.string().trim().min(1).max(200),\r\n bankCode: z.string().trim().min(1).max(64).optional(),\r\n poolAccountNumber: z.string().trim().min(1).max(64).optional(),\r\n metadata: Metadata.optional(),\r\n});\r\nexport type UpsertPartnerProfileInput = z.infer<\r\n typeof UpsertPartnerProfileInputSchema\r\n>;\r\n\r\n// ───────────────────────────── fundings ─────────────────────────────\r\n\r\nexport const PartnerFundingEventInputSchema = z.object({\r\n externalRef: z.string().trim().min(8).max(128),\r\n direction: z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),\r\n userId: z.string().uuid().optional(),\r\n accountId: z.string().uuid().optional(),\r\n amountMinor: PositiveMinor,\r\n currency: Currency,\r\n fundingSource: z.string().trim().min(1).max(64).optional(),\r\n providerMetadata: Metadata.optional(),\r\n});\r\nexport type PartnerFundingEventInput = z.infer<\r\n typeof PartnerFundingEventInputSchema\r\n>;\r\n\r\nexport const PartnerFundingSchema = z.object({\r\n fundingId: z.string().uuid(),\r\n partnerId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n userId: z.string().uuid().nullable(),\r\n direction: z.enum(PARTNER_FUNDING_DIRECTIONS),\r\n currency: z.string(),\r\n amountMinor: MinorString,\r\n externalRef: z.string(),\r\n status: z.enum(PARTNER_FUNDING_STATUSES),\r\n fundingSource: z.string(),\r\n ledgerRef: z.string(),\r\n providerMetadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type PartnerFunding = z.infer<typeof PartnerFundingSchema>;\r\n\r\nexport const IngestFundingResultSchema = z.object({\r\n funding: PartnerFundingSchema,\r\n replayed: z.boolean(),\r\n});\r\nexport type IngestFundingResult = z.infer<typeof IngestFundingResultSchema>;\r\n\r\n// ───────────────────────────── destinations ─────────────────────────────\r\n\r\nexport const PayoutDestinationSchema = z.object({\r\n destinationId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n partnerId: z.string().uuid(),\r\n bankCode: z.string(),\r\n accountNumber: z.string(),\r\n accountName: z.string(),\r\n status: z.enum(PAYOUT_DESTINATION_STATUSES),\r\n verifiedAtMs: z.number().int().nonnegative().nullable(),\r\n metadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type PayoutDestination = z.infer<typeof PayoutDestinationSchema>;\r\n\r\nexport const CreatePayoutDestinationInputSchema = z.object({\r\n partnerId: z.string().uuid(),\r\n bankCode: z.string().trim().min(1).max(32),\r\n accountNumber: z.string().trim().min(4).max(64),\r\n accountName: z.string().trim().min(1).max(200),\r\n metadata: Metadata.optional(),\r\n});\r\nexport type CreatePayoutDestinationInput = z.infer<\r\n typeof CreatePayoutDestinationInputSchema\r\n>;\r\n\r\nexport const ListPayoutDestinationsResultSchema = z.object({\r\n items: z.array(PayoutDestinationSchema),\r\n});\r\nexport type ListPayoutDestinationsResult = z.infer<\r\n typeof ListPayoutDestinationsResultSchema\r\n>;\r\n\r\n// ───────────────────────────── withdrawals ─────────────────────────────\r\n\r\nexport const WithdrawalSchema = z.object({\r\n withdrawalId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n userId: z.string().uuid(),\r\n partnerId: z.string().uuid(),\r\n destinationId: z.string().uuid(),\r\n currency: z.string(),\r\n amountMinor: MinorString,\r\n state: z.enum(WITHDRAWAL_STATES),\r\n idempotencyKey: z.string(),\r\n providerRef: z.string().nullable(),\r\n lastError: z.string().nullable(),\r\n ledgerRef: z.string(),\r\n reverseLedgerRef: z.string().nullable(),\r\n metadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type Withdrawal = z.infer<typeof WithdrawalSchema>;\r\n\r\nexport const CreateWithdrawalInputSchema = z.object({\r\n destinationId: z.string().uuid(),\r\n amountMinor: PositiveMinor,\r\n currency: Currency,\r\n idempotencyKey: z.string().trim().min(8).max(128),\r\n metadata: Metadata.optional(),\r\n});\r\nexport type CreateWithdrawalInput = z.infer<typeof CreateWithdrawalInputSchema>;\r\n\r\nexport const CreateWithdrawalResultSchema = z.object({\r\n withdrawal: WithdrawalSchema,\r\n replayed: z.boolean(),\r\n});\r\nexport type CreateWithdrawalResult = z.infer<\r\n typeof CreateWithdrawalResultSchema\r\n>;\r\n\r\n// ───────────────────────────── payout events ─────────────────────────────\r\n\r\nexport const PayoutEventInputSchema = z.object({\r\n externalRef: z.string().trim().min(8).max(128),\r\n withdrawalId: z.string().uuid().optional(),\r\n state: z.enum(['submitted', 'processing', 'paid', 'failed']),\r\n providerRef: z.string().trim().min(1).max(128).optional(),\r\n failureCode: z.string().trim().max(64).optional(),\r\n failureMessage: z.string().trim().max(512).optional(),\r\n providerMetadata: Metadata.optional(),\r\n});\r\nexport type PayoutEventInput = z.infer<typeof PayoutEventInputSchema>;\r\n\r\nexport const RecordPayoutEventResultSchema = z.object({\r\n withdrawal: WithdrawalSchema,\r\n replayed: z.boolean(),\r\n});\r\nexport type RecordPayoutEventResult = z.infer<\r\n typeof RecordPayoutEventResultSchema\r\n>;\r\n\r\n// ───────────────────────────── reconciliation ─────────────────────────────\r\n\r\nexport const ReconciliationReportSchema = z.object({\r\n partnerId: z.string().uuid(),\r\n currency: z.string(),\r\n fromMs: z.number().int().nonnegative(),\r\n toMs: z.number().int().nonnegative(),\r\n fundingsCreditMinor: MinorString,\r\n fundingsDebitMinor: MinorString,\r\n withdrawalsPaidMinor: MinorString,\r\n withdrawalsReversedMinor: MinorString,\r\n withdrawalsInFlightMinor: MinorString,\r\n expectedReserveBalanceMinor: MinorString,\r\n actualReserveBalanceMinor: MinorString,\r\n imbalanceMinor: MinorString,\r\n generatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type ReconciliationReport = z.infer<typeof ReconciliationReportSchema>;\r\n\r\n// ───────────────────────────── partner client ─────────────────────────────\r\n\r\nexport type PartnerFundingClient = {\r\n /** Submit a funding event (idempotent on externalRef per partner). */\r\n ingestFunding: (\r\n input: PartnerFundingEventInput,\r\n ) => Promise<IngestFundingResult>;\r\n /** Send a payout state update (idempotent on terminal states). */\r\n recordPayoutEvent: (\r\n input: PayoutEventInput,\r\n ) => Promise<RecordPayoutEventResult>;\r\n /** Fetch the daily reconciliation report. */\r\n reconciliation: (input: {\r\n currency: string;\r\n fromMs?: number;\r\n toMs?: number;\r\n }) => Promise<ReconciliationReport>;\r\n};\r\n\r\nexport function createPartnerFundingClient(\r\n partner: FlurPartnerClient,\r\n): PartnerFundingClient {\r\n return {\r\n ingestFunding: async (input) => {\r\n const body = PartnerFundingEventInputSchema.parse(input);\r\n const raw = await partner.request({\r\n method: 'POST',\r\n path: '/v1/partners/fundings',\r\n body,\r\n });\r\n return IngestFundingResultSchema.parse(raw);\r\n },\r\n recordPayoutEvent: async (input) => {\r\n const body = PayoutEventInputSchema.parse(input);\r\n const raw = await partner.request({\r\n method: 'POST',\r\n path: '/v1/partners/payouts/events',\r\n body,\r\n });\r\n return RecordPayoutEventResultSchema.parse(raw);\r\n },\r\n reconciliation: async (input) => {\r\n const qs = new URLSearchParams({\r\n currency: input.currency,\r\n });\r\n if (typeof input.fromMs === 'number')\r\n qs.set('fromMs', String(input.fromMs));\r\n if (typeof input.toMs === 'number') qs.set('toMs', String(input.toMs));\r\n const raw = await partner.request({\r\n method: 'GET',\r\n path: `/v1/partners/reconciliation/daily?${qs.toString()}`,\r\n });\r\n return ReconciliationReportSchema.parse(raw);\r\n },\r\n };\r\n}\r\n\r\n// ───────────────────────────── consumer client ─────────────────────────────\r\n\r\nexport type ConsumerWithdrawalsClientOptions = {\r\n baseUrl: string;\r\n /** Session-authenticated fetch (Authorization: Bearer <session-token>). */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type ConsumerWithdrawalsClient = {\r\n listDestinations: () => Promise<ListPayoutDestinationsResult>;\r\n createDestination: (\r\n input: CreatePayoutDestinationInput,\r\n ) => Promise<PayoutDestination>;\r\n verifyDestination: (destinationId: string) => Promise<PayoutDestination>;\r\n disableDestination: (destinationId: string) => Promise<PayoutDestination>;\r\n createWithdrawal: (\r\n input: CreateWithdrawalInput,\r\n ) => Promise<CreateWithdrawalResult>;\r\n getWithdrawal: (withdrawalId: string) => Promise<Withdrawal>;\r\n};\r\n\r\nexport function createConsumerWithdrawalsClient(\r\n opts: ConsumerWithdrawalsClientOptions,\r\n): ConsumerWithdrawalsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createConsumerWithdrawalsClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: { accept: 'application/json' },\r\n };\r\n if (body !== undefined) {\r\n init.body = JSON.stringify(body);\r\n init.headers = { ...init.headers, 'content-type': 'application/json' };\r\n }\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n raw = text;\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n return {\r\n listDestinations: () =>\r\n call('GET', '/v1/me/payout-destinations', undefined, (raw) =>\r\n ListPayoutDestinationsResultSchema.parse(raw),\r\n ),\r\n createDestination: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/me/payout-destinations',\r\n CreatePayoutDestinationInputSchema.parse(input),\r\n (raw) => PayoutDestinationSchema.parse(raw),\r\n ),\r\n verifyDestination: (destinationId) =>\r\n call(\r\n 'POST',\r\n `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/verify`,\r\n {},\r\n (raw) => PayoutDestinationSchema.parse(raw),\r\n ),\r\n disableDestination: (destinationId) =>\r\n call(\r\n 'POST',\r\n `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/disable`,\r\n {},\r\n (raw) => PayoutDestinationSchema.parse(raw),\r\n ),\r\n createWithdrawal: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/me/withdrawals',\r\n CreateWithdrawalInputSchema.parse(input),\r\n (raw) => CreateWithdrawalResultSchema.parse(raw),\r\n ),\r\n getWithdrawal: (withdrawalId) =>\r\n call(\r\n 'GET',\r\n `/v1/me/withdrawals/${encodeURIComponent(withdrawalId)}`,\r\n undefined,\r\n (raw) => WithdrawalSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n\r\n// ───────────────────────────── partner profile admin ─────────────────────────────\r\n\r\n/**\r\n * Partner profile upsert is session-authenticated on the backend (a member\r\n * of the partner account must perform the action), so it uses a regular\r\n * session-bearer fetch rather than the partner HMAC client.\r\n */\r\nexport type PartnerProfileAdminClientOptions = {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type PartnerProfileAdminClient = {\r\n upsertProfile: (\r\n partnerAccountId: string,\r\n input: UpsertPartnerProfileInput,\r\n ) => Promise<PartnerProfile>;\r\n};\r\n\r\nexport function createPartnerProfileAdminClient(\r\n opts: PartnerProfileAdminClientOptions,\r\n): PartnerProfileAdminClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createPartnerProfileAdminClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n return {\r\n upsertProfile: async (partnerAccountId, input) => {\r\n const body = {\r\n partnerAccountId,\r\n ...UpsertPartnerProfileInputSchema.parse(input),\r\n };\r\n const resp = await fetchImpl(`${baseUrl}/v1/partners/profile`, {\r\n method: 'POST',\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n raw = text;\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return PartnerProfileSchema.parse(raw);\r\n },\r\n };\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport {\r\n signIssuerP256 as signP256,\r\n verifyIssuerP256 as verifyP256,\r\n} from '../crypto/p256-issuer.js';\r\n\r\n/**\r\n * Flur v1 Signed Artifact envelope.\r\n *\r\n * URI form:\r\n * flur://v1/<artifact-type>/<base64url(canonical-json(body))>.<base64url(sig)>\r\n *\r\n * Body shape (canonical JSON, sorted keys):\r\n * {\r\n * v: 1, // envelope version\r\n * t: '<artifact-type>', // matches the URI segment (redundant for safety)\r\n * iss: '<issuer-id>', // user/merchant/partner id\r\n * kid: '<device-key-id>', // identifier of the signing device key\r\n * iat: <epoch-seconds>, // issued-at\r\n * exp?: <epoch-seconds>, // optional expiry\r\n * nonce: '<string>', // unique per artifact (replay guard)\r\n * data: <artifact body> // type-specific, validated by registered schema\r\n * }\r\n *\r\n * Signature: P-256 ECDSA (SHA-256) over canonicalJSONBytes(body), ASN.1 DER, base64.\r\n *\r\n * Design notes:\r\n * - URI scheme `flur://v1/...` is the single transport for all signed artifacts.\r\n * - Scanners route on the path segment; verifiers look up the issuer/kid public key\r\n * (SubjectPublicKeyInfo DER, base64) from the backend device-key registry.\r\n * - Pure NIBSS NQR payments remain unchanged; this envelope rides separately.\r\n */\r\n\r\nexport const FLUR_ARTIFACT_URI_SCHEME = 'flur';\r\nexport const FLUR_ARTIFACT_VERSION = 1;\r\nexport const FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;\r\n\r\nconst ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;\r\n\r\nexport const ArtifactHeaderSchema = z.object({\r\n v: z.literal(FLUR_ARTIFACT_VERSION),\r\n t: z.string().regex(ArtifactTypeRe, 'invalid artifact type'),\r\n iss: z.string().min(1).max(128),\r\n kid: z.string().min(1).max(128),\r\n iat: z.number().int().nonnegative(),\r\n exp: z.number().int().positive().optional(),\r\n nonce: z\r\n .string()\r\n .min(8)\r\n .max(64)\r\n .regex(/^[A-Za-z0-9_-]+$/, 'nonce must be url-safe'),\r\n});\r\n\r\nexport type ArtifactHeader = z.infer<typeof ArtifactHeaderSchema>;\r\n\r\nexport type ArtifactBody<T = unknown> = ArtifactHeader & { data: T };\r\n\r\nexport type SignedArtifact<T = unknown> = {\r\n body: ArtifactBody<T>;\r\n /** ASN.1 DER ECDSA P-256 signature, base64 (standard, not url-safe). */\r\n sig: string;\r\n};\r\n\r\nexport class FlurArtifactError extends Error {\r\n constructor(\r\n message: string,\r\n public code:\r\n | 'INVALID_URI'\r\n | 'INVALID_TYPE'\r\n | 'INVALID_BODY'\r\n | 'INVALID_SIGNATURE'\r\n | 'EXPIRED'\r\n | 'TYPE_MISMATCH',\r\n ) {\r\n super(message);\r\n this.name = 'FlurArtifactError';\r\n }\r\n}\r\n\r\n// --- base64url helpers (no padding) ---\r\n\r\nexport function base64UrlEncode(bytes: Uint8Array): string {\r\n let bin = '';\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\r\n // btoa is available in browsers, RN (Hermes), and Node >= 16.\r\n const b64 =\r\n typeof btoa === 'function'\r\n ? btoa(bin)\r\n : Buffer.from(bytes).toString('base64');\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\r\n}\r\n\r\nexport function base64UrlDecode(s: string): Uint8Array {\r\n const pad = s.length % 4 === 0 ? '' : '='.repeat(4 - (s.length % 4));\r\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/') + pad;\r\n if (typeof atob === 'function') {\r\n const bin = atob(b64);\r\n const out = new Uint8Array(bin.length);\r\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\r\n return out;\r\n }\r\n return new Uint8Array(Buffer.from(b64, 'base64'));\r\n}\r\n\r\n// --- envelope build / sign / verify ---\r\n\r\nexport function buildArtifactBody<T>(input: {\r\n type: string;\r\n issuer: string;\r\n keyId: string;\r\n data: T;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n nonce: string;\r\n}): ArtifactBody<T> {\r\n if (!ArtifactTypeRe.test(input.type)) {\r\n throw new FlurArtifactError(\r\n `Invalid artifact type: ${input.type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1000);\r\n const header: ArtifactHeader = {\r\n v: FLUR_ARTIFACT_VERSION,\r\n t: input.type,\r\n iss: input.issuer,\r\n kid: input.keyId,\r\n iat,\r\n ...(input.expiresAtSeconds !== undefined\r\n ? { exp: input.expiresAtSeconds }\r\n : {}),\r\n nonce: input.nonce,\r\n };\r\n // Validate header structure early so callers get a clean error.\r\n ArtifactHeaderSchema.parse(header);\r\n return { ...header, data: input.data };\r\n}\r\n\r\nexport function signArtifact<T>(\r\n body: ArtifactBody<T>,\r\n privateKey: Uint8Array,\r\n): SignedArtifact<T> {\r\n const sig = signP256(canonicalJSONBytes(body), privateKey);\r\n return { body, sig };\r\n}\r\n\r\nexport function encodeArtifactUri<T>(signed: SignedArtifact<T>): string {\r\n const bodyBytes = canonicalJSONBytes(signed.body);\r\n const bodyB64 = base64UrlEncode(bodyBytes);\r\n // signed.sig is standard base64; re-encode as base64url for URI transport.\r\n const sigBytes = base64UrlDecode(signed.sig);\r\n const sigB64Url = base64UrlEncode(sigBytes);\r\n return `${FLUR_ARTIFACT_URI_PREFIX}${signed.body.t}/${bodyB64}.${sigB64Url}`;\r\n}\r\n\r\nexport type DecodedArtifactUri = {\r\n type: string;\r\n bodyBytes: Uint8Array;\r\n body: ArtifactBody;\r\n /** ASN.1 DER ECDSA P-256 signature, base64 (standard). */\r\n sig: string;\r\n};\r\n\r\nexport function decodeArtifactUri(uri: string): DecodedArtifactUri {\r\n if (!uri.startsWith(FLUR_ARTIFACT_URI_PREFIX)) {\r\n throw new FlurArtifactError(\r\n `URI does not start with ${FLUR_ARTIFACT_URI_PREFIX}`,\r\n 'INVALID_URI',\r\n );\r\n }\r\n const rest = uri.slice(FLUR_ARTIFACT_URI_PREFIX.length);\r\n const slash = rest.indexOf('/');\r\n if (slash <= 0) {\r\n throw new FlurArtifactError('Missing artifact type segment', 'INVALID_URI');\r\n }\r\n const type = rest.slice(0, slash);\r\n const payload = rest.slice(slash + 1);\r\n const dot = payload.indexOf('.');\r\n if (dot <= 0 || dot === payload.length - 1) {\r\n throw new FlurArtifactError(\r\n 'Missing body/signature separator',\r\n 'INVALID_URI',\r\n );\r\n }\r\n if (!ArtifactTypeRe.test(type)) {\r\n throw new FlurArtifactError(\r\n `Invalid artifact type: ${type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n\r\n const bodyBytes = base64UrlDecode(payload.slice(0, dot));\r\n const sigBytes = base64UrlDecode(payload.slice(dot + 1));\r\n // P-256 ECDSA DER signatures are typically ~70–72 bytes; allow a small\r\n // range to defend against malformed payloads.\r\n if (sigBytes.length < 64 || sigBytes.length > 80) {\r\n throw new FlurArtifactError(\r\n `Signature length out of range: ${sigBytes.length}`,\r\n 'INVALID_SIGNATURE',\r\n );\r\n }\r\n\r\n let bodyJson: unknown;\r\n try {\r\n bodyJson = JSON.parse(new TextDecoder().decode(bodyBytes));\r\n } catch {\r\n throw new FlurArtifactError('Body is not valid JSON', 'INVALID_BODY');\r\n }\r\n\r\n const headerOnly = ArtifactHeaderSchema.safeParse(bodyJson);\r\n if (!headerOnly.success) {\r\n throw new FlurArtifactError(\r\n `Body header invalid: ${headerOnly.error.message}`,\r\n 'INVALID_BODY',\r\n );\r\n }\r\n if (headerOnly.data.t !== type) {\r\n throw new FlurArtifactError(\r\n `URI type ${type} does not match body type ${headerOnly.data.t}`,\r\n 'TYPE_MISMATCH',\r\n );\r\n }\r\n\r\n return {\r\n type,\r\n bodyBytes,\r\n body: bodyJson as ArtifactBody,\r\n // Encode as standard base64 (not url-safe) for sig field consistency.\r\n sig: encodeStdBase64(sigBytes),\r\n };\r\n}\r\n\r\nfunction encodeStdBase64(bytes: Uint8Array): string {\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(bytes).toString('base64');\r\n }\r\n let bin = '';\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\r\n return typeof btoa === 'function' ? btoa(bin) : '';\r\n}\r\n\r\nexport type VerifyArtifactOptions = {\r\n /** Caller-supplied current time (seconds). Defaults to Date.now()/1000. */\r\n nowSeconds?: number;\r\n /** When true (default), reject artifacts whose `exp` is in the past. */\r\n enforceExpiry?: boolean;\r\n};\r\n\r\nexport function verifyArtifactSignature(\r\n decoded: DecodedArtifactUri,\r\n publicKeySpkiB64: string,\r\n options: VerifyArtifactOptions = {},\r\n): boolean {\r\n if (options.enforceExpiry !== false && decoded.body.exp !== undefined) {\r\n const now = options.nowSeconds ?? Math.floor(Date.now() / 1000);\r\n if (decoded.body.exp < now) {\r\n throw new FlurArtifactError('Artifact has expired', 'EXPIRED');\r\n }\r\n }\r\n return verifyP256(decoded.bodyBytes, decoded.sig, publicKeySpkiB64);\r\n}\r\n","import { z } from 'zod';\nimport { OfflinePaymentAuthorizationSchema } from '../offline/messages.js';\n\n/**\n * Registry of all Flur v1 signed artifact types.\n *\n * Each artifact has:\n * - a string discriminator (used in the URI path segment & header `t`),\n * - a Zod schema validating the `data` payload only (envelope header is validated separately).\n *\n * Two artifacts are fully specified in this slice (OPA + Receipt) as the\n * canonical implementation pattern. The remaining nine carry stub schemas\n * (`z.unknown()`) so types compile and the registry is complete; bodies\n * will be locked in subsequent slices once their backend ledger shapes\n * are finalised.\n */\n\nexport const ARTIFACT_TYPES = {\n OFFLINE_PAYMENT_AUTHORIZATION: 'offline_payment_authorization',\n RECEIPT: 'receipt',\n // --- stubs, schemas to be hardened in follow-ups ---\n NQR_PAYMENT_REQUEST: 'nqr_payment_request',\n PAYMENT_INTENT: 'payment_intent',\n OFFLINE_CLAIM: 'offline_claim',\n SETTLEMENT_RECORD: 'settlement_record',\n REVERSAL_RECORD: 'reversal_record',\n LEDGER_JOURNAL_ENTRY: 'ledger_journal_entry',\n STATEMENT: 'statement',\n PASS: 'pass',\n IDENTITY: 'identity',\n} as const;\n\nexport type ArtifactType = (typeof ARTIFACT_TYPES)[keyof typeof ARTIFACT_TYPES];\n\nconst HexString = (length: number) =>\n z\n .string()\n .regex(\n new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),\n `expected ${length}-byte hex string`,\n );\n\n// --- Fully specified: offline_payment_authorization ---\n// Wraps the existing FLUR2: payload in the unified envelope. The inner\n// OfflinePaymentAuthorization is already self-signed; embedding it here\n// adds the device-key issuer attestation + uniform nonce/expiry handling.\nexport const OfflinePaymentAuthorizationArtifactSchema = z.object({\n authorization: OfflinePaymentAuthorizationSchema,\n});\nexport type OfflinePaymentAuthorizationArtifact = z.infer<\n typeof OfflinePaymentAuthorizationArtifactSchema\n>;\n\n// --- Fully specified: receipt ---\n// Payment receipt produced by the payee after a payment settles (online or\n// reconciled from offline). Signed by the issuer's device key so payers and\n// auditors can verify provenance offline.\nexport const ReceiptArtifactSchema = z.object({\n receiptId: z.string().min(1).max(64),\n paymentReference: z.string().min(1).max(64),\n payerUserId: z.string().min(1).max(64).optional(),\n payeeUserId: z.string().min(1).max(64),\n amountKobo: z.number().int().positive(),\n currency: z.literal('NGN'),\n channel: z.enum(['online', 'offline_reconciled', 'pay_link', 'nqr']),\n settledAtMs: z.number().int().positive(),\n ledgerTxnId: z.string().min(1).max(64).optional(),\n memo: z.string().max(140).optional(),\n hashChainPrev: HexString(32).optional(),\n});\nexport type ReceiptArtifact = z.infer<typeof ReceiptArtifactSchema>;\n\n// --- Shared field primitives (reused across the remaining artifacts) ---\nconst ShortId = z.string().min(1).max(64);\nconst PositiveInt = z.number().int().positive();\nconst NonNegativeInt = z.number().int().nonnegative();\nconst Currency = z.literal('NGN');\nconst Memo = z.string().max(140);\n\n// --- nqr_payment_request ---\n// Merchant- or payee-issued payment request rendered as a Flur QR. The amount\n// may be omitted for \"any amount\" / open-tab flows. Verifiers should refuse\n// expired requests and surface `memo` to the payer.\nexport const NqrPaymentRequestArtifactSchema = z.object({\n requestId: ShortId,\n payeeUserId: ShortId,\n amountKobo: PositiveInt.optional(),\n currency: Currency,\n memo: Memo.optional(),\n expiresAtMs: PositiveInt.optional(),\n});\nexport type NqrPaymentRequestArtifact = z.infer<\n typeof NqrPaymentRequestArtifactSchema\n>;\n\n// --- payment_intent ---\n// Payer-side commitment to pay a specific payee. Bound to an idempotency key\n// so a single intent cannot drive multiple settlements server-side.\nexport const PaymentIntentArtifactSchema = z.object({\n intentId: ShortId,\n payerUserId: ShortId,\n payeeUserId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n idempotencyKey: ShortId,\n createdAtMs: PositiveInt,\n});\nexport type PaymentIntentArtifact = z.infer<typeof PaymentIntentArtifactSchema>;\n\n// --- offline_claim ---\n// Payee's signed claim submitted to settle a previously presented OPA.\n// `claimedAmountKobo` may differ from the OPA face value (e.g. partial fills).\nexport const OfflineClaimArtifactSchema = z.object({\n claimId: ShortId,\n authorizationId: ShortId,\n payeeUserId: ShortId,\n claimedAmountKobo: PositiveInt,\n currency: Currency,\n claimedAtMs: PositiveInt,\n paymentReference: ShortId.optional(),\n});\nexport type OfflineClaimArtifact = z.infer<typeof OfflineClaimArtifactSchema>;\n\n// --- settlement_record ---\n// Internal record of a settlement event, linking the source artifact (OPA,\n// claim, transfer, pay-link) to its ledger transaction.\nexport const SettlementRecordArtifactSchema = z.object({\n settlementId: ShortId,\n ledgerTxnId: ShortId,\n sourceRefType: z.enum([\n 'offline_authorization',\n 'offline_claim',\n 'transfer',\n 'pay_link',\n ]),\n sourceRefId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n settledAtMs: PositiveInt,\n});\nexport type SettlementRecordArtifact = z.infer<\n typeof SettlementRecordArtifactSchema\n>;\n\n// --- reversal_record ---\n// Reversal of a prior settled transaction. `reason` is a closed enum so\n// downstream analytics can bucket disputes reliably.\nexport const ReversalRecordArtifactSchema = z.object({\n reversalId: ShortId,\n originalTxnId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n reason: z.enum([\n 'user_dispute',\n 'fraud',\n 'duplicate',\n 'admin_correction',\n 'other',\n ]),\n reversedAtMs: PositiveInt,\n memo: Memo.optional(),\n});\nexport type ReversalRecordArtifact = z.infer<\n typeof ReversalRecordArtifactSchema\n>;\n\n// --- ledger_journal_entry ---\n// One side-balanced double-entry journal line. `debitAccountId` and\n// `creditAccountId` are opaque internal account identifiers.\nexport const LedgerJournalEntryArtifactSchema = z.object({\n entryId: ShortId,\n journalId: ShortId,\n debitAccountId: ShortId,\n creditAccountId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n postedAtMs: PositiveInt,\n refType: ShortId.optional(),\n refId: ShortId.optional(),\n});\nexport type LedgerJournalEntryArtifact = z.infer<\n typeof LedgerJournalEntryArtifactSchema\n>;\n\n// --- statement ---\n// Account-statement summary for a closed period. `hashChainPrev` links to\n// the prior statement for tamper-evident chaining.\nexport const StatementArtifactSchema = z\n .object({\n statementId: ShortId,\n userId: ShortId,\n periodStartMs: PositiveInt,\n periodEndMs: PositiveInt,\n openingBalanceKobo: z.number().int(),\n closingBalanceKobo: z.number().int(),\n transactionCount: NonNegativeInt,\n currency: Currency,\n hashChainPrev: HexString(32).optional(),\n })\n .refine((v) => v.periodEndMs > v.periodStartMs, {\n message: 'periodEndMs must be greater than periodStartMs',\n path: ['periodEndMs'],\n });\nexport type StatementArtifact = z.infer<typeof StatementArtifactSchema>;\n\n// --- pass ---\n// Generic digital pass (membership, ticket, loyalty, access, voucher).\n// `metadata` is intentionally narrow — only scalar values — so canonical\n// JSON ordering remains deterministic across SDK versions.\nexport const PassArtifactSchema = z\n .object({\n passId: ShortId,\n holderId: ShortId,\n category: z.enum(['membership', 'ticket', 'loyalty', 'access', 'voucher']),\n title: z.string().min(1).max(120),\n validFromMs: PositiveInt,\n validUntilMs: PositiveInt.optional(),\n metadata: z\n .record(\n z.string().min(1).max(64),\n z.union([z.string().max(280), z.number(), z.boolean()]),\n )\n .optional(),\n })\n .refine(\n (v) => v.validUntilMs === undefined || v.validUntilMs > v.validFromMs,\n {\n message: 'validUntilMs must be greater than validFromMs',\n path: ['validUntilMs'],\n },\n );\nexport type PassArtifact = z.infer<typeof PassArtifactSchema>;\n\n// --- identity ---\n// Identity attestation. `claimValueHash` is the SHA-256 of the underlying\n// value so the artifact can be shared without leaking PII.\nexport const IdentityArtifactSchema = z.object({\n attestationId: ShortId,\n subjectId: ShortId,\n claimType: z.enum([\n 'phone_verified',\n 'email_verified',\n 'bvn_verified',\n 'kyc_tier',\n 'age_band',\n ]),\n claimValueHash: HexString(32),\n attestedAtMs: PositiveInt,\n});\nexport type IdentityArtifact = z.infer<typeof IdentityArtifactSchema>;\n\nexport const ARTIFACT_BODY_SCHEMAS = {\n [ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]:\n OfflinePaymentAuthorizationArtifactSchema,\n [ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,\n [ARTIFACT_TYPES.NQR_PAYMENT_REQUEST]: NqrPaymentRequestArtifactSchema,\n [ARTIFACT_TYPES.PAYMENT_INTENT]: PaymentIntentArtifactSchema,\n [ARTIFACT_TYPES.OFFLINE_CLAIM]: OfflineClaimArtifactSchema,\n [ARTIFACT_TYPES.SETTLEMENT_RECORD]: SettlementRecordArtifactSchema,\n [ARTIFACT_TYPES.REVERSAL_RECORD]: ReversalRecordArtifactSchema,\n [ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,\n [ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,\n [ARTIFACT_TYPES.PASS]: PassArtifactSchema,\n [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema,\n} as const;\n\n/** Artifact types whose body schema is fully specified and safe to dispatch. */\nexport const HARDENED_ARTIFACT_TYPES = new Set<ArtifactType>([\n ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,\n ARTIFACT_TYPES.RECEIPT,\n ARTIFACT_TYPES.NQR_PAYMENT_REQUEST,\n ARTIFACT_TYPES.PAYMENT_INTENT,\n ARTIFACT_TYPES.OFFLINE_CLAIM,\n ARTIFACT_TYPES.SETTLEMENT_RECORD,\n ARTIFACT_TYPES.REVERSAL_RECORD,\n ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,\n ARTIFACT_TYPES.STATEMENT,\n ARTIFACT_TYPES.PASS,\n ARTIFACT_TYPES.IDENTITY,\n]);\n\nexport function isKnownArtifactType(t: string): t is ArtifactType {\n return (Object.values(ARTIFACT_TYPES) as string[]).includes(t);\n}\n\nexport function isHardenedArtifactType(t: string): t is ArtifactType {\n return HARDENED_ARTIFACT_TYPES.has(t as ArtifactType);\n}\n","import { z } from 'zod';\r\nimport {\r\n decodeArtifactUri,\r\n FlurArtifactError,\r\n type ArtifactBody,\r\n type DecodedArtifactUri,\r\n type SignedArtifact,\r\n type VerifyArtifactOptions,\r\n buildArtifactBody,\r\n signArtifact,\r\n encodeArtifactUri,\r\n verifyArtifactSignature,\r\n} from './envelope.js';\r\nimport {\r\n ARTIFACT_BODY_SCHEMAS,\r\n ARTIFACT_TYPES,\r\n isHardenedArtifactType,\r\n isKnownArtifactType,\r\n type ArtifactType,\r\n type OfflinePaymentAuthorizationArtifact,\r\n type ReceiptArtifact,\r\n} from './types.js';\r\n\r\n/**\r\n * Build, sign and encode a typed artifact into a flur://v1/... URI.\r\n *\r\n * - Validates the body against the registered Zod schema for `type`.\r\n * - Refuses unknown artifact types.\r\n * - Refuses stub types (those without a hardened schema) to avoid shipping\r\n * unverifiable payloads.\r\n */\r\nexport function createArtifactUri<T>(input: {\r\n type: ArtifactType;\r\n issuer: string;\r\n keyId: string;\r\n privateKey: Uint8Array;\r\n data: T;\r\n nonce: string;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n}): { uri: string; signed: SignedArtifact<T> } {\r\n if (!isKnownArtifactType(input.type)) {\r\n throw new FlurArtifactError(\r\n `Unknown artifact type: ${input.type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n if (!isHardenedArtifactType(input.type)) {\r\n throw new FlurArtifactError(\r\n `Artifact type ${input.type} is not yet hardened for emission`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n const schema = ARTIFACT_BODY_SCHEMAS[input.type] as unknown as z.ZodType<T>;\r\n const parsedData = schema.parse(input.data);\r\n\r\n const body = buildArtifactBody({\r\n type: input.type,\r\n issuer: input.issuer,\r\n keyId: input.keyId,\r\n data: parsedData,\r\n nonce: input.nonce,\r\n issuedAtSeconds: input.issuedAtSeconds,\r\n expiresAtSeconds: input.expiresAtSeconds,\r\n });\r\n const signed = signArtifact(body, input.privateKey);\r\n return { uri: encodeArtifactUri(signed), signed };\r\n}\r\n\r\nexport type VerifiedArtifact<T = unknown> = {\r\n type: ArtifactType;\r\n body: ArtifactBody<T>;\r\n sig: string;\r\n decoded: DecodedArtifactUri;\r\n};\r\n\r\n/**\r\n * Decode and verify a flur://v1/... URI.\r\n *\r\n * - Parses the URI and envelope header.\r\n * - Validates the body against the registered Zod schema.\r\n * - Verifies the P-256 ECDSA(SHA-256) DER signature against the supplied public key.\r\n * - Enforces expiry unless `options.enforceExpiry === false`.\r\n *\r\n * The caller is responsible for resolving the public key from (issuer, kid)\r\n * against the backend device-key registry, and for enforcing nonce uniqueness\r\n * via the artifact_nonces store.\r\n */\r\nexport function verifyArtifactUri<T = unknown>(\r\n uri: string,\r\n publicKeySpkiB64: string,\r\n options: VerifyArtifactOptions = {},\r\n): VerifiedArtifact<T> {\r\n const decoded = decodeArtifactUri(uri);\r\n\r\n if (!isKnownArtifactType(decoded.type)) {\r\n throw new FlurArtifactError(\r\n `Unknown artifact type: ${decoded.type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n if (!isHardenedArtifactType(decoded.type)) {\r\n throw new FlurArtifactError(\r\n `Artifact type ${decoded.type} is not yet hardened for verification`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n\r\n const schema = ARTIFACT_BODY_SCHEMAS[decoded.type as ArtifactType];\r\n const dataParsed = schema.safeParse(decoded.body.data);\r\n if (!dataParsed.success) {\r\n throw new FlurArtifactError(\r\n `Artifact body invalid: ${dataParsed.error.message}`,\r\n 'INVALID_BODY',\r\n );\r\n }\r\n\r\n const ok = verifyArtifactSignature(decoded, publicKeySpkiB64, options);\r\n if (!ok) {\r\n throw new FlurArtifactError(\r\n 'Artifact signature verification failed',\r\n 'INVALID_SIGNATURE',\r\n );\r\n }\r\n\r\n return {\r\n type: decoded.type as ArtifactType,\r\n body: decoded.body as ArtifactBody<T>,\r\n sig: decoded.sig,\r\n decoded,\r\n };\r\n}\r\n\r\n// Convenience helpers that pin the artifact-type generic for the two\r\n// hardened artifacts. Useful for app code that wants compile-time guarantees\r\n// without repeating the schema reference.\r\n\r\nexport function createReceiptArtifactUri(input: {\r\n issuer: string;\r\n keyId: string;\r\n privateKey: Uint8Array;\r\n data: ReceiptArtifact;\r\n nonce: string;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n}) {\r\n return createArtifactUri<ReceiptArtifact>({\r\n ...input,\r\n type: ARTIFACT_TYPES.RECEIPT,\r\n });\r\n}\r\n\r\nexport function createOfflinePaymentAuthorizationArtifactUri(input: {\r\n issuer: string;\r\n keyId: string;\r\n privateKey: Uint8Array;\r\n data: OfflinePaymentAuthorizationArtifact;\r\n nonce: string;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n}) {\r\n return createArtifactUri<OfflinePaymentAuthorizationArtifact>({\r\n ...input,\r\n type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,\r\n });\r\n}\r\n"],"mappings":"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","names":["z","z","z","candidate","z","z","CurrencySchema","init","init","z","z","z","z","z","z","sha256","bytesToHex","init","z","sha256","hmac","bytesToHex","z","sha256Hex","bytesToHex","sha256","hmac","defaultNonce","init","z","z","z","Base64Std","z","z","z","init","init","z","z","init","z","z","Base64Std","z","z","Base64Std","init","p256","sha256","ENCOUNTER_DOMAIN","bytesToHex","sha256","bytesToBase64","base64ToBytes","P256_SPKI_HEADER","p256","z","Base64Std","z","z","z","base64UrlEncodeUtf8","base64UrlDecodeUtf8","p256","base64UrlEncodeUtf8","base64UrlDecodeUtf8","sha256","bytesToHex","p256","z","z","init","z","z","z","z","Currency"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/contracts.ts","../src/errors.ts","../src/primitives.ts","../src/collections/client.ts","../src/nqr/fields.ts","../src/nqr/crc16.ts","../src/nqr/tlv.ts","../src/nqr/encoder.ts","../src/nqr/parser.ts","../src/nqr/routing.ts","../src/crypto/canonical.ts","../src/crypto/ct.ts","../src/offline/oac.ts","../src/crypto/p256-issuer.ts","../src/offline/codec.ts","../src/offline/messages.ts","../src/offline/settlements.ts","../src/auth/hmac.ts","../src/partner/client.ts","../src/passes/pass.ts","../src/passes/redemption.ts","../src/receipts/receipt.ts","../src/passes/client.ts","../src/receipts/client.ts","../src/client/flur.ts","../src/accounts/client.ts","../src/me-offline/client.ts","../src/me-offline/revocation.ts","../src/me-offline/signer.ts","../src/me-offline/request.ts","../src/me-offline/settlement.ts","../src/me-offline/oac.ts","../src/me-offline/sms.ts","../src/partner-funding/client.ts","../src/artifacts/envelope.ts","../src/artifacts/types.ts","../src/artifacts/codec.ts"],"sourcesContent":["import { z, type ZodType } from 'zod';\nimport {\n AccountSummaryResponseSchema,\n AuthLogoutRequestSchema,\n AuthRefreshRequestSchema,\n AuthRefreshResponseSchema,\n CreatePayLinkResponseSchema,\n CreateTransferRequestSchema,\n E164Regex,\n HealthResponseSchema,\n OkResponseSchema,\n OnboardingCompleteRequestSchema,\n OnboardingCompleteResponseSchema,\n OnboardingStartRequestSchema,\n OnboardingStartResponseSchema,\n PinSetRequestSchema,\n PinVerifyRequestSchema,\n PushRegisterRequestSchema,\n RegisterDeviceRequestSchema,\n RegisterDeviceResponseSchema,\n RegisterSendDeviceKeyRequestSchema,\n ResolvePayLinkResponseSchema,\n ResolveRecipientRequestSchema,\n ResolveRecipientResponseSchema,\n SendChallengeRequestSchema,\n SendChallengeResponseSchema,\n SendVerifyRequestSchema,\n SendVerifyResponseSchema,\n TransactionDetailResponseSchema,\n TransactionsListResponseSchema,\n TransferResponseSchema,\n WelcomeResponseSchema,\n} from './contracts.js';\nimport { FlurError, mapToFlurError } from './errors.js';\nimport { type Money, moneyMinorToNumber, normalizeE164 } from './primitives.js';\nimport {\n CollectionPaymentResultSchema,\n PayCollectionInputSchema,\n PublicCollectionIntentSchema,\n type CollectionPaymentResult,\n type PayCollectionInput as CollectionPayInput,\n type PublicCollectionIntent,\n} from './collections/index.js';\n\nexport type FlurClientOptions = {\n baseUrl: string;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n getExtraHeaders?: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n};\n\nexport type OnboardingFallback = 'SILENT_AUTH' | 'OTP';\n\nexport type OnboardingStartInput = {\n phoneE164: string;\n appInstanceId: string;\n platform: 'android' | 'ios' | 'web';\n turnstileToken?: string;\n appAttestation?: {\n provider: 'android' | 'ios' | 'web';\n token: string;\n };\n firstName?: string;\n lastName?: string;\n};\n\nexport type OnboardingStartResponse = {\n requestId: string;\n checkUrl?: string;\n expiresInSec: number;\n fallback: OnboardingFallback;\n};\n\nexport type OnboardingRiskReason =\n | 'SIM_SWAP_RECENT'\n | 'ROAMING'\n | 'CARRIER_CHANGED';\n\nexport type OnboardingCompleteInput = {\n requestId: string;\n code: string;\n appInstanceId: string;\n fingerprintHash?: string;\n};\n\nexport type OnboardingCompleteResponse = {\n accessToken: string;\n refreshToken: string;\n userId: string;\n restricted: boolean;\n risk_reasons: OnboardingRiskReason[];\n stepUpRequired?: boolean;\n riskStatus?: 'ok' | 'unavailable';\n};\n\nexport type RegisterDeviceInput = {\n userId: string;\n appInstanceId: string;\n platform: string;\n model?: string;\n networkSignals: {\n ip?: string;\n asn?: number;\n country?: string;\n carrier?: string;\n };\n};\n\nexport type DeviceTrustState =\n | 'TRUSTED_PRIMARY'\n | 'TRUSTED_SECONDARY'\n | 'UNVERIFIED';\n\nexport type RegisterDeviceResponse = {\n deviceId: string;\n fingerprintHash: string;\n driftScore: number;\n trustState: DeviceTrustState;\n stepUpRequired: boolean;\n};\n\nexport type AuthRefreshInput = {\n userId: string;\n refreshToken: string;\n appInstanceId: string;\n fingerprintHash: string;\n};\n\nexport type AuthRefreshResponse = {\n accessToken: string;\n refreshToken: string;\n stepUpRequired: boolean;\n};\n\nexport type AuthLogoutInput = {\n userId: string;\n refreshToken: string;\n};\n\nexport type PinSetInput = {\n userId: string;\n pin: string;\n};\n\nexport type PinVerifyInput = {\n userId: string;\n pin: string;\n};\n\nexport type RegisterSendDeviceKeyInput = {\n userId: string;\n deviceId: string;\n publicKey: string;\n};\n\nexport type SendChallengeInput = {\n userId: string;\n deviceId: string;\n /** Optional step-up purpose. Backend defaults to 'send_money'. */\n purpose?: 'send_money' | 'offline_revoke';\n};\n\nexport type SendChallengeResponse = {\n challengeId: string;\n nonce: string;\n expiresAt: string;\n};\n\nexport type SendVerifyInput = {\n userId: string;\n deviceId: string;\n challengeId: string;\n signature: string;\n};\n\nexport type SendVerifyResponse = {\n sendAuthToken: string;\n};\n\nexport type RecipientResolveInput = {\n identifier: string;\n};\n\nexport type RecipientResolveResponse = {\n recipientUserId: string;\n displayName: string;\n normalizedIdentifier: string;\n isActive: boolean;\n};\n\nexport type TransferInput = {\n recipientIdentifier: string;\n amountMinor: number;\n currency: string;\n sendAuthToken: string;\n};\n\nexport type TransferStatus = 'SETTLED' | 'PENDING_REVIEW' | 'DECLINED';\n\n/**\n * Successful response from `POST /api/v1/transfers`. Derived directly\n * from the canonical Zod schema so the static type and the runtime\n * parser stay in lockstep with the backend response.\n */\nexport type TransferResponse = z.infer<typeof TransferResponseSchema>;\n\nexport type TransactionDirection = 'OUTGOING' | 'INCOMING';\n\nexport type AccountActivityItem = {\n id: string;\n type: string;\n direction: TransactionDirection;\n name: string;\n identifier: string;\n amountMinor: number;\n currency: string;\n status: string;\n timestamp: string;\n};\n\nexport type AccountSummaryResponse = {\n userId: string;\n nuban: string | null;\n balance: number;\n currency: string;\n dailySendLimit: number;\n dailySendRemaining: number;\n kycTier: string;\n kycStatus: string;\n recentActivity: AccountActivityItem[];\n};\n\nexport type TransactionsListResponse = {\n items: AccountActivityItem[];\n nextCursor: string | null;\n};\n\nexport type TransactionDetailResponse = {\n transactionId: string;\n type: string;\n direction: TransactionDirection;\n counterpartyName: string;\n counterpartyIdentifier: string;\n amountMinor: number;\n currency: string;\n status: string;\n timestamp: string;\n};\n\nexport type PushPlatform = 'ios' | 'android' | 'web';\n\nexport type PushRegisterInput = {\n deviceId: string;\n platform: PushPlatform;\n token: string;\n};\n\nexport type CreatePayLinkResponse = {\n token: string;\n};\n\nexport type ResolvePayLinkResponse = {\n recipientUserId: string;\n displayName: string;\n normalizedIdentifier: string;\n isActive: boolean;\n};\n\nexport type AuthorizedOptions = {\n accessToken: string;\n};\n\nexport type CreateTransferOptions = AuthorizedOptions & {\n deviceId: string;\n idempotencyKey: string;\n};\n\nexport type ListTransactionsOptions = AuthorizedOptions & {\n cursor?: string;\n limit?: number;\n};\n\nexport type BiometricSigner = {\n getOrCreateKeyPair(deviceId: string): Promise<string>;\n sign(payload: string): Promise<string>;\n};\n\nexport type SendMoneyInput = {\n recipientIdentifier: string;\n money: Money;\n sendAuthToken: string;\n /**\n * Stable, caller-owned idempotency key. REQUIRED: generate one per logical\n * transfer and reuse it across retries so a dropped response can never settle\n * the same transfer twice.\n */\n idempotencyKey: string;\n defaultCountry?: string;\n};\n\nexport type SendMoneyOptions = AuthorizedOptions & {\n deviceId: string;\n};\n\nexport type ResolveCollectionOptions = AuthorizedOptions;\n\nexport type PayCollectionOptions = AuthorizedOptions & {\n idempotencyKey?: string;\n};\n\nexport type ResolveCollectionResponse = PublicCollectionIntent;\nexport type PayCollectionResponse = CollectionPaymentResult;\n\nexport type AuthorizeSendWithBiometricInput = {\n userId: string;\n deviceId: string;\n accessToken: string;\n signer: BiometricSigner;\n};\n\nexport class FlurClient {\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly getExtraHeaders?: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n\n constructor(opts: FlurClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.fetchImpl = opts.fetchImpl ?? fetch;\n this.timeoutMs = opts.timeoutMs ?? 10_000;\n this.getExtraHeaders = opts.getExtraHeaders;\n }\n\n async health(): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/health',\n { method: 'GET' },\n undefined,\n HealthResponseSchema,\n );\n }\n\n async welcome(): Promise<{ message: string }> {\n return this.requestJson(\n '/welcome',\n { method: 'GET' },\n undefined,\n WelcomeResponseSchema,\n );\n }\n\n async onboardingStart(\n input: OnboardingStartInput,\n ): Promise<OnboardingStartResponse> {\n return this.requestJson(\n '/v1/onboarding/start',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n },\n OnboardingStartRequestSchema,\n OnboardingStartResponseSchema,\n input,\n );\n }\n\n async onboardingComplete(\n input: OnboardingCompleteInput,\n ): Promise<OnboardingCompleteResponse> {\n return this.requestJson(\n '/v1/onboarding/complete',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n },\n OnboardingCompleteRequestSchema,\n OnboardingCompleteResponseSchema,\n input,\n );\n }\n\n async registerDevice(\n input: RegisterDeviceInput,\n options: AuthorizedOptions,\n ): Promise<RegisterDeviceResponse> {\n return this.requestJson(\n '/v1/devices/register',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n RegisterDeviceRequestSchema,\n RegisterDeviceResponseSchema,\n input,\n );\n }\n\n async authRefresh(input: AuthRefreshInput): Promise<AuthRefreshResponse> {\n return this.requestJson(\n '/v1/auth/refresh',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n },\n AuthRefreshRequestSchema,\n AuthRefreshResponseSchema,\n input,\n );\n }\n\n async authLogout(\n input: AuthLogoutInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/v1/auth/logout',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n AuthLogoutRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async pinSet(\n input: PinSetInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/v1/auth/pin/set',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n PinSetRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async pinVerify(\n input: PinVerifyInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/v1/auth/pin/verify',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n PinVerifyRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async registerSendDeviceKey(\n input: RegisterSendDeviceKeyInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/api/v1/auth/send/device-key',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n RegisterSendDeviceKeyRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async createSendChallenge(\n input: SendChallengeInput,\n options: AuthorizedOptions,\n ): Promise<SendChallengeResponse> {\n return this.requestJson(\n '/api/v1/auth/send/challenge',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n SendChallengeRequestSchema,\n SendChallengeResponseSchema,\n input,\n );\n }\n\n async verifySendChallenge(\n input: SendVerifyInput,\n options: AuthorizedOptions,\n ): Promise<SendVerifyResponse> {\n return this.requestJson(\n '/api/v1/auth/send/verify',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n SendVerifyRequestSchema,\n SendVerifyResponseSchema,\n input,\n );\n }\n\n async registerBiometricDeviceKey(input: {\n userId: string;\n deviceId: string;\n accessToken: string;\n signer: BiometricSigner;\n }): Promise<{ ok: boolean }> {\n const publicKey = await input.signer.getOrCreateKeyPair(input.deviceId);\n return this.registerSendDeviceKey(\n {\n userId: input.userId,\n deviceId: input.deviceId,\n publicKey,\n },\n { accessToken: input.accessToken },\n );\n }\n\n async authorizeSendWithBiometric(\n input: AuthorizeSendWithBiometricInput,\n ): Promise<SendVerifyResponse> {\n const challenge = await this.createSendChallenge(\n {\n userId: input.userId,\n deviceId: input.deviceId,\n },\n { accessToken: input.accessToken },\n );\n\n const signature = await input.signer.sign(challenge.nonce);\n return this.verifySendChallenge(\n {\n userId: input.userId,\n deviceId: input.deviceId,\n challengeId: challenge.challengeId,\n signature,\n },\n { accessToken: input.accessToken },\n );\n }\n\n async resolveRecipient(\n input: RecipientResolveInput,\n options: AuthorizedOptions,\n ): Promise<RecipientResolveResponse> {\n return this.requestJson(\n '/api/v1/recipients/resolve',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n ResolveRecipientRequestSchema,\n ResolveRecipientResponseSchema,\n input,\n );\n }\n\n async createTransfer(\n input: TransferInput,\n options: CreateTransferOptions,\n ): Promise<TransferResponse> {\n return this.requestJson(\n '/api/v1/transfers',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n 'x-device-id': options.deviceId,\n 'x-idempotency-key': options.idempotencyKey,\n },\n },\n CreateTransferRequestSchema,\n TransferResponseSchema,\n input,\n );\n }\n\n async sendMoney(\n input: SendMoneyInput,\n options: SendMoneyOptions,\n ): Promise<TransferResponse> {\n const normalizedRecipient = E164Regex.test(input.recipientIdentifier)\n ? input.recipientIdentifier\n : normalizeE164(input.recipientIdentifier, input.defaultCountry);\n\n const idempotencyKey = input.idempotencyKey?.trim();\n if (!idempotencyKey) {\n throw new Error(\n 'Flur SDK: sendMoney requires a stable idempotencyKey. Generate one per ' +\n 'logical transfer and reuse it across retries to prevent double-spends.',\n );\n }\n return this.createTransfer(\n {\n recipientIdentifier: normalizedRecipient,\n amountMinor: moneyMinorToNumber(input.money.amountMinor),\n currency: input.money.currency,\n sendAuthToken: input.sendAuthToken,\n },\n {\n accessToken: options.accessToken,\n deviceId: options.deviceId,\n idempotencyKey,\n },\n );\n }\n\n async resolveCollection(\n reference: string,\n options: ResolveCollectionOptions,\n ): Promise<ResolveCollectionResponse> {\n return this.requestJson(\n `/v1/collections/resolve/${encodeURIComponent(reference)}`,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n PublicCollectionIntentSchema,\n );\n }\n\n async payCollection(\n input: CollectionPayInput,\n options: PayCollectionOptions,\n ): Promise<PayCollectionResponse> {\n const idempotencyKey = (\n input.idempotencyKey ?? options.idempotencyKey\n )?.trim();\n if (!idempotencyKey) {\n throw new Error(\n 'Flur SDK: payCollection requires a stable idempotencyKey (on the input ' +\n 'or options). Reuse it across retries to prevent paying a collection twice.',\n );\n }\n return this.requestJson(\n '/v1/collections/pay',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n 'x-idempotency-key': idempotencyKey,\n },\n },\n PayCollectionInputSchema,\n CollectionPaymentResultSchema,\n { ...input, idempotencyKey },\n );\n }\n\n async accountSummary(\n options: AuthorizedOptions,\n ): Promise<AccountSummaryResponse> {\n return this.requestJson(\n '/api/v1/account/summary',\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n AccountSummaryResponseSchema,\n );\n }\n\n async listTransactions(\n options: ListTransactionsOptions,\n ): Promise<TransactionsListResponse> {\n const query = new URLSearchParams();\n if (\n typeof options.cursor === 'string' &&\n options.cursor.trim().length > 0\n ) {\n query.set('cursor', options.cursor);\n }\n if (typeof options.limit === 'number') {\n query.set('limit', String(options.limit));\n }\n\n const path =\n query.size > 0\n ? `/api/v1/transactions?${query.toString()}`\n : '/api/v1/transactions';\n return this.requestJson(\n path,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n TransactionsListResponseSchema,\n );\n }\n\n async transactionDetail(\n transactionId: string,\n options: AuthorizedOptions,\n ): Promise<TransactionDetailResponse> {\n const encodedId = encodeURIComponent(transactionId);\n return this.requestJson(\n `/api/v1/transactions/${encodedId}`,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n TransactionDetailResponseSchema,\n );\n }\n\n async registerPushToken(\n input: PushRegisterInput,\n options: AuthorizedOptions,\n ): Promise<{ ok: boolean }> {\n return this.requestJson(\n '/api/v1/push/register',\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n PushRegisterRequestSchema,\n OkResponseSchema,\n input,\n );\n }\n\n async createPayLink(\n options: AuthorizedOptions,\n ): Promise<CreatePayLinkResponse> {\n return this.requestJson(\n '/api/v1/pay-links',\n {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n CreatePayLinkResponseSchema,\n );\n }\n\n async resolvePayLink(\n token: string,\n options: AuthorizedOptions,\n ): Promise<ResolvePayLinkResponse> {\n const encodedToken = encodeURIComponent(token);\n return this.requestJson(\n `/api/v1/pay-links/${encodedToken}`,\n {\n method: 'GET',\n headers: {\n authorization: `Bearer ${options.accessToken}`,\n },\n },\n undefined,\n ResolvePayLinkResponseSchema,\n );\n }\n\n private async requestJson<TInput, TOutput>(\n path: string,\n init: RequestInit,\n requestSchema?: ZodType<TInput>,\n responseSchema?: ZodType<TOutput>,\n input?: TInput,\n ): Promise<TOutput> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const t = setTimeout(() => controller.abort(), this.timeoutMs);\n let body = init.body;\n try {\n body = requestSchema\n ? JSON.stringify(requestSchema.parse(input))\n : init.body;\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new FlurError('Invalid request payload', 'INVALID_REQUEST', {\n details: err.flatten(),\n });\n }\n throw err;\n }\n\n try {\n let extraHeaders: Record<string, string> = {};\n if (this.getExtraHeaders) {\n extraHeaders = await this.getExtraHeaders();\n }\n\n const finalHeaders = {\n ...init.headers,\n ...extraHeaders,\n };\n\n const res = await this.fetchImpl(url, {\n ...init,\n headers: finalHeaders,\n body,\n signal: controller.signal,\n });\n if (!res.ok) throw await mapToFlurError(res);\n const payload = (await res.json()) as unknown;\n if (!responseSchema) return payload as TOutput;\n try {\n return responseSchema.parse(payload);\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new FlurError(\n 'SDK contract validation failed',\n 'INVALID_REQUEST',\n {\n details: err.flatten(),\n },\n );\n }\n throw err;\n }\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new FlurError('Request timed out', 'TIMEOUT');\n }\n if (err instanceof FlurError) throw err;\n throw new FlurError('Network error', 'NETWORK_ERROR', {\n details: String(err),\n });\n } finally {\n clearTimeout(t);\n }\n }\n}\n","import { z } from 'zod';\n\nexport const E164Regex = /^\\+[1-9]\\d{7,14}$/;\n\nconst UuidSchema = z.string().uuid();\nconst IsoDateSchema = z.string().datetime({ offset: true });\nconst CurrencySchema = z\n .string()\n .trim()\n .length(3)\n .transform((value) => value.toUpperCase());\n\nexport const HealthResponseSchema = z.object({\n ok: z.boolean(),\n});\n\nexport const WelcomeResponseSchema = z.object({\n message: z.string(),\n});\n\nexport const OnboardingStartRequestSchema = z.object({\n phoneE164: z.string().regex(E164Regex),\n appInstanceId: z.string().min(3),\n platform: z.enum(['android', 'ios', 'web']),\n turnstileToken: z.string().min(20).optional(),\n appAttestation: z\n .object({\n provider: z.enum(['android', 'ios', 'web']),\n token: z.string().min(24),\n })\n .optional(),\n firstName: z.string().trim().min(1).max(80).optional(),\n lastName: z.string().trim().min(1).max(80).optional(),\n});\n\nexport const OnboardingStartResponseSchema = z.object({\n requestId: z.string().min(1),\n checkUrl: z.string().url().optional(),\n expiresInSec: z.number().int().positive(),\n fallback: z.enum(['SILENT_AUTH', 'OTP']),\n});\n\nexport const OnboardingCompleteRequestSchema = z.object({\n requestId: z.string().min(1),\n code: z.string().min(1).max(32),\n appInstanceId: z.string().min(3),\n fingerprintHash: z.string().min(3).optional(),\n});\n\nexport const OnboardingCompleteResponseSchema = z.object({\n accessToken: z.string().min(8),\n refreshToken: z.string().min(8),\n userId: UuidSchema,\n restricted: z.boolean(),\n risk_reasons: z.array(\n z.enum(['SIM_SWAP_RECENT', 'ROAMING', 'CARRIER_CHANGED']),\n ),\n stepUpRequired: z.boolean().optional(),\n riskStatus: z.enum(['ok', 'unavailable']).optional(),\n});\n\nexport const RegisterDeviceRequestSchema = z.object({\n userId: UuidSchema,\n appInstanceId: z.string().min(3),\n platform: z.string().min(2),\n model: z.string().optional(),\n networkSignals: z.object({\n ip: z.string().min(3).optional(),\n asn: z.number().int().optional(),\n country: z.string().min(2).optional(),\n carrier: z.string().optional(),\n }),\n});\n\nexport const RegisterDeviceResponseSchema = z.object({\n deviceId: z.string().min(1),\n fingerprintHash: z.string().min(1),\n driftScore: z.number(),\n trustState: z.enum(['TRUSTED_PRIMARY', 'TRUSTED_SECONDARY', 'UNVERIFIED']),\n stepUpRequired: z.boolean(),\n});\n\nexport const AuthRefreshRequestSchema = z.object({\n userId: UuidSchema,\n refreshToken: z.string().min(8),\n appInstanceId: z.string().min(3),\n fingerprintHash: z.string().min(3),\n});\n\nexport const AuthRefreshResponseSchema = z.object({\n accessToken: z.string().min(8),\n refreshToken: z.string().min(8),\n stepUpRequired: z.boolean(),\n});\n\nexport const AuthLogoutRequestSchema = z.object({\n userId: UuidSchema,\n refreshToken: z.string().min(8),\n});\n\nexport const PinSetRequestSchema = z.object({\n userId: UuidSchema,\n pin: z.string().regex(/^\\d{6}$/),\n});\n\nexport const PinVerifyRequestSchema = z.object({\n userId: UuidSchema,\n pin: z.string().regex(/^\\d{6}$/),\n});\n\nexport const OkResponseSchema = z.object({\n ok: z.boolean(),\n});\n\nexport const RegisterSendDeviceKeyRequestSchema = z.object({\n userId: UuidSchema,\n deviceId: z.string().min(3),\n publicKey: z.string().min(32),\n});\n\n/**\n * Supported step-up purposes for /api/v1/auth/send/challenge.\n * Mirrors `SUPPORTED_SEND_AUTH_PURPOSES` in flur-backend/src/routes/auth.ts.\n * Defaults to 'send_money' server-side when omitted.\n */\nexport const SEND_AUTH_PURPOSES = ['send_money', 'offline_revoke'] as const;\nexport type SendAuthPurpose = (typeof SEND_AUTH_PURPOSES)[number];\n\nexport const SendChallengeRequestSchema = z.object({\n userId: UuidSchema,\n deviceId: z.string().min(3),\n purpose: z.enum(SEND_AUTH_PURPOSES).optional(),\n});\n\nexport const SendChallengeResponseSchema = z.object({\n challengeId: UuidSchema,\n nonce: z.string().min(1),\n expiresAt: IsoDateSchema,\n});\n\nexport const SendVerifyRequestSchema = z.object({\n userId: UuidSchema,\n deviceId: z.string().min(3),\n challengeId: UuidSchema,\n signature: z.string().min(16),\n});\n\nexport const SendVerifyResponseSchema = z.object({\n sendAuthToken: z.string().min(16),\n});\n\nexport const ResolveRecipientRequestSchema = z.object({\n identifier: z.string().min(3),\n});\n\nexport const ResolveRecipientResponseSchema = z.object({\n recipientUserId: UuidSchema,\n displayName: z.string().min(1),\n normalizedIdentifier: z.string().regex(E164Regex),\n isActive: z.boolean(),\n});\n\nexport const CreateTransferRequestSchema = z.object({\n recipientIdentifier: z.string().min(3),\n amountMinor: z.number().int().positive(),\n currency: CurrencySchema,\n sendAuthToken: z.string().min(16),\n});\n\nconst TransferStatusSchema = z.enum(['SETTLED', 'PENDING_REVIEW', 'DECLINED']);\n\nexport const TransferResponseSchema = z.object({\n transactionId: z.string().min(1),\n status: TransferStatusSchema,\n userStatus: TransferStatusSchema,\n recipientName: z.string().min(1),\n timestamp: IsoDateSchema,\n});\n\nconst DirectionSchema = z.enum(['OUTGOING', 'INCOMING']);\n\nexport const AccountActivityItemSchema = z.object({\n id: z.string().min(1),\n type: z.string().min(1),\n direction: DirectionSchema,\n name: z.string().min(1),\n identifier: z.string().min(1),\n amountMinor: z.number().int(),\n currency: CurrencySchema,\n status: z.string().min(1),\n timestamp: IsoDateSchema,\n});\n\nexport const AccountSummaryResponseSchema = z.object({\n /** Authenticated user's stable internal id. */\n userId: UuidSchema,\n /**\n * 10-digit Nigeria Uniform Bank Account Number (NUBAN) allocated by the\n * bank partner. `null` when the user has no partner-allocated account yet.\n */\n nuban: z\n .string()\n .regex(/^[0-9]{10}$/)\n .nullable(),\n balance: z.number().int(),\n currency: CurrencySchema,\n dailySendLimit: z.number().int().nonnegative(),\n dailySendRemaining: z.number().int().nonnegative(),\n kycTier: z.string().min(1),\n kycStatus: z.string().min(1),\n recentActivity: z.array(AccountActivityItemSchema),\n});\n\nexport const TransactionsListResponseSchema = z.object({\n items: z.array(AccountActivityItemSchema),\n nextCursor: z.string().nullable(),\n});\n\nexport const TransactionDetailResponseSchema = z.object({\n transactionId: z.string().min(1),\n type: z.string().min(1),\n direction: DirectionSchema,\n counterpartyName: z.string().min(1),\n counterpartyIdentifier: z.string().min(1),\n amountMinor: z.number().int(),\n currency: CurrencySchema,\n status: z.string().min(1),\n timestamp: IsoDateSchema,\n});\n\nexport const PushRegisterRequestSchema = z.object({\n deviceId: z.string().min(3),\n platform: z.enum(['ios', 'android', 'web']),\n token: z.string().min(16),\n});\n\nexport const CreatePayLinkResponseSchema = z.object({\n token: z.string().min(1),\n});\n\nexport const ResolvePayLinkResponseSchema = z.object({\n recipientUserId: UuidSchema,\n displayName: z.string().min(1),\n normalizedIdentifier: z.string().regex(E164Regex),\n isActive: z.boolean(),\n});\n","export type FlurErrorCode =\r\n | 'NETWORK_ERROR'\r\n | 'HTTP_ERROR'\r\n | 'TIMEOUT'\r\n | 'UNKNOWN'\r\n | 'UNAUTHORIZED'\r\n | 'INVALID_REQUEST'\r\n | 'RATE_LIMITED'\r\n | 'NOT_FOUND'\r\n | 'USER_NOT_FOUND'\r\n | 'TOKEN_REPLAYED'\r\n | 'SESSION_MISMATCH'\r\n | 'PIN_INVALID'\r\n | 'PIN_LOCKED'\r\n | 'PIN_NOT_SET'\r\n | 'STEP_UP_REQUIRED'\r\n | 'DEVICE_KEY_NOT_REGISTERED'\r\n | 'CHALLENGE_INVALID'\r\n | 'CHALLENGE_EXPIRED'\r\n | 'DEVICE_KEY_REVOKED'\r\n | 'SIGNATURE_INVALID'\r\n | 'INVALID_RECIPIENT'\r\n | 'SEND_AUTH_INVALID'\r\n | 'IDEMPOTENCY_KEY_CONFLICT'\r\n | 'IDEMPOTENCY_IN_PROGRESS'\r\n | 'CANNOT_SEND_TO_SELF'\r\n | 'INSUFFICIENT_FUNDS';\r\n\r\nconst backendErrorCodeSet: ReadonlySet<FlurErrorCode> = new Set([\r\n 'UNAUTHORIZED',\r\n 'INVALID_REQUEST',\r\n 'RATE_LIMITED',\r\n 'NOT_FOUND',\r\n 'USER_NOT_FOUND',\r\n 'TOKEN_REPLAYED',\r\n 'SESSION_MISMATCH',\r\n 'PIN_INVALID',\r\n 'PIN_LOCKED',\r\n 'PIN_NOT_SET',\r\n 'STEP_UP_REQUIRED',\r\n 'DEVICE_KEY_NOT_REGISTERED',\r\n 'CHALLENGE_INVALID',\r\n 'CHALLENGE_EXPIRED',\r\n 'DEVICE_KEY_REVOKED',\r\n 'SIGNATURE_INVALID',\r\n 'INVALID_RECIPIENT',\r\n 'SEND_AUTH_INVALID',\r\n 'IDEMPOTENCY_KEY_CONFLICT',\r\n 'IDEMPOTENCY_IN_PROGRESS',\r\n 'CANNOT_SEND_TO_SELF',\r\n 'INSUFFICIENT_FUNDS',\r\n]);\r\n\r\nexport class FlurError extends Error {\r\n public readonly code: FlurErrorCode;\r\n public readonly status?: number;\r\n public readonly details?: unknown;\r\n public readonly reqId?: string | null;\r\n\r\n constructor(\r\n message: string,\r\n code: FlurErrorCode,\r\n opts?: { status?: number; details?: unknown; reqId?: string | null },\r\n ) {\r\n super(message);\r\n this.name = 'FlurError';\r\n this.code = code;\r\n this.status = opts?.status;\r\n this.details = opts?.details;\r\n this.reqId = opts?.reqId;\r\n }\r\n}\r\n\r\n/**\r\n * Generic API error thrown by HTTP clients in `flur.passes` / `flur.receipts`\r\n * for non-2xx responses. Lives at the SDK root so bounded-context modules\r\n * (passes, receipts) never cross-import each other.\r\n */\r\nexport class FlurApiError extends Error {\r\n constructor(\r\n public readonly status: number,\r\n public readonly code: string,\r\n message: string,\r\n public readonly raw?: unknown,\r\n ) {\r\n super(message);\r\n this.name = 'FlurApiError';\r\n }\r\n}\r\n\r\n/** Thrown by `buildRedemption` when the pass is past its `validUntilMs`. */\r\nexport class FlurExpiredError extends Error {\r\n public readonly code = 'PASS_EXPIRED' as const;\r\n constructor(message = 'pass is expired') {\r\n super(message);\r\n this.name = 'FlurExpiredError';\r\n }\r\n}\r\n\r\n/** Thrown by `buildRedemption` when `counter` is not strictly greater than the\r\n * caller-supplied `lastSeenCounter` (replay / out-of-order redemption attempt). */\r\nexport class FlurReplayError extends Error {\r\n public readonly code = 'PASS_REPLAY' as const;\r\n constructor(message = 'redemption counter is not strictly increasing') {\r\n super(message);\r\n this.name = 'FlurReplayError';\r\n }\r\n}\r\n\r\n/** Thrown by `buildRedemption` when this redemption would breach the pass's\r\n * `cumulativeCapKobo` given the caller-supplied `cumulativeUsedKobo`. */\r\nexport class FlurCapExceededError extends Error {\r\n public readonly code = 'PASS_CAP_EXCEEDED' as const;\r\n constructor(message = 'redemption exceeds cumulative cap') {\r\n super(message);\r\n this.name = 'FlurCapExceededError';\r\n }\r\n}\r\n\r\nexport async function mapToFlurError(res: Response): Promise<FlurError> {\r\n const reqId = res.headers.get('x-request-id');\r\n let details: unknown = undefined;\r\n let mappedCode: FlurErrorCode = 'HTTP_ERROR';\r\n let mappedMessage = `HTTP ${res.status}`;\r\n try {\r\n const ct = res.headers.get('content-type') ?? '';\r\n details = ct.includes('application/json')\r\n ? await res.json()\r\n : await res.text();\r\n if (details && typeof details === 'object') {\r\n const candidateCode = (details as { code?: unknown }).code;\r\n const candidateMessage = (\r\n details as { message?: unknown; error?: unknown }\r\n ).message;\r\n const fallbackMessage = (details as { error?: unknown }).error;\r\n\r\n if (\r\n typeof candidateCode === 'string' &&\r\n backendErrorCodeSet.has(candidateCode as FlurErrorCode)\r\n ) {\r\n mappedCode = candidateCode as FlurErrorCode;\r\n }\r\n\r\n if (typeof candidateMessage === 'string' && candidateMessage.length > 0) {\r\n mappedMessage = candidateMessage;\r\n } else if (\r\n typeof fallbackMessage === 'string' &&\r\n fallbackMessage.length > 0\r\n ) {\r\n mappedMessage = fallbackMessage;\r\n }\r\n }\r\n } catch {\r\n // ignore parse issues\r\n }\r\n return new FlurError(mappedMessage, mappedCode, {\r\n status: res.status,\r\n details,\r\n reqId,\r\n });\r\n}\r\n","import { z } from \"zod\";\r\nimport { FlurError } from \"./errors.js\";\r\nimport { E164Regex } from \"./contracts.js\";\r\n\r\nexport type Money = {\r\n amountMinor: bigint;\r\n currency: string;\r\n};\r\n\r\nconst CurrencyCodeSchema = z.string().trim().length(3).transform((value) => value.toUpperCase());\r\n\r\nconst currencyFractionDigits: Record<string, number> = {\r\n NGN: 2,\r\n USD: 2,\r\n EUR: 2,\r\n GBP: 2,\r\n CAD: 2,\r\n JPY: 0,\r\n};\r\n\r\nfunction getFractionDigits(currency: string): number {\r\n return currencyFractionDigits[currency] ?? 2;\r\n}\r\n\r\nexport function parseAmountInput(value: string, currency: string): Money {\r\n const normalizedCurrency = CurrencyCodeSchema.parse(currency);\r\n const raw = value.trim();\r\n\r\n if (!/^\\d+(\\.\\d+)?$/.test(raw)) {\r\n throw new FlurError(\"Invalid amount format\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const [whole, fraction = \"\"] = raw.split(\".\");\r\n const fractionDigits = getFractionDigits(normalizedCurrency);\r\n\r\n if (fraction.length > fractionDigits) {\r\n throw new FlurError(\"Too many decimal places for currency\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const paddedFraction = fraction.padEnd(fractionDigits, \"0\");\r\n const minorAsString = `${whole}${paddedFraction}`.replace(/^0+(\\d)/, \"$1\") || \"0\";\r\n const amountMinor = BigInt(minorAsString);\r\n\r\n if (amountMinor < 0n) {\r\n throw new FlurError(\"Amount cannot be negative\", \"INVALID_REQUEST\");\r\n }\r\n\r\n return {\r\n amountMinor,\r\n currency: normalizedCurrency,\r\n };\r\n}\r\n\r\nexport function formatAmount(amountMinor: bigint, currency: string): string {\r\n const normalizedCurrency = CurrencyCodeSchema.parse(currency);\r\n if (amountMinor < 0n) {\r\n throw new FlurError(\"Amount cannot be negative\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const fractionDigits = getFractionDigits(normalizedCurrency);\r\n if (fractionDigits === 0) {\r\n return amountMinor.toString();\r\n }\r\n\r\n const divisor = 10n ** BigInt(fractionDigits);\r\n const whole = amountMinor / divisor;\r\n const fraction = (amountMinor % divisor).toString().padStart(fractionDigits, \"0\");\r\n return `${whole.toString()}.${fraction}`;\r\n}\r\n\r\nconst defaultCountryDialingCode: Record<string, string> = {\r\n NG: \"234\",\r\n US: \"1\",\r\n CA: \"1\",\r\n GB: \"44\",\r\n};\r\n\r\nexport function normalizeE164(input: string, defaultCountry?: string): string {\r\n const trimmed = input.trim();\r\n\r\n if (trimmed.startsWith(\"+\")) {\r\n if (!E164Regex.test(trimmed)) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n return trimmed;\r\n }\r\n\r\n const digits = trimmed.replace(/\\D/g, \"\");\r\n if (digits.length === 0) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n\r\n if (digits.startsWith(\"00\")) {\r\n const candidate = `+${digits.slice(2)}`;\r\n if (!E164Regex.test(candidate)) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n return candidate;\r\n }\r\n\r\n const normalizedCountry = defaultCountry?.trim().toUpperCase();\r\n const countryCode = normalizedCountry ? defaultCountryDialingCode[normalizedCountry] : undefined;\r\n if (!countryCode) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n\r\n const localDigits = digits.startsWith(\"0\") ? digits.slice(1) : digits;\r\n const candidate = `+${countryCode}${localDigits}`;\r\n if (!E164Regex.test(candidate)) {\r\n throw new FlurError(\"Invalid phone number\", \"INVALID_REQUEST\");\r\n }\r\n return candidate;\r\n}\r\n\r\nexport function moneyMinorToNumber(amountMinor: bigint): number {\r\n const asNumber = Number(amountMinor);\r\n if (!Number.isSafeInteger(asNumber)) {\r\n throw new FlurError(\"Amount exceeds safe integer range\", \"INVALID_REQUEST\");\r\n }\r\n return asNumber;\r\n}\r\n","import { z } from 'zod';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport const MERCHANT_PROFILE_STATUSES = [\r\n 'pending',\r\n 'active',\r\n 'suspended',\r\n 'closed',\r\n] as const;\r\nexport const SETTLEMENT_SCHEDULES = ['manual', 'daily', 't1'] as const;\r\nexport const COLLECTION_INTENT_STATUSES = [\r\n 'created',\r\n 'pending',\r\n 'paid',\r\n 'expired',\r\n 'cancelled',\r\n 'failed',\r\n 'reversed',\r\n] as const;\r\nexport const COLLECTION_PAYMENT_STATUSES = [\r\n 'pending',\r\n 'paid',\r\n 'failed',\r\n 'reversed',\r\n] as const;\r\nexport const MERCHANT_PAYOUT_STATUSES = [\r\n 'requested',\r\n 'processing',\r\n 'paid',\r\n 'failed',\r\n 'cancelled',\r\n] as const;\r\n\r\nconst MoneyKoboSchema = z\r\n .number()\r\n .int()\r\n .positive()\r\n .max(Number.MAX_SAFE_INTEGER);\r\nconst MetadataSchema = z.record(\r\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\r\n);\r\nconst CurrencySchema = z\r\n .string()\r\n .trim()\r\n .length(3)\r\n .transform((value) => value.toUpperCase());\r\nconst ReferenceSchema = z\r\n .string()\r\n .trim()\r\n .min(6)\r\n .max(128)\r\n .regex(/^[A-Za-z0-9._:-]+$/);\r\n\r\nexport const MerchantProfileSchema = z.object({\r\n accountId: z.string().uuid(),\r\n legalName: z.string(),\r\n tradingName: z.string(),\r\n merchantCategoryCode: z.string().regex(/^\\d{4}$/),\r\n nqrMerchantId: z.string(),\r\n settlementBankCode: z.string(),\r\n settlementAccountNumber: z.string(),\r\n settlementAccountName: z.string(),\r\n settlementSchedule: z.enum(SETTLEMENT_SCHEDULES),\r\n status: z.enum(MERCHANT_PROFILE_STATUSES),\r\n offlineEnabled: z.boolean(),\r\n perTxLimitKobo: MoneyKoboSchema,\r\n dailyLimitKobo: MoneyKoboSchema,\r\n metadata: MetadataSchema,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type MerchantProfile = z.infer<typeof MerchantProfileSchema>;\r\n\r\nexport const UpsertMerchantProfileInputSchema = z.object({\r\n legalName: z.string().trim().min(1).max(200),\r\n tradingName: z.string().trim().min(1).max(25),\r\n merchantCategoryCode: z\r\n .string()\r\n .trim()\r\n .regex(/^\\d{4}$/),\r\n nqrMerchantId: z.string().trim().min(3).max(64),\r\n settlementBankCode: z.string().trim().min(2).max(16),\r\n settlementAccountNumber: z.string().trim().min(5).max(32),\r\n settlementAccountName: z.string().trim().min(1).max(200),\r\n settlementSchedule: z.enum(SETTLEMENT_SCHEDULES).optional(),\r\n status: z.enum(MERCHANT_PROFILE_STATUSES).optional(),\r\n offlineEnabled: z.boolean().optional(),\r\n perTxLimitKobo: MoneyKoboSchema.optional(),\r\n dailyLimitKobo: MoneyKoboSchema.optional(),\r\n metadata: MetadataSchema.optional(),\r\n});\r\nexport type UpsertMerchantProfileInput = z.infer<\r\n typeof UpsertMerchantProfileInputSchema\r\n>;\r\n\r\nexport const CollectionIntentSchema = z.object({\r\n intentId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n terminalId: z.string().uuid().nullable(),\r\n reference: z.string(),\r\n amountKobo: z.number().int().positive().nullable(),\r\n currency: z.string().length(3),\r\n status: z.enum(COLLECTION_INTENT_STATUSES),\r\n description: z.string().nullable(),\r\n nqrPayload: z.string(),\r\n provider: z.string(),\r\n providerReference: z.string().nullable(),\r\n metadata: MetadataSchema,\r\n expiresAtMs: z.number().int().nonnegative().nullable(),\r\n paidAtMs: z.number().int().nonnegative().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type CollectionIntent = z.infer<typeof CollectionIntentSchema>;\r\n\r\nexport const CreateCollectionIntentInputSchema = z.object({\r\n reference: ReferenceSchema.optional(),\r\n amountKobo: MoneyKoboSchema.optional(),\r\n currency: CurrencySchema.optional(),\r\n terminalId: z.string().uuid().optional(),\r\n terminalLabel: z.string().trim().min(1).max(25).optional(),\r\n merchantCity: z.string().trim().min(1).max(15).optional(),\r\n description: z.string().trim().min(1).max(280).optional(),\r\n expiresAtMs: z.number().int().positive().optional(),\r\n provider: z.string().trim().min(1).max(40).optional(),\r\n metadata: MetadataSchema.optional(),\r\n});\r\nexport type CreateCollectionIntentInput = z.infer<\r\n typeof CreateCollectionIntentInputSchema\r\n>;\r\n\r\nexport const PublicCollectionIntentSchema = z.object({\r\n intentId: z.string().uuid(),\r\n reference: z.string(),\r\n amountKobo: z.number().int().positive().nullable(),\r\n currency: z.string().length(3),\r\n status: z.enum(COLLECTION_INTENT_STATUSES),\r\n merchantAccountId: z.string().uuid(),\r\n merchantName: z.string(),\r\n merchantCategoryCode: z.string(),\r\n description: z.string().nullable(),\r\n expiresAtMs: z.number().int().nonnegative().nullable(),\r\n});\r\nexport type PublicCollectionIntent = z.infer<\r\n typeof PublicCollectionIntentSchema\r\n>;\r\n\r\nexport const PayCollectionInputSchema = z.object({\r\n reference: ReferenceSchema,\r\n amountKobo: MoneyKoboSchema.optional(),\r\n currency: CurrencySchema.optional(),\r\n idempotencyKey: z.string().trim().min(8).max(160).optional(),\r\n});\r\nexport type PayCollectionInput = z.infer<typeof PayCollectionInputSchema>;\r\n\r\nexport const CollectionPaymentSchema = z.object({\r\n paymentId: z.string().uuid(),\r\n intentId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n payerUserId: z.string().uuid().nullable(),\r\n merchantOwnerUserId: z.string().uuid(),\r\n amountKobo: MoneyKoboSchema,\r\n currency: z.string().length(3),\r\n status: z.enum(COLLECTION_PAYMENT_STATUSES),\r\n provider: z.string(),\r\n providerReference: z.string().nullable(),\r\n idempotencyKey: z.string().nullable(),\r\n ledgerRef: z.string(),\r\n failureCode: z.string().nullable(),\r\n failureMessage: z.string().nullable(),\r\n paidAtMs: z.number().int().nonnegative().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type CollectionPayment = z.infer<typeof CollectionPaymentSchema>;\r\n\r\nexport const CollectionPaymentResultSchema = z.object({\r\n payment: CollectionPaymentSchema,\r\n intent: CollectionIntentSchema,\r\n receipt: z.unknown().optional(),\r\n replayed: z.boolean(),\r\n});\r\nexport type CollectionPaymentResult = z.infer<\r\n typeof CollectionPaymentResultSchema\r\n>;\r\n\r\nexport const CollectionReportSummarySchema = z.object({\r\n accountId: z.string().uuid(),\r\n fromMs: z.number().int().nonnegative(),\r\n toMs: z.number().int().nonnegative(),\r\n currency: z.string().length(3),\r\n paidCount: z.number().int().nonnegative(),\r\n paidAmountKobo: z.number().int().nonnegative(),\r\n pendingCount: z.number().int().nonnegative(),\r\n failedCount: z.number().int().nonnegative(),\r\n reversedCount: z.number().int().nonnegative(),\r\n availableBalanceKobo: z.number().int().nonnegative(),\r\n});\r\nexport type CollectionReportSummary = z.infer<\r\n typeof CollectionReportSummarySchema\r\n>;\r\n\r\nexport const CollectionStatementSchema = z.object({\r\n accountId: z.string().uuid(),\r\n year: z.number().int(),\r\n month: z.number().int().min(1).max(12),\r\n currency: z.string().length(3),\r\n totalPaidKobo: z.number().int().nonnegative(),\r\n items: z.array(CollectionPaymentSchema),\r\n});\r\nexport type CollectionStatement = z.infer<typeof CollectionStatementSchema>;\r\n\r\nexport const CreatePayoutInputSchema = z.object({\r\n amountKobo: MoneyKoboSchema,\r\n currency: CurrencySchema.optional(),\r\n idempotencyKey: z.string().trim().min(8).max(160),\r\n});\r\nexport type CreatePayoutInput = z.infer<typeof CreatePayoutInputSchema>;\r\n\r\nexport const MerchantPayoutSchema = z.object({\r\n payoutId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n amountKobo: MoneyKoboSchema,\r\n currency: z.string().length(3),\r\n status: z.enum(MERCHANT_PAYOUT_STATUSES),\r\n idempotencyKey: z.string().nullable(),\r\n ledgerRef: z.string(),\r\n providerReference: z.string().nullable(),\r\n requestedByUserId: z.string().uuid().nullable(),\r\n failureCode: z.string().nullable(),\r\n failureMessage: z.string().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type MerchantPayout = z.infer<typeof MerchantPayoutSchema>;\r\n\r\nexport const ProviderEventInputSchema = z.object({\r\n provider: z.string().trim().min(1).max(80),\r\n eventId: z.string().trim().min(1).max(160),\r\n eventType: z.string().trim().min(1).max(120),\r\n payload: z.record(z.unknown()).optional(),\r\n});\r\nexport type ProviderEventInput = z.infer<typeof ProviderEventInputSchema>;\r\n\r\nexport const ProviderEventRecordSchema = z.object({\r\n id: z.string().uuid(),\r\n provider: z.string(),\r\n eventId: z.string(),\r\n eventType: z.string(),\r\n signatureVerified: z.boolean(),\r\n receivedAtMs: z.number().int().nonnegative(),\r\n processedAtMs: z.number().int().nonnegative().nullable(),\r\n});\r\nexport type ProviderEventRecord = z.infer<typeof ProviderEventRecordSchema>;\r\n\r\nexport type CollectionsClientOptions = {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type CollectionsClient = {\r\n upsertMerchantProfile: (\r\n accountId: string,\r\n input: UpsertMerchantProfileInput,\r\n ) => Promise<MerchantProfile>;\r\n getMerchantProfile: (accountId: string) => Promise<MerchantProfile>;\r\n createIntent: (\r\n input: CreateCollectionIntentInput,\r\n ) => Promise<CollectionIntent>;\r\n getIntent: (intentId: string) => Promise<CollectionIntent>;\r\n resolveIntent: (reference: string) => Promise<PublicCollectionIntent>;\r\n pay: (input: PayCollectionInput) => Promise<CollectionPaymentResult>;\r\n reportSummary: (input: {\r\n fromMs: number;\r\n toMs: number;\r\n currency?: string;\r\n }) => Promise<CollectionReportSummary>;\r\n monthlyStatement: (input: {\r\n year: number;\r\n month: number;\r\n currency?: string;\r\n }) => Promise<CollectionStatement>;\r\n createPayout: (input: CreatePayoutInput) => Promise<MerchantPayout>;\r\n getPayout: (payoutId: string) => Promise<MerchantPayout>;\r\n recordProviderEvent: (\r\n input: ProviderEventInput,\r\n ) => Promise<ProviderEventRecord>;\r\n};\r\n\r\nexport type PartnerCollectionsClient = Pick<\r\n CollectionsClient,\r\n | 'createIntent'\r\n | 'getIntent'\r\n | 'reportSummary'\r\n | 'monthlyStatement'\r\n | 'createPayout'\r\n | 'getPayout'\r\n | 'recordProviderEvent'\r\n>;\r\n\r\nexport type ConsumerCollectionsClient = Pick<\r\n CollectionsClient,\r\n 'resolveIntent' | 'pay'\r\n>;\r\n\r\nexport function createCollectionsClient(\r\n opts: CollectionsClientOptions,\r\n): CollectionsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createCollectionsClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: { accept: 'application/json' },\r\n };\r\n if (body !== undefined) {\r\n init.body = JSON.stringify(body);\r\n init.headers = { ...init.headers, 'content-type': 'application/json' };\r\n }\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n raw = text;\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n return {\r\n upsertMerchantProfile: (accountId, input) =>\r\n call(\r\n 'PUT',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,\r\n UpsertMerchantProfileInputSchema.parse(input),\r\n (raw) => MerchantProfileSchema.parse(raw),\r\n ),\r\n getMerchantProfile: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/merchant-profile`,\r\n undefined,\r\n (raw) => MerchantProfileSchema.parse(raw),\r\n ),\r\n createIntent: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/intents',\r\n CreateCollectionIntentInputSchema.parse(input),\r\n (raw) => CollectionIntentSchema.parse(raw),\r\n ),\r\n getIntent: (intentId) =>\r\n call(\r\n 'GET',\r\n `/v1/collections/intents/${encodeURIComponent(intentId)}`,\r\n undefined,\r\n (raw) => CollectionIntentSchema.parse(raw),\r\n ),\r\n resolveIntent: (reference) =>\r\n call(\r\n 'GET',\r\n `/v1/collections/resolve/${encodeURIComponent(reference)}`,\r\n undefined,\r\n (raw) => PublicCollectionIntentSchema.parse(raw),\r\n ),\r\n pay: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/pay',\r\n PayCollectionInputSchema.parse(input),\r\n (raw) => CollectionPaymentResultSchema.parse(raw),\r\n ),\r\n reportSummary: (input) => {\r\n const qs = new URLSearchParams({\r\n fromMs: String(input.fromMs),\r\n toMs: String(input.toMs),\r\n });\r\n if (input.currency) qs.set('currency', input.currency);\r\n return call(\r\n 'GET',\r\n `/v1/collections/reports/summary?${qs.toString()}`,\r\n undefined,\r\n (raw) => CollectionReportSummarySchema.parse(raw),\r\n );\r\n },\r\n monthlyStatement: (input) => {\r\n const qs = new URLSearchParams({\r\n year: String(input.year),\r\n month: String(input.month),\r\n });\r\n if (input.currency) qs.set('currency', input.currency);\r\n return call(\r\n 'GET',\r\n `/v1/collections/statements/monthly?${qs.toString()}`,\r\n undefined,\r\n (raw) => CollectionStatementSchema.parse(raw),\r\n );\r\n },\r\n createPayout: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/payouts',\r\n CreatePayoutInputSchema.parse(input),\r\n (raw) => MerchantPayoutSchema.parse(raw),\r\n ),\r\n getPayout: (payoutId) =>\r\n call(\r\n 'GET',\r\n `/v1/collections/payouts/${encodeURIComponent(payoutId)}`,\r\n undefined,\r\n (raw) => MerchantPayoutSchema.parse(raw),\r\n ),\r\n recordProviderEvent: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/collections/provider-events',\r\n ProviderEventInputSchema.parse(input),\r\n (raw) => ProviderEventRecordSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n\r\nexport function createPartnerCollectionsClient(\r\n opts: CollectionsClientOptions,\r\n): PartnerCollectionsClient {\r\n const client = createCollectionsClient(opts);\r\n return {\r\n createIntent: client.createIntent,\r\n getIntent: client.getIntent,\r\n reportSummary: client.reportSummary,\r\n monthlyStatement: client.monthlyStatement,\r\n createPayout: client.createPayout,\r\n getPayout: client.getPayout,\r\n recordProviderEvent: client.recordProviderEvent,\r\n };\r\n}\r\n\r\nexport function createConsumerCollectionsClient(\r\n opts: CollectionsClientOptions,\r\n): ConsumerCollectionsClient {\r\n const client = createCollectionsClient(opts);\r\n return {\r\n resolveIntent: client.resolveIntent,\r\n pay: client.pay,\r\n };\r\n}\r\n","/**\r\n * EMV / NQR Merchant-Presented top-level field IDs.\r\n * See EMVCo MPM v1.1 §4 and NIBSS NQR specification.\r\n */\r\nexport const FIELD = {\r\n PAYLOAD_FORMAT_INDICATOR: '00',\r\n POINT_OF_INITIATION: '01',\r\n // 02..51 — Merchant Account Information templates (issuer-specific)\r\n MERCHANT_CATEGORY_CODE: '52',\r\n TRANSACTION_CURRENCY: '53',\r\n TRANSACTION_AMOUNT: '54',\r\n TIP_OR_CONVENIENCE_INDICATOR: '55',\r\n VALUE_CONVENIENCE_FEE_FIXED: '56',\r\n VALUE_CONVENIENCE_FEE_PERCENT: '57',\r\n COUNTRY_CODE: '58',\r\n MERCHANT_NAME: '59',\r\n MERCHANT_CITY: '60',\r\n POSTAL_CODE: '61',\r\n ADDITIONAL_DATA_FIELD: '62',\r\n CRC: '63',\r\n MERCHANT_INFO_LANGUAGE: '64',\r\n // 80..99 — Unreserved Templates\r\n} as const;\r\n\r\nexport const ADDITIONAL_DATA_SUBFIELD = {\r\n BILL_NUMBER: '01',\r\n MOBILE_NUMBER: '02',\r\n STORE_LABEL: '03',\r\n LOYALTY_NUMBER: '04',\r\n REFERENCE_LABEL: '05',\r\n CUSTOMER_LABEL: '06',\r\n TERMINAL_LABEL: '07',\r\n PURPOSE_OF_TRANSACTION: '08',\r\n} as const;\r\n\r\nexport const POINT_OF_INITIATION = {\r\n STATIC: '11',\r\n DYNAMIC: '12',\r\n} as const;\r\n\r\nexport const PAYLOAD_FORMAT_INDICATOR_VALUE = '01';\r\nexport const NGN_CURRENCY_CODE = '566';\r\nexport const NG_COUNTRY_CODE = 'NG';\r\nexport const CRC_TAG_PREFIX = '6304'; // tag 63 + length 04\r\n","/**\r\n * CRC-16/CCITT-FALSE — polynomial 0x1021, initial 0xFFFF, no reflection,\r\n * no XOR-out. Specified by EMVCo MPM for tag 63 (CRC).\r\n */\r\nexport function crc16ccitt(bytes: Uint8Array): number {\r\n let crc = 0xffff;\r\n for (let i = 0; i < bytes.length; i++) {\r\n crc ^= bytes[i] << 8;\r\n for (let j = 0; j < 8; j++) {\r\n if (crc & 0x8000) {\r\n crc = (crc << 1) ^ 0x1021;\r\n } else {\r\n crc <<= 1;\r\n }\r\n crc &= 0xffff;\r\n }\r\n }\r\n return crc;\r\n}\r\n\r\nexport function crc16ccittHex(bytes: Uint8Array): string {\r\n return crc16ccitt(bytes).toString(16).toUpperCase().padStart(4, '0');\r\n}\r\n","/**\r\n * EMV TLV (Tag-Length-Value) primitives.\r\n * - Tag is 2 ASCII digits.\r\n * - Length is 2 ASCII digits (00..99).\r\n * - Value is up to 99 ASCII characters.\r\n */\r\n\r\nexport type TLVField = { tag: string; value: string };\r\n\r\nexport function writeTLV(tag: string, value: string): string {\r\n if (!/^\\d{2}$/.test(tag)) {\r\n throw new Error(`TLV: tag must be 2 digits, got \"${tag}\"`);\r\n }\r\n if (value.length > 99) {\r\n throw new Error(\r\n `TLV: value for tag ${tag} exceeds 99 chars (${value.length})`,\r\n );\r\n }\r\n const len = value.length.toString().padStart(2, '0');\r\n return `${tag}${len}${value}`;\r\n}\r\n\r\nexport function readTLV(buf: string): TLVField[] {\r\n const out: TLVField[] = [];\r\n let i = 0;\r\n while (i < buf.length) {\r\n if (i + 4 > buf.length) {\r\n throw new Error(`TLV: truncated header at offset ${i}`);\r\n }\r\n const tag = buf.slice(i, i + 2);\r\n const lenStr = buf.slice(i + 2, i + 4);\r\n if (!/^\\d{2}$/.test(tag)) {\r\n throw new Error(`TLV: bad tag \"${tag}\" at offset ${i}`);\r\n }\r\n if (!/^\\d{2}$/.test(lenStr)) {\r\n throw new Error(`TLV: bad length \"${lenStr}\" at offset ${i + 2}`);\r\n }\r\n const len = parseInt(lenStr, 10);\r\n const valStart = i + 4;\r\n const valEnd = valStart + len;\r\n if (valEnd > buf.length) {\r\n throw new Error(\r\n `TLV: truncated value for tag ${tag} at offset ${valStart}`,\r\n );\r\n }\r\n out.push({ tag, value: buf.slice(valStart, valEnd) });\r\n i = valEnd;\r\n }\r\n return out;\r\n}\r\n","import {\r\n ADDITIONAL_DATA_SUBFIELD,\r\n CRC_TAG_PREFIX,\r\n FIELD,\r\n NGN_CURRENCY_CODE,\r\n NG_COUNTRY_CODE,\r\n PAYLOAD_FORMAT_INDICATOR_VALUE,\r\n POINT_OF_INITIATION,\r\n} from './fields.js';\r\nimport { crc16ccittHex } from './crc16.js';\r\nimport { writeTLV } from './tlv.js';\r\nimport type {\r\n AdditionalData,\r\n MerchantAccountInfo,\r\n NQRPayloadInput,\r\n} from './types.js';\r\n\r\nconst ASCII_PRINTABLE = /^[\\x20-\\x7E]*$/;\r\n\r\n/** Build the inner content of a Merchant Account Information template. */\r\nfunction buildMAIValue(mai: MerchantAccountInfo): string {\r\n if (!/^(0[2-9]|[1-4]\\d|5[0-1])$/.test(mai.tag)) {\r\n throw new Error(\r\n `encodeNQR: merchantAccountInfo.tag must be in 02..51, got \"${mai.tag}\"`,\r\n );\r\n }\r\n let out = '';\r\n for (const c of mai.children) {\r\n out += writeTLV(c.tag, c.value);\r\n }\r\n return out;\r\n}\r\n\r\nfunction buildAdditionalDataValue(ad: AdditionalData): string {\r\n let out = '';\r\n const map: Array<[keyof AdditionalData, string]> = [\r\n ['billNumber', ADDITIONAL_DATA_SUBFIELD.BILL_NUMBER],\r\n ['mobileNumber', ADDITIONAL_DATA_SUBFIELD.MOBILE_NUMBER],\r\n ['storeLabel', ADDITIONAL_DATA_SUBFIELD.STORE_LABEL],\r\n ['loyaltyNumber', ADDITIONAL_DATA_SUBFIELD.LOYALTY_NUMBER],\r\n ['referenceLabel', ADDITIONAL_DATA_SUBFIELD.REFERENCE_LABEL],\r\n ['customerLabel', ADDITIONAL_DATA_SUBFIELD.CUSTOMER_LABEL],\r\n ['terminalLabel', ADDITIONAL_DATA_SUBFIELD.TERMINAL_LABEL],\r\n ['purposeOfTransaction', ADDITIONAL_DATA_SUBFIELD.PURPOSE_OF_TRANSACTION],\r\n ];\r\n for (const [k, t] of map) {\r\n const v = ad[k];\r\n if (v !== undefined) {\r\n out += writeTLV(t, v);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nfunction assertAscii(name: string, v: string): void {\r\n if (!ASCII_PRINTABLE.test(v)) {\r\n throw new Error(\r\n `encodeNQR: ${name} contains non-printable-ASCII characters`,\r\n );\r\n }\r\n}\r\n\r\nfunction assertMaxLen(name: string, v: string, max: number): void {\r\n if (v.length > max) {\r\n throw new Error(`encodeNQR: ${name} length ${v.length} exceeds max ${max}`);\r\n }\r\n}\r\n\r\nfunction assertMCC(mcc: string): void {\r\n if (!/^\\d{4}$/.test(mcc)) {\r\n throw new Error(\r\n `encodeNQR: merchantCategoryCode must be 4 digits, got \"${mcc}\"`,\r\n );\r\n }\r\n}\r\n\r\nfunction assertAmount(amt: string): void {\r\n // Up to 13 chars per EMV; decimal fraction separator is \".\"\r\n if (!/^\\d{1,10}(\\.\\d{1,2})?$/.test(amt)) {\r\n throw new Error(\r\n `encodeNQR: transactionAmount must match /^\\\\d{1,10}(\\\\.\\\\d{1,2})?$/, got \"${amt}\"`,\r\n );\r\n }\r\n if (amt.length > 13) {\r\n throw new Error(\r\n `encodeNQR: transactionAmount length ${amt.length} exceeds 13`,\r\n );\r\n }\r\n}\r\n\r\nexport function encodeNQR(input: NQRPayloadInput): string {\r\n assertMCC(input.merchantCategoryCode);\r\n assertAscii('merchantName', input.merchantName);\r\n assertMaxLen('merchantName', input.merchantName, 25);\r\n assertAscii('merchantCity', input.merchantCity);\r\n assertMaxLen('merchantCity', input.merchantCity, 15);\r\n if (input.postalCode !== undefined) {\r\n assertAscii('postalCode', input.postalCode);\r\n assertMaxLen('postalCode', input.postalCode, 10);\r\n }\r\n if (input.transactionAmount !== undefined) {\r\n assertAmount(input.transactionAmount);\r\n }\r\n if (\r\n input.pointOfInitiation === 'dynamic' &&\r\n input.transactionAmount === undefined\r\n ) {\r\n // amount is optional even for dynamic per spec, but warn-by-throw kept for now.\r\n // Allow undefined: some dynamic flows fill the amount in real-time. No throw.\r\n }\r\n\r\n let out = '';\r\n out += writeTLV(\r\n FIELD.PAYLOAD_FORMAT_INDICATOR,\r\n PAYLOAD_FORMAT_INDICATOR_VALUE,\r\n );\r\n out += writeTLV(\r\n FIELD.POINT_OF_INITIATION,\r\n input.pointOfInitiation === 'dynamic'\r\n ? POINT_OF_INITIATION.DYNAMIC\r\n : POINT_OF_INITIATION.STATIC,\r\n );\r\n out += writeTLV(\r\n input.merchantAccountInfo.tag,\r\n buildMAIValue(input.merchantAccountInfo),\r\n );\r\n out += writeTLV(FIELD.MERCHANT_CATEGORY_CODE, input.merchantCategoryCode);\r\n out += writeTLV(FIELD.TRANSACTION_CURRENCY, NGN_CURRENCY_CODE);\r\n if (input.transactionAmount !== undefined) {\r\n out += writeTLV(FIELD.TRANSACTION_AMOUNT, input.transactionAmount);\r\n }\r\n out += writeTLV(FIELD.COUNTRY_CODE, NG_COUNTRY_CODE);\r\n out += writeTLV(FIELD.MERCHANT_NAME, input.merchantName);\r\n out += writeTLV(FIELD.MERCHANT_CITY, input.merchantCity);\r\n if (input.postalCode !== undefined) {\r\n out += writeTLV(FIELD.POSTAL_CODE, input.postalCode);\r\n }\r\n if (input.additionalData) {\r\n const adfValue = buildAdditionalDataValue(input.additionalData);\r\n if (adfValue.length > 0) {\r\n out += writeTLV(FIELD.ADDITIONAL_DATA_FIELD, adfValue);\r\n }\r\n }\r\n\r\n // CRC over everything including \"6304\" header.\r\n out += CRC_TAG_PREFIX;\r\n const crc = crc16ccittHex(new TextEncoder().encode(out));\r\n out += crc;\r\n return out;\r\n}\r\n","import {\r\n CRC_TAG_PREFIX,\r\n FIELD,\r\n NGN_CURRENCY_CODE,\r\n NG_COUNTRY_CODE,\r\n} from './fields.js';\r\nimport { crc16ccittHex } from './crc16.js';\r\nimport { readTLV } from './tlv.js';\r\nimport type {\r\n AdditionalData,\r\n MerchantAccountInfo,\r\n ParsedNQR,\r\n} from './types.js';\r\n\r\nexport class NQRParseError extends Error {\r\n readonly path: string;\r\n constructor(message: string, path = '') {\r\n super(message);\r\n this.name = 'NQRParseError';\r\n this.path = path;\r\n }\r\n}\r\n\r\nexport function parseNQR(payload: string): ParsedNQR {\r\n if (payload.length < 8) {\r\n throw new NQRParseError(`payload too short (${payload.length} chars)`);\r\n }\r\n // CRC validation: last 4 chars are CRC; preceding 4 must be \"6304\".\r\n const crcTagAndLen = payload.slice(-8, -4);\r\n const crcValue = payload.slice(-4);\r\n if (crcTagAndLen !== CRC_TAG_PREFIX) {\r\n throw new NQRParseError(\r\n `CRC tag prefix not found (expected \"6304\" at end)`,\r\n );\r\n }\r\n const beforeCrc = payload.slice(0, -4);\r\n const expectedCrc = crc16ccittHex(new TextEncoder().encode(beforeCrc));\r\n if (expectedCrc !== crcValue.toUpperCase()) {\r\n throw new NQRParseError(\r\n `CRC mismatch: payload says ${crcValue}, computed ${expectedCrc}`,\r\n '63',\r\n );\r\n }\r\n\r\n // Parse top-level TLV (excluding the trailing CRC field).\r\n const topBuf = payload.slice(0, -8);\r\n const top = readTLV(topBuf);\r\n\r\n const get = (tag: string): string | undefined =>\r\n top.find((f) => f.tag === tag)?.value;\r\n\r\n const pfi = get(FIELD.PAYLOAD_FORMAT_INDICATOR);\r\n if (pfi !== '01')\r\n throw new NQRParseError(\r\n `payloadFormatIndicator must be \"01\", got \"${pfi}\"`,\r\n '00',\r\n );\r\n\r\n const poiRaw = get(FIELD.POINT_OF_INITIATION);\r\n const pointOfInitiation: ParsedNQR['pointOfInitiation'] =\r\n poiRaw === '11' ? 'static' : poiRaw === '12' ? 'dynamic' : 'unknown';\r\n\r\n const currency = get(FIELD.TRANSACTION_CURRENCY);\r\n if (currency !== NGN_CURRENCY_CODE) {\r\n throw new NQRParseError(\r\n `unsupported currency \"${currency}\" (expected ${NGN_CURRENCY_CODE})`,\r\n '53',\r\n );\r\n }\r\n const country = get(FIELD.COUNTRY_CODE);\r\n if (country !== NG_COUNTRY_CODE) {\r\n throw new NQRParseError(\r\n `unsupported country \"${country}\" (expected ${NG_COUNTRY_CODE})`,\r\n '58',\r\n );\r\n }\r\n\r\n const mcc = get(FIELD.MERCHANT_CATEGORY_CODE);\r\n if (!mcc) throw new NQRParseError('merchantCategoryCode missing', '52');\r\n const merchantName = get(FIELD.MERCHANT_NAME) ?? '';\r\n const merchantCity = get(FIELD.MERCHANT_CITY) ?? '';\r\n const transactionAmount = get(FIELD.TRANSACTION_AMOUNT);\r\n const postalCode = get(FIELD.POSTAL_CODE);\r\n\r\n // Merchant Account Information templates: tags 02..51.\r\n const mais: MerchantAccountInfo[] = [];\r\n for (const f of top) {\r\n const n = parseInt(f.tag, 10);\r\n if (n >= 2 && n <= 51) {\r\n const children = readTLV(f.value).map((c) => ({\r\n tag: c.tag,\r\n value: c.value,\r\n }));\r\n mais.push({ tag: f.tag, children });\r\n }\r\n }\r\n\r\n // Additional Data Field (62).\r\n let additionalData: AdditionalData | undefined;\r\n const adfRaw = get(FIELD.ADDITIONAL_DATA_FIELD);\r\n if (adfRaw !== undefined) {\r\n additionalData = {};\r\n for (const c of readTLV(adfRaw)) {\r\n switch (c.tag) {\r\n case '01':\r\n additionalData.billNumber = c.value;\r\n break;\r\n case '02':\r\n additionalData.mobileNumber = c.value;\r\n break;\r\n case '03':\r\n additionalData.storeLabel = c.value;\r\n break;\r\n case '04':\r\n additionalData.loyaltyNumber = c.value;\r\n break;\r\n case '05':\r\n additionalData.referenceLabel = c.value;\r\n break;\r\n case '06':\r\n additionalData.customerLabel = c.value;\r\n break;\r\n case '07':\r\n additionalData.terminalLabel = c.value;\r\n break;\r\n case '08':\r\n additionalData.purposeOfTransaction = c.value;\r\n break;\r\n // unknown sub-tags ignored (forward-compat).\r\n }\r\n }\r\n }\r\n\r\n return {\r\n payloadFormatIndicator: pfi,\r\n pointOfInitiation,\r\n merchantAccountInfo: mais,\r\n merchantCategoryCode: mcc,\r\n transactionCurrency: currency,\r\n transactionAmount,\r\n countryCode: country,\r\n merchantName,\r\n merchantCity,\r\n postalCode,\r\n additionalData,\r\n flurReference: additionalData?.referenceLabel?.startsWith('FL-')\r\n ? additionalData.referenceLabel\r\n : undefined,\r\n raw: payload,\r\n };\r\n}\r\n","import type { ParsedNQR } from './types.js';\r\n\r\nexport type RoutingHint = 'flur-onus' | 'nibss' | 'unknown';\r\n\r\n/**\r\n * Decide whether a parsed NQR payload should be routed on-us through Flur\r\n * (because it carries a Flur reference label) or sent through standard NIBSS.\r\n */\r\nexport function routingHint(parsed: ParsedNQR): RoutingHint {\r\n if (parsed.flurReference && parsed.flurReference.startsWith('FL-')) {\r\n return 'flur-onus';\r\n }\r\n if (parsed.merchantAccountInfo.length > 0) return 'nibss';\r\n return 'unknown';\r\n}\r\n","/**\r\n * Deterministic JSON serialization for cryptographic signing.\r\n *\r\n * Rules:\r\n * - Object keys sorted lexicographically (recursively).\r\n * - Arrays preserve order.\r\n * - undefined / NaN / Infinity / bigint / function / symbol are rejected.\r\n * Signatures must be unambiguous; ambiguous values are bugs.\r\n */\r\nexport function canonicalJSONStringify(value: unknown): string {\r\n return stringify(value);\r\n}\r\n\r\nexport function canonicalJSONBytes(value: unknown): Uint8Array {\r\n return new TextEncoder().encode(canonicalJSONStringify(value));\r\n}\r\n\r\nfunction stringify(v: unknown): string {\r\n if (v === null) return 'null';\r\n const t = typeof v;\r\n if (t === 'string') return JSON.stringify(v);\r\n if (t === 'boolean') return v ? 'true' : 'false';\r\n if (t === 'number') {\r\n if (!Number.isFinite(v as number)) {\r\n throw new Error('canonicalJSON: non-finite number not allowed');\r\n }\r\n return JSON.stringify(v);\r\n }\r\n if (\r\n t === 'bigint' ||\r\n t === 'function' ||\r\n t === 'symbol' ||\r\n t === 'undefined'\r\n ) {\r\n throw new Error(`canonicalJSON: unsupported value type ${t}`);\r\n }\r\n if (Array.isArray(v)) {\r\n const parts: string[] = [];\r\n for (const item of v) parts.push(stringify(item));\r\n return '[' + parts.join(',') + ']';\r\n }\r\n if (t === 'object') {\r\n const obj = v as Record<string, unknown>;\r\n const keys = Object.keys(obj).sort();\r\n const parts: string[] = [];\r\n for (const k of keys) {\r\n const val = obj[k];\r\n if (val === undefined) {\r\n throw new Error(`canonicalJSON: undefined value at key \"${k}\"`);\r\n }\r\n parts.push(JSON.stringify(k) + ':' + stringify(val));\r\n }\r\n return '{' + parts.join(',') + '}';\r\n }\r\n throw new Error(`canonicalJSON: unsupported value type ${t}`);\r\n}\r\n","/**\r\n * Constant-time equality for byte arrays. Returns false fast on length\r\n * mismatch (length is not secret); compares byte-wise without short-circuit\r\n * for equal-length inputs.\r\n */\r\nexport function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {\r\n if (a.length !== b.length) return false;\r\n let diff = 0;\r\n for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];\r\n return diff === 0;\r\n}\r\n","/**\r\n * Offline Authorization Certificate (OAC) — P-256 edition (Stage 2c).\r\n *\r\n * Previous wire format used raw 32-byte Ed25519 hex device keys and 64-byte\r\n * hex Ed25519 signatures. The cutover keeps the JSON field names but moves\r\n * to base64:\r\n * - `devicePublicKey` : SubjectPublicKeyInfo DER, base64 (P-256, ~124 chars).\r\n * - `issuerSig` : ASN.1 DER ECDSA(SHA-256) signature, base64 (~96 chars).\r\n *\r\n * `issuerPrivateKey` is a raw 32-byte P-256 scalar (Uint8Array) — same shape as\r\n * the SDK's other P-256 helpers. `issuerPublicKey` (for verification) is now a\r\n * base64 SPKI DER string, matching the rest of the migrated SDK surface.\r\n */\r\nimport { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\n\r\nexport const OAC_DEFAULT_PER_TX_KOBO = 500_000;\r\nexport const OAC_DEFAULT_CUMULATIVE_KOBO = 2_000_000;\r\nexport const OAC_DEFAULT_VALIDITY_MS = 24 * 60 * 60 * 1000;\r\n\r\n// Wide enough for SPKI public keys (~124 chars) and DER signatures (~96 chars).\r\nconst Base64Std = z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/, 'expected base64 (standard) string');\r\n\r\nexport const OACSchema = z\r\n .object({\r\n userId: z.string().min(1),\r\n deviceId: z.string().min(1),\r\n /** SubjectPublicKeyInfo DER, base64 (P-256). */\r\n devicePublicKey: Base64Std,\r\n perTxCapKobo: z.number().int().nonnegative(),\r\n cumulativeCapKobo: z.number().int().nonnegative(),\r\n validFromMs: z.number().int().nonnegative(),\r\n validUntilMs: z.number().int().positive(),\r\n counterSeed: z.number().int().nonnegative(),\r\n nonce: z.string().min(1),\r\n /** ASN.1 DER ECDSA(SHA-256) signature, base64. */\r\n issuerSig: Base64Std,\r\n })\r\n .refine((v) => v.validUntilMs > v.validFromMs, {\r\n message: 'validUntilMs must be greater than validFromMs',\r\n })\r\n .refine((v) => v.perTxCapKobo <= v.cumulativeCapKobo, {\r\n message: 'perTxCapKobo must not exceed cumulativeCapKobo',\r\n });\r\n\r\nexport type OAC = z.infer<typeof OACSchema>;\r\nexport type UnsignedOAC = Omit<OAC, 'issuerSig'>;\r\n\r\nexport function buildOAC(input: {\r\n userId: string;\r\n deviceId: string;\r\n /** SPKI DER base64 string (P-256). */\r\n devicePublicKey: string;\r\n perTxCapKobo?: number;\r\n cumulativeCapKobo?: number;\r\n validFromMs: number;\r\n validUntilMs: number;\r\n counterSeed?: number;\r\n nonce: string;\r\n}): UnsignedOAC {\r\n return {\r\n userId: input.userId,\r\n deviceId: input.deviceId,\r\n devicePublicKey: input.devicePublicKey,\r\n perTxCapKobo: input.perTxCapKobo ?? OAC_DEFAULT_PER_TX_KOBO,\r\n cumulativeCapKobo: input.cumulativeCapKobo ?? OAC_DEFAULT_CUMULATIVE_KOBO,\r\n validFromMs: input.validFromMs,\r\n validUntilMs: input.validUntilMs,\r\n counterSeed: input.counterSeed ?? 0,\r\n nonce: input.nonce,\r\n };\r\n}\r\n\r\nexport function signOAC(\r\n unsigned: UnsignedOAC,\r\n issuerPrivateKey: Uint8Array,\r\n): OAC {\r\n const issuerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerPrivateKey,\r\n );\r\n return { ...unsigned, issuerSig };\r\n}\r\n\r\nexport function verifyOAC(oac: OAC, issuerPublicKeySpkiB64: string): boolean {\r\n try {\r\n const parsed = OACSchema.parse(oac);\r\n const { issuerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-exported small byte helpers — kept for QR/codec callers; they are not\r\n// part of the OAC contract any more.\r\nexport function bytesToHex(b: Uint8Array): string {\r\n let s = '';\r\n for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, '0');\r\n return s;\r\n}\r\n\r\nexport function hexToBytes(s: string): Uint8Array {\r\n if (s.length % 2 !== 0) throw new Error('hex: odd length');\r\n const out = new Uint8Array(s.length / 2);\r\n for (let i = 0; i < out.length; i++)\r\n out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16);\r\n return out;\r\n}\r\n","/**\r\n * P-256 (ECDSA over secp256r1) issuer signing helpers for SDK-side\r\n * sign/verify of artefacts (passes, receipts).\r\n *\r\n * Wire format matches the backend (`flur-backend/src/crypto/issuer-p256.ts`)\r\n * and the mobile native secure-signer modules:\r\n * - private key: raw 32-byte P-256 secret (matches `@noble/curves/nist`).\r\n * - public key: SubjectPublicKeyInfo DER, base64 (on-wire form).\r\n * - signature: ASN.1 DER ECDSA, base64.\r\n * - hash: SHA-256 (consumed internally via `{ prehash: true }`).\r\n *\r\n * `signPass` / `signReceipt` typically only run in tests and trusted\r\n * server-side integrators; mobile consumers only verify.\r\n */\r\n\r\nimport { p256 } from '@noble/curves/nist';\r\n\r\n// ─────────────────────────── byte/base64 utils ───────────────────────────\r\n\r\nfunction bytesToBase64(bytes: Uint8Array): string {\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(bytes).toString('base64');\r\n }\r\n let bin = '';\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]!);\r\n // eslint-disable-next-line no-undef\r\n return btoa(bin);\r\n}\r\n\r\nfunction base64ToBytes(b64: string): Uint8Array {\r\n if (typeof Buffer !== 'undefined') {\r\n return new Uint8Array(Buffer.from(b64, 'base64'));\r\n }\r\n // eslint-disable-next-line no-undef\r\n const bin = atob(b64);\r\n const out = new Uint8Array(bin.length);\r\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\r\n return out;\r\n}\r\n\r\n// ─────────────────────────── SPKI <-> raw helpers ────────────────────────\r\n//\r\n// @noble/curves emits the raw X9.62 uncompressed point (0x04 || X || Y).\r\n// SubjectPublicKeyInfo DER wraps that with a fixed 26-byte ASN.1 header for\r\n// P-256. Strip/wrap to convert.\r\n\r\nconst P256_SPKI_HEADER = new Uint8Array([\r\n 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,\r\n 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,\r\n]);\r\n\r\nexport function p256SpkiB64ToRaw(spkiB64: string): Uint8Array {\r\n const spki = base64ToBytes(spkiB64);\r\n if (spki.length !== P256_SPKI_HEADER.length + 65) {\r\n throw new Error('p256: invalid SPKI length');\r\n }\r\n for (let i = 0; i < P256_SPKI_HEADER.length; i++) {\r\n if (spki[i] !== P256_SPKI_HEADER[i]) {\r\n throw new Error('p256: invalid SPKI header');\r\n }\r\n }\r\n return spki.slice(P256_SPKI_HEADER.length);\r\n}\r\n\r\nexport function p256RawToSpkiB64(rawUncompressed: Uint8Array): string {\r\n if (rawUncompressed.length !== 65 || rawUncompressed[0] !== 0x04) {\r\n throw new Error('p256: expected 65-byte uncompressed point');\r\n }\r\n const out = new Uint8Array(P256_SPKI_HEADER.length + rawUncompressed.length);\r\n out.set(P256_SPKI_HEADER, 0);\r\n out.set(rawUncompressed, P256_SPKI_HEADER.length);\r\n return bytesToBase64(out);\r\n}\r\n\r\n// ─────────────────────────── sign / verify ───────────────────────────\r\n\r\n/**\r\n * Sign a byte array with a raw 32-byte P-256 private key.\r\n * Returns ASN.1 DER ECDSA signature, base64.\r\n */\r\nexport function signIssuerP256(\r\n bytes: Uint8Array,\r\n issuerPrivateKey: Uint8Array,\r\n): string {\r\n const sig = p256.sign(bytes, issuerPrivateKey, { prehash: true });\r\n return bytesToBase64(sig.toBytes('der'));\r\n}\r\n\r\n/**\r\n * Verify a base64 DER ECDSA P-256 signature against the issuer's SPKI DER\r\n * public key (base64). Returns `false` on any decoding/verification failure.\r\n */\r\nexport function verifyIssuerP256(\r\n bytes: Uint8Array,\r\n signatureB64: string,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const pubRaw = p256SpkiB64ToRaw(issuerPublicKeySpkiB64);\r\n const sigBytes = base64ToBytes(signatureB64);\r\n return p256.verify(sigBytes, bytes, pubRaw, {\r\n prehash: true,\r\n format: 'der',\r\n });\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","// RFC 9285 base45 encoder/decoder.\r\nconst ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';\r\nconst REVERSE: Record<string, number> = {};\r\nfor (let i = 0; i < ALPHABET.length; i++) REVERSE[ALPHABET[i]] = i;\r\n\r\nexport function encodeBase45(bytes: Uint8Array): string {\r\n let out = '';\r\n let i = 0;\r\n for (; i + 1 < bytes.length; i += 2) {\r\n const x = (bytes[i] << 8) | bytes[i + 1];\r\n const e = Math.floor(x / (45 * 45));\r\n const d = Math.floor((x % (45 * 45)) / 45);\r\n const c = x % 45;\r\n out += ALPHABET[c] + ALPHABET[d] + ALPHABET[e];\r\n }\r\n if (i < bytes.length) {\r\n const x = bytes[i];\r\n const d = Math.floor(x / 45);\r\n const c = x % 45;\r\n out += ALPHABET[c] + ALPHABET[d];\r\n }\r\n return out;\r\n}\r\n\r\nexport function decodeBase45(s: string): Uint8Array {\r\n if (s.length === 0) return new Uint8Array(0);\r\n const fullChunks = Math.floor(s.length / 3);\r\n const tail = s.length - fullChunks * 3;\r\n if (tail === 1) throw new Error('base45: invalid length');\r\n const out = new Uint8Array(fullChunks * 2 + (tail === 2 ? 1 : 0));\r\n let oi = 0;\r\n for (let i = 0; i < fullChunks; i++) {\r\n const c = REVERSE[s[i * 3]];\r\n const d = REVERSE[s[i * 3 + 1]];\r\n const e = REVERSE[s[i * 3 + 2]];\r\n if (c === undefined || d === undefined || e === undefined) {\r\n throw new Error('base45: invalid character');\r\n }\r\n const x = c + 45 * d + 45 * 45 * e;\r\n if (x > 0xffff) throw new Error('base45: chunk overflow');\r\n out[oi++] = (x >> 8) & 0xff;\r\n out[oi++] = x & 0xff;\r\n }\r\n if (tail === 2) {\r\n const c = REVERSE[s[fullChunks * 3]];\r\n const d = REVERSE[s[fullChunks * 3 + 1]];\r\n if (c === undefined || d === undefined)\r\n throw new Error('base45: invalid character');\r\n const x = c + 45 * d;\r\n if (x > 0xff) throw new Error('base45: tail overflow');\r\n out[oi++] = x & 0xff;\r\n }\r\n return out;\r\n}\r\n","/**\r\n * Offline payment messages — P-256 edition (Stage 2c).\r\n *\r\n * Wire-shape change vs. the previous Ed25519 hex format:\r\n * - `merchantSig`, `payerSig` : ASN.1 DER ECDSA(SHA-256) signature, base64.\r\n * - device signing keys are passed as raw 32-byte P-256 scalars (Uint8Array);\r\n * issuer-side verification arguments use SPKI DER base64 strings.\r\n *\r\n * Note: `verifyPaymentRequest` and `verifyAuthorization` take the *issuer*\r\n * public key (SPKI b64) — they re-verify the merchant/payer OAC against the\r\n * issuer, then verify the merchant/payer signature against the device key\r\n * embedded in their OAC.\r\n */\r\nimport { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\nimport { OACSchema, type OAC } from './oac.js';\r\nimport { encodeBase45, decodeBase45 } from './codec.js';\r\n\r\nconst Base64Sig = z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/, 'expected base64 (standard) signature');\r\n\r\nexport const OfflinePaymentRequestSchema = z.object({\r\n reference: z.string().min(1),\r\n amountKobo: z.number().int().positive(),\r\n merchantOAC: OACSchema,\r\n expiresAtMs: z.number().int().positive(),\r\n merchantSig: Base64Sig,\r\n});\r\nexport type OfflinePaymentRequest = z.infer<typeof OfflinePaymentRequestSchema>;\r\nexport type UnsignedOfflinePaymentRequest = Omit<\r\n OfflinePaymentRequest,\r\n 'merchantSig'\r\n>;\r\n\r\nexport const OfflinePaymentAuthorizationSchema = z.object({\r\n request: OfflinePaymentRequestSchema,\r\n payerOAC: OACSchema,\r\n payerCounter: z.number().int().positive(),\r\n payerSig: Base64Sig,\r\n});\r\nexport type OfflinePaymentAuthorization = z.infer<\r\n typeof OfflinePaymentAuthorizationSchema\r\n>;\r\nexport type UnsignedOfflinePaymentAuthorization = Omit<\r\n OfflinePaymentAuthorization,\r\n 'payerSig'\r\n>;\r\n\r\nexport function buildPaymentRequest(input: {\r\n reference: string;\r\n amountKobo: number;\r\n merchantOAC: OAC;\r\n expiresAtMs: number;\r\n}): UnsignedOfflinePaymentRequest {\r\n if (!Number.isInteger(input.amountKobo) || input.amountKobo <= 0) {\r\n throw new Error('amountKobo must be a positive integer');\r\n }\r\n if (input.amountKobo > input.merchantOAC.perTxCapKobo) {\r\n throw new Error('amountKobo exceeds merchant OAC perTxCapKobo');\r\n }\r\n return {\r\n reference: input.reference,\r\n amountKobo: input.amountKobo,\r\n merchantOAC: input.merchantOAC,\r\n expiresAtMs: input.expiresAtMs,\r\n };\r\n}\r\n\r\nexport function signPaymentRequest(\r\n unsigned: UnsignedOfflinePaymentRequest,\r\n merchantDevicePrivateKey: Uint8Array,\r\n): OfflinePaymentRequest {\r\n const merchantSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n merchantDevicePrivateKey,\r\n );\r\n return { ...unsigned, merchantSig };\r\n}\r\n\r\nexport function verifyPaymentRequest(\r\n req: OfflinePaymentRequest,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = OfflinePaymentRequestSchema.parse(req);\r\n // 1. Issuer must have signed the merchant OAC.\r\n const { issuerSig: merchantOacSig, ...merchantOacUnsigned } =\r\n parsed.merchantOAC;\r\n if (\r\n !verifyIssuerP256(\r\n canonicalJSONBytes(merchantOacUnsigned),\r\n merchantOacSig,\r\n issuerPublicKeySpkiB64,\r\n )\r\n ) {\r\n return false;\r\n }\r\n // 2. The merchant's device key (in the OAC) must have signed this request.\r\n const { merchantSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n merchantSig,\r\n parsed.merchantOAC.devicePublicKey,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function buildAuthorization(input: {\r\n request: OfflinePaymentRequest;\r\n payerOAC: OAC;\r\n payerCounter: number;\r\n}): UnsignedOfflinePaymentAuthorization {\r\n if (!Number.isInteger(input.payerCounter) || input.payerCounter <= 0) {\r\n throw new Error('payerCounter must be a positive integer');\r\n }\r\n if (input.request.amountKobo > input.payerOAC.perTxCapKobo) {\r\n throw new Error('amountKobo exceeds payer OAC perTxCapKobo');\r\n }\r\n return {\r\n request: input.request,\r\n payerOAC: input.payerOAC,\r\n payerCounter: input.payerCounter,\r\n };\r\n}\r\n\r\nexport function signAuthorization(\r\n unsigned: UnsignedOfflinePaymentAuthorization,\r\n payerDevicePrivateKey: Uint8Array,\r\n): OfflinePaymentAuthorization {\r\n const payerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n payerDevicePrivateKey,\r\n );\r\n return { ...unsigned, payerSig };\r\n}\r\n\r\nexport function verifyAuthorization(\r\n auth: OfflinePaymentAuthorization,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = OfflinePaymentAuthorizationSchema.parse(auth);\r\n if (!verifyPaymentRequest(parsed.request, issuerPublicKeySpkiB64))\r\n return false;\r\n // Issuer must have signed the payer OAC.\r\n const { issuerSig: payerOacSig, ...payerOacUnsigned } = parsed.payerOAC;\r\n if (\r\n !verifyIssuerP256(\r\n canonicalJSONBytes(payerOacUnsigned),\r\n payerOacSig,\r\n issuerPublicKeySpkiB64,\r\n )\r\n ) {\r\n return false;\r\n }\r\n // Payer device key must have signed this authorization.\r\n const { payerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n payerSig,\r\n parsed.payerOAC.devicePublicKey,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function encodePaymentRequestQR(req: OfflinePaymentRequest): string {\r\n const json = JSON.stringify(req);\r\n return 'FLUR1:' + encodeBase45(new TextEncoder().encode(json));\r\n}\r\n\r\nexport function decodePaymentRequestQR(s: string): OfflinePaymentRequest {\r\n if (!s.startsWith('FLUR1:'))\r\n throw new Error('not a Flur offline payment request QR');\r\n const bytes = decodeBase45(s.slice('FLUR1:'.length));\r\n const json = new TextDecoder().decode(bytes);\r\n return OfflinePaymentRequestSchema.parse(JSON.parse(json));\r\n}\r\n\r\nexport function encodeAuthorizationQR(\r\n auth: OfflinePaymentAuthorization,\r\n): string {\r\n const json = JSON.stringify(auth);\r\n return 'FLUR2:' + encodeBase45(new TextEncoder().encode(json));\r\n}\r\n\r\nexport function decodeAuthorizationQR(s: string): OfflinePaymentAuthorization {\r\n if (!s.startsWith('FLUR2:'))\r\n throw new Error('not a Flur offline authorization QR');\r\n const bytes = decodeBase45(s.slice('FLUR2:'.length));\r\n const json = new TextDecoder().decode(bytes);\r\n return OfflinePaymentAuthorizationSchema.parse(JSON.parse(json));\r\n}\r\n","/**\r\n * Offline settlement SDK helpers.\r\n *\r\n * The SDK does not \"pay\" offline — it produces signed `PaymentClaim`s and posts\r\n * them to `/v1/offline/settlements`. The backend enforces \"paid once\" via\r\n * UNIQUE(settlement_key) and UNIQUE(token_serial).\r\n */\r\nimport { z } from 'zod';\r\nimport type { FlurPartnerClient } from '../partner/client.js';\r\n\r\n// ───────────────────────────── schemas ─────────────────────────────\r\n\r\nexport const OfflineTokenSchema = z.object({\r\n tokenId: z.string().uuid(),\r\n tokenSerial: z.string(),\r\n issuerAccountId: z.string().uuid(),\r\n payerUserId: z.string().uuid(),\r\n maxAmountKobo: z.number().int().positive(),\r\n currency: z.string().length(3),\r\n issuedAtMs: z.number().int().nonnegative(),\r\n expiresAtMs: z.number().int().nonnegative(),\r\n issuerSig: z.string(),\r\n});\r\nexport type OfflineToken = z.infer<typeof OfflineTokenSchema>;\r\n\r\nexport const PaymentClaimSchema = z.object({\r\n encounterId: z\r\n .string()\r\n .regex(/^[0-9a-f]{64}$/i)\r\n .optional(),\r\n tokenSerial: z.string(),\r\n payerUserId: z.string().uuid(),\r\n payeeUserId: z.string().uuid(),\r\n payerNonce: z.string(),\r\n payeeNonce: z.string(),\r\n amountKobo: z.number().int().positive(),\r\n currency: z.string().length(3).default('NGN'),\r\n occurredAtMs: z.number().int().nonnegative(),\r\n completedAtMs: z.number().int().nonnegative().optional(),\r\n contextId: z.string().optional(),\r\n // Stage 2c: P-256 device keys are now SubjectPublicKeyInfo DER, base64.\r\n // Signatures are ASN.1 DER ECDSA(SHA-256), base64. Backwards-incompatible\r\n // wire change; the backend has the matching widening in offline-settlements\r\n // service + zod schema.\r\n payerPubkey: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n payerSignature: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n payeePubkey: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/)\r\n .optional(),\r\n payeeSignature: z\r\n .string()\r\n .min(16)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/)\r\n .optional(),\r\n});\r\nexport type PaymentClaim = z.infer<typeof PaymentClaimSchema>;\r\n\r\nexport const SettlementSchema = z.object({\r\n settlementId: z.string().uuid(),\r\n settlementKey: z.string().regex(/^[0-9a-f]{64}$/i),\r\n encounterId: z.string().regex(/^[0-9a-f]{64}$/i),\r\n issuerAccountId: z.string().uuid(),\r\n tokenSerial: z.string(),\r\n payerUserId: z.string().uuid(),\r\n payeeUserId: z.string().uuid(),\r\n amountKobo: z.number().int().nonnegative(),\r\n currency: z.string().length(3),\r\n receiptId: z.string().nullable(),\r\n status: z.enum(['SETTLED', 'REVIEW', 'REJECTED']),\r\n issuerSig: z.string(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type Settlement = z.infer<typeof SettlementSchema>;\r\n\r\nexport const SettleResponseSchema = z.object({\r\n settlement: SettlementSchema,\r\n encounterId: z.string().regex(/^[0-9a-f]{64}$/i),\r\n replayed: z.boolean(),\r\n});\r\nexport type SettleResponse = z.infer<typeof SettleResponseSchema>;\r\n\r\n// ───────────────────────────── deterministic ids ─────────────────────────────\r\n\r\nimport { sha256 } from '@noble/hashes/sha256';\r\nimport { bytesToHex } from '@noble/hashes/utils';\r\n\r\nconst ENCOUNTER_DOMAIN = 'offline:v1:encounter';\r\n\r\n/** SHA-256 hex helper. Pure-JS via @noble/hashes — works in Node, browser, and React Native. */\r\nasync function sha256Hex(input: string): Promise<string> {\r\n return bytesToHex(sha256(new TextEncoder().encode(input)));\r\n}\r\n\r\n/**\r\n * Compute the deterministic encounterId. Both parties produce the same value;\r\n * the backend enforces it.\r\n */\r\nexport async function computeEncounterId(input: {\r\n payerUserId: string;\r\n payeeUserId: string;\r\n payerNonce: string;\r\n payeeNonce: string;\r\n tokenSerial: string;\r\n}): Promise<string> {\r\n return sha256Hex(\r\n ENCOUNTER_DOMAIN +\r\n '|' +\r\n [\r\n input.payerUserId,\r\n input.payeeUserId,\r\n input.payerNonce,\r\n input.payeeNonce,\r\n input.tokenSerial,\r\n ].join('|'),\r\n );\r\n}\r\n\r\n// ───────────────────────────── client ─────────────────────────────\r\n\r\nexport type IssueOfflineTokenInput = {\r\n /** Optional client-supplied serial (must be unique). */\r\n tokenSerial?: string;\r\n payerUserId: string;\r\n maxAmountKobo: number;\r\n currency?: string;\r\n ttlMs: number;\r\n};\r\n\r\nexport type FlurOfflineSettlementsClient = {\r\n /** Partner-only: pre-issue a bounded offline settlement token. */\r\n issueOfflineToken: (input: IssueOfflineTokenInput) => Promise<OfflineToken>;\r\n /** Get a token by serial (partner-scoped). */\r\n getOfflineToken: (tokenSerial: string) => Promise<OfflineToken>;\r\n /** Atomically settle a signed payment claim (idempotent). */\r\n settle: (claim: PaymentClaim) => Promise<SettleResponse>;\r\n /** Fetch a stored settlement by id or settlement_key. */\r\n getSettlement: (idOrKey: string) => Promise<Settlement>;\r\n /** List queued conflict/review items (partner-scoped). */\r\n listConflicts: () => Promise<{ items: unknown[] }>;\r\n};\r\n\r\nexport function createOfflineSettlementsClient(\r\n partner: FlurPartnerClient,\r\n): FlurOfflineSettlementsClient {\r\n return {\r\n issueOfflineToken: (input) =>\r\n partner.request<OfflineToken>({\r\n method: 'POST',\r\n path: '/v1/offline/tokens',\r\n body: {\r\n payerUserId: input.payerUserId,\r\n maxAmountKobo: input.maxAmountKobo,\r\n currency: input.currency ?? 'NGN',\r\n ttlMs: input.ttlMs,\r\n ...(input.tokenSerial ? { tokenSerial: input.tokenSerial } : {}),\r\n },\r\n }),\r\n getOfflineToken: (serial) =>\r\n partner.request<OfflineToken>({\r\n method: 'GET',\r\n path: `/v1/offline/tokens/${encodeURIComponent(serial)}`,\r\n }),\r\n settle: (claim) =>\r\n partner.request<SettleResponse>({\r\n method: 'POST',\r\n path: '/v1/offline/settlements',\r\n body: claim,\r\n }),\r\n getSettlement: (id) =>\r\n partner.request<Settlement>({\r\n method: 'GET',\r\n path: `/v1/offline/settlements/${encodeURIComponent(id)}`,\r\n }),\r\n listConflicts: () =>\r\n partner.request<{ items: unknown[] }>({\r\n method: 'GET',\r\n path: '/v1/offline/conflicts',\r\n }),\r\n };\r\n}\r\n","import { hmac } from '@noble/hashes/hmac';\r\nimport { sha256 } from '@noble/hashes/sha256';\r\n\r\nfunction bytesToHex(b: Uint8Array): string {\r\n let s = '';\r\n for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, '0');\r\n return s;\r\n}\r\n\r\nfunction constantTimeStringEqual(a: string, b: string): boolean {\r\n if (a.length !== b.length) return false;\r\n let diff = 0;\r\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n return diff === 0;\r\n}\r\n\r\nexport function bodySha256Hex(body: string): string {\r\n return bytesToHex(sha256(new TextEncoder().encode(body)));\r\n}\r\n\r\nexport function canonicalRequestString(input: {\r\n method: string;\r\n path: string;\r\n timestamp: string;\r\n nonce: string;\r\n body: string;\r\n}): string {\r\n return [\r\n input.method.toUpperCase(),\r\n input.path,\r\n input.timestamp,\r\n input.nonce,\r\n bodySha256Hex(input.body),\r\n ].join('\\n');\r\n}\r\n\r\nexport function signRequestHMAC(input: {\r\n method: string;\r\n path: string;\r\n timestamp: string;\r\n nonce: string;\r\n body: string;\r\n apiSecret: string;\r\n}): string {\r\n return bytesToHex(\r\n hmac(sha256, input.apiSecret, canonicalRequestString(input)),\r\n );\r\n}\r\n\r\nexport function verifyRequestHMAC(input: {\r\n method: string;\r\n path: string;\r\n timestamp: string;\r\n nonce: string;\r\n body: string;\r\n apiSecret: string;\r\n signature: string;\r\n}): boolean {\r\n const expected = signRequestHMAC(input);\r\n return constantTimeStringEqual(expected, input.signature.toLowerCase());\r\n}\r\n","import { z } from 'zod';\r\nimport { sha256 } from '@noble/hashes/sha256';\r\nimport { hmac } from '@noble/hashes/hmac';\r\nimport { bytesToHex } from '@noble/hashes/utils';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport const PARTNER_SCOPES = [\r\n 'passes:write',\r\n 'passes:read',\r\n 'passes:redeem',\r\n 'receipts:write',\r\n 'receipts:read',\r\n 'offline:issue',\r\n 'offline:settle',\r\n 'offline:read',\r\n 'collections:write',\r\n 'collections:read',\r\n 'collections:pay',\r\n 'collections:webhook',\r\n 'reports:read',\r\n 'payouts:write',\r\n 'payouts:read',\r\n 'partner:funding:write',\r\n 'partner:payout:write',\r\n 'partner:reconciliation:read',\r\n] as const;\r\nexport type PartnerScope = (typeof PARTNER_SCOPES)[number];\r\n\r\nexport const ApiCredentialPublicSchema = z.object({\r\n id: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n keyId: z.string(),\r\n scopes: z.array(z.enum(PARTNER_SCOPES)),\r\n label: z.string().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n lastUsedAtMs: z.number().int().nonnegative().nullable(),\r\n revokedAtMs: z.number().int().nonnegative().nullable(),\r\n});\r\nexport type ApiCredentialPublic = z.infer<typeof ApiCredentialPublicSchema>;\r\n\r\nexport const MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({\r\n secret: z.string().min(1),\r\n});\r\nexport type MintedApiCredential = z.infer<typeof MintedApiCredentialSchema>;\r\n\r\nexport type PartnerClientOptions = {\r\n baseUrl: string;\r\n /** Stable account id of the partner; included for observability only. */\r\n accountId?: string;\r\n /** Public key id from the mint response (e.g. flur_pk_...). */\r\n keyId: string;\r\n /** Plaintext secret from the mint response (e.g. flur_sk_...). */\r\n secret: string;\r\n fetchImpl?: typeof fetch;\r\n /** Override clock for tests. Returns ms. */\r\n nowMs?: () => number;\r\n /** Override nonce generator for tests. */\r\n nonce?: () => string;\r\n /** Optional scope claim forwarded as X-Flur-Scope; backend credentials remain authoritative. */\r\n scope?: readonly PartnerScope[];\r\n};\r\n\r\nconst enc = new TextEncoder();\r\n\r\nasync function sha256Hex(input: string | Uint8Array): Promise<string> {\r\n const data = typeof input === 'string' ? enc.encode(input) : input;\r\n return bytesToHex(sha256(data));\r\n}\r\n\r\nasync function hmacSha256Hex(keyHex: string, message: string): Promise<string> {\r\n // The server stores `secret_hash` as the hex string of sha256(secret) and\r\n // uses Node `createHmac('sha256', secret_hash)`, which treats the hex\r\n // STRING as raw UTF-8 bytes for the HMAC key. We do the same here.\r\n return bytesToHex(hmac(sha256, enc.encode(keyHex), enc.encode(message)));\r\n}\r\n\r\n/** Generate a 128-bit nonce as hex. CSPRNG-only — throws if unavailable. */\r\nfunction defaultNonce(): string {\r\n const c = (\r\n globalThis as {\r\n crypto?: {\r\n randomUUID?: () => string;\r\n getRandomValues?: (a: Uint8Array) => Uint8Array;\r\n };\r\n }\r\n ).crypto;\r\n if (typeof c?.randomUUID === 'function') return c.randomUUID();\r\n if (typeof c?.getRandomValues !== 'function') {\r\n throw new Error(\r\n 'Flur SDK: no CSPRNG available (globalThis.crypto.getRandomValues missing). ' +\r\n 'Refusing to fall back to Math.random for partner HMAC nonce generation.',\r\n );\r\n }\r\n const arr = new Uint8Array(16);\r\n c.getRandomValues(arr);\r\n let s = '';\r\n for (let i = 0; i < arr.length; i++) {\r\n s += arr[i].toString(16).padStart(2, '0');\r\n }\r\n return s;\r\n}\r\n\r\n/**\r\n * Build the canonical signing string. Must mirror the server.\r\n */\r\nfunction canonical(params: {\r\n method: string;\r\n path: string;\r\n ts: string;\r\n nonce: string;\r\n bodyHash: string;\r\n}): string {\r\n return [\r\n params.method.toUpperCase(),\r\n params.path,\r\n params.ts,\r\n params.nonce,\r\n params.bodyHash,\r\n ].join('\\n');\r\n}\r\n\r\nexport type PartnerSignResult = {\r\n authorization: string;\r\n ts: string;\r\n nonce: string;\r\n bodyHash: string;\r\n};\r\n\r\nexport async function signPartnerRequest(params: {\r\n keyId: string;\r\n secret: string;\r\n method: string;\r\n path: string;\r\n body?: string | Uint8Array;\r\n nowMs?: number;\r\n nonce?: string;\r\n}): Promise<PartnerSignResult> {\r\n const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1000));\r\n const nonce = params.nonce ?? defaultNonce();\r\n const bodyData =\r\n typeof params.body === 'string'\r\n ? enc.encode(params.body)\r\n : (params.body ?? new Uint8Array());\r\n const bodyHash = await sha256Hex(bodyData);\r\n const message = canonical({\r\n method: params.method,\r\n path: params.path,\r\n ts,\r\n nonce,\r\n bodyHash,\r\n });\r\n const signingKey = await sha256Hex(params.secret);\r\n const sig = await hmacSha256Hex(signingKey, message);\r\n return {\r\n authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,\r\n ts,\r\n nonce,\r\n bodyHash,\r\n };\r\n}\r\n\r\nexport type FlurPartnerClient = {\r\n /** Make a signed request. Resolves to parsed JSON or throws FlurApiError. */\r\n request: <T = unknown>(opts: {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n body?: unknown;\r\n }) => Promise<T>;\r\n /** Returns a fetch-compatible function with auto-signing. */\r\n fetch: typeof fetch;\r\n};\r\n\r\nexport function createFlurPartnerClient(\r\n opts: PartnerClientOptions,\r\n): FlurPartnerClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createFlurPartnerClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n const scopeHeader = normalizeScopeHeader(opts.scope);\r\n\r\n async function makeSignedInit(\r\n method: string,\r\n path: string,\r\n body?: string,\r\n ): Promise<RequestInit> {\r\n const sig = await signPartnerRequest({\r\n keyId: opts.keyId,\r\n secret: opts.secret,\r\n method,\r\n path,\r\n body: body ?? '',\r\n nowMs: opts.nowMs?.(),\r\n nonce: opts.nonce?.(),\r\n });\r\n const headers: Record<string, string> = {\r\n authorization: sig.authorization,\r\n accept: 'application/json',\r\n };\r\n if (scopeHeader) headers['x-flur-scope'] = scopeHeader;\r\n if (body !== undefined) headers['content-type'] = 'application/json';\r\n const init: RequestInit = { method, headers };\r\n if (body !== undefined) init.body = body;\r\n return init;\r\n }\r\n\r\n async function request<T>(opts2: {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n body?: unknown;\r\n }): Promise<T> {\r\n const bodyStr =\r\n opts2.body === undefined ? undefined : JSON.stringify(opts2.body);\r\n const init = await makeSignedInit(opts2.method, opts2.path, bodyStr);\r\n const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return raw as T;\r\n }\r\n\r\n const fetchLike: typeof fetch = async (input, init) => {\r\n const url = typeof input === 'string' ? input : (input as URL).toString();\r\n const u = new URL(url, baseUrl);\r\n const path = `${u.pathname}${u.search}`;\r\n const method = (init?.method ?? 'GET').toUpperCase();\r\n let bodyStr: string | undefined;\r\n if (init?.body) {\r\n bodyStr =\r\n typeof init.body === 'string'\r\n ? init.body\r\n : (init.body as { toString(): string }).toString();\r\n }\r\n const signed = await makeSignedInit(method, path, bodyStr);\r\n return fetchImpl(`${baseUrl}${path}`, {\r\n ...init,\r\n ...signed,\r\n headers: {\r\n ...(init?.headers as Record<string, string>),\r\n ...(signed.headers as Record<string, string>),\r\n },\r\n });\r\n };\r\n\r\n return { request, fetch: fetchLike };\r\n}\r\n\r\nfunction normalizeScopeHeader(\r\n scope: readonly PartnerScope[] | undefined,\r\n): string | undefined {\r\n if (!scope || scope.length === 0) return undefined;\r\n const unique = Array.from(new Set(scope));\r\n for (const item of unique) {\r\n if (!(PARTNER_SCOPES as readonly string[]).includes(item)) {\r\n throw new Error(`unsupported partner scope: ${item}`);\r\n }\r\n }\r\n return unique.join(' ');\r\n}\r\n\r\n/**\r\n * SDK helper for partner credential management endpoints. Uses an arbitrary\r\n * fetchImpl (typically a session-authenticated fetch) — not the partner HMAC.\r\n */\r\nexport type ApiCredentialsAdminClient = {\r\n list: (accountId: string) => Promise<{ items: ApiCredentialPublic[] }>;\r\n mint: (\r\n accountId: string,\r\n input: { scopes: PartnerScope[]; label?: string | null },\r\n ) => Promise<MintedApiCredential>;\r\n revoke: (\r\n accountId: string,\r\n credentialId: string,\r\n ) => Promise<ApiCredentialPublic>;\r\n};\r\n\r\nexport function createApiCredentialsAdminClient(opts: {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n}): ApiCredentialsAdminClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createApiCredentialsAdminClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n const listSchema = z.object({\r\n items: z.array(ApiCredentialPublicSchema),\r\n });\r\n\r\n return {\r\n list: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${accountId}/api-credentials`,\r\n undefined,\r\n (raw) => listSchema.parse(raw),\r\n ),\r\n mint: (accountId, input) =>\r\n call('POST', `/v1/accounts/${accountId}/api-credentials`, input, (raw) =>\r\n MintedApiCredentialSchema.parse(raw),\r\n ),\r\n revoke: (accountId, credentialId) =>\r\n call(\r\n 'DELETE',\r\n `/v1/accounts/${accountId}/api-credentials/${credentialId}`,\r\n undefined,\r\n (raw) => ApiCredentialPublicSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\n\r\nexport const PASS_KINDS = [\r\n 'ride-ticket',\r\n 'transit-pass',\r\n 'event-ticket',\r\n 'voucher',\r\n 'loyalty',\r\n 'receipt-link',\r\n] as const;\r\nexport type PassKind = (typeof PASS_KINDS)[number];\r\n\r\nexport const PASS_STATES = [\r\n 'issued',\r\n 'active',\r\n 'redeemed',\r\n 'expired',\r\n 'revoked',\r\n] as const;\r\nexport type PassState = (typeof PASS_STATES)[number];\r\n\r\n/** JSON-serialisable metadata payload — bounded to keep QR/offline encodings tractable. */\r\nexport const PassMetadataSchema = z.record(\r\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\r\n);\r\nexport type PassMetadata = z.infer<typeof PassMetadataSchema>;\r\n\r\nexport const PassSchema = z\r\n .object({\r\n passId: z.string().min(1),\r\n /** Optional client/template grouping id (server may omit). */\r\n templateId: z.string().min(1).optional(),\r\n /** Optional human-facing holder identity (server may omit). The cryptographic binding\r\n * is `holderDevicePubkey` below. */\r\n holderUserId: z.string().min(1).optional(),\r\n kind: z.enum(PASS_KINDS),\r\n issuerId: z.string().min(1),\r\n issuedAtMs: z.number().int().nonnegative(),\r\n validFromMs: z.number().int().nonnegative(),\r\n validUntilMs: z.number().int().positive(),\r\n state: z.enum(PASS_STATES),\r\n metadata: PassMetadataSchema,\r\n nonce: z.string().min(1),\r\n /** Device id this pass is bound to (FK to backend `device_keys`). */\r\n holderDeviceId: z.string().min(1),\r\n /** SubjectPublicKeyInfo DER (P-256) of the bound device, base64. The redemption\r\n * signature is verified against this key — it is the security-critical binding. */\r\n holderDevicePubkey: z\r\n .string()\r\n .min(64)\r\n .max(4096)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n /** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */\r\n amountKobo: z.number().int().nonnegative().optional(),\r\n /** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */\r\n currency: z.string().min(3).max(8),\r\n /** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */\r\n counterSeed: z.number().int().nonnegative(),\r\n /** Optional cumulative spend cap in kobo across all redemptions of this pass. */\r\n cumulativeCapKobo: z.number().int().nonnegative().optional(),\r\n /** ASN.1 DER ECDSA P-256 signature, base64. */\r\n issuerSig: z\r\n .string()\r\n .min(64)\r\n .max(2048)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n })\r\n .refine((v) => v.validUntilMs > v.validFromMs, {\r\n message: 'validUntilMs must be greater than validFromMs',\r\n });\r\n\r\nexport type Pass = z.infer<typeof PassSchema>;\r\nexport type UnsignedPass = Omit<Pass, 'issuerSig'>;\r\n\r\nexport type BuildPassInput = {\r\n passId: string;\r\n templateId?: string;\r\n holderUserId?: string;\r\n kind: PassKind;\r\n issuerId: string;\r\n issuedAtMs: number;\r\n validFromMs: number;\r\n validUntilMs: number;\r\n state: PassState;\r\n metadata: PassMetadata;\r\n nonce: string;\r\n holderDeviceId: string;\r\n holderDevicePubkey: string;\r\n amountKobo?: number;\r\n currency?: string;\r\n counterSeed: number;\r\n cumulativeCapKobo?: number;\r\n};\r\n\r\nexport function buildPass(input: BuildPassInput): UnsignedPass {\r\n if (input.validUntilMs <= input.validFromMs) {\r\n throw new Error('validUntilMs must be greater than validFromMs');\r\n }\r\n const out: UnsignedPass = {\r\n passId: input.passId,\r\n kind: input.kind,\r\n issuerId: input.issuerId,\r\n issuedAtMs: input.issuedAtMs,\r\n validFromMs: input.validFromMs,\r\n validUntilMs: input.validUntilMs,\r\n state: input.state,\r\n metadata: input.metadata,\r\n nonce: input.nonce,\r\n holderDeviceId: input.holderDeviceId,\r\n holderDevicePubkey: input.holderDevicePubkey,\r\n currency: input.currency ?? 'NGN',\r\n counterSeed: input.counterSeed,\r\n };\r\n if (typeof input.templateId === 'string') out.templateId = input.templateId;\r\n if (typeof input.holderUserId === 'string')\r\n out.holderUserId = input.holderUserId;\r\n if (typeof input.amountKobo === 'number') out.amountKobo = input.amountKobo;\r\n if (typeof input.cumulativeCapKobo === 'number') {\r\n out.cumulativeCapKobo = input.cumulativeCapKobo;\r\n }\r\n return out;\r\n}\r\n\r\nexport function signPass(\r\n unsigned: UnsignedPass,\r\n issuerPrivateKey: Uint8Array,\r\n): Pass {\r\n const issuerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerPrivateKey,\r\n );\r\n return { ...unsigned, issuerSig };\r\n}\r\n\r\nexport function verifyPass(\r\n pass: Pass,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = PassSchema.parse(pass);\r\n const { issuerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Validity window check is done separately from signature verification so callers can\r\n * decide their clock-skew tolerance.\r\n */\r\nexport function isPassWithinValidity(pass: Pass, nowMs: number): boolean {\r\n return nowMs >= pass.validFromMs && nowMs < pass.validUntilMs;\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport {\r\n signIssuerP256 as signP256,\r\n verifyIssuerP256 as verifyP256,\r\n} from '../crypto/p256-issuer.js';\r\nimport { PassSchema, type Pass } from './pass.js';\r\nimport {\r\n FlurExpiredError,\r\n FlurReplayError,\r\n FlurCapExceededError,\r\n} from '../errors.js';\r\n\r\nconst Base64Std = z\r\n .string()\r\n .min(16)\r\n .max(2048)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/, 'expected base64 (std)');\r\n\r\nexport const RedemptionSchema = z.object({\r\n pass: PassSchema,\r\n redeemerId: z.string().min(1),\r\n redeemedAtMs: z.number().int().nonnegative(),\r\n /** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed\r\n * and > the redeemer's lastSeenCounter for this pass. */\r\n counter: z.number().int().positive(),\r\n /** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */\r\n amountKobo: z.number().int().nonnegative(),\r\n nonce: z.string().min(1),\r\n /** ASN.1 DER ECDSA P-256 signature over canonicalJSONBytes(unsigned), base64. */\r\n holderSig: Base64Std,\r\n});\r\nexport type Redemption = z.infer<typeof RedemptionSchema>;\r\nexport type UnsignedRedemption = Omit<Redemption, 'holderSig'>;\r\n\r\nexport type BuildRedemptionInput = {\r\n pass: Pass;\r\n redeemerId: string;\r\n redeemedAtMs: number;\r\n counter: number;\r\n amountKobo?: number;\r\n nonce: string;\r\n /** Optional local clock — if supplied, fail-fast against pass.validUntilMs. */\r\n nowMs?: number;\r\n /** Last counter the holder has seen for this pass (default: pass.counterSeed). */\r\n lastSeenCounter?: number;\r\n /** Total kobo already redeemed against this pass (default: 0). Used with pass.cumulativeCapKobo. */\r\n cumulativeUsedKobo?: number;\r\n};\r\n\r\nconst REDEEMABLE_STATES = new Set(['issued', 'active']);\r\n\r\nexport function buildRedemption(\r\n input: BuildRedemptionInput,\r\n): UnsignedRedemption {\r\n if (!REDEEMABLE_STATES.has(input.pass.state)) {\r\n throw new Error(`pass not in redeemable state: ${input.pass.state}`);\r\n }\r\n if (input.redeemedAtMs < input.pass.validFromMs) {\r\n throw new Error('redeemedAtMs is before pass validFromMs');\r\n }\r\n if (input.redeemedAtMs >= input.pass.validUntilMs) {\r\n throw new FlurExpiredError(\r\n `pass ${input.pass.passId} expired at ${input.pass.validUntilMs}`,\r\n );\r\n }\r\n // Wall-clock expiry check (offline-safe; backend remains authoritative).\r\n const now =\r\n typeof input.nowMs === 'number' ? input.nowMs : input.redeemedAtMs;\r\n if (now >= input.pass.validUntilMs) {\r\n throw new FlurExpiredError(\r\n `pass ${input.pass.passId} expired at ${input.pass.validUntilMs}`,\r\n );\r\n }\r\n if (!input.pass.holderDevicePubkey) {\r\n throw new Error(\r\n 'pass.holderDevicePubkey is required to build a redemption',\r\n );\r\n }\r\n\r\n // Counter monotonicity: must exceed both seed and any locally-known prior counter.\r\n const lastSeen = Math.max(\r\n input.pass.counterSeed,\r\n typeof input.lastSeenCounter === 'number' ? input.lastSeenCounter : 0,\r\n );\r\n if (input.counter <= lastSeen) {\r\n throw new FlurReplayError(\r\n `redemption counter ${input.counter} must be > lastSeenCounter ${lastSeen}`,\r\n );\r\n }\r\n\r\n const amount = input.amountKobo ?? 0;\r\n\r\n // Cumulative cap (when set on the pass): used + this <= cap.\r\n if (typeof input.pass.cumulativeCapKobo === 'number') {\r\n const used = input.cumulativeUsedKobo ?? 0;\r\n if (used + amount > input.pass.cumulativeCapKobo) {\r\n throw new FlurCapExceededError(\r\n `pass ${input.pass.passId} cap ${input.pass.cumulativeCapKobo} would be exceeded (used ${used} + ${amount})`,\r\n );\r\n }\r\n }\r\n\r\n return {\r\n pass: input.pass,\r\n redeemerId: input.redeemerId,\r\n redeemedAtMs: input.redeemedAtMs,\r\n counter: input.counter,\r\n amountKobo: amount,\r\n nonce: input.nonce,\r\n };\r\n}\r\n\r\nexport function signRedemption(\r\n unsigned: UnsignedRedemption,\r\n holderDevicePrivateKey: Uint8Array,\r\n): Redemption {\r\n const holderSig = signP256(\r\n canonicalJSONBytes(unsigned),\r\n holderDevicePrivateKey,\r\n );\r\n return { ...unsigned, holderSig };\r\n}\r\n\r\n/**\r\n * Verifies, in order:\r\n * 1. The pass itself is signed by the issuer.\r\n * 2. The pass binds a `holderDevicePubkey` (top-level, security-critical).\r\n * 3. The redemption is signed by that bound device key.\r\n * 4. The redemption counter is strictly greater than pass.counterSeed.\r\n */\r\nexport function verifyRedemption(\r\n r: Redemption,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = RedemptionSchema.parse(r);\r\n if (parsed.counter <= parsed.pass.counterSeed) return false;\r\n const { issuerSig, ...passUnsigned } = parsed.pass;\r\n if (\r\n !verifyP256(\r\n canonicalJSONBytes(passUnsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n )\r\n ) {\r\n return false;\r\n }\r\n const holderPub = parsed.pass.holderDevicePubkey;\r\n if (typeof holderPub !== 'string') return false;\r\n const { holderSig, ...unsigned } = parsed;\r\n return verifyP256(canonicalJSONBytes(unsigned), holderSig, holderPub);\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport { signIssuerP256, verifyIssuerP256 } from '../crypto/p256-issuer.js';\r\n\r\nexport const RECEIPT_CHANNELS = ['cash', 'pass'] as const;\r\nexport type ReceiptChannel = (typeof RECEIPT_CHANNELS)[number];\r\n\r\n/** @deprecated use {@link RECEIPT_CHANNELS}. Will be removed before 1.0. */\r\nexport const RECEIPT_KINDS = RECEIPT_CHANNELS;\r\n/** @deprecated use {@link ReceiptChannel}. */\r\nexport type ReceiptKind = ReceiptChannel;\r\n\r\n/** Free-form payload reserved for channel-specific extras (e.g. memo, intent metadata).\r\n * Top-level fields below are the security-relevant facts and must not be duplicated here. */\r\nexport const ReceiptPayloadSchema = z.record(\r\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\r\n);\r\nexport type ReceiptPayload = z.infer<typeof ReceiptPayloadSchema>;\r\n\r\n/** BE-20 wire schema: channel + exactly one of `intentId` (cash) or `passRedemptionId` (pass). */\r\nexport const ReceiptSchema = z\r\n .object({\r\n receiptId: z.string().min(1),\r\n channel: z.enum(RECEIPT_CHANNELS),\r\n /** Cash-channel: send_intents.id. Required when channel === 'cash'. */\r\n intentId: z.string().min(1).optional(),\r\n /** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */\r\n passRedemptionId: z.string().min(1).optional(),\r\n payerUserId: z.string().min(1),\r\n payeeUserId: z.string().min(1),\r\n amountKobo: z.number().int().nonnegative(),\r\n currency: z.string().min(3).max(8),\r\n issuedAtMs: z.number().int().nonnegative(),\r\n issuerId: z.string().min(1),\r\n payload: ReceiptPayloadSchema,\r\n /** ASN.1 DER ECDSA P-256 signature, base64. */\r\n issuerSig: z\r\n .string()\r\n .min(64)\r\n .max(2048)\r\n .regex(/^[A-Za-z0-9+/]+={0,2}$/),\r\n })\r\n .superRefine((v, ctx) => {\r\n if (v.channel === 'cash') {\r\n if (!v.intentId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'cash receipts require intentId',\r\n path: ['intentId'],\r\n });\r\n }\r\n if (v.passRedemptionId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'cash receipts must not carry passRedemptionId',\r\n path: ['passRedemptionId'],\r\n });\r\n }\r\n } else if (v.channel === 'pass') {\r\n if (!v.passRedemptionId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'pass receipts require passRedemptionId',\r\n path: ['passRedemptionId'],\r\n });\r\n }\r\n if (v.intentId) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'pass receipts must not carry intentId',\r\n path: ['intentId'],\r\n });\r\n }\r\n }\r\n });\r\nexport type Receipt = z.infer<typeof ReceiptSchema>;\r\nexport type UnsignedReceipt = Omit<Receipt, 'issuerSig'>;\r\n\r\nexport type BuildReceiptInput = {\r\n receiptId: string;\r\n channel: ReceiptChannel;\r\n intentId?: string;\r\n passRedemptionId?: string;\r\n payerUserId: string;\r\n payeeUserId: string;\r\n amountKobo: number;\r\n currency: string;\r\n issuedAtMs: number;\r\n issuerId: string;\r\n payload?: ReceiptPayload;\r\n};\r\n\r\nexport function buildReceipt(input: BuildReceiptInput): UnsignedReceipt {\r\n if (input.channel === 'cash') {\r\n if (!input.intentId) {\r\n throw new Error('cash receipts require intentId');\r\n }\r\n if (input.passRedemptionId) {\r\n throw new Error('cash receipts must not carry passRedemptionId');\r\n }\r\n } else {\r\n if (!input.passRedemptionId) {\r\n throw new Error('pass receipts require passRedemptionId');\r\n }\r\n if (input.intentId) {\r\n throw new Error('pass receipts must not carry intentId');\r\n }\r\n }\r\n const out: UnsignedReceipt = {\r\n receiptId: input.receiptId,\r\n channel: input.channel,\r\n payerUserId: input.payerUserId,\r\n payeeUserId: input.payeeUserId,\r\n amountKobo: input.amountKobo,\r\n currency: input.currency,\r\n issuedAtMs: input.issuedAtMs,\r\n issuerId: input.issuerId,\r\n payload: input.payload ?? {},\r\n };\r\n if (input.intentId) out.intentId = input.intentId;\r\n if (input.passRedemptionId) out.passRedemptionId = input.passRedemptionId;\r\n return out;\r\n}\r\n\r\nexport function signReceipt(\r\n unsigned: UnsignedReceipt,\r\n issuerPrivateKey: Uint8Array,\r\n): Receipt {\r\n const issuerSig = signIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerPrivateKey,\r\n );\r\n return { ...unsigned, issuerSig };\r\n}\r\n\r\nexport function verifyReceipt(\r\n r: Receipt,\r\n issuerPublicKeySpkiB64: string,\r\n): boolean {\r\n try {\r\n const parsed = ReceiptSchema.parse(r);\r\n const { issuerSig, ...unsigned } = parsed;\r\n return verifyIssuerP256(\r\n canonicalJSONBytes(unsigned),\r\n issuerSig,\r\n issuerPublicKeySpkiB64,\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","import {\r\n PassSchema,\r\n verifyPass as verifyPassFn,\r\n type Pass,\r\n type PassKind,\r\n type PassMetadata,\r\n type PassState,\r\n} from './pass.js';\r\nimport { RedemptionSchema, type Redemption } from './redemption.js';\r\nimport {\r\n ReceiptSchema,\r\n type ReceiptPayload,\r\n type Receipt,\r\n} from '../receipts/receipt.js';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\n// Re-export so existing `from \"./client.js\"` imports keep working.\r\nexport { FlurApiError };\r\n\r\nexport type PassesClientOptions = {\r\n baseUrl: string;\r\n /**\r\n * Pre-configured fetch that signs partner requests. Use the fetch returned by\r\n * `createFlurPartnerClient(...)` (Flur-Hmac scheme). Falls back to global fetch.\r\n */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type IssuePassInput = {\r\n /** Device this pass is bound to. Required (BE-19). */\r\n holderDeviceId: string;\r\n /** P-256 SubjectPublicKeyInfo DER public key (base64) of the bound device. Required (BE-19). */\r\n holderDevicePubkey: string;\r\n /** Pass kind (server may default for templated flows). */\r\n kind: PassKind;\r\n /** Optional fixed amount for monetary passes (kobo). */\r\n amountKobo?: number;\r\n /** Optional cumulative spend cap in kobo across all redemptions. */\r\n cumulativeCapKobo?: number;\r\n validFromMs: number;\r\n validUntilMs: number;\r\n metadata?: PassMetadata;\r\n /** Optional template grouping id (server may emit one if omitted). */\r\n templateId?: string;\r\n /** Optional human-facing holder identity. */\r\n holderUserId?: string;\r\n /** Optional client-supplied id for idempotency / retries. */\r\n passId?: string;\r\n};\r\n\r\nexport type ListPassesInput = {\r\n holderDeviceId?: string;\r\n holderUserId?: string;\r\n state?: PassState;\r\n kind?: PassKind;\r\n templateId?: string;\r\n limit?: number;\r\n cursor?: string;\r\n};\r\n\r\nexport type ListPassesResponse = {\r\n items: Pass[];\r\n nextCursor: string | null;\r\n};\r\n\r\nexport type RevokePassInput = {\r\n reason: string;\r\n};\r\n\r\nexport type RedeemPassResponse = {\r\n pass: Pass;\r\n redemptionId: string;\r\n};\r\n\r\nexport type AtomicRedeemReceiptInput = {\r\n payeeUserId: string;\r\n payload?: ReceiptPayload;\r\n receiptId?: string;\r\n};\r\n\r\nexport type AtomicRedeemResponse = {\r\n pass: Pass;\r\n redemptionId: string;\r\n receipt: Receipt;\r\n};\r\n\r\nexport type PassesClient = {\r\n issuePass: (input: IssuePassInput) => Promise<Pass>;\r\n listPasses: (input: ListPassesInput) => Promise<ListPassesResponse>;\r\n getPass: (passId: string) => Promise<Pass>;\r\n redeemPassDetailed: (\r\n passId: string,\r\n redemption: Redemption,\r\n ) => Promise<RedeemPassResponse>;\r\n redeemPass: (passId: string, redemption: Redemption) => Promise<Pass>;\r\n redeemPassWithReceipt: (\r\n passId: string,\r\n redemption: Redemption,\r\n receipt: AtomicRedeemReceiptInput,\r\n ) => Promise<AtomicRedeemResponse>;\r\n revokePass: (passId: string, input: RevokePassInput) => Promise<Pass>;\r\n /** Local P-256 ECDSA verification of a pass envelope under the supplied issuer SPKI base64 key. */\r\n verifyPass: (pass: Pass, issuerPublicKeySpkiB64: string) => boolean;\r\n};\r\n\r\nexport function createPassesClient(opts: PassesClientOptions): PassesClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl)\r\n throw new Error('createPassesClient: no fetch implementation available');\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown = undefined;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON error body\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n (raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : undefined) ?? `http_${resp.status}`;\r\n const message =\r\n (raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : undefined) ?? `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n return {\r\n issuePass: (input) =>\r\n call('POST', '/v1/passes', input, (raw) => PassSchema.parse(raw)),\r\n\r\n listPasses: (input) => {\r\n const qs = new URLSearchParams();\r\n if (input.holderDeviceId) qs.set('holderDeviceId', input.holderDeviceId);\r\n if (input.holderUserId) qs.set('holderUserId', input.holderUserId);\r\n if (input.state) qs.set('state', input.state);\r\n if (input.kind) qs.set('kind', input.kind);\r\n if (input.templateId) qs.set('templateId', input.templateId);\r\n if (typeof input.limit === 'number') qs.set('limit', String(input.limit));\r\n if (input.cursor) qs.set('cursor', input.cursor);\r\n const path = `/v1/passes${qs.size > 0 ? `?${qs.toString()}` : ''}`;\r\n return call('GET', path, undefined, (raw) => {\r\n const obj = raw as { items?: unknown; nextCursor?: unknown };\r\n const items = (obj.items as unknown[]).map((it) =>\r\n PassSchema.parse(it),\r\n );\r\n const nextCursor =\r\n typeof obj.nextCursor === 'string' ? obj.nextCursor : null;\r\n return { items, nextCursor };\r\n });\r\n },\r\n\r\n getPass: (passId) =>\r\n call(\r\n 'GET',\r\n `/v1/passes/${encodeURIComponent(passId)}`,\r\n undefined,\r\n (raw) => PassSchema.parse(raw),\r\n ),\r\n\r\n redeemPass: (passId, redemption) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/redeem`,\r\n RedemptionSchema.parse(redemption),\r\n (raw) => {\r\n const obj = raw as { redemptionId?: unknown };\r\n return {\r\n pass: PassSchema.parse(raw),\r\n redemptionId:\r\n typeof obj.redemptionId === 'string' ? obj.redemptionId : '',\r\n };\r\n },\r\n ).then((result) => result.pass),\r\n\r\n redeemPassDetailed: (passId, redemption) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/redeem`,\r\n RedemptionSchema.parse(redemption),\r\n (raw) => {\r\n const obj = raw as { redemptionId?: unknown };\r\n return {\r\n pass: PassSchema.parse(raw),\r\n redemptionId:\r\n typeof obj.redemptionId === 'string' ? obj.redemptionId : '',\r\n };\r\n },\r\n ),\r\n\r\n redeemPassWithReceipt: (passId, redemption, receipt) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/redeem-with-receipt`,\r\n {\r\n redemption: RedemptionSchema.parse(redemption),\r\n receipt,\r\n },\r\n (raw) => {\r\n const obj = raw as {\r\n pass?: unknown;\r\n redemptionId?: unknown;\r\n receipt?: unknown;\r\n };\r\n return {\r\n pass: PassSchema.parse(obj.pass),\r\n redemptionId:\r\n typeof obj.redemptionId === 'string' ? obj.redemptionId : '',\r\n receipt: ReceiptSchema.parse(obj.receipt),\r\n };\r\n },\r\n ),\r\n\r\n revokePass: (passId, input) =>\r\n call(\r\n 'POST',\r\n `/v1/passes/${encodeURIComponent(passId)}/revoke`,\r\n input,\r\n (raw) => PassSchema.parse(raw),\r\n ),\r\n\r\n verifyPass: (pass, issuerPublicKey) => verifyPassFn(pass, issuerPublicKey),\r\n };\r\n}\r\n","import {\r\n ReceiptSchema,\r\n verifyReceipt as verifyReceiptFn,\r\n type Receipt,\r\n type ReceiptChannel,\r\n type ReceiptPayload,\r\n} from './receipt.js';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport type ReceiptsClientOptions = {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type IssueReceiptInput = {\r\n channel: ReceiptChannel;\r\n /** Required for cash channel; FK to send_intents.id. */\r\n intentId?: string;\r\n /** Required for pass channel; FK to pass_redemptions.id. */\r\n passRedemptionId?: string;\r\n payerUserId: string;\r\n payeeUserId: string;\r\n amountKobo: number;\r\n currency: string;\r\n payload?: ReceiptPayload;\r\n /** Optional client-supplied id for idempotency / retries. */\r\n receiptId?: string;\r\n};\r\n\r\nexport type ListReceiptsInput = {\r\n /** Filter by either side of the receipt. Server scopes by caller identity. */\r\n payerUserId?: string;\r\n payeeUserId?: string;\r\n channel?: ReceiptChannel;\r\n limit?: number;\r\n cursor?: string;\r\n};\r\n\r\nexport type ListReceiptsResponse = {\r\n items: Receipt[];\r\n nextCursor: string | null;\r\n};\r\n\r\nexport type ReceiptsClient = {\r\n issueReceipt: (input: IssueReceiptInput) => Promise<Receipt>;\r\n /** Alias of `getById`, matches addendum surface. */\r\n getReceipt: (receiptId: string) => Promise<Receipt>;\r\n getById: (receiptId: string) => Promise<Receipt>;\r\n /** Look up a cash-channel receipt by its originating intentId. */\r\n getByIntentId: (intentId: string) => Promise<Receipt>;\r\n /** Look up a pass-channel receipt by its originating passRedemptionId. */\r\n getByPassRedemptionId: (passRedemptionId: string) => Promise<Receipt>;\r\n listForUser: (input: ListReceiptsInput) => Promise<ListReceiptsResponse>;\r\n /** Local P-256 ECDSA verification of a receipt envelope under the supplied issuer SPKI base64 key. */\r\n verifyReceipt: (receipt: Receipt, issuerPublicKeySpkiB64: string) => boolean;\r\n};\r\n\r\nexport function createReceiptsClient(\r\n opts: ReceiptsClientOptions,\r\n): ReceiptsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl)\r\n throw new Error('createReceiptsClient: no fetch implementation available');\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown = undefined;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // ignore non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n const getById: ReceiptsClient['getById'] = (receiptId) =>\r\n call(\r\n 'GET',\r\n `/v1/receipts/${encodeURIComponent(receiptId)}`,\r\n undefined,\r\n (raw) => ReceiptSchema.parse(raw),\r\n );\r\n\r\n return {\r\n issueReceipt: (input) =>\r\n call('POST', '/v1/receipts', input, (raw) => ReceiptSchema.parse(raw)),\r\n\r\n getReceipt: getById,\r\n getById,\r\n\r\n getByIntentId: (intentId) =>\r\n call(\r\n 'GET',\r\n `/v1/receipts/by-intent/${encodeURIComponent(intentId)}`,\r\n undefined,\r\n (raw) => ReceiptSchema.parse(raw),\r\n ),\r\n\r\n getByPassRedemptionId: (passRedemptionId) =>\r\n call(\r\n 'GET',\r\n `/v1/receipts/by-pass-redemption/${encodeURIComponent(passRedemptionId)}`,\r\n undefined,\r\n (raw) => ReceiptSchema.parse(raw),\r\n ),\r\n\r\n listForUser: (input) => {\r\n const qs = new URLSearchParams();\r\n if (input.payerUserId) qs.set('payerUserId', input.payerUserId);\r\n if (input.payeeUserId) qs.set('payeeUserId', input.payeeUserId);\r\n if (input.channel) qs.set('channel', input.channel);\r\n if (typeof input.limit === 'number') qs.set('limit', String(input.limit));\r\n if (input.cursor) qs.set('cursor', input.cursor);\r\n const path = `/v1/receipts${qs.size > 0 ? `?${qs.toString()}` : ''}`;\r\n return call('GET', path, undefined, (raw) => {\r\n const obj = raw as { items?: unknown; nextCursor?: unknown };\r\n const items = (obj.items as unknown[]).map((it) =>\r\n ReceiptSchema.parse(it),\r\n );\r\n const nextCursor =\r\n typeof obj.nextCursor === 'string' ? obj.nextCursor : null;\r\n return { items, nextCursor };\r\n });\r\n },\r\n\r\n verifyReceipt: (receipt, issuerPublicKey) =>\r\n verifyReceiptFn(receipt, issuerPublicKey),\r\n };\r\n}\r\n","import {\r\n encodeNQR,\r\n parseNQR,\r\n type NQRPayloadInput,\r\n type ParsedNQR,\r\n} from '../nqr/index.js';\r\nimport { createFlurPartnerClient } from '../partner/index.js';\r\nimport type { PartnerScope } from '../partner/index.js';\r\nimport { createPassesClient, type PassesClient } from '../passes/index.js';\r\nimport {\r\n createReceiptsClient,\r\n type ReceiptsClient,\r\n} from '../receipts/index.js';\r\nimport {\r\n createPartnerCollectionsClient,\r\n type PartnerCollectionsClient,\r\n} from '../collections/index.js';\r\n\r\nexport type FlurInitOptions = {\r\n apiKey: string;\r\n apiSecret: string;\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n /** When true, all QR generation is performed locally without any network call. */\r\n offlineMode?: boolean;\r\n /** Optional scope claim forwarded as `X-Flur-Scope`. Backend credentials remain authoritative. */\r\n scope?: readonly PartnerScope[];\r\n};\r\n\r\nexport type FlurPaymentEvent = {\r\n type: string;\r\n reference?: string;\r\n [k: string]: unknown;\r\n};\r\n\r\nexport type SubscribeOptions = {\r\n reference: string;\r\n onEvent: (event: FlurPaymentEvent) => void;\r\n onError?: (err: unknown) => void;\r\n};\r\n\r\nexport function generateStaticQR(\r\n input: Omit<NQRPayloadInput, 'pointOfInitiation'>,\r\n): string {\r\n return encodeNQR({ ...input, pointOfInitiation: 'static' });\r\n}\r\n\r\nexport function generateDynamicQR(\r\n input: Omit<NQRPayloadInput, 'pointOfInitiation'>,\r\n): string {\r\n return encodeNQR({ ...input, pointOfInitiation: 'dynamic' });\r\n}\r\n\r\nexport function parseQR(payload: string): ParsedNQR {\r\n return parseNQR(payload);\r\n}\r\n\r\nexport type CashNamespace = {\r\n generateStaticQR: typeof generateStaticQR;\r\n generateDynamicQR: typeof generateDynamicQR;\r\n parseQR: typeof parseQR;\r\n subscribeToPayments: (opts: SubscribeOptions) => () => void;\r\n};\r\n\r\nexport type FlurHandle = CashNamespace & {\r\n /** Cash / money: NQR generation, payment subscriptions, transfers (future). */\r\n cash: CashNamespace;\r\n /** Collections: merchant NQR intents, reports, statements, payouts. */\r\n collections: PartnerCollectionsClient;\r\n /** Passes: tickets, vouchers, loyalty, transit. */\r\n passes: PassesClient;\r\n /** Receipts: signed, immutable views over cash + pass events. */\r\n receipts: ReceiptsClient;\r\n};\r\n\r\nexport function init(opts: FlurInitOptions): FlurHandle {\r\n const partner = createFlurPartnerClient({\r\n baseUrl: opts.baseUrl,\r\n keyId: opts.apiKey,\r\n secret: opts.apiSecret,\r\n fetchImpl: opts.fetchImpl,\r\n scope: opts.scope,\r\n });\r\n const signedFetch = partner.fetch;\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n function subscribeToPayments(s: SubscribeOptions) {\r\n let cancelled = false;\r\n\r\n queueMicrotask(() => {\r\n if (cancelled) return;\r\n s.onError?.(\r\n new Error(\r\n 'cash.subscribeToPayments is not available on this backend release; use collections reports or provider webhooks for payment status.',\r\n ),\r\n );\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }\r\n\r\n const cash: CashNamespace = {\r\n generateStaticQR,\r\n generateDynamicQR,\r\n parseQR,\r\n subscribeToPayments,\r\n };\r\n\r\n const passes = createPassesClient({ baseUrl, fetchImpl: signedFetch });\r\n const receipts = createReceiptsClient({ baseUrl, fetchImpl: signedFetch });\r\n const collections = createPartnerCollectionsClient({\r\n baseUrl,\r\n fetchImpl: signedFetch,\r\n });\r\n\r\n return {\r\n // top-level back-compat surface\r\n generateStaticQR,\r\n generateDynamicQR,\r\n parseQR,\r\n subscribeToPayments,\r\n // namespaces\r\n cash,\r\n collections,\r\n passes,\r\n receipts,\r\n };\r\n}\r\n","import { z } from 'zod';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\nexport const ACCOUNT_TYPES = ['personal', 'business', 'partner'] as const;\r\nexport type AccountType = (typeof ACCOUNT_TYPES)[number];\r\n\r\nexport const ACCOUNT_STATUSES = ['active', 'suspended', 'closed'] as const;\r\nexport type AccountStatus = (typeof ACCOUNT_STATUSES)[number];\r\n\r\nexport const MEMBERSHIP_ROLES = ['owner', 'admin', 'driver', 'staff'] as const;\r\nexport type MembershipRole = (typeof MEMBERSHIP_ROLES)[number];\r\n\r\nexport const AccountSchema = z.object({\r\n accountId: z.string().uuid(),\r\n type: z.enum(ACCOUNT_TYPES),\r\n displayName: z.string().min(1),\r\n status: z.enum(ACCOUNT_STATUSES),\r\n ownerUserId: z.string().uuid().nullable(),\r\n createdAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type Account = z.infer<typeof AccountSchema>;\r\n\r\nexport const AccountMembershipSchema = z.object({\r\n accountId: z.string().uuid(),\r\n userId: z.string().uuid(),\r\n role: z.enum(MEMBERSHIP_ROLES),\r\n createdAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type AccountMembership = z.infer<typeof AccountMembershipSchema>;\r\n\r\nexport type AccountsClientOptions = {\r\n baseUrl: string;\r\n /** Pre-configured fetch (e.g. with a session bearer or partner HMAC). */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type CreateBusinessAccountInput = {\r\n displayName: string;\r\n type?: 'business' | 'partner';\r\n};\r\n\r\nexport type AddMemberInput = {\r\n userId: string;\r\n role: MembershipRole;\r\n};\r\n\r\nexport type AccountsClient = {\r\n listMyAccounts: () => Promise<{ items: Account[] }>;\r\n getAccount: (accountId: string) => Promise<Account>;\r\n listMembers: (accountId: string) => Promise<{ items: AccountMembership[] }>;\r\n createBusinessAccount: (\r\n input: CreateBusinessAccountInput,\r\n ) => Promise<Account>;\r\n addMember: (\r\n accountId: string,\r\n input: AddMemberInput,\r\n ) => Promise<AccountMembership>;\r\n};\r\n\r\nexport function createAccountsClient(\r\n opts: AccountsClientOptions,\r\n): AccountsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error('createAccountsClient: no fetch implementation available');\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n };\r\n if (body !== undefined) init.body = JSON.stringify(body);\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown = undefined;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n // non-JSON\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n const itemsSchema = z.object({ items: z.array(AccountSchema) });\r\n const memberItemsSchema = z.object({\r\n items: z.array(AccountMembershipSchema),\r\n });\r\n\r\n return {\r\n listMyAccounts: () =>\r\n call('GET', '/v1/accounts/me', undefined, (raw) =>\r\n itemsSchema.parse(raw),\r\n ),\r\n getAccount: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${encodeURIComponent(accountId)}`,\r\n undefined,\r\n (raw) => AccountSchema.parse(raw),\r\n ),\r\n listMembers: (accountId) =>\r\n call(\r\n 'GET',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/members`,\r\n undefined,\r\n (raw) => memberItemsSchema.parse(raw),\r\n ),\r\n createBusinessAccount: (input) =>\r\n call('POST', '/v1/accounts', input, (raw) => AccountSchema.parse(raw)),\r\n addMember: (accountId, input) =>\r\n call(\r\n 'POST',\r\n `/v1/accounts/${encodeURIComponent(accountId)}/members`,\r\n input,\r\n (raw) => AccountMembershipSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n","/**\n * Consumer-side Offline Collect SDK client.\n *\n * Wraps the backend `/v1/me/offline/*` routes (session-bearer auth ONLY —\n * NOT partner HMAC). These power the payer authorization side of Flur Offline Collect:\n * - register/list/revoke device signing keys\n * - issue account-funded Offline Authorization Certificates (OACs)\n * - read offline status (active OAC)\n * - submit a signed offline collection claim for settlement\n *\n * Schemas mirror `flur-backend/src/offline-consumer/types.ts`.\n */\nimport { z } from 'zod';\nimport { FlurApiError } from '../errors.js';\nimport {\n SignedRevocationListSchema,\n type SignedRevocationList,\n} from './revocation.js';\n\n// ───────────────────────────── shared regex ─────────────────────────────\n\nconst Sha256Hex = z.string().regex(/^[0-9a-f]{64}$/);\nconst Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);\nconst ClaimNonce = z\n .string()\n .min(8)\n .max(128)\n .refine((value) => !value.includes('|'), {\n message: 'nonce must not contain |',\n });\n\n/**\n * Hard upper bound on an account-funded OAC's validity window (24h). The OAC\n * is a *rolling* 24h credential: a device that comes online at any point\n * proactively reissues a fresh 24h window, while a device that stays offline\n * beyond 24h loses spend authority (short TTL is the revocation-propagation\n * mechanism). The offline verifier rejects any window longer than this.\n */\nexport const ACCOUNT_FUNDED_OAC_MAX_TTL_MS = 1000 * 60 * 60 * 24;\n\n/**\n * Pinned issuer trust-bundle entry returned by `GET /v1/issuer/keys`. Devices\n * pin these public keys and verify unified OACs OFFLINE against them — never\n * against the key embedded in the credential. The shape is a superset of\n * `TrustedIssuerKey` so it can be passed straight to `verifyOacOffline`.\n */\nexport const IssuerTrustKeySchema = z.object({\n issuerId: z.string().min(1).max(128),\n alg: z.literal('p256'),\n publicKeySpkiB64: Base64Std.min(64).max(4096),\n notBeforeMs: z.number().int().nonnegative().optional(),\n notAfterMs: z.number().int().positive().optional(),\n});\nexport type IssuerTrustKey = z.infer<typeof IssuerTrustKeySchema>;\n\nexport const IssuerTrustBundleSchema = z.object({\n keys: z.array(IssuerTrustKeySchema).min(1),\n});\nexport type IssuerTrustBundle = z.infer<typeof IssuerTrustBundleSchema>;\n\n/**\n * Counterparty claim-submission grace after `oac.validUntilMs`. Claims\n * signed while the OAC was valid may still be relayed within this window\n * and the backend will settle them (cumulative cap and revocation still\n * apply). Mobile outbox / queue logic MUST honor this grace before pruning\n * a queued claim — otherwise legitimate offline payments are silently\n * dropped between OAC expiry and the backend grace boundary.\n *\n * Mirrors `CONSUMER_OFFLINE_DEFAULTS.claimSubmitGraceMs` in\n * `flur-backend/src/offline-consumer/service.ts`.\n */\nexport const CONSUMER_OFFLINE_CLAIM_SUBMIT_GRACE_MS = 1000 * 60 * 60 * 24;\n\n// ───────────────────────────── device key ─────────────────────────────\n\nexport const AttestationSecurityLevelSchema = z.enum([\n 'STRONGBOX',\n 'TEE',\n 'SECURE_ENCLAVE',\n 'SOFTWARE',\n]);\nexport type AttestationSecurityLevel = z.infer<\n typeof AttestationSecurityLevelSchema\n>;\n\nexport const DeviceKeyAlgSchema = z.literal('p256');\nexport type DeviceKeyAlg = z.infer<typeof DeviceKeyAlgSchema>;\n\nexport const RegisterDeviceKeyP256InputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n /** P-256 SubjectPublicKeyInfo DER, base64. */\n publicKeySpkiB64: Base64Std.min(64).max(4096),\n /** Base64 of the server-issued enrollment challenge string. */\n challengeB64: Base64Std.min(8).max(1024),\n /** iOS App Attest payload or Android X.509 Key Attestation chain. */\n attestationChainB64: z.array(Base64Std.min(16).max(16_384)).min(1).max(16),\n securityLevel: AttestationSecurityLevelSchema,\n});\nexport type RegisterDeviceKeyP256Input = z.infer<\n typeof RegisterDeviceKeyP256InputSchema\n>;\n\nexport const P256EnrollmentChallengeInputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n});\nexport type P256EnrollmentChallengeInput = z.infer<\n typeof P256EnrollmentChallengeInputSchema\n>;\n\nexport const P256EnrollmentChallengeResultSchema = z.object({\n challenge: z.string().min(16),\n expiresAtMs: z.number().int().positive(),\n});\nexport type P256EnrollmentChallengeResult = z.infer<\n typeof P256EnrollmentChallengeResultSchema\n>;\n\nexport const DeviceKeyRecordSchema = z.object({\n id: z.string().uuid(),\n userId: z.string().uuid(),\n deviceId: z.string(),\n /** Always 'p256' on the consumer offline rail. Field retained for forward-compat. */\n alg: DeviceKeyAlgSchema.default('p256'),\n /** P-256 SubjectPublicKeyInfo DER, base64. */\n publicKeySpkiB64: Base64Std.nullable().default(null),\n securityLevel: AttestationSecurityLevelSchema.nullable().default(null),\n hardwareBacked: z.boolean().default(false),\n attestedAtMs: z.number().int().nonnegative().nullable().default(null),\n createdAtMs: z.number().int().nonnegative(),\n revokedAtMs: z.number().int().nonnegative().nullable(),\n});\nexport type DeviceKeyRecord = z.infer<typeof DeviceKeyRecordSchema>;\n\n// ───────────────────────────── OAC ─────────────────────────────\n//\n// OAC v2 binds a P-256 hardware-backed device key. The consumer offline\n// rail is P-256 only.\nexport const ConsumerOACSchema = z.object({\n oacId: z.string().uuid(),\n issuerId: z.string().min(1).max(64),\n userId: z.string().uuid(),\n deviceId: z.string().min(1).max(128),\n /**\n * Always 'p256'. Required on the wire (backend always emits it).\n * Kept as a literal so input/output infer identically and the schema\n * can be nested inside other response shapes without Zod input/output\n * divergence under tsup DTS bundling.\n */\n alg: z.literal('p256'),\n /** P-256 SubjectPublicKeyInfo DER, base64. */\n devicePubkeySpkiB64: Base64Std.min(64).max(4096),\n /**\n * Per-transaction / cumulative offline spend ceilings. Zero is valid and\n * denotes an identity-only OAC: the credential proves who the holder is and\n * binds their device key for offline-verifiable first contact, but carries\n * no offline spend authority (every claim against it routes to REVIEW).\n * Issued to zero-balance wallets so they can still be paid offline.\n */\n perTxCapKobo: z.number().int().nonnegative(),\n cumulativeCapKobo: z.number().int().nonnegative(),\n currency: z.string().length(3),\n validFromMs: z.number().int().nonnegative(),\n validUntilMs: z.number().int().nonnegative(),\n counterSeed: z.number().int().nonnegative(),\n issuedAtMs: z.number().int().nonnegative(),\n /**\n * Issuer-attested identity folded into the OAC so a single signed\n * credential serves both Tier B offline-verifiable identity and offline\n * spend authority. Verified offline against a pinned issuer key; the\n * backend remains authoritative at settlement.\n */\n phoneE164: z.string().regex(/^\\+[1-9]\\d{7,14}$/),\n displayName: z.string().min(1).max(64),\n});\nexport type ConsumerOAC = z.infer<typeof ConsumerOACSchema>;\n\nexport const SignedConsumerOACSchema = z.object({\n oac: ConsumerOACSchema,\n /** ASN.1 DER ECDSA P-256 issuer signature, base64. */\n issuerSig: Base64Std.min(16).max(2048),\n /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */\n issuerPublicKeySpkiB64: Base64Std.min(64).max(4096),\n});\nexport type SignedConsumerOAC = z.infer<typeof SignedConsumerOACSchema>;\n\nexport const OACRecordSchema = SignedConsumerOACSchema.extend({\n currentOfflineSpentKobo: z.number().int().nonnegative(),\n status: z.enum(['active', 'superseded', 'expired', 'revoked']),\n supersededAtMs: z.number().int().nonnegative().nullable(),\n revokedAtMs: z.number().int().nonnegative().nullable(),\n});\nexport type OACRecord = z.infer<typeof OACRecordSchema>;\n\n/**\n * Inputs for issuing an account-funded OAC.\n *\n * Mirrors the backend `POST /v1/me/offline/oac` route. No funds are\n * pre-reserved; offline claims settle by debiting the payer's main\n * wallet at submission time via the canonical transfer primitive. Claims\n * signed during the OAC validity window may be submitted during the server's\n * bounded grace window; devices should refresh this credential when online.\n */\nexport const IssueAccountOacInputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n perTxCapKobo: z.number().int().positive().optional(),\n cumulativeCapKobo: z.number().int().positive().optional(),\n ttlMs: z\n .number()\n .int()\n .min(60_000)\n .max(ACCOUNT_FUNDED_OAC_MAX_TTL_MS)\n .optional(),\n});\nexport type IssueAccountOacInput = z.infer<typeof IssueAccountOacInputSchema>;\n\n// ───────────────────────────── status ─────────────────────────────\n\nexport const OfflineStatusResultSchema = z.object({\n active: OACRecordSchema.nullable(),\n});\nexport type OfflineStatusResult = z.infer<typeof OfflineStatusResultSchema>;\n\n// ───────────────────────────── payment claim ─────────────────────────────\n//\n// The consumer offline payment rail is P-256 ONLY. Device signatures are\n// produced by `flur-secure-signer` (iOS Secure Enclave / Android StrongBox)\n// over the canonical bytes built by `canonicalClaimSigningBytes`\n// (domain `flur:consumer-offline:v2:claim`). Backend verification is shared\n// via `verifyClaimSignature` from `@nokinc-flur/sdk`.\n//\n// Wire format:\n// - publicKey: SubjectPublicKeyInfo DER, base64.\n// - signature: ASN.1 DER ECDSA signature, base64.\n//\n// Legacy ed25519 claims are no longer accepted at this boundary.\n\nexport const ConsumerPaymentClaimSchema = z.object({\n /** Always 'p256'. Retained for forward-compat and as an explicit domain marker. */\n alg: z.literal('p256').default('p256'),\n oacId: z.string().uuid(),\n encounterId: Sha256Hex.optional(),\n payerUserId: z.string().uuid(),\n payeeUserId: z.string().uuid(),\n payerDeviceId: z.string().min(1).max(128),\n payerNonce: ClaimNonce,\n payeeNonce: ClaimNonce,\n amountKobo: z.number().int().positive(),\n currency: z.string().length(3).default('NGN'),\n occurredAtMs: z.number().int().nonnegative(),\n completedAtMs: z.number().int().nonnegative().optional(),\n contextId: z.string().max(128).optional(),\n\n requestId: z.string().uuid().optional(),\n requestMode: z.enum(['fixed', 'editable']).optional(),\n requestTakerUserId: z.string().uuid().optional(),\n requestAmountKobo: z.number().int().positive().optional(),\n requestCurrency: z.string().length(3).optional(),\n requestReference: z.string().max(128).nullable().optional(),\n requestCreatedAtMs: z.number().int().nonnegative().optional(),\n requestExpiresAtMs: z.number().int().positive().optional(),\n requestNonce: z.string().min(8).max(128).optional(),\n requestTakerDeviceId: z.string().min(1).max(128).nullable().optional(),\n requestTakerPubkeySpkiB64: Base64Std.min(64).max(4096).optional(),\n requestTakerSignatureDerB64: Base64Std.min(16).max(2048).optional(),\n\n payerPubkeySpkiB64: Base64Std.min(64).max(4096),\n payerSignatureDerB64: Base64Std.min(16).max(2048),\n payeePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),\n payeeSignatureDerB64: Base64Std.min(16).max(2048).optional(),\n});\nexport type ConsumerPaymentClaim = z.infer<typeof ConsumerPaymentClaimSchema>;\n\nexport const ConsumerSettlementSchema = z.object({\n settlementId: z.string().uuid(),\n settlementKey: Sha256Hex,\n encounterId: Sha256Hex,\n oacId: z.string().uuid(),\n payerUserId: z.string().uuid(),\n payeeUserId: z.string().uuid(),\n amountKobo: z.number().int().positive(),\n currency: z.string().length(3),\n status: z.enum(['SETTLED', 'REVIEW']),\n reviewReason: z.string().nullable(),\n ledgerRef: z.string().nullable(),\n /** ASN.1 DER ECDSA P-256 issuer signature, base64. */\n issuerSig: Base64Std.min(16).max(2048),\n /** Canonical millisecond timestamp signed into the settlement receipt. */\n issuedAtMs: z.number().int().nonnegative(),\n /** Compatibility alias for API consumers that predate issuedAtMs. */\n createdAtMs: z.number().int().nonnegative().optional(),\n});\nexport type ConsumerSettlement = z.infer<typeof ConsumerSettlementSchema>;\n\nexport const ConsumerSettleResultSchema = z.object({\n settlement: ConsumerSettlementSchema,\n encounterId: Sha256Hex,\n replayed: z.boolean(),\n});\nexport type ConsumerSettleResult = z.infer<typeof ConsumerSettleResultSchema>;\n\n// ───────────────────────────── revoke ─────────────────────────────\n\nexport const RevokeDeviceKeyInputSchema = z.object({\n deviceId: z.string().min(1).max(128),\n /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */\n sendAuthToken: z.string().min(16),\n});\nexport type RevokeDeviceKeyInput = z.infer<typeof RevokeDeviceKeyInputSchema>;\n\n// ───────────────────────────── client ─────────────────────────────\n\nexport type MeOfflineClientOptions = {\n baseUrl: string;\n /** Pre-configured fetch (session bearer attached upstream). */\n fetchImpl?: typeof fetch;\n};\n\nexport type MeOfflineClient = {\n issueP256EnrollmentChallenge: (\n input: P256EnrollmentChallengeInput,\n ) => Promise<P256EnrollmentChallengeResult>;\n registerDeviceKeyP256: (\n input: RegisterDeviceKeyP256Input,\n ) => Promise<DeviceKeyRecord>;\n listDeviceKeys: () => Promise<{ items: DeviceKeyRecord[] }>;\n revokeDeviceKey: (input: RevokeDeviceKeyInput) => Promise<void>;\n /** Issue an account-funded OAC for this device. */\n issueAccountOac: (input: IssueAccountOacInput) => Promise<OACRecord>;\n getStatus: (deviceId?: string) => Promise<OfflineStatusResult>;\n submitClaim: (claim: ConsumerPaymentClaim) => Promise<ConsumerSettleResult>;\n getSettlement: (idOrKey: string) => Promise<ConsumerSettlement>;\n /** Fetch the public pinned issuer trust bundle (`GET /v1/issuer/keys`). */\n getIssuerKeys: () => Promise<IssuerTrustBundle>;\n /**\n * Fetch the issuer-signed OAC revocation status-list\n * (`GET /v1/issuer/revocations`). Pinned and checked offline alongside the\n * issuer trust bundle to bound the revocation window below the OAC TTL.\n */\n getRevocations: () => Promise<SignedRevocationList>;\n};\n\nexport function createMeOfflineClient(\n opts: MeOfflineClientOptions,\n): MeOfflineClient {\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new Error('createMeOfflineClient: no fetch implementation available');\n }\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\n\n async function call<T>(\n method: string,\n path: string,\n body: unknown,\n parser: (raw: unknown) => T,\n ): Promise<T> {\n const init: RequestInit = {\n method,\n headers: {\n 'content-type': 'application/json',\n accept: 'application/json',\n },\n };\n if (body !== undefined) init.body = JSON.stringify(body);\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\n const text = await resp.text();\n let raw: unknown = undefined;\n if (text) {\n try {\n raw = JSON.parse(text);\n } catch {\n // non-JSON\n }\n }\n if (!resp.ok) {\n const code =\n raw &&\n typeof raw === 'object' &&\n 'code' in raw &&\n typeof (raw as { code: unknown }).code === 'string'\n ? (raw as { code: string }).code\n : `http_${resp.status}`;\n const message =\n raw &&\n typeof raw === 'object' &&\n 'message' in raw &&\n typeof (raw as { message: unknown }).message === 'string'\n ? (raw as { message: string }).message\n : `request failed with status ${resp.status}`;\n throw new FlurApiError(resp.status, code, message, raw);\n }\n return parser(raw);\n }\n\n const deviceKeyItems = z.object({ items: z.array(DeviceKeyRecordSchema) });\n\n return {\n issueP256EnrollmentChallenge: (input) =>\n call(\n 'POST',\n '/v1/me/offline/keys/p256/challenge',\n P256EnrollmentChallengeInputSchema.parse(input),\n (raw) => P256EnrollmentChallengeResultSchema.parse(raw),\n ),\n registerDeviceKeyP256: (input) =>\n call(\n 'POST',\n '/v1/me/offline/keys/p256',\n RegisterDeviceKeyP256InputSchema.parse(input),\n (raw) => DeviceKeyRecordSchema.parse(raw),\n ),\n listDeviceKeys: () =>\n call('GET', '/v1/me/offline/keys', undefined, (raw) =>\n deviceKeyItems.parse(raw),\n ),\n revokeDeviceKey: (input) =>\n call(\n 'POST',\n '/v1/me/offline/keys/revoke',\n RevokeDeviceKeyInputSchema.parse(input),\n () => undefined,\n ),\n issueAccountOac: (input) =>\n call(\n 'POST',\n '/v1/me/offline/oac',\n IssueAccountOacInputSchema.parse(input),\n (raw) => OACRecordSchema.parse(raw),\n ),\n getStatus: (deviceId) => {\n const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : '';\n return call('GET', `/v1/me/offline/status${qs}`, undefined, (raw) =>\n OfflineStatusResultSchema.parse(raw),\n );\n },\n submitClaim: (claim) =>\n call(\n 'POST',\n '/v1/me/offline/claims',\n ConsumerPaymentClaimSchema.parse(claim),\n (raw) => ConsumerSettleResultSchema.parse(raw),\n ),\n getSettlement: (idOrKey) =>\n call(\n 'GET',\n `/v1/me/offline/settlements/${encodeURIComponent(idOrKey)}`,\n undefined,\n (raw) => ConsumerSettlementSchema.parse(raw),\n ),\n getIssuerKeys: () =>\n call('GET', '/v1/issuer/keys', undefined, (raw) =>\n IssuerTrustBundleSchema.parse(raw),\n ),\n getRevocations: () =>\n call('GET', '/v1/issuer/revocations', undefined, (raw) =>\n SignedRevocationListSchema.parse(raw),\n ),\n };\n}\n","/**\n * OAC revocation status-list — offline verification.\n *\n * Short OAC TTL (24h, rolling) is the BASELINE revocation-propagation\n * mechanism: a revoked user cannot refresh, so their credential lapses within\n * the issuance window. The revocation status-list shrinks that window from\n * \"up to 24h\" to \"time since the device last pinned a fresh list\": the issuer\n * publishes a signed list of OAC IDs that are revoked AND not yet expired, and\n * the offline verifier rejects any scanned OAC whose id appears in it.\n *\n * The list is naturally bounded: an OAC that lapses on its own TTL drops off\n * the list (expiry already covers it), so the published set only ever carries\n * revocations from roughly the last 24h.\n *\n * Trust model mirrors the OAC itself: the list is issuer-signed and verified\n * OFFLINE against the SAME pinned issuer trust bundle (`GET /v1/issuer/keys`),\n * never the key embedded in the payload. A `sequence` makes the list\n * monotonic so a device never accepts an older snapshot over a newer one.\n */\nimport { z } from 'zod';\n\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { verifyIssuerP256 } from '../crypto/p256-issuer.js';\nimport type { TrustedIssuerKey } from './oac.js';\n\nconst Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);\n\n/**\n * Domain tag bound into the revocation-list issuer signature. MUST match\n * `REVOCATION_DOMAIN` in `flur-backend/src/offline-consumer/service.ts`.\n */\nexport const CONSUMER_REVOCATION_DOMAIN =\n 'flur:consumer-offline:v1:revocation' as const;\n\n/**\n * Hard cap on the number of revoked ids in a single list. Because the list\n * only carries unexpired revocations (~24h window), this bounds the payload\n * while comfortably exceeding any realistic revocation rate.\n */\nexport const REVOCATION_LIST_MAX_ENTRIES = 100_000;\n\nexport const RevocationListSchema = z.object({\n issuerId: z.string().min(1).max(64),\n /**\n * Monotonic snapshot counter. A device MUST NOT replace a pinned list with\n * one carrying a lower sequence — this defeats a downgrade/rollback attack\n * that replays an older list to resurrect a revoked credential.\n */\n sequence: z.number().int().nonnegative(),\n issuedAtMs: z.number().int().nonnegative(),\n /**\n * Freshness bound. After this instant the list is considered stale and the\n * verifier treats it as untrustworthy (fail-closed), forcing a re-pin.\n * Optional so the issuer may publish a list without a hard expiry.\n */\n notAfterMs: z.number().int().positive().optional(),\n /** OAC ids that are revoked AND not yet past their own validity window. */\n revokedOacIds: z.array(z.string().uuid()).max(REVOCATION_LIST_MAX_ENTRIES),\n});\nexport type RevocationList = z.infer<typeof RevocationListSchema>;\n\nexport const SignedRevocationListSchema = z.object({\n list: RevocationListSchema,\n /** ASN.1 DER ECDSA P-256 issuer signature over the signing payload, base64. */\n issuerSig: Base64Std.min(16).max(2048),\n /** Issuer's P-256 public key as SubjectPublicKeyInfo DER, base64. */\n issuerPublicKeySpkiB64: Base64Std.min(64).max(4096),\n});\nexport type SignedRevocationList = z.infer<typeof SignedRevocationListSchema>;\n\nexport type VerifyRevocationListResult =\n | { ok: true; list: RevocationList; revokedOacIds: ReadonlySet<string> }\n | {\n ok: false;\n reason: 'malformed' | 'untrusted_issuer' | 'signature_invalid' | 'stale';\n };\n\nexport interface VerifyRevocationListOptions {\n /** Override the wall clock; defaults to `Date.now()`. */\n nowMs?: number;\n}\n\n/**\n * Canonical revocation-list payload (domain-bound) the issuer signs.\n *\n * Cross-implementation contract (MUST match the backend signer byte-for-byte):\n * optional fields with no value are OMITTED from the signed object, never\n * emitted as `null` or `undefined`. `canonicalJSONBytes` rejects `undefined`\n * object values outright, so building the payload explicitly (rather than\n * spreading a `list` that may carry an explicit `notAfterMs: undefined`) keeps\n * verification total — it can never throw on a well-typed list — and keeps the\n * signed bytes identical whether `notAfterMs` was absent or explicitly unset.\n */\nexport function revocationListSigningPayload(\n list: RevocationList,\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n domain: CONSUMER_REVOCATION_DOMAIN,\n issuerId: list.issuerId,\n sequence: list.sequence,\n issuedAtMs: list.issuedAtMs,\n revokedOacIds: list.revokedOacIds,\n };\n if (list.notAfterMs !== undefined) payload.notAfterMs = list.notAfterMs;\n return payload;\n}\n\n/**\n * Verify a signed revocation list offline against pinned issuer keys.\n *\n * Security invariants (identical to `verifyOacOffline`):\n * - The signature is checked against the PINNED key for `list.issuerId`,\n * never the payload-embedded key.\n * - The pinned key's own validity window is enforced.\n * - A list past `notAfterMs` fails closed (`stale`) so a long-offline device\n * cannot keep trusting a frozen snapshot forever.\n *\n * Note: rollback protection via `sequence` is intentionally NOT enforced here\n * (verification is stateless). The caller persisting the pinned list MUST\n * reject any replacement whose `sequence` is lower than the pinned one.\n */\nexport function verifyRevocationList(\n signed: SignedRevocationList,\n trustedKeys: readonly TrustedIssuerKey[],\n options: VerifyRevocationListOptions = {},\n): VerifyRevocationListResult {\n const parsed = SignedRevocationListSchema.safeParse(signed);\n if (!parsed.success) return { ok: false, reason: 'malformed' };\n const list = parsed.data.list;\n const nowMs = options.nowMs ?? Date.now();\n\n const pinned = trustedKeys.filter(\n (k) =>\n k.issuerId === list.issuerId &&\n (k.notBeforeMs === undefined || nowMs >= k.notBeforeMs) &&\n (k.notAfterMs === undefined || nowMs <= k.notAfterMs),\n );\n if (pinned.length === 0) return { ok: false, reason: 'untrusted_issuer' };\n\n const signingBytes = canonicalJSONBytes(revocationListSigningPayload(list));\n const signatureOk = pinned.some((k) =>\n verifyIssuerP256(signingBytes, parsed.data.issuerSig, k.publicKeySpkiB64),\n );\n if (!signatureOk) return { ok: false, reason: 'signature_invalid' };\n\n if (list.notAfterMs !== undefined && nowMs > list.notAfterMs) {\n return { ok: false, reason: 'stale' };\n }\n\n return { ok: true, list, revokedOacIds: new Set(list.revokedOacIds) };\n}\n\n/** True iff `oacId` appears in a verified revocation set. */\nexport function isOacRevoked(\n oacId: string,\n revokedOacIds: ReadonlySet<string>,\n): boolean {\n return revokedOacIds.has(oacId);\n}\n","/**\n * Offline-claim signer abstraction for Flur.\n *\n * Why this exists:\n * - Mobile clients sign payment claims with a hardware-backed P-256 key\n * (iOS Secure Enclave / Android Keystore StrongBox). Native modules\n * implement that custody, not this file.\n * - Server-side partners, test harnesses, and custodied integrators need a\n * *software* P-256 signer with the same surface so the SDK contract is\n * uniform.\n * - Both producers and verifiers (consumer mobile, partner backend, Flur\n * backend) must agree byte-for-byte on what gets signed. That's the job\n * of `canonicalClaimSigningPayload` / `canonicalClaimSigningBytes`.\n *\n * Wire format (P-256, hardware-backed):\n * - Public key: SubjectPublicKeyInfo DER, base64. Same format the\n * Apple/Android native modules return.\n * - Signature: ASN.1 DER ECDSA(SHA-256) signature, base64.\n *\n * Domain separation:\n * - V2 payload binds `alg='p256'` and is tagged with `CLAIM_DOMAIN_V2`.\n * The legacy ed25519 V1 path has been removed; the migration to P-256\n * is final.\n */\n\nimport { p256 } from '@noble/curves/nist';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\n\n// ─────────────────────────── domain ───────────────────────────\n\n/**\n * V2 canonical claim domain. Must match the backend's V2 verifier exactly.\n * Bumped from `flur:consumer-offline:v1:claim` so a payer's V2 hardware\n * signature is non-replayable against a legacy V1 verifier and vice-versa.\n */\nexport const CLAIM_DOMAIN_V2 = 'flur:consumer-offline:v2:claim' as const;\nconst ENCOUNTER_DOMAIN = 'flur:consumer-offline:v1:encounter';\n\n// ─────────────────────────── types ───────────────────────────\n\nexport type OfflineClaimAlgorithm = 'p256';\n\n/**\n * Inputs the SDK accepts to build canonical signing bytes.\n *\n * Optional fields default to `null` inside the canonical payload, so callers\n * that omit them still produce stable, deterministic bytes.\n */\nexport interface CanonicalClaimInput {\n alg: OfflineClaimAlgorithm;\n oacId: string;\n payerUserId: string;\n payeeUserId: string;\n payerDeviceId: string;\n payerNonce: string;\n payeeNonce: string;\n amountKobo: number;\n currency: string;\n occurredAtMs: number;\n completedAtMs?: number | null;\n contextId?: string | null;\n}\n\n/** Public key + signature pair from a signer. */\nexport interface SignerPublicKey {\n alg: OfflineClaimAlgorithm;\n /** SubjectPublicKeyInfo DER, base64. */\n publicKey: string;\n}\n\nexport interface ClaimSignature {\n alg: OfflineClaimAlgorithm;\n /** ASN.1 DER ECDSA(SHA-256) signature, base64. */\n signature: string;\n}\n\n/** Abstract signer interface. Software and native impls both honour this. */\nexport interface OfflineClaimSigner {\n readonly alg: OfflineClaimAlgorithm;\n getPublicKey(): Promise<SignerPublicKey>;\n sign(bytes: Uint8Array): Promise<ClaimSignature>;\n}\n\n// ─────────────────────────── canonical payload ───────────────────────────\n\n/**\n * The exact object that gets canonical-JSON-encoded and signed.\n *\n * Key ordering doesn't matter for the *output* because `canonicalJSONBytes`\n * sorts keys lexicographically — but the field SET and value normalization\n * must match the backend verifier byte-for-byte. Treat this function as the\n * cryptographic contract.\n */\nexport function canonicalClaimSigningPayload(claim: CanonicalClaimInput): {\n domain: typeof CLAIM_DOMAIN_V2;\n alg: OfflineClaimAlgorithm;\n oacId: string;\n payerUserId: string;\n payeeUserId: string;\n payerDeviceId: string;\n payerNonce: string;\n payeeNonce: string;\n amountKobo: number;\n currency: string;\n occurredAtMs: number;\n completedAtMs: number | null;\n contextId: string | null;\n} {\n return {\n domain: CLAIM_DOMAIN_V2,\n alg: claim.alg,\n oacId: claim.oacId,\n payerUserId: claim.payerUserId,\n payeeUserId: claim.payeeUserId,\n payerDeviceId: claim.payerDeviceId,\n payerNonce: claim.payerNonce,\n payeeNonce: claim.payeeNonce,\n amountKobo: claim.amountKobo,\n currency: claim.currency,\n occurredAtMs: claim.occurredAtMs,\n completedAtMs: claim.completedAtMs ?? null,\n contextId: claim.contextId ?? null,\n };\n}\n\n/** Bytes the signer must operate on. */\nexport function canonicalClaimSigningBytes(\n claim: CanonicalClaimInput,\n): Uint8Array {\n return canonicalJSONBytes(canonicalClaimSigningPayload(claim));\n}\n\n/** Deterministic encounter id used by backend settlement dedupe. */\nexport function computeConsumerClaimEncounterId(input: {\n oacId: string;\n payerUserId: string;\n payeeUserId: string;\n payerNonce: string;\n payeeNonce: string;\n}): string {\n const material = `${ENCOUNTER_DOMAIN}|${[\n assertEncounterPart('oacId', input.oacId),\n assertEncounterPart('payerUserId', input.payerUserId),\n assertEncounterPart('payeeUserId', input.payeeUserId),\n assertEncounterPart('payerNonce', input.payerNonce),\n assertEncounterPart('payeeNonce', input.payeeNonce),\n ].join('|')}`;\n return bytesToHex(sha256(new TextEncoder().encode(material)));\n}\n\nfunction assertEncounterPart(field: string, value: string): string {\n if (value.includes('|')) {\n throw new Error(`consumer encounter id ${field} must not contain |`);\n }\n return value;\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let out = '';\n for (const byte of bytes) out += byte.toString(16).padStart(2, '0');\n return out;\n}\n\n// ─────────────────────────── base64 ───────────────────────────\n//\n// Tiny base64 helpers that work in Node 18+ and all browsers without\n// pulling a new dep. We only need standard (not URL-safe) base64.\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n let bin = '';\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]!);\n // btoa is available in browsers and Node ≥ 16.\n return btoa(bin);\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(b64, 'base64'));\n }\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n// ─────────────────────────── P-256 SPKI helpers ───────────────────────────\n//\n// @noble/curves emits the raw X9.62 uncompressed point (0x04 || X || Y, 65\n// bytes). The backend ingests SubjectPublicKeyInfo DER (the same wrapper the\n// Android Keystore and iOS Secure Enclave native modules return). We wrap\n// and unwrap with the fixed P-256 SPKI header so the wire format is uniform\n// regardless of which signer produced it.\n\nconst P256_SPKI_HEADER = new Uint8Array([\n 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,\n 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,\n]);\n\nfunction p256PublicKeyToSpkiB64(rawUncompressed: Uint8Array): string {\n if (rawUncompressed.length !== 65 || rawUncompressed[0] !== 0x04) {\n throw new Error('p256: expected 65-byte uncompressed point');\n }\n const out = new Uint8Array(P256_SPKI_HEADER.length + rawUncompressed.length);\n out.set(P256_SPKI_HEADER, 0);\n out.set(rawUncompressed, P256_SPKI_HEADER.length);\n return bytesToBase64(out);\n}\n\nfunction p256SpkiB64ToPublicKey(spkiB64: string): Uint8Array {\n const spki = base64ToBytes(spkiB64);\n // Validate the header (cheap correctness check; full ASN.1 parse not needed\n // for a fixed key type).\n if (spki.length !== P256_SPKI_HEADER.length + 65) {\n throw new Error('p256: invalid SPKI length');\n }\n for (let i = 0; i < P256_SPKI_HEADER.length; i++) {\n if (spki[i] !== P256_SPKI_HEADER[i]) {\n throw new Error('p256: invalid SPKI header');\n }\n }\n return spki.slice(P256_SPKI_HEADER.length);\n}\n\n// ─────────────────────────── software signer ───────────────────────────\n\n/**\n * Software P-256 signer. Useful for:\n * - test harnesses\n * - Node integrators that issue claims server-side (custodied wallets)\n * - simulators where Secure Enclave / StrongBox is unavailable\n *\n * The hardware-backed equivalent (mobile) implements the same interface\n * but defers key storage and signing to the OS secure element.\n */\nexport function createSoftwareP256Signer(\n privateKey: Uint8Array,\n): OfflineClaimSigner {\n // Uncompressed point: 0x04 || X(32) || Y(32) — matches what Apple/Android\n // raw public-key APIs emit before SPKI wrapping.\n const raw = p256.getPublicKey(privateKey, false);\n const spkiB64 = p256PublicKeyToSpkiB64(raw);\n\n return {\n alg: 'p256',\n async getPublicKey() {\n return { alg: 'p256', publicKey: spkiB64 };\n },\n async sign(bytes: Uint8Array) {\n // The backend (and the native modules) compute SHA-256 internally; for\n // wire interop we sign the SHA-256 hash of the canonical bytes here.\n // `prehash: true` keeps that pattern consistent across software and\n // hardware paths.\n const sig = p256.sign(bytes, privateKey, { prehash: true });\n // ECDSA DER encoding — the Apple/Android native signers also return\n // DER, so the wire format is identical regardless of producer.\n const der = sig.toBytes('der');\n return { alg: 'p256', signature: bytesToBase64(der) };\n },\n };\n}\n\n// ─────────────────────────── verification ───────────────────────────\n\nexport interface VerifyClaimSignatureInput {\n alg: OfflineClaimAlgorithm;\n bytes: Uint8Array;\n signature: string;\n publicKey: string;\n}\n\n/**\n * Verifier the backend, partners, and self-checks all share. Returns a plain\n * boolean — callers should treat `false` and thrown errors uniformly as\n * \"not authenticated\".\n */\nexport function verifyClaimSignature(\n input: VerifyClaimSignatureInput,\n): boolean {\n try {\n if (input.alg !== 'p256') return false;\n const sigDer = base64ToBytes(input.signature);\n const pub = p256SpkiB64ToPublicKey(input.publicKey);\n return p256.verify(sigDer, input.bytes, pub, {\n prehash: true,\n format: 'der',\n });\n } catch {\n return false;\n }\n}\n","import { z } from 'zod';\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { type OfflineClaimSigner, verifyClaimSignature } from './signer.js';\n\nconst Base64Std = z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);\n\nexport const CONSUMER_PAYMENT_REQUEST_DOMAIN =\n 'flur:consumer-offline:v1:request' as const;\n\nexport const ConsumerPaymentRequestEnvelopeSchema = z\n .object({\n requestId: z.string().uuid(),\n mode: z.enum(['fixed', 'editable']),\n takerUserId: z.string().uuid(),\n amountKobo: z.number().int().positive(),\n currency: z.string().length(3).default('NGN'),\n reference: z.string().max(128).nullable().default(null),\n createdAtMs: z.number().int().nonnegative(),\n expiresAtMs: z.number().int().positive(),\n nonce: z.string().min(8).max(128),\n takerDeviceId: z.string().min(1).max(128).nullable().default(null),\n takerPubkeySpkiB64: Base64Std.min(64).max(4096).optional(),\n takerSignatureDerB64: Base64Std.min(16).max(2048).optional(),\n })\n .superRefine((value, ctx) => {\n if (value.expiresAtMs <= value.createdAtMs) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['expiresAtMs'],\n message: 'expiresAtMs must be greater than createdAtMs',\n });\n }\n const hasSignature = Boolean(\n value.takerPubkeySpkiB64 || value.takerSignatureDerB64,\n );\n if (value.mode === 'fixed' || hasSignature) {\n if (!value.takerDeviceId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['takerDeviceId'],\n message: 'signed requests require takerDeviceId',\n });\n }\n if (!value.takerPubkeySpkiB64) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['takerPubkeySpkiB64'],\n message: 'signed requests require takerPubkeySpkiB64',\n });\n }\n if (!value.takerSignatureDerB64) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['takerSignatureDerB64'],\n message: 'signed requests require takerSignatureDerB64',\n });\n }\n }\n });\n\nexport type ConsumerPaymentRequestEnvelope = z.infer<\n typeof ConsumerPaymentRequestEnvelopeSchema\n>;\n\nexport type UnsignedConsumerPaymentRequest = Omit<\n ConsumerPaymentRequestEnvelope,\n 'takerPubkeySpkiB64' | 'takerSignatureDerB64'\n>;\n\nexport function buildConsumerPaymentRequest(input: {\n requestId: string;\n mode: 'fixed' | 'editable';\n takerUserId: string;\n amountKobo: number;\n currency?: string;\n reference?: string | null;\n createdAtMs: number;\n expiresAtMs: number;\n nonce: string;\n takerDeviceId?: string | null;\n}): UnsignedConsumerPaymentRequest {\n const unsigned = {\n requestId: input.requestId,\n mode: input.mode,\n takerUserId: input.takerUserId,\n amountKobo: input.amountKobo,\n currency: input.currency ?? 'NGN',\n reference: input.reference ?? null,\n createdAtMs: input.createdAtMs,\n expiresAtMs: input.expiresAtMs,\n nonce: input.nonce,\n takerDeviceId: input.takerDeviceId ?? null,\n };\n if (unsigned.mode === 'fixed' && !unsigned.takerDeviceId) {\n throw new Error('fixed requests require takerDeviceId');\n }\n if (unsigned.expiresAtMs <= unsigned.createdAtMs) {\n throw new Error('expiresAtMs must be greater than createdAtMs');\n }\n return unsigned;\n}\n\nexport function consumerPaymentRequestSigningPayload(\n request: UnsignedConsumerPaymentRequest | ConsumerPaymentRequestEnvelope,\n) {\n return {\n domain: CONSUMER_PAYMENT_REQUEST_DOMAIN,\n version: 1,\n requestId: request.requestId,\n mode: request.mode,\n takerUserId: request.takerUserId,\n amountKobo: request.amountKobo,\n currency: request.currency,\n reference: request.reference ?? null,\n createdAtMs: request.createdAtMs,\n expiresAtMs: request.expiresAtMs,\n nonce: request.nonce,\n takerDeviceId: request.takerDeviceId ?? null,\n };\n}\n\nexport function consumerPaymentRequestSigningBytes(\n request: UnsignedConsumerPaymentRequest | ConsumerPaymentRequestEnvelope,\n): Uint8Array {\n return canonicalJSONBytes(consumerPaymentRequestSigningPayload(request));\n}\n\nexport async function signConsumerPaymentRequest(\n unsigned: UnsignedConsumerPaymentRequest,\n signer: OfflineClaimSigner,\n): Promise<ConsumerPaymentRequestEnvelope> {\n if (signer.alg !== 'p256') {\n throw new Error('consumer payment requests require p256 signer');\n }\n const publicKey = await signer.getPublicKey();\n if (publicKey.alg !== 'p256') {\n throw new Error('consumer payment requests require p256 public key');\n }\n const signature = await signer.sign(\n consumerPaymentRequestSigningBytes(unsigned),\n );\n return ConsumerPaymentRequestEnvelopeSchema.parse({\n ...unsigned,\n takerPubkeySpkiB64: publicKey.publicKey,\n takerSignatureDerB64: signature.signature,\n });\n}\n\nexport function verifyConsumerPaymentRequest(\n request: ConsumerPaymentRequestEnvelope,\n): boolean {\n const parsed = ConsumerPaymentRequestEnvelopeSchema.safeParse(request);\n if (!parsed.success) return false;\n const value = parsed.data;\n if (!value.takerPubkeySpkiB64 || !value.takerSignatureDerB64) return false;\n return verifyClaimSignature({\n alg: 'p256',\n bytes: consumerPaymentRequestSigningBytes(value),\n signature: value.takerSignatureDerB64,\n publicKey: value.takerPubkeySpkiB64,\n });\n}\n\nexport function isConsumerPaymentRequestExpired(\n request: ConsumerPaymentRequestEnvelope,\n nowMs = Date.now(),\n): boolean {\n const parsed = ConsumerPaymentRequestEnvelopeSchema.parse(request);\n return parsed.expiresAtMs <= nowMs;\n}\n","import { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { verifyIssuerP256 } from '../crypto/p256-issuer.js';\nimport { ConsumerSettlementSchema, type ConsumerSettlement } from './client.js';\n\nexport const CONSUMER_SETTLEMENT_DOMAIN =\n 'flur:consumer-offline:v1:settlement' as const;\n\nexport const CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX = 'FLURSR1.' as const;\n\nexport function consumerSettlementSigningPayload(\n settlement: ConsumerSettlement,\n) {\n return {\n domain: CONSUMER_SETTLEMENT_DOMAIN,\n settlementId: settlement.settlementId,\n settlementKey: settlement.settlementKey,\n encounterId: settlement.encounterId,\n oacId: settlement.oacId,\n payerUserId: settlement.payerUserId,\n payeeUserId: settlement.payeeUserId,\n amountKobo: settlement.amountKobo,\n currency: settlement.currency,\n status: settlement.status,\n reviewReason: settlement.reviewReason,\n ledgerRef: settlement.ledgerRef,\n issuedAtMs: settlement.issuedAtMs,\n };\n}\n\nexport function verifyConsumerSettlement(\n settlement: ConsumerSettlement,\n issuerPublicKeySpkiB64: string,\n): boolean {\n const parsed = ConsumerSettlementSchema.safeParse(settlement);\n if (!parsed.success) return false;\n return verifyIssuerP256(\n canonicalJSONBytes(consumerSettlementSigningPayload(parsed.data)),\n parsed.data.issuerSig,\n issuerPublicKeySpkiB64,\n );\n}\n\nexport function encodeConsumerSettlementReceiptQR(\n settlement: ConsumerSettlement,\n): string {\n const parsed = ConsumerSettlementSchema.parse(settlement);\n return `${CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX}${base64UrlEncodeUtf8(\n JSON.stringify(parsed),\n )}`;\n}\n\nexport function decodeUnverifiedConsumerSettlementReceiptQR(\n value: string,\n): ConsumerSettlement {\n if (!value.startsWith(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX)) {\n throw new Error('not a Flur consumer settlement receipt QR');\n }\n const encoded = value.slice(CONSUMER_SETTLEMENT_RECEIPT_QR_PREFIX.length);\n let raw: unknown;\n try {\n raw = JSON.parse(base64UrlDecodeUtf8(encoded));\n } catch {\n throw new Error('consumer settlement receipt QR is malformed');\n }\n return ConsumerSettlementSchema.parse(raw);\n}\n\nexport function verifyConsumerSettlementReceiptQR(\n value: string,\n issuerPublicKeySpkiB64: string,\n): ConsumerSettlement {\n const settlement = decodeUnverifiedConsumerSettlementReceiptQR(value);\n if (!verifyConsumerSettlement(settlement, issuerPublicKeySpkiB64)) {\n throw new Error('consumer settlement receipt QR signature invalid');\n }\n return settlement;\n}\n\nfunction base64UrlEncodeUtf8(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n const base64 =\n typeof btoa === 'function'\n ? btoa(binary)\n : typeof Buffer !== 'undefined'\n ? Buffer.from(bytes).toString('base64')\n : undefined;\n if (!base64) throw new Error('base64 encoder unavailable');\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction base64UrlDecodeUtf8(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n '=',\n );\n if (typeof atob === 'function') {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index++) {\n bytes[index] = binary.charCodeAt(index);\n }\n return new TextDecoder().decode(bytes);\n }\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(padded, 'base64').toString('utf8');\n }\n throw new Error('base64 decoder unavailable');\n}\n","/**\n * Offline verification of the unified Offline Authorization Certificate (OAC).\n *\n * The OAC is issuer-signed and folds identity (phoneE164, displayName, bound\n * device key) into the same credential that carries offline spend authority.\n * This lets two users who meet for the first time recognise and pay each\n * other WITHOUT a network round-trip: the verifier checks the issuer\n * signature against a *pinned* trusted issuer key (a Trust Bundle refreshed\n * whenever the device is online), never the key embedded in the credential.\n *\n * Trust model:\n * - Provisional offline authorization, authoritative online settlement.\n * A successful offline verify proves the credential was issued by Flur\n * and is within its validity window; the backend still re-checks\n * revocation, balance, and caps at settlement. Short OAC TTL is the\n * revocation-propagation mechanism — a revoked user cannot refresh and\n * their OAC expires within the issuance TTL.\n *\n * Wire format mirrors `flur-backend/src/offline-consumer/service.ts`\n * (`oacSigningPayload`): the issuer signs `canonicalJSONBytes({ domain, ...oac })`\n * with its P-256 key. Adding fields to `ConsumerOAC` automatically includes\n * them in the signed bytes, so identity is covered without a new domain.\n */\nimport { z } from 'zod';\n\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\nimport { verifyIssuerP256 } from '../crypto/p256-issuer.js';\nimport {\n ACCOUNT_FUNDED_OAC_MAX_TTL_MS,\n ConsumerOACSchema,\n SignedConsumerOACSchema,\n type ConsumerOAC,\n type SignedConsumerOAC,\n} from './client.js';\n\n/**\n * Domain tag bound into the OAC issuer signature. MUST match\n * `OAC_DOMAIN` in `flur-backend/src/offline-consumer/service.ts`.\n */\nexport const CONSUMER_OAC_DOMAIN = 'flur:consumer-offline:v1:oac' as const;\n\n/**\n * A pinned issuer key the device trusts for offline OAC verification.\n * Sourced from the backend Trust Bundle (`GET /v1/issuer/keys`) and cached\n * on-device. `notBeforeMs` / `notAfterMs` bound the key's own validity so a\n * rotated-out key cannot be used to verify a freshly minted credential.\n */\nexport interface TrustedIssuerKey {\n issuerId: string;\n /** Issuer P-256 public key as SubjectPublicKeyInfo DER, base64. */\n publicKeySpkiB64: string;\n notBeforeMs?: number;\n notAfterMs?: number;\n}\n\n/** Identity surfaced to the caller after a successful offline verify. */\nexport interface OacOfflineIdentity {\n oacId: string;\n issuerId: string;\n userId: string;\n phoneE164: string;\n displayName: string;\n /** Holder's bound device key; lets the caller verify receipts offline. */\n devicePubkeySpkiB64: string;\n}\n\nexport type VerifyOacOfflineResult =\n | { ok: true; oac: ConsumerOAC; identity: OacOfflineIdentity }\n | {\n ok: false;\n reason:\n | 'malformed'\n | 'untrusted_issuer'\n | 'signature_invalid'\n | 'window_too_long'\n | 'not_yet_valid'\n | 'expired'\n | 'revoked';\n };\n\nexport interface VerifyOacOfflineOptions {\n /** Override the wall clock; defaults to `Date.now()`. */\n nowMs?: number;\n /**\n * Verified revoked-OAC id set from a pinned revocation status-list (see\n * `verifyRevocationList`). When supplied, an otherwise-valid OAC whose\n * `oacId` is present is rejected with reason `'revoked'`. Omitting this\n * preserves the TTL-only revocation baseline.\n */\n revokedOacIds?: ReadonlySet<string>;\n}\n\n/** Canonical OAC payload (domain-bound) the backend issuer signs. */\nexport function consumerOacSigningPayload(oac: ConsumerOAC) {\n return { domain: CONSUMER_OAC_DOMAIN, ...oac };\n}\n\n/**\n * Verify a signed OAC offline against a pinned set of trusted issuer keys.\n *\n * Security invariants:\n * - The signature is checked against the PINNED key for `oac.issuerId`,\n * never the credential-embedded `issuerPublicKeySpkiB64`. An attacker who\n * forges an OAC with their own key (and a matching embedded key) fails\n * because their key is not pinned.\n * - The pinned key's own validity window is enforced.\n * - The OAC validity window is enforced (`validFromMs <= now < validUntilMs`).\n */\nexport function verifyOacOffline(\n signed: SignedConsumerOAC,\n trustedKeys: readonly TrustedIssuerKey[],\n options: VerifyOacOfflineOptions = {},\n): VerifyOacOfflineResult {\n const parsed = SignedConsumerOACSchema.safeParse(signed);\n if (!parsed.success) return { ok: false, reason: 'malformed' };\n const oacParsed = ConsumerOACSchema.safeParse(parsed.data.oac);\n if (!oacParsed.success) return { ok: false, reason: 'malformed' };\n const oac = oacParsed.data;\n const nowMs = options.nowMs ?? Date.now();\n\n const pinned = trustedKeys.filter(\n (k) =>\n k.issuerId === oac.issuerId &&\n (k.notBeforeMs === undefined || nowMs >= k.notBeforeMs) &&\n (k.notAfterMs === undefined || nowMs <= k.notAfterMs),\n );\n if (pinned.length === 0) return { ok: false, reason: 'untrusted_issuer' };\n\n const signingBytes = canonicalJSONBytes(consumerOacSigningPayload(oac));\n const signatureOk = pinned.some((k) =>\n verifyIssuerP256(signingBytes, parsed.data.issuerSig, k.publicKeySpkiB64),\n );\n if (!signatureOk) return { ok: false, reason: 'signature_invalid' };\n\n // Defense-in-depth: reject any credential whose validity window exceeds the\n // bounded max TTL even if signed by a trusted issuer. Short OAC TTL is the\n // revocation-propagation mechanism, so an over-long window — however it was\n // minted — must never verify offline.\n if (oac.validUntilMs - oac.validFromMs > ACCOUNT_FUNDED_OAC_MAX_TTL_MS) {\n return { ok: false, reason: 'window_too_long' };\n }\n\n if (nowMs < oac.validFromMs) return { ok: false, reason: 'not_yet_valid' };\n if (nowMs >= oac.validUntilMs) return { ok: false, reason: 'expired' };\n\n // Revocation status-list check: bounds the trust window below the OAC TTL.\n if (options.revokedOacIds?.has(oac.oacId)) {\n return { ok: false, reason: 'revoked' };\n }\n\n return {\n ok: true,\n oac,\n identity: {\n oacId: oac.oacId,\n issuerId: oac.issuerId,\n userId: oac.userId,\n phoneE164: oac.phoneE164,\n displayName: oac.displayName,\n devicePubkeySpkiB64: oac.devicePubkeySpkiB64,\n },\n };\n}\n\n/**\n * QR prefix for a presented unified OAC. A holder shows this QR to be paid\n * and/or identified offline; the scanner decodes it and calls\n * `verifyOacOffline` against its pinned trust bundle. Distinct from the\n * settlement-receipt (`FLURSR1.`) and pay-card prefixes so the scanner can\n * dispatch by prefix without ambiguity.\n */\nexport const CONSUMER_OAC_QR_PREFIX = 'FLUROAC1.' as const;\n\n/** True iff `value` looks like a presented OAC QR payload. */\nexport function isConsumerOacQR(value: string): boolean {\n return value.startsWith(CONSUMER_OAC_QR_PREFIX);\n}\n\n/**\n * Advisory \"pay me\" request a holder may attach to a presented OAC pay code:\n * an amount, a purpose/intent, and a free-text reference. This rides as an\n * UNSIGNED suffix on the QR (see {@link encodeConsumerOacQR}) — it is never\n * part of the issuer-signed credential and carries no authority. The payer's\n * app treats it purely as a prefill hint and always confirms the amount,\n * exactly as with a NIBSS dynamic QR.\n */\nexport const OacPresentmentRequestSchema = z\n .object({\n /** Requested amount in minor units (kobo). */\n amountMinor: z.number().int().positive().max(1_000_000_000_000).optional(),\n /** Purpose/intent code (mirrors the NIBSS intent vocabulary). */\n intent: z.string().min(1).max(32).optional(),\n /** Free-text reference / note. */\n reference: z.string().min(1).max(64).optional(),\n })\n .strict();\nexport type OacPresentmentRequest = z.infer<typeof OacPresentmentRequestSchema>;\n\n/**\n * Encode a signed OAC as a scannable QR payload. The envelope is validated\n * before encoding so a malformed credential can never be presented.\n *\n * An optional advisory {@link OacPresentmentRequest} is appended as a\n * dot-separated, base64url-encoded suffix:\n * `FLUROAC1.<base64url(signed)>.<base64url(request)>`\n * The signed segment is byte-identical with or without the suffix, so the\n * credential's verifiability is unaffected. An empty request adds no suffix.\n */\nexport function encodeConsumerOacQR(\n signed: SignedConsumerOAC,\n request?: OacPresentmentRequest,\n): string {\n const parsed = SignedConsumerOACSchema.parse(signed);\n const base = `${CONSUMER_OAC_QR_PREFIX}${base64UrlEncodeUtf8(JSON.stringify(parsed))}`;\n if (request === undefined) return base;\n const parsedRequest = OacPresentmentRequestSchema.parse(request);\n if (Object.keys(parsedRequest).length === 0) return base;\n return `${base}.${base64UrlEncodeUtf8(JSON.stringify(parsedRequest))}`;\n}\n\n/**\n * Decode (WITHOUT verifying) a presented OAC QR back into a signed envelope.\n * Any advisory request suffix is ignored here — use\n * {@link decodeConsumerOacRequest} to read it. The caller MUST pass the result\n * to `verifyOacOffline` against pinned keys before trusting any field —\n * decoding proves nothing about authenticity.\n */\nexport function decodeUnverifiedConsumerOacQR(\n value: string,\n): SignedConsumerOAC {\n if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) {\n throw new Error('not a Flur consumer OAC QR');\n }\n const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);\n // The base64url alphabet excludes '.', so the first segment is the signed\n // credential and anything after the first dot is the advisory suffix.\n const encoded = remainder.split('.', 1)[0];\n let raw: unknown;\n try {\n raw = JSON.parse(base64UrlDecodeUtf8(encoded));\n } catch {\n throw new Error('consumer OAC QR is malformed');\n }\n return SignedConsumerOACSchema.parse(raw);\n}\n\n/**\n * Read the advisory {@link OacPresentmentRequest} from a presented OAC QR, or\n * `null` if absent/malformed. This is purely a prefill hint and is NEVER\n * authoritative — a malformed suffix is treated as \"no request\" and never\n * throws, so a bad suffix can never block a verifiable credential.\n */\nexport function decodeConsumerOacRequest(\n value: string,\n): OacPresentmentRequest | null {\n if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) return null;\n const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);\n const dot = remainder.indexOf('.');\n if (dot < 0) return null;\n const suffix = remainder.slice(dot + 1);\n if (suffix.length === 0) return null;\n try {\n const raw = JSON.parse(base64UrlDecodeUtf8(suffix));\n const parsed = OacPresentmentRequestSchema.safeParse(raw);\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n}\n\nfunction base64UrlEncodeUtf8(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n const base64 =\n typeof btoa === 'function'\n ? btoa(binary)\n : typeof Buffer !== 'undefined'\n ? Buffer.from(bytes).toString('base64')\n : undefined;\n if (!base64) throw new Error('base64 encoder unavailable');\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction base64UrlDecodeUtf8(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n '=',\n );\n if (typeof atob === 'function') {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index++) {\n bytes[index] = binary.charCodeAt(index);\n }\n return new TextDecoder().decode(bytes);\n }\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(padded, 'base64').toString('utf8');\n }\n throw new Error('base64 decoder unavailable');\n}\n","/**\n * FLURA1 — single-SMS consumer-offline settle token.\n *\n * Why this exists:\n * - The legacy `FLURC1.` codec packed the entire dual-party-signed\n * `ConsumerPaymentClaim` JSON into a base64url SMS, which (a) overran\n * the 160-char GSM-7 single-SMS budget for any non-trivial claim and\n * (b) leaked enough state through the carrier to allow a hostile relay\n * to replay the claim out-of-band.\n * - Text-banking rails in the real world (737-SMS, M-Pesa STK applet)\n * settle from a much smaller payload, but they substitute MSISDN trust\n * + tiny daily limits for cryptographic auth. We can do strictly better\n * because we already have hardware-backed P-256 device keys.\n *\n * FLURA1 wire (112 bytes, signed by the payer's hardware key):\n *\n * off len field\n * 0 1 version 0x01\n * 1 1 flags reserved, must be 0x00\n * 2 16 encounterId prefix first 16 of sha256(encounterId)\n * 18 8 payer userId prefix first 8 bytes of UUID binary\n * 26 8 payee userId prefix first 8 bytes of UUID binary\n * 34 8 amountKobo uint64 big-endian\n * 42 6 occurredAtMs uint48 big-endian\n * 48 64 signature raw ECDSA-P256 r‖s (32 + 32)\n *\n * Signing input is `FLURA1_DOMAIN ‖ bytes[0..47]` (31 + 48 = 79 bytes),\n * SHA-256-prehashed inside `p256.sign`. Currency is the platform invariant\n * NGN and never travels on the wire. The backend resolves full UUIDs from\n * the 8-byte prefixes (collision probability < 1e-12 at our scale; the\n * backend rejects ambiguous matches).\n *\n * Wire encoding: `FLURA1.<base64url(112 bytes)>` = 7 + 150 = 157 chars,\n * fits one GSM-7 SMS with 3 chars to spare.\n *\n * This payload is enough to *settle* unilaterally — the payer's signature\n * is the authority, the OAC active at `occurredAtMs` is the limit. The\n * payee can dispute the amount in person; the ledger move is final once\n * verified, just like cash.\n */\n\nimport { p256 } from '@noble/curves/nist';\nimport { p256SpkiB64ToRaw } from '../crypto/p256-issuer.js';\nimport {\n ConsumerPaymentClaimSchema,\n type ConsumerPaymentClaim,\n} from './client.js';\n\n// ─────────────────────────── public constants ───────────────────────────\n\n/**\n * Full-claim QR envelope used for authenticated app-to-app relay. This is\n * intentionally NOT the carrier-SMS settle rail: the JSON claim can exceed\n * a single SMS and must not be sent to the provider webhook. Mobile keeps\n * this for QR/paste flows that submit to `/v1/me/offline/claims`.\n */\nexport const OFFLINE_CLAIM_SMS_PREFIX = 'FLURC1.' as const;\n\nconst CLAIM_TOKEN_RE = /(?:^|\\s)(FLURC1\\.[A-Za-z0-9_-]+={0,2})(?:\\s|$)/;\n\nexport function encodeOfflineClaimSmsMessage(\n claim: ConsumerPaymentClaim,\n): string {\n const parsed = ConsumerPaymentClaimSchema.parse(claim);\n return `${OFFLINE_CLAIM_SMS_PREFIX}${base64UrlEncodeUtf8(\n JSON.stringify(parsed),\n )}`;\n}\n\nexport function decodeOfflineClaimSmsMessage(\n message: string,\n): ConsumerPaymentClaim {\n const token = extractOfflineClaimSmsToken(message);\n if (!token) throw new Error('offline claim QR token not found');\n const encoded = token.slice(OFFLINE_CLAIM_SMS_PREFIX.length);\n let raw: unknown;\n try {\n raw = JSON.parse(base64UrlDecodeUtf8(encoded));\n } catch {\n throw new Error('offline claim QR token is malformed');\n }\n const parsed = ConsumerPaymentClaimSchema.safeParse(raw);\n if (!parsed.success) throw new Error('offline claim QR token is invalid');\n return parsed.data;\n}\n\nexport function extractOfflineClaimSmsToken(message: string): string | null {\n const trimmed = message.trim();\n if (trimmed.startsWith(OFFLINE_CLAIM_SMS_PREFIX)) {\n return trimmed.split(/\\s+/, 1)[0] ?? null;\n }\n return CLAIM_TOKEN_RE.exec(message)?.[1] ?? null;\n}\n\nexport const OFFLINE_SMS_SETTLE_PREFIX = 'FLURA1.' as const;\n\n/** Domain string prepended to the 48-byte header before signing/verifying. */\nexport const OFFLINE_SMS_SETTLE_DOMAIN =\n 'flur:consumer-offline:v1:attest' as const;\n\n/** Fixed total binary length, in bytes. */\nexport const OFFLINE_SMS_SETTLE_TOKEN_BYTES = 112 as const;\n\n/** Length of the signed prefix (everything except the 64-byte signature). */\nexport const OFFLINE_SMS_SETTLE_HEADER_BYTES = 48 as const;\n\n/** Length of the raw P-256 r‖s signature appended after the header. */\nexport const OFFLINE_SMS_SETTLE_SIGNATURE_BYTES = 64 as const;\n\n/** Wire version supported by this codec. */\nexport const OFFLINE_SMS_SETTLE_VERSION = 0x01 as const;\n\n/** Matches FLURA1 tokens embedded in arbitrary SMS body text. */\nconst TOKEN_RE = /(?:^|[\\s,;:()<>\"'])(FLURA1\\.[A-Za-z0-9_-]{150})/;\n\n// ─────────────────────────── public types ───────────────────────────\n\n/**\n * Inputs the caller supplies when building a FLURA1 token. All identifier\n * fields are full hex/UUID strings; this codec computes prefixes.\n */\nexport interface OfflineSmsSettleInput {\n /** Opaque encounter identifier — same value the claim uses. */\n encounterId: string;\n /** Full payer user UUID (string form, e.g. `8c...-...-...-...-...`). */\n payerUserId: string;\n /** Full payee user UUID (string form). */\n payeeUserId: string;\n amountKobo: number;\n occurredAtMs: number;\n}\n\n/**\n * Decoded view of a FLURA1 token. Field prefixes are returned as hex\n * strings; raw byte arrays are exposed for callers that need them\n * (signature verification, audit storage).\n */\nexport interface DecodedOfflineSmsSettleToken {\n version: number;\n flags: number;\n encounterIdPrefixHex: string;\n payerUserIdPrefixHex: string;\n payeeUserIdPrefixHex: string;\n amountKobo: number;\n occurredAtMs: number;\n /** Raw 64-byte ECDSA-P256 r‖s signature. */\n signature: Uint8Array;\n /** 48-byte signed header (`bytes[0..47]`). */\n header: Uint8Array;\n /** 79-byte domain-tagged buffer that was actually fed into `p256.verify`. */\n signedBytes: Uint8Array;\n}\n\n/**\n * Minimal signer surface accepted by `encodeOfflineSmsSettleToken`. Returns\n * raw 64-byte r‖s ECDSA-P256. Hardware signers that natively emit DER must\n * convert before calling this codec — see `derToRawP256Signature`.\n */\nexport interface OfflineSmsSettleSigner {\n signRaw(bytes: Uint8Array): Promise<Uint8Array>;\n}\n\n// ─────────────────────────── encode ───────────────────────────\n\nexport async function encodeOfflineSmsSettleToken(\n input: OfflineSmsSettleInput,\n signer: OfflineSmsSettleSigner,\n): Promise<string> {\n const header = await buildSmsSettleHeader(input);\n const sig = await signer.signRaw(domainTag(header));\n if (sig.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {\n throw new Error(\n `FLURA1: signer returned ${sig.length}-byte sig; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`,\n );\n }\n const out = new Uint8Array(OFFLINE_SMS_SETTLE_TOKEN_BYTES);\n out.set(header, 0);\n out.set(sig, OFFLINE_SMS_SETTLE_HEADER_BYTES);\n return `${OFFLINE_SMS_SETTLE_PREFIX}${bytesToBase64Url(out)}`;\n}\n\n/**\n * Build the 48-byte signed header for the given input. Exposed so callers\n * that own the signing primitive directly (e.g. a native Secure Enclave\n * bridge that emits DER) can compute the bytes-to-sign without going\n * through `OfflineSmsSettleSigner`.\n */\nexport async function buildSmsSettleHeader(\n input: OfflineSmsSettleInput,\n): Promise<Uint8Array> {\n assertSafeUint64(input.amountKobo, 'amountKobo');\n if (input.amountKobo <= 0) {\n throw new Error('FLURA1: amountKobo must be greater than zero');\n }\n assertSafeUint48(input.occurredAtMs, 'occurredAtMs');\n const encounterPrefix = (await sha256(utf8(input.encounterId))).slice(0, 16);\n const payerPrefix = uuidToBytes(input.payerUserId).slice(0, 8);\n const payeePrefix = uuidToBytes(input.payeeUserId).slice(0, 8);\n\n const header = new Uint8Array(OFFLINE_SMS_SETTLE_HEADER_BYTES);\n const dv = new DataView(header.buffer);\n header[0] = OFFLINE_SMS_SETTLE_VERSION;\n header[1] = 0x00; // flags\n header.set(encounterPrefix, 2);\n header.set(payerPrefix, 18);\n header.set(payeePrefix, 26);\n writeUint64BE(dv, 34, input.amountKobo);\n writeUint48BE(dv, 42, input.occurredAtMs);\n return header;\n}\n\n/**\n * Bytes a signer must operate on: `OFFLINE_SMS_SETTLE_DOMAIN ‖ header`.\n * Exposed for hardware bridges that own the signing call themselves.\n */\nexport function domainTag(header: Uint8Array): Uint8Array {\n if (header.length !== OFFLINE_SMS_SETTLE_HEADER_BYTES) {\n throw new Error(\n `FLURA1: header must be ${OFFLINE_SMS_SETTLE_HEADER_BYTES} bytes`,\n );\n }\n const domain = utf8(OFFLINE_SMS_SETTLE_DOMAIN);\n const out = new Uint8Array(domain.length + header.length);\n out.set(domain, 0);\n out.set(header, domain.length);\n return out;\n}\n\n// ─────────────────────────── decode ───────────────────────────\n\nexport function decodeOfflineSmsSettleToken(\n message: string,\n): DecodedOfflineSmsSettleToken {\n const token = extractOfflineSmsSettleToken(message);\n if (!token) throw new Error('FLURA1: token not found');\n const encoded = token.slice(OFFLINE_SMS_SETTLE_PREFIX.length);\n let bytes: Uint8Array;\n try {\n bytes = base64UrlToBytes(encoded);\n } catch {\n throw new Error('FLURA1: token base64url is malformed');\n }\n if (bytesToBase64Url(bytes) !== encoded) {\n throw new Error('FLURA1: token base64url is malformed');\n }\n if (bytes.length !== OFFLINE_SMS_SETTLE_TOKEN_BYTES) {\n throw new Error(\n `FLURA1: expected ${OFFLINE_SMS_SETTLE_TOKEN_BYTES} bytes, got ${bytes.length}`,\n );\n }\n const version = bytes[0]!;\n const flags = bytes[1]!;\n if (version !== OFFLINE_SMS_SETTLE_VERSION) {\n throw new Error(`FLURA1: unsupported version ${version}`);\n }\n if (flags !== 0x00) {\n throw new Error(`FLURA1: reserved flags must be 0, got ${flags}`);\n }\n const header = bytes.slice(0, OFFLINE_SMS_SETTLE_HEADER_BYTES);\n const signature = bytes.slice(OFFLINE_SMS_SETTLE_HEADER_BYTES);\n const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const amountKobo = readUint64BE(dv, 34);\n if (amountKobo <= 0) {\n throw new Error('FLURA1: amountKobo must be greater than zero');\n }\n return {\n version,\n flags,\n encounterIdPrefixHex: bytesToHex(bytes.slice(2, 18)),\n payerUserIdPrefixHex: bytesToHex(bytes.slice(18, 26)),\n payeeUserIdPrefixHex: bytesToHex(bytes.slice(26, 34)),\n amountKobo,\n occurredAtMs: readUint48BE(dv, 42),\n signature,\n header,\n signedBytes: domainTag(header),\n };\n}\n\nexport function extractOfflineSmsSettleToken(message: string): string | null {\n const trimmed = message.trim();\n if (trimmed.startsWith(OFFLINE_SMS_SETTLE_PREFIX)) {\n return trimmed.split(/\\s+/, 1)[0] ?? null;\n }\n return TOKEN_RE.exec(message)?.[1] ?? null;\n}\n\n// ─────────────────────────── verify ───────────────────────────\n\n/**\n * Verify a decoded FLURA1 token against a candidate payer SPKI public key.\n * Returns `false` (never throws) on any signature or key-decode failure so\n * callers can iterate a candidate set safely.\n */\nexport function verifyOfflineSmsSettleToken(\n decoded: DecodedOfflineSmsSettleToken,\n payerPubkeySpkiB64: string,\n): boolean {\n try {\n const pubRaw = p256SpkiB64ToRaw(payerPubkeySpkiB64);\n return p256.verify(decoded.signature, decoded.signedBytes, pubRaw, {\n prehash: true,\n format: 'compact',\n });\n } catch {\n return false;\n }\n}\n\n// ─────────────────────────── DER ↔ raw helper ───────────────────────────\n\n/**\n * Convert an ASN.1 DER ECDSA-P256 signature (the format every hardware\n * Secure-Enclave / Keystore bridge in this codebase emits) into the\n * 64-byte raw r‖s form that FLURA1 carries on the wire.\n *\n * Throws on any DER parse failure or out-of-range coordinate.\n */\nexport function derToRawP256Signature(derBytes: Uint8Array): Uint8Array {\n const sig = p256.Signature.fromBytes(derBytes, 'der');\n const raw = sig.toBytes('compact');\n if (raw.length !== OFFLINE_SMS_SETTLE_SIGNATURE_BYTES) {\n throw new Error(\n `FLURA1: DER→raw produced ${raw.length} bytes; expected ${OFFLINE_SMS_SETTLE_SIGNATURE_BYTES}`,\n );\n }\n return raw;\n}\n\n// ─────────────────────────── byte/format utils ───────────────────────────\n//\n// All helpers here are local to FLURA1 — they do not allocate beyond what\n// the codec needs and are safe in RN / browser / Node without polyfills.\n\nfunction utf8(s: string): Uint8Array {\n return new TextEncoder().encode(s);\n}\n\nasync function sha256(bytes: Uint8Array): Promise<Uint8Array> {\n // Prefer Web Crypto where available (RN Hermes since Expo SDK 51 ships\n // it, browsers always, Node ≥ 20). Fall back to @noble/hashes only if\n // the platform truly lacks SubtleCrypto.\n const subtle =\n (typeof globalThis !== 'undefined' && globalThis.crypto?.subtle) ||\n undefined;\n if (subtle) {\n const digest = await subtle.digest('SHA-256', bytes);\n return new Uint8Array(digest);\n }\n // Lazy import to avoid pulling the dep into bundles that never need it.\n const { sha256: nobleSha256 } = await import('@noble/hashes/sha2');\n return nobleSha256(bytes);\n}\n\nfunction uuidToBytes(uuid: string): Uint8Array {\n // Accept the canonical 8-4-4-4-12 form. Any other shape is a programmer\n // error and fails loudly — these IDs come from a server-issued source.\n const hex = uuid.replace(/-/g, '').toLowerCase();\n if (hex.length !== 32 || !/^[0-9a-f]{32}$/.test(hex)) {\n throw new Error(`FLURA1: invalid UUID: ${uuid}`);\n }\n const out = new Uint8Array(16);\n for (let i = 0; i < 16; i++) {\n out[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nfunction assertSafeUint64(value: number, field: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`FLURA1: ${field} must be a non-negative integer`);\n }\n if (value > Number.MAX_SAFE_INTEGER) {\n throw new Error(`FLURA1: ${field} exceeds Number.MAX_SAFE_INTEGER`);\n }\n}\n\nfunction assertSafeUint48(value: number, field: string): void {\n assertSafeUint64(value, field);\n if (value > 0xffffffffffff) {\n throw new Error(`FLURA1: ${field} exceeds uint48 range`);\n }\n}\n\nfunction writeUint64BE(dv: DataView, offset: number, value: number): void {\n // JS Number is safe to 2^53−1, well below uint64 max; we split into two\n // 32-bit words rather than depend on BigInt for RN/Hermes parity.\n const high = Math.floor(value / 0x100000000);\n const low = value >>> 0;\n dv.setUint32(offset, high, false);\n dv.setUint32(offset + 4, low, false);\n}\n\nfunction readUint64BE(dv: DataView, offset: number): number {\n const high = dv.getUint32(offset, false);\n const low = dv.getUint32(offset + 4, false);\n if (high > 0x001fffff) {\n throw new Error('FLURA1: amountKobo exceeds Number.MAX_SAFE_INTEGER');\n }\n return high * 0x100000000 + low;\n}\n\nfunction writeUint48BE(dv: DataView, offset: number, value: number): void {\n const high = Math.floor(value / 0x10000);\n const low = value & 0xffff;\n dv.setUint32(offset, high, false);\n dv.setUint16(offset + 4, low, false);\n}\n\nfunction readUint48BE(dv: DataView, offset: number): number {\n const high = dv.getUint32(offset, false);\n const low = dv.getUint16(offset + 4, false);\n return high * 0x10000 + low;\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n out += bytes[i]!.toString(16).padStart(2, '0');\n }\n return out;\n}\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let base64: string;\n if (typeof Buffer !== 'undefined') {\n base64 = Buffer.from(bytes).toString('base64');\n } else {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n if (typeof btoa !== 'function') {\n throw new Error('FLURA1: base64 encoder unavailable');\n }\n base64 = btoa(binary);\n }\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction base64UrlEncodeUtf8(input: string): string {\n return bytesToBase64Url(utf8(input));\n}\n\nfunction base64UrlDecodeUtf8(input: string): string {\n return new TextDecoder().decode(base64UrlToBytes(input));\n}\n\nfunction base64UrlToBytes(input: string): Uint8Array {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n '=',\n );\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(padded, 'base64'));\n }\n if (typeof atob !== 'function') {\n throw new Error('FLURA1: base64 decoder unavailable');\n }\n const binary = atob(padded);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n return out;\n}\n","/**\r\n * Partner-funded wallet rails SDK.\r\n *\r\n * Provides two clients:\r\n * - `createPartnerFundingClient(partnerClient)` — uses partner HMAC for\r\n * the bank/merchant partner endpoints (funding webhook, payout events,\r\n * daily reconciliation). The caller MUST have minted credentials with\r\n * the appropriate scopes (`partner:funding:write`, `partner:payout:write`,\r\n * `partner:reconciliation:read`).\r\n * - `createConsumerWithdrawalsClient(opts)` — session-bearer auth for the\r\n * consumer endpoints (linked payout destinations, withdrawals).\r\n *\r\n * Schemas mirror `flur-backend/src/partner-funding/types.ts`. Money is\r\n * always represented in MINOR units (e.g. kobo for NGN). BIGINT-bearing\r\n * response fields are serialized as integer strings to avoid JS number\r\n * precision issues; reserve balances and imbalances may be signed.\r\n */\r\nimport { z } from 'zod';\r\nimport type { FlurPartnerClient } from '../partner/client.js';\r\nimport { FlurApiError } from '../errors.js';\r\n\r\n// ───────────────────────────── shared ─────────────────────────────\r\n\r\nconst MinorString = z.string().regex(/^-?\\d+$/);\r\nconst PositiveMinor = z.union([\r\n z.number().int().positive(),\r\n z.string().regex(/^[1-9]\\d{0,18}$/),\r\n]);\r\nconst Currency = z\r\n .string()\r\n .trim()\r\n .length(3)\r\n .transform((v) => v.toUpperCase());\r\nconst Metadata = z.record(z.unknown());\r\n\r\nexport const PARTNER_KINDS = ['bank', 'merchant'] as const;\r\nexport type PartnerKind = (typeof PARTNER_KINDS)[number];\r\n\r\nexport const CUSTODIAL_MODES = ['agent_of_bank', 'flur_virtual_pool'] as const;\r\nexport type CustodialMode = (typeof CUSTODIAL_MODES)[number];\r\n\r\nexport const PARTNER_PROFILE_STATUSES = [\r\n 'active',\r\n 'suspended',\r\n 'closed',\r\n] as const;\r\nexport type PartnerProfileStatus = (typeof PARTNER_PROFILE_STATUSES)[number];\r\n\r\nexport const PARTNER_FUNDING_DIRECTIONS = ['credit', 'debit'] as const;\r\nexport type PartnerFundingDirection =\r\n (typeof PARTNER_FUNDING_DIRECTIONS)[number];\r\n\r\nexport const PARTNER_FUNDING_STATUSES = [\r\n 'pending',\r\n 'posted',\r\n 'failed',\r\n] as const;\r\nexport type PartnerFundingStatus = (typeof PARTNER_FUNDING_STATUSES)[number];\r\n\r\nexport const PAYOUT_DESTINATION_STATUSES = [\r\n 'pending',\r\n 'verified',\r\n 'disabled',\r\n] as const;\r\nexport type PayoutDestinationStatus =\r\n (typeof PAYOUT_DESTINATION_STATUSES)[number];\r\n\r\nexport const WITHDRAWAL_STATES = [\r\n 'requested',\r\n 'submitted',\r\n 'processing',\r\n 'paid',\r\n 'failed',\r\n 'reversed',\r\n] as const;\r\nexport type WithdrawalState = (typeof WITHDRAWAL_STATES)[number];\r\n\r\n// ───────────────────────────── profile ─────────────────────────────\r\n\r\nexport const PartnerProfileSchema = z.object({\r\n partnerAccountId: z.string().uuid(),\r\n kind: z.enum(PARTNER_KINDS),\r\n custodialMode: z.enum(CUSTODIAL_MODES),\r\n displayName: z.string(),\r\n bankCode: z.string().nullable(),\r\n poolAccountNumber: z.string().nullable(),\r\n status: z.enum(PARTNER_PROFILE_STATUSES),\r\n metadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type PartnerProfile = z.infer<typeof PartnerProfileSchema>;\r\n\r\nexport const UpsertPartnerProfileInputSchema = z.object({\r\n kind: z.enum(PARTNER_KINDS),\r\n custodialMode: z.enum(CUSTODIAL_MODES),\r\n displayName: z.string().trim().min(1).max(200),\r\n bankCode: z.string().trim().min(1).max(64).optional(),\r\n poolAccountNumber: z.string().trim().min(1).max(64).optional(),\r\n metadata: Metadata.optional(),\r\n});\r\nexport type UpsertPartnerProfileInput = z.infer<\r\n typeof UpsertPartnerProfileInputSchema\r\n>;\r\n\r\n// ───────────────────────────── fundings ─────────────────────────────\r\n\r\nexport const PartnerFundingEventInputSchema = z.object({\r\n externalRef: z.string().trim().min(8).max(128),\r\n direction: z.enum(PARTNER_FUNDING_DIRECTIONS).optional(),\r\n userId: z.string().uuid().optional(),\r\n accountId: z.string().uuid().optional(),\r\n amountMinor: PositiveMinor,\r\n currency: Currency,\r\n fundingSource: z.string().trim().min(1).max(64).optional(),\r\n providerMetadata: Metadata.optional(),\r\n});\r\nexport type PartnerFundingEventInput = z.infer<\r\n typeof PartnerFundingEventInputSchema\r\n>;\r\n\r\nexport const PartnerFundingSchema = z.object({\r\n fundingId: z.string().uuid(),\r\n partnerId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n userId: z.string().uuid().nullable(),\r\n direction: z.enum(PARTNER_FUNDING_DIRECTIONS),\r\n currency: z.string(),\r\n amountMinor: MinorString,\r\n externalRef: z.string(),\r\n status: z.enum(PARTNER_FUNDING_STATUSES),\r\n fundingSource: z.string(),\r\n ledgerRef: z.string(),\r\n providerMetadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type PartnerFunding = z.infer<typeof PartnerFundingSchema>;\r\n\r\nexport const IngestFundingResultSchema = z.object({\r\n funding: PartnerFundingSchema,\r\n replayed: z.boolean(),\r\n});\r\nexport type IngestFundingResult = z.infer<typeof IngestFundingResultSchema>;\r\n\r\n// ───────────────────────────── destinations ─────────────────────────────\r\n\r\nexport const PayoutDestinationSchema = z.object({\r\n destinationId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n partnerId: z.string().uuid(),\r\n bankCode: z.string(),\r\n accountNumber: z.string(),\r\n accountName: z.string(),\r\n status: z.enum(PAYOUT_DESTINATION_STATUSES),\r\n verifiedAtMs: z.number().int().nonnegative().nullable(),\r\n metadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type PayoutDestination = z.infer<typeof PayoutDestinationSchema>;\r\n\r\nexport const CreatePayoutDestinationInputSchema = z.object({\r\n partnerId: z.string().uuid(),\r\n bankCode: z.string().trim().min(1).max(32),\r\n accountNumber: z.string().trim().min(4).max(64),\r\n accountName: z.string().trim().min(1).max(200),\r\n metadata: Metadata.optional(),\r\n});\r\nexport type CreatePayoutDestinationInput = z.infer<\r\n typeof CreatePayoutDestinationInputSchema\r\n>;\r\n\r\nexport const ListPayoutDestinationsResultSchema = z.object({\r\n items: z.array(PayoutDestinationSchema),\r\n});\r\nexport type ListPayoutDestinationsResult = z.infer<\r\n typeof ListPayoutDestinationsResultSchema\r\n>;\r\n\r\n// ───────────────────────────── withdrawals ─────────────────────────────\r\n\r\nexport const WithdrawalSchema = z.object({\r\n withdrawalId: z.string().uuid(),\r\n accountId: z.string().uuid(),\r\n userId: z.string().uuid(),\r\n partnerId: z.string().uuid(),\r\n destinationId: z.string().uuid(),\r\n currency: z.string(),\r\n amountMinor: MinorString,\r\n state: z.enum(WITHDRAWAL_STATES),\r\n idempotencyKey: z.string(),\r\n providerRef: z.string().nullable(),\r\n lastError: z.string().nullable(),\r\n ledgerRef: z.string(),\r\n reverseLedgerRef: z.string().nullable(),\r\n metadata: Metadata,\r\n createdAtMs: z.number().int().nonnegative(),\r\n updatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type Withdrawal = z.infer<typeof WithdrawalSchema>;\r\n\r\nexport const CreateWithdrawalInputSchema = z.object({\r\n destinationId: z.string().uuid(),\r\n amountMinor: PositiveMinor,\r\n currency: Currency,\r\n idempotencyKey: z.string().trim().min(8).max(128),\r\n metadata: Metadata.optional(),\r\n});\r\nexport type CreateWithdrawalInput = z.infer<typeof CreateWithdrawalInputSchema>;\r\n\r\nexport const CreateWithdrawalResultSchema = z.object({\r\n withdrawal: WithdrawalSchema,\r\n replayed: z.boolean(),\r\n});\r\nexport type CreateWithdrawalResult = z.infer<\r\n typeof CreateWithdrawalResultSchema\r\n>;\r\n\r\n// ───────────────────────────── payout events ─────────────────────────────\r\n\r\nexport const PayoutEventInputSchema = z.object({\r\n externalRef: z.string().trim().min(8).max(128),\r\n withdrawalId: z.string().uuid().optional(),\r\n state: z.enum(['submitted', 'processing', 'paid', 'failed']),\r\n providerRef: z.string().trim().min(1).max(128).optional(),\r\n failureCode: z.string().trim().max(64).optional(),\r\n failureMessage: z.string().trim().max(512).optional(),\r\n providerMetadata: Metadata.optional(),\r\n});\r\nexport type PayoutEventInput = z.infer<typeof PayoutEventInputSchema>;\r\n\r\nexport const RecordPayoutEventResultSchema = z.object({\r\n withdrawal: WithdrawalSchema,\r\n replayed: z.boolean(),\r\n});\r\nexport type RecordPayoutEventResult = z.infer<\r\n typeof RecordPayoutEventResultSchema\r\n>;\r\n\r\n// ───────────────────────────── reconciliation ─────────────────────────────\r\n\r\nexport const ReconciliationReportSchema = z.object({\r\n partnerId: z.string().uuid(),\r\n currency: z.string(),\r\n fromMs: z.number().int().nonnegative(),\r\n toMs: z.number().int().nonnegative(),\r\n fundingsCreditMinor: MinorString,\r\n fundingsDebitMinor: MinorString,\r\n withdrawalsPaidMinor: MinorString,\r\n withdrawalsReversedMinor: MinorString,\r\n withdrawalsInFlightMinor: MinorString,\r\n expectedReserveBalanceMinor: MinorString,\r\n actualReserveBalanceMinor: MinorString,\r\n imbalanceMinor: MinorString,\r\n generatedAtMs: z.number().int().nonnegative(),\r\n});\r\nexport type ReconciliationReport = z.infer<typeof ReconciliationReportSchema>;\r\n\r\n// ───────────────────────────── partner client ─────────────────────────────\r\n\r\nexport type PartnerFundingClient = {\r\n /** Submit a funding event (idempotent on externalRef per partner). */\r\n ingestFunding: (\r\n input: PartnerFundingEventInput,\r\n ) => Promise<IngestFundingResult>;\r\n /** Send a payout state update (idempotent on terminal states). */\r\n recordPayoutEvent: (\r\n input: PayoutEventInput,\r\n ) => Promise<RecordPayoutEventResult>;\r\n /** Fetch the daily reconciliation report. */\r\n reconciliation: (input: {\r\n currency: string;\r\n fromMs?: number;\r\n toMs?: number;\r\n }) => Promise<ReconciliationReport>;\r\n};\r\n\r\nexport function createPartnerFundingClient(\r\n partner: FlurPartnerClient,\r\n): PartnerFundingClient {\r\n return {\r\n ingestFunding: async (input) => {\r\n const body = PartnerFundingEventInputSchema.parse(input);\r\n const raw = await partner.request({\r\n method: 'POST',\r\n path: '/v1/partners/fundings',\r\n body,\r\n });\r\n return IngestFundingResultSchema.parse(raw);\r\n },\r\n recordPayoutEvent: async (input) => {\r\n const body = PayoutEventInputSchema.parse(input);\r\n const raw = await partner.request({\r\n method: 'POST',\r\n path: '/v1/partners/payouts/events',\r\n body,\r\n });\r\n return RecordPayoutEventResultSchema.parse(raw);\r\n },\r\n reconciliation: async (input) => {\r\n const qs = new URLSearchParams({\r\n currency: input.currency,\r\n });\r\n if (typeof input.fromMs === 'number')\r\n qs.set('fromMs', String(input.fromMs));\r\n if (typeof input.toMs === 'number') qs.set('toMs', String(input.toMs));\r\n const raw = await partner.request({\r\n method: 'GET',\r\n path: `/v1/partners/reconciliation/daily?${qs.toString()}`,\r\n });\r\n return ReconciliationReportSchema.parse(raw);\r\n },\r\n };\r\n}\r\n\r\n// ───────────────────────────── consumer client ─────────────────────────────\r\n\r\nexport type ConsumerWithdrawalsClientOptions = {\r\n baseUrl: string;\r\n /** Session-authenticated fetch (Authorization: Bearer <session-token>). */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type ConsumerWithdrawalsClient = {\r\n listDestinations: () => Promise<ListPayoutDestinationsResult>;\r\n createDestination: (\r\n input: CreatePayoutDestinationInput,\r\n ) => Promise<PayoutDestination>;\r\n verifyDestination: (destinationId: string) => Promise<PayoutDestination>;\r\n disableDestination: (destinationId: string) => Promise<PayoutDestination>;\r\n createWithdrawal: (\r\n input: CreateWithdrawalInput,\r\n ) => Promise<CreateWithdrawalResult>;\r\n getWithdrawal: (withdrawalId: string) => Promise<Withdrawal>;\r\n};\r\n\r\nexport function createConsumerWithdrawalsClient(\r\n opts: ConsumerWithdrawalsClientOptions,\r\n): ConsumerWithdrawalsClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createConsumerWithdrawalsClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n\r\n async function call<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n parser: (raw: unknown) => T,\r\n ): Promise<T> {\r\n const init: RequestInit = {\r\n method,\r\n headers: { accept: 'application/json' },\r\n };\r\n if (body !== undefined) {\r\n init.body = JSON.stringify(body);\r\n init.headers = { ...init.headers, 'content-type': 'application/json' };\r\n }\r\n const resp = await fetchImpl(`${baseUrl}${path}`, init);\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n raw = text;\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return parser(raw);\r\n }\r\n\r\n return {\r\n listDestinations: () =>\r\n call('GET', '/v1/me/payout-destinations', undefined, (raw) =>\r\n ListPayoutDestinationsResultSchema.parse(raw),\r\n ),\r\n createDestination: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/me/payout-destinations',\r\n CreatePayoutDestinationInputSchema.parse(input),\r\n (raw) => PayoutDestinationSchema.parse(raw),\r\n ),\r\n verifyDestination: (destinationId) =>\r\n call(\r\n 'POST',\r\n `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/verify`,\r\n {},\r\n (raw) => PayoutDestinationSchema.parse(raw),\r\n ),\r\n disableDestination: (destinationId) =>\r\n call(\r\n 'POST',\r\n `/v1/me/payout-destinations/${encodeURIComponent(destinationId)}/disable`,\r\n {},\r\n (raw) => PayoutDestinationSchema.parse(raw),\r\n ),\r\n createWithdrawal: (input) =>\r\n call(\r\n 'POST',\r\n '/v1/me/withdrawals',\r\n CreateWithdrawalInputSchema.parse(input),\r\n (raw) => CreateWithdrawalResultSchema.parse(raw),\r\n ),\r\n getWithdrawal: (withdrawalId) =>\r\n call(\r\n 'GET',\r\n `/v1/me/withdrawals/${encodeURIComponent(withdrawalId)}`,\r\n undefined,\r\n (raw) => WithdrawalSchema.parse(raw),\r\n ),\r\n };\r\n}\r\n\r\n// ───────────────────────────── partner profile admin ─────────────────────────────\r\n\r\n/**\r\n * Partner profile upsert is session-authenticated on the backend (a member\r\n * of the partner account must perform the action), so it uses a regular\r\n * session-bearer fetch rather than the partner HMAC client.\r\n */\r\nexport type PartnerProfileAdminClientOptions = {\r\n baseUrl: string;\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\nexport type PartnerProfileAdminClient = {\r\n upsertProfile: (\r\n partnerAccountId: string,\r\n input: UpsertPartnerProfileInput,\r\n ) => Promise<PartnerProfile>;\r\n};\r\n\r\nexport function createPartnerProfileAdminClient(\r\n opts: PartnerProfileAdminClientOptions,\r\n): PartnerProfileAdminClient {\r\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\r\n if (!fetchImpl) {\r\n throw new Error(\r\n 'createPartnerProfileAdminClient: no fetch implementation available',\r\n );\r\n }\r\n const baseUrl = opts.baseUrl.replace(/\\/$/, '');\r\n return {\r\n upsertProfile: async (partnerAccountId, input) => {\r\n const body = {\r\n partnerAccountId,\r\n ...UpsertPartnerProfileInputSchema.parse(input),\r\n };\r\n const resp = await fetchImpl(`${baseUrl}/v1/partners/profile`, {\r\n method: 'POST',\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n const text = await resp.text();\r\n let raw: unknown;\r\n if (text) {\r\n try {\r\n raw = JSON.parse(text);\r\n } catch {\r\n raw = text;\r\n }\r\n }\r\n if (!resp.ok) {\r\n const code =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'code' in raw &&\r\n typeof (raw as { code: unknown }).code === 'string'\r\n ? (raw as { code: string }).code\r\n : `http_${resp.status}`;\r\n const message =\r\n raw &&\r\n typeof raw === 'object' &&\r\n 'message' in raw &&\r\n typeof (raw as { message: unknown }).message === 'string'\r\n ? (raw as { message: string }).message\r\n : `request failed with status ${resp.status}`;\r\n throw new FlurApiError(resp.status, code, message, raw);\r\n }\r\n return PartnerProfileSchema.parse(raw);\r\n },\r\n };\r\n}\r\n","import { z } from 'zod';\r\nimport { canonicalJSONBytes } from '../crypto/canonical.js';\r\nimport {\r\n signIssuerP256 as signP256,\r\n verifyIssuerP256 as verifyP256,\r\n} from '../crypto/p256-issuer.js';\r\n\r\n/**\r\n * Flur v1 Signed Artifact envelope.\r\n *\r\n * URI form:\r\n * flur://v1/<artifact-type>/<base64url(canonical-json(body))>.<base64url(sig)>\r\n *\r\n * Body shape (canonical JSON, sorted keys):\r\n * {\r\n * v: 1, // envelope version\r\n * t: '<artifact-type>', // matches the URI segment (redundant for safety)\r\n * iss: '<issuer-id>', // user/merchant/partner id\r\n * kid: '<device-key-id>', // identifier of the signing device key\r\n * iat: <epoch-seconds>, // issued-at\r\n * exp?: <epoch-seconds>, // optional expiry\r\n * nonce: '<string>', // unique per artifact (replay guard)\r\n * data: <artifact body> // type-specific, validated by registered schema\r\n * }\r\n *\r\n * Signature: P-256 ECDSA (SHA-256) over canonicalJSONBytes(body), ASN.1 DER, base64.\r\n *\r\n * Design notes:\r\n * - URI scheme `flur://v1/...` is the single transport for all signed artifacts.\r\n * - Scanners route on the path segment; verifiers look up the issuer/kid public key\r\n * (SubjectPublicKeyInfo DER, base64) from the backend device-key registry.\r\n * - Pure NIBSS NQR payments remain unchanged; this envelope rides separately.\r\n */\r\n\r\nexport const FLUR_ARTIFACT_URI_SCHEME = 'flur';\r\nexport const FLUR_ARTIFACT_VERSION = 1;\r\nexport const FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;\r\n\r\nconst ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;\r\n\r\nexport const ArtifactHeaderSchema = z.object({\r\n v: z.literal(FLUR_ARTIFACT_VERSION),\r\n t: z.string().regex(ArtifactTypeRe, 'invalid artifact type'),\r\n iss: z.string().min(1).max(128),\r\n kid: z.string().min(1).max(128),\r\n iat: z.number().int().nonnegative(),\r\n exp: z.number().int().positive().optional(),\r\n nonce: z\r\n .string()\r\n .min(8)\r\n .max(64)\r\n .regex(/^[A-Za-z0-9_-]+$/, 'nonce must be url-safe'),\r\n});\r\n\r\nexport type ArtifactHeader = z.infer<typeof ArtifactHeaderSchema>;\r\n\r\nexport type ArtifactBody<T = unknown> = ArtifactHeader & { data: T };\r\n\r\nexport type SignedArtifact<T = unknown> = {\r\n body: ArtifactBody<T>;\r\n /** ASN.1 DER ECDSA P-256 signature, base64 (standard, not url-safe). */\r\n sig: string;\r\n};\r\n\r\nexport class FlurArtifactError extends Error {\r\n constructor(\r\n message: string,\r\n public code:\r\n | 'INVALID_URI'\r\n | 'INVALID_TYPE'\r\n | 'INVALID_BODY'\r\n | 'INVALID_SIGNATURE'\r\n | 'EXPIRED'\r\n | 'TYPE_MISMATCH',\r\n ) {\r\n super(message);\r\n this.name = 'FlurArtifactError';\r\n }\r\n}\r\n\r\n// --- base64url helpers (no padding) ---\r\n\r\nexport function base64UrlEncode(bytes: Uint8Array): string {\r\n let bin = '';\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\r\n // btoa is available in browsers, RN (Hermes), and Node >= 16.\r\n const b64 =\r\n typeof btoa === 'function'\r\n ? btoa(bin)\r\n : Buffer.from(bytes).toString('base64');\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\r\n}\r\n\r\nexport function base64UrlDecode(s: string): Uint8Array {\r\n const pad = s.length % 4 === 0 ? '' : '='.repeat(4 - (s.length % 4));\r\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/') + pad;\r\n if (typeof atob === 'function') {\r\n const bin = atob(b64);\r\n const out = new Uint8Array(bin.length);\r\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\r\n return out;\r\n }\r\n return new Uint8Array(Buffer.from(b64, 'base64'));\r\n}\r\n\r\n// --- envelope build / sign / verify ---\r\n\r\nexport function buildArtifactBody<T>(input: {\r\n type: string;\r\n issuer: string;\r\n keyId: string;\r\n data: T;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n nonce: string;\r\n}): ArtifactBody<T> {\r\n if (!ArtifactTypeRe.test(input.type)) {\r\n throw new FlurArtifactError(\r\n `Invalid artifact type: ${input.type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1000);\r\n const header: ArtifactHeader = {\r\n v: FLUR_ARTIFACT_VERSION,\r\n t: input.type,\r\n iss: input.issuer,\r\n kid: input.keyId,\r\n iat,\r\n ...(input.expiresAtSeconds !== undefined\r\n ? { exp: input.expiresAtSeconds }\r\n : {}),\r\n nonce: input.nonce,\r\n };\r\n // Validate header structure early so callers get a clean error.\r\n ArtifactHeaderSchema.parse(header);\r\n return { ...header, data: input.data };\r\n}\r\n\r\nexport function signArtifact<T>(\r\n body: ArtifactBody<T>,\r\n privateKey: Uint8Array,\r\n): SignedArtifact<T> {\r\n const sig = signP256(canonicalJSONBytes(body), privateKey);\r\n return { body, sig };\r\n}\r\n\r\nexport function encodeArtifactUri<T>(signed: SignedArtifact<T>): string {\r\n const bodyBytes = canonicalJSONBytes(signed.body);\r\n const bodyB64 = base64UrlEncode(bodyBytes);\r\n // signed.sig is standard base64; re-encode as base64url for URI transport.\r\n const sigBytes = base64UrlDecode(signed.sig);\r\n const sigB64Url = base64UrlEncode(sigBytes);\r\n return `${FLUR_ARTIFACT_URI_PREFIX}${signed.body.t}/${bodyB64}.${sigB64Url}`;\r\n}\r\n\r\nexport type DecodedArtifactUri = {\r\n type: string;\r\n bodyBytes: Uint8Array;\r\n body: ArtifactBody;\r\n /** ASN.1 DER ECDSA P-256 signature, base64 (standard). */\r\n sig: string;\r\n};\r\n\r\nexport function decodeArtifactUri(uri: string): DecodedArtifactUri {\r\n if (!uri.startsWith(FLUR_ARTIFACT_URI_PREFIX)) {\r\n throw new FlurArtifactError(\r\n `URI does not start with ${FLUR_ARTIFACT_URI_PREFIX}`,\r\n 'INVALID_URI',\r\n );\r\n }\r\n const rest = uri.slice(FLUR_ARTIFACT_URI_PREFIX.length);\r\n const slash = rest.indexOf('/');\r\n if (slash <= 0) {\r\n throw new FlurArtifactError('Missing artifact type segment', 'INVALID_URI');\r\n }\r\n const type = rest.slice(0, slash);\r\n const payload = rest.slice(slash + 1);\r\n const dot = payload.indexOf('.');\r\n if (dot <= 0 || dot === payload.length - 1) {\r\n throw new FlurArtifactError(\r\n 'Missing body/signature separator',\r\n 'INVALID_URI',\r\n );\r\n }\r\n if (!ArtifactTypeRe.test(type)) {\r\n throw new FlurArtifactError(\r\n `Invalid artifact type: ${type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n\r\n const bodyBytes = base64UrlDecode(payload.slice(0, dot));\r\n const sigBytes = base64UrlDecode(payload.slice(dot + 1));\r\n // P-256 ECDSA DER signatures are typically ~70–72 bytes; allow a small\r\n // range to defend against malformed payloads.\r\n if (sigBytes.length < 64 || sigBytes.length > 80) {\r\n throw new FlurArtifactError(\r\n `Signature length out of range: ${sigBytes.length}`,\r\n 'INVALID_SIGNATURE',\r\n );\r\n }\r\n\r\n let bodyJson: unknown;\r\n try {\r\n bodyJson = JSON.parse(new TextDecoder().decode(bodyBytes));\r\n } catch {\r\n throw new FlurArtifactError('Body is not valid JSON', 'INVALID_BODY');\r\n }\r\n\r\n const headerOnly = ArtifactHeaderSchema.safeParse(bodyJson);\r\n if (!headerOnly.success) {\r\n throw new FlurArtifactError(\r\n `Body header invalid: ${headerOnly.error.message}`,\r\n 'INVALID_BODY',\r\n );\r\n }\r\n if (headerOnly.data.t !== type) {\r\n throw new FlurArtifactError(\r\n `URI type ${type} does not match body type ${headerOnly.data.t}`,\r\n 'TYPE_MISMATCH',\r\n );\r\n }\r\n\r\n return {\r\n type,\r\n bodyBytes,\r\n body: bodyJson as ArtifactBody,\r\n // Encode as standard base64 (not url-safe) for sig field consistency.\r\n sig: encodeStdBase64(sigBytes),\r\n };\r\n}\r\n\r\nfunction encodeStdBase64(bytes: Uint8Array): string {\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(bytes).toString('base64');\r\n }\r\n let bin = '';\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\r\n return typeof btoa === 'function' ? btoa(bin) : '';\r\n}\r\n\r\nexport type VerifyArtifactOptions = {\r\n /** Caller-supplied current time (seconds). Defaults to Date.now()/1000. */\r\n nowSeconds?: number;\r\n /** When true (default), reject artifacts whose `exp` is in the past. */\r\n enforceExpiry?: boolean;\r\n};\r\n\r\nexport function verifyArtifactSignature(\r\n decoded: DecodedArtifactUri,\r\n publicKeySpkiB64: string,\r\n options: VerifyArtifactOptions = {},\r\n): boolean {\r\n if (options.enforceExpiry !== false && decoded.body.exp !== undefined) {\r\n const now = options.nowSeconds ?? Math.floor(Date.now() / 1000);\r\n if (decoded.body.exp < now) {\r\n throw new FlurArtifactError('Artifact has expired', 'EXPIRED');\r\n }\r\n }\r\n return verifyP256(decoded.bodyBytes, decoded.sig, publicKeySpkiB64);\r\n}\r\n","import { z } from 'zod';\nimport { OfflinePaymentAuthorizationSchema } from '../offline/messages.js';\n\n/**\n * Registry of all Flur v1 signed artifact types.\n *\n * Each artifact has:\n * - a string discriminator (used in the URI path segment & header `t`),\n * - a Zod schema validating the `data` payload only (envelope header is validated separately).\n *\n * Two artifacts are fully specified in this slice (OPA + Receipt) as the\n * canonical implementation pattern. The remaining nine carry stub schemas\n * (`z.unknown()`) so types compile and the registry is complete; bodies\n * will be locked in subsequent slices once their backend ledger shapes\n * are finalised.\n */\n\nexport const ARTIFACT_TYPES = {\n OFFLINE_PAYMENT_AUTHORIZATION: 'offline_payment_authorization',\n RECEIPT: 'receipt',\n // --- stubs, schemas to be hardened in follow-ups ---\n NQR_PAYMENT_REQUEST: 'nqr_payment_request',\n PAYMENT_INTENT: 'payment_intent',\n OFFLINE_CLAIM: 'offline_claim',\n SETTLEMENT_RECORD: 'settlement_record',\n REVERSAL_RECORD: 'reversal_record',\n LEDGER_JOURNAL_ENTRY: 'ledger_journal_entry',\n STATEMENT: 'statement',\n PASS: 'pass',\n IDENTITY: 'identity',\n} as const;\n\nexport type ArtifactType = (typeof ARTIFACT_TYPES)[keyof typeof ARTIFACT_TYPES];\n\nconst HexString = (length: number) =>\n z\n .string()\n .regex(\n new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),\n `expected ${length}-byte hex string`,\n );\n\n// --- Fully specified: offline_payment_authorization ---\n// Wraps the existing FLUR2: payload in the unified envelope. The inner\n// OfflinePaymentAuthorization is already self-signed; embedding it here\n// adds the device-key issuer attestation + uniform nonce/expiry handling.\nexport const OfflinePaymentAuthorizationArtifactSchema = z.object({\n authorization: OfflinePaymentAuthorizationSchema,\n});\nexport type OfflinePaymentAuthorizationArtifact = z.infer<\n typeof OfflinePaymentAuthorizationArtifactSchema\n>;\n\n// --- Fully specified: receipt ---\n// Payment receipt produced by the payee after a payment settles (online or\n// reconciled from offline). Signed by the issuer's device key so payers and\n// auditors can verify provenance offline.\nexport const ReceiptArtifactSchema = z.object({\n receiptId: z.string().min(1).max(64),\n paymentReference: z.string().min(1).max(64),\n payerUserId: z.string().min(1).max(64).optional(),\n payeeUserId: z.string().min(1).max(64),\n amountKobo: z.number().int().positive(),\n currency: z.literal('NGN'),\n channel: z.enum(['online', 'offline_reconciled', 'pay_link', 'nqr']),\n settledAtMs: z.number().int().positive(),\n ledgerTxnId: z.string().min(1).max(64).optional(),\n memo: z.string().max(140).optional(),\n hashChainPrev: HexString(32).optional(),\n});\nexport type ReceiptArtifact = z.infer<typeof ReceiptArtifactSchema>;\n\n// --- Shared field primitives (reused across the remaining artifacts) ---\nconst ShortId = z.string().min(1).max(64);\nconst PositiveInt = z.number().int().positive();\nconst NonNegativeInt = z.number().int().nonnegative();\nconst Currency = z.literal('NGN');\nconst Memo = z.string().max(140);\n\n// --- nqr_payment_request ---\n// Merchant- or payee-issued payment request rendered as a Flur QR. The amount\n// may be omitted for \"any amount\" / open-tab flows. Verifiers should refuse\n// expired requests and surface `memo` to the payer.\nexport const NqrPaymentRequestArtifactSchema = z.object({\n requestId: ShortId,\n payeeUserId: ShortId,\n amountKobo: PositiveInt.optional(),\n currency: Currency,\n memo: Memo.optional(),\n expiresAtMs: PositiveInt.optional(),\n});\nexport type NqrPaymentRequestArtifact = z.infer<\n typeof NqrPaymentRequestArtifactSchema\n>;\n\n// --- payment_intent ---\n// Payer-side commitment to pay a specific payee. Bound to an idempotency key\n// so a single intent cannot drive multiple settlements server-side.\nexport const PaymentIntentArtifactSchema = z.object({\n intentId: ShortId,\n payerUserId: ShortId,\n payeeUserId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n idempotencyKey: ShortId,\n createdAtMs: PositiveInt,\n});\nexport type PaymentIntentArtifact = z.infer<typeof PaymentIntentArtifactSchema>;\n\n// --- offline_claim ---\n// Payee's signed claim submitted to settle a previously presented OPA.\n// `claimedAmountKobo` may differ from the OPA face value (e.g. partial fills).\nexport const OfflineClaimArtifactSchema = z.object({\n claimId: ShortId,\n authorizationId: ShortId,\n payeeUserId: ShortId,\n claimedAmountKobo: PositiveInt,\n currency: Currency,\n claimedAtMs: PositiveInt,\n paymentReference: ShortId.optional(),\n});\nexport type OfflineClaimArtifact = z.infer<typeof OfflineClaimArtifactSchema>;\n\n// --- settlement_record ---\n// Internal record of a settlement event, linking the source artifact (OPA,\n// claim, transfer, pay-link) to its ledger transaction.\nexport const SettlementRecordArtifactSchema = z.object({\n settlementId: ShortId,\n ledgerTxnId: ShortId,\n sourceRefType: z.enum([\n 'offline_authorization',\n 'offline_claim',\n 'transfer',\n 'pay_link',\n ]),\n sourceRefId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n settledAtMs: PositiveInt,\n});\nexport type SettlementRecordArtifact = z.infer<\n typeof SettlementRecordArtifactSchema\n>;\n\n// --- reversal_record ---\n// Reversal of a prior settled transaction. `reason` is a closed enum so\n// downstream analytics can bucket disputes reliably.\nexport const ReversalRecordArtifactSchema = z.object({\n reversalId: ShortId,\n originalTxnId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n reason: z.enum([\n 'user_dispute',\n 'fraud',\n 'duplicate',\n 'admin_correction',\n 'other',\n ]),\n reversedAtMs: PositiveInt,\n memo: Memo.optional(),\n});\nexport type ReversalRecordArtifact = z.infer<\n typeof ReversalRecordArtifactSchema\n>;\n\n// --- ledger_journal_entry ---\n// One side-balanced double-entry journal line. `debitAccountId` and\n// `creditAccountId` are opaque internal account identifiers.\nexport const LedgerJournalEntryArtifactSchema = z.object({\n entryId: ShortId,\n journalId: ShortId,\n debitAccountId: ShortId,\n creditAccountId: ShortId,\n amountKobo: PositiveInt,\n currency: Currency,\n postedAtMs: PositiveInt,\n refType: ShortId.optional(),\n refId: ShortId.optional(),\n});\nexport type LedgerJournalEntryArtifact = z.infer<\n typeof LedgerJournalEntryArtifactSchema\n>;\n\n// --- statement ---\n// Account-statement summary for a closed period. `hashChainPrev` links to\n// the prior statement for tamper-evident chaining.\nexport const StatementArtifactSchema = z\n .object({\n statementId: ShortId,\n userId: ShortId,\n periodStartMs: PositiveInt,\n periodEndMs: PositiveInt,\n openingBalanceKobo: z.number().int(),\n closingBalanceKobo: z.number().int(),\n transactionCount: NonNegativeInt,\n currency: Currency,\n hashChainPrev: HexString(32).optional(),\n })\n .refine((v) => v.periodEndMs > v.periodStartMs, {\n message: 'periodEndMs must be greater than periodStartMs',\n path: ['periodEndMs'],\n });\nexport type StatementArtifact = z.infer<typeof StatementArtifactSchema>;\n\n// --- pass ---\n// Generic digital pass (membership, ticket, loyalty, access, voucher).\n// `metadata` is intentionally narrow — only scalar values — so canonical\n// JSON ordering remains deterministic across SDK versions.\nexport const PassArtifactSchema = z\n .object({\n passId: ShortId,\n holderId: ShortId,\n category: z.enum(['membership', 'ticket', 'loyalty', 'access', 'voucher']),\n title: z.string().min(1).max(120),\n validFromMs: PositiveInt,\n validUntilMs: PositiveInt.optional(),\n metadata: z\n .record(\n z.string().min(1).max(64),\n z.union([z.string().max(280), z.number(), z.boolean()]),\n )\n .optional(),\n })\n .refine(\n (v) => v.validUntilMs === undefined || v.validUntilMs > v.validFromMs,\n {\n message: 'validUntilMs must be greater than validFromMs',\n path: ['validUntilMs'],\n },\n );\nexport type PassArtifact = z.infer<typeof PassArtifactSchema>;\n\n// --- identity ---\n// Identity attestation. `claimValueHash` is the SHA-256 of the underlying\n// value so the artifact can be shared without leaking PII.\nexport const IdentityArtifactSchema = z.object({\n attestationId: ShortId,\n subjectId: ShortId,\n claimType: z.enum([\n 'phone_verified',\n 'email_verified',\n 'bvn_verified',\n 'kyc_tier',\n 'age_band',\n ]),\n claimValueHash: HexString(32),\n attestedAtMs: PositiveInt,\n});\nexport type IdentityArtifact = z.infer<typeof IdentityArtifactSchema>;\n\nexport const ARTIFACT_BODY_SCHEMAS = {\n [ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]:\n OfflinePaymentAuthorizationArtifactSchema,\n [ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,\n [ARTIFACT_TYPES.NQR_PAYMENT_REQUEST]: NqrPaymentRequestArtifactSchema,\n [ARTIFACT_TYPES.PAYMENT_INTENT]: PaymentIntentArtifactSchema,\n [ARTIFACT_TYPES.OFFLINE_CLAIM]: OfflineClaimArtifactSchema,\n [ARTIFACT_TYPES.SETTLEMENT_RECORD]: SettlementRecordArtifactSchema,\n [ARTIFACT_TYPES.REVERSAL_RECORD]: ReversalRecordArtifactSchema,\n [ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,\n [ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,\n [ARTIFACT_TYPES.PASS]: PassArtifactSchema,\n [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema,\n} as const;\n\n/** Artifact types whose body schema is fully specified and safe to dispatch. */\nexport const HARDENED_ARTIFACT_TYPES = new Set<ArtifactType>([\n ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,\n ARTIFACT_TYPES.RECEIPT,\n ARTIFACT_TYPES.NQR_PAYMENT_REQUEST,\n ARTIFACT_TYPES.PAYMENT_INTENT,\n ARTIFACT_TYPES.OFFLINE_CLAIM,\n ARTIFACT_TYPES.SETTLEMENT_RECORD,\n ARTIFACT_TYPES.REVERSAL_RECORD,\n ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,\n ARTIFACT_TYPES.STATEMENT,\n ARTIFACT_TYPES.PASS,\n ARTIFACT_TYPES.IDENTITY,\n]);\n\nexport function isKnownArtifactType(t: string): t is ArtifactType {\n return (Object.values(ARTIFACT_TYPES) as string[]).includes(t);\n}\n\nexport function isHardenedArtifactType(t: string): t is ArtifactType {\n return HARDENED_ARTIFACT_TYPES.has(t as ArtifactType);\n}\n","import { z } from 'zod';\r\nimport {\r\n decodeArtifactUri,\r\n FlurArtifactError,\r\n type ArtifactBody,\r\n type DecodedArtifactUri,\r\n type SignedArtifact,\r\n type VerifyArtifactOptions,\r\n buildArtifactBody,\r\n signArtifact,\r\n encodeArtifactUri,\r\n verifyArtifactSignature,\r\n} from './envelope.js';\r\nimport {\r\n ARTIFACT_BODY_SCHEMAS,\r\n ARTIFACT_TYPES,\r\n isHardenedArtifactType,\r\n isKnownArtifactType,\r\n type ArtifactType,\r\n type OfflinePaymentAuthorizationArtifact,\r\n type ReceiptArtifact,\r\n} from './types.js';\r\n\r\n/**\r\n * Build, sign and encode a typed artifact into a flur://v1/... URI.\r\n *\r\n * - Validates the body against the registered Zod schema for `type`.\r\n * - Refuses unknown artifact types.\r\n * - Refuses stub types (those without a hardened schema) to avoid shipping\r\n * unverifiable payloads.\r\n */\r\nexport function createArtifactUri<T>(input: {\r\n type: ArtifactType;\r\n issuer: string;\r\n keyId: string;\r\n privateKey: Uint8Array;\r\n data: T;\r\n nonce: string;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n}): { uri: string; signed: SignedArtifact<T> } {\r\n if (!isKnownArtifactType(input.type)) {\r\n throw new FlurArtifactError(\r\n `Unknown artifact type: ${input.type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n if (!isHardenedArtifactType(input.type)) {\r\n throw new FlurArtifactError(\r\n `Artifact type ${input.type} is not yet hardened for emission`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n const schema = ARTIFACT_BODY_SCHEMAS[input.type] as unknown as z.ZodType<T>;\r\n const parsedData = schema.parse(input.data);\r\n\r\n const body = buildArtifactBody({\r\n type: input.type,\r\n issuer: input.issuer,\r\n keyId: input.keyId,\r\n data: parsedData,\r\n nonce: input.nonce,\r\n issuedAtSeconds: input.issuedAtSeconds,\r\n expiresAtSeconds: input.expiresAtSeconds,\r\n });\r\n const signed = signArtifact(body, input.privateKey);\r\n return { uri: encodeArtifactUri(signed), signed };\r\n}\r\n\r\nexport type VerifiedArtifact<T = unknown> = {\r\n type: ArtifactType;\r\n body: ArtifactBody<T>;\r\n sig: string;\r\n decoded: DecodedArtifactUri;\r\n};\r\n\r\n/**\r\n * Decode and verify a flur://v1/... URI.\r\n *\r\n * - Parses the URI and envelope header.\r\n * - Validates the body against the registered Zod schema.\r\n * - Verifies the P-256 ECDSA(SHA-256) DER signature against the supplied public key.\r\n * - Enforces expiry unless `options.enforceExpiry === false`.\r\n *\r\n * The caller is responsible for resolving the public key from (issuer, kid)\r\n * against the backend device-key registry, and for enforcing nonce uniqueness\r\n * via the artifact_nonces store.\r\n */\r\nexport function verifyArtifactUri<T = unknown>(\r\n uri: string,\r\n publicKeySpkiB64: string,\r\n options: VerifyArtifactOptions = {},\r\n): VerifiedArtifact<T> {\r\n const decoded = decodeArtifactUri(uri);\r\n\r\n if (!isKnownArtifactType(decoded.type)) {\r\n throw new FlurArtifactError(\r\n `Unknown artifact type: ${decoded.type}`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n if (!isHardenedArtifactType(decoded.type)) {\r\n throw new FlurArtifactError(\r\n `Artifact type ${decoded.type} is not yet hardened for verification`,\r\n 'INVALID_TYPE',\r\n );\r\n }\r\n\r\n const schema = ARTIFACT_BODY_SCHEMAS[decoded.type as ArtifactType];\r\n const dataParsed = schema.safeParse(decoded.body.data);\r\n if (!dataParsed.success) {\r\n throw new FlurArtifactError(\r\n `Artifact body invalid: ${dataParsed.error.message}`,\r\n 'INVALID_BODY',\r\n );\r\n }\r\n\r\n const ok = verifyArtifactSignature(decoded, publicKeySpkiB64, options);\r\n if (!ok) {\r\n throw new FlurArtifactError(\r\n 'Artifact signature verification failed',\r\n 'INVALID_SIGNATURE',\r\n );\r\n }\r\n\r\n return {\r\n type: decoded.type as ArtifactType,\r\n body: decoded.body as ArtifactBody<T>,\r\n sig: decoded.sig,\r\n decoded,\r\n };\r\n}\r\n\r\n// Convenience helpers that pin the artifact-type generic for the two\r\n// hardened artifacts. Useful for app code that wants compile-time guarantees\r\n// without repeating the schema reference.\r\n\r\nexport function createReceiptArtifactUri(input: {\r\n issuer: string;\r\n keyId: string;\r\n privateKey: Uint8Array;\r\n data: ReceiptArtifact;\r\n nonce: string;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n}) {\r\n return createArtifactUri<ReceiptArtifact>({\r\n ...input,\r\n type: ARTIFACT_TYPES.RECEIPT,\r\n });\r\n}\r\n\r\nexport function createOfflinePaymentAuthorizationArtifactUri(input: {\r\n issuer: string;\r\n keyId: string;\r\n privateKey: Uint8Array;\r\n data: OfflinePaymentAuthorizationArtifact;\r\n nonce: string;\r\n issuedAtSeconds?: number;\r\n expiresAtSeconds?: number;\r\n}) {\r\n return createArtifactUri<OfflinePaymentAuthorizationArtifact>({\r\n ...input,\r\n type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,\r\n });\r\n}\r\n"],"mappings":";AAAA,SAAS,KAAAA,UAAuB;;;ACAhC,SAAS,SAAS;AAEX,IAAM,YAAY;AAEzB,IAAM,aAAa,EAAE,OAAO,EAAE,KAAK;AACnC,IAAM,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,KAAK,CAAC;AAC1D,IAAM,iBAAiB,EACpB,OAAO,EACP,KAAK,EACL,OAAO,CAAC,EACR,UAAU,CAAC,UAAU,MAAM,YAAY,CAAC;AAEpC,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,IAAI,EAAE,QAAQ;AAChB,CAAC;AAEM,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,SAAS,EAAE,OAAO;AACpB,CAAC;AAEM,IAAM,+BAA+B,EAAE,OAAO;AAAA,EACnD,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS;AAAA,EACrC,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,UAAU,EAAE,KAAK,CAAC,WAAW,OAAO,KAAK,CAAC;AAAA,EAC1C,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAC5C,gBAAgB,EACb,OAAO;AAAA,IACN,UAAU,EAAE,KAAK,CAAC,WAAW,OAAO,KAAK,CAAC;AAAA,IAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;AAAA,EAC1B,CAAC,EACA,SAAS;AAAA,EACZ,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACrD,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AACtD,CAAC;AAEM,IAAM,gCAAgC,EAAE,OAAO;AAAA,EACpD,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACpC,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACxC,UAAU,EAAE,KAAK,CAAC,eAAe,KAAK,CAAC;AACzC,CAAC;AAEM,IAAM,kCAAkC,EAAE,OAAO;AAAA,EACtD,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAC9B,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAC9C,CAAC;AAEM,IAAM,mCAAmC,EAAE,OAAO;AAAA,EACvD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,QAAQ;AAAA,EACR,YAAY,EAAE,QAAQ;AAAA,EACtB,cAAc,EAAE;AAAA,IACd,EAAE,KAAK,CAAC,mBAAmB,WAAW,iBAAiB,CAAC;AAAA,EAC1D;AAAA,EACA,gBAAgB,EAAE,QAAQ,EAAE,SAAS;AAAA,EACrC,YAAY,EAAE,KAAK,CAAC,MAAM,aAAa,CAAC,EAAE,SAAS;AACrD,CAAC;AAEM,IAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,QAAQ;AAAA,EACR,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,gBAAgB,EAAE,OAAO;AAAA,IACvB,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IAC/B,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,IAC/B,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACpC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,CAAC;AACH,CAAC;AAEM,IAAM,+BAA+B,EAAE,OAAO;AAAA,EACnD,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACjC,YAAY,EAAE,OAAO;AAAA,EACrB,YAAY,EAAE,KAAK,CAAC,mBAAmB,qBAAqB,YAAY,CAAC;AAAA,EACzE,gBAAgB,EAAE,QAAQ;AAC5B,CAAC;AAEM,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,QAAQ;AAAA,EACR,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC;AACnC,CAAC;AAEM,IAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,gBAAgB,EAAE,QAAQ;AAC5B,CAAC;AAEM,IAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,QAAQ;AAAA,EACR,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAChC,CAAC;AAEM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,QAAQ;AAAA,EACR,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS;AACjC,CAAC;AAEM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,QAAQ;AAAA,EACR,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS;AACjC,CAAC;AAEM,IAAM,mBAAmB,EAAE,OAAO;AAAA,EACvC,IAAI,EAAE,QAAQ;AAChB,CAAC;AAEM,IAAM,qCAAqC,EAAE,OAAO;AAAA,EACzD,QAAQ;AAAA,EACR,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE;AAC9B,CAAC;AAOM,IAAM,qBAAqB,CAAC,cAAc,gBAAgB;AAG1D,IAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,QAAQ;AAAA,EACR,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,SAAS,EAAE,KAAK,kBAAkB,EAAE,SAAS;AAC/C,CAAC;AAEM,IAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,aAAa;AAAA,EACb,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,WAAW;AACb,CAAC;AAEM,IAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,QAAQ;AAAA,EACR,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,aAAa;AAAA,EACb,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE;AAC9B,CAAC;AAEM,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE;AAClC,CAAC;AAEM,IAAM,gCAAgC,EAAE,OAAO;AAAA,EACpD,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAC9B,CAAC;AAEM,IAAM,iCAAiC,EAAE,OAAO;AAAA,EACrD,iBAAiB;AAAA,EACjB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,sBAAsB,EAAE,OAAO,EAAE,MAAM,SAAS;AAAA,EAChD,UAAU,EAAE,QAAQ;AACtB,CAAC;AAEM,IAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,qBAAqB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACrC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACvC,UAAU;AAAA,EACV,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE;AAClC,CAAC;AAED,IAAM,uBAAuB,EAAE,KAAK,CAAC,WAAW,kBAAkB,UAAU,CAAC;AAEtE,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,WAAW;AACb,CAAC;AAED,IAAM,kBAAkB,EAAE,KAAK,CAAC,YAAY,UAAU,CAAC;AAEhD,IAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,WAAW;AAAA,EACX,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC5B,aAAa,EAAE,OAAO,EAAE,IAAI;AAAA,EAC5B,UAAU;AAAA,EACV,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,WAAW;AACb,CAAC;AAEM,IAAM,+BAA+B,EAAE,OAAO;AAAA;AAAA,EAEnD,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAKR,OAAO,EACJ,OAAO,EACP,MAAM,aAAa,EACnB,SAAS;AAAA,EACZ,SAAS,EAAE,OAAO,EAAE,IAAI;AAAA,EACxB,UAAU;AAAA,EACV,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC7C,oBAAoB,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACjD,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,gBAAgB,EAAE,MAAM,yBAAyB;AACnD,CAAC;AAEM,IAAM,iCAAiC,EAAE,OAAO;AAAA,EACrD,OAAO,EAAE,MAAM,yBAAyB;AAAA,EACxC,YAAY,EAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAEM,IAAM,kCAAkC,EAAE,OAAO;AAAA,EACtD,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,WAAW;AAAA,EACX,kBAAkB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAClC,wBAAwB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxC,aAAa,EAAE,OAAO,EAAE,IAAI;AAAA,EAC5B,UAAU;AAAA,EACV,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,WAAW;AACb,CAAC;AAEM,IAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,UAAU,EAAE,KAAK,CAAC,OAAO,WAAW,KAAK,CAAC;AAAA,EAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;AAC1B,CAAC;AAEM,IAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACzB,CAAC;AAEM,IAAM,+BAA+B,EAAE,OAAO;AAAA,EACnD,iBAAiB;AAAA,EACjB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,sBAAsB,EAAE,OAAO,EAAE,MAAM,SAAS;AAAA,EAChD,UAAU,EAAE,QAAQ;AACtB,CAAC;;;ACzND,IAAM,sBAAkD,oBAAI,IAAI;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEhB,YACE,SACA,MACA,MACA;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,UAAU,MAAM;AACrB,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;AAOO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACkB,QACA,MAChB,SACgB,KAChB;AACA,UAAM,OAAO;AALG;AACA;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EAPkB;AAAA,EACA;AAAA,EAEA;AAKpB;AAGO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1B,OAAO;AAAA,EACvB,YAAY,UAAU,mBAAmB;AACvC,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAIO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzB,OAAO;AAAA,EACvB,YAAY,UAAU,iDAAiD;AACrE,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAIO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC9B,OAAO;AAAA,EACvB,YAAY,UAAU,qCAAqC;AACzD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,eAAsB,eAAe,KAAmC;AACtE,QAAM,QAAQ,IAAI,QAAQ,IAAI,cAAc;AAC5C,MAAI,UAAmB;AACvB,MAAI,aAA4B;AAChC,MAAI,gBAAgB,QAAQ,IAAI,MAAM;AACtC,MAAI;AACF,UAAM,KAAK,IAAI,QAAQ,IAAI,cAAc,KAAK;AAC9C,cAAU,GAAG,SAAS,kBAAkB,IACpC,MAAM,IAAI,KAAK,IACf,MAAM,IAAI,KAAK;AACnB,QAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,YAAM,gBAAiB,QAA+B;AACtD,YAAM,mBACJ,QACA;AACF,YAAM,kBAAmB,QAAgC;AAEzD,UACE,OAAO,kBAAkB,YACzB,oBAAoB,IAAI,aAA8B,GACtD;AACA,qBAAa;AAAA,MACf;AAEA,UAAI,OAAO,qBAAqB,YAAY,iBAAiB,SAAS,GAAG;AACvE,wBAAgB;AAAA,MAClB,WACE,OAAO,oBAAoB,YAC3B,gBAAgB,SAAS,GACzB;AACA,wBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,IAAI,UAAU,eAAe,YAAY;AAAA,IAC9C,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA;AAAA,EACF,CAAC;AACH;;;AChKA,SAAS,KAAAC,UAAS;AASlB,IAAM,qBAAqBC,GAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,UAAU,MAAM,YAAY,CAAC;AAE/F,IAAM,yBAAiD;AAAA,EACrD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAEA,SAAS,kBAAkB,UAA0B;AACnD,SAAO,uBAAuB,QAAQ,KAAK;AAC7C;AAEO,SAAS,iBAAiB,OAAe,UAAyB;AACvE,QAAM,qBAAqB,mBAAmB,MAAM,QAAQ;AAC5D,QAAM,MAAM,MAAM,KAAK;AAEvB,MAAI,CAAC,gBAAgB,KAAK,GAAG,GAAG;AAC9B,UAAM,IAAI,UAAU,yBAAyB,iBAAiB;AAAA,EAChE;AAEA,QAAM,CAAC,OAAO,WAAW,EAAE,IAAI,IAAI,MAAM,GAAG;AAC5C,QAAM,iBAAiB,kBAAkB,kBAAkB;AAE3D,MAAI,SAAS,SAAS,gBAAgB;AACpC,UAAM,IAAI,UAAU,wCAAwC,iBAAiB;AAAA,EAC/E;AAEA,QAAM,iBAAiB,SAAS,OAAO,gBAAgB,GAAG;AAC1D,QAAM,gBAAgB,GAAG,KAAK,GAAG,cAAc,GAAG,QAAQ,WAAW,IAAI,KAAK;AAC9E,QAAM,cAAc,OAAO,aAAa;AAExC,MAAI,cAAc,IAAI;AACpB,UAAM,IAAI,UAAU,6BAA6B,iBAAiB;AAAA,EACpE;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,EACZ;AACF;AAEO,SAAS,aAAa,aAAqB,UAA0B;AAC1E,QAAM,qBAAqB,mBAAmB,MAAM,QAAQ;AAC5D,MAAI,cAAc,IAAI;AACpB,UAAM,IAAI,UAAU,6BAA6B,iBAAiB;AAAA,EACpE;AAEA,QAAM,iBAAiB,kBAAkB,kBAAkB;AAC3D,MAAI,mBAAmB,GAAG;AACxB,WAAO,YAAY,SAAS;AAAA,EAC9B;AAEA,QAAM,UAAU,OAAO,OAAO,cAAc;AAC5C,QAAM,QAAQ,cAAc;AAC5B,QAAM,YAAY,cAAc,SAAS,SAAS,EAAE,SAAS,gBAAgB,GAAG;AAChF,SAAO,GAAG,MAAM,SAAS,CAAC,IAAI,QAAQ;AACxC;AAEA,IAAM,4BAAoD;AAAA,EACxD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEO,SAAS,cAAc,OAAe,gBAAiC;AAC5E,QAAM,UAAU,MAAM,KAAK;AAE3B,MAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,QAAI,CAAC,UAAU,KAAK,OAAO,GAAG;AAC5B,YAAM,IAAI,UAAU,wBAAwB,iBAAiB;AAAA,IAC/D;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,QAAQ,QAAQ,OAAO,EAAE;AACxC,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,UAAU,wBAAwB,iBAAiB;AAAA,EAC/D;AAEA,MAAI,OAAO,WAAW,IAAI,GAAG;AAC3B,UAAMC,aAAY,IAAI,OAAO,MAAM,CAAC,CAAC;AACrC,QAAI,CAAC,UAAU,KAAKA,UAAS,GAAG;AAC9B,YAAM,IAAI,UAAU,wBAAwB,iBAAiB;AAAA,IAC/D;AACA,WAAOA;AAAA,EACT;AAEA,QAAM,oBAAoB,gBAAgB,KAAK,EAAE,YAAY;AAC7D,QAAM,cAAc,oBAAoB,0BAA0B,iBAAiB,IAAI;AACvF,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,UAAU,wBAAwB,iBAAiB;AAAA,EAC/D;AAEA,QAAM,cAAc,OAAO,WAAW,GAAG,IAAI,OAAO,MAAM,CAAC,IAAI;AAC/D,QAAM,YAAY,IAAI,WAAW,GAAG,WAAW;AAC/C,MAAI,CAAC,UAAU,KAAK,SAAS,GAAG;AAC9B,UAAM,IAAI,UAAU,wBAAwB,iBAAiB;AAAA,EAC/D;AACA,SAAO;AACT;AAEO,SAAS,mBAAmB,aAA6B;AAC9D,QAAM,WAAW,OAAO,WAAW;AACnC,MAAI,CAAC,OAAO,cAAc,QAAQ,GAAG;AACnC,UAAM,IAAI,UAAU,qCAAqC,iBAAiB;AAAA,EAC5E;AACA,SAAO;AACT;;;ACxHA,SAAS,KAAAC,UAAS;AAGX,IAAM,4BAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,IAAM,uBAAuB,CAAC,UAAU,SAAS,IAAI;AACrD,IAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,IAAM,8BAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,kBAAkBC,GACrB,OAAO,EACP,IAAI,EACJ,SAAS,EACT,IAAI,OAAO,gBAAgB;AAC9B,IAAM,iBAAiBA,GAAE;AAAA,EACvBA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,OAAO,GAAGA,GAAE,QAAQ,GAAGA,GAAE,KAAK,CAAC,CAAC;AACzD;AACA,IAAMC,kBAAiBD,GACpB,OAAO,EACP,KAAK,EACL,OAAO,CAAC,EACR,UAAU,CAAC,UAAU,MAAM,YAAY,CAAC;AAC3C,IAAM,kBAAkBA,GACrB,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,IAAI,GAAG,EACP,MAAM,oBAAoB;AAEtB,IAAM,wBAAwBA,GAAE,OAAO;AAAA,EAC5C,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,WAAWA,GAAE,OAAO;AAAA,EACpB,aAAaA,GAAE,OAAO;AAAA,EACtB,sBAAsBA,GAAE,OAAO,EAAE,MAAM,SAAS;AAAA,EAChD,eAAeA,GAAE,OAAO;AAAA,EACxB,oBAAoBA,GAAE,OAAO;AAAA,EAC7B,yBAAyBA,GAAE,OAAO;AAAA,EAClC,uBAAuBA,GAAE,OAAO;AAAA,EAChC,oBAAoBA,GAAE,KAAK,oBAAoB;AAAA,EAC/C,QAAQA,GAAE,KAAK,yBAAyB;AAAA,EACxC,gBAAgBA,GAAE,QAAQ;AAAA,EAC1B,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,mCAAmCA,GAAE,OAAO;AAAA,EACvD,WAAWA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC3C,aAAaA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAC5C,sBAAsBA,GACnB,OAAO,EACP,KAAK,EACL,MAAM,SAAS;AAAA,EAClB,eAAeA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAC9C,oBAAoBA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACnD,yBAAyBA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACxD,uBAAuBA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EACvD,oBAAoBA,GAAE,KAAK,oBAAoB,EAAE,SAAS;AAAA,EAC1D,QAAQA,GAAE,KAAK,yBAAyB,EAAE,SAAS;AAAA,EACnD,gBAAgBA,GAAE,QAAQ,EAAE,SAAS;AAAA,EACrC,gBAAgB,gBAAgB,SAAS;AAAA,EACzC,gBAAgB,gBAAgB,SAAS;AAAA,EACzC,UAAU,eAAe,SAAS;AACpC,CAAC;AAKM,IAAM,yBAAyBA,GAAE,OAAO;AAAA,EAC7C,UAAUA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,YAAYA,GAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACvC,WAAWA,GAAE,OAAO;AAAA,EACpB,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,QAAQA,GAAE,KAAK,0BAA0B;AAAA,EACzC,aAAaA,GAAE,OAAO,EAAE,SAAS;AAAA,EACjC,YAAYA,GAAE,OAAO;AAAA,EACrB,UAAUA,GAAE,OAAO;AAAA,EACnB,mBAAmBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACvC,UAAU;AAAA,EACV,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACrD,UAAUA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EAClD,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,oCAAoCA,GAAE,OAAO;AAAA,EACxD,WAAW,gBAAgB,SAAS;AAAA,EACpC,YAAY,gBAAgB,SAAS;AAAA,EACrC,UAAUC,gBAAe,SAAS;AAAA,EAClC,YAAYD,GAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACvC,eAAeA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACzD,cAAcA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACxD,aAAaA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACxD,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAClD,UAAUA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACpD,UAAU,eAAe,SAAS;AACpC,CAAC;AAKM,IAAM,+BAA+BA,GAAE,OAAO;AAAA,EACnD,UAAUA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,WAAWA,GAAE,OAAO;AAAA,EACpB,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,QAAQA,GAAE,KAAK,0BAA0B;AAAA,EACzC,mBAAmBA,GAAE,OAAO,EAAE,KAAK;AAAA,EACnC,cAAcA,GAAE,OAAO;AAAA,EACvB,sBAAsBA,GAAE,OAAO;AAAA,EAC/B,aAAaA,GAAE,OAAO,EAAE,SAAS;AAAA,EACjC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACvD,CAAC;AAKM,IAAM,2BAA2BA,GAAE,OAAO;AAAA,EAC/C,WAAW;AAAA,EACX,YAAY,gBAAgB,SAAS;AAAA,EACrC,UAAUC,gBAAe,SAAS;AAAA,EAClC,gBAAgBD,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAC7D,CAAC;AAGM,IAAM,0BAA0BA,GAAE,OAAO;AAAA,EAC9C,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,UAAUA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,aAAaA,GAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACxC,qBAAqBA,GAAE,OAAO,EAAE,KAAK;AAAA,EACrC,YAAY;AAAA,EACZ,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,QAAQA,GAAE,KAAK,2BAA2B;AAAA,EAC1C,UAAUA,GAAE,OAAO;AAAA,EACnB,mBAAmBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACvC,gBAAgBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACpC,WAAWA,GAAE,OAAO;AAAA,EACpB,aAAaA,GAAE,OAAO,EAAE,SAAS;AAAA,EACjC,gBAAgBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACpC,UAAUA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EAClD,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,gCAAgCA,GAAE,OAAO;AAAA,EACpD,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAASA,GAAE,QAAQ,EAAE,SAAS;AAAA,EAC9B,UAAUA,GAAE,QAAQ;AACtB,CAAC;AAKM,IAAM,gCAAgCA,GAAE,OAAO;AAAA,EACpD,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,QAAQA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACrC,MAAMA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACnC,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,WAAWA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACxC,gBAAgBA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC7C,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC5C,sBAAsBA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AACrD,CAAC;AAKM,IAAM,4BAA4BA,GAAE,OAAO;AAAA,EAChD,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,MAAMA,GAAE,OAAO,EAAE,IAAI;AAAA,EACrB,OAAOA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACrC,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC5C,OAAOA,GAAE,MAAM,uBAAuB;AACxC,CAAC;AAGM,IAAM,0BAA0BA,GAAE,OAAO;AAAA,EAC9C,YAAY;AAAA,EACZ,UAAUC,gBAAe,SAAS;AAAA,EAClC,gBAAgBD,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAClD,CAAC;AAGM,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EAC3C,UAAUA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,YAAY;AAAA,EACZ,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,QAAQA,GAAE,KAAK,wBAAwB;AAAA,EACvC,gBAAgBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACpC,WAAWA,GAAE,OAAO;AAAA,EACpB,mBAAmBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACvC,mBAAmBA,GAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC9C,aAAaA,GAAE,OAAO,EAAE,SAAS;AAAA,EACjC,gBAAgBA,GAAE,OAAO,EAAE,SAAS;AAAA,EACpC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,2BAA2BA,GAAE,OAAO;AAAA,EAC/C,UAAUA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACzC,SAASA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EACzC,WAAWA,GAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC3C,SAASA,GAAE,OAAOA,GAAE,QAAQ,CAAC,EAAE,SAAS;AAC1C,CAAC;AAGM,IAAM,4BAA4BA,GAAE,OAAO;AAAA,EAChD,IAAIA,GAAE,OAAO,EAAE,KAAK;AAAA,EACpB,UAAUA,GAAE,OAAO;AAAA,EACnB,SAASA,GAAE,OAAO;AAAA,EAClB,WAAWA,GAAE,OAAO;AAAA,EACpB,mBAAmBA,GAAE,QAAQ;AAAA,EAC7B,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACzD,CAAC;AAqDM,SAAS,wBACd,MACmB;AACnB,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAME,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACxC;AACA,QAAI,SAAS,QAAW;AACtB,MAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AAC/B,MAAAA,MAAK,UAAU,EAAE,GAAGA,MAAK,SAAS,gBAAgB,mBAAmB;AAAA,IACvE;AACA,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACJ,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AACN,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,uBAAuB,CAAC,WAAW,UACjC;AAAA,MACE;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C,iCAAiC,MAAM,KAAK;AAAA,MAC5C,CAAC,QAAQ,sBAAsB,MAAM,GAAG;AAAA,IAC1C;AAAA,IACF,oBAAoB,CAAC,cACnB;AAAA,MACE;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,MACA,CAAC,QAAQ,sBAAsB,MAAM,GAAG;AAAA,IAC1C;AAAA,IACF,cAAc,CAAC,UACb;AAAA,MACE;AAAA,MACA;AAAA,MACA,kCAAkC,MAAM,KAAK;AAAA,MAC7C,CAAC,QAAQ,uBAAuB,MAAM,GAAG;AAAA,IAC3C;AAAA,IACF,WAAW,CAAC,aACV;AAAA,MACE;AAAA,MACA,2BAA2B,mBAAmB,QAAQ,CAAC;AAAA,MACvD;AAAA,MACA,CAAC,QAAQ,uBAAuB,MAAM,GAAG;AAAA,IAC3C;AAAA,IACF,eAAe,CAAC,cACd;AAAA,MACE;AAAA,MACA,2BAA2B,mBAAmB,SAAS,CAAC;AAAA,MACxD;AAAA,MACA,CAAC,QAAQ,6BAA6B,MAAM,GAAG;AAAA,IACjD;AAAA,IACF,KAAK,CAAC,UACJ;AAAA,MACE;AAAA,MACA;AAAA,MACA,yBAAyB,MAAM,KAAK;AAAA,MACpC,CAAC,QAAQ,8BAA8B,MAAM,GAAG;AAAA,IAClD;AAAA,IACF,eAAe,CAAC,UAAU;AACxB,YAAM,KAAK,IAAI,gBAAgB;AAAA,QAC7B,QAAQ,OAAO,MAAM,MAAM;AAAA,QAC3B,MAAM,OAAO,MAAM,IAAI;AAAA,MACzB,CAAC;AACD,UAAI,MAAM,SAAU,IAAG,IAAI,YAAY,MAAM,QAAQ;AACrD,aAAO;AAAA,QACL;AAAA,QACA,mCAAmC,GAAG,SAAS,CAAC;AAAA,QAChD;AAAA,QACA,CAAC,QAAQ,8BAA8B,MAAM,GAAG;AAAA,MAClD;AAAA,IACF;AAAA,IACA,kBAAkB,CAAC,UAAU;AAC3B,YAAM,KAAK,IAAI,gBAAgB;AAAA,QAC7B,MAAM,OAAO,MAAM,IAAI;AAAA,QACvB,OAAO,OAAO,MAAM,KAAK;AAAA,MAC3B,CAAC;AACD,UAAI,MAAM,SAAU,IAAG,IAAI,YAAY,MAAM,QAAQ;AACrD,aAAO;AAAA,QACL;AAAA,QACA,sCAAsC,GAAG,SAAS,CAAC;AAAA,QACnD;AAAA,QACA,CAAC,QAAQ,0BAA0B,MAAM,GAAG;AAAA,MAC9C;AAAA,IACF;AAAA,IACA,cAAc,CAAC,UACb;AAAA,MACE;AAAA,MACA;AAAA,MACA,wBAAwB,MAAM,KAAK;AAAA,MACnC,CAAC,QAAQ,qBAAqB,MAAM,GAAG;AAAA,IACzC;AAAA,IACF,WAAW,CAAC,aACV;AAAA,MACE;AAAA,MACA,2BAA2B,mBAAmB,QAAQ,CAAC;AAAA,MACvD;AAAA,MACA,CAAC,QAAQ,qBAAqB,MAAM,GAAG;AAAA,IACzC;AAAA,IACF,qBAAqB,CAAC,UACpB;AAAA,MACE;AAAA,MACA;AAAA,MACA,yBAAyB,MAAM,KAAK;AAAA,MACpC,CAAC,QAAQ,0BAA0B,MAAM,GAAG;AAAA,IAC9C;AAAA,EACJ;AACF;AAEO,SAAS,+BACd,MAC0B;AAC1B,QAAM,SAAS,wBAAwB,IAAI;AAC3C,SAAO;AAAA,IACL,cAAc,OAAO;AAAA,IACrB,WAAW,OAAO;AAAA,IAClB,eAAe,OAAO;AAAA,IACtB,kBAAkB,OAAO;AAAA,IACzB,cAAc,OAAO;AAAA,IACrB,WAAW,OAAO;AAAA,IAClB,qBAAqB,OAAO;AAAA,EAC9B;AACF;AAEO,SAAS,gCACd,MAC2B;AAC3B,QAAM,SAAS,wBAAwB,IAAI;AAC3C,SAAO;AAAA,IACL,eAAe,OAAO;AAAA,IACtB,KAAK,OAAO;AAAA,EACd;AACF;;;AJ1JO,IAAM,aAAN,MAAiB;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAIjB,YAAY,MAAyB;AACnC,SAAK,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAC7C,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,kBAAkB,KAAK;AAAA,EAC9B;AAAA,EAEA,MAAM,SAAmC;AACvC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,EAAE,QAAQ,MAAM;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,UAAwC;AAC5C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,EAAE,QAAQ,MAAM;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBACJ,OACkC;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,OACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,OACA,SACiC;AACjC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAuD;AACvE,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WACJ,OACA,SAC0B;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,OACJ,OACA,SAC0B;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,UACJ,OACA,SAC0B;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,sBACJ,OACA,SAC0B;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,oBACJ,OACA,SACgC;AAChC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,oBACJ,OACA,SAC6B;AAC7B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,2BAA2B,OAKJ;AAC3B,UAAM,YAAY,MAAM,MAAM,OAAO,mBAAmB,MAAM,QAAQ;AACtE,WAAO,KAAK;AAAA,MACV;AAAA,QACE,QAAQ,MAAM;AAAA,QACd,UAAU,MAAM;AAAA,QAChB;AAAA,MACF;AAAA,MACA,EAAE,aAAa,MAAM,YAAY;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAM,2BACJ,OAC6B;AAC7B,UAAM,YAAY,MAAM,KAAK;AAAA,MAC3B;AAAA,QACE,QAAQ,MAAM;AAAA,QACd,UAAU,MAAM;AAAA,MAClB;AAAA,MACA,EAAE,aAAa,MAAM,YAAY;AAAA,IACnC;AAEA,UAAM,YAAY,MAAM,MAAM,OAAO,KAAK,UAAU,KAAK;AACzD,WAAO,KAAK;AAAA,MACV;AAAA,QACE,QAAQ,MAAM;AAAA,QACd,UAAU,MAAM;AAAA,QAChB,aAAa,UAAU;AAAA,QACvB;AAAA,MACF;AAAA,MACA,EAAE,aAAa,MAAM,YAAY;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAM,iBACJ,OACA,SACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,OACA,SAC2B;AAC3B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,UAC5C,eAAe,QAAQ;AAAA,UACvB,qBAAqB,QAAQ;AAAA,QAC/B;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,UACJ,OACA,SAC2B;AAC3B,UAAM,sBAAsB,UAAU,KAAK,MAAM,mBAAmB,IAChE,MAAM,sBACN,cAAc,MAAM,qBAAqB,MAAM,cAAc;AAEjE,UAAM,iBAAiB,MAAM,gBAAgB,KAAK;AAClD,QAAI,CAAC,gBAAgB;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,MACV;AAAA,QACE,qBAAqB;AAAA,QACrB,aAAa,mBAAmB,MAAM,MAAM,WAAW;AAAA,QACvD,UAAU,MAAM,MAAM;AAAA,QACtB,eAAe,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,QACE,aAAa,QAAQ;AAAA,QACrB,UAAU,QAAQ;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBACJ,WACA,SACoC;AACpC,WAAO,KAAK;AAAA,MACV,2BAA2B,mBAAmB,SAAS,CAAC;AAAA,MACxD;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cACJ,OACA,SACgC;AAChC,UAAM,kBACJ,MAAM,kBAAkB,QAAQ,iBAC/B,KAAK;AACR,QAAI,CAAC,gBAAgB;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,UAC5C,qBAAqB;AAAA,QACvB;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,GAAG,OAAO,eAAe;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,SACiC;AACjC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,iBACJ,SACmC;AACnC,UAAM,QAAQ,IAAI,gBAAgB;AAClC,QACE,OAAO,QAAQ,WAAW,YAC1B,QAAQ,OAAO,KAAK,EAAE,SAAS,GAC/B;AACA,YAAM,IAAI,UAAU,QAAQ,MAAM;AAAA,IACpC;AACA,QAAI,OAAO,QAAQ,UAAU,UAAU;AACrC,YAAM,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAAA,IAC1C;AAEA,UAAM,OACJ,MAAM,OAAO,IACT,wBAAwB,MAAM,SAAS,CAAC,KACxC;AACN,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBACJ,eACA,SACoC;AACpC,UAAM,YAAY,mBAAmB,aAAa;AAClD,WAAO,KAAK;AAAA,MACV,wBAAwB,SAAS;AAAA,MACjC;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBACJ,OACA,SAC0B;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cACJ,SACgC;AAChC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,OACA,SACiC;AACjC,UAAM,eAAe,mBAAmB,KAAK;AAC7C,WAAO,KAAK;AAAA,MACV,qBAAqB,YAAY;AAAA,MACjC;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,QAAQ,WAAW;AAAA,QAC9C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,YACZ,MACAC,OACA,eACA,gBACA,OACkB;AAClB,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,IAAI,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,SAAS;AAC7D,QAAI,OAAOA,MAAK;AAChB,QAAI;AACF,aAAO,gBACH,KAAK,UAAU,cAAc,MAAM,KAAK,CAAC,IACzCA,MAAK;AAAA,IACX,SAAS,KAAc;AACrB,UAAI,eAAeC,GAAE,UAAU;AAC7B,cAAM,IAAI,UAAU,2BAA2B,mBAAmB;AAAA,UAChE,SAAS,IAAI,QAAQ;AAAA,QACvB,CAAC;AAAA,MACH;AACA,YAAM;AAAA,IACR;AAEA,QAAI;AACF,UAAI,eAAuC,CAAC;AAC5C,UAAI,KAAK,iBAAiB;AACxB,uBAAe,MAAM,KAAK,gBAAgB;AAAA,MAC5C;AAEA,YAAM,eAAe;AAAA,QACnB,GAAGD,MAAK;AAAA,QACR,GAAG;AAAA,MACL;AAEA,YAAM,MAAM,MAAM,KAAK,UAAU,KAAK;AAAA,QACpC,GAAGA;AAAA,QACH,SAAS;AAAA,QACT;AAAA,QACA,QAAQ,WAAW;AAAA,MACrB,CAAC;AACD,UAAI,CAAC,IAAI,GAAI,OAAM,MAAM,eAAe,GAAG;AAC3C,YAAM,UAAW,MAAM,IAAI,KAAK;AAChC,UAAI,CAAC,eAAgB,QAAO;AAC5B,UAAI;AACF,eAAO,eAAe,MAAM,OAAO;AAAA,MACrC,SAAS,KAAc;AACrB,YAAI,eAAeC,GAAE,UAAU;AAC7B,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,YACA;AAAA,cACE,SAAS,IAAI,QAAQ;AAAA,YACvB;AAAA,UACF;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF,SAAS,KAAc;AACrB,UAAI,eAAe,SAAS,IAAI,SAAS,cAAc;AACrD,cAAM,IAAI,UAAU,qBAAqB,SAAS;AAAA,MACpD;AACA,UAAI,eAAe,UAAW,OAAM;AACpC,YAAM,IAAI,UAAU,iBAAiB,iBAAiB;AAAA,QACpD,SAAS,OAAO,GAAG;AAAA,MACrB,CAAC;AAAA,IACH,UAAE;AACA,mBAAa,CAAC;AAAA,IAChB;AAAA,EACF;AACF;;;AKv2BO,IAAM,QAAQ;AAAA,EACnB,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA;AAAA,EAErB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,8BAA8B;AAAA,EAC9B,6BAA6B;AAAA,EAC7B,+BAA+B;AAAA,EAC/B,cAAc;AAAA,EACd,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,uBAAuB;AAAA,EACvB,KAAK;AAAA,EACL,wBAAwB;AAAA;AAE1B;AAEO,IAAM,2BAA2B;AAAA,EACtC,aAAa;AAAA,EACb,eAAe;AAAA,EACf,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,wBAAwB;AAC1B;AAEO,IAAM,sBAAsB;AAAA,EACjC,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,IAAM,iCAAiC;AACvC,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,iBAAiB;;;ACvCvB,SAAS,WAAW,OAA2B;AACpD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,WAAO,MAAM,CAAC,KAAK;AACnB,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,MAAM,OAAQ;AAChB,cAAO,OAAO,IAAK;AAAA,MACrB,OAAO;AACL,gBAAQ;AAAA,MACV;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,OAA2B;AACvD,SAAO,WAAW,KAAK,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG;AACrE;;;ACbO,SAAS,SAAS,KAAa,OAAuB;AAC3D,MAAI,CAAC,UAAU,KAAK,GAAG,GAAG;AACxB,UAAM,IAAI,MAAM,mCAAmC,GAAG,GAAG;AAAA,EAC3D;AACA,MAAI,MAAM,SAAS,IAAI;AACrB,UAAM,IAAI;AAAA,MACR,sBAAsB,GAAG,sBAAsB,MAAM,MAAM;AAAA,IAC7D;AAAA,EACF;AACA,QAAM,MAAM,MAAM,OAAO,SAAS,EAAE,SAAS,GAAG,GAAG;AACnD,SAAO,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK;AAC7B;AAEO,SAAS,QAAQ,KAAyB;AAC/C,QAAM,MAAkB,CAAC;AACzB,MAAI,IAAI;AACR,SAAO,IAAI,IAAI,QAAQ;AACrB,QAAI,IAAI,IAAI,IAAI,QAAQ;AACtB,YAAM,IAAI,MAAM,mCAAmC,CAAC,EAAE;AAAA,IACxD;AACA,UAAM,MAAM,IAAI,MAAM,GAAG,IAAI,CAAC;AAC9B,UAAM,SAAS,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC;AACrC,QAAI,CAAC,UAAU,KAAK,GAAG,GAAG;AACxB,YAAM,IAAI,MAAM,iBAAiB,GAAG,eAAe,CAAC,EAAE;AAAA,IACxD;AACA,QAAI,CAAC,UAAU,KAAK,MAAM,GAAG;AAC3B,YAAM,IAAI,MAAM,oBAAoB,MAAM,eAAe,IAAI,CAAC,EAAE;AAAA,IAClE;AACA,UAAM,MAAM,SAAS,QAAQ,EAAE;AAC/B,UAAM,WAAW,IAAI;AACrB,UAAM,SAAS,WAAW;AAC1B,QAAI,SAAS,IAAI,QAAQ;AACvB,YAAM,IAAI;AAAA,QACR,gCAAgC,GAAG,cAAc,QAAQ;AAAA,MAC3D;AAAA,IACF;AACA,QAAI,KAAK,EAAE,KAAK,OAAO,IAAI,MAAM,UAAU,MAAM,EAAE,CAAC;AACpD,QAAI;AAAA,EACN;AACA,SAAO;AACT;;;AChCA,IAAM,kBAAkB;AAGxB,SAAS,cAAc,KAAkC;AACvD,MAAI,CAAC,4BAA4B,KAAK,IAAI,GAAG,GAAG;AAC9C,UAAM,IAAI;AAAA,MACR,8DAA8D,IAAI,GAAG;AAAA,IACvE;AAAA,EACF;AACA,MAAI,MAAM;AACV,aAAW,KAAK,IAAI,UAAU;AAC5B,WAAO,SAAS,EAAE,KAAK,EAAE,KAAK;AAAA,EAChC;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,IAA4B;AAC5D,MAAI,MAAM;AACV,QAAM,MAA6C;AAAA,IACjD,CAAC,cAAc,yBAAyB,WAAW;AAAA,IACnD,CAAC,gBAAgB,yBAAyB,aAAa;AAAA,IACvD,CAAC,cAAc,yBAAyB,WAAW;AAAA,IACnD,CAAC,iBAAiB,yBAAyB,cAAc;AAAA,IACzD,CAAC,kBAAkB,yBAAyB,eAAe;AAAA,IAC3D,CAAC,iBAAiB,yBAAyB,cAAc;AAAA,IACzD,CAAC,iBAAiB,yBAAyB,cAAc;AAAA,IACzD,CAAC,wBAAwB,yBAAyB,sBAAsB;AAAA,EAC1E;AACA,aAAW,CAAC,GAAG,CAAC,KAAK,KAAK;AACxB,UAAM,IAAI,GAAG,CAAC;AACd,QAAI,MAAM,QAAW;AACnB,aAAO,SAAS,GAAG,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAc,GAAiB;AAClD,MAAI,CAAC,gBAAgB,KAAK,CAAC,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR,cAAc,IAAI;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAAc,GAAW,KAAmB;AAChE,MAAI,EAAE,SAAS,KAAK;AAClB,UAAM,IAAI,MAAM,cAAc,IAAI,WAAW,EAAE,MAAM,gBAAgB,GAAG,EAAE;AAAA,EAC5E;AACF;AAEA,SAAS,UAAU,KAAmB;AACpC,MAAI,CAAC,UAAU,KAAK,GAAG,GAAG;AACxB,UAAM,IAAI;AAAA,MACR,0DAA0D,GAAG;AAAA,IAC/D;AAAA,EACF;AACF;AAEA,SAAS,aAAa,KAAmB;AAEvC,MAAI,CAAC,yBAAyB,KAAK,GAAG,GAAG;AACvC,UAAM,IAAI;AAAA,MACR,6EAA6E,GAAG;AAAA,IAClF;AAAA,EACF;AACA,MAAI,IAAI,SAAS,IAAI;AACnB,UAAM,IAAI;AAAA,MACR,uCAAuC,IAAI,MAAM;AAAA,IACnD;AAAA,EACF;AACF;AAEO,SAAS,UAAU,OAAgC;AACxD,YAAU,MAAM,oBAAoB;AACpC,cAAY,gBAAgB,MAAM,YAAY;AAC9C,eAAa,gBAAgB,MAAM,cAAc,EAAE;AACnD,cAAY,gBAAgB,MAAM,YAAY;AAC9C,eAAa,gBAAgB,MAAM,cAAc,EAAE;AACnD,MAAI,MAAM,eAAe,QAAW;AAClC,gBAAY,cAAc,MAAM,UAAU;AAC1C,iBAAa,cAAc,MAAM,YAAY,EAAE;AAAA,EACjD;AACA,MAAI,MAAM,sBAAsB,QAAW;AACzC,iBAAa,MAAM,iBAAiB;AAAA,EACtC;AACA,MACE,MAAM,sBAAsB,aAC5B,MAAM,sBAAsB,QAC5B;AAAA,EAGF;AAEA,MAAI,MAAM;AACV,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,sBAAsB,YACxB,oBAAoB,UACpB,oBAAoB;AAAA,EAC1B;AACA,SAAO;AAAA,IACL,MAAM,oBAAoB;AAAA,IAC1B,cAAc,MAAM,mBAAmB;AAAA,EACzC;AACA,SAAO,SAAS,MAAM,wBAAwB,MAAM,oBAAoB;AACxE,SAAO,SAAS,MAAM,sBAAsB,iBAAiB;AAC7D,MAAI,MAAM,sBAAsB,QAAW;AACzC,WAAO,SAAS,MAAM,oBAAoB,MAAM,iBAAiB;AAAA,EACnE;AACA,SAAO,SAAS,MAAM,cAAc,eAAe;AACnD,SAAO,SAAS,MAAM,eAAe,MAAM,YAAY;AACvD,SAAO,SAAS,MAAM,eAAe,MAAM,YAAY;AACvD,MAAI,MAAM,eAAe,QAAW;AAClC,WAAO,SAAS,MAAM,aAAa,MAAM,UAAU;AAAA,EACrD;AACA,MAAI,MAAM,gBAAgB;AACxB,UAAM,WAAW,yBAAyB,MAAM,cAAc;AAC9D,QAAI,SAAS,SAAS,GAAG;AACvB,aAAO,SAAS,MAAM,uBAAuB,QAAQ;AAAA,IACvD;AAAA,EACF;AAGA,SAAO;AACP,QAAM,MAAM,cAAc,IAAI,YAAY,EAAE,OAAO,GAAG,CAAC;AACvD,SAAO;AACP,SAAO;AACT;;;ACvIO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAC9B;AAAA,EACT,YAAY,SAAiB,OAAO,IAAI;AACtC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,SAAS,SAA4B;AACnD,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,IAAI,cAAc,sBAAsB,QAAQ,MAAM,SAAS;AAAA,EACvE;AAEA,QAAM,eAAe,QAAQ,MAAM,IAAI,EAAE;AACzC,QAAM,WAAW,QAAQ,MAAM,EAAE;AACjC,MAAI,iBAAiB,gBAAgB;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,YAAY,QAAQ,MAAM,GAAG,EAAE;AACrC,QAAM,cAAc,cAAc,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AACrE,MAAI,gBAAgB,SAAS,YAAY,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR,8BAA8B,QAAQ,cAAc,WAAW;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,QAAM,MAAM,QAAQ,MAAM;AAE1B,QAAM,MAAM,CAAC,QACX,IAAI,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG,GAAG;AAElC,QAAM,MAAM,IAAI,MAAM,wBAAwB;AAC9C,MAAI,QAAQ;AACV,UAAM,IAAI;AAAA,MACR,6CAA6C,GAAG;AAAA,MAChD;AAAA,IACF;AAEF,QAAM,SAAS,IAAI,MAAM,mBAAmB;AAC5C,QAAM,oBACJ,WAAW,OAAO,WAAW,WAAW,OAAO,YAAY;AAE7D,QAAM,WAAW,IAAI,MAAM,oBAAoB;AAC/C,MAAI,aAAa,mBAAmB;AAClC,UAAM,IAAI;AAAA,MACR,yBAAyB,QAAQ,eAAe,iBAAiB;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,IAAI,MAAM,YAAY;AACtC,MAAI,YAAY,iBAAiB;AAC/B,UAAM,IAAI;AAAA,MACR,wBAAwB,OAAO,eAAe,eAAe;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,MAAM,sBAAsB;AAC5C,MAAI,CAAC,IAAK,OAAM,IAAI,cAAc,gCAAgC,IAAI;AACtE,QAAM,eAAe,IAAI,MAAM,aAAa,KAAK;AACjD,QAAM,eAAe,IAAI,MAAM,aAAa,KAAK;AACjD,QAAM,oBAAoB,IAAI,MAAM,kBAAkB;AACtD,QAAM,aAAa,IAAI,MAAM,WAAW;AAGxC,QAAM,OAA8B,CAAC;AACrC,aAAW,KAAK,KAAK;AACnB,UAAM,IAAI,SAAS,EAAE,KAAK,EAAE;AAC5B,QAAI,KAAK,KAAK,KAAK,IAAI;AACrB,YAAM,WAAW,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO;AAAA,QAC5C,KAAK,EAAE;AAAA,QACP,OAAO,EAAE;AAAA,MACX,EAAE;AACF,WAAK,KAAK,EAAE,KAAK,EAAE,KAAK,SAAS,CAAC;AAAA,IACpC;AAAA,EACF;AAGA,MAAI;AACJ,QAAM,SAAS,IAAI,MAAM,qBAAqB;AAC9C,MAAI,WAAW,QAAW;AACxB,qBAAiB,CAAC;AAClB,eAAW,KAAK,QAAQ,MAAM,GAAG;AAC/B,cAAQ,EAAE,KAAK;AAAA,QACb,KAAK;AACH,yBAAe,aAAa,EAAE;AAC9B;AAAA,QACF,KAAK;AACH,yBAAe,eAAe,EAAE;AAChC;AAAA,QACF,KAAK;AACH,yBAAe,aAAa,EAAE;AAC9B;AAAA,QACF,KAAK;AACH,yBAAe,gBAAgB,EAAE;AACjC;AAAA,QACF,KAAK;AACH,yBAAe,iBAAiB,EAAE;AAClC;AAAA,QACF,KAAK;AACH,yBAAe,gBAAgB,EAAE;AACjC;AAAA,QACF,KAAK;AACH,yBAAe,gBAAgB,EAAE;AACjC;AAAA,QACF,KAAK;AACH,yBAAe,uBAAuB,EAAE;AACxC;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,wBAAwB;AAAA,IACxB;AAAA,IACA,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,gBAAgB,gBAAgB,WAAW,KAAK,IAC3D,eAAe,iBACf;AAAA,IACJ,KAAK;AAAA,EACP;AACF;;;AC9IO,SAAS,YAAY,QAAgC;AAC1D,MAAI,OAAO,iBAAiB,OAAO,cAAc,WAAW,KAAK,GAAG;AAClE,WAAO;AAAA,EACT;AACA,MAAI,OAAO,oBAAoB,SAAS,EAAG,QAAO;AAClD,SAAO;AACT;;;ACLO,SAAS,uBAAuB,OAAwB;AAC7D,SAAO,UAAU,KAAK;AACxB;AAEO,SAAS,mBAAmB,OAA4B;AAC7D,SAAO,IAAI,YAAY,EAAE,OAAO,uBAAuB,KAAK,CAAC;AAC/D;AAEA,SAAS,UAAU,GAAoB;AACrC,MAAI,MAAM,KAAM,QAAO;AACvB,QAAM,IAAI,OAAO;AACjB,MAAI,MAAM,SAAU,QAAO,KAAK,UAAU,CAAC;AAC3C,MAAI,MAAM,UAAW,QAAO,IAAI,SAAS;AACzC,MAAI,MAAM,UAAU;AAClB,QAAI,CAAC,OAAO,SAAS,CAAW,GAAG;AACjC,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AACA,MACE,MAAM,YACN,MAAM,cACN,MAAM,YACN,MAAM,aACN;AACA,UAAM,IAAI,MAAM,yCAAyC,CAAC,EAAE;AAAA,EAC9D;AACA,MAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,EAAG,OAAM,KAAK,UAAU,IAAI,CAAC;AAChD,WAAO,MAAM,MAAM,KAAK,GAAG,IAAI;AAAA,EACjC;AACA,MAAI,MAAM,UAAU;AAClB,UAAM,MAAM;AACZ,UAAM,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK;AACnC,UAAM,QAAkB,CAAC;AACzB,eAAW,KAAK,MAAM;AACpB,YAAM,MAAM,IAAI,CAAC;AACjB,UAAI,QAAQ,QAAW;AACrB,cAAM,IAAI,MAAM,0CAA0C,CAAC,GAAG;AAAA,MAChE;AACA,YAAM,KAAK,KAAK,UAAU,CAAC,IAAI,MAAM,UAAU,GAAG,CAAC;AAAA,IACrD;AACA,WAAO,MAAM,MAAM,KAAK,GAAG,IAAI;AAAA,EACjC;AACA,QAAM,IAAI,MAAM,yCAAyC,CAAC,EAAE;AAC9D;;;AClDO,SAAS,kBAAkB,GAAe,GAAwB;AACvE,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,SAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;AACrD,SAAO,SAAS;AAClB;;;ACGA,SAAS,KAAAC,UAAS;;;ACElB,SAAS,YAAY;AAIrB,SAAS,cAAc,OAA2B;AAChD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAAA,EAC7C;AACA,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,QAAO,OAAO,aAAa,MAAM,CAAC,CAAE;AAE3E,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,cAAc,KAAyB;AAC9C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,IAAI,WAAW,OAAO,KAAK,KAAK,QAAQ,CAAC;AAAA,EAClD;AAEA,QAAM,MAAM,KAAK,GAAG;AACpB,QAAM,MAAM,IAAI,WAAW,IAAI,MAAM;AACrC,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,KAAI,CAAC,IAAI,IAAI,WAAW,CAAC;AAC9D,SAAO;AACT;AAQA,IAAM,mBAAmB,IAAI,WAAW;AAAA,EACtC;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACxE;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAC1E,CAAC;AAEM,SAAS,iBAAiB,SAA6B;AAC5D,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,KAAK,WAAW,iBAAiB,SAAS,IAAI;AAChD,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,WAAS,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;AAChD,QAAI,KAAK,CAAC,MAAM,iBAAiB,CAAC,GAAG;AACnC,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,EACF;AACA,SAAO,KAAK,MAAM,iBAAiB,MAAM;AAC3C;AAkBO,SAAS,eACd,OACA,kBACQ;AACR,QAAM,MAAM,KAAK,KAAK,OAAO,kBAAkB,EAAE,SAAS,KAAK,CAAC;AAChE,SAAO,cAAc,IAAI,QAAQ,KAAK,CAAC;AACzC;AAMO,SAAS,iBACd,OACA,cACA,wBACS;AACT,MAAI;AACF,UAAM,SAAS,iBAAiB,sBAAsB;AACtD,UAAM,WAAW,cAAc,YAAY;AAC3C,WAAO,KAAK,OAAO,UAAU,OAAO,QAAQ;AAAA,MAC1C,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AD1FO,IAAM,0BAA0B;AAChC,IAAM,8BAA8B;AACpC,IAAM,0BAA0B,KAAK,KAAK,KAAK;AAGtD,IAAM,YAAYC,GACf,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,0BAA0B,mCAAmC;AAE/D,IAAM,YAAYA,GACtB,OAAO;AAAA,EACN,QAAQA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE1B,iBAAiB;AAAA,EACjB,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,mBAAmBA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAChD,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACxC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,WAAW;AACb,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa;AAAA,EAC7C,SAAS;AACX,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,mBAAmB;AAAA,EACpD,SAAS;AACX,CAAC;AAKI,SAAS,SAAS,OAWT;AACd,SAAO;AAAA,IACL,QAAQ,MAAM;AAAA,IACd,UAAU,MAAM;AAAA,IAChB,iBAAiB,MAAM;AAAA,IACvB,cAAc,MAAM,gBAAgB;AAAA,IACpC,mBAAmB,MAAM,qBAAqB;AAAA,IAC9C,aAAa,MAAM;AAAA,IACnB,cAAc,MAAM;AAAA,IACpB,aAAa,MAAM,eAAe;AAAA,IAClC,OAAO,MAAM;AAAA,EACf;AACF;AAEO,SAAS,QACd,UACA,kBACK;AACL,QAAM,YAAY;AAAA,IAChB,mBAAmB,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,GAAG,UAAU,UAAU;AAClC;AAEO,SAAS,UAAU,KAAU,wBAAyC;AAC3E,MAAI;AACF,UAAM,SAAS,UAAU,MAAM,GAAG;AAClC,UAAM,EAAE,WAAW,GAAG,SAAS,IAAI;AACnC,WAAO;AAAA,MACL,mBAAmB,QAAQ;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AEpGA,IAAM,WAAW;AACjB,IAAM,UAAkC,CAAC;AACzC,SAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAK,SAAQ,SAAS,CAAC,CAAC,IAAI;AAE1D,SAAS,aAAa,OAA2B;AACtD,MAAI,MAAM;AACV,MAAI,IAAI;AACR,SAAO,IAAI,IAAI,MAAM,QAAQ,KAAK,GAAG;AACnC,UAAM,IAAK,MAAM,CAAC,KAAK,IAAK,MAAM,IAAI,CAAC;AACvC,UAAM,IAAI,KAAK,MAAM,KAAK,KAAK,GAAG;AAClC,UAAM,IAAI,KAAK,MAAO,KAAK,KAAK,MAAO,EAAE;AACzC,UAAM,IAAI,IAAI;AACd,WAAO,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,SAAS,CAAC;AAAA,EAC/C;AACA,MAAI,IAAI,MAAM,QAAQ;AACpB,UAAM,IAAI,MAAM,CAAC;AACjB,UAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,UAAM,IAAI,IAAI;AACd,WAAO,SAAS,CAAC,IAAI,SAAS,CAAC;AAAA,EACjC;AACA,SAAO;AACT;AAEO,SAAS,aAAa,GAAuB;AAClD,MAAI,EAAE,WAAW,EAAG,QAAO,IAAI,WAAW,CAAC;AAC3C,QAAM,aAAa,KAAK,MAAM,EAAE,SAAS,CAAC;AAC1C,QAAM,OAAO,EAAE,SAAS,aAAa;AACrC,MAAI,SAAS,EAAG,OAAM,IAAI,MAAM,wBAAwB;AACxD,QAAM,MAAM,IAAI,WAAW,aAAa,KAAK,SAAS,IAAI,IAAI,EAAE;AAChE,MAAI,KAAK;AACT,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,UAAM,IAAI,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC1B,UAAM,IAAI,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC;AAC9B,UAAM,IAAI,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC;AAC9B,QAAI,MAAM,UAAa,MAAM,UAAa,MAAM,QAAW;AACzD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AACA,UAAM,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;AACjC,QAAI,IAAI,MAAQ,OAAM,IAAI,MAAM,wBAAwB;AACxD,QAAI,IAAI,IAAK,KAAK,IAAK;AACvB,QAAI,IAAI,IAAI,IAAI;AAAA,EAClB;AACA,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,QAAQ,EAAE,aAAa,CAAC,CAAC;AACnC,UAAM,IAAI,QAAQ,EAAE,aAAa,IAAI,CAAC,CAAC;AACvC,QAAI,MAAM,UAAa,MAAM;AAC3B,YAAM,IAAI,MAAM,2BAA2B;AAC7C,UAAM,IAAI,IAAI,KAAK;AACnB,QAAI,IAAI,IAAM,OAAM,IAAI,MAAM,uBAAuB;AACrD,QAAI,IAAI,IAAI,IAAI;AAAA,EAClB;AACA,SAAO;AACT;;;ACxCA,SAAS,KAAAC,UAAS;AAMlB,IAAM,YAAYC,GACf,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,0BAA0B,sCAAsC;AAElE,IAAM,8BAA8BA,GAAE,OAAO;AAAA,EAClD,WAAWA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,aAAa;AAAA,EACb,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACvC,aAAa;AACf,CAAC;AAOM,IAAM,oCAAoCA,GAAE,OAAO;AAAA,EACxD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACxC,UAAU;AACZ,CAAC;AASM,SAAS,oBAAoB,OAKF;AAChC,MAAI,CAAC,OAAO,UAAU,MAAM,UAAU,KAAK,MAAM,cAAc,GAAG;AAChE,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,MAAI,MAAM,aAAa,MAAM,YAAY,cAAc;AACrD,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,EACrB;AACF;AAEO,SAAS,mBACd,UACA,0BACuB;AACvB,QAAM,cAAc;AAAA,IAClB,mBAAmB,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,GAAG,UAAU,YAAY;AACpC;AAEO,SAAS,qBACd,KACA,wBACS;AACT,MAAI;AACF,UAAM,SAAS,4BAA4B,MAAM,GAAG;AAEpD,UAAM,EAAE,WAAW,gBAAgB,GAAG,oBAAoB,IACxD,OAAO;AACT,QACE,CAAC;AAAA,MACC,mBAAmB,mBAAmB;AAAA,MACtC;AAAA,MACA;AAAA,IACF,GACA;AACA,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,aAAa,GAAG,SAAS,IAAI;AACrC,WAAO;AAAA,MACL,mBAAmB,QAAQ;AAAA,MAC3B;AAAA,MACA,OAAO,YAAY;AAAA,IACrB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,OAIK;AACtC,MAAI,CAAC,OAAO,UAAU,MAAM,YAAY,KAAK,MAAM,gBAAgB,GAAG;AACpE,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AACA,MAAI,MAAM,QAAQ,aAAa,MAAM,SAAS,cAAc;AAC1D,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,UAAU,MAAM;AAAA,IAChB,cAAc,MAAM;AAAA,EACtB;AACF;AAEO,SAAS,kBACd,UACA,uBAC6B;AAC7B,QAAM,WAAW;AAAA,IACf,mBAAmB,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,GAAG,UAAU,SAAS;AACjC;AAEO,SAAS,oBACd,MACA,wBACS;AACT,MAAI;AACF,UAAM,SAAS,kCAAkC,MAAM,IAAI;AAC3D,QAAI,CAAC,qBAAqB,OAAO,SAAS,sBAAsB;AAC9D,aAAO;AAET,UAAM,EAAE,WAAW,aAAa,GAAG,iBAAiB,IAAI,OAAO;AAC/D,QACE,CAAC;AAAA,MACC,mBAAmB,gBAAgB;AAAA,MACnC;AAAA,MACA;AAAA,IACF,GACA;AACA,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,UAAU,GAAG,SAAS,IAAI;AAClC,WAAO;AAAA,MACL,mBAAmB,QAAQ;AAAA,MAC3B;AAAA,MACA,OAAO,SAAS;AAAA,IAClB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,uBAAuB,KAAoC;AACzE,QAAM,OAAO,KAAK,UAAU,GAAG;AAC/B,SAAO,WAAW,aAAa,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC;AAC/D;AAEO,SAAS,uBAAuB,GAAkC;AACvE,MAAI,CAAC,EAAE,WAAW,QAAQ;AACxB,UAAM,IAAI,MAAM,uCAAuC;AACzD,QAAM,QAAQ,aAAa,EAAE,MAAM,SAAS,MAAM,CAAC;AACnD,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAC3C,SAAO,4BAA4B,MAAM,KAAK,MAAM,IAAI,CAAC;AAC3D;AAEO,SAAS,sBACd,MACQ;AACR,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,SAAO,WAAW,aAAa,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC;AAC/D;AAEO,SAAS,sBAAsB,GAAwC;AAC5E,MAAI,CAAC,EAAE,WAAW,QAAQ;AACxB,UAAM,IAAI,MAAM,qCAAqC;AACvD,QAAM,QAAQ,aAAa,EAAE,MAAM,SAAS,MAAM,CAAC;AACnD,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAC3C,SAAO,kCAAkC,MAAM,KAAK,MAAM,IAAI,CAAC;AACjE;;;AChMA,SAAS,KAAAC,UAAS;AAwFlB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AApFpB,IAAM,qBAAqBA,GAAE,OAAO;AAAA,EACzC,SAASA,GAAE,OAAO,EAAE,KAAK;AAAA,EACzB,aAAaA,GAAE,OAAO;AAAA,EACtB,iBAAiBA,GAAE,OAAO,EAAE,KAAK;AAAA,EACjC,aAAaA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACzC,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACzC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,WAAWA,GAAE,OAAO;AACtB,CAAC;AAGM,IAAM,qBAAqBA,GAAE,OAAO;AAAA,EACzC,aAAaA,GACV,OAAO,EACP,MAAM,iBAAiB,EACvB,SAAS;AAAA,EACZ,aAAaA,GAAE,OAAO;AAAA,EACtB,aAAaA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,aAAaA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,YAAYA,GAAE,OAAO;AAAA,EACrB,YAAYA,GAAE,OAAO;AAAA,EACrB,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK;AAAA,EAC5C,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACvD,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/B,aAAaA,GACV,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB;AAAA,EACjC,gBAAgBA,GACb,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB;AAAA,EACjC,aAAaA,GACV,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB,EAC9B,SAAS;AAAA,EACZ,gBAAgBA,GACb,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB,EAC9B,SAAS;AACd,CAAC;AAGM,IAAM,mBAAmBA,GAAE,OAAO;AAAA,EACvC,cAAcA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC9B,eAAeA,GAAE,OAAO,EAAE,MAAM,iBAAiB;AAAA,EACjD,aAAaA,GAAE,OAAO,EAAE,MAAM,iBAAiB;AAAA,EAC/C,iBAAiBA,GAAE,OAAO,EAAE,KAAK;AAAA,EACjC,aAAaA,GAAE,OAAO;AAAA,EACtB,aAAaA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,aAAaA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACzC,UAAUA,GAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQA,GAAE,KAAK,CAAC,WAAW,UAAU,UAAU,CAAC;AAAA,EAChD,WAAWA,GAAE,OAAO;AAAA,EACpB,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EAC3C,YAAY;AAAA,EACZ,aAAaA,GAAE,OAAO,EAAE,MAAM,iBAAiB;AAAA,EAC/C,UAAUA,GAAE,QAAQ;AACtB,CAAC;AAQD,IAAM,mBAAmB;AAGzB,eAAe,UAAU,OAAgC;AACvD,SAAO,WAAW,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,CAAC,CAAC;AAC3D;AAMA,eAAsB,mBAAmB,OAMrB;AAClB,SAAO;AAAA,IACL,mBACE,MACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACR,EAAE,KAAK,GAAG;AAAA,EACd;AACF;AA0BO,SAAS,+BACd,SAC8B;AAC9B,SAAO;AAAA,IACL,mBAAmB,CAAC,UAClB,QAAQ,QAAsB;AAAA,MAC5B,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,aAAa,MAAM;AAAA,QACnB,eAAe,MAAM;AAAA,QACrB,UAAU,MAAM,YAAY;AAAA,QAC5B,OAAO,MAAM;AAAA,QACb,GAAI,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,MAChE;AAAA,IACF,CAAC;AAAA,IACH,iBAAiB,CAAC,WAChB,QAAQ,QAAsB;AAAA,MAC5B,QAAQ;AAAA,MACR,MAAM,sBAAsB,mBAAmB,MAAM,CAAC;AAAA,IACxD,CAAC;AAAA,IACH,QAAQ,CAAC,UACP,QAAQ,QAAwB;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAAA,IACH,eAAe,CAAC,OACd,QAAQ,QAAoB;AAAA,MAC1B,QAAQ;AAAA,MACR,MAAM,2BAA2B,mBAAmB,EAAE,CAAC;AAAA,IACzD,CAAC;AAAA,IACH,eAAe,MACb,QAAQ,QAA8B;AAAA,MACpC,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AAAA,EACL;AACF;;;AC/LA,SAAS,YAAY;AACrB,SAAS,UAAAC,eAAc;AAEvB,SAASC,YAAW,GAAuB;AACzC,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,MAAK,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACzE,SAAO;AACT;AAEA,SAAS,wBAAwB,GAAW,GAAoB;AAC9D,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,SAAQ,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;AAC3E,SAAO,SAAS;AAClB;AAEO,SAAS,cAAc,MAAsB;AAClD,SAAOA,YAAWD,QAAO,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC,CAAC;AAC1D;AAEO,SAAS,uBAAuB,OAM5B;AACT,SAAO;AAAA,IACL,MAAM,OAAO,YAAY;AAAA,IACzB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,cAAc,MAAM,IAAI;AAAA,EAC1B,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,gBAAgB,OAOrB;AACT,SAAOC;AAAA,IACL,KAAKD,SAAQ,MAAM,WAAW,uBAAuB,KAAK,CAAC;AAAA,EAC7D;AACF;AAEO,SAAS,kBAAkB,OAQtB;AACV,QAAM,WAAW,gBAAgB,KAAK;AACtC,SAAO,wBAAwB,UAAU,MAAM,UAAU,YAAY,CAAC;AACxE;;;AC5DA,SAAS,KAAAE,UAAS;AAClB,SAAS,UAAAC,eAAc;AACvB,SAAS,QAAAC,aAAY;AACrB,SAAS,cAAAC,mBAAkB;AAGpB,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,4BAA4BC,GAAE,OAAO;AAAA,EAChD,IAAIA,GAAE,OAAO,EAAE,KAAK;AAAA,EACpB,WAAWA,GAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,OAAOA,GAAE,OAAO;AAAA,EAChB,QAAQA,GAAE,MAAMA,GAAE,KAAK,cAAc,CAAC;AAAA,EACtC,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACtD,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACvD,CAAC;AAGM,IAAM,4BAA4B,0BAA0B,OAAO;AAAA,EACxE,QAAQA,GAAE,OAAO,EAAE,IAAI,CAAC;AAC1B,CAAC;AAoBD,IAAM,MAAM,IAAI,YAAY;AAE5B,eAAeC,WAAU,OAA6C;AACpE,QAAM,OAAO,OAAO,UAAU,WAAW,IAAI,OAAO,KAAK,IAAI;AAC7D,SAAOC,YAAWC,QAAO,IAAI,CAAC;AAChC;AAEA,eAAe,cAAc,QAAgB,SAAkC;AAI7E,SAAOD,YAAWE,MAAKD,SAAQ,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,OAAO,CAAC,CAAC;AACzE;AAGA,SAAS,eAAuB;AAC9B,QAAM,IACJ,WAMA;AACF,MAAI,OAAO,GAAG,eAAe,WAAY,QAAO,EAAE,WAAW;AAC7D,MAAI,OAAO,GAAG,oBAAoB,YAAY;AAC5C,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,QAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,IAAE,gBAAgB,GAAG;AACrB,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,SAAK,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,EAC1C;AACA,SAAO;AACT;AAKA,SAAS,UAAU,QAMR;AACT,SAAO;AAAA,IACL,OAAO,OAAO,YAAY;AAAA,IAC1B,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT,EAAE,KAAK,IAAI;AACb;AASA,eAAsB,mBAAmB,QAQV;AAC7B,QAAM,KAAK,OAAO,KAAK,OAAO,OAAO,SAAS,KAAK,IAAI,KAAK,GAAI,CAAC;AACjE,QAAM,QAAQ,OAAO,SAAS,aAAa;AAC3C,QAAM,WACJ,OAAO,OAAO,SAAS,WACnB,IAAI,OAAO,OAAO,IAAI,IACrB,OAAO,QAAQ,IAAI,WAAW;AACrC,QAAM,WAAW,MAAMF,WAAU,QAAQ;AACzC,QAAM,UAAU,UAAU;AAAA,IACxB,QAAQ,OAAO;AAAA,IACf,MAAM,OAAO;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,aAAa,MAAMA,WAAU,OAAO,MAAM;AAChD,QAAM,MAAM,MAAM,cAAc,YAAY,OAAO;AACnD,SAAO;AAAA,IACL,eAAe,iBAAiB,OAAO,KAAK,QAAQ,EAAE,WAAW,KAAK,SAAS,GAAG;AAAA,IAClF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAaO,SAAS,wBACd,MACmB;AACnB,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAC9C,QAAM,cAAc,qBAAqB,KAAK,KAAK;AAEnD,iBAAe,eACb,QACA,MACA,MACsB;AACtB,UAAM,MAAM,MAAM,mBAAmB;AAAA,MACnC,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,OAAO,KAAK,QAAQ;AAAA,MACpB,OAAO,KAAK,QAAQ;AAAA,IACtB,CAAC;AACD,UAAM,UAAkC;AAAA,MACtC,eAAe,IAAI;AAAA,MACnB,QAAQ;AAAA,IACV;AACA,QAAI,YAAa,SAAQ,cAAc,IAAI;AAC3C,QAAI,SAAS,OAAW,SAAQ,cAAc,IAAI;AAClD,UAAMI,QAAoB,EAAE,QAAQ,QAAQ;AAC5C,QAAI,SAAS,OAAW,CAAAA,MAAK,OAAO;AACpC,WAAOA;AAAA,EACT;AAEA,iBAAe,QAAW,OAIX;AACb,UAAM,UACJ,MAAM,SAAS,SAAY,SAAY,KAAK,UAAU,MAAM,IAAI;AAClE,UAAMA,QAAO,MAAM,eAAe,MAAM,QAAQ,MAAM,MAAM,OAAO;AACnE,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,IAAI,IAAIA,KAAI;AAC5D,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACJ,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAA0B,OAAO,OAAOA,UAAS;AACrD,UAAM,MAAM,OAAO,UAAU,WAAW,QAAS,MAAc,SAAS;AACxE,UAAM,IAAI,IAAI,IAAI,KAAK,OAAO;AAC9B,UAAM,OAAO,GAAG,EAAE,QAAQ,GAAG,EAAE,MAAM;AACrC,UAAM,UAAUA,OAAM,UAAU,OAAO,YAAY;AACnD,QAAI;AACJ,QAAIA,OAAM,MAAM;AACd,gBACE,OAAOA,MAAK,SAAS,WACjBA,MAAK,OACJA,MAAK,KAAgC,SAAS;AAAA,IACvD;AACA,UAAM,SAAS,MAAM,eAAe,QAAQ,MAAM,OAAO;AACzD,WAAO,UAAU,GAAG,OAAO,GAAG,IAAI,IAAI;AAAA,MACpC,GAAGA;AAAA,MACH,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAIA,OAAM;AAAA,QACV,GAAI,OAAO;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,SAAS,OAAO,UAAU;AACrC;AAEA,SAAS,qBACP,OACoB;AACpB,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO;AACzC,QAAM,SAAS,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC;AACxC,aAAW,QAAQ,QAAQ;AACzB,QAAI,CAAE,eAAqC,SAAS,IAAI,GAAG;AACzD,YAAM,IAAI,MAAM,8BAA8B,IAAI,EAAE;AAAA,IACtD;AAAA,EACF;AACA,SAAO,OAAO,KAAK,GAAG;AACxB;AAkBO,SAAS,gCAAgC,MAGlB;AAC5B,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAMA,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,SAAS,OAAW,CAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AACvD,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACJ,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,QAAM,aAAaL,GAAE,OAAO;AAAA,IAC1B,OAAOA,GAAE,MAAM,yBAAyB;AAAA,EAC1C,CAAC;AAED,SAAO;AAAA,IACL,MAAM,CAAC,cACL;AAAA,MACE;AAAA,MACA,gBAAgB,SAAS;AAAA,MACzB;AAAA,MACA,CAAC,QAAQ,WAAW,MAAM,GAAG;AAAA,IAC/B;AAAA,IACF,MAAM,CAAC,WAAW,UAChB;AAAA,MAAK;AAAA,MAAQ,gBAAgB,SAAS;AAAA,MAAoB;AAAA,MAAO,CAAC,QAChE,0BAA0B,MAAM,GAAG;AAAA,IACrC;AAAA,IACF,QAAQ,CAAC,WAAW,iBAClB;AAAA,MACE;AAAA,MACA,gBAAgB,SAAS,oBAAoB,YAAY;AAAA,MACzD;AAAA,MACA,CAAC,QAAQ,0BAA0B,MAAM,GAAG;AAAA,IAC9C;AAAA,EACJ;AACF;;;AC9XA,SAAS,KAAAM,UAAS;AAIX,IAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,IAAM,qBAAqBC,GAAE;AAAA,EAClCA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,OAAO,GAAGA,GAAE,QAAQ,GAAGA,GAAE,KAAK,CAAC,CAAC;AACzD;AAGO,IAAM,aAAaA,GACvB,OAAO;AAAA,EACN,QAAQA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAExB,YAAYA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA;AAAA,EAGvC,cAAcA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACzC,MAAMA,GAAE,KAAK,UAAU;AAAA,EACvB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACzC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACxC,OAAOA,GAAE,KAAK,WAAW;AAAA,EACzB,UAAU;AAAA,EACV,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,gBAAgBA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA;AAAA,EAGhC,oBAAoBA,GACjB,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB;AAAA;AAAA,EAEjC,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA;AAAA,EAEpD,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA;AAAA,EAEjC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA,EAE1C,mBAAmBA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA;AAAA,EAE3D,WAAWA,GACR,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB;AACnC,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa;AAAA,EAC7C,SAAS;AACX,CAAC;AAyBI,SAAS,UAAU,OAAqC;AAC7D,MAAI,MAAM,gBAAgB,MAAM,aAAa;AAC3C,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,QAAM,MAAoB;AAAA,IACxB,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,cAAc,MAAM;AAAA,IACpB,OAAO,MAAM;AAAA,IACb,UAAU,MAAM;AAAA,IAChB,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,oBAAoB,MAAM;AAAA,IAC1B,UAAU,MAAM,YAAY;AAAA,IAC5B,aAAa,MAAM;AAAA,EACrB;AACA,MAAI,OAAO,MAAM,eAAe,SAAU,KAAI,aAAa,MAAM;AACjE,MAAI,OAAO,MAAM,iBAAiB;AAChC,QAAI,eAAe,MAAM;AAC3B,MAAI,OAAO,MAAM,eAAe,SAAU,KAAI,aAAa,MAAM;AACjE,MAAI,OAAO,MAAM,sBAAsB,UAAU;AAC/C,QAAI,oBAAoB,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,SACd,UACA,kBACM;AACN,QAAM,YAAY;AAAA,IAChB,mBAAmB,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,GAAG,UAAU,UAAU;AAClC;AAEO,SAAS,WACd,MACA,wBACS;AACT,MAAI;AACF,UAAM,SAAS,WAAW,MAAM,IAAI;AACpC,UAAM,EAAE,WAAW,GAAG,SAAS,IAAI;AACnC,WAAO;AAAA,MACL,mBAAmB,QAAQ;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,qBAAqB,MAAY,OAAwB;AACvE,SAAO,SAAS,KAAK,eAAe,QAAQ,KAAK;AACnD;;;AC/JA,SAAS,KAAAC,WAAS;AAalB,IAAMC,aAAYC,IACf,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,0BAA0B,uBAAuB;AAEnD,IAAM,mBAAmBA,IAAE,OAAO;AAAA,EACvC,MAAM;AAAA,EACN,YAAYA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC5B,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA;AAAA,EAG3C,SAASA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA;AAAA,EAEnC,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACzC,OAAOA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,WAAWD;AACb,CAAC;AAmBD,IAAM,oBAAoB,oBAAI,IAAI,CAAC,UAAU,QAAQ,CAAC;AAE/C,SAAS,gBACd,OACoB;AACpB,MAAI,CAAC,kBAAkB,IAAI,MAAM,KAAK,KAAK,GAAG;AAC5C,UAAM,IAAI,MAAM,iCAAiC,MAAM,KAAK,KAAK,EAAE;AAAA,EACrE;AACA,MAAI,MAAM,eAAe,MAAM,KAAK,aAAa;AAC/C,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AACA,MAAI,MAAM,gBAAgB,MAAM,KAAK,cAAc;AACjD,UAAM,IAAI;AAAA,MACR,QAAQ,MAAM,KAAK,MAAM,eAAe,MAAM,KAAK,YAAY;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,MACJ,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,MAAM;AACxD,MAAI,OAAO,MAAM,KAAK,cAAc;AAClC,UAAM,IAAI;AAAA,MACR,QAAQ,MAAM,KAAK,MAAM,eAAe,MAAM,KAAK,YAAY;AAAA,IACjE;AAAA,EACF;AACA,MAAI,CAAC,MAAM,KAAK,oBAAoB;AAClC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,KAAK;AAAA,IACpB,MAAM,KAAK;AAAA,IACX,OAAO,MAAM,oBAAoB,WAAW,MAAM,kBAAkB;AAAA,EACtE;AACA,MAAI,MAAM,WAAW,UAAU;AAC7B,UAAM,IAAI;AAAA,MACR,sBAAsB,MAAM,OAAO,8BAA8B,QAAQ;AAAA,IAC3E;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,cAAc;AAGnC,MAAI,OAAO,MAAM,KAAK,sBAAsB,UAAU;AACpD,UAAM,OAAO,MAAM,sBAAsB;AACzC,QAAI,OAAO,SAAS,MAAM,KAAK,mBAAmB;AAChD,YAAM,IAAI;AAAA,QACR,QAAQ,MAAM,KAAK,MAAM,QAAQ,MAAM,KAAK,iBAAiB,4BAA4B,IAAI,MAAM,MAAM;AAAA,MAC3G;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,YAAY,MAAM;AAAA,IAClB,cAAc,MAAM;AAAA,IACpB,SAAS,MAAM;AAAA,IACf,YAAY;AAAA,IACZ,OAAO,MAAM;AAAA,EACf;AACF;AAEO,SAAS,eACd,UACA,wBACY;AACZ,QAAM,YAAY;AAAA,IAChB,mBAAmB,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,GAAG,UAAU,UAAU;AAClC;AASO,SAAS,iBACd,GACA,wBACS;AACT,MAAI;AACF,UAAM,SAAS,iBAAiB,MAAM,CAAC;AACvC,QAAI,OAAO,WAAW,OAAO,KAAK,YAAa,QAAO;AACtD,UAAM,EAAE,WAAW,GAAG,aAAa,IAAI,OAAO;AAC9C,QACE,CAAC;AAAA,MACC,mBAAmB,YAAY;AAAA,MAC/B;AAAA,MACA;AAAA,IACF,GACA;AACA,aAAO;AAAA,IACT;AACA,UAAM,YAAY,OAAO,KAAK;AAC9B,QAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,UAAM,EAAE,WAAW,GAAG,SAAS,IAAI;AACnC,WAAO,iBAAW,mBAAmB,QAAQ,GAAG,WAAW,SAAS;AAAA,EACtE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC3JA,SAAS,KAAAE,WAAS;AAIX,IAAM,mBAAmB,CAAC,QAAQ,MAAM;AAIxC,IAAM,gBAAgB;AAMtB,IAAM,uBAAuBC,IAAE;AAAA,EACpCA,IAAE,MAAM,CAACA,IAAE,OAAO,GAAGA,IAAE,OAAO,GAAGA,IAAE,QAAQ,GAAGA,IAAE,KAAK,CAAC,CAAC;AACzD;AAIO,IAAM,gBAAgBA,IAC1B,OAAO;AAAA,EACN,WAAWA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,SAASA,IAAE,KAAK,gBAAgB;AAAA;AAAA,EAEhC,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA,EAErC,kBAAkBA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC7C,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACzC,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EACjC,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACzC,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,SAAS;AAAA;AAAA,EAET,WAAWA,IACR,OAAO,EACP,IAAI,EAAE,EACN,IAAI,IAAI,EACR,MAAM,wBAAwB;AACnC,CAAC,EACA,YAAY,CAAC,GAAG,QAAQ;AACvB,MAAI,EAAE,YAAY,QAAQ;AACxB,QAAI,CAAC,EAAE,UAAU;AACf,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,CAAC,UAAU;AAAA,MACnB,CAAC;AAAA,IACH;AACA,QAAI,EAAE,kBAAkB;AACtB,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,CAAC,kBAAkB;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF,WAAW,EAAE,YAAY,QAAQ;AAC/B,QAAI,CAAC,EAAE,kBAAkB;AACvB,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,CAAC,kBAAkB;AAAA,MAC3B,CAAC;AAAA,IACH;AACA,QAAI,EAAE,UAAU;AACd,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,CAAC,UAAU;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;AAkBI,SAAS,aAAa,OAA2C;AACtE,MAAI,MAAM,YAAY,QAAQ;AAC5B,QAAI,CAAC,MAAM,UAAU;AACnB,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,QAAI,MAAM,kBAAkB;AAC1B,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAAA,EACF,OAAO;AACL,QAAI,CAAC,MAAM,kBAAkB;AAC3B,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,QAAI,MAAM,UAAU;AAClB,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAAA,EACF;AACA,QAAM,MAAuB;AAAA,IAC3B,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,SAAS,MAAM,WAAW,CAAC;AAAA,EAC7B;AACA,MAAI,MAAM,SAAU,KAAI,WAAW,MAAM;AACzC,MAAI,MAAM,iBAAkB,KAAI,mBAAmB,MAAM;AACzD,SAAO;AACT;AAEO,SAAS,YACd,UACA,kBACS;AACT,QAAM,YAAY;AAAA,IAChB,mBAAmB,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,GAAG,UAAU,UAAU;AAClC;AAEO,SAAS,cACd,GACA,wBACS;AACT,MAAI;AACF,UAAM,SAAS,cAAc,MAAM,CAAC;AACpC,UAAM,EAAE,WAAW,GAAG,SAAS,IAAI;AACnC,WAAO;AAAA,MACL,mBAAmB,QAAQ;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC7CO,SAAS,mBAAmB,MAAyC;AAC1E,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC;AACH,UAAM,IAAI,MAAM,uDAAuD;AACzE,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAMC,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,SAAS,OAAW,CAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AACvD,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,MAAe;AACnB,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,QACH,OACD,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,WAAc,QAAQ,KAAK,MAAM;AACvC,YAAM,WACH,OACD,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,WAAc,8BAA8B,KAAK,MAAM;AAC7D,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,WAAW,CAAC,UACV,KAAK,QAAQ,cAAc,OAAO,CAAC,QAAQ,WAAW,MAAM,GAAG,CAAC;AAAA,IAElE,YAAY,CAAC,UAAU;AACrB,YAAM,KAAK,IAAI,gBAAgB;AAC/B,UAAI,MAAM,eAAgB,IAAG,IAAI,kBAAkB,MAAM,cAAc;AACvE,UAAI,MAAM,aAAc,IAAG,IAAI,gBAAgB,MAAM,YAAY;AACjE,UAAI,MAAM,MAAO,IAAG,IAAI,SAAS,MAAM,KAAK;AAC5C,UAAI,MAAM,KAAM,IAAG,IAAI,QAAQ,MAAM,IAAI;AACzC,UAAI,MAAM,WAAY,IAAG,IAAI,cAAc,MAAM,UAAU;AAC3D,UAAI,OAAO,MAAM,UAAU,SAAU,IAAG,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACxE,UAAI,MAAM,OAAQ,IAAG,IAAI,UAAU,MAAM,MAAM;AAC/C,YAAM,OAAO,aAAa,GAAG,OAAO,IAAI,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE;AAChE,aAAO,KAAK,OAAO,MAAM,QAAW,CAAC,QAAQ;AAC3C,cAAM,MAAM;AACZ,cAAM,QAAS,IAAI,MAAoB;AAAA,UAAI,CAAC,OAC1C,WAAW,MAAM,EAAE;AAAA,QACrB;AACA,cAAM,aACJ,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AACxD,eAAO,EAAE,OAAO,WAAW;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,IAEA,SAAS,CAAC,WACR;AAAA,MACE;AAAA,MACA,cAAc,mBAAmB,MAAM,CAAC;AAAA,MACxC;AAAA,MACA,CAAC,QAAQ,WAAW,MAAM,GAAG;AAAA,IAC/B;AAAA,IAEF,YAAY,CAAC,QAAQ,eACnB;AAAA,MACE;AAAA,MACA,cAAc,mBAAmB,MAAM,CAAC;AAAA,MACxC,iBAAiB,MAAM,UAAU;AAAA,MACjC,CAAC,QAAQ;AACP,cAAM,MAAM;AACZ,eAAO;AAAA,UACL,MAAM,WAAW,MAAM,GAAG;AAAA,UAC1B,cACE,OAAO,IAAI,iBAAiB,WAAW,IAAI,eAAe;AAAA,QAC9D;AAAA,MACF;AAAA,IACF,EAAE,KAAK,CAAC,WAAW,OAAO,IAAI;AAAA,IAEhC,oBAAoB,CAAC,QAAQ,eAC3B;AAAA,MACE;AAAA,MACA,cAAc,mBAAmB,MAAM,CAAC;AAAA,MACxC,iBAAiB,MAAM,UAAU;AAAA,MACjC,CAAC,QAAQ;AACP,cAAM,MAAM;AACZ,eAAO;AAAA,UACL,MAAM,WAAW,MAAM,GAAG;AAAA,UAC1B,cACE,OAAO,IAAI,iBAAiB,WAAW,IAAI,eAAe;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,IAEF,uBAAuB,CAAC,QAAQ,YAAY,YAC1C;AAAA,MACE;AAAA,MACA,cAAc,mBAAmB,MAAM,CAAC;AAAA,MACxC;AAAA,QACE,YAAY,iBAAiB,MAAM,UAAU;AAAA,QAC7C;AAAA,MACF;AAAA,MACA,CAAC,QAAQ;AACP,cAAM,MAAM;AAKZ,eAAO;AAAA,UACL,MAAM,WAAW,MAAM,IAAI,IAAI;AAAA,UAC/B,cACE,OAAO,IAAI,iBAAiB,WAAW,IAAI,eAAe;AAAA,UAC5D,SAAS,cAAc,MAAM,IAAI,OAAO;AAAA,QAC1C;AAAA,MACF;AAAA,IACF;AAAA,IAEF,YAAY,CAAC,QAAQ,UACnB;AAAA,MACE;AAAA,MACA,cAAc,mBAAmB,MAAM,CAAC;AAAA,MACxC;AAAA,MACA,CAAC,QAAQ,WAAW,MAAM,GAAG;AAAA,IAC/B;AAAA,IAEF,YAAY,CAAC,MAAM,oBAAoB,WAAa,MAAM,eAAe;AAAA,EAC3E;AACF;;;AClMO,SAAS,qBACd,MACgB;AAChB,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC;AACH,UAAM,IAAI,MAAM,yDAAyD;AAC3E,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAMC,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,SAAS,OAAW,CAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AACvD,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,MAAe;AACnB,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,QAAM,UAAqC,CAAC,cAC1C;AAAA,IACE;AAAA,IACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,IAC7C;AAAA,IACA,CAAC,QAAQ,cAAc,MAAM,GAAG;AAAA,EAClC;AAEF,SAAO;AAAA,IACL,cAAc,CAAC,UACb,KAAK,QAAQ,gBAAgB,OAAO,CAAC,QAAQ,cAAc,MAAM,GAAG,CAAC;AAAA,IAEvE,YAAY;AAAA,IACZ;AAAA,IAEA,eAAe,CAAC,aACd;AAAA,MACE;AAAA,MACA,0BAA0B,mBAAmB,QAAQ,CAAC;AAAA,MACtD;AAAA,MACA,CAAC,QAAQ,cAAc,MAAM,GAAG;AAAA,IAClC;AAAA,IAEF,uBAAuB,CAAC,qBACtB;AAAA,MACE;AAAA,MACA,mCAAmC,mBAAmB,gBAAgB,CAAC;AAAA,MACvE;AAAA,MACA,CAAC,QAAQ,cAAc,MAAM,GAAG;AAAA,IAClC;AAAA,IAEF,aAAa,CAAC,UAAU;AACtB,YAAM,KAAK,IAAI,gBAAgB;AAC/B,UAAI,MAAM,YAAa,IAAG,IAAI,eAAe,MAAM,WAAW;AAC9D,UAAI,MAAM,YAAa,IAAG,IAAI,eAAe,MAAM,WAAW;AAC9D,UAAI,MAAM,QAAS,IAAG,IAAI,WAAW,MAAM,OAAO;AAClD,UAAI,OAAO,MAAM,UAAU,SAAU,IAAG,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACxE,UAAI,MAAM,OAAQ,IAAG,IAAI,UAAU,MAAM,MAAM;AAC/C,YAAM,OAAO,eAAe,GAAG,OAAO,IAAI,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE;AAClE,aAAO,KAAK,OAAO,MAAM,QAAW,CAAC,QAAQ;AAC3C,cAAM,MAAM;AACZ,cAAM,QAAS,IAAI,MAAoB;AAAA,UAAI,CAAC,OAC1C,cAAc,MAAM,EAAE;AAAA,QACxB;AACA,cAAM,aACJ,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AACxD,eAAO,EAAE,OAAO,WAAW;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,IAEA,eAAe,CAAC,SAAS,oBACvB,cAAgB,SAAS,eAAe;AAAA,EAC5C;AACF;;;ACzHO,SAAS,iBACd,OACQ;AACR,SAAO,UAAU,EAAE,GAAG,OAAO,mBAAmB,SAAS,CAAC;AAC5D;AAEO,SAAS,kBACd,OACQ;AACR,SAAO,UAAU,EAAE,GAAG,OAAO,mBAAmB,UAAU,CAAC;AAC7D;AAEO,SAAS,QAAQ,SAA4B;AAClD,SAAO,SAAS,OAAO;AACzB;AAoBO,SAAS,KAAK,MAAmC;AACtD,QAAM,UAAU,wBAAwB;AAAA,IACtC,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,EACd,CAAC;AACD,QAAM,cAAc,QAAQ;AAC5B,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,WAAS,oBAAoB,GAAqB;AAChD,QAAI,YAAY;AAEhB,mBAAe,MAAM;AACnB,UAAI,UAAW;AACf,QAAE;AAAA,QACA,IAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,OAAsB;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAAS,mBAAmB,EAAE,SAAS,WAAW,YAAY,CAAC;AACrE,QAAM,WAAW,qBAAqB,EAAE,SAAS,WAAW,YAAY,CAAC;AACzE,QAAM,cAAc,+BAA+B;AAAA,IACjD;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AAED,SAAO;AAAA;AAAA,IAEL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjIA,SAAS,KAAAC,WAAS;AAGX,IAAM,gBAAgB,CAAC,YAAY,YAAY,SAAS;AAGxD,IAAM,mBAAmB,CAAC,UAAU,aAAa,QAAQ;AAGzD,IAAM,mBAAmB,CAAC,SAAS,SAAS,UAAU,OAAO;AAG7D,IAAM,gBAAgBC,IAAE,OAAO;AAAA,EACpC,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,MAAMA,IAAE,KAAK,aAAa;AAAA,EAC1B,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,QAAQA,IAAE,KAAK,gBAAgB;AAAA,EAC/B,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACxC,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,0BAA0BA,IAAE,OAAO;AAAA,EAC9C,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,QAAQA,IAAE,OAAO,EAAE,KAAK;AAAA,EACxB,MAAMA,IAAE,KAAK,gBAAgB;AAAA,EAC7B,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAgCM,SAAS,qBACd,MACgB;AAChB,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAMC,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,SAAS,OAAW,CAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AACvD,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,MAAe;AACnB,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,QAAM,cAAcD,IAAE,OAAO,EAAE,OAAOA,IAAE,MAAM,aAAa,EAAE,CAAC;AAC9D,QAAM,oBAAoBA,IAAE,OAAO;AAAA,IACjC,OAAOA,IAAE,MAAM,uBAAuB;AAAA,EACxC,CAAC;AAED,SAAO;AAAA,IACL,gBAAgB,MACd;AAAA,MAAK;AAAA,MAAO;AAAA,MAAmB;AAAA,MAAW,CAAC,QACzC,YAAY,MAAM,GAAG;AAAA,IACvB;AAAA,IACF,YAAY,CAAC,cACX;AAAA,MACE;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,MACA,CAAC,QAAQ,cAAc,MAAM,GAAG;AAAA,IAClC;AAAA,IACF,aAAa,CAAC,cACZ;AAAA,MACE;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,MACA,CAAC,QAAQ,kBAAkB,MAAM,GAAG;AAAA,IACtC;AAAA,IACF,uBAAuB,CAAC,UACtB,KAAK,QAAQ,gBAAgB,OAAO,CAAC,QAAQ,cAAc,MAAM,GAAG,CAAC;AAAA,IACvE,WAAW,CAAC,WAAW,UACrB;AAAA,MACE;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,MACA,CAAC,QAAQ,wBAAwB,MAAM,GAAG;AAAA,IAC5C;AAAA,EACJ;AACF;;;ACtIA,SAAS,KAAAE,WAAS;;;ACOlB,SAAS,KAAAC,WAAS;AAMlB,IAAMC,aAAYC,IAAE,OAAO,EAAE,MAAM,wBAAwB;AAMpD,IAAM,6BACX;AAOK,IAAM,8BAA8B;AAEpC,IAAM,uBAAuBA,IAAE,OAAO;AAAA,EAC3C,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,UAAUA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACvC,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzC,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,EAEjD,eAAeA,IAAE,MAAMA,IAAE,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,2BAA2B;AAC3E,CAAC;AAGM,IAAM,6BAA6BA,IAAE,OAAO;AAAA,EACjD,MAAM;AAAA;AAAA,EAEN,WAAWD,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA;AAAA,EAErC,wBAAwBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AACpD,CAAC;AA0BM,SAAS,6BACd,MACyB;AACzB,QAAM,UAAmC;AAAA,IACvC,QAAQ;AAAA,IACR,UAAU,KAAK;AAAA,IACf,UAAU,KAAK;AAAA,IACf,YAAY,KAAK;AAAA,IACjB,eAAe,KAAK;AAAA,EACtB;AACA,MAAI,KAAK,eAAe,OAAW,SAAQ,aAAa,KAAK;AAC7D,SAAO;AACT;AAgBO,SAAS,qBACd,QACA,aACA,UAAuC,CAAC,GACZ;AAC5B,QAAM,SAAS,2BAA2B,UAAU,MAAM;AAC1D,MAAI,CAAC,OAAO,QAAS,QAAO,EAAE,IAAI,OAAO,QAAQ,YAAY;AAC7D,QAAM,OAAO,OAAO,KAAK;AACzB,QAAM,QAAQ,QAAQ,SAAS,KAAK,IAAI;AAExC,QAAM,SAAS,YAAY;AAAA,IACzB,CAAC,MACC,EAAE,aAAa,KAAK,aACnB,EAAE,gBAAgB,UAAa,SAAS,EAAE,iBAC1C,EAAE,eAAe,UAAa,SAAS,EAAE;AAAA,EAC9C;AACA,MAAI,OAAO,WAAW,EAAG,QAAO,EAAE,IAAI,OAAO,QAAQ,mBAAmB;AAExE,QAAM,eAAe,mBAAmB,6BAA6B,IAAI,CAAC;AAC1E,QAAM,cAAc,OAAO;AAAA,IAAK,CAAC,MAC/B,iBAAiB,cAAc,OAAO,KAAK,WAAW,EAAE,gBAAgB;AAAA,EAC1E;AACA,MAAI,CAAC,YAAa,QAAO,EAAE,IAAI,OAAO,QAAQ,oBAAoB;AAElE,MAAI,KAAK,eAAe,UAAa,QAAQ,KAAK,YAAY;AAC5D,WAAO,EAAE,IAAI,OAAO,QAAQ,QAAQ;AAAA,EACtC;AAEA,SAAO,EAAE,IAAI,MAAM,MAAM,eAAe,IAAI,IAAI,KAAK,aAAa,EAAE;AACtE;AAGO,SAAS,aACd,OACA,eACS;AACT,SAAO,cAAc,IAAI,KAAK;AAChC;;;ADzIA,IAAM,YAAYE,IAAE,OAAO,EAAE,MAAM,gBAAgB;AACnD,IAAMC,aAAYD,IAAE,OAAO,EAAE,MAAM,wBAAwB;AAC3D,IAAM,aAAaA,IAChB,OAAO,EACP,IAAI,CAAC,EACL,IAAI,GAAG,EACP,OAAO,CAAC,UAAU,CAAC,MAAM,SAAS,GAAG,GAAG;AAAA,EACvC,SAAS;AACX,CAAC;AASI,IAAM,gCAAgC,MAAO,KAAK,KAAK;AAQvD,IAAM,uBAAuBA,IAAE,OAAO;AAAA,EAC3C,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EACnC,KAAKA,IAAE,QAAQ,MAAM;AAAA,EACrB,kBAAkBC,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA,EAC5C,aAAaD,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACrD,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AACnD,CAAC;AAGM,IAAM,0BAA0BA,IAAE,OAAO;AAAA,EAC9C,MAAMA,IAAE,MAAM,oBAAoB,EAAE,IAAI,CAAC;AAC3C,CAAC;AAcM,IAAM,yCAAyC,MAAO,KAAK,KAAK;AAIhE,IAAM,iCAAiCA,IAAE,KAAK;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,qBAAqBA,IAAE,QAAQ,MAAM;AAG3C,IAAM,mCAAmCA,IAAE,OAAO;AAAA,EACvD,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA;AAAA,EAEnC,kBAAkBC,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA;AAAA,EAE5C,cAAcA,WAAU,IAAI,CAAC,EAAE,IAAI,IAAI;AAAA;AAAA,EAEvC,qBAAqBD,IAAE,MAAMC,WAAU,IAAI,EAAE,EAAE,IAAI,KAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACzE,eAAe;AACjB,CAAC;AAKM,IAAM,qCAAqCD,IAAE,OAAO;AAAA,EACzD,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AACrC,CAAC;AAKM,IAAM,sCAAsCA,IAAE,OAAO;AAAA,EAC1D,WAAWA,IAAE,OAAO,EAAE,IAAI,EAAE;AAAA,EAC5B,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AACzC,CAAC;AAKM,IAAM,wBAAwBA,IAAE,OAAO;AAAA,EAC5C,IAAIA,IAAE,OAAO,EAAE,KAAK;AAAA,EACpB,QAAQA,IAAE,OAAO,EAAE,KAAK;AAAA,EACxB,UAAUA,IAAE,OAAO;AAAA;AAAA,EAEnB,KAAK,mBAAmB,QAAQ,MAAM;AAAA;AAAA,EAEtC,kBAAkBC,WAAU,SAAS,EAAE,QAAQ,IAAI;AAAA,EACnD,eAAe,+BAA+B,SAAS,EAAE,QAAQ,IAAI;AAAA,EACrE,gBAAgBD,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACzC,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,IAAI;AAAA,EACpE,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACvD,CAAC;AAOM,IAAM,oBAAoBA,IAAE,OAAO;AAAA,EACxC,OAAOA,IAAE,OAAO,EAAE,KAAK;AAAA,EACvB,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAClC,QAAQA,IAAE,OAAO,EAAE,KAAK;AAAA,EACxB,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,KAAKA,IAAE,QAAQ,MAAM;AAAA;AAAA,EAErB,qBAAqBC,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ/C,cAAcD,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,mBAAmBA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAChD,UAAUA,IAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzC,WAAWA,IAAE,OAAO,EAAE,MAAM,mBAAmB;AAAA,EAC/C,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AACvC,CAAC;AAGM,IAAM,0BAA0BA,IAAE,OAAO;AAAA,EAC9C,KAAK;AAAA;AAAA,EAEL,WAAWC,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA;AAAA,EAErC,wBAAwBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AACpD,CAAC;AAGM,IAAM,kBAAkB,wBAAwB,OAAO;AAAA,EAC5D,yBAAyBD,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACtD,QAAQA,IAAE,KAAK,CAAC,UAAU,cAAc,WAAW,SAAS,CAAC;AAAA,EAC7D,gBAAgBA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACxD,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACvD,CAAC;AAYM,IAAM,6BAA6BA,IAAE,OAAO;AAAA,EACjD,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EACnC,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACnD,mBAAmBA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACxD,OAAOA,IACJ,OAAO,EACP,IAAI,EACJ,IAAI,GAAM,EACV,IAAI,6BAA6B,EACjC,SAAS;AACd,CAAC;AAKM,IAAM,4BAA4BA,IAAE,OAAO;AAAA,EAChD,QAAQ,gBAAgB,SAAS;AACnC,CAAC;AAiBM,IAAM,6BAA6BA,IAAE,OAAO;AAAA;AAAA,EAEjD,KAAKA,IAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM;AAAA,EACrC,OAAOA,IAAE,OAAO,EAAE,KAAK;AAAA,EACvB,aAAa,UAAU,SAAS;AAAA,EAChC,aAAaA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,aAAaA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,eAAeA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EACxC,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,UAAUA,IAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK;AAAA,EAC5C,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC3C,eAAeA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACvD,WAAWA,IAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAExC,WAAWA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACtC,aAAaA,IAAE,KAAK,CAAC,SAAS,UAAU,CAAC,EAAE,SAAS;AAAA,EACpD,oBAAoBA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC/C,mBAAmBA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACxD,iBAAiBA,IAAE,OAAO,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC/C,kBAAkBA,IAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;AAAA,EAC1D,oBAAoBA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EAC5D,oBAAoBA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACzD,cAAcA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAClD,sBAAsBA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;AAAA,EACrE,2BAA2BC,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,SAAS;AAAA,EAChE,6BAA6BA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,SAAS;AAAA,EAElE,oBAAoBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA,EAC9C,sBAAsBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA,EAChD,oBAAoBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,SAAS;AAAA,EACzD,sBAAsBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,SAAS;AAC7D,CAAC;AAGM,IAAM,2BAA2BD,IAAE,OAAO;AAAA,EAC/C,cAAcA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC9B,eAAe;AAAA,EACf,aAAa;AAAA,EACb,OAAOA,IAAE,OAAO,EAAE,KAAK;AAAA,EACvB,aAAaA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,aAAaA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,UAAUA,IAAE,OAAO,EAAE,OAAO,CAAC;AAAA,EAC7B,QAAQA,IAAE,KAAK,CAAC,WAAW,QAAQ,CAAC;AAAA,EACpC,cAAcA,IAAE,OAAO,EAAE,SAAS;AAAA,EAClC,WAAWA,IAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE/B,WAAWC,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI;AAAA;AAAA,EAErC,YAAYD,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA,EAEzC,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACvD,CAAC;AAGM,IAAM,6BAA6BA,IAAE,OAAO;AAAA,EACjD,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,UAAUA,IAAE,QAAQ;AACtB,CAAC;AAKM,IAAM,6BAA6BA,IAAE,OAAO;AAAA,EACjD,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA;AAAA,EAEnC,eAAeA,IAAE,OAAO,EAAE,IAAI,EAAE;AAClC,CAAC;AAmCM,SAAS,sBACd,MACiB;AACjB,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAME,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,SAAS,OAAW,CAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AACvD,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,MAAe;AACnB,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,QAAM,iBAAiBF,IAAE,OAAO,EAAE,OAAOA,IAAE,MAAM,qBAAqB,EAAE,CAAC;AAEzE,SAAO;AAAA,IACL,8BAA8B,CAAC,UAC7B;AAAA,MACE;AAAA,MACA;AAAA,MACA,mCAAmC,MAAM,KAAK;AAAA,MAC9C,CAAC,QAAQ,oCAAoC,MAAM,GAAG;AAAA,IACxD;AAAA,IACF,uBAAuB,CAAC,UACtB;AAAA,MACE;AAAA,MACA;AAAA,MACA,iCAAiC,MAAM,KAAK;AAAA,MAC5C,CAAC,QAAQ,sBAAsB,MAAM,GAAG;AAAA,IAC1C;AAAA,IACF,gBAAgB,MACd;AAAA,MAAK;AAAA,MAAO;AAAA,MAAuB;AAAA,MAAW,CAAC,QAC7C,eAAe,MAAM,GAAG;AAAA,IAC1B;AAAA,IACF,iBAAiB,CAAC,UAChB;AAAA,MACE;AAAA,MACA;AAAA,MACA,2BAA2B,MAAM,KAAK;AAAA,MACtC,MAAM;AAAA,IACR;AAAA,IACF,iBAAiB,CAAC,UAChB;AAAA,MACE;AAAA,MACA;AAAA,MACA,2BAA2B,MAAM,KAAK;AAAA,MACtC,CAAC,QAAQ,gBAAgB,MAAM,GAAG;AAAA,IACpC;AAAA,IACF,WAAW,CAAC,aAAa;AACvB,YAAM,KAAK,WAAW,aAAa,mBAAmB,QAAQ,CAAC,KAAK;AACpE,aAAO;AAAA,QAAK;AAAA,QAAO,wBAAwB,EAAE;AAAA,QAAI;AAAA,QAAW,CAAC,QAC3D,0BAA0B,MAAM,GAAG;AAAA,MACrC;AAAA,IACF;AAAA,IACA,aAAa,CAAC,UACZ;AAAA,MACE;AAAA,MACA;AAAA,MACA,2BAA2B,MAAM,KAAK;AAAA,MACtC,CAAC,QAAQ,2BAA2B,MAAM,GAAG;AAAA,IAC/C;AAAA,IACF,eAAe,CAAC,YACd;AAAA,MACE;AAAA,MACA,8BAA8B,mBAAmB,OAAO,CAAC;AAAA,MACzD;AAAA,MACA,CAAC,QAAQ,yBAAyB,MAAM,GAAG;AAAA,IAC7C;AAAA,IACF,eAAe,MACb;AAAA,MAAK;AAAA,MAAO;AAAA,MAAmB;AAAA,MAAW,CAAC,QACzC,wBAAwB,MAAM,GAAG;AAAA,IACnC;AAAA,IACF,gBAAgB,MACd;AAAA,MAAK;AAAA,MAAO;AAAA,MAA0B;AAAA,MAAW,CAAC,QAChD,2BAA2B,MAAM,GAAG;AAAA,IACtC;AAAA,EACJ;AACF;;;AEjbA,SAAS,QAAAG,aAAY;AACrB,SAAS,UAAAC,eAAc;AAUhB,IAAM,kBAAkB;AAC/B,IAAMC,oBAAmB;AAyDlB,SAAS,6BAA6B,OAc3C;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,KAAK,MAAM;AAAA,IACX,OAAO,MAAM;AAAA,IACb,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB,eAAe,MAAM;AAAA,IACrB,YAAY,MAAM;AAAA,IAClB,YAAY,MAAM;AAAA,IAClB,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,cAAc,MAAM;AAAA,IACpB,eAAe,MAAM,iBAAiB;AAAA,IACtC,WAAW,MAAM,aAAa;AAAA,EAChC;AACF;AAGO,SAAS,2BACd,OACY;AACZ,SAAO,mBAAmB,6BAA6B,KAAK,CAAC;AAC/D;AAGO,SAAS,gCAAgC,OAMrC;AACT,QAAM,WAAW,GAAGA,iBAAgB,IAAI;AAAA,IACtC,oBAAoB,SAAS,MAAM,KAAK;AAAA,IACxC,oBAAoB,eAAe,MAAM,WAAW;AAAA,IACpD,oBAAoB,eAAe,MAAM,WAAW;AAAA,IACpD,oBAAoB,cAAc,MAAM,UAAU;AAAA,IAClD,oBAAoB,cAAc,MAAM,UAAU;AAAA,EACpD,EAAE,KAAK,GAAG,CAAC;AACX,SAAOC,YAAWC,QAAO,IAAI,YAAY,EAAE,OAAO,QAAQ,CAAC,CAAC;AAC9D;AAEA,SAAS,oBAAoB,OAAe,OAAuB;AACjE,MAAI,MAAM,SAAS,GAAG,GAAG;AACvB,UAAM,IAAI,MAAM,yBAAyB,KAAK,qBAAqB;AAAA,EACrE;AACA,SAAO;AACT;AAEA,SAASD,YAAW,OAA2B;AAC7C,MAAI,MAAM;AACV,aAAW,QAAQ,MAAO,QAAO,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAClE,SAAO;AACT;AAOA,SAASE,eAAc,OAA2B;AAChD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAAA,EAC7C;AACA,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,QAAO,OAAO,aAAa,MAAM,CAAC,CAAE;AAE3E,SAAO,KAAK,GAAG;AACjB;AAEA,SAASC,eAAc,KAAyB;AAC9C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,IAAI,WAAW,OAAO,KAAK,KAAK,QAAQ,CAAC;AAAA,EAClD;AACA,QAAM,MAAM,KAAK,GAAG;AACpB,QAAM,MAAM,IAAI,WAAW,IAAI,MAAM;AACrC,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,KAAI,CAAC,IAAI,IAAI,WAAW,CAAC;AAC9D,SAAO;AACT;AAUA,IAAMC,oBAAmB,IAAI,WAAW;AAAA,EACtC;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACxE;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAC1E,CAAC;AAED,SAAS,uBAAuB,iBAAqC;AACnE,MAAI,gBAAgB,WAAW,MAAM,gBAAgB,CAAC,MAAM,GAAM;AAChE,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,QAAM,MAAM,IAAI,WAAWA,kBAAiB,SAAS,gBAAgB,MAAM;AAC3E,MAAI,IAAIA,mBAAkB,CAAC;AAC3B,MAAI,IAAI,iBAAiBA,kBAAiB,MAAM;AAChD,SAAOF,eAAc,GAAG;AAC1B;AAEA,SAAS,uBAAuB,SAA6B;AAC3D,QAAM,OAAOC,eAAc,OAAO;AAGlC,MAAI,KAAK,WAAWC,kBAAiB,SAAS,IAAI;AAChD,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,WAAS,IAAI,GAAG,IAAIA,kBAAiB,QAAQ,KAAK;AAChD,QAAI,KAAK,CAAC,MAAMA,kBAAiB,CAAC,GAAG;AACnC,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,EACF;AACA,SAAO,KAAK,MAAMA,kBAAiB,MAAM;AAC3C;AAaO,SAAS,yBACd,YACoB;AAGpB,QAAM,MAAMC,MAAK,aAAa,YAAY,KAAK;AAC/C,QAAM,UAAU,uBAAuB,GAAG;AAE1C,SAAO;AAAA,IACL,KAAK;AAAA,IACL,MAAM,eAAe;AACnB,aAAO,EAAE,KAAK,QAAQ,WAAW,QAAQ;AAAA,IAC3C;AAAA,IACA,MAAM,KAAK,OAAmB;AAK5B,YAAM,MAAMA,MAAK,KAAK,OAAO,YAAY,EAAE,SAAS,KAAK,CAAC;AAG1D,YAAM,MAAM,IAAI,QAAQ,KAAK;AAC7B,aAAO,EAAE,KAAK,QAAQ,WAAWH,eAAc,GAAG,EAAE;AAAA,IACtD;AAAA,EACF;AACF;AAgBO,SAAS,qBACd,OACS;AACT,MAAI;AACF,QAAI,MAAM,QAAQ,OAAQ,QAAO;AACjC,UAAM,SAASC,eAAc,MAAM,SAAS;AAC5C,UAAM,MAAM,uBAAuB,MAAM,SAAS;AAClD,WAAOE,MAAK,OAAO,QAAQ,MAAM,OAAO,KAAK;AAAA,MAC3C,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACrSA,SAAS,KAAAC,WAAS;AAIlB,IAAMC,aAAYC,IAAE,OAAO,EAAE,MAAM,wBAAwB;AAEpD,IAAM,kCACX;AAEK,IAAM,uCAAuCA,IACjD,OAAO;AAAA,EACN,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,MAAMA,IAAE,KAAK,CAAC,SAAS,UAAU,CAAC;AAAA,EAClC,aAAaA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC7B,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,UAAUA,IAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK;AAAA,EAC5C,WAAWA,IAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,QAAQ,IAAI;AAAA,EACtD,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACvC,OAAOA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAChC,eAAeA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,QAAQ,IAAI;AAAA,EACjE,oBAAoBD,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,SAAS;AAAA,EACzD,sBAAsBA,WAAU,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,SAAS;AAC7D,CAAC,EACA,YAAY,CAAC,OAAO,QAAQ;AAC3B,MAAI,MAAM,eAAe,MAAM,aAAa;AAC1C,QAAI,SAAS;AAAA,MACX,MAAMC,IAAE,aAAa;AAAA,MACrB,MAAM,CAAC,aAAa;AAAA,MACpB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,QAAM,eAAe;AAAA,IACnB,MAAM,sBAAsB,MAAM;AAAA,EACpC;AACA,MAAI,MAAM,SAAS,WAAW,cAAc;AAC1C,QAAI,CAAC,MAAM,eAAe;AACxB,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,MAAM,CAAC,eAAe;AAAA,QACtB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA,QAAI,CAAC,MAAM,oBAAoB;AAC7B,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,MAAM,CAAC,oBAAoB;AAAA,QAC3B,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA,QAAI,CAAC,MAAM,sBAAsB;AAC/B,UAAI,SAAS;AAAA,QACX,MAAMA,IAAE,aAAa;AAAA,QACrB,MAAM,CAAC,sBAAsB;AAAA,QAC7B,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;AAWI,SAAS,4BAA4B,OAWT;AACjC,QAAM,WAAW;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,MAAM,MAAM;AAAA,IACZ,aAAa,MAAM;AAAA,IACnB,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM,YAAY;AAAA,IAC5B,WAAW,MAAM,aAAa;AAAA,IAC9B,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB,OAAO,MAAM;AAAA,IACb,eAAe,MAAM,iBAAiB;AAAA,EACxC;AACA,MAAI,SAAS,SAAS,WAAW,CAAC,SAAS,eAAe;AACxD,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,MAAI,SAAS,eAAe,SAAS,aAAa;AAChD,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;AAEO,SAAS,qCACd,SACA;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW,QAAQ;AAAA,IACnB,MAAM,QAAQ;AAAA,IACd,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,UAAU,QAAQ;AAAA,IAClB,WAAW,QAAQ,aAAa;AAAA,IAChC,aAAa,QAAQ;AAAA,IACrB,aAAa,QAAQ;AAAA,IACrB,OAAO,QAAQ;AAAA,IACf,eAAe,QAAQ,iBAAiB;AAAA,EAC1C;AACF;AAEO,SAAS,mCACd,SACY;AACZ,SAAO,mBAAmB,qCAAqC,OAAO,CAAC;AACzE;AAEA,eAAsB,2BACpB,UACA,QACyC;AACzC,MAAI,OAAO,QAAQ,QAAQ;AACzB,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,QAAM,YAAY,MAAM,OAAO,aAAa;AAC5C,MAAI,UAAU,QAAQ,QAAQ;AAC5B,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,QAAM,YAAY,MAAM,OAAO;AAAA,IAC7B,mCAAmC,QAAQ;AAAA,EAC7C;AACA,SAAO,qCAAqC,MAAM;AAAA,IAChD,GAAG;AAAA,IACH,oBAAoB,UAAU;AAAA,IAC9B,sBAAsB,UAAU;AAAA,EAClC,CAAC;AACH;AAEO,SAAS,6BACd,SACS;AACT,QAAM,SAAS,qCAAqC,UAAU,OAAO;AACrE,MAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,MAAM,sBAAsB,CAAC,MAAM,qBAAsB,QAAO;AACrE,SAAO,qBAAqB;AAAA,IAC1B,KAAK;AAAA,IACL,OAAO,mCAAmC,KAAK;AAAA,IAC/C,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM;AAAA,EACnB,CAAC;AACH;AAEO,SAAS,gCACd,SACA,QAAQ,KAAK,IAAI,GACR;AACT,QAAM,SAAS,qCAAqC,MAAM,OAAO;AACjE,SAAO,OAAO,eAAe;AAC/B;;;ACrKO,IAAM,6BACX;AAEK,IAAM,wCAAwC;AAE9C,SAAS,iCACd,YACA;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,cAAc,WAAW;AAAA,IACzB,eAAe,WAAW;AAAA,IAC1B,aAAa,WAAW;AAAA,IACxB,OAAO,WAAW;AAAA,IAClB,aAAa,WAAW;AAAA,IACxB,aAAa,WAAW;AAAA,IACxB,YAAY,WAAW;AAAA,IACvB,UAAU,WAAW;AAAA,IACrB,QAAQ,WAAW;AAAA,IACnB,cAAc,WAAW;AAAA,IACzB,WAAW,WAAW;AAAA,IACtB,YAAY,WAAW;AAAA,EACzB;AACF;AAEO,SAAS,yBACd,YACA,wBACS;AACT,QAAM,SAAS,yBAAyB,UAAU,UAAU;AAC5D,MAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,SAAO;AAAA,IACL,mBAAmB,iCAAiC,OAAO,IAAI,CAAC;AAAA,IAChE,OAAO,KAAK;AAAA,IACZ;AAAA,EACF;AACF;AAEO,SAAS,kCACd,YACQ;AACR,QAAM,SAAS,yBAAyB,MAAM,UAAU;AACxD,SAAO,GAAG,qCAAqC,GAAG;AAAA,IAChD,KAAK,UAAU,MAAM;AAAA,EACvB,CAAC;AACH;AAEO,SAAS,4CACd,OACoB;AACpB,MAAI,CAAC,MAAM,WAAW,qCAAqC,GAAG;AAC5D,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,QAAM,UAAU,MAAM,MAAM,sCAAsC,MAAM;AACxE,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAM,oBAAoB,OAAO,CAAC;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,SAAO,yBAAyB,MAAM,GAAG;AAC3C;AAEO,SAAS,kCACd,OACA,wBACoB;AACpB,QAAM,aAAa,4CAA4C,KAAK;AACpE,MAAI,CAAC,yBAAyB,YAAY,sBAAsB,GAAG;AACjE,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,OAAuB;AAClD,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,KAAK;AAC5C,MAAI,SAAS;AACb,aAAW,QAAQ,MAAO,WAAU,OAAO,aAAa,IAAI;AAC5D,QAAM,SACJ,OAAO,SAAS,aACZ,KAAK,MAAM,IACX,OAAO,WAAW,cAChB,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,IACpC;AACR,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,4BAA4B;AACzD,SAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC1E;AAEA,SAAS,oBAAoB,OAAuB;AAClD,QAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACzD,QAAM,SAAS,OAAO;AAAA,IACpB,OAAO,UAAW,IAAK,OAAO,SAAS,KAAM;AAAA,IAC7C;AAAA,EACF;AACA,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,SAAS,KAAK,MAAM;AAC1B,UAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,aAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS;AAClD,YAAM,KAAK,IAAI,OAAO,WAAW,KAAK;AAAA,IACxC;AACA,WAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,EACvC;AACA,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,QAAQ,QAAQ,EAAE,SAAS,MAAM;AAAA,EACtD;AACA,QAAM,IAAI,MAAM,4BAA4B;AAC9C;;;ACvFA,SAAS,KAAAC,WAAS;AAgBX,IAAM,sBAAsB;AAsD5B,SAAS,0BAA0B,KAAkB;AAC1D,SAAO,EAAE,QAAQ,qBAAqB,GAAG,IAAI;AAC/C;AAaO,SAAS,iBACd,QACA,aACA,UAAmC,CAAC,GACZ;AACxB,QAAM,SAAS,wBAAwB,UAAU,MAAM;AACvD,MAAI,CAAC,OAAO,QAAS,QAAO,EAAE,IAAI,OAAO,QAAQ,YAAY;AAC7D,QAAM,YAAY,kBAAkB,UAAU,OAAO,KAAK,GAAG;AAC7D,MAAI,CAAC,UAAU,QAAS,QAAO,EAAE,IAAI,OAAO,QAAQ,YAAY;AAChE,QAAM,MAAM,UAAU;AACtB,QAAM,QAAQ,QAAQ,SAAS,KAAK,IAAI;AAExC,QAAM,SAAS,YAAY;AAAA,IACzB,CAAC,MACC,EAAE,aAAa,IAAI,aAClB,EAAE,gBAAgB,UAAa,SAAS,EAAE,iBAC1C,EAAE,eAAe,UAAa,SAAS,EAAE;AAAA,EAC9C;AACA,MAAI,OAAO,WAAW,EAAG,QAAO,EAAE,IAAI,OAAO,QAAQ,mBAAmB;AAExE,QAAM,eAAe,mBAAmB,0BAA0B,GAAG,CAAC;AACtE,QAAM,cAAc,OAAO;AAAA,IAAK,CAAC,MAC/B,iBAAiB,cAAc,OAAO,KAAK,WAAW,EAAE,gBAAgB;AAAA,EAC1E;AACA,MAAI,CAAC,YAAa,QAAO,EAAE,IAAI,OAAO,QAAQ,oBAAoB;AAMlE,MAAI,IAAI,eAAe,IAAI,cAAc,+BAA+B;AACtE,WAAO,EAAE,IAAI,OAAO,QAAQ,kBAAkB;AAAA,EAChD;AAEA,MAAI,QAAQ,IAAI,YAAa,QAAO,EAAE,IAAI,OAAO,QAAQ,gBAAgB;AACzE,MAAI,SAAS,IAAI,aAAc,QAAO,EAAE,IAAI,OAAO,QAAQ,UAAU;AAGrE,MAAI,QAAQ,eAAe,IAAI,IAAI,KAAK,GAAG;AACzC,WAAO,EAAE,IAAI,OAAO,QAAQ,UAAU;AAAA,EACxC;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,UAAU;AAAA,MACR,OAAO,IAAI;AAAA,MACX,UAAU,IAAI;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,MACjB,qBAAqB,IAAI;AAAA,IAC3B;AAAA,EACF;AACF;AASO,IAAM,yBAAyB;AAG/B,SAAS,gBAAgB,OAAwB;AACtD,SAAO,MAAM,WAAW,sBAAsB;AAChD;AAUO,IAAM,8BAA8BC,IACxC,OAAO;AAAA;AAAA,EAEN,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAiB,EAAE,SAAS;AAAA;AAAA,EAEzE,QAAQA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA;AAAA,EAE3C,WAAWA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAChD,CAAC,EACA,OAAO;AAaH,SAAS,oBACd,QACA,SACQ;AACR,QAAM,SAAS,wBAAwB,MAAM,MAAM;AACnD,QAAM,OAAO,GAAG,sBAAsB,GAAGC,qBAAoB,KAAK,UAAU,MAAM,CAAC,CAAC;AACpF,MAAI,YAAY,OAAW,QAAO;AAClC,QAAM,gBAAgB,4BAA4B,MAAM,OAAO;AAC/D,MAAI,OAAO,KAAK,aAAa,EAAE,WAAW,EAAG,QAAO;AACpD,SAAO,GAAG,IAAI,IAAIA,qBAAoB,KAAK,UAAU,aAAa,CAAC,CAAC;AACtE;AASO,SAAS,8BACd,OACmB;AACnB,MAAI,CAAC,MAAM,WAAW,sBAAsB,GAAG;AAC7C,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AACA,QAAM,YAAY,MAAM,MAAM,uBAAuB,MAAM;AAG3D,QAAM,UAAU,UAAU,MAAM,KAAK,CAAC,EAAE,CAAC;AACzC,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAMC,qBAAoB,OAAO,CAAC;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACA,SAAO,wBAAwB,MAAM,GAAG;AAC1C;AAQO,SAAS,yBACd,OAC8B;AAC9B,MAAI,CAAC,MAAM,WAAW,sBAAsB,EAAG,QAAO;AACtD,QAAM,YAAY,MAAM,MAAM,uBAAuB,MAAM;AAC3D,QAAM,MAAM,UAAU,QAAQ,GAAG;AACjC,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,SAAS,UAAU,MAAM,MAAM,CAAC;AACtC,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,MAAI;AACF,UAAM,MAAM,KAAK,MAAMA,qBAAoB,MAAM,CAAC;AAClD,UAAM,SAAS,4BAA4B,UAAU,GAAG;AACxD,WAAO,OAAO,UAAU,OAAO,OAAO;AAAA,EACxC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAASD,qBAAoB,OAAuB;AAClD,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,KAAK;AAC5C,MAAI,SAAS;AACb,aAAW,QAAQ,MAAO,WAAU,OAAO,aAAa,IAAI;AAC5D,QAAM,SACJ,OAAO,SAAS,aACZ,KAAK,MAAM,IACX,OAAO,WAAW,cAChB,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,IACpC;AACR,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,4BAA4B;AACzD,SAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC1E;AAEA,SAASC,qBAAoB,OAAuB;AAClD,QAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACzD,QAAM,SAAS,OAAO;AAAA,IACpB,OAAO,UAAW,IAAK,OAAO,SAAS,KAAM;AAAA,IAC7C;AAAA,EACF;AACA,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,SAAS,KAAK,MAAM;AAC1B,UAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,aAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS;AAClD,YAAM,KAAK,IAAI,OAAO,WAAW,KAAK;AAAA,IACxC;AACA,WAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,EACvC;AACA,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,QAAQ,QAAQ,EAAE,SAAS,MAAM;AAAA,EACtD;AACA,QAAM,IAAI,MAAM,4BAA4B;AAC9C;;;ACrQA,SAAS,QAAAC,aAAY;AAed,IAAM,2BAA2B;AAExC,IAAM,iBAAiB;AAEhB,SAAS,6BACd,OACQ;AACR,QAAM,SAAS,2BAA2B,MAAM,KAAK;AACrD,SAAO,GAAG,wBAAwB,GAAGC;AAAA,IACnC,KAAK,UAAU,MAAM;AAAA,EACvB,CAAC;AACH;AAEO,SAAS,6BACd,SACsB;AACtB,QAAM,QAAQ,4BAA4B,OAAO;AACjD,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,kCAAkC;AAC9D,QAAM,UAAU,MAAM,MAAM,yBAAyB,MAAM;AAC3D,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAMC,qBAAoB,OAAO,CAAC;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AACA,QAAM,SAAS,2BAA2B,UAAU,GAAG;AACvD,MAAI,CAAC,OAAO,QAAS,OAAM,IAAI,MAAM,mCAAmC;AACxE,SAAO,OAAO;AAChB;AAEO,SAAS,4BAA4B,SAAgC;AAC1E,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,QAAQ,WAAW,wBAAwB,GAAG;AAChD,WAAO,QAAQ,MAAM,OAAO,CAAC,EAAE,CAAC,KAAK;AAAA,EACvC;AACA,SAAO,eAAe,KAAK,OAAO,IAAI,CAAC,KAAK;AAC9C;AAEO,IAAM,4BAA4B;AAGlC,IAAM,4BACX;AAGK,IAAM,iCAAiC;AAGvC,IAAM,kCAAkC;AAGxC,IAAM,qCAAqC;AAG3C,IAAM,6BAA6B;AAG1C,IAAM,WAAW;AAmDjB,eAAsB,4BACpB,OACA,QACiB;AACjB,QAAM,SAAS,MAAM,qBAAqB,KAAK;AAC/C,QAAM,MAAM,MAAM,OAAO,QAAQ,UAAU,MAAM,CAAC;AAClD,MAAI,IAAI,WAAW,oCAAoC;AACrD,UAAM,IAAI;AAAA,MACR,2BAA2B,IAAI,MAAM,uBAAuB,kCAAkC;AAAA,IAChG;AAAA,EACF;AACA,QAAM,MAAM,IAAI,WAAW,8BAA8B;AACzD,MAAI,IAAI,QAAQ,CAAC;AACjB,MAAI,IAAI,KAAK,+BAA+B;AAC5C,SAAO,GAAG,yBAAyB,GAAG,iBAAiB,GAAG,CAAC;AAC7D;AAQA,eAAsB,qBACpB,OACqB;AACrB,mBAAiB,MAAM,YAAY,YAAY;AAC/C,MAAI,MAAM,cAAc,GAAG;AACzB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,mBAAiB,MAAM,cAAc,cAAc;AACnD,QAAM,mBAAmB,MAAMC,QAAO,KAAK,MAAM,WAAW,CAAC,GAAG,MAAM,GAAG,EAAE;AAC3E,QAAM,cAAc,YAAY,MAAM,WAAW,EAAE,MAAM,GAAG,CAAC;AAC7D,QAAM,cAAc,YAAY,MAAM,WAAW,EAAE,MAAM,GAAG,CAAC;AAE7D,QAAM,SAAS,IAAI,WAAW,+BAA+B;AAC7D,QAAM,KAAK,IAAI,SAAS,OAAO,MAAM;AACrC,SAAO,CAAC,IAAI;AACZ,SAAO,CAAC,IAAI;AACZ,SAAO,IAAI,iBAAiB,CAAC;AAC7B,SAAO,IAAI,aAAa,EAAE;AAC1B,SAAO,IAAI,aAAa,EAAE;AAC1B,gBAAc,IAAI,IAAI,MAAM,UAAU;AACtC,gBAAc,IAAI,IAAI,MAAM,YAAY;AACxC,SAAO;AACT;AAMO,SAAS,UAAU,QAAgC;AACxD,MAAI,OAAO,WAAW,iCAAiC;AACrD,UAAM,IAAI;AAAA,MACR,0BAA0B,+BAA+B;AAAA,IAC3D;AAAA,EACF;AACA,QAAM,SAAS,KAAK,yBAAyB;AAC7C,QAAM,MAAM,IAAI,WAAW,OAAO,SAAS,OAAO,MAAM;AACxD,MAAI,IAAI,QAAQ,CAAC;AACjB,MAAI,IAAI,QAAQ,OAAO,MAAM;AAC7B,SAAO;AACT;AAIO,SAAS,4BACd,SAC8B;AAC9B,QAAM,QAAQ,6BAA6B,OAAO;AAClD,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,yBAAyB;AACrD,QAAM,UAAU,MAAM,MAAM,0BAA0B,MAAM;AAC5D,MAAI;AACJ,MAAI;AACF,YAAQ,iBAAiB,OAAO;AAAA,EAClC,QAAQ;AACN,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,MAAI,iBAAiB,KAAK,MAAM,SAAS;AACvC,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,MAAI,MAAM,WAAW,gCAAgC;AACnD,UAAM,IAAI;AAAA,MACR,oBAAoB,8BAA8B,eAAe,MAAM,MAAM;AAAA,IAC/E;AAAA,EACF;AACA,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,QAAQ,MAAM,CAAC;AACrB,MAAI,YAAY,4BAA4B;AAC1C,UAAM,IAAI,MAAM,+BAA+B,OAAO,EAAE;AAAA,EAC1D;AACA,MAAI,UAAU,GAAM;AAClB,UAAM,IAAI,MAAM,yCAAyC,KAAK,EAAE;AAAA,EAClE;AACA,QAAM,SAAS,MAAM,MAAM,GAAG,+BAA+B;AAC7D,QAAM,YAAY,MAAM,MAAM,+BAA+B;AAC7D,QAAM,KAAK,IAAI,SAAS,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;AACxE,QAAM,aAAa,aAAa,IAAI,EAAE;AACtC,MAAI,cAAc,GAAG;AACnB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsBC,YAAW,MAAM,MAAM,GAAG,EAAE,CAAC;AAAA,IACnD,sBAAsBA,YAAW,MAAM,MAAM,IAAI,EAAE,CAAC;AAAA,IACpD,sBAAsBA,YAAW,MAAM,MAAM,IAAI,EAAE,CAAC;AAAA,IACpD;AAAA,IACA,cAAc,aAAa,IAAI,EAAE;AAAA,IACjC;AAAA,IACA;AAAA,IACA,aAAa,UAAU,MAAM;AAAA,EAC/B;AACF;AAEO,SAAS,6BAA6B,SAAgC;AAC3E,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,QAAQ,WAAW,yBAAyB,GAAG;AACjD,WAAO,QAAQ,MAAM,OAAO,CAAC,EAAE,CAAC,KAAK;AAAA,EACvC;AACA,SAAO,SAAS,KAAK,OAAO,IAAI,CAAC,KAAK;AACxC;AASO,SAAS,4BACd,SACA,oBACS;AACT,MAAI;AACF,UAAM,SAAS,iBAAiB,kBAAkB;AAClD,WAAOC,MAAK,OAAO,QAAQ,WAAW,QAAQ,aAAa,QAAQ;AAAA,MACjE,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWO,SAAS,sBAAsB,UAAkC;AACtE,QAAM,MAAMA,MAAK,UAAU,UAAU,UAAU,KAAK;AACpD,QAAM,MAAM,IAAI,QAAQ,SAAS;AACjC,MAAI,IAAI,WAAW,oCAAoC;AACrD,UAAM,IAAI;AAAA,MACR,iCAA4B,IAAI,MAAM,oBAAoB,kCAAkC;AAAA,IAC9F;AAAA,EACF;AACA,SAAO;AACT;AAOA,SAAS,KAAK,GAAuB;AACnC,SAAO,IAAI,YAAY,EAAE,OAAO,CAAC;AACnC;AAEA,eAAeF,QAAO,OAAwC;AAI5D,QAAM,SACH,OAAO,eAAe,eAAe,WAAW,QAAQ,UACzD;AACF,MAAI,QAAQ;AACV,UAAM,SAAS,MAAM,OAAO,OAAO,WAAW,KAAK;AACnD,WAAO,IAAI,WAAW,MAAM;AAAA,EAC9B;AAEA,QAAM,EAAE,QAAQ,YAAY,IAAI,MAAM,OAAO,oBAAoB;AACjE,SAAO,YAAY,KAAK;AAC1B;AAEA,SAAS,YAAY,MAA0B;AAG7C,QAAM,MAAM,KAAK,QAAQ,MAAM,EAAE,EAAE,YAAY;AAC/C,MAAI,IAAI,WAAW,MAAM,CAAC,iBAAiB,KAAK,GAAG,GAAG;AACpD,UAAM,IAAI,MAAM,yBAAyB,IAAI,EAAE;AAAA,EACjD;AACA,QAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QAAI,CAAC,IAAI,SAAS,IAAI,UAAU,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;AAAA,EACvD;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAe,OAAqB;AAC5D,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAM,IAAI,MAAM,WAAW,KAAK,iCAAiC;AAAA,EACnE;AACA,MAAI,QAAQ,OAAO,kBAAkB;AACnC,UAAM,IAAI,MAAM,WAAW,KAAK,kCAAkC;AAAA,EACpE;AACF;AAEA,SAAS,iBAAiB,OAAe,OAAqB;AAC5D,mBAAiB,OAAO,KAAK;AAC7B,MAAI,QAAQ,iBAAgB;AAC1B,UAAM,IAAI,MAAM,WAAW,KAAK,uBAAuB;AAAA,EACzD;AACF;AAEA,SAAS,cAAc,IAAc,QAAgB,OAAqB;AAGxE,QAAM,OAAO,KAAK,MAAM,QAAQ,UAAW;AAC3C,QAAM,MAAM,UAAU;AACtB,KAAG,UAAU,QAAQ,MAAM,KAAK;AAChC,KAAG,UAAU,SAAS,GAAG,KAAK,KAAK;AACrC;AAEA,SAAS,aAAa,IAAc,QAAwB;AAC1D,QAAM,OAAO,GAAG,UAAU,QAAQ,KAAK;AACvC,QAAM,MAAM,GAAG,UAAU,SAAS,GAAG,KAAK;AAC1C,MAAI,OAAO,SAAY;AACrB,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAO,OAAO,aAAc;AAC9B;AAEA,SAAS,cAAc,IAAc,QAAgB,OAAqB;AACxE,QAAM,OAAO,KAAK,MAAM,QAAQ,KAAO;AACvC,QAAM,MAAM,QAAQ;AACpB,KAAG,UAAU,QAAQ,MAAM,KAAK;AAChC,KAAG,UAAU,SAAS,GAAG,KAAK,KAAK;AACrC;AAEA,SAAS,aAAa,IAAc,QAAwB;AAC1D,QAAM,OAAO,GAAG,UAAU,QAAQ,KAAK;AACvC,QAAM,MAAM,GAAG,UAAU,SAAS,GAAG,KAAK;AAC1C,SAAO,OAAO,QAAU;AAC1B;AAEA,SAASC,YAAW,OAA2B;AAC7C,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,WAAO,MAAM,CAAC,EAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAA2B;AACnD,MAAI;AACJ,MAAI,OAAO,WAAW,aAAa;AACjC,aAAS,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAAA,EAC/C,OAAO;AACL,QAAI,SAAS;AACb,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,IACzC;AACA,QAAI,OAAO,SAAS,YAAY;AAC9B,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,aAAS,KAAK,MAAM;AAAA,EACtB;AACA,SAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC1E;AAEA,SAASH,qBAAoB,OAAuB;AAClD,SAAO,iBAAiB,KAAK,KAAK,CAAC;AACrC;AAEA,SAASC,qBAAoB,OAAuB;AAClD,SAAO,IAAI,YAAY,EAAE,OAAO,iBAAiB,KAAK,CAAC;AACzD;AAEA,SAAS,iBAAiB,OAA2B;AACnD,QAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACzD,QAAM,SAAS,OAAO;AAAA,IACpB,OAAO,UAAW,IAAK,OAAO,SAAS,KAAM;AAAA,IAC7C;AAAA,EACF;AACA,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,IAAI,WAAW,OAAO,KAAK,QAAQ,QAAQ,CAAC;AAAA,EACrD;AACA,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,QAAM,SAAS,KAAK,MAAM;AAC1B,QAAM,MAAM,IAAI,WAAW,OAAO,MAAM;AACxC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,KAAI,CAAC,IAAI,OAAO,WAAW,CAAC;AACpE,SAAO;AACT;;;AC/bA,SAAS,KAAAI,WAAS;AAMlB,IAAM,cAAcC,IAAE,OAAO,EAAE,MAAM,SAAS;AAC9C,IAAM,gBAAgBA,IAAE,MAAM;AAAA,EAC5BA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAC1BA,IAAE,OAAO,EAAE,MAAM,iBAAiB;AACpC,CAAC;AACD,IAAM,WAAWA,IACd,OAAO,EACP,KAAK,EACL,OAAO,CAAC,EACR,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC;AACnC,IAAM,WAAWA,IAAE,OAAOA,IAAE,QAAQ,CAAC;AAE9B,IAAM,gBAAgB,CAAC,QAAQ,UAAU;AAGzC,IAAM,kBAAkB,CAAC,iBAAiB,mBAAmB;AAG7D,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,6BAA6B,CAAC,UAAU,OAAO;AAIrD,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,8BAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF;AAIO,IAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,uBAAuBA,IAAE,OAAO;AAAA,EAC3C,kBAAkBA,IAAE,OAAO,EAAE,KAAK;AAAA,EAClC,MAAMA,IAAE,KAAK,aAAa;AAAA,EAC1B,eAAeA,IAAE,KAAK,eAAe;AAAA,EACrC,aAAaA,IAAE,OAAO;AAAA,EACtB,UAAUA,IAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,mBAAmBA,IAAE,OAAO,EAAE,SAAS;AAAA,EACvC,QAAQA,IAAE,KAAK,wBAAwB;AAAA,EACvC,UAAU;AAAA,EACV,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,kCAAkCA,IAAE,OAAO;AAAA,EACtD,MAAMA,IAAE,KAAK,aAAa;AAAA,EAC1B,eAAeA,IAAE,KAAK,eAAe;AAAA,EACrC,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC7C,UAAUA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACpD,mBAAmBA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAC7D,UAAU,SAAS,SAAS;AAC9B,CAAC;AAOM,IAAM,iCAAiCA,IAAE,OAAO;AAAA,EACrD,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC7C,WAAWA,IAAE,KAAK,0BAA0B,EAAE,SAAS;AAAA,EACvD,QAAQA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACnC,WAAWA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACtC,aAAa;AAAA,EACb,UAAU;AAAA,EACV,eAAeA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACzD,kBAAkB,SAAS,SAAS;AACtC,CAAC;AAKM,IAAM,uBAAuBA,IAAE,OAAO;AAAA,EAC3C,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,QAAQA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACnC,WAAWA,IAAE,KAAK,0BAA0B;AAAA,EAC5C,UAAUA,IAAE,OAAO;AAAA,EACnB,aAAa;AAAA,EACb,aAAaA,IAAE,OAAO;AAAA,EACtB,QAAQA,IAAE,KAAK,wBAAwB;AAAA,EACvC,eAAeA,IAAE,OAAO;AAAA,EACxB,WAAWA,IAAE,OAAO;AAAA,EACpB,kBAAkB;AAAA,EAClB,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,4BAA4BA,IAAE,OAAO;AAAA,EAChD,SAAS;AAAA,EACT,UAAUA,IAAE,QAAQ;AACtB,CAAC;AAKM,IAAM,0BAA0BA,IAAE,OAAO;AAAA,EAC9C,eAAeA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,UAAUA,IAAE,OAAO;AAAA,EACnB,eAAeA,IAAE,OAAO;AAAA,EACxB,aAAaA,IAAE,OAAO;AAAA,EACtB,QAAQA,IAAE,KAAK,2BAA2B;AAAA,EAC1C,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACtD,UAAU;AAAA,EACV,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,qCAAqCA,IAAE,OAAO;AAAA,EACzD,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,UAAUA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACzC,eAAeA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAC9C,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC7C,UAAU,SAAS,SAAS;AAC9B,CAAC;AAKM,IAAM,qCAAqCA,IAAE,OAAO;AAAA,EACzD,OAAOA,IAAE,MAAM,uBAAuB;AACxC,CAAC;AAOM,IAAM,mBAAmBA,IAAE,OAAO;AAAA,EACvC,cAAcA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC9B,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,QAAQA,IAAE,OAAO,EAAE,KAAK;AAAA,EACxB,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAeA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,UAAUA,IAAE,OAAO;AAAA,EACnB,aAAa;AAAA,EACb,OAAOA,IAAE,KAAK,iBAAiB;AAAA,EAC/B,gBAAgBA,IAAE,OAAO;AAAA,EACzB,aAAaA,IAAE,OAAO,EAAE,SAAS;AAAA,EACjC,WAAWA,IAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,WAAWA,IAAE,OAAO;AAAA,EACpB,kBAAkBA,IAAE,OAAO,EAAE,SAAS;AAAA,EACtC,UAAU;AAAA,EACV,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC;AAGM,IAAM,8BAA8BA,IAAE,OAAO;AAAA,EAClD,eAAeA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,aAAa;AAAA,EACb,UAAU;AAAA,EACV,gBAAgBA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAChD,UAAU,SAAS,SAAS;AAC9B,CAAC;AAGM,IAAM,+BAA+BA,IAAE,OAAO;AAAA,EACnD,YAAY;AAAA,EACZ,UAAUA,IAAE,QAAQ;AACtB,CAAC;AAOM,IAAM,yBAAyBA,IAAE,OAAO;AAAA,EAC7C,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC7C,cAAcA,IAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACzC,OAAOA,IAAE,KAAK,CAAC,aAAa,cAAc,QAAQ,QAAQ,CAAC;AAAA,EAC3D,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACxD,aAAaA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAChD,gBAAgBA,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACpD,kBAAkB,SAAS,SAAS;AACtC,CAAC;AAGM,IAAM,gCAAgCA,IAAE,OAAO;AAAA,EACpD,YAAY;AAAA,EACZ,UAAUA,IAAE,QAAQ;AACtB,CAAC;AAOM,IAAM,6BAA6BA,IAAE,OAAO;AAAA,EACjD,WAAWA,IAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,UAAUA,IAAE,OAAO;AAAA,EACnB,QAAQA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACrC,MAAMA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACnC,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,0BAA0B;AAAA,EAC1B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,2BAA2B;AAAA,EAC3B,gBAAgB;AAAA,EAChB,eAAeA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC9C,CAAC;AAsBM,SAAS,2BACd,SACsB;AACtB,SAAO;AAAA,IACL,eAAe,OAAO,UAAU;AAC9B,YAAM,OAAO,+BAA+B,MAAM,KAAK;AACvD,YAAM,MAAM,MAAM,QAAQ,QAAQ;AAAA,QAChC,QAAQ;AAAA,QACR,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AACD,aAAO,0BAA0B,MAAM,GAAG;AAAA,IAC5C;AAAA,IACA,mBAAmB,OAAO,UAAU;AAClC,YAAM,OAAO,uBAAuB,MAAM,KAAK;AAC/C,YAAM,MAAM,MAAM,QAAQ,QAAQ;AAAA,QAChC,QAAQ;AAAA,QACR,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AACD,aAAO,8BAA8B,MAAM,GAAG;AAAA,IAChD;AAAA,IACA,gBAAgB,OAAO,UAAU;AAC/B,YAAM,KAAK,IAAI,gBAAgB;AAAA,QAC7B,UAAU,MAAM;AAAA,MAClB,CAAC;AACD,UAAI,OAAO,MAAM,WAAW;AAC1B,WAAG,IAAI,UAAU,OAAO,MAAM,MAAM,CAAC;AACvC,UAAI,OAAO,MAAM,SAAS,SAAU,IAAG,IAAI,QAAQ,OAAO,MAAM,IAAI,CAAC;AACrE,YAAM,MAAM,MAAM,QAAQ,QAAQ;AAAA,QAChC,QAAQ;AAAA,QACR,MAAM,qCAAqC,GAAG,SAAS,CAAC;AAAA,MAC1D,CAAC;AACD,aAAO,2BAA2B,MAAM,GAAG;AAAA,IAC7C;AAAA,EACF;AACF;AAuBO,SAAS,gCACd,MAC2B;AAC3B,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAE9C,iBAAe,KACb,QACA,MACA,MACA,QACY;AACZ,UAAMC,QAAoB;AAAA,MACxB;AAAA,MACA,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACxC;AACA,QAAI,SAAS,QAAW;AACtB,MAAAA,MAAK,OAAO,KAAK,UAAU,IAAI;AAC/B,MAAAA,MAAK,UAAU,EAAE,GAAGA,MAAK,SAAS,gBAAgB,mBAAmB;AAAA,IACvE;AACA,UAAM,OAAO,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,IAAIA,KAAI;AACtD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACJ,QAAI,MAAM;AACR,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AACN,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,YAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,YAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,IACxD;AACA,WAAO,OAAO,GAAG;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,kBAAkB,MAChB;AAAA,MAAK;AAAA,MAAO;AAAA,MAA8B;AAAA,MAAW,CAAC,QACpD,mCAAmC,MAAM,GAAG;AAAA,IAC9C;AAAA,IACF,mBAAmB,CAAC,UAClB;AAAA,MACE;AAAA,MACA;AAAA,MACA,mCAAmC,MAAM,KAAK;AAAA,MAC9C,CAAC,QAAQ,wBAAwB,MAAM,GAAG;AAAA,IAC5C;AAAA,IACF,mBAAmB,CAAC,kBAClB;AAAA,MACE;AAAA,MACA,8BAA8B,mBAAmB,aAAa,CAAC;AAAA,MAC/D,CAAC;AAAA,MACD,CAAC,QAAQ,wBAAwB,MAAM,GAAG;AAAA,IAC5C;AAAA,IACF,oBAAoB,CAAC,kBACnB;AAAA,MACE;AAAA,MACA,8BAA8B,mBAAmB,aAAa,CAAC;AAAA,MAC/D,CAAC;AAAA,MACD,CAAC,QAAQ,wBAAwB,MAAM,GAAG;AAAA,IAC5C;AAAA,IACF,kBAAkB,CAAC,UACjB;AAAA,MACE;AAAA,MACA;AAAA,MACA,4BAA4B,MAAM,KAAK;AAAA,MACvC,CAAC,QAAQ,6BAA6B,MAAM,GAAG;AAAA,IACjD;AAAA,IACF,eAAe,CAAC,iBACd;AAAA,MACE;AAAA,MACA,sBAAsB,mBAAmB,YAAY,CAAC;AAAA,MACtD;AAAA,MACA,CAAC,QAAQ,iBAAiB,MAAM,GAAG;AAAA,IACrC;AAAA,EACJ;AACF;AAqBO,SAAS,gCACd,MAC2B;AAC3B,QAAM,YAAY,KAAK,aAAa,WAAW;AAC/C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAC9C,SAAO;AAAA,IACL,eAAe,OAAO,kBAAkB,UAAU;AAChD,YAAM,OAAO;AAAA,QACX;AAAA,QACA,GAAG,gCAAgC,MAAM,KAAK;AAAA,MAChD;AACA,YAAM,OAAO,MAAM,UAAU,GAAG,OAAO,wBAAwB;AAAA,QAC7D,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AACD,YAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,UAAI;AACJ,UAAI,MAAM;AACR,YAAI;AACF,gBAAM,KAAK,MAAM,IAAI;AAAA,QACvB,QAAQ;AACN,gBAAM;AAAA,QACR;AAAA,MACF;AACA,UAAI,CAAC,KAAK,IAAI;AACZ,cAAM,OACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACV,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,QAAQ,KAAK,MAAM;AACzB,cAAM,UACJ,OACA,OAAO,QAAQ,YACf,aAAa,OACb,OAAQ,IAA6B,YAAY,WAC5C,IAA4B,UAC7B,8BAA8B,KAAK,MAAM;AAC/C,cAAM,IAAI,aAAa,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,MACxD;AACA,aAAO,qBAAqB,MAAM,GAAG;AAAA,IACvC;AAAA,EACF;AACF;;;AC3fA,SAAS,KAAAC,WAAS;AAkCX,IAAM,2BAA2B;AACjC,IAAM,wBAAwB;AAC9B,IAAM,2BAA2B,GAAG,wBAAwB,OAAO,qBAAqB;AAE/F,IAAM,iBAAiB;AAEhB,IAAM,uBAAuBC,IAAE,OAAO;AAAA,EAC3C,GAAGA,IAAE,QAAQ,qBAAqB;AAAA,EAClC,GAAGA,IAAE,OAAO,EAAE,MAAM,gBAAgB,uBAAuB;AAAA,EAC3D,KAAKA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC9B,KAAKA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC9B,KAAKA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAClC,KAAKA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAC1C,OAAOA,IACJ,OAAO,EACP,IAAI,CAAC,EACL,IAAI,EAAE,EACN,MAAM,oBAAoB,wBAAwB;AACvD,CAAC;AAYM,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACE,SACO,MAOP;AACA,UAAM,OAAO;AARN;AASP,SAAK,OAAO;AAAA,EACd;AAAA,EAVS;AAWX;AAIO,SAAS,gBAAgB,OAA2B;AACzD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,QAAO,OAAO,aAAa,MAAM,CAAC,CAAC;AAE1E,QAAM,MACJ,OAAO,SAAS,aACZ,KAAK,GAAG,IACR,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAC1C,SAAO,IAAI,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,EAAE;AACtE;AAEO,SAAS,gBAAgB,GAAuB;AACrD,QAAM,MAAM,EAAE,SAAS,MAAM,IAAI,KAAK,IAAI,OAAO,IAAK,EAAE,SAAS,CAAE;AACnE,QAAM,MAAM,EAAE,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,IAAI;AACtD,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,MAAM,KAAK,GAAG;AACpB,UAAM,MAAM,IAAI,WAAW,IAAI,MAAM;AACrC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,KAAI,CAAC,IAAI,IAAI,WAAW,CAAC;AAC9D,WAAO;AAAA,EACT;AACA,SAAO,IAAI,WAAW,OAAO,KAAK,KAAK,QAAQ,CAAC;AAClD;AAIO,SAAS,kBAAqB,OAQjB;AAClB,MAAI,CAAC,eAAe,KAAK,MAAM,IAAI,GAAG;AACpC,UAAM,IAAI;AAAA,MACR,0BAA0B,MAAM,IAAI;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,MAAM,mBAAmB,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACjE,QAAM,SAAyB;AAAA,IAC7B,GAAG;AAAA,IACH,GAAG,MAAM;AAAA,IACT,KAAK,MAAM;AAAA,IACX,KAAK,MAAM;AAAA,IACX;AAAA,IACA,GAAI,MAAM,qBAAqB,SAC3B,EAAE,KAAK,MAAM,iBAAiB,IAC9B,CAAC;AAAA,IACL,OAAO,MAAM;AAAA,EACf;AAEA,uBAAqB,MAAM,MAAM;AACjC,SAAO,EAAE,GAAG,QAAQ,MAAM,MAAM,KAAK;AACvC;AAEO,SAAS,aACd,MACA,YACmB;AACnB,QAAM,MAAM,eAAS,mBAAmB,IAAI,GAAG,UAAU;AACzD,SAAO,EAAE,MAAM,IAAI;AACrB;AAEO,SAAS,kBAAqB,QAAmC;AACtE,QAAM,YAAY,mBAAmB,OAAO,IAAI;AAChD,QAAM,UAAU,gBAAgB,SAAS;AAEzC,QAAM,WAAW,gBAAgB,OAAO,GAAG;AAC3C,QAAM,YAAY,gBAAgB,QAAQ;AAC1C,SAAO,GAAG,wBAAwB,GAAG,OAAO,KAAK,CAAC,IAAI,OAAO,IAAI,SAAS;AAC5E;AAUO,SAAS,kBAAkB,KAAiC;AACjE,MAAI,CAAC,IAAI,WAAW,wBAAwB,GAAG;AAC7C,UAAM,IAAI;AAAA,MACR,2BAA2B,wBAAwB;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,IAAI,MAAM,yBAAyB,MAAM;AACtD,QAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,kBAAkB,iCAAiC,aAAa;AAAA,EAC5E;AACA,QAAM,OAAO,KAAK,MAAM,GAAG,KAAK;AAChC,QAAM,UAAU,KAAK,MAAM,QAAQ,CAAC;AACpC,QAAM,MAAM,QAAQ,QAAQ,GAAG;AAC/B,MAAI,OAAO,KAAK,QAAQ,QAAQ,SAAS,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,eAAe,KAAK,IAAI,GAAG;AAC9B,UAAM,IAAI;AAAA,MACR,0BAA0B,IAAI;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,gBAAgB,QAAQ,MAAM,GAAG,GAAG,CAAC;AACvD,QAAM,WAAW,gBAAgB,QAAQ,MAAM,MAAM,CAAC,CAAC;AAGvD,MAAI,SAAS,SAAS,MAAM,SAAS,SAAS,IAAI;AAChD,UAAM,IAAI;AAAA,MACR,kCAAkC,SAAS,MAAM;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AAAA,EAC3D,QAAQ;AACN,UAAM,IAAI,kBAAkB,0BAA0B,cAAc;AAAA,EACtE;AAEA,QAAM,aAAa,qBAAqB,UAAU,QAAQ;AAC1D,MAAI,CAAC,WAAW,SAAS;AACvB,UAAM,IAAI;AAAA,MACR,wBAAwB,WAAW,MAAM,OAAO;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW,KAAK,MAAM,MAAM;AAC9B,UAAM,IAAI;AAAA,MACR,YAAY,IAAI,6BAA6B,WAAW,KAAK,CAAC;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM;AAAA;AAAA,IAEN,KAAK,gBAAgB,QAAQ;AAAA,EAC/B;AACF;AAEA,SAAS,gBAAgB,OAA2B;AAClD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAAA,EAC7C;AACA,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,QAAO,OAAO,aAAa,MAAM,CAAC,CAAC;AAC1E,SAAO,OAAO,SAAS,aAAa,KAAK,GAAG,IAAI;AAClD;AASO,SAAS,wBACd,SACA,kBACA,UAAiC,CAAC,GACzB;AACT,MAAI,QAAQ,kBAAkB,SAAS,QAAQ,KAAK,QAAQ,QAAW;AACrE,UAAM,MAAM,QAAQ,cAAc,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC9D,QAAI,QAAQ,KAAK,MAAM,KAAK;AAC1B,YAAM,IAAI,kBAAkB,wBAAwB,SAAS;AAAA,IAC/D;AAAA,EACF;AACA,SAAO,iBAAW,QAAQ,WAAW,QAAQ,KAAK,gBAAgB;AACpE;;;ACrQA,SAAS,KAAAC,WAAS;AAiBX,IAAM,iBAAiB;AAAA,EAC5B,+BAA+B;AAAA,EAC/B,SAAS;AAAA;AAAA,EAET,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,sBAAsB;AAAA,EACtB,WAAW;AAAA,EACX,MAAM;AAAA,EACN,UAAU;AACZ;AAIA,IAAM,YAAY,CAAC,WACjBC,IACG,OAAO,EACP;AAAA,EACC,IAAI,OAAO,gBAAgB,SAAS,CAAC,IAAI;AAAA,EACzC,YAAY,MAAM;AACpB;AAMG,IAAM,4CAA4CA,IAAE,OAAO;AAAA,EAChE,eAAe;AACjB,CAAC;AASM,IAAM,wBAAwBA,IAAE,OAAO;AAAA,EAC5C,WAAWA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACnC,kBAAkBA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAC1C,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAChD,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EACrC,YAAYA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,UAAUA,IAAE,QAAQ,KAAK;AAAA,EACzB,SAASA,IAAE,KAAK,CAAC,UAAU,sBAAsB,YAAY,KAAK,CAAC;AAAA,EACnE,aAAaA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACvC,aAAaA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAChD,MAAMA,IAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACnC,eAAe,UAAU,EAAE,EAAE,SAAS;AACxC,CAAC;AAID,IAAM,UAAUA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AACxC,IAAM,cAAcA,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAC9C,IAAM,iBAAiBA,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AACpD,IAAMC,YAAWD,IAAE,QAAQ,KAAK;AAChC,IAAM,OAAOA,IAAE,OAAO,EAAE,IAAI,GAAG;AAMxB,IAAM,kCAAkCA,IAAE,OAAO;AAAA,EACtD,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY,YAAY,SAAS;AAAA,EACjC,UAAUC;AAAA,EACV,MAAM,KAAK,SAAS;AAAA,EACpB,aAAa,YAAY,SAAS;AACpC,CAAC;AAQM,IAAM,8BAA8BD,IAAE,OAAO;AAAA,EAClD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAUC;AAAA,EACV,gBAAgB;AAAA,EAChB,aAAa;AACf,CAAC;AAMM,IAAM,6BAA6BD,IAAE,OAAO;AAAA,EACjD,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,UAAUC;AAAA,EACV,aAAa;AAAA,EACb,kBAAkB,QAAQ,SAAS;AACrC,CAAC;AAMM,IAAM,iCAAiCD,IAAE,OAAO;AAAA,EACrD,cAAc;AAAA,EACd,aAAa;AAAA,EACb,eAAeA,IAAE,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAUC;AAAA,EACV,aAAa;AACf,CAAC;AAQM,IAAM,+BAA+BD,IAAE,OAAO;AAAA,EACnD,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,UAAUC;AAAA,EACV,QAAQD,IAAE,KAAK;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,cAAc;AAAA,EACd,MAAM,KAAK,SAAS;AACtB,CAAC;AAQM,IAAM,mCAAmCA,IAAE,OAAO;AAAA,EACvD,SAAS;AAAA,EACT,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,UAAUC;AAAA,EACV,YAAY;AAAA,EACZ,SAAS,QAAQ,SAAS;AAAA,EAC1B,OAAO,QAAQ,SAAS;AAC1B,CAAC;AAQM,IAAM,0BAA0BD,IACpC,OAAO;AAAA,EACN,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,aAAa;AAAA,EACb,oBAAoBA,IAAE,OAAO,EAAE,IAAI;AAAA,EACnC,oBAAoBA,IAAE,OAAO,EAAE,IAAI;AAAA,EACnC,kBAAkB;AAAA,EAClB,UAAUC;AAAA,EACV,eAAe,UAAU,EAAE,EAAE,SAAS;AACxC,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,eAAe;AAAA,EAC9C,SAAS;AAAA,EACT,MAAM,CAAC,aAAa;AACtB,CAAC;AAOI,IAAM,qBAAqBD,IAC/B,OAAO;AAAA,EACN,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAUA,IAAE,KAAK,CAAC,cAAc,UAAU,WAAW,UAAU,SAAS,CAAC;AAAA,EACzE,OAAOA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAChC,aAAa;AAAA,EACb,cAAc,YAAY,SAAS;AAAA,EACnC,UAAUA,IACP;AAAA,IACCA,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IACxBA,IAAE,MAAM,CAACA,IAAE,OAAO,EAAE,IAAI,GAAG,GAAGA,IAAE,OAAO,GAAGA,IAAE,QAAQ,CAAC,CAAC;AAAA,EACxD,EACC,SAAS;AACd,CAAC,EACA;AAAA,EACC,CAAC,MAAM,EAAE,iBAAiB,UAAa,EAAE,eAAe,EAAE;AAAA,EAC1D;AAAA,IACE,SAAS;AAAA,IACT,MAAM,CAAC,cAAc;AAAA,EACvB;AACF;AAMK,IAAM,yBAAyBA,IAAE,OAAO;AAAA,EAC7C,eAAe;AAAA,EACf,WAAW;AAAA,EACX,WAAWA,IAAE,KAAK;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,gBAAgB,UAAU,EAAE;AAAA,EAC5B,cAAc;AAChB,CAAC;AAGM,IAAM,wBAAwB;AAAA,EACnC,CAAC,eAAe,6BAA6B,GAC3C;AAAA,EACF,CAAC,eAAe,OAAO,GAAG;AAAA,EAC1B,CAAC,eAAe,mBAAmB,GAAG;AAAA,EACtC,CAAC,eAAe,cAAc,GAAG;AAAA,EACjC,CAAC,eAAe,aAAa,GAAG;AAAA,EAChC,CAAC,eAAe,iBAAiB,GAAG;AAAA,EACpC,CAAC,eAAe,eAAe,GAAG;AAAA,EAClC,CAAC,eAAe,oBAAoB,GAAG;AAAA,EACvC,CAAC,eAAe,SAAS,GAAG;AAAA,EAC5B,CAAC,eAAe,IAAI,GAAG;AAAA,EACvB,CAAC,eAAe,QAAQ,GAAG;AAC7B;AAGO,IAAM,0BAA0B,oBAAI,IAAkB;AAAA,EAC3D,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AACjB,CAAC;AAEM,SAAS,oBAAoB,GAA8B;AAChE,SAAQ,OAAO,OAAO,cAAc,EAAe,SAAS,CAAC;AAC/D;AAEO,SAAS,uBAAuB,GAA8B;AACnE,SAAO,wBAAwB,IAAI,CAAiB;AACtD;;;AChQO,SAAS,kBAAqB,OASU;AAC7C,MAAI,CAAC,oBAAoB,MAAM,IAAI,GAAG;AACpC,UAAM,IAAI;AAAA,MACR,0BAA0B,MAAM,IAAI;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,uBAAuB,MAAM,IAAI,GAAG;AACvC,UAAM,IAAI;AAAA,MACR,iBAAiB,MAAM,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,sBAAsB,MAAM,IAAI;AAC/C,QAAM,aAAa,OAAO,MAAM,MAAM,IAAI;AAE1C,QAAM,OAAO,kBAAkB;AAAA,IAC7B,MAAM,MAAM;AAAA,IACZ,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM;AAAA,IACb,MAAM;AAAA,IACN,OAAO,MAAM;AAAA,IACb,iBAAiB,MAAM;AAAA,IACvB,kBAAkB,MAAM;AAAA,EAC1B,CAAC;AACD,QAAM,SAAS,aAAa,MAAM,MAAM,UAAU;AAClD,SAAO,EAAE,KAAK,kBAAkB,MAAM,GAAG,OAAO;AAClD;AAqBO,SAAS,kBACd,KACA,kBACA,UAAiC,CAAC,GACb;AACrB,QAAM,UAAU,kBAAkB,GAAG;AAErC,MAAI,CAAC,oBAAoB,QAAQ,IAAI,GAAG;AACtC,UAAM,IAAI;AAAA,MACR,0BAA0B,QAAQ,IAAI;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,uBAAuB,QAAQ,IAAI,GAAG;AACzC,UAAM,IAAI;AAAA,MACR,iBAAiB,QAAQ,IAAI;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,sBAAsB,QAAQ,IAAoB;AACjE,QAAM,aAAa,OAAO,UAAU,QAAQ,KAAK,IAAI;AACrD,MAAI,CAAC,WAAW,SAAS;AACvB,UAAM,IAAI;AAAA,MACR,0BAA0B,WAAW,MAAM,OAAO;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,wBAAwB,SAAS,kBAAkB,OAAO;AACrE,MAAI,CAAC,IAAI;AACP,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ;AAAA,IACd,KAAK,QAAQ;AAAA,IACb;AAAA,EACF;AACF;AAMO,SAAS,yBAAyB,OAQtC;AACD,SAAO,kBAAmC;AAAA,IACxC,GAAG;AAAA,IACH,MAAM,eAAe;AAAA,EACvB,CAAC;AACH;AAEO,SAAS,6CAA6C,OAQ1D;AACD,SAAO,kBAAuD;AAAA,IAC5D,GAAG;AAAA,IACH,MAAM,eAAe;AAAA,EACvB,CAAC;AACH;","names":["z","z","z","candidate","z","z","CurrencySchema","init","init","z","z","z","z","z","z","sha256","bytesToHex","z","sha256","hmac","bytesToHex","z","sha256Hex","bytesToHex","sha256","hmac","init","z","z","z","Base64Std","z","z","z","init","init","z","z","init","z","z","Base64Std","z","z","Base64Std","init","p256","sha256","ENCOUNTER_DOMAIN","bytesToHex","sha256","bytesToBase64","base64ToBytes","P256_SPKI_HEADER","p256","z","Base64Std","z","z","z","base64UrlEncodeUtf8","base64UrlDecodeUtf8","p256","base64UrlEncodeUtf8","base64UrlDecodeUtf8","sha256","bytesToHex","p256","z","z","init","z","z","z","z","Currency"]}