@nile-squad/nylonpay-ts 1.0.10 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +21 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -6
- package/dist/index.d.ts +21 -6
- package/dist/index.js +21 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -375,6 +375,7 @@ function parseError(error) {
|
|
|
375
375
|
|
|
376
376
|
// src/payment.ts
|
|
377
377
|
var STATUS_TO_EVENT = {
|
|
378
|
+
pending: "processing",
|
|
378
379
|
successful: "success",
|
|
379
380
|
failed: "failed",
|
|
380
381
|
processing: "processing",
|
|
@@ -398,6 +399,7 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
398
399
|
status: normalizeStatus(initialResponse.status),
|
|
399
400
|
transaction: null,
|
|
400
401
|
pollingTimer: null,
|
|
402
|
+
lastStatusEvent: null,
|
|
401
403
|
resolved: false,
|
|
402
404
|
pollAttempts: 0,
|
|
403
405
|
pollStartTime: Date.now(),
|
|
@@ -416,6 +418,7 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
416
418
|
function emitEvent(event, error, category, retryable) {
|
|
417
419
|
const data = {
|
|
418
420
|
event,
|
|
421
|
+
reference: state.reference,
|
|
419
422
|
transaction: state.transaction ?? void 0,
|
|
420
423
|
error,
|
|
421
424
|
category,
|
|
@@ -452,18 +455,17 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
452
455
|
return;
|
|
453
456
|
}
|
|
454
457
|
const newStatus = normalizeStatus(response.status);
|
|
455
|
-
const oldStatus = state.status;
|
|
456
458
|
state.status = newStatus;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
459
|
+
const event = statusToEvent(newStatus);
|
|
460
|
+
if (!event || event === state.lastStatusEvent) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
state.lastStatusEvent = event;
|
|
464
|
+
if (TERMINAL_STATES.has(newStatus)) {
|
|
465
|
+
await handleTerminalState(newStatus);
|
|
466
|
+
return;
|
|
466
467
|
}
|
|
468
|
+
emitEvent(event);
|
|
467
469
|
}
|
|
468
470
|
function handlePollError(error) {
|
|
469
471
|
const parsed = parseError(error);
|
|
@@ -517,6 +519,15 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
517
519
|
}, 0);
|
|
518
520
|
return;
|
|
519
521
|
}
|
|
522
|
+
const initialEvent = statusToEvent(state.status);
|
|
523
|
+
if (initialEvent) {
|
|
524
|
+
state.lastStatusEvent = initialEvent;
|
|
525
|
+
setTimeout(() => {
|
|
526
|
+
if (!state.resolved) {
|
|
527
|
+
emitEvent(initialEvent);
|
|
528
|
+
}
|
|
529
|
+
}, 0);
|
|
530
|
+
}
|
|
520
531
|
scheduleNextPoll();
|
|
521
532
|
}
|
|
522
533
|
function stopUpdates() {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pubsub.ts","../src/sdk.config.ts","../src/fingerprint.ts","../src/nonce.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.ts","../src/phone.ts","../src/verify-webhook.ts","../src/sdk.ts","../src/create-nylon-pay.ts"],"names":["type","platform","arch","release","hostname","createHash","randomBytes","createHmac","timingSafeEqual","Err","Ok","delay","safeTry"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Simple internal pubsub/event emitter for SDK payment lifecycle events.\n * Functional implementation without classes.\n *\n * @see Spec 2 section 2 - \"emits events such as nylonpay.on('success', (data) => {})\"\n *\n * @example\n * ```ts\n * const emitter = createEmitter<PaymentEvent>();\n * emitter.on(\"success\", (data) => console.log(data));\n * emitter.emit(\"success\", { event: \"success\", timestamp: \"...\" });\n * emitter.off(\"success\", handler);\n * ```\n */\n\n/**\n * Handler function type for event listeners.\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\n/**\n * Internal state for the emitter.\n * @internal\n */\ninterface EmitterState<T> {\n listeners: Map<T, Set<EventHandler<T>>>;\n}\n\n/**\n * Create a new event emitter instance.\n *\n * @returns Emitter with on/off/emit methods\n *\n * @example\n * ```ts\n * const emitter = createEmitter<string>();\n * const unsub = emitter.on(\"hello\", (msg) => console.log(msg));\n * emitter.emit(\"hello\", \"world\");\n * unsub(); // remove listener\n * ```\n */\nexport function createEmitter<T extends string>() {\n const state: EmitterState<T> = {\n listeners: new Map(),\n };\n\n /**\n * Subscribe to an event.\n * Returns an unsubscribe function for convenience.\n */\n function on(event: T, handler: EventHandler): () => void {\n if (!state.listeners.has(event)) {\n state.listeners.set(event, new Set());\n }\n state.listeners.get(event)?.add(handler as EventHandler<unknown>);\n return () => off(event, handler);\n }\n\n /**\n * Subscribe to an event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal payment events (e.g. \"successful\", \"failed\").\n * Returns the emitter for chaining.\n */\n function once(event: T, handler: EventHandler): typeof emitter {\n const wrapper: EventHandler = (data) => {\n off(event, wrapper);\n handler(data);\n };\n on(event, wrapper);\n return emitter;\n }\n\n /**\n * Unsubscribe from an event.\n */\n function off(event: T, handler: EventHandler): void {\n const handlers = state.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<unknown>);\n }\n }\n\n /**\n * Emit an event with data to all listeners.\n * Handlers are called synchronously in subscription order.\n */\n function emit(event: T, data: unknown): void {\n const handlers = state.listeners.get(event);\n if (!handlers || handlers.size === 0) return;\n for (const handler of handlers) {\n try {\n (handler as EventHandler<unknown>)(data);\n } catch {\n // Swallow handler errors to prevent one bad handler\n // from breaking the entire event chain\n }\n }\n }\n\n /**\n * Remove all listeners for a specific event, or all events if no event specified.\n */\n function clear(event?: T): void {\n if (event) {\n state.listeners.delete(event);\n } else {\n state.listeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event.\n */\n function listenerCount(event: T): number {\n return state.listeners.get(event)?.size ?? 0;\n }\n\n const emitter = { on, once, off, emit, clear, listenerCount };\n return emitter;\n}\n\n/**\n * Type for the emitter interface returned by createEmitter.\n */\nexport type Emitter<T extends string> = ReturnType<typeof createEmitter<T>>;\n","/** Default production backend URL */\nexport const DEFAULT_BASE_URL =\n \"https://api.nylonpay.nilesquad.com/api/services\";\n\n/** Default request timeout (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default max retry attempts for transport failures */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** Default polling interval between status checks (2 seconds) */\nexport const DEFAULT_MAX_POLL_INTERVAL_MS = 2_000;\n\n/** Default max total polling duration before timing out (5 minutes) */\nexport const DEFAULT_MAX_POLL_DURATION_MS = 300_000;\n\n/** Default max polling attempts before giving up */\nexport const DEFAULT_MAX_POLL_ATTEMPTS = 150;\n\n/**\n * Random jitter (ms) added to each poll interval so many concurrent payments\n * don't synchronise into a thundering herd on the status endpoint.\n */\nexport const POLL_JITTER_MS = 250;\n\n/** Nile.js service name for all SDK operations */\nexport const SDK_SERVICE = \"sdk\";\n\n/** Maps SDK operation names to backend action names */\nexport const SDK_ACTIONS = {\n collectPayment: \"sdk-collect-payment\",\n collectPaymentAndResolve: \"sdk-collect-payment-and-resolve\",\n makePayout: \"sdk-make-payout\",\n makePayoutAndResolve: \"sdk-make-payout-and-resolve\",\n getStatus: \"sdk-get-status\",\n getTransaction: \"sdk-get-transaction\",\n verifyPhone: \"sdk-verify-phone\",\n createInvoice: \"sdk-create-invoice\",\n} as const;\n\n/** HTTP status codes that trigger retries */\nexport const RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\n","/**\n * Server fingerprint generation for SDK requests.\n * Provides a stable identifier based on runtime environment.\n *\n * @see Spec 2 section 1 - \"a server fingerprint based on runtime, os, etc\"\n */\n\nimport { createHash } from \"node:crypto\";\nimport { arch, hostname, platform, release, type } from \"node:os\";\n\n/**\n * Generate a server fingerprint based on runtime environment.\n * This provides a stable identifier for the server making requests.\n * The fingerprint is a SHA-256 hash of system characteristics.\n *\n * @returns Hex-encoded SHA-256 hash of system info\n *\n * @example\n * ```ts\n * const fingerprint = generateFingerprint();\n * // => \"e3b0c44298fc1c149afbf4c8996fb924...\"\n * ```\n */\nexport function generateFingerprint(): string {\n const components = [\n `type:${type()}`,\n `platform:${platform()}`,\n `arch:${arch()}`,\n `release:${release()}`,\n `hostname:${hostname()}`,\n `node:${process.versions.node}`,\n `v8:${process.versions.v8}`,\n ].join(\"|\");\n\n return createHash(\"sha256\").update(components).digest(\"hex\");\n}\n","/**\n * Cryptographically secure nonce generation for SDK requests.\n *\n * @see Spec 2 section 1 - \"Internally the sdk generates a nounce\"\n */\n\nimport { randomBytes } from \"node:crypto\";\n\n/**\n * Generate a cryptographically secure random nonce.\n * Uses Node.js crypto.randomBytes for security.\n *\n * @param length - Byte length of the nonce (default: 16 = 32 hex chars)\n * @returns Hex-encoded random string\n *\n * @example\n * ```ts\n * const nonce = generateNonce();\n * // => \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"\n * ```\n */\nexport function generateNonce(length = 16): string {\n return randomBytes(length).toString(\"hex\");\n}\n","/**\n * HMAC-SHA256 signature creation for SDK requests.\n * Must match the backend's verification logic in verify-signature.ts.\n *\n * Signature payload format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * @see backend/src/services/sdk/verify-signature.ts\n * @see Spec 2 section 1 - \"creates a signature using these values and the api secret (HMAC 256)\"\n */\n\nimport { createHmac } from \"node:crypto\";\n\n/**\n * Recursively sort object keys by Unicode code point for deterministic JSON.\n *\n * The comparison MUST be by UTF-16 code unit (the JavaScript `<` operator), the\n * canonicalization rule from RFC 8785 (JSON Canonicalization Scheme). A\n * locale-sensitive comparison (e.g. `localeCompare`) is forbidden: its order\n * depends on the runtime's locale/ICU data, so two parties could canonicalize\n * the same payload to different bytes and fail signature verification on valid\n * traffic. Must match backend's createCanonicalPayload function byte-for-byte.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\n */\n/** Compare two keys by UTF-16 code unit (RFC 8785), never by locale. */\nfunction compareByCodePoint(first: string, second: string): number {\n if (first < second) {\n return -1;\n }\n if (first > second) {\n return 1;\n }\n return 0;\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => sortValue(entry));\n }\n\n if (value && typeof value === \"object\") {\n const sortedEntries = Object.entries(value as Record<string, unknown>).sort(\n ([firstKey], [secondKey]) => compareByCodePoint(firstKey, secondKey),\n );\n\n return Object.fromEntries(\n sortedEntries.map(([entryKey, entryValue]) => [\n entryKey,\n sortValue(entryValue),\n ]),\n );\n }\n\n return value;\n}\n\n/**\n * Create a canonical JSON string from a payload, per RFC 8785 (JCS): object keys\n * sorted by Unicode code point, no insignificant whitespace. Numbers and strings\n * serialize via `JSON.stringify`, whose V8 output already matches the JCS rules\n * (ECMAScript number-to-string and minimal JSON string escaping).\n */\nexport function createCanonicalPayload(payload: unknown): string {\n return JSON.stringify(sortValue(payload));\n}\n\n/**\n * Build the signature payload string.\n * Format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * The fingerprint is included in the signature to prevent tampering\n * with server identity information.\n *\n * @see backend/src/services/sdk/verify-signature.ts:createSignaturePayload\n */\nexport function createSignaturePayload(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n timestamp: string;\n}): string {\n return `${input.fingerprint}.${input.nonce}.${input.timestamp}.${createCanonicalPayload(input.payload)}`;\n}\n\n/**\n * Create an HMAC-SHA256 signature for SDK request authentication.\n *\n * The signature includes the server fingerprint to ensure the request\n * origin cannot be spoofed. The fingerprint contains runtime/OS info\n * that is bound to this specific server instance.\n *\n * @param input.fingerprint - Server fingerprint (included in signature)\n * @param input.nonce - Random nonce for replay protection\n * @param input.timestamp - Unix timestamp in milliseconds\n * @param input.payload - Request body (will be canonicalized)\n * @param input.secret - API secret for signing\n * @returns Hex-encoded HMAC-SHA256 signature\n */\nexport function createSignature(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n secret: string;\n timestamp: string;\n}): string {\n const payload = createSignaturePayload(input);\n\n return createHmac(\"sha256\", input.secret).update(payload).digest(\"hex\");\n}\n\n/**\n * Create a timestamp string in milliseconds.\n * Used as part of the signature payload.\n */\nexport function createTimestamp(): string {\n return Date.now().toString();\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { createCanonicalPayload } from \"./signature\";\n\n/**\n * Verify an authenticated backend response body before exposing it to SDK\n * consumers so tampered payloads are rejected consistently.\n *\n * @param data - Response payload without the `_responseSignature` field\n * @param signature - Hex-encoded HMAC-SHA256 signature from the backend\n * @param secret - API secret used for request authentication\n * @returns True when the signature matches the payload\n */\nexport function verifyResponseSignature(\n data: unknown,\n signature: string,\n secret: string,\n): boolean {\n const expectedSignature = createHmac(\"sha256\", secret)\n .update(createCanonicalPayload(data))\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(providedBuffer, expectedBuffer);\n}\n","/**\n * HTTP transport layer for SDK communication with the Nylon Pay backend.\n * Handles the Nile.js envelope format, HMAC request signing, response\n * signature verification, retries, and timeouts.\n *\n * @internal\n */\n\nimport { Err, Ok, type Result } from \"slang-ts\";\nimport { generateFingerprint } from \"./fingerprint\";\nimport { generateNonce } from \"./nonce\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n RETRYABLE_STATUS_CODES,\n SDK_SERVICE,\n} from \"./sdk.config\";\nimport { createSignature, createTimestamp } from \"./signature\";\nimport type { SdkError, SdkErrorCategory, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\n\n/** Known failure categories the server tags onto error messages. */\nconst KNOWN_CATEGORIES = new Set<SdkErrorCategory>([\n \"auth\",\n \"validation\",\n \"limit\",\n \"rate_limit\",\n \"account\",\n \"provider\",\n \"duplicate\",\n \"not_found\",\n \"internal\",\n \"network\",\n \"timeout\",\n]);\n\n/** HTTP status → category for errors that aren't server-tagged. */\nconst STATUS_CATEGORY: Record<number, SdkErrorCategory> = {\n 408: \"timeout\",\n 429: \"rate_limit\",\n};\n\n/** Matches the server's ` -- error-type: <category>` message suffix. */\nconst ERROR_TYPE_SUFFIX = /^(.*?)\\s*--\\s*error-type:\\s*([a-z_]+)\\s*$/is;\n\n/**\n * Split the server's tagged category off an error message. The backend appends\n * ` -- error-type: <category>` to every SDK error (the only channel available —\n * Nile returns 200/400 only and drops the response `data` on failures). The\n * leading `[logId]` and human text are preserved as the message.\n */\nfunction parseCategoryFromMessage(message: string): {\n category: SdkErrorCategory | null;\n message: string;\n} {\n const match = ERROR_TYPE_SUFFIX.exec(message);\n if (match?.[2] && KNOWN_CATEGORIES.has(match[2] as SdkErrorCategory)) {\n return {\n category: match[2] as SdkErrorCategory,\n message: match[1] ?? message,\n };\n }\n return { category: null, message };\n}\n\n/** Build a structured SdkError from an HTTP error body's message + status. */\nfunction buildHttpError(params: {\n message: string;\n statusCode: number;\n}): SdkError {\n const parsed = parseCategoryFromMessage(params.message);\n const category: SdkErrorCategory =\n parsed.category ??\n STATUS_CATEGORY[params.statusCode] ??\n (params.statusCode >= 500 ? \"internal\" : \"validation\");\n return {\n category,\n message: parsed.message,\n retryable: RETRYABLE_STATUS_CODES.has(params.statusCode),\n };\n}\n\n/**\n * Convert a structured SdkError into a throwable Error that still carries the\n * category and retryable flag. Used by async operations that throw on\n * initiation failure (invalid key, etc.) so merchants can `catch (e)` and read\n * `e.category`.\n */\nexport function createSdkError(error: SdkError): Error & SdkError {\n return Object.assign(new Error(error.message), {\n category: error.category,\n retryable: error.retryable,\n });\n}\n\n/** Calculate exponential backoff delay with jitter. */\nfunction calculateBackoff(attempt: number): number {\n const base = 2 ** attempt * 1000;\n const jitter = Math.random() * 500;\n return base + jitter;\n}\n\n/** Promise-based delay. */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Strip _responseSignature from a payload and return it separately. */\nfunction stripResponseSignature<T>(payload: T): {\n data: T;\n responseSignature: string | null;\n} {\n if (\n !payload ||\n typeof payload !== \"object\" ||\n !(\"_responseSignature\" in payload)\n ) {\n return { data: payload, responseSignature: null };\n }\n\n const { _responseSignature, ...rest } = payload as Record<string, unknown>;\n\n return {\n data: rest as T,\n responseSignature:\n typeof _responseSignature === \"string\" ? _responseSignature : null,\n };\n}\n\n/** Build the Nile.js request envelope. */\nfunction buildEnvelope({\n action,\n payload,\n}: TransportRequest): Record<string, unknown> {\n return {\n intent: \"execute\",\n service: SDK_SERVICE,\n action,\n payload: {\n ...(payload as Record<string, unknown>),\n _fingerprint: CACHED_FINGERPRINT,\n },\n };\n}\n\n/**\n * Build auth headers for a request.\n *\n * The signature is computed over the inner `payload` (the operation input plus\n * `_fingerprint`), NOT the full Nile envelope. This matches the server, which\n * verifies the signature against the raw request payload — see the Transport\n * Contract in the Nylon Pay SDK Spec (https://github.com/nile-squad/specs).\n */\nfunction buildAuthHeaders({\n apiKey,\n apiSecret,\n payload,\n}: {\n apiKey: string;\n apiSecret: string;\n payload: unknown;\n}): Record<string, string> {\n const nonce = generateNonce();\n const timestamp = createTimestamp();\n const signature = createSignature({\n fingerprint: CACHED_FINGERPRINT,\n nonce,\n timestamp,\n payload,\n secret: apiSecret,\n });\n\n return {\n \"content-type\": \"application/json\",\n \"x-nylon-key\": apiKey,\n \"x-nylon-nonce\": nonce,\n \"x-nylon-signature\": signature,\n \"x-nylon-timestamp\": timestamp,\n };\n}\n\n/** Create an AbortController with a timeout. Returns cleanup to clear the timer. */\nfunction withTimeout(timeoutMs: number): {\n controller: AbortController;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n return { controller, cleanup: () => clearTimeout(timeoutId) };\n}\n\n/**\n * Create the transport layer for SDK requests.\n *\n * @param config - Resolved SDK configuration\n * @returns Transport functions\n *\n * @internal\n */\nexport function createTransport({\n apiKey,\n apiSecret,\n baseUrl = DEFAULT_BASE_URL,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n maxRetries = DEFAULT_MAX_RETRIES,\n fetch: fetchImpl,\n}: {\n apiKey: string;\n apiSecret: string;\n baseUrl?: string;\n timeoutMs?: number;\n maxRetries?: number;\n fetch: typeof globalThis.fetch;\n}) {\n /**\n * Send a request to the backend.\n * Builds the envelope and headers once, then retries only the fetch call.\n */\n async function send<T>(\n request: TransportRequest,\n ): Promise<Result<T, string>> {\n const envelope = buildEnvelope(request);\n const signedPayload = (envelope as { payload: unknown }).payload;\n const headers = buildAuthHeaders({\n apiKey,\n apiSecret,\n payload: signedPayload,\n });\n const bodyString = JSON.stringify(envelope);\n\n async function attempt(currentAttempt: number): Promise<Result<T, string>> {\n const { controller, cleanup } = withTimeout(timeoutMs);\n\n try {\n const response = await fetchImpl(baseUrl, {\n method: \"POST\",\n headers,\n body: bodyString,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n const retryable = RETRYABLE_STATUS_CODES.has(statusCode);\n\n let errorMessage = `HTTP ${statusCode}`;\n try {\n const errorBody = await response.json();\n if (\n errorBody &&\n typeof errorBody === \"object\" &&\n \"message\" in errorBody\n ) {\n errorMessage = String(errorBody.message);\n }\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n\n if (retryable && currentAttempt < maxRetries) {\n cleanup();\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n cleanup();\n return Err(\n JSON.stringify(\n buildHttpError({ message: errorMessage, statusCode }),\n ),\n );\n }\n\n const responseBody = await response.json();\n\n if (\n !responseBody ||\n typeof responseBody !== \"object\" ||\n !(\"status\" in responseBody)\n ) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response missing status field\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const { status, message, data } = responseBody as {\n status: boolean;\n message: string;\n data: unknown;\n };\n\n if (status === true) {\n const { data: strippedData, responseSignature } =\n stripResponseSignature(data);\n\n // Fail closed. Every authenticated success response from the backend\n // is signed (see backend signSdkResponse). A missing signature means\n // the response was tampered with — e.g. a MITM stripped the field — or\n // did not originate from the backend. Reject rather than trust\n // unverified data; a prior version skipped verification when the field\n // was absent, which let a stripped-signature response through.\n if (!responseSignature) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature missing\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature verification failed\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n cleanup();\n return Ok(strippedData as T);\n }\n\n // status === false\n const parsedError = parseError(message);\n cleanup();\n return Err(JSON.stringify(parsedError));\n } catch (error) {\n cleanup();\n\n const isAbort =\n error instanceof DOMException && error.name === \"AbortError\";\n const sdkError: SdkError = {\n category: isAbort ? \"timeout\" : \"network\",\n message: isAbort\n ? `Request timed out after ${timeoutMs}ms`\n : String(error),\n retryable: true,\n };\n\n if (currentAttempt < maxRetries) {\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n return Err(JSON.stringify(sdkError));\n }\n }\n\n return attempt(0);\n }\n\n return { send, parseError };\n}\n\n/**\n * Parse an error string into a structured SdkError with a `category`.\n * Tries the JSON envelope first; otherwise pulls the server's\n * ` -- error-type: <category>` suffix off a raw message, falling back to\n * category `internal` when untagged.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-2026-001\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.category, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n // Sync helper: `safeTry` is async-only. The try/catch is the sync\n // boundary for JSON.parse and stays as-is (mirrors the pre-existing\n // contract that the SDK always exposes `parseError` synchronously).\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"category\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).category === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not our JSON envelope — fall through to suffix parsing.\n }\n\n // Raw server message: pull the ` -- error-type: <category>` suffix if present.\n const fromSuffix = parseCategoryFromMessage(error);\n return {\n category: fromSuffix.category ?? \"internal\",\n message: fromSuffix.message,\n };\n}\n","/**\n * Payment instance with event emission for transaction lifecycle.\n * Handles polling, event emission, and wait-for-completion.\n *\n * @see Spec 2 section 2 - \".collectPayment() returns a payment instance that they have to listen for events on\"\n * @see Spec 2 section 9 - \"sdk on merchant side internally calls another action to our backend to get transaction status updates by polling\"\n */\n\nimport type { Result } from \"slang-ts\";\nimport { createEmitter, type Emitter } from \"./pubsub\";\nimport { POLL_JITTER_MS } from \"./sdk.config\";\nimport { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\n SdkError,\n StatusResponse,\n Transaction,\n TransactionStatus,\n} from \"./types\";\n\n/**\n * Internal state for a payment instance.\n * @internal\n */\ntype PaymentState = {\n reference: string;\n status: TransactionStatus;\n transaction: Transaction | null;\n pollingTimer: ReturnType<typeof setTimeout> | null;\n resolved: boolean;\n pollAttempts: number;\n pollStartTime: number;\n emitter: Emitter<PaymentEvent>;\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs: number;\n maxPollDuration: number;\n maxPollAttempts: number;\n};\n\n/** Map transaction status to payment event. */\nconst STATUS_TO_EVENT: Partial<Record<TransactionStatus, PaymentEvent>> = {\n successful: \"success\",\n failed: \"failed\",\n processing: \"processing\",\n cancelled: \"cancelled\",\n};\n\nfunction statusToEvent(status: TransactionStatus): PaymentEvent | null {\n return STATUS_TO_EVENT[status] ?? null;\n}\n\n/** Terminal states that stop polling. */\nconst TERMINAL_STATES = new Set<TransactionStatus>([\n \"successful\",\n \"failed\",\n \"cancelled\",\n]);\n\n/**\n * Normalise raw backend status strings to TransactionStatus.\n * The backend may return \"completed\" for successful payments — map it to\n * \"successful\" so SDK events fire correctly.\n */\nfunction normalizeStatus(raw: string): TransactionStatus {\n if (raw === \"completed\") return \"successful\";\n return raw as TransactionStatus;\n}\n\n/**\n * Create a new payment instance.\n *\n * @param initialResponse - Response with reference and initial status\n * @param deps - Dependencies injected by the SDK\n * @returns Payment instance with event subscription\n *\n * @internal\n */\nexport function createPaymentInstance(\n initialResponse: { reference: string; status: TransactionStatus },\n deps: {\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs?: number;\n maxPollDuration?: number;\n maxPollAttempts?: number;\n /**\n * When set, the operation never started (the backend rejected initiation).\n * The instance emits this as an `\"error\"` event on the next tick instead of\n * polling — so a server-side rejection surfaces as an event, not a throw.\n */\n initialError?: SdkError;\n },\n): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: normalizeStatus(initialResponse.status),\n transaction: null,\n pollingTimer: null,\n resolved: false,\n pollAttempts: 0,\n pollStartTime: Date.now(),\n emitter: createEmitter<PaymentEvent>(),\n fetchStatus: deps.fetchStatus,\n fetchTransaction: deps.fetchTransaction,\n pollIntervalMs: deps.pollIntervalMs ?? 2000,\n maxPollDuration: deps.maxPollDuration ?? 300000,\n maxPollAttempts: deps.maxPollAttempts ?? 150,\n };\n\n function resolveWithError(error: string): void {\n state.resolved = true;\n stopUpdates();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(\n event: PaymentEvent,\n error?: string,\n category?: SdkError[\"category\"],\n retryable?: boolean,\n ): void {\n const data: EventData = {\n event,\n transaction: state.transaction ?? undefined,\n error,\n category,\n retryable,\n timestamp: new Date().toISOString(),\n };\n state.emitter.emit(event, data);\n }\n\n /**\n * Handle terminal state by fetching full transaction record.\n * @internal\n */\n async function handleTerminalState(status: TransactionStatus): Promise<void> {\n const txResult = await state.fetchTransaction({\n reference: state.reference,\n });\n if (txResult.isOk) {\n state.transaction = txResult.value;\n const event = statusToEvent(status);\n if (event) {\n const error =\n status === \"failed\"\n ? (state.transaction.failureReason ?? undefined)\n : undefined;\n emitEvent(event, error);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\n // Once the instance has resolved (terminal state, error, or timeout), no\n // further events may fire. A late status — e.g. an SSE chunk buffered before\n // the stream closed on fallback, or an in-flight poll — must be ignored so\n // it cannot emit a duplicate terminal event or a spurious out-of-order one.\n // The guard runs before any await, so the first caller to resolve wins.\n if (state.resolved) {\n return;\n }\n\n if (response.reference !== state.reference) {\n resolveWithError(\n `Reference mismatch: expected ${state.reference} but got ${response.reference}`,\n );\n return;\n }\n\n const newStatus = normalizeStatus(response.status);\n const oldStatus = state.status;\n\n state.status = newStatus;\n\n if (newStatus !== oldStatus) {\n const event = statusToEvent(newStatus);\n if (event) {\n if (TERMINAL_STATES.has(newStatus)) {\n await handleTerminalState(newStatus);\n return;\n }\n emitEvent(event);\n }\n }\n }\n\n /**\n * Handle polling error.\n * A `not_found` category during early polling is expected (the transaction\n * may not have propagated yet) — keep polling. Any other category is a real\n * failure that stops polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const parsed = parseError(error);\n if (parsed.category === \"not_found\") {\n return;\n }\n emitEvent(\"error\", parsed.message);\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one\n * finishes (no overlap). A random jitter is added to the interval so many\n * concurrent payments don't synchronise into a thundering herd on the status\n * endpoint.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n const delay = state.pollIntervalMs + Math.random() * POLL_JITTER_MS;\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, delay);\n }\n\n /**\n * Execute one polling cycle and queue the next one when appropriate.\n * @internal\n */\n async function pollStatus(): Promise<void> {\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n if (state.pollAttempts >= state.maxPollAttempts) {\n resolveWithError(\"Polling timeout: exceeded maximum attempts\");\n return;\n }\n\n if (Date.now() - state.pollStartTime >= state.maxPollDuration) {\n resolveWithError(\"Polling timeout: exceeded maximum duration\");\n return;\n }\n\n state.pollAttempts += 1;\n\n const result = await state.fetchStatus({ reference: state.reference });\n\n if (result.isOk) {\n await handleStatusUpdate(result.value);\n } else {\n handlePollError(result.error);\n }\n\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start status updates. If the initial status is already terminal (e.g. sandbox\n * resolves synchronously), emit the terminal event after a tick so handlers\n * registered after instance creation still fire. Otherwise begin polling.\n * @internal\n */\n function startUpdates(): void {\n if (TERMINAL_STATES.has(state.status)) {\n setTimeout(() => {\n void handleTerminalState(state.status);\n }, 0);\n return;\n }\n scheduleNextPoll();\n }\n\n /**\n * Stop all status updates (the poll timer).\n * @internal\n */\n function stopUpdates(): void {\n if (state.pollingTimer) {\n clearTimeout(state.pollingTimer);\n state.pollingTimer = null;\n }\n }\n\n /**\n * Subscribe to payment events.\n */\n function on(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.on(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Unsubscribe from payment events.\n */\n function off(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.off(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Subscribe to a payment event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal events like \"success\" or \"failed\".\n */\n function once(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.once(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Wait for payment to reach a terminal state.\n * Resolves with the full Transaction on success, null on failure/cancel/error.\n * Never rejects — check the return value to determine outcome.\n */\n function wait(): Promise<Transaction | null> {\n return new Promise((resolve) => {\n if (state.resolved) {\n resolve(\n state.status === \"successful\" && state.transaction\n ? state.transaction\n : null,\n );\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n resolve(state.transaction ?? null);\n }\n\n function onFailed(): void {\n cleanup();\n resolve(null);\n }\n\n function onCancelled(): void {\n cleanup();\n resolve(null);\n }\n\n function onError(): void {\n cleanup();\n resolve(null);\n }\n\n function cleanup(): void {\n state.emitter.off(\"success\", onSuccess);\n state.emitter.off(\"failed\", onFailed);\n state.emitter.off(\"cancelled\", onCancelled);\n state.emitter.off(\"error\", onError);\n }\n\n state.emitter.on(\"success\", onSuccess);\n state.emitter.on(\"failed\", onFailed);\n state.emitter.on(\"cancelled\", onCancelled);\n state.emitter.on(\"error\", onError);\n });\n }\n\n const paymentInstance: PaymentInstance = {\n get reference() {\n return state.reference;\n },\n get status() {\n return state.status;\n },\n on,\n once,\n off,\n wait,\n };\n\n // When the backend rejected initiation, there is nothing to poll.\n // Emit an \"error\" event on the next tick so handlers registered after\n // creation still fire, and mark resolved so wait() returns null.\n if (deps.initialError) {\n state.resolved = true;\n const err = deps.initialError;\n setTimeout(() => {\n emitEvent(\"error\", err.message, err.category, err.retryable);\n }, 0);\n } else {\n startUpdates();\n }\n\n return paymentInstance;\n}\n","/**\n * Normalize a phone number to international format without leading +.\n *\n * - Strips all whitespace\n * - Strips leading +\n * - If starts with \"0\" and length is 10 → prepend \"256\"\n *\n * WHY: Phone numbers like \"0768499027\" reach the backend unnormalized.\n * SDK normalizing first means the wire payload is already correct,\n * providing defense-in-depth even though the backend also normalizes.\n */\nexport function normalizePhone(phone: string): string {\n let normalized = phone.replace(/\\s+/g, \"\").replace(/^\\+/, \"\");\n\n if (normalized.startsWith(\"0\") && normalized.length === 10) {\n normalized = `256${normalized.slice(1)}`;\n }\n\n return normalized;\n}\n","/**\n * Standalone webhook signature verification utility.\n * Merchants use this to confirm that incoming webhook payloads\n * were genuinely sent by Nylon Pay before acting on them.\n */\n\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { VerifyWebhookInput } from \"./types\";\n\n/** Default replay-protection window: the signed timestamp must be this fresh. */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/** Decode the (already signature-verified) payload to a UTF-8 string. */\nfunction decodePayload(payload: string | Uint8Array): string {\n return typeof payload === \"string\"\n ? payload\n : Buffer.from(payload).toString(\"utf8\");\n}\n\n/**\n * Pull the signed `timestamp` out of a verified webhook body and return it as\n * epoch milliseconds. The timestamp lives inside the HMAC-signed body (the\n * backend stamps every delivery and every retry fresh), so it cannot be forged\n * or refreshed by a replay attacker without the secret. Returns `null` when the\n * body is not JSON or carries no parseable timestamp.\n */\nfunction extractSignedTimestampMs(payloadString: string): number | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(payloadString);\n } catch {\n return null;\n }\n\n if (!parsed || typeof parsed !== \"object\") {\n return null;\n }\n\n const raw = (parsed as Record<string, unknown>).timestamp;\n\n if (typeof raw === \"number\" && Number.isFinite(raw)) {\n // Accept epoch seconds or milliseconds — values below ~1e12 are seconds.\n return raw < 1e12 ? raw * 1000 : raw;\n }\n\n if (typeof raw === \"string\") {\n const ms = Date.parse(raw);\n return Number.isNaN(ms) ? null : ms;\n }\n\n return null;\n}\n\n/**\n * Verify that a webhook payload was genuinely sent by Nylon Pay.\n *\n * Two checks, both must pass:\n * 1. **Authenticity** — HMAC-SHA256 over the raw payload bytes (NOT parsed\n * JSON, spec invariant #8) matches the provided signature.\n * 2. **Freshness** — the `timestamp` carried inside the signed body is within\n * `toleranceSeconds` of now (default 300s). This is what stops a replay: a\n * captured `(body, signature)` pair stays cryptographically valid forever,\n * but its embedded timestamp goes stale. Every genuine delivery, including\n * retries hours later, is re-stamped and re-signed, so this never rejects\n * legitimate traffic. Pass `toleranceSeconds: 0` to skip this check.\n *\n * @returns True when the signature is valid and (when enforced) the webhook is fresh\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadString = decodePayload(input.payload);\n const payloadBytes = Buffer.from(payloadString, \"utf8\");\n\n const expectedSignature = createHmac(\"sha256\", input.secret)\n .update(payloadBytes)\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(input.signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n if (!timingSafeEqual(providedBuffer, expectedBuffer)) {\n return false;\n }\n\n // Signature is authentic — now enforce freshness using the signed timestamp.\n const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (toleranceSeconds <= 0) {\n return true;\n }\n\n const timestampMs = extractSignedTimestampMs(payloadString);\n if (timestampMs === null) {\n // Fail closed: a valid signature with no verifiable timestamp cannot be\n // proven fresh, so it cannot be distinguished from a replay.\n return false;\n }\n\n const ageMs = Math.abs(Date.now() - timestampMs);\n return ageMs <= toleranceSeconds * 1000;\n}\n","/**\n * SDK instance providing all merchant-facing payment operations.\n * Created via createNylonPay factory and returned as NylonPaySdk.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { Err, Ok, type Result, safeTry } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { normalizePhone } from \"./phone\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createSdkError, createTransport, parseError } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\n SdkHook,\n SdkHooks,\n StatusResponse,\n Transaction,\n TransactionStatus,\n VerifyPhoneInput,\n VerifyWebhookInput,\n} from \"./types\";\nimport { verifyWebhookSignature } from \"./verify-webhook\";\n\nexport type { NylonPaySdk } from \"./types\";\n\ntype ResolvedConfig = {\n apiKey: string;\n apiSecret: string;\n baseUrl: string;\n timeoutMs: number;\n maxRetries: number;\n maxPollIntervalMs: number;\n maxPollDurationMs: number;\n maxPollAttempts: number;\n fetch: typeof globalThis.fetch;\n hooks?: SdkHooks;\n};\n\n/** Generate a random 15-character hex reference for idempotency. */\nfunction generateReference(): string {\n return randomBytes(16).toString(\"hex\").slice(0, 15);\n}\n\n/**\n * PivotPay caps the `merchantTransactionId` (our reference) at 13–15 characters.\n * The backend echoes the reference verbatim as that id, so an out-of-range\n * reference is rejected server-side (and historically surfaced as an opaque\n * provider error). Auto-generated references are always 15 chars; this only\n * bites when a merchant supplies their own (e.g. a 36-char UUID order id).\n */\nconst REFERENCE_MIN_LENGTH = 13;\nconst REFERENCE_MAX_LENGTH = 15;\n\n/**\n * Resolve the idempotency reference for a create call: auto-generate when the\n * merchant omits it, otherwise validate their value against the 13–15 char\n * limit *synchronously* (like validateAmount) so a bad reference throws locally\n * instead of costing a backend round-trip.\n */\nfunction resolveReference(reference?: string): string {\n if (reference === undefined) {\n return generateReference();\n }\n if (\n reference.length < REFERENCE_MIN_LENGTH ||\n reference.length > REFERENCE_MAX_LENGTH\n ) {\n throwValidation(\n `reference must be ${REFERENCE_MIN_LENGTH}–${REFERENCE_MAX_LENGTH} characters`,\n );\n }\n return reference;\n}\n\n/**\n * Run a lifecycle hook safely. A disabled or unset hook is a no-op. The hook's\n * `fn` runs inside `safeTry` so a throw/rejection in merchant code never bubbles\n * into the payment flow — it is routed to the hook's `onError` (which is itself\n * wrapped, so a faulty handler can't crash us either).\n *\n * Returns the hook's resolved value on success, or `undefined` when the hook was\n * skipped or failed. Callers treat `undefined` as \"no override\" — for before\n * hooks that means the original payload is used unchanged.\n */\nasync function runHook<TFn extends (...args: never[]) => unknown>(\n hook: SdkHook<TFn> | undefined,\n ...args: Parameters<TFn>\n): Promise<Awaited<ReturnType<TFn>> | undefined> {\n if (!hook || hook.enabled === false) return undefined;\n\n const result = await safeTry(async () => hook.fn(...args));\n // safeTry widens the success value to `unknown` through the generic bound;\n // by construction it is the hook's resolved return type.\n if (result.isOk) return result.value as Awaited<ReturnType<TFn>>;\n\n await safeTry(async () => hook.onError(result.error));\n return undefined;\n}\n\n/**\n * Throw a categorized input-validation error. Keeps thrown errors consistent\n * with transport-init failures so a merchant's `catch (e)` can always read\n * `e.category` (here always `\"validation\"`).\n */\nfunction throwValidation(message: string): never {\n throw createSdkError({ category: \"validation\", message });\n}\n\n/** Validate collection amount is a positive integer >= 500. */\nfunction validateCollectionAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 500) {\n throwValidation(\"Collection amount must be at least 500 UGX\");\n }\n}\n\n/** Validate payout amount is a positive integer >= 5000. */\nfunction validatePayoutAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 5000) {\n throwValidation(\"Payout amount must be at least 5000 UGX\");\n }\n}\n\n/** Validate that a string value is non-empty. */\nfunction validateNonEmpty(value: string, fieldName: string): void {\n if (!value || value.trim() === \"\") {\n throwValidation(`${fieldName} is required`);\n }\n}\n\n/**\n * Create an SDK instance with resolved configuration.\n * Returns an object implementing the NylonPaySdk interface.\n */\nexport function createSdkInstance(config: ResolvedConfig): NylonPaySdk {\n const transport = createTransport({\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl: config.baseUrl,\n timeoutMs: config.timeoutMs,\n maxRetries: config.maxRetries,\n fetch: config.fetch,\n });\n\n const commonDeps = {\n fetchStatus: (input: GetStatusInput) =>\n transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n }),\n fetchTransaction: (input: GetTransactionInput) =>\n transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n }),\n pollIntervalMs: config.maxPollIntervalMs,\n maxPollDuration: config.maxPollDurationMs,\n maxPollAttempts: config.maxPollAttempts,\n };\n\n /**\n * Initiate a collection payment.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function collectPayment(\n input: CollectPaymentInput,\n ): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed (invalid key, signature, limit, provider reject). The\n // transaction never started — return a PaymentInstance that emits an\n // \"error\" event instead of throwing, so merchants handle it via events.\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a collection and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function collectPaymentAndResolve(\n input: CollectPaymentInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Initiate a payout.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function makePayout(input: MakePayoutInput): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed — return a PaymentInstance that emits an \"error\"\n // event instead of throwing (see collectPayment for rationale).\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a payout and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function makePayoutAndResolve(\n input: MakePayoutInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the current status of a transaction.\n * Lightweight check that returns only status fields.\n */\n async function getStatus(\n input: GetStatusInput,\n ): Promise<Result<StatusResponse, string>> {\n validateNonEmpty(input.reference, \"reference\");\n\n const result = await transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the full transaction record.\n * Requires at least one of id or reference.\n */\n async function getTransaction(\n input: GetTransactionInput,\n ): Promise<Result<Transaction, string>> {\n if (!input.id && !input.reference) {\n throwValidation(\"id or reference is required\");\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a phone number with the provider.\n * Returns the registered name for identity confirmation.\n */\n async function verifyPhone(\n input: VerifyPhoneInput,\n ): Promise<Result<PhoneVerification, string>> {\n validateNonEmpty(input.phoneNumber, \"phoneNumber\");\n const normalizedPhone = normalizePhone(input.phoneNumber);\n\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: { ...input, phoneNumber: normalizedPhone },\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Create a hosted invoice.\n * Auto-generates reference if omitted. Returns payment link and token.\n */\n async function createInvoice(\n input: CreateInvoiceInput,\n ): Promise<Result<InvoiceResponse, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throwValidation(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throwValidation(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throwValidation(\"item unitPrice must be a positive integer\");\n }\n }\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<InvoiceResponse>({\n action: SDK_ACTIONS.createInvoice,\n payload,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a webhook payload signature.\n * Delegates to the standalone verifyWebhookSignature utility.\n */\n function verifyWebhook(input: VerifyWebhookInput): boolean {\n return verifyWebhookSignature(input);\n }\n\n return {\n collectPayment,\n collectPaymentAndResolve,\n makePayout,\n makePayoutAndResolve,\n getStatus,\n getTransaction,\n verifyPhone,\n createInvoice,\n verifyWebhookSignature: verifyWebhook,\n };\n}\n","/**\n * Factory function to create a Nylon Pay SDK instance.\n * This is the main entry point for merchants.\n *\n * Calling createNylonPay with the same apiKey, apiSecret and baseUrl returns the\n * same instance (singleton per key+secret+url). Rotating the secret yields a\n * fresh instance. Pass { force: true } to force a new instance regardless.\n *\n * @example\n * ```ts\n * import { createNylonPay } from \"@nile-squad/nylonpay-ts\";\n *\n * export const nylonpay = createNylonPay({\n * apiKey: \"npk_...\",\n * apiSecret: \"nps_...\",\n * });\n * ```\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createSdkInstance, type NylonPaySdk } from \"./sdk\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_POLL_ATTEMPTS,\n DEFAULT_MAX_POLL_DURATION_MS,\n DEFAULT_MAX_POLL_INTERVAL_MS,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n} from \"./sdk.config\";\nimport type { NylonPayConfig } from \"./types\";\n\nconst instances = new Map<string, NylonPaySdk>();\n\n/**\n * Create a Nylon Pay SDK instance.\n *\n * Returns the same instance for the same apiKey + apiSecret + baseUrl\n * combination unless { force: true } is passed. Use your test keys for sandbox,\n * production keys for live.\n *\n * @param config - SDK configuration with apiKey and apiSecret\n * @returns SDK instance with all payment operations\n *\n * @throws Error if required config is missing or invalid\n */\nexport function createNylonPay(config: NylonPayConfig): NylonPaySdk {\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n if (!config.apiKey.startsWith(\"npk_\")) {\n throw new Error('apiKey must start with \"npk_\"');\n }\n if (!config.apiSecret) {\n throw new Error(\"apiSecret is required\");\n }\n if (!config.apiSecret.startsWith(\"nps_\")) {\n throw new Error('apiSecret must start with \"nps_\"');\n }\n\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n // Include a hash of the secret in the cache key so rotating apiSecret in a\n // long-running process returns a fresh instance instead of a stale one signing\n // with the old secret. Hashed (not raw) so the secret never sits in a Map key.\n const secretHash = createHash(\"sha256\")\n .update(config.apiSecret)\n .digest(\"hex\")\n .slice(0, 16);\n const instanceKey = `${config.apiKey}:${baseUrl}:${secretHash}`;\n\n if (!config.force) {\n const existing = instances.get(instanceKey);\n if (existing) return existing;\n }\n\n const resolvedConfig = {\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,\n maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,\n maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n hooks: config.hooks,\n };\n\n const instance = createSdkInstance(resolvedConfig);\n instances.set(instanceKey, instance);\n return instance;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/pubsub.ts","../src/sdk.config.ts","../src/fingerprint.ts","../src/nonce.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.ts","../src/phone.ts","../src/verify-webhook.ts","../src/sdk.ts","../src/create-nylon-pay.ts"],"names":["type","platform","arch","release","hostname","createHash","randomBytes","createHmac","timingSafeEqual","Err","Ok","delay","safeTry"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Simple internal pubsub/event emitter for SDK payment lifecycle events.\n * Functional implementation without classes.\n *\n * @see Spec 2 section 2 - \"emits events such as nylonpay.on('success', (data) => {})\"\n *\n * @example\n * ```ts\n * const emitter = createEmitter<PaymentEvent>();\n * emitter.on(\"success\", (data) => console.log(data));\n * emitter.emit(\"success\", { event: \"success\", timestamp: \"...\" });\n * emitter.off(\"success\", handler);\n * ```\n */\n\n/**\n * Handler function type for event listeners.\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\n/**\n * Internal state for the emitter.\n * @internal\n */\ninterface EmitterState<T> {\n listeners: Map<T, Set<EventHandler<T>>>;\n}\n\n/**\n * Create a new event emitter instance.\n *\n * @returns Emitter with on/off/emit methods\n *\n * @example\n * ```ts\n * const emitter = createEmitter<string>();\n * const unsub = emitter.on(\"hello\", (msg) => console.log(msg));\n * emitter.emit(\"hello\", \"world\");\n * unsub(); // remove listener\n * ```\n */\nexport function createEmitter<T extends string>() {\n const state: EmitterState<T> = {\n listeners: new Map(),\n };\n\n /**\n * Subscribe to an event.\n * Returns an unsubscribe function for convenience.\n */\n function on(event: T, handler: EventHandler): () => void {\n if (!state.listeners.has(event)) {\n state.listeners.set(event, new Set());\n }\n state.listeners.get(event)?.add(handler as EventHandler<unknown>);\n return () => off(event, handler);\n }\n\n /**\n * Subscribe to an event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal payment events (e.g. \"successful\", \"failed\").\n * Returns the emitter for chaining.\n */\n function once(event: T, handler: EventHandler): typeof emitter {\n const wrapper: EventHandler = (data) => {\n off(event, wrapper);\n handler(data);\n };\n on(event, wrapper);\n return emitter;\n }\n\n /**\n * Unsubscribe from an event.\n */\n function off(event: T, handler: EventHandler): void {\n const handlers = state.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<unknown>);\n }\n }\n\n /**\n * Emit an event with data to all listeners.\n * Handlers are called synchronously in subscription order.\n */\n function emit(event: T, data: unknown): void {\n const handlers = state.listeners.get(event);\n if (!handlers || handlers.size === 0) return;\n for (const handler of handlers) {\n try {\n (handler as EventHandler<unknown>)(data);\n } catch {\n // Swallow handler errors to prevent one bad handler\n // from breaking the entire event chain\n }\n }\n }\n\n /**\n * Remove all listeners for a specific event, or all events if no event specified.\n */\n function clear(event?: T): void {\n if (event) {\n state.listeners.delete(event);\n } else {\n state.listeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event.\n */\n function listenerCount(event: T): number {\n return state.listeners.get(event)?.size ?? 0;\n }\n\n const emitter = { on, once, off, emit, clear, listenerCount };\n return emitter;\n}\n\n/**\n * Type for the emitter interface returned by createEmitter.\n */\nexport type Emitter<T extends string> = ReturnType<typeof createEmitter<T>>;\n","/** Default production backend URL */\nexport const DEFAULT_BASE_URL =\n \"https://api.nylonpay.nilesquad.com/api/services\";\n\n/** Default request timeout (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default max retry attempts for transport failures */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** Default polling interval between status checks (2 seconds) */\nexport const DEFAULT_MAX_POLL_INTERVAL_MS = 2_000;\n\n/** Default max total polling duration before timing out (5 minutes) */\nexport const DEFAULT_MAX_POLL_DURATION_MS = 300_000;\n\n/** Default max polling attempts before giving up */\nexport const DEFAULT_MAX_POLL_ATTEMPTS = 150;\n\n/**\n * Random jitter (ms) added to each poll interval so many concurrent payments\n * don't synchronise into a thundering herd on the status endpoint.\n */\nexport const POLL_JITTER_MS = 250;\n\n/** Nile.js service name for all SDK operations */\nexport const SDK_SERVICE = \"sdk\";\n\n/** Maps SDK operation names to backend action names */\nexport const SDK_ACTIONS = {\n collectPayment: \"sdk-collect-payment\",\n collectPaymentAndResolve: \"sdk-collect-payment-and-resolve\",\n makePayout: \"sdk-make-payout\",\n makePayoutAndResolve: \"sdk-make-payout-and-resolve\",\n getStatus: \"sdk-get-status\",\n getTransaction: \"sdk-get-transaction\",\n verifyPhone: \"sdk-verify-phone\",\n createInvoice: \"sdk-create-invoice\",\n} as const;\n\n/** HTTP status codes that trigger retries */\nexport const RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\n","/**\n * Server fingerprint generation for SDK requests.\n * Provides a stable identifier based on runtime environment.\n *\n * @see Spec 2 section 1 - \"a server fingerprint based on runtime, os, etc\"\n */\n\nimport { createHash } from \"node:crypto\";\nimport { arch, hostname, platform, release, type } from \"node:os\";\n\n/**\n * Generate a server fingerprint based on runtime environment.\n * This provides a stable identifier for the server making requests.\n * The fingerprint is a SHA-256 hash of system characteristics.\n *\n * @returns Hex-encoded SHA-256 hash of system info\n *\n * @example\n * ```ts\n * const fingerprint = generateFingerprint();\n * // => \"e3b0c44298fc1c149afbf4c8996fb924...\"\n * ```\n */\nexport function generateFingerprint(): string {\n const components = [\n `type:${type()}`,\n `platform:${platform()}`,\n `arch:${arch()}`,\n `release:${release()}`,\n `hostname:${hostname()}`,\n `node:${process.versions.node}`,\n `v8:${process.versions.v8}`,\n ].join(\"|\");\n\n return createHash(\"sha256\").update(components).digest(\"hex\");\n}\n","/**\n * Cryptographically secure nonce generation for SDK requests.\n *\n * @see Spec 2 section 1 - \"Internally the sdk generates a nounce\"\n */\n\nimport { randomBytes } from \"node:crypto\";\n\n/**\n * Generate a cryptographically secure random nonce.\n * Uses Node.js crypto.randomBytes for security.\n *\n * @param length - Byte length of the nonce (default: 16 = 32 hex chars)\n * @returns Hex-encoded random string\n *\n * @example\n * ```ts\n * const nonce = generateNonce();\n * // => \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"\n * ```\n */\nexport function generateNonce(length = 16): string {\n return randomBytes(length).toString(\"hex\");\n}\n","/**\n * HMAC-SHA256 signature creation for SDK requests.\n * Must match the backend's verification logic in verify-signature.ts.\n *\n * Signature payload format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * @see backend/src/services/sdk/verify-signature.ts\n * @see Spec 2 section 1 - \"creates a signature using these values and the api secret (HMAC 256)\"\n */\n\nimport { createHmac } from \"node:crypto\";\n\n/**\n * Recursively sort object keys by Unicode code point for deterministic JSON.\n *\n * The comparison MUST be by UTF-16 code unit (the JavaScript `<` operator), the\n * canonicalization rule from RFC 8785 (JSON Canonicalization Scheme). A\n * locale-sensitive comparison (e.g. `localeCompare`) is forbidden: its order\n * depends on the runtime's locale/ICU data, so two parties could canonicalize\n * the same payload to different bytes and fail signature verification on valid\n * traffic. Must match backend's createCanonicalPayload function byte-for-byte.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\n */\n/** Compare two keys by UTF-16 code unit (RFC 8785), never by locale. */\nfunction compareByCodePoint(first: string, second: string): number {\n if (first < second) {\n return -1;\n }\n if (first > second) {\n return 1;\n }\n return 0;\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => sortValue(entry));\n }\n\n if (value && typeof value === \"object\") {\n const sortedEntries = Object.entries(value as Record<string, unknown>).sort(\n ([firstKey], [secondKey]) => compareByCodePoint(firstKey, secondKey),\n );\n\n return Object.fromEntries(\n sortedEntries.map(([entryKey, entryValue]) => [\n entryKey,\n sortValue(entryValue),\n ]),\n );\n }\n\n return value;\n}\n\n/**\n * Create a canonical JSON string from a payload, per RFC 8785 (JCS): object keys\n * sorted by Unicode code point, no insignificant whitespace. Numbers and strings\n * serialize via `JSON.stringify`, whose V8 output already matches the JCS rules\n * (ECMAScript number-to-string and minimal JSON string escaping).\n */\nexport function createCanonicalPayload(payload: unknown): string {\n return JSON.stringify(sortValue(payload));\n}\n\n/**\n * Build the signature payload string.\n * Format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * The fingerprint is included in the signature to prevent tampering\n * with server identity information.\n *\n * @see backend/src/services/sdk/verify-signature.ts:createSignaturePayload\n */\nexport function createSignaturePayload(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n timestamp: string;\n}): string {\n return `${input.fingerprint}.${input.nonce}.${input.timestamp}.${createCanonicalPayload(input.payload)}`;\n}\n\n/**\n * Create an HMAC-SHA256 signature for SDK request authentication.\n *\n * The signature includes the server fingerprint to ensure the request\n * origin cannot be spoofed. The fingerprint contains runtime/OS info\n * that is bound to this specific server instance.\n *\n * @param input.fingerprint - Server fingerprint (included in signature)\n * @param input.nonce - Random nonce for replay protection\n * @param input.timestamp - Unix timestamp in milliseconds\n * @param input.payload - Request body (will be canonicalized)\n * @param input.secret - API secret for signing\n * @returns Hex-encoded HMAC-SHA256 signature\n */\nexport function createSignature(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n secret: string;\n timestamp: string;\n}): string {\n const payload = createSignaturePayload(input);\n\n return createHmac(\"sha256\", input.secret).update(payload).digest(\"hex\");\n}\n\n/**\n * Create a timestamp string in milliseconds.\n * Used as part of the signature payload.\n */\nexport function createTimestamp(): string {\n return Date.now().toString();\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { createCanonicalPayload } from \"./signature\";\n\n/**\n * Verify an authenticated backend response body before exposing it to SDK\n * consumers so tampered payloads are rejected consistently.\n *\n * @param data - Response payload without the `_responseSignature` field\n * @param signature - Hex-encoded HMAC-SHA256 signature from the backend\n * @param secret - API secret used for request authentication\n * @returns True when the signature matches the payload\n */\nexport function verifyResponseSignature(\n data: unknown,\n signature: string,\n secret: string,\n): boolean {\n const expectedSignature = createHmac(\"sha256\", secret)\n .update(createCanonicalPayload(data))\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(providedBuffer, expectedBuffer);\n}\n","/**\n * HTTP transport layer for SDK communication with the Nylon Pay backend.\n * Handles the Nile.js envelope format, HMAC request signing, response\n * signature verification, retries, and timeouts.\n *\n * @internal\n */\n\nimport { Err, Ok, type Result } from \"slang-ts\";\nimport { generateFingerprint } from \"./fingerprint\";\nimport { generateNonce } from \"./nonce\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n RETRYABLE_STATUS_CODES,\n SDK_SERVICE,\n} from \"./sdk.config\";\nimport { createSignature, createTimestamp } from \"./signature\";\nimport type { SdkError, SdkErrorCategory, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\n\n/** Known failure categories the server tags onto error messages. */\nconst KNOWN_CATEGORIES = new Set<SdkErrorCategory>([\n \"auth\",\n \"validation\",\n \"limit\",\n \"rate_limit\",\n \"account\",\n \"provider\",\n \"duplicate\",\n \"not_found\",\n \"internal\",\n \"network\",\n \"timeout\",\n]);\n\n/** HTTP status → category for errors that aren't server-tagged. */\nconst STATUS_CATEGORY: Record<number, SdkErrorCategory> = {\n 408: \"timeout\",\n 429: \"rate_limit\",\n};\n\n/** Matches the server's ` -- error-type: <category>` message suffix. */\nconst ERROR_TYPE_SUFFIX = /^(.*?)\\s*--\\s*error-type:\\s*([a-z_]+)\\s*$/is;\n\n/**\n * Split the server's tagged category off an error message. The backend appends\n * ` -- error-type: <category>` to every SDK error (the only channel available —\n * Nile returns 200/400 only and drops the response `data` on failures). The\n * leading `[logId]` and human text are preserved as the message.\n */\nfunction parseCategoryFromMessage(message: string): {\n category: SdkErrorCategory | null;\n message: string;\n} {\n const match = ERROR_TYPE_SUFFIX.exec(message);\n if (match?.[2] && KNOWN_CATEGORIES.has(match[2] as SdkErrorCategory)) {\n return {\n category: match[2] as SdkErrorCategory,\n message: match[1] ?? message,\n };\n }\n return { category: null, message };\n}\n\n/** Build a structured SdkError from an HTTP error body's message + status. */\nfunction buildHttpError(params: {\n message: string;\n statusCode: number;\n}): SdkError {\n const parsed = parseCategoryFromMessage(params.message);\n const category: SdkErrorCategory =\n parsed.category ??\n STATUS_CATEGORY[params.statusCode] ??\n (params.statusCode >= 500 ? \"internal\" : \"validation\");\n return {\n category,\n message: parsed.message,\n retryable: RETRYABLE_STATUS_CODES.has(params.statusCode),\n };\n}\n\n/**\n * Convert a structured SdkError into a throwable Error that still carries the\n * category and retryable flag. Used by async operations that throw on\n * initiation failure (invalid key, etc.) so merchants can `catch (e)` and read\n * `e.category`.\n */\nexport function createSdkError(error: SdkError): Error & SdkError {\n return Object.assign(new Error(error.message), {\n category: error.category,\n retryable: error.retryable,\n });\n}\n\n/** Calculate exponential backoff delay with jitter. */\nfunction calculateBackoff(attempt: number): number {\n const base = 2 ** attempt * 1000;\n const jitter = Math.random() * 500;\n return base + jitter;\n}\n\n/** Promise-based delay. */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Strip _responseSignature from a payload and return it separately. */\nfunction stripResponseSignature<T>(payload: T): {\n data: T;\n responseSignature: string | null;\n} {\n if (\n !payload ||\n typeof payload !== \"object\" ||\n !(\"_responseSignature\" in payload)\n ) {\n return { data: payload, responseSignature: null };\n }\n\n const { _responseSignature, ...rest } = payload as Record<string, unknown>;\n\n return {\n data: rest as T,\n responseSignature:\n typeof _responseSignature === \"string\" ? _responseSignature : null,\n };\n}\n\n/** Build the Nile.js request envelope. */\nfunction buildEnvelope({\n action,\n payload,\n}: TransportRequest): Record<string, unknown> {\n return {\n intent: \"execute\",\n service: SDK_SERVICE,\n action,\n payload: {\n ...(payload as Record<string, unknown>),\n _fingerprint: CACHED_FINGERPRINT,\n },\n };\n}\n\n/**\n * Build auth headers for a request.\n *\n * The signature is computed over the inner `payload` (the operation input plus\n * `_fingerprint`), NOT the full Nile envelope. This matches the server, which\n * verifies the signature against the raw request payload — see the Transport\n * Contract in the Nylon Pay SDK Spec (https://github.com/nile-squad/specs).\n */\nfunction buildAuthHeaders({\n apiKey,\n apiSecret,\n payload,\n}: {\n apiKey: string;\n apiSecret: string;\n payload: unknown;\n}): Record<string, string> {\n const nonce = generateNonce();\n const timestamp = createTimestamp();\n const signature = createSignature({\n fingerprint: CACHED_FINGERPRINT,\n nonce,\n timestamp,\n payload,\n secret: apiSecret,\n });\n\n return {\n \"content-type\": \"application/json\",\n \"x-nylon-key\": apiKey,\n \"x-nylon-nonce\": nonce,\n \"x-nylon-signature\": signature,\n \"x-nylon-timestamp\": timestamp,\n };\n}\n\n/** Create an AbortController with a timeout. Returns cleanup to clear the timer. */\nfunction withTimeout(timeoutMs: number): {\n controller: AbortController;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n return { controller, cleanup: () => clearTimeout(timeoutId) };\n}\n\n/**\n * Create the transport layer for SDK requests.\n *\n * @param config - Resolved SDK configuration\n * @returns Transport functions\n *\n * @internal\n */\nexport function createTransport({\n apiKey,\n apiSecret,\n baseUrl = DEFAULT_BASE_URL,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n maxRetries = DEFAULT_MAX_RETRIES,\n fetch: fetchImpl,\n}: {\n apiKey: string;\n apiSecret: string;\n baseUrl?: string;\n timeoutMs?: number;\n maxRetries?: number;\n fetch: typeof globalThis.fetch;\n}) {\n /**\n * Send a request to the backend.\n * Builds the envelope and headers once, then retries only the fetch call.\n */\n async function send<T>(\n request: TransportRequest,\n ): Promise<Result<T, string>> {\n const envelope = buildEnvelope(request);\n const signedPayload = (envelope as { payload: unknown }).payload;\n const headers = buildAuthHeaders({\n apiKey,\n apiSecret,\n payload: signedPayload,\n });\n const bodyString = JSON.stringify(envelope);\n\n async function attempt(currentAttempt: number): Promise<Result<T, string>> {\n const { controller, cleanup } = withTimeout(timeoutMs);\n\n try {\n const response = await fetchImpl(baseUrl, {\n method: \"POST\",\n headers,\n body: bodyString,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n const retryable = RETRYABLE_STATUS_CODES.has(statusCode);\n\n let errorMessage = `HTTP ${statusCode}`;\n try {\n const errorBody = await response.json();\n if (\n errorBody &&\n typeof errorBody === \"object\" &&\n \"message\" in errorBody\n ) {\n errorMessage = String(errorBody.message);\n }\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n\n if (retryable && currentAttempt < maxRetries) {\n cleanup();\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n cleanup();\n return Err(\n JSON.stringify(\n buildHttpError({ message: errorMessage, statusCode }),\n ),\n );\n }\n\n const responseBody = await response.json();\n\n if (\n !responseBody ||\n typeof responseBody !== \"object\" ||\n !(\"status\" in responseBody)\n ) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response missing status field\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const { status, message, data } = responseBody as {\n status: boolean;\n message: string;\n data: unknown;\n };\n\n if (status === true) {\n const { data: strippedData, responseSignature } =\n stripResponseSignature(data);\n\n // Fail closed. Every authenticated success response from the backend\n // is signed (see backend signSdkResponse). A missing signature means\n // the response was tampered with — e.g. a MITM stripped the field — or\n // did not originate from the backend. Reject rather than trust\n // unverified data; a prior version skipped verification when the field\n // was absent, which let a stripped-signature response through.\n if (!responseSignature) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature missing\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature verification failed\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n cleanup();\n return Ok(strippedData as T);\n }\n\n // status === false\n const parsedError = parseError(message);\n cleanup();\n return Err(JSON.stringify(parsedError));\n } catch (error) {\n cleanup();\n\n const isAbort =\n error instanceof DOMException && error.name === \"AbortError\";\n const sdkError: SdkError = {\n category: isAbort ? \"timeout\" : \"network\",\n message: isAbort\n ? `Request timed out after ${timeoutMs}ms`\n : String(error),\n retryable: true,\n };\n\n if (currentAttempt < maxRetries) {\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n return Err(JSON.stringify(sdkError));\n }\n }\n\n return attempt(0);\n }\n\n return { send, parseError };\n}\n\n/**\n * Parse an error string into a structured SdkError with a `category`.\n * Tries the JSON envelope first; otherwise pulls the server's\n * ` -- error-type: <category>` suffix off a raw message, falling back to\n * category `internal` when untagged.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-2026-001\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.category, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n // Sync helper: `safeTry` is async-only. The try/catch is the sync\n // boundary for JSON.parse and stays as-is (mirrors the pre-existing\n // contract that the SDK always exposes `parseError` synchronously).\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"category\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).category === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not our JSON envelope — fall through to suffix parsing.\n }\n\n // Raw server message: pull the ` -- error-type: <category>` suffix if present.\n const fromSuffix = parseCategoryFromMessage(error);\n return {\n category: fromSuffix.category ?? \"internal\",\n message: fromSuffix.message,\n };\n}\n","/**\n * Payment instance with event emission for transaction lifecycle.\n * Handles polling, event emission, and wait-for-completion.\n *\n * @see Spec 2 section 2 - \".collectPayment() returns a payment instance that they have to listen for events on\"\n * @see Spec 2 section 9 - \"sdk on merchant side internally calls another action to our backend to get transaction status updates by polling\"\n */\n\nimport type { Result } from \"slang-ts\";\nimport { createEmitter, type Emitter } from \"./pubsub\";\nimport { POLL_JITTER_MS } from \"./sdk.config\";\nimport { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\n SdkError,\n StatusResponse,\n Transaction,\n TransactionStatus,\n} from \"./types\";\n\n/**\n * Internal state for a payment instance.\n * @internal\n */\ntype PaymentState = {\n reference: string;\n status: TransactionStatus;\n transaction: Transaction | null;\n pollingTimer: ReturnType<typeof setTimeout> | null;\n /** Last lifecycle event emitted from a status (dedupes repeat emissions). */\n lastStatusEvent: PaymentEvent | null;\n resolved: boolean;\n pollAttempts: number;\n pollStartTime: number;\n emitter: Emitter<PaymentEvent>;\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs: number;\n maxPollDuration: number;\n maxPollAttempts: number;\n};\n\n/**\n * Map transaction status to payment event. Both \"pending\" and \"processing\"\n * map to the \"processing\" event — to the merchant they are the same lifecycle\n * moment (payment accepted, in flight, awaiting the customer/provider).\n * Emission is deduped by event, so pending → processing never double-fires.\n */\nconst STATUS_TO_EVENT: Partial<Record<TransactionStatus, PaymentEvent>> = {\n pending: \"processing\",\n successful: \"success\",\n failed: \"failed\",\n processing: \"processing\",\n cancelled: \"cancelled\",\n};\n\nfunction statusToEvent(status: TransactionStatus): PaymentEvent | null {\n return STATUS_TO_EVENT[status] ?? null;\n}\n\n/** Terminal states that stop polling. */\nconst TERMINAL_STATES = new Set<TransactionStatus>([\n \"successful\",\n \"failed\",\n \"cancelled\",\n]);\n\n/**\n * Normalise raw backend status strings to TransactionStatus.\n * The backend may return \"completed\" for successful payments — map it to\n * \"successful\" so SDK events fire correctly.\n */\nfunction normalizeStatus(raw: string): TransactionStatus {\n if (raw === \"completed\") return \"successful\";\n return raw as TransactionStatus;\n}\n\n/**\n * Create a new payment instance.\n *\n * @param initialResponse - Response with reference and initial status\n * @param deps - Dependencies injected by the SDK\n * @returns Payment instance with event subscription\n *\n * @internal\n */\nexport function createPaymentInstance(\n initialResponse: { reference: string; status: TransactionStatus },\n deps: {\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs?: number;\n maxPollDuration?: number;\n maxPollAttempts?: number;\n /**\n * When set, the operation never started (the backend rejected initiation).\n * The instance emits this as an `\"error\"` event on the next tick instead of\n * polling — so a server-side rejection surfaces as an event, not a throw.\n */\n initialError?: SdkError;\n },\n): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: normalizeStatus(initialResponse.status),\n transaction: null,\n pollingTimer: null,\n lastStatusEvent: null,\n resolved: false,\n pollAttempts: 0,\n pollStartTime: Date.now(),\n emitter: createEmitter<PaymentEvent>(),\n fetchStatus: deps.fetchStatus,\n fetchTransaction: deps.fetchTransaction,\n pollIntervalMs: deps.pollIntervalMs ?? 2000,\n maxPollDuration: deps.maxPollDuration ?? 300000,\n maxPollAttempts: deps.maxPollAttempts ?? 150,\n };\n\n function resolveWithError(error: string): void {\n state.resolved = true;\n stopUpdates();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(\n event: PaymentEvent,\n error?: string,\n category?: SdkError[\"category\"],\n retryable?: boolean,\n ): void {\n const data: EventData = {\n event,\n reference: state.reference,\n transaction: state.transaction ?? undefined,\n error,\n category,\n retryable,\n timestamp: new Date().toISOString(),\n };\n state.emitter.emit(event, data);\n }\n\n /**\n * Handle terminal state by fetching full transaction record.\n * @internal\n */\n async function handleTerminalState(status: TransactionStatus): Promise<void> {\n const txResult = await state.fetchTransaction({\n reference: state.reference,\n });\n if (txResult.isOk) {\n state.transaction = txResult.value;\n const event = statusToEvent(status);\n if (event) {\n const error =\n status === \"failed\"\n ? (state.transaction.failureReason ?? undefined)\n : undefined;\n emitEvent(event, error);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\n // Once the instance has resolved (terminal state, error, or timeout), no\n // further events may fire. A late status — e.g. an SSE chunk buffered before\n // the stream closed on fallback, or an in-flight poll — must be ignored so\n // it cannot emit a duplicate terminal event or a spurious out-of-order one.\n // The guard runs before any await, so the first caller to resolve wins.\n if (state.resolved) {\n return;\n }\n\n if (response.reference !== state.reference) {\n resolveWithError(\n `Reference mismatch: expected ${state.reference} but got ${response.reference}`,\n );\n return;\n }\n\n const newStatus = normalizeStatus(response.status);\n state.status = newStatus;\n\n // Dedupe by *event*, not raw status — \"pending\" and \"processing\" both map\n // to the \"processing\" event, and a status flap (processing → pending) must\n // not re-fire it. Each lifecycle event fires at most once per instance.\n const event = statusToEvent(newStatus);\n if (!event || event === state.lastStatusEvent) {\n return;\n }\n state.lastStatusEvent = event;\n\n if (TERMINAL_STATES.has(newStatus)) {\n await handleTerminalState(newStatus);\n return;\n }\n emitEvent(event);\n }\n\n /**\n * Handle polling error.\n * A `not_found` category during early polling is expected (the transaction\n * may not have propagated yet) — keep polling. Any other category is a real\n * failure that stops polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const parsed = parseError(error);\n if (parsed.category === \"not_found\") {\n return;\n }\n emitEvent(\"error\", parsed.message);\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one\n * finishes (no overlap). A random jitter is added to the interval so many\n * concurrent payments don't synchronise into a thundering herd on the status\n * endpoint.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n const delay = state.pollIntervalMs + Math.random() * POLL_JITTER_MS;\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, delay);\n }\n\n /**\n * Execute one polling cycle and queue the next one when appropriate.\n * @internal\n */\n async function pollStatus(): Promise<void> {\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n if (state.pollAttempts >= state.maxPollAttempts) {\n resolveWithError(\"Polling timeout: exceeded maximum attempts\");\n return;\n }\n\n if (Date.now() - state.pollStartTime >= state.maxPollDuration) {\n resolveWithError(\"Polling timeout: exceeded maximum duration\");\n return;\n }\n\n state.pollAttempts += 1;\n\n const result = await state.fetchStatus({ reference: state.reference });\n\n if (result.isOk) {\n await handleStatusUpdate(result.value);\n } else {\n handlePollError(result.error);\n }\n\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start status updates. If the initial status is already terminal (e.g. sandbox\n * resolves synchronously), emit the terminal event after a tick so handlers\n * registered after instance creation still fire. Otherwise emit the initial\n * in-flight event (\"processing\") on the next tick — the initiation response\n * is typically \"pending\", and a fast payment can jump straight to a terminal\n * status between polls, which previously meant \"processing\" never fired —\n * then begin polling.\n * @internal\n */\n function startUpdates(): void {\n if (TERMINAL_STATES.has(state.status)) {\n setTimeout(() => {\n void handleTerminalState(state.status);\n }, 0);\n return;\n }\n\n const initialEvent = statusToEvent(state.status);\n if (initialEvent) {\n // Mark as emitted synchronously so a poll result mapping to the same\n // event cannot race a duplicate in before the timeout fires.\n state.lastStatusEvent = initialEvent;\n setTimeout(() => {\n if (!state.resolved) {\n emitEvent(initialEvent);\n }\n }, 0);\n }\n scheduleNextPoll();\n }\n\n /**\n * Stop all status updates (the poll timer).\n * @internal\n */\n function stopUpdates(): void {\n if (state.pollingTimer) {\n clearTimeout(state.pollingTimer);\n state.pollingTimer = null;\n }\n }\n\n /**\n * Subscribe to payment events.\n */\n function on(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.on(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Unsubscribe from payment events.\n */\n function off(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.off(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Subscribe to a payment event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal events like \"success\" or \"failed\".\n */\n function once(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.once(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Wait for payment to reach a terminal state.\n * Resolves with the full Transaction on success, null on failure/cancel/error.\n * Never rejects — check the return value to determine outcome.\n */\n function wait(): Promise<Transaction | null> {\n return new Promise((resolve) => {\n if (state.resolved) {\n resolve(\n state.status === \"successful\" && state.transaction\n ? state.transaction\n : null,\n );\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n resolve(state.transaction ?? null);\n }\n\n function onFailed(): void {\n cleanup();\n resolve(null);\n }\n\n function onCancelled(): void {\n cleanup();\n resolve(null);\n }\n\n function onError(): void {\n cleanup();\n resolve(null);\n }\n\n function cleanup(): void {\n state.emitter.off(\"success\", onSuccess);\n state.emitter.off(\"failed\", onFailed);\n state.emitter.off(\"cancelled\", onCancelled);\n state.emitter.off(\"error\", onError);\n }\n\n state.emitter.on(\"success\", onSuccess);\n state.emitter.on(\"failed\", onFailed);\n state.emitter.on(\"cancelled\", onCancelled);\n state.emitter.on(\"error\", onError);\n });\n }\n\n const paymentInstance: PaymentInstance = {\n get reference() {\n return state.reference;\n },\n get status() {\n return state.status;\n },\n on,\n once,\n off,\n wait,\n };\n\n // When the backend rejected initiation, there is nothing to poll.\n // Emit an \"error\" event on the next tick so handlers registered after\n // creation still fire, and mark resolved so wait() returns null.\n if (deps.initialError) {\n state.resolved = true;\n const err = deps.initialError;\n setTimeout(() => {\n emitEvent(\"error\", err.message, err.category, err.retryable);\n }, 0);\n } else {\n startUpdates();\n }\n\n return paymentInstance;\n}\n","/**\n * Normalize a phone number to international format without leading +.\n *\n * - Strips all whitespace\n * - Strips leading +\n * - If starts with \"0\" and length is 10 → prepend \"256\"\n *\n * WHY: Phone numbers like \"0768499027\" reach the backend unnormalized.\n * SDK normalizing first means the wire payload is already correct,\n * providing defense-in-depth even though the backend also normalizes.\n */\nexport function normalizePhone(phone: string): string {\n let normalized = phone.replace(/\\s+/g, \"\").replace(/^\\+/, \"\");\n\n if (normalized.startsWith(\"0\") && normalized.length === 10) {\n normalized = `256${normalized.slice(1)}`;\n }\n\n return normalized;\n}\n","/**\n * Standalone webhook signature verification utility.\n * Merchants use this to confirm that incoming webhook payloads\n * were genuinely sent by Nylon Pay before acting on them.\n */\n\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { VerifyWebhookInput } from \"./types\";\n\n/** Default replay-protection window: the signed timestamp must be this fresh. */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/** Decode the (already signature-verified) payload to a UTF-8 string. */\nfunction decodePayload(payload: string | Uint8Array): string {\n return typeof payload === \"string\"\n ? payload\n : Buffer.from(payload).toString(\"utf8\");\n}\n\n/**\n * Pull the signed `timestamp` out of a verified webhook body and return it as\n * epoch milliseconds. The timestamp lives inside the HMAC-signed body (the\n * backend stamps every delivery and every retry fresh), so it cannot be forged\n * or refreshed by a replay attacker without the secret. Returns `null` when the\n * body is not JSON or carries no parseable timestamp.\n */\nfunction extractSignedTimestampMs(payloadString: string): number | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(payloadString);\n } catch {\n return null;\n }\n\n if (!parsed || typeof parsed !== \"object\") {\n return null;\n }\n\n const raw = (parsed as Record<string, unknown>).timestamp;\n\n if (typeof raw === \"number\" && Number.isFinite(raw)) {\n // Accept epoch seconds or milliseconds — values below ~1e12 are seconds.\n return raw < 1e12 ? raw * 1000 : raw;\n }\n\n if (typeof raw === \"string\") {\n const ms = Date.parse(raw);\n return Number.isNaN(ms) ? null : ms;\n }\n\n return null;\n}\n\n/**\n * Verify that a webhook payload was genuinely sent by Nylon Pay.\n *\n * Two checks, both must pass:\n * 1. **Authenticity** — HMAC-SHA256 over the raw payload bytes (NOT parsed\n * JSON, spec invariant #8) matches the provided signature.\n * 2. **Freshness** — the `timestamp` carried inside the signed body is within\n * `toleranceSeconds` of now (default 300s). This is what stops a replay: a\n * captured `(body, signature)` pair stays cryptographically valid forever,\n * but its embedded timestamp goes stale. Every genuine delivery, including\n * retries hours later, is re-stamped and re-signed, so this never rejects\n * legitimate traffic. Pass `toleranceSeconds: 0` to skip this check.\n *\n * @returns True when the signature is valid and (when enforced) the webhook is fresh\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadString = decodePayload(input.payload);\n const payloadBytes = Buffer.from(payloadString, \"utf8\");\n\n const expectedSignature = createHmac(\"sha256\", input.secret)\n .update(payloadBytes)\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(input.signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n if (!timingSafeEqual(providedBuffer, expectedBuffer)) {\n return false;\n }\n\n // Signature is authentic — now enforce freshness using the signed timestamp.\n const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (toleranceSeconds <= 0) {\n return true;\n }\n\n const timestampMs = extractSignedTimestampMs(payloadString);\n if (timestampMs === null) {\n // Fail closed: a valid signature with no verifiable timestamp cannot be\n // proven fresh, so it cannot be distinguished from a replay.\n return false;\n }\n\n const ageMs = Math.abs(Date.now() - timestampMs);\n return ageMs <= toleranceSeconds * 1000;\n}\n","/**\n * SDK instance providing all merchant-facing payment operations.\n * Created via createNylonPay factory and returned as NylonPaySdk.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { Err, Ok, type Result, safeTry } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { normalizePhone } from \"./phone\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createSdkError, createTransport, parseError } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\n SdkHook,\n SdkHooks,\n StatusResponse,\n Transaction,\n TransactionStatus,\n VerifyPhoneInput,\n VerifyWebhookInput,\n} from \"./types\";\nimport { verifyWebhookSignature } from \"./verify-webhook\";\n\nexport type { NylonPaySdk } from \"./types\";\n\ntype ResolvedConfig = {\n apiKey: string;\n apiSecret: string;\n baseUrl: string;\n timeoutMs: number;\n maxRetries: number;\n maxPollIntervalMs: number;\n maxPollDurationMs: number;\n maxPollAttempts: number;\n fetch: typeof globalThis.fetch;\n hooks?: SdkHooks;\n};\n\n/** Generate a random 15-character hex reference for idempotency. */\nfunction generateReference(): string {\n return randomBytes(16).toString(\"hex\").slice(0, 15);\n}\n\n/**\n * PivotPay caps the `merchantTransactionId` (our reference) at 13–15 characters.\n * The backend echoes the reference verbatim as that id, so an out-of-range\n * reference is rejected server-side (and historically surfaced as an opaque\n * provider error). Auto-generated references are always 15 chars; this only\n * bites when a merchant supplies their own (e.g. a 36-char UUID order id).\n */\nconst REFERENCE_MIN_LENGTH = 13;\nconst REFERENCE_MAX_LENGTH = 15;\n\n/**\n * Resolve the idempotency reference for a create call: auto-generate when the\n * merchant omits it, otherwise validate their value against the 13–15 char\n * limit *synchronously* (like validateAmount) so a bad reference throws locally\n * instead of costing a backend round-trip.\n */\nfunction resolveReference(reference?: string): string {\n if (reference === undefined) {\n return generateReference();\n }\n if (\n reference.length < REFERENCE_MIN_LENGTH ||\n reference.length > REFERENCE_MAX_LENGTH\n ) {\n throwValidation(\n `reference must be ${REFERENCE_MIN_LENGTH}–${REFERENCE_MAX_LENGTH} characters`,\n );\n }\n return reference;\n}\n\n/**\n * Run a lifecycle hook safely. A disabled or unset hook is a no-op. The hook's\n * `fn` runs inside `safeTry` so a throw/rejection in merchant code never bubbles\n * into the payment flow — it is routed to the hook's `onError` (which is itself\n * wrapped, so a faulty handler can't crash us either).\n *\n * Returns the hook's resolved value on success, or `undefined` when the hook was\n * skipped or failed. Callers treat `undefined` as \"no override\" — for before\n * hooks that means the original payload is used unchanged.\n */\nasync function runHook<TFn extends (...args: never[]) => unknown>(\n hook: SdkHook<TFn> | undefined,\n ...args: Parameters<TFn>\n): Promise<Awaited<ReturnType<TFn>> | undefined> {\n if (!hook || hook.enabled === false) return undefined;\n\n const result = await safeTry(async () => hook.fn(...args));\n // safeTry widens the success value to `unknown` through the generic bound;\n // by construction it is the hook's resolved return type.\n if (result.isOk) return result.value as Awaited<ReturnType<TFn>>;\n\n await safeTry(async () => hook.onError(result.error));\n return undefined;\n}\n\n/**\n * Throw a categorized input-validation error. Keeps thrown errors consistent\n * with transport-init failures so a merchant's `catch (e)` can always read\n * `e.category` (here always `\"validation\"`).\n */\nfunction throwValidation(message: string): never {\n throw createSdkError({ category: \"validation\", message });\n}\n\n/** Validate collection amount is a positive integer >= 500. */\nfunction validateCollectionAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 500) {\n throwValidation(\"Collection amount must be at least 500 UGX\");\n }\n}\n\n/** Validate payout amount is a positive integer >= 5000. */\nfunction validatePayoutAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 5000) {\n throwValidation(\"Payout amount must be at least 5000 UGX\");\n }\n}\n\n/** Validate that a string value is non-empty. */\nfunction validateNonEmpty(value: string, fieldName: string): void {\n if (!value || value.trim() === \"\") {\n throwValidation(`${fieldName} is required`);\n }\n}\n\n/**\n * Create an SDK instance with resolved configuration.\n * Returns an object implementing the NylonPaySdk interface.\n */\nexport function createSdkInstance(config: ResolvedConfig): NylonPaySdk {\n const transport = createTransport({\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl: config.baseUrl,\n timeoutMs: config.timeoutMs,\n maxRetries: config.maxRetries,\n fetch: config.fetch,\n });\n\n const commonDeps = {\n fetchStatus: (input: GetStatusInput) =>\n transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n }),\n fetchTransaction: (input: GetTransactionInput) =>\n transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n }),\n pollIntervalMs: config.maxPollIntervalMs,\n maxPollDuration: config.maxPollDurationMs,\n maxPollAttempts: config.maxPollAttempts,\n };\n\n /**\n * Initiate a collection payment.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function collectPayment(\n input: CollectPaymentInput,\n ): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed (invalid key, signature, limit, provider reject). The\n // transaction never started — return a PaymentInstance that emits an\n // \"error\" event instead of throwing, so merchants handle it via events.\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a collection and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function collectPaymentAndResolve(\n input: CollectPaymentInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Initiate a payout.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function makePayout(input: MakePayoutInput): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed — return a PaymentInstance that emits an \"error\"\n // event instead of throwing (see collectPayment for rationale).\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a payout and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function makePayoutAndResolve(\n input: MakePayoutInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the current status of a transaction.\n * Lightweight check that returns only status fields.\n */\n async function getStatus(\n input: GetStatusInput,\n ): Promise<Result<StatusResponse, string>> {\n validateNonEmpty(input.reference, \"reference\");\n\n const result = await transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the full transaction record.\n * Requires at least one of id or reference.\n */\n async function getTransaction(\n input: GetTransactionInput,\n ): Promise<Result<Transaction, string>> {\n if (!input.id && !input.reference) {\n throwValidation(\"id or reference is required\");\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a phone number with the provider.\n * Returns the registered name for identity confirmation.\n */\n async function verifyPhone(\n input: VerifyPhoneInput,\n ): Promise<Result<PhoneVerification, string>> {\n validateNonEmpty(input.phoneNumber, \"phoneNumber\");\n const normalizedPhone = normalizePhone(input.phoneNumber);\n\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: { ...input, phoneNumber: normalizedPhone },\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Create a hosted invoice.\n * Auto-generates reference if omitted. Returns payment link and token.\n */\n async function createInvoice(\n input: CreateInvoiceInput,\n ): Promise<Result<InvoiceResponse, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throwValidation(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throwValidation(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throwValidation(\"item unitPrice must be a positive integer\");\n }\n }\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<InvoiceResponse>({\n action: SDK_ACTIONS.createInvoice,\n payload,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a webhook payload signature.\n * Delegates to the standalone verifyWebhookSignature utility.\n */\n function verifyWebhook(input: VerifyWebhookInput): boolean {\n return verifyWebhookSignature(input);\n }\n\n return {\n collectPayment,\n collectPaymentAndResolve,\n makePayout,\n makePayoutAndResolve,\n getStatus,\n getTransaction,\n verifyPhone,\n createInvoice,\n verifyWebhookSignature: verifyWebhook,\n };\n}\n","/**\n * Factory function to create a Nylon Pay SDK instance.\n * This is the main entry point for merchants.\n *\n * Calling createNylonPay with the same apiKey, apiSecret and baseUrl returns the\n * same instance (singleton per key+secret+url). Rotating the secret yields a\n * fresh instance. Pass { force: true } to force a new instance regardless.\n *\n * @example\n * ```ts\n * import { createNylonPay } from \"@nile-squad/nylonpay-ts\";\n *\n * export const nylonpay = createNylonPay({\n * apiKey: \"npk_...\",\n * apiSecret: \"nps_...\",\n * });\n * ```\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createSdkInstance, type NylonPaySdk } from \"./sdk\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_POLL_ATTEMPTS,\n DEFAULT_MAX_POLL_DURATION_MS,\n DEFAULT_MAX_POLL_INTERVAL_MS,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n} from \"./sdk.config\";\nimport type { NylonPayConfig } from \"./types\";\n\nconst instances = new Map<string, NylonPaySdk>();\n\n/**\n * Create a Nylon Pay SDK instance.\n *\n * Returns the same instance for the same apiKey + apiSecret + baseUrl\n * combination unless { force: true } is passed. Use your test keys for sandbox,\n * production keys for live.\n *\n * @param config - SDK configuration with apiKey and apiSecret\n * @returns SDK instance with all payment operations\n *\n * @throws Error if required config is missing or invalid\n */\nexport function createNylonPay(config: NylonPayConfig): NylonPaySdk {\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n if (!config.apiKey.startsWith(\"npk_\")) {\n throw new Error('apiKey must start with \"npk_\"');\n }\n if (!config.apiSecret) {\n throw new Error(\"apiSecret is required\");\n }\n if (!config.apiSecret.startsWith(\"nps_\")) {\n throw new Error('apiSecret must start with \"nps_\"');\n }\n\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n // Include a hash of the secret in the cache key so rotating apiSecret in a\n // long-running process returns a fresh instance instead of a stale one signing\n // with the old secret. Hashed (not raw) so the secret never sits in a Map key.\n const secretHash = createHash(\"sha256\")\n .update(config.apiSecret)\n .digest(\"hex\")\n .slice(0, 16);\n const instanceKey = `${config.apiKey}:${baseUrl}:${secretHash}`;\n\n if (!config.force) {\n const existing = instances.get(instanceKey);\n if (existing) return existing;\n }\n\n const resolvedConfig = {\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,\n maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,\n maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n hooks: config.hooks,\n };\n\n const instance = createSdkInstance(resolvedConfig);\n instances.set(instanceKey, instance);\n return instance;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -178,6 +178,13 @@ type Transaction = {
|
|
|
178
178
|
* payment was initiated; use a fresh reference to start a new one.
|
|
179
179
|
*/
|
|
180
180
|
duplicate?: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* The underlying operator's (telco's/bank's) own transaction id — what the
|
|
183
|
+
* paying customer sees on their receipt. Use it to cross-validate customer
|
|
184
|
+
* pay claims. Null until the operator reports it (typically at terminal
|
|
185
|
+
* status); may be absent on older backend versions.
|
|
186
|
+
*/
|
|
187
|
+
operatorTid?: string | null;
|
|
181
188
|
phone: string;
|
|
182
189
|
email: string | null;
|
|
183
190
|
failureReason: string | null;
|
|
@@ -348,15 +355,17 @@ type SdkError = {
|
|
|
348
355
|
retryable?: boolean;
|
|
349
356
|
};
|
|
350
357
|
/**
|
|
351
|
-
* Data passed to every payment event handler. `
|
|
352
|
-
* for status
|
|
353
|
-
* `
|
|
354
|
-
* reference
|
|
358
|
+
* Data passed to every payment event handler. `reference` is always present;
|
|
359
|
+
* `transaction` is populated for terminal status events (`success`, `failed`,
|
|
360
|
+
* `cancelled`) — the `processing` event can fire before the full record is
|
|
361
|
+
* fetched, so use `reference` there. `error` is populated for the `"error"`
|
|
362
|
+
* event (network failure, timeout, reference mismatch).
|
|
355
363
|
*
|
|
356
364
|
* @example
|
|
357
365
|
* ```ts
|
|
358
366
|
* payment.on("success", (data: EventData) => {
|
|
359
|
-
* console.log(data.
|
|
367
|
+
* console.log(data.reference); // "ORDER-2026-001"
|
|
368
|
+
* console.log(data.transaction?.id);
|
|
360
369
|
* console.log(data.timestamp); // "2026-05-30T12:00:00.000Z"
|
|
361
370
|
* });
|
|
362
371
|
* ```
|
|
@@ -364,7 +373,13 @@ type SdkError = {
|
|
|
364
373
|
type EventData = {
|
|
365
374
|
/** The event that triggered this handler. */
|
|
366
375
|
event: PaymentEvent;
|
|
367
|
-
/**
|
|
376
|
+
/**
|
|
377
|
+
* The transaction reference. Always present — available on every event,
|
|
378
|
+
* including lifecycle events fired before the full transaction record
|
|
379
|
+
* has been fetched.
|
|
380
|
+
*/
|
|
381
|
+
reference: string;
|
|
382
|
+
/** Full transaction record. Present for terminal status events. */
|
|
368
383
|
transaction?: Transaction;
|
|
369
384
|
/** Error message. Present for the `"error"` event. */
|
|
370
385
|
error?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -178,6 +178,13 @@ type Transaction = {
|
|
|
178
178
|
* payment was initiated; use a fresh reference to start a new one.
|
|
179
179
|
*/
|
|
180
180
|
duplicate?: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* The underlying operator's (telco's/bank's) own transaction id — what the
|
|
183
|
+
* paying customer sees on their receipt. Use it to cross-validate customer
|
|
184
|
+
* pay claims. Null until the operator reports it (typically at terminal
|
|
185
|
+
* status); may be absent on older backend versions.
|
|
186
|
+
*/
|
|
187
|
+
operatorTid?: string | null;
|
|
181
188
|
phone: string;
|
|
182
189
|
email: string | null;
|
|
183
190
|
failureReason: string | null;
|
|
@@ -348,15 +355,17 @@ type SdkError = {
|
|
|
348
355
|
retryable?: boolean;
|
|
349
356
|
};
|
|
350
357
|
/**
|
|
351
|
-
* Data passed to every payment event handler. `
|
|
352
|
-
* for status
|
|
353
|
-
* `
|
|
354
|
-
* reference
|
|
358
|
+
* Data passed to every payment event handler. `reference` is always present;
|
|
359
|
+
* `transaction` is populated for terminal status events (`success`, `failed`,
|
|
360
|
+
* `cancelled`) — the `processing` event can fire before the full record is
|
|
361
|
+
* fetched, so use `reference` there. `error` is populated for the `"error"`
|
|
362
|
+
* event (network failure, timeout, reference mismatch).
|
|
355
363
|
*
|
|
356
364
|
* @example
|
|
357
365
|
* ```ts
|
|
358
366
|
* payment.on("success", (data: EventData) => {
|
|
359
|
-
* console.log(data.
|
|
367
|
+
* console.log(data.reference); // "ORDER-2026-001"
|
|
368
|
+
* console.log(data.transaction?.id);
|
|
360
369
|
* console.log(data.timestamp); // "2026-05-30T12:00:00.000Z"
|
|
361
370
|
* });
|
|
362
371
|
* ```
|
|
@@ -364,7 +373,13 @@ type SdkError = {
|
|
|
364
373
|
type EventData = {
|
|
365
374
|
/** The event that triggered this handler. */
|
|
366
375
|
event: PaymentEvent;
|
|
367
|
-
/**
|
|
376
|
+
/**
|
|
377
|
+
* The transaction reference. Always present — available on every event,
|
|
378
|
+
* including lifecycle events fired before the full transaction record
|
|
379
|
+
* has been fetched.
|
|
380
|
+
*/
|
|
381
|
+
reference: string;
|
|
382
|
+
/** Full transaction record. Present for terminal status events. */
|
|
368
383
|
transaction?: Transaction;
|
|
369
384
|
/** Error message. Present for the `"error"` event. */
|
|
370
385
|
error?: string;
|
package/dist/index.js
CHANGED
|
@@ -373,6 +373,7 @@ function parseError(error) {
|
|
|
373
373
|
|
|
374
374
|
// src/payment.ts
|
|
375
375
|
var STATUS_TO_EVENT = {
|
|
376
|
+
pending: "processing",
|
|
376
377
|
successful: "success",
|
|
377
378
|
failed: "failed",
|
|
378
379
|
processing: "processing",
|
|
@@ -396,6 +397,7 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
396
397
|
status: normalizeStatus(initialResponse.status),
|
|
397
398
|
transaction: null,
|
|
398
399
|
pollingTimer: null,
|
|
400
|
+
lastStatusEvent: null,
|
|
399
401
|
resolved: false,
|
|
400
402
|
pollAttempts: 0,
|
|
401
403
|
pollStartTime: Date.now(),
|
|
@@ -414,6 +416,7 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
414
416
|
function emitEvent(event, error, category, retryable) {
|
|
415
417
|
const data = {
|
|
416
418
|
event,
|
|
419
|
+
reference: state.reference,
|
|
417
420
|
transaction: state.transaction ?? void 0,
|
|
418
421
|
error,
|
|
419
422
|
category,
|
|
@@ -450,18 +453,17 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
450
453
|
return;
|
|
451
454
|
}
|
|
452
455
|
const newStatus = normalizeStatus(response.status);
|
|
453
|
-
const oldStatus = state.status;
|
|
454
456
|
state.status = newStatus;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
457
|
+
const event = statusToEvent(newStatus);
|
|
458
|
+
if (!event || event === state.lastStatusEvent) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
state.lastStatusEvent = event;
|
|
462
|
+
if (TERMINAL_STATES.has(newStatus)) {
|
|
463
|
+
await handleTerminalState(newStatus);
|
|
464
|
+
return;
|
|
464
465
|
}
|
|
466
|
+
emitEvent(event);
|
|
465
467
|
}
|
|
466
468
|
function handlePollError(error) {
|
|
467
469
|
const parsed = parseError(error);
|
|
@@ -515,6 +517,15 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
515
517
|
}, 0);
|
|
516
518
|
return;
|
|
517
519
|
}
|
|
520
|
+
const initialEvent = statusToEvent(state.status);
|
|
521
|
+
if (initialEvent) {
|
|
522
|
+
state.lastStatusEvent = initialEvent;
|
|
523
|
+
setTimeout(() => {
|
|
524
|
+
if (!state.resolved) {
|
|
525
|
+
emitEvent(initialEvent);
|
|
526
|
+
}
|
|
527
|
+
}, 0);
|
|
528
|
+
}
|
|
518
529
|
scheduleNextPoll();
|
|
519
530
|
}
|
|
520
531
|
function stopUpdates() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pubsub.ts","../src/sdk.config.ts","../src/fingerprint.ts","../src/nonce.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.ts","../src/phone.ts","../src/verify-webhook.ts","../src/sdk.ts","../src/create-nylon-pay.ts"],"names":["createHmac","delay","timingSafeEqual","randomBytes","Ok","Err","createHash"],"mappings":";;;;;;;AAyCO,SAAS,aAAA,GAAkC;AAChD,EAAA,MAAM,KAAA,GAAyB;AAAA,IAC7B,SAAA,sBAAe,GAAA;AAAI,GACrB;AAMA,EAAA,SAAS,EAAA,CAAG,OAAU,OAAA,EAAmC;AACvD,IAAA,IAAI,CAAC,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,EAAG;AAC/B,MAAA,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAA,kBAAO,IAAI,KAAK,CAAA;AAAA,IACtC;AACA,IAAA,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,EAAG,IAAI,OAAgC,CAAA;AAChE,IAAA,OAAO,MAAM,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,EACjC;AAOA,EAAA,SAAS,IAAA,CAAK,OAAU,OAAA,EAAuC;AAC7D,IAAA,MAAM,OAAA,GAAwB,CAAC,IAAA,KAAS;AACtC,MAAA,GAAA,CAAI,OAAO,OAAO,CAAA;AAClB,MAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,IACd,CAAA;AACA,IAAA,EAAA,CAAG,OAAO,OAAO,CAAA;AACjB,IAAA,OAAO,OAAA;AAAA,EACT;AAKA,EAAA,SAAS,GAAA,CAAI,OAAU,OAAA,EAA6B;AAClD,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA;AAC1C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,OAAO,OAAgC,CAAA;AAAA,IAClD;AAAA,EACF;AAMA,EAAA,SAAS,IAAA,CAAK,OAAU,IAAA,EAAqB;AAC3C,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA;AAC1C,IAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,IAAA,KAAS,CAAA,EAAG;AACtC,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,IAAI;AACF,QAAC,QAAkC,IAAI,CAAA;AAAA,MACzC,CAAA,CAAA,MAAQ;AAAA,MAGR;AAAA,IACF;AAAA,EACF;AAKA,EAAA,SAAS,MAAM,KAAA,EAAiB;AAC9B,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,KAAA,CAAM,SAAA,CAAU,OAAO,KAAK,CAAA;AAAA,IAC9B,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,UAAU,KAAA,EAAM;AAAA,IACxB;AAAA,EACF;AAKA,EAAA,SAAS,cAAc,KAAA,EAAkB;AACvC,IAAA,OAAO,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAK,GAAG,IAAA,IAAQ,CAAA;AAAA,EAC7C;AAEA,EAAA,MAAM,UAAU,EAAE,EAAA,EAAI,MAAM,GAAA,EAAK,IAAA,EAAM,OAAO,aAAA,EAAc;AAC5D,EAAA,OAAO,OAAA;AACT;;;ACtHO,IAAM,gBAAA,GACX,iDAAA;AAGK,IAAM,kBAAA,GAAqB,GAAA;AAG3B,IAAM,mBAAA,GAAsB,CAAA;AAG5B,IAAM,4BAAA,GAA+B,GAAA;AAGrC,IAAM,4BAAA,GAA+B,GAAA;AAGrC,IAAM,yBAAA,GAA4B,GAAA;AAMlC,IAAM,cAAA,GAAiB,GAAA;AAGvB,IAAM,WAAA,GAAc,KAAA;AAGpB,IAAM,WAAA,GAAc;AAAA,EACzB,cAAA,EAAgB,qBAAA;AAAA,EAChB,wBAAA,EAA0B,iCAAA;AAAA,EAC1B,UAAA,EAAY,iBAAA;AAAA,EACZ,oBAAA,EAAsB,6BAAA;AAAA,EACtB,SAAA,EAAW,gBAAA;AAAA,EACX,cAAA,EAAgB,qBAAA;AAAA,EAChB,WAAA,EAAa,kBAAA;AAAA,EACb,aAAA,EAAe;AACjB,CAAA;AAGO,IAAM,sBAAA,mBAAyB,IAAI,GAAA,CAAI,CAAC,GAAA,EAAK,KAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC,CAAA;AClBrE,SAAS,mBAAA,GAA8B;AAC5C,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAA;AAAA,IACd,CAAA,SAAA,EAAY,UAAU,CAAA,CAAA;AAAA,IACtB,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAA;AAAA,IACd,CAAA,QAAA,EAAW,SAAS,CAAA,CAAA;AAAA,IACpB,CAAA,SAAA,EAAY,UAAU,CAAA,CAAA;AAAA,IACtB,CAAA,KAAA,EAAQ,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,CAAA;AAAA,IAC7B,CAAA,GAAA,EAAM,OAAA,CAAQ,QAAA,CAAS,EAAE,CAAA;AAAA,GAC3B,CAAE,KAAK,GAAG,CAAA;AAEV,EAAA,OAAO,WAAW,QAAQ,CAAA,CAAE,OAAO,UAAU,CAAA,CAAE,OAAO,KAAK,CAAA;AAC7D;ACdO,SAAS,aAAA,CAAc,SAAS,EAAA,EAAY;AACjD,EAAA,OAAO,WAAA,CAAY,MAAM,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA;AAC3C;ACEA,SAAS,kBAAA,CAAmB,OAAe,MAAA,EAAwB;AACjE,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,OAAO,EAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,OAAO,CAAA;AACT;AAEA,SAAS,UAAU,KAAA,EAAyB;AAC1C,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,MAAM,GAAA,CAAI,CAAC,KAAA,KAAU,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EAC9C;AAEA,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,IAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,OAAA,CAAQ,KAAgC,CAAA,CAAE,IAAA;AAAA,MACrE,CAAC,CAAC,QAAQ,CAAA,EAAG,CAAC,SAAS,CAAA,KAAM,kBAAA,CAAmB,QAAA,EAAU,SAAS;AAAA,KACrE;AAEA,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,MACZ,cAAc,GAAA,CAAI,CAAC,CAAC,QAAA,EAAU,UAAU,CAAA,KAAM;AAAA,QAC5C,QAAA;AAAA,QACA,UAAU,UAAU;AAAA,OACrB;AAAA,KACH;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAQO,SAAS,uBAAuB,OAAA,EAA0B;AAC/D,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,SAAA,CAAU,OAAO,CAAC,CAAA;AAC1C;AAWO,SAAS,uBAAuB,KAAA,EAK5B;AACT,EAAA,OAAO,CAAA,EAAG,KAAA,CAAM,WAAW,CAAA,CAAA,EAAI,KAAA,CAAM,KAAK,CAAA,CAAA,EAAI,KAAA,CAAM,SAAS,CAAA,CAAA,EAAI,sBAAA,CAAuB,KAAA,CAAM,OAAO,CAAC,CAAA,CAAA;AACxG;AAgBO,SAAS,gBAAgB,KAAA,EAMrB;AACT,EAAA,MAAM,OAAA,GAAU,uBAAuB,KAAK,CAAA;AAE5C,EAAA,OAAO,UAAA,CAAW,UAAU,KAAA,CAAM,MAAM,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AACxE;AAMO,SAAS,eAAA,GAA0B;AACxC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,EAAS;AAC7B;ACxGO,SAAS,uBAAA,CACd,IAAA,EACA,SAAA,EACA,MAAA,EACS;AACT,EAAA,MAAM,iBAAA,GAAoBA,UAAAA,CAAW,QAAA,EAAU,MAAM,CAAA,CAClD,MAAA,CAAO,sBAAA,CAAuB,IAAI,CAAC,CAAA,CACnC,MAAA,CAAO,KAAK,CAAA;AAEf,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,KAAK,CAAA;AACnD,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,IAAA,CAAK,iBAAA,EAAmB,KAAK,CAAA;AAE3D,EAAA,IAAI,cAAA,CAAe,MAAA,KAAW,cAAA,CAAe,MAAA,EAAQ;AACnD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,eAAA,CAAgB,gBAAgB,cAAc,CAAA;AACvD;;;ACNA,IAAM,qBAAqB,mBAAA,EAAoB;AAG/C,IAAM,gBAAA,uBAAuB,GAAA,CAAsB;AAAA,EACjD,MAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAC,CAAA;AAGD,IAAM,eAAA,GAAoD;AAAA,EACxD,GAAA,EAAK,SAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AAGA,IAAM,iBAAA,GAAoB,6CAAA;AAQ1B,SAAS,yBAAyB,OAAA,EAGhC;AACA,EAAA,MAAM,KAAA,GAAQ,iBAAA,CAAkB,IAAA,CAAK,OAAO,CAAA;AAC5C,EAAA,IAAI,KAAA,GAAQ,CAAC,CAAA,IAAK,gBAAA,CAAiB,IAAI,KAAA,CAAM,CAAC,CAAqB,CAAA,EAAG;AACpE,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,MAAM,CAAC,CAAA;AAAA,MACjB,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACvB;AAAA,EACF;AACA,EAAA,OAAO,EAAE,QAAA,EAAU,IAAA,EAAM,OAAA,EAAQ;AACnC;AAGA,SAAS,eAAe,MAAA,EAGX;AACX,EAAA,MAAM,MAAA,GAAS,wBAAA,CAAyB,MAAA,CAAO,OAAO,CAAA;AACtD,EAAA,MAAM,QAAA,GACJ,MAAA,CAAO,QAAA,IACP,eAAA,CAAgB,MAAA,CAAO,UAAU,CAAA,KAChC,MAAA,CAAO,UAAA,IAAc,GAAA,GAAM,UAAA,GAAa,YAAA,CAAA;AAC3C,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,SAAA,EAAW,sBAAA,CAAuB,GAAA,CAAI,MAAA,CAAO,UAAU;AAAA,GACzD;AACF;AAQO,SAAS,eAAe,KAAA,EAAmC;AAChE,EAAA,OAAO,OAAO,MAAA,CAAO,IAAI,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA,EAAG;AAAA,IAC7C,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,WAAW,KAAA,CAAM;AAAA,GAClB,CAAA;AACH;AAGA,SAAS,iBAAiB,OAAA,EAAyB;AACjD,EAAA,MAAM,IAAA,GAAO,KAAK,OAAA,GAAU,GAAA;AAC5B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA;AAC/B,EAAA,OAAO,IAAA,GAAO,MAAA;AAChB;AAGA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAGA,SAAS,uBAA0B,OAAA,EAGjC;AACA,EAAA,IACE,CAAC,OAAA,IACD,OAAO,YAAY,QAAA,IACnB,EAAE,wBAAwB,OAAA,CAAA,EAC1B;AACA,IAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,iBAAA,EAAmB,IAAA,EAAK;AAAA,EAClD;AAEA,EAAA,MAAM,EAAE,kBAAA,EAAoB,GAAG,IAAA,EAAK,GAAI,OAAA;AAExC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,IAAA;AAAA,IACN,iBAAA,EACE,OAAO,kBAAA,KAAuB,QAAA,GAAW,kBAAA,GAAqB;AAAA,GAClE;AACF;AAGA,SAAS,aAAA,CAAc;AAAA,EACrB,MAAA;AAAA,EACA;AACF,CAAA,EAA8C;AAC5C,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,SAAA;AAAA,IACR,OAAA,EAAS,WAAA;AAAA,IACT,MAAA;AAAA,IACA,OAAA,EAAS;AAAA,MACP,GAAI,OAAA;AAAA,MACJ,YAAA,EAAc;AAAA;AAChB,GACF;AACF;AAUA,SAAS,gBAAA,CAAiB;AAAA,EACxB,MAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAI2B;AACzB,EAAA,MAAM,QAAQ,aAAA,EAAc;AAC5B,EAAA,MAAM,YAAY,eAAA,EAAgB;AAClC,EAAA,MAAM,YAAY,eAAA,CAAgB;AAAA,IAChC,WAAA,EAAa,kBAAA;AAAA,IACb,KAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACT,CAAA;AAED,EAAA,OAAO;AAAA,IACL,cAAA,EAAgB,kBAAA;AAAA,IAChB,aAAA,EAAe,MAAA;AAAA,IACf,eAAA,EAAiB,KAAA;AAAA,IACjB,mBAAA,EAAqB,SAAA;AAAA,IACrB,mBAAA,EAAqB;AAAA,GACvB;AACF;AAGA,SAAS,YAAY,SAAA,EAGnB;AACA,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,SAAS,CAAA;AAChE,EAAA,OAAO,EAAE,UAAA,EAAY,OAAA,EAAS,MAAM,YAAA,CAAa,SAAS,CAAA,EAAE;AAC9D;AAUO,SAAS,eAAA,CAAgB;AAAA,EAC9B,MAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA,GAAU,gBAAA;AAAA,EACV,SAAA,GAAY,kBAAA;AAAA,EACZ,UAAA,GAAa,mBAAA;AAAA,EACb,KAAA,EAAO;AACT,CAAA,EAOG;AAKD,EAAA,eAAe,KACb,OAAA,EAC4B;AAC5B,IAAA,MAAM,QAAA,GAAW,cAAc,OAAO,CAAA;AACtC,IAAA,MAAM,gBAAiB,QAAA,CAAkC,OAAA;AACzD,IAAA,MAAM,UAAU,gBAAA,CAAiB;AAAA,MAC/B,MAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACV,CAAA;AACD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA;AAE1C,IAAA,eAAe,QAAQ,cAAA,EAAoD;AACzE,MAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAQ,GAAI,YAAY,SAAS,CAAA;AAErD,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,OAAA,EAAS;AAAA,UACxC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA;AAAA,UACA,IAAA,EAAM,UAAA;AAAA,UACN,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAED,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,MAAM,aAAa,QAAA,CAAS,MAAA;AAC5B,UAAA,MAAM,SAAA,GAAY,sBAAA,CAAuB,GAAA,CAAI,UAAU,CAAA;AAEvD,UAAA,IAAI,YAAA,GAAe,QAAQ,UAAU,CAAA,CAAA;AACrC,UAAA,IAAI;AACF,YAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,YAAA,IACE,SAAA,IACA,OAAO,SAAA,KAAc,QAAA,IACrB,aAAa,SAAA,EACb;AACA,cAAA,YAAA,GAAe,MAAA,CAAO,UAAU,OAAO,CAAA;AAAA,YACzC;AAAA,UACF,CAAA,CAAA,MAAQ;AACN,YAAA,YAAA,GAAe,SAAS,UAAA,IAAc,YAAA;AAAA,UACxC;AAEA,UAAA,IAAI,SAAA,IAAa,iBAAiB,UAAA,EAAY;AAC5C,YAAA,OAAA,EAAQ;AACR,YAAA,MAAM,KAAA,CAAM,gBAAA,CAAiB,cAAc,CAAC,CAAA;AAC5C,YAAA,OAAO,OAAA,CAAQ,iBAAiB,CAAC,CAAA;AAAA,UACnC;AAEA,UAAA,OAAA,EAAQ;AACR,UAAA,OAAO,GAAA;AAAA,YACL,IAAA,CAAK,SAAA;AAAA,cACH,cAAA,CAAe,EAAE,OAAA,EAAS,YAAA,EAAc,YAAY;AAAA;AACtD,WACF;AAAA,QACF;AAEA,QAAA,MAAM,YAAA,GAAe,MAAM,QAAA,CAAS,IAAA,EAAK;AAEzC,QAAA,IACE,CAAC,YAAA,IACD,OAAO,iBAAiB,QAAA,IACxB,EAAE,YAAY,YAAA,CAAA,EACd;AACA,UAAA,OAAA,EAAQ;AACR,UAAA,OAAO,GAAA;AAAA,YACL,KAAK,SAAA,CAAU;AAAA,cACb,QAAA,EAAU,UAAA;AAAA,cACV,OAAA,EAAS,+BAAA;AAAA,cACT,SAAA,EAAW;AAAA,aACO;AAAA,WACtB;AAAA,QACF;AAEA,QAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAK,GAAI,YAAA;AAMlC,QAAA,IAAI,WAAW,IAAA,EAAM;AACnB,UAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAc,iBAAA,EAAkB,GAC5C,uBAAuB,IAAI,CAAA;AAQ7B,UAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,YAAA,OAAA,EAAQ;AACR,YAAA,OAAO,GAAA;AAAA,cACL,KAAK,SAAA,CAAU;AAAA,gBACb,QAAA,EAAU,UAAA;AAAA,gBACV,OAAA,EAAS,4BAAA;AAAA,gBACT,SAAA,EAAW;AAAA,eACO;AAAA,aACtB;AAAA,UACF;AAEA,UAAA,MAAM,OAAA,GAAU,uBAAA;AAAA,YACd,YAAA;AAAA,YACA,iBAAA;AAAA,YACA;AAAA,WACF;AACA,UAAA,IAAI,CAAC,OAAA,EAAS;AACZ,YAAA,OAAA,EAAQ;AACR,YAAA,OAAO,GAAA;AAAA,cACL,KAAK,SAAA,CAAU;AAAA,gBACb,QAAA,EAAU,UAAA;AAAA,gBACV,OAAA,EAAS,wCAAA;AAAA,gBACT,SAAA,EAAW;AAAA,eACO;AAAA,aACtB;AAAA,UACF;AAEA,UAAA,OAAA,EAAQ;AACR,UAAA,OAAO,GAAG,YAAiB,CAAA;AAAA,QAC7B;AAGA,QAAA,MAAM,WAAA,GAAc,WAAW,OAAO,CAAA;AACtC,QAAA,OAAA,EAAQ;AACR,QAAA,OAAO,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,WAAW,CAAC,CAAA;AAAA,MACxC,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,EAAQ;AAER,QAAA,MAAM,OAAA,GACJ,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,YAAA;AAClD,QAAA,MAAM,QAAA,GAAqB;AAAA,UACzB,QAAA,EAAU,UAAU,SAAA,GAAY,SAAA;AAAA,UAChC,SAAS,OAAA,GACL,CAAA,wBAAA,EAA2B,SAAS,CAAA,EAAA,CAAA,GACpC,OAAO,KAAK,CAAA;AAAA,UAChB,SAAA,EAAW;AAAA,SACb;AAEA,QAAA,IAAI,iBAAiB,UAAA,EAAY;AAC/B,UAAA,MAAM,KAAA,CAAM,gBAAA,CAAiB,cAAc,CAAC,CAAA;AAC5C,UAAA,OAAO,OAAA,CAAQ,iBAAiB,CAAC,CAAA;AAAA,QACnC;AAEA,QAAA,OAAO,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,MACrC;AAAA,IACF;AAEA,IAAA,OAAO,QAAQ,CAAC,CAAA;AAAA,EAClB;AAEA,EAAA,OAAO,EAAE,MAAM,UAAA,EAAW;AAC5B;AAiBO,SAAS,WAAW,KAAA,EAAyB;AAIlD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAC/B,IAAA,IACE,MAAA,IACA,OAAO,MAAA,KAAW,QAAA,IAClB,cAAc,MAAA,IACd,SAAA,IAAa,MAAA,IACb,OAAQ,OAAmC,QAAA,KAAa,QAAA,IACxD,OAAQ,MAAA,CAAmC,YAAY,QAAA,EACvD;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAGA,EAAA,MAAM,UAAA,GAAa,yBAAyB,KAAK,CAAA;AACjD,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,WAAW,QAAA,IAAY,UAAA;AAAA,IACjC,SAAS,UAAA,CAAW;AAAA,GACtB;AACF;;;AC5WA,IAAM,eAAA,GAAoE;AAAA,EACxE,UAAA,EAAY,SAAA;AAAA,EACZ,MAAA,EAAQ,QAAA;AAAA,EACR,UAAA,EAAY,YAAA;AAAA,EACZ,SAAA,EAAW;AACb,CAAA;AAEA,SAAS,cAAc,MAAA,EAAgD;AACrE,EAAA,OAAO,eAAA,CAAgB,MAAM,CAAA,IAAK,IAAA;AACpC;AAGA,IAAM,eAAA,uBAAsB,GAAA,CAAuB;AAAA,EACjD,YAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAC,CAAA;AAOD,SAAS,gBAAgB,GAAA,EAAgC;AACvD,EAAA,IAAI,GAAA,KAAQ,aAAa,OAAO,YAAA;AAChC,EAAA,OAAO,GAAA;AACT;AAWO,SAAS,qBAAA,CACd,iBACA,IAAA,EAiBiB;AACjB,EAAA,MAAM,KAAA,GAAsB;AAAA,IAC1B,WAAW,eAAA,CAAgB,SAAA;AAAA,IAC3B,MAAA,EAAQ,eAAA,CAAgB,eAAA,CAAgB,MAAM,CAAA;AAAA,IAC9C,WAAA,EAAa,IAAA;AAAA,IACb,YAAA,EAAc,IAAA;AAAA,IACd,QAAA,EAAU,KAAA;AAAA,IACV,YAAA,EAAc,CAAA;AAAA,IACd,aAAA,EAAe,KAAK,GAAA,EAAI;AAAA,IACxB,SAAS,aAAA,EAA4B;AAAA,IACrC,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,kBAAkB,IAAA,CAAK,gBAAA;AAAA,IACvB,cAAA,EAAgB,KAAK,cAAA,IAAkB,GAAA;AAAA,IACvC,eAAA,EAAiB,KAAK,eAAA,IAAmB,GAAA;AAAA,IACzC,eAAA,EAAiB,KAAK,eAAA,IAAmB;AAAA,GAC3C;AAEA,EAAA,SAAS,iBAAiB,KAAA,EAAqB;AAC7C,IAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,IAAA,WAAA,EAAY;AACZ,IAAA,SAAA,CAAU,OAAA,EAAS,UAAA,CAAW,KAAK,CAAA,CAAE,OAAO,CAAA;AAAA,EAC9C;AAMA,EAAA,SAAS,SAAA,CACP,KAAA,EACA,KAAA,EACA,QAAA,EACA,SAAA,EACM;AACN,IAAA,MAAM,IAAA,GAAkB;AAAA,MACtB,KAAA;AAAA,MACA,WAAA,EAAa,MAAM,WAAA,IAAe,MAAA;AAAA,MAClC,KAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,KACpC;AACA,IAAA,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAO,IAAI,CAAA;AAAA,EAChC;AAMA,EAAA,eAAe,oBAAoB,MAAA,EAA0C;AAC3E,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,gBAAA,CAAiB;AAAA,MAC5C,WAAW,KAAA,CAAM;AAAA,KAClB,CAAA;AACD,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,KAAA,CAAM,cAAc,QAAA,CAAS,KAAA;AAC7B,MAAA,MAAM,KAAA,GAAQ,cAAc,MAAM,CAAA;AAClC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,MAAM,QACJ,MAAA,KAAW,QAAA,GACN,KAAA,CAAM,WAAA,CAAY,iBAAiB,MAAA,GACpC,MAAA;AACN,QAAA,SAAA,CAAU,OAAO,KAAK,CAAA;AAAA,MACxB;AAAA,IACF,CAAA,MAAO;AACL,MAAA,SAAA,CAAU,OAAA,EAAS,CAAA,6BAAA,EAAgC,QAAA,CAAS,KAAK,CAAA,CAAE,CAAA;AAAA,IACrE;AACA,IAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,IAAA,WAAA,EAAY;AAAA,EACd;AAMA,EAAA,eAAe,mBAAmB,QAAA,EAAyC;AAMzE,IAAA,IAAI,MAAM,QAAA,EAAU;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,QAAA,CAAS,SAAA,KAAc,KAAA,CAAM,SAAA,EAAW;AAC1C,MAAA,gBAAA;AAAA,QACE,CAAA,6BAAA,EAAgC,KAAA,CAAM,SAAS,CAAA,SAAA,EAAY,SAAS,SAAS,CAAA;AAAA,OAC/E;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,QAAA,CAAS,MAAM,CAAA;AACjD,IAAA,MAAM,YAAY,KAAA,CAAM,MAAA;AAExB,IAAA,KAAA,CAAM,MAAA,GAAS,SAAA;AAEf,IAAA,IAAI,cAAc,SAAA,EAAW;AAC3B,MAAA,MAAM,KAAA,GAAQ,cAAc,SAAS,CAAA;AACrC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,SAAS,CAAA,EAAG;AAClC,UAAA,MAAM,oBAAoB,SAAS,CAAA;AACnC,UAAA;AAAA,QACF;AACA,QAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AASA,EAAA,SAAS,gBAAgB,KAAA,EAAqB;AAC5C,IAAA,MAAM,MAAA,GAAS,WAAW,KAAK,CAAA;AAC/B,IAAA,IAAI,MAAA,CAAO,aAAa,WAAA,EAAa;AACnC,MAAA;AAAA,IACF;AACA,IAAA,SAAA,CAAU,OAAA,EAAS,OAAO,OAAO,CAAA;AACjC,IAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,IAAA,WAAA,EAAY;AAAA,EACd;AAUA,EAAA,SAAS,gBAAA,GAAyB;AAChC,IAAA,IAAI,KAAA,CAAM,QAAA,IAAY,KAAA,CAAM,YAAA,EAAc;AACxC,MAAA;AAAA,IACF;AAEA,IAAA,MAAMC,MAAAA,GAAQ,KAAA,CAAM,cAAA,GAAiB,IAAA,CAAK,QAAO,GAAI,cAAA;AACrD,IAAA,KAAA,CAAM,YAAA,GAAe,WAAW,MAAM;AACpC,MAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AACrB,MAAA,KAAK,UAAA,EAAW;AAAA,IAClB,GAAGA,MAAK,CAAA;AAAA,EACV;AAMA,EAAA,eAAe,UAAA,GAA4B;AACzC,IAAA,IAAI,MAAM,QAAA,EAAU;AAClB,MAAA,WAAA,EAAY;AACZ,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,KAAA,CAAM,YAAA,IAAgB,KAAA,CAAM,eAAA,EAAiB;AAC/C,MAAA,gBAAA,CAAiB,4CAA4C,CAAA;AAC7D,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,KAAK,GAAA,EAAI,GAAI,KAAA,CAAM,aAAA,IAAiB,MAAM,eAAA,EAAiB;AAC7D,MAAA,gBAAA,CAAiB,4CAA4C,CAAA;AAC7D,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,YAAA,IAAgB,CAAA;AAEtB,IAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,WAAA,CAAY,EAAE,SAAA,EAAW,KAAA,CAAM,WAAW,CAAA;AAErE,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAM,kBAAA,CAAmB,OAAO,KAAK,CAAA;AAAA,IACvC,CAAA,MAAO;AACL,MAAA,eAAA,CAAgB,OAAO,KAAK,CAAA;AAAA,IAC9B;AAEA,IAAA,IAAI,MAAM,QAAA,EAAU;AAClB,MAAA,WAAA,EAAY;AACZ,MAAA;AAAA,IACF;AAEA,IAAA,gBAAA,EAAiB;AAAA,EACnB;AAQA,EAAA,SAAS,YAAA,GAAqB;AAC5B,IAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACrC,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,KAAK,mBAAA,CAAoB,MAAM,MAAM,CAAA;AAAA,MACvC,GAAG,CAAC,CAAA;AACJ,MAAA;AAAA,IACF;AACA,IAAA,gBAAA,EAAiB;AAAA,EACnB;AAMA,EAAA,SAAS,WAAA,GAAoB;AAC3B,IAAA,IAAI,MAAM,YAAA,EAAc;AACtB,MAAA,YAAA,CAAa,MAAM,YAAY,CAAA;AAC/B,MAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AAAA,IACvB;AAAA,EACF;AAKA,EAAA,SAAS,EAAA,CACP,OACA,OAAA,EACiB;AACjB,IAAA,KAAA,CAAM,OAAA,CAAQ,EAAA,CAAG,KAAA,EAAO,OAAkC,CAAA;AAC1D,IAAA,OAAO,eAAA;AAAA,EACT;AAKA,EAAA,SAAS,GAAA,CACP,OACA,OAAA,EACiB;AACjB,IAAA,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,OAAkC,CAAA;AAC3D,IAAA,OAAO,eAAA;AAAA,EACT;AAMA,EAAA,SAAS,IAAA,CACP,OACA,OAAA,EACiB;AACjB,IAAA,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAO,OAAkC,CAAA;AAC5D,IAAA,OAAO,eAAA;AAAA,EACT;AAOA,EAAA,SAAS,IAAA,GAAoC;AAC3C,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,IAAI,MAAM,QAAA,EAAU;AAClB,QAAA,OAAA;AAAA,UACE,MAAM,MAAA,KAAW,YAAA,IAAgB,KAAA,CAAM,WAAA,GACnC,MAAM,WAAA,GACN;AAAA,SACN;AACA,QAAA;AAAA,MACF;AAEA,MAAA,SAAS,SAAA,GAAkB;AACzB,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,CAAQ,KAAA,CAAM,eAAe,IAAI,CAAA;AAAA,MACnC;AAEA,MAAA,SAAS,QAAA,GAAiB;AACxB,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd;AAEA,MAAA,SAAS,WAAA,GAAoB;AAC3B,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd;AAEA,MAAA,SAAS,OAAA,GAAgB;AACvB,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd;AAEA,MAAA,SAAS,OAAA,GAAgB;AACvB,QAAA,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,SAAS,CAAA;AACtC,QAAA,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,QAAA,EAAU,QAAQ,CAAA;AACpC,QAAA,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,WAAA,EAAa,WAAW,CAAA;AAC1C,QAAA,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,OAAA,EAAS,OAAO,CAAA;AAAA,MACpC;AAEA,MAAA,KAAA,CAAM,OAAA,CAAQ,EAAA,CAAG,SAAA,EAAW,SAAS,CAAA;AACrC,MAAA,KAAA,CAAM,OAAA,CAAQ,EAAA,CAAG,QAAA,EAAU,QAAQ,CAAA;AACnC,MAAA,KAAA,CAAM,OAAA,CAAQ,EAAA,CAAG,WAAA,EAAa,WAAW,CAAA;AACzC,MAAA,KAAA,CAAM,OAAA,CAAQ,EAAA,CAAG,OAAA,EAAS,OAAO,CAAA;AAAA,IACnC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,eAAA,GAAmC;AAAA,IACvC,IAAI,SAAA,GAAY;AACd,MAAA,OAAO,KAAA,CAAM,SAAA;AAAA,IACf,CAAA;AAAA,IACA,IAAI,MAAA,GAAS;AACX,MAAA,OAAO,KAAA,CAAM,MAAA;AAAA,IACf,CAAA;AAAA,IACA,EAAA;AAAA,IACA,IAAA;AAAA,IACA,GAAA;AAAA,IACA;AAAA,GACF;AAKA,EAAA,IAAI,KAAK,YAAA,EAAc;AACrB,IAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,IAAA,MAAM,MAAM,IAAA,CAAK,YAAA;AACjB,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,SAAA,CAAU,SAAS,GAAA,CAAI,OAAA,EAAS,GAAA,CAAI,QAAA,EAAU,IAAI,SAAS,CAAA;AAAA,IAC7D,GAAG,CAAC,CAAA;AAAA,EACN,CAAA,MAAO;AACL,IAAA,YAAA,EAAa;AAAA,EACf;AAEA,EAAA,OAAO,eAAA;AACT;;;AC/ZO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,IAAI,UAAA,GAAa,MAAM,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AAE5D,EAAA,IAAI,WAAW,UAAA,CAAW,GAAG,CAAA,IAAK,UAAA,CAAW,WAAW,EAAA,EAAI;AAC1D,IAAA,UAAA,GAAa,CAAA,GAAA,EAAM,UAAA,CAAW,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,UAAA;AACT;ACTA,IAAM,yBAAA,GAA4B,GAAA;AAGlC,SAAS,cAAc,OAAA,EAAsC;AAC3D,EAAA,OAAO,OAAO,YAAY,QAAA,GACtB,OAAA,GACA,OAAO,IAAA,CAAK,OAAO,CAAA,CAAE,QAAA,CAAS,MAAM,CAAA;AAC1C;AASA,SAAS,yBAAyB,aAAA,EAAsC;AACtE,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAA,CAAK,MAAM,aAAa,CAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,EAAU;AACzC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAO,MAAA,CAAmC,SAAA;AAEhD,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AAEnD,IAAA,OAAO,GAAA,GAAM,IAAA,GAAO,GAAA,GAAM,GAAA,GAAO,GAAA;AAAA,EACnC;AAEA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AACzB,IAAA,OAAO,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,GAAI,IAAA,GAAO,EAAA;AAAA,EACnC;AAEA,EAAA,OAAO,IAAA;AACT;AAiBO,SAAS,uBAAuB,KAAA,EAAoC;AACzE,EAAA,MAAM,aAAA,GAAgB,aAAA,CAAc,KAAA,CAAM,OAAO,CAAA;AACjD,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,IAAA,CAAK,aAAA,EAAe,MAAM,CAAA;AAEtD,EAAA,MAAM,iBAAA,GAAoBD,UAAAA,CAAW,QAAA,EAAU,KAAA,CAAM,MAAM,EACxD,MAAA,CAAO,YAAY,CAAA,CACnB,MAAA,CAAO,KAAK,CAAA;AAEf,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,WAAW,KAAK,CAAA;AACzD,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,IAAA,CAAK,iBAAA,EAAmB,KAAK,CAAA;AAE3D,EAAA,IAAI,cAAA,CAAe,MAAA,KAAW,cAAA,CAAe,MAAA,EAAQ;AACnD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAACE,eAAAA,CAAgB,cAAA,EAAgB,cAAc,CAAA,EAAG;AACpD,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,MAAM,gBAAA,GAAmB,MAAM,gBAAA,IAAoB,yBAAA;AACnD,EAAA,IAAI,oBAAoB,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,yBAAyB,aAAa,CAAA;AAC1D,EAAA,IAAI,gBAAgB,IAAA,EAAM;AAGxB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,KAAQ,WAAW,CAAA;AAC/C,EAAA,OAAO,SAAS,gBAAA,GAAmB,GAAA;AACrC;;;ACvDA,SAAS,iBAAA,GAA4B;AACnC,EAAA,OAAOC,WAAAA,CAAY,EAAE,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AACpD;AASA,IAAM,oBAAA,GAAuB,EAAA;AAC7B,IAAM,oBAAA,GAAuB,EAAA;AAQ7B,SAAS,iBAAiB,SAAA,EAA4B;AACpD,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA,OAAO,iBAAA,EAAkB;AAAA,EAC3B;AACA,EAAA,IACE,SAAA,CAAU,MAAA,GAAS,oBAAA,IACnB,SAAA,CAAU,SAAS,oBAAA,EACnB;AACA,IAAA,eAAA;AAAA,MACE,CAAA,kBAAA,EAAqB,oBAAoB,CAAA,MAAA,EAAI,oBAAoB,CAAA,WAAA;AAAA,KACnE;AAAA,EACF;AACA,EAAA,OAAO,SAAA;AACT;AAYA,eAAe,OAAA,CACb,SACG,IAAA,EAC4C;AAC/C,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,OAAA,KAAY,OAAO,OAAO,MAAA;AAE5C,EAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,YAAY,KAAK,EAAA,CAAG,GAAG,IAAI,CAAC,CAAA;AAGzD,EAAA,IAAI,MAAA,CAAO,IAAA,EAAM,OAAO,MAAA,CAAO,KAAA;AAE/B,EAAA,MAAM,QAAQ,YAAY,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAC,CAAA;AACpD,EAAA,OAAO,MAAA;AACT;AAOA,SAAS,gBAAgB,OAAA,EAAwB;AAC/C,EAAA,MAAM,cAAA,CAAe,EAAE,QAAA,EAAU,YAAA,EAAc,SAAS,CAAA;AAC1D;AAGA,SAAS,yBAAyB,MAAA,EAAsB;AACtD,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,MAAM,CAAA,IAAK,UAAU,CAAA,EAAG;AAC5C,IAAA,eAAA,CAAgB,mCAAmC,CAAA;AAAA,EACrD;AACA,EAAA,IAAI,SAAS,GAAA,EAAK;AAChB,IAAA,eAAA,CAAgB,4CAA4C,CAAA;AAAA,EAC9D;AACF;AAGA,SAAS,qBAAqB,MAAA,EAAsB;AAClD,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,MAAM,CAAA,IAAK,UAAU,CAAA,EAAG;AAC5C,IAAA,eAAA,CAAgB,mCAAmC,CAAA;AAAA,EACrD;AACA,EAAA,IAAI,SAAS,GAAA,EAAM;AACjB,IAAA,eAAA,CAAgB,yCAAyC,CAAA;AAAA,EAC3D;AACF;AAGA,SAAS,gBAAA,CAAiB,OAAe,SAAA,EAAyB;AAChE,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,IAAA,OAAW,EAAA,EAAI;AACjC,IAAA,eAAA,CAAgB,CAAA,EAAG,SAAS,CAAA,YAAA,CAAc,CAAA;AAAA,EAC5C;AACF;AAMO,SAAS,kBAAkB,MAAA,EAAqC;AACrE,EAAA,MAAM,YAAY,eAAA,CAAgB;AAAA,IAChC,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,OAAO,MAAA,CAAO;AAAA,GACf,CAAA;AAED,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,WAAA,EAAa,CAAC,KAAA,KACZ,SAAA,CAAU,IAAA,CAAqB;AAAA,MAC7B,QAAQ,WAAA,CAAY,SAAA;AAAA,MACpB,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,IACH,gBAAA,EAAkB,CAAC,KAAA,KACjB,SAAA,CAAU,IAAA,CAAkB;AAAA,MAC1B,QAAQ,WAAA,CAAY,cAAA;AAAA,MACpB,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,IACH,gBAAgB,MAAA,CAAO,iBAAA;AAAA,IACvB,iBAAiB,MAAA,CAAO,iBAAA;AAAA,IACxB,iBAAiB,MAAA,CAAO;AAAA,GAC1B;AAOA,EAAA,eAAe,eACb,KAAA,EAC0B;AAC1B,IAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,KAAA,CAAM,SAAS,CAAA;AAClD,IAAA,wBAAA,CAAyB,MAAM,MAAM,CAAA;AACrC,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,IAAA,EAAM,eAAe,CAAA;AACrD,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,WAAA,EAAa,sBAAsB,CAAA;AACnE,IAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,KAAA,CAAM,QAAA,CAAS,WAAW,CAAA;AACjE,IAAA,gBAAA,CAAiB,KAAA,CAAM,aAAa,aAAa,CAAA;AACjD,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,MAAA,IAAU,CAAC,MAAM,IAAA,EAAM;AAC1C,MAAA,eAAA,CAAgB,iDAAiD,CAAA;AAAA,IACnE;AAEA,IAAA,IAAI,OAAA,GAAU;AAAA,MACZ,GAAG,KAAA;AAAA,MACH,SAAA;AAAA,MACA,UAAU,EAAE,GAAG,KAAA,CAAM,QAAA,EAAU,aAAa,eAAA;AAAgB,KAC9D;AACA,IAAA,MAAM,UAAU,MAAM,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,eAAe,OAAO,CAAA;AAClE,IAAA,IAAI,OAAA,IAAW,IAAA;AACb,MAAA,OAAA,GAAU,EAAE,GAAG,OAAA,EAAS,SAAA,EAAW,OAAA,CAAQ,aAAa,SAAA,EAAU;AAEpE,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAG5B;AAAA,MACD,QAAQ,WAAA,CAAY,cAAA;AAAA,MACpB;AAAA,KACD,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,MACJ,OAAO,KAAA,EAAO,YAAA;AAAA,MACd,OAAO,IAAA,GACHC,EAAAA,CAAG,EAAE,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA,EAAW,MAAA,EAAQ,MAAA,CAAO,MAAM,MAAA,EAAQ,CAAA,GACrEC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,MACpB;AAAA,KACF;AAKA,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,MAAM,MAAA,GAAS,UAAA,CAAW,MAAA,CAAO,KAAK,CAAA;AACtC,MAAA,OAAO,qBAAA;AAAA,QACL,EAAE,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAU;AAAA,QAC/B,EAAE,GAAG,UAAA,EAAY,YAAA,EAAc,MAAA;AAAO,OACxC;AAAA,IACF;AAEA,IAAA,OAAO,qBAAA,CAAsB,MAAA,CAAO,KAAA,EAAO,UAAU,CAAA;AAAA,EACvD;AAMA,EAAA,eAAe,yBACb,KAAA,EACsC;AACtC,IAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,KAAA,CAAM,SAAS,CAAA;AAClD,IAAA,wBAAA,CAAyB,MAAM,MAAM,CAAA;AACrC,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,IAAA,EAAM,eAAe,CAAA;AACrD,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,WAAA,EAAa,sBAAsB,CAAA;AACnE,IAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,KAAA,CAAM,QAAA,CAAS,WAAW,CAAA;AACjE,IAAA,gBAAA,CAAiB,KAAA,CAAM,aAAa,aAAa,CAAA;AACjD,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,MAAA,IAAU,CAAC,MAAM,IAAA,EAAM;AAC1C,MAAA,eAAA,CAAgB,iDAAiD,CAAA;AAAA,IACnE;AAEA,IAAA,IAAI,OAAA,GAAU;AAAA,MACZ,GAAG,KAAA;AAAA,MACH,SAAA;AAAA,MACA,UAAU,EAAE,GAAG,KAAA,CAAM,QAAA,EAAU,aAAa,eAAA;AAAgB,KAC9D;AACA,IAAA,MAAM,UAAU,MAAM,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,eAAe,OAAO,CAAA;AAClE,IAAA,IAAI,OAAA,IAAW,IAAA;AACb,MAAA,OAAA,GAAU,EAAE,GAAG,OAAA,EAAS,SAAA,EAAW,OAAA,CAAQ,aAAa,SAAA,EAAU;AAEpE,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAAkB;AAAA,MAC/C,QAAQ,WAAA,CAAY,wBAAA;AAAA,MACpB;AAAA,KACD,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,MACJ,OAAO,KAAA,EAAO,YAAA;AAAA,MACd,OAAO,IAAA,GACHD,EAAAA,CAAG,EAAE,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA,EAAW,MAAA,EAAQ,MAAA,CAAO,MAAM,MAAA,EAAQ,CAAA,GACrEC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,MACpB;AAAA,KACF;AAEA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,OAAOD,EAAAA,CAAG,OAAO,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAOC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACzB;AAOA,EAAA,eAAe,WAAW,KAAA,EAAkD;AAC1E,IAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,KAAA,CAAM,SAAS,CAAA;AAClD,IAAA,oBAAA,CAAqB,MAAM,MAAM,CAAA;AACjC,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,IAAA,EAAM,eAAe,CAAA;AACrD,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,WAAA,EAAa,sBAAsB,CAAA;AACnE,IAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,KAAA,CAAM,QAAA,CAAS,WAAW,CAAA;AACjE,IAAA,gBAAA,CAAiB,KAAA,CAAM,aAAa,aAAa,CAAA;AACjD,IAAA,gBAAA;AAAA,MACE,MAAM,WAAA,CAAY,iBAAA;AAAA,MAClB;AAAA,KACF;AACA,IAAA,gBAAA;AAAA,MACE,MAAM,WAAA,CAAY,aAAA;AAAA,MAClB;AAAA,KACF;AAEA,IAAA,IAAI,OAAA,GAAU;AAAA,MACZ,GAAG,KAAA;AAAA,MACH,SAAA;AAAA,MACA,UAAU,EAAE,GAAG,KAAA,CAAM,QAAA,EAAU,aAAa,eAAA;AAAgB,KAC9D;AACA,IAAA,MAAM,UAAU,MAAM,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,cAAc,OAAO,CAAA;AACjE,IAAA,IAAI,OAAA,IAAW,IAAA;AACb,MAAA,OAAA,GAAU,EAAE,GAAG,OAAA,EAAS,SAAA,EAAW,OAAA,CAAQ,aAAa,SAAA,EAAU;AAEpE,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAG5B;AAAA,MACD,QAAQ,WAAA,CAAY,UAAA;AAAA,MACpB;AAAA,KACD,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,MACJ,OAAO,KAAA,EAAO,WAAA;AAAA,MACd,OAAO,IAAA,GACHD,EAAAA,CAAG,EAAE,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA,EAAW,MAAA,EAAQ,MAAA,CAAO,MAAM,MAAA,EAAQ,CAAA,GACrEC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,MACpB;AAAA,KACF;AAIA,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,MAAM,MAAA,GAAS,UAAA,CAAW,MAAA,CAAO,KAAK,CAAA;AACtC,MAAA,OAAO,qBAAA;AAAA,QACL,EAAE,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAU;AAAA,QAC/B,EAAE,GAAG,UAAA,EAAY,YAAA,EAAc,MAAA;AAAO,OACxC;AAAA,IACF;AAEA,IAAA,OAAO,qBAAA,CAAsB,MAAA,CAAO,KAAA,EAAO,UAAU,CAAA;AAAA,EACvD;AAMA,EAAA,eAAe,qBACb,KAAA,EACsC;AACtC,IAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,KAAA,CAAM,SAAS,CAAA;AAClD,IAAA,oBAAA,CAAqB,MAAM,MAAM,CAAA;AACjC,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,IAAA,EAAM,eAAe,CAAA;AACrD,IAAA,gBAAA,CAAiB,KAAA,CAAM,QAAA,CAAS,WAAA,EAAa,sBAAsB,CAAA;AACnE,IAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,KAAA,CAAM,QAAA,CAAS,WAAW,CAAA;AACjE,IAAA,gBAAA,CAAiB,KAAA,CAAM,aAAa,aAAa,CAAA;AACjD,IAAA,gBAAA;AAAA,MACE,MAAM,WAAA,CAAY,iBAAA;AAAA,MAClB;AAAA,KACF;AACA,IAAA,gBAAA;AAAA,MACE,MAAM,WAAA,CAAY,aAAA;AAAA,MAClB;AAAA,KACF;AAEA,IAAA,IAAI,OAAA,GAAU;AAAA,MACZ,GAAG,KAAA;AAAA,MACH,SAAA;AAAA,MACA,UAAU,EAAE,GAAG,KAAA,CAAM,QAAA,EAAU,aAAa,eAAA;AAAgB,KAC9D;AACA,IAAA,MAAM,UAAU,MAAM,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,cAAc,OAAO,CAAA;AACjE,IAAA,IAAI,OAAA,IAAW,IAAA;AACb,MAAA,OAAA,GAAU,EAAE,GAAG,OAAA,EAAS,SAAA,EAAW,OAAA,CAAQ,aAAa,SAAA,EAAU;AAEpE,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAAkB;AAAA,MAC/C,QAAQ,WAAA,CAAY,oBAAA;AAAA,MACpB;AAAA,KACD,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,MACJ,OAAO,KAAA,EAAO,WAAA;AAAA,MACd,OAAO,IAAA,GACHD,EAAAA,CAAG,EAAE,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA,EAAW,MAAA,EAAQ,MAAA,CAAO,MAAM,MAAA,EAAQ,CAAA,GACrEC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,MACpB;AAAA,KACF;AAEA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,OAAOD,EAAAA,CAAG,OAAO,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAOC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACzB;AAMA,EAAA,eAAe,UACb,KAAA,EACyC;AACzC,IAAA,gBAAA,CAAiB,KAAA,CAAM,WAAW,WAAW,CAAA;AAE7C,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAAqB;AAAA,MAClD,QAAQ,WAAA,CAAY,SAAA;AAAA,MACpB,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,OAAOD,EAAAA,CAAG,OAAO,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAOC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACzB;AAMA,EAAA,eAAe,eACb,KAAA,EACsC;AACtC,IAAA,IAAI,CAAC,KAAA,CAAM,EAAA,IAAM,CAAC,MAAM,SAAA,EAAW;AACjC,MAAA,eAAA,CAAgB,6BAA6B,CAAA;AAAA,IAC/C;AAEA,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAAkB;AAAA,MAC/C,QAAQ,WAAA,CAAY,cAAA;AAAA,MACpB,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,OAAOD,EAAAA,CAAG,OAAO,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAOC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACzB;AAMA,EAAA,eAAe,YACb,KAAA,EAC4C;AAC5C,IAAA,gBAAA,CAAiB,KAAA,CAAM,aAAa,aAAa,CAAA;AACjD,IAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,KAAA,CAAM,WAAW,CAAA;AAExD,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAAwB;AAAA,MACrD,QAAQ,WAAA,CAAY,WAAA;AAAA,MACpB,OAAA,EAAS,EAAE,GAAG,KAAA,EAAO,aAAa,eAAA;AAAgB,KACnD,CAAA;AAED,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,OAAOD,EAAAA,CAAG,OAAO,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAOC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACzB;AAMA,EAAA,eAAe,cACb,KAAA,EAC0C;AAC1C,IAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,KAAA,CAAM,SAAS,CAAA;AAClD,IAAA,wBAAA,CAAyB,MAAM,MAAM,CAAA;AACrC,IAAA,gBAAA,CAAiB,KAAA,CAAM,aAAa,aAAa,CAAA;AAEjD,IAAA,IAAI,MAAM,KAAA,EAAO;AACf,MAAA,IAAI,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,EAAA,EAAI;AAC3B,QAAA,eAAA,CAAgB,0BAA0B,CAAA;AAAA,MAC5C;AACA,MAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,QAAA,IAAI,CAAC,OAAO,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA,IAAK,IAAA,CAAK,YAAY,CAAA,EAAG;AAC1D,UAAA,eAAA,CAAgB,0CAA0C,CAAA;AAAA,QAC5D;AACA,QAAA,IAAI,CAAC,OAAO,SAAA,CAAU,IAAA,CAAK,SAAS,CAAA,IAAK,IAAA,CAAK,aAAa,CAAA,EAAG;AAC5D,UAAA,eAAA,CAAgB,2CAA2C,CAAA;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,EAAE,GAAG,KAAA,EAAO,SAAA,EAAU;AACtC,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,IAAA,CAAsB;AAAA,MACnD,QAAQ,WAAA,CAAY,aAAA;AAAA,MACpB;AAAA,KACD,CAAA;AAED,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,OAAOD,EAAAA,CAAG,OAAO,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAOC,GAAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EACzB;AAMA,EAAA,SAAS,cAAc,KAAA,EAAoC;AACzD,IAAA,OAAO,uBAAuB,KAAK,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO;AAAA,IACL,cAAA;AAAA,IACA,wBAAA;AAAA,IACA,UAAA;AAAA,IACA,oBAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA,sBAAA,EAAwB;AAAA,GAC1B;AACF;;;ACxdA,IAAM,SAAA,uBAAgB,GAAA,EAAyB;AAcxC,SAAS,eAAe,MAAA,EAAqC;AAClE,EAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,IAAA,MAAM,IAAI,MAAM,oBAAoB,CAAA;AAAA,EACtC;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,MAAA,CAAO,UAAA,CAAW,MAAM,CAAA,EAAG;AACrC,IAAA,MAAM,IAAI,MAAM,+BAA+B,CAAA;AAAA,EACjD;AACA,EAAA,IAAI,CAAC,OAAO,SAAA,EAAW;AACrB,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACzC;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,UAAA,CAAW,MAAM,CAAA,EAAG;AACxC,IAAA,MAAM,IAAI,MAAM,kCAAkC,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,OAAA,GAAU,OAAO,OAAA,IAAW,gBAAA;AAIlC,EAAA,MAAM,UAAA,GAAaC,UAAAA,CAAW,QAAQ,CAAA,CACnC,MAAA,CAAO,MAAA,CAAO,SAAS,CAAA,CACvB,MAAA,CAAO,KAAK,CAAA,CACZ,KAAA,CAAM,GAAG,EAAE,CAAA;AACd,EAAA,MAAM,cAAc,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA,CAAA,EAAI,OAAO,IAAI,UAAU,CAAA,CAAA;AAE7D,EAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AACjB,IAAA,MAAM,QAAA,GAAW,SAAA,CAAU,GAAA,CAAI,WAAW,CAAA;AAC1C,IAAA,IAAI,UAAU,OAAO,QAAA;AAAA,EACvB;AAEA,EAAA,MAAM,cAAA,GAAiB;AAAA,IACrB,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,OAAA;AAAA,IACA,SAAA,EAAW,OAAO,SAAA,IAAa,kBAAA;AAAA,IAC/B,UAAA,EAAY,OAAO,UAAA,IAAc,mBAAA;AAAA,IACjC,iBAAA,EAAmB,OAAO,iBAAA,IAAqB,4BAAA;AAAA,IAC/C,iBAAA,EAAmB,OAAO,iBAAA,IAAqB,4BAAA;AAAA,IAC/C,eAAA,EAAiB,OAAO,eAAA,IAAmB,yBAAA;AAAA,IAC3C,OAAO,MAAA,CAAO,KAAA,IAAS,UAAA,CAAW,KAAA,CAAM,KAAK,UAAU,CAAA;AAAA,IACvD,OAAO,MAAA,CAAO;AAAA,GAChB;AAEA,EAAA,MAAM,QAAA,GAAW,kBAAkB,cAAc,CAAA;AACjD,EAAA,SAAA,CAAU,GAAA,CAAI,aAAa,QAAQ,CAAA;AACnC,EAAA,OAAO,QAAA;AACT","file":"index.js","sourcesContent":["/**\n * Simple internal pubsub/event emitter for SDK payment lifecycle events.\n * Functional implementation without classes.\n *\n * @see Spec 2 section 2 - \"emits events such as nylonpay.on('success', (data) => {})\"\n *\n * @example\n * ```ts\n * const emitter = createEmitter<PaymentEvent>();\n * emitter.on(\"success\", (data) => console.log(data));\n * emitter.emit(\"success\", { event: \"success\", timestamp: \"...\" });\n * emitter.off(\"success\", handler);\n * ```\n */\n\n/**\n * Handler function type for event listeners.\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\n/**\n * Internal state for the emitter.\n * @internal\n */\ninterface EmitterState<T> {\n listeners: Map<T, Set<EventHandler<T>>>;\n}\n\n/**\n * Create a new event emitter instance.\n *\n * @returns Emitter with on/off/emit methods\n *\n * @example\n * ```ts\n * const emitter = createEmitter<string>();\n * const unsub = emitter.on(\"hello\", (msg) => console.log(msg));\n * emitter.emit(\"hello\", \"world\");\n * unsub(); // remove listener\n * ```\n */\nexport function createEmitter<T extends string>() {\n const state: EmitterState<T> = {\n listeners: new Map(),\n };\n\n /**\n * Subscribe to an event.\n * Returns an unsubscribe function for convenience.\n */\n function on(event: T, handler: EventHandler): () => void {\n if (!state.listeners.has(event)) {\n state.listeners.set(event, new Set());\n }\n state.listeners.get(event)?.add(handler as EventHandler<unknown>);\n return () => off(event, handler);\n }\n\n /**\n * Subscribe to an event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal payment events (e.g. \"successful\", \"failed\").\n * Returns the emitter for chaining.\n */\n function once(event: T, handler: EventHandler): typeof emitter {\n const wrapper: EventHandler = (data) => {\n off(event, wrapper);\n handler(data);\n };\n on(event, wrapper);\n return emitter;\n }\n\n /**\n * Unsubscribe from an event.\n */\n function off(event: T, handler: EventHandler): void {\n const handlers = state.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<unknown>);\n }\n }\n\n /**\n * Emit an event with data to all listeners.\n * Handlers are called synchronously in subscription order.\n */\n function emit(event: T, data: unknown): void {\n const handlers = state.listeners.get(event);\n if (!handlers || handlers.size === 0) return;\n for (const handler of handlers) {\n try {\n (handler as EventHandler<unknown>)(data);\n } catch {\n // Swallow handler errors to prevent one bad handler\n // from breaking the entire event chain\n }\n }\n }\n\n /**\n * Remove all listeners for a specific event, or all events if no event specified.\n */\n function clear(event?: T): void {\n if (event) {\n state.listeners.delete(event);\n } else {\n state.listeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event.\n */\n function listenerCount(event: T): number {\n return state.listeners.get(event)?.size ?? 0;\n }\n\n const emitter = { on, once, off, emit, clear, listenerCount };\n return emitter;\n}\n\n/**\n * Type for the emitter interface returned by createEmitter.\n */\nexport type Emitter<T extends string> = ReturnType<typeof createEmitter<T>>;\n","/** Default production backend URL */\nexport const DEFAULT_BASE_URL =\n \"https://api.nylonpay.nilesquad.com/api/services\";\n\n/** Default request timeout (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default max retry attempts for transport failures */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** Default polling interval between status checks (2 seconds) */\nexport const DEFAULT_MAX_POLL_INTERVAL_MS = 2_000;\n\n/** Default max total polling duration before timing out (5 minutes) */\nexport const DEFAULT_MAX_POLL_DURATION_MS = 300_000;\n\n/** Default max polling attempts before giving up */\nexport const DEFAULT_MAX_POLL_ATTEMPTS = 150;\n\n/**\n * Random jitter (ms) added to each poll interval so many concurrent payments\n * don't synchronise into a thundering herd on the status endpoint.\n */\nexport const POLL_JITTER_MS = 250;\n\n/** Nile.js service name for all SDK operations */\nexport const SDK_SERVICE = \"sdk\";\n\n/** Maps SDK operation names to backend action names */\nexport const SDK_ACTIONS = {\n collectPayment: \"sdk-collect-payment\",\n collectPaymentAndResolve: \"sdk-collect-payment-and-resolve\",\n makePayout: \"sdk-make-payout\",\n makePayoutAndResolve: \"sdk-make-payout-and-resolve\",\n getStatus: \"sdk-get-status\",\n getTransaction: \"sdk-get-transaction\",\n verifyPhone: \"sdk-verify-phone\",\n createInvoice: \"sdk-create-invoice\",\n} as const;\n\n/** HTTP status codes that trigger retries */\nexport const RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\n","/**\n * Server fingerprint generation for SDK requests.\n * Provides a stable identifier based on runtime environment.\n *\n * @see Spec 2 section 1 - \"a server fingerprint based on runtime, os, etc\"\n */\n\nimport { createHash } from \"node:crypto\";\nimport { arch, hostname, platform, release, type } from \"node:os\";\n\n/**\n * Generate a server fingerprint based on runtime environment.\n * This provides a stable identifier for the server making requests.\n * The fingerprint is a SHA-256 hash of system characteristics.\n *\n * @returns Hex-encoded SHA-256 hash of system info\n *\n * @example\n * ```ts\n * const fingerprint = generateFingerprint();\n * // => \"e3b0c44298fc1c149afbf4c8996fb924...\"\n * ```\n */\nexport function generateFingerprint(): string {\n const components = [\n `type:${type()}`,\n `platform:${platform()}`,\n `arch:${arch()}`,\n `release:${release()}`,\n `hostname:${hostname()}`,\n `node:${process.versions.node}`,\n `v8:${process.versions.v8}`,\n ].join(\"|\");\n\n return createHash(\"sha256\").update(components).digest(\"hex\");\n}\n","/**\n * Cryptographically secure nonce generation for SDK requests.\n *\n * @see Spec 2 section 1 - \"Internally the sdk generates a nounce\"\n */\n\nimport { randomBytes } from \"node:crypto\";\n\n/**\n * Generate a cryptographically secure random nonce.\n * Uses Node.js crypto.randomBytes for security.\n *\n * @param length - Byte length of the nonce (default: 16 = 32 hex chars)\n * @returns Hex-encoded random string\n *\n * @example\n * ```ts\n * const nonce = generateNonce();\n * // => \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"\n * ```\n */\nexport function generateNonce(length = 16): string {\n return randomBytes(length).toString(\"hex\");\n}\n","/**\n * HMAC-SHA256 signature creation for SDK requests.\n * Must match the backend's verification logic in verify-signature.ts.\n *\n * Signature payload format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * @see backend/src/services/sdk/verify-signature.ts\n * @see Spec 2 section 1 - \"creates a signature using these values and the api secret (HMAC 256)\"\n */\n\nimport { createHmac } from \"node:crypto\";\n\n/**\n * Recursively sort object keys by Unicode code point for deterministic JSON.\n *\n * The comparison MUST be by UTF-16 code unit (the JavaScript `<` operator), the\n * canonicalization rule from RFC 8785 (JSON Canonicalization Scheme). A\n * locale-sensitive comparison (e.g. `localeCompare`) is forbidden: its order\n * depends on the runtime's locale/ICU data, so two parties could canonicalize\n * the same payload to different bytes and fail signature verification on valid\n * traffic. Must match backend's createCanonicalPayload function byte-for-byte.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\n */\n/** Compare two keys by UTF-16 code unit (RFC 8785), never by locale. */\nfunction compareByCodePoint(first: string, second: string): number {\n if (first < second) {\n return -1;\n }\n if (first > second) {\n return 1;\n }\n return 0;\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => sortValue(entry));\n }\n\n if (value && typeof value === \"object\") {\n const sortedEntries = Object.entries(value as Record<string, unknown>).sort(\n ([firstKey], [secondKey]) => compareByCodePoint(firstKey, secondKey),\n );\n\n return Object.fromEntries(\n sortedEntries.map(([entryKey, entryValue]) => [\n entryKey,\n sortValue(entryValue),\n ]),\n );\n }\n\n return value;\n}\n\n/**\n * Create a canonical JSON string from a payload, per RFC 8785 (JCS): object keys\n * sorted by Unicode code point, no insignificant whitespace. Numbers and strings\n * serialize via `JSON.stringify`, whose V8 output already matches the JCS rules\n * (ECMAScript number-to-string and minimal JSON string escaping).\n */\nexport function createCanonicalPayload(payload: unknown): string {\n return JSON.stringify(sortValue(payload));\n}\n\n/**\n * Build the signature payload string.\n * Format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * The fingerprint is included in the signature to prevent tampering\n * with server identity information.\n *\n * @see backend/src/services/sdk/verify-signature.ts:createSignaturePayload\n */\nexport function createSignaturePayload(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n timestamp: string;\n}): string {\n return `${input.fingerprint}.${input.nonce}.${input.timestamp}.${createCanonicalPayload(input.payload)}`;\n}\n\n/**\n * Create an HMAC-SHA256 signature for SDK request authentication.\n *\n * The signature includes the server fingerprint to ensure the request\n * origin cannot be spoofed. The fingerprint contains runtime/OS info\n * that is bound to this specific server instance.\n *\n * @param input.fingerprint - Server fingerprint (included in signature)\n * @param input.nonce - Random nonce for replay protection\n * @param input.timestamp - Unix timestamp in milliseconds\n * @param input.payload - Request body (will be canonicalized)\n * @param input.secret - API secret for signing\n * @returns Hex-encoded HMAC-SHA256 signature\n */\nexport function createSignature(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n secret: string;\n timestamp: string;\n}): string {\n const payload = createSignaturePayload(input);\n\n return createHmac(\"sha256\", input.secret).update(payload).digest(\"hex\");\n}\n\n/**\n * Create a timestamp string in milliseconds.\n * Used as part of the signature payload.\n */\nexport function createTimestamp(): string {\n return Date.now().toString();\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { createCanonicalPayload } from \"./signature\";\n\n/**\n * Verify an authenticated backend response body before exposing it to SDK\n * consumers so tampered payloads are rejected consistently.\n *\n * @param data - Response payload without the `_responseSignature` field\n * @param signature - Hex-encoded HMAC-SHA256 signature from the backend\n * @param secret - API secret used for request authentication\n * @returns True when the signature matches the payload\n */\nexport function verifyResponseSignature(\n data: unknown,\n signature: string,\n secret: string,\n): boolean {\n const expectedSignature = createHmac(\"sha256\", secret)\n .update(createCanonicalPayload(data))\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(providedBuffer, expectedBuffer);\n}\n","/**\n * HTTP transport layer for SDK communication with the Nylon Pay backend.\n * Handles the Nile.js envelope format, HMAC request signing, response\n * signature verification, retries, and timeouts.\n *\n * @internal\n */\n\nimport { Err, Ok, type Result } from \"slang-ts\";\nimport { generateFingerprint } from \"./fingerprint\";\nimport { generateNonce } from \"./nonce\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n RETRYABLE_STATUS_CODES,\n SDK_SERVICE,\n} from \"./sdk.config\";\nimport { createSignature, createTimestamp } from \"./signature\";\nimport type { SdkError, SdkErrorCategory, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\n\n/** Known failure categories the server tags onto error messages. */\nconst KNOWN_CATEGORIES = new Set<SdkErrorCategory>([\n \"auth\",\n \"validation\",\n \"limit\",\n \"rate_limit\",\n \"account\",\n \"provider\",\n \"duplicate\",\n \"not_found\",\n \"internal\",\n \"network\",\n \"timeout\",\n]);\n\n/** HTTP status → category for errors that aren't server-tagged. */\nconst STATUS_CATEGORY: Record<number, SdkErrorCategory> = {\n 408: \"timeout\",\n 429: \"rate_limit\",\n};\n\n/** Matches the server's ` -- error-type: <category>` message suffix. */\nconst ERROR_TYPE_SUFFIX = /^(.*?)\\s*--\\s*error-type:\\s*([a-z_]+)\\s*$/is;\n\n/**\n * Split the server's tagged category off an error message. The backend appends\n * ` -- error-type: <category>` to every SDK error (the only channel available —\n * Nile returns 200/400 only and drops the response `data` on failures). The\n * leading `[logId]` and human text are preserved as the message.\n */\nfunction parseCategoryFromMessage(message: string): {\n category: SdkErrorCategory | null;\n message: string;\n} {\n const match = ERROR_TYPE_SUFFIX.exec(message);\n if (match?.[2] && KNOWN_CATEGORIES.has(match[2] as SdkErrorCategory)) {\n return {\n category: match[2] as SdkErrorCategory,\n message: match[1] ?? message,\n };\n }\n return { category: null, message };\n}\n\n/** Build a structured SdkError from an HTTP error body's message + status. */\nfunction buildHttpError(params: {\n message: string;\n statusCode: number;\n}): SdkError {\n const parsed = parseCategoryFromMessage(params.message);\n const category: SdkErrorCategory =\n parsed.category ??\n STATUS_CATEGORY[params.statusCode] ??\n (params.statusCode >= 500 ? \"internal\" : \"validation\");\n return {\n category,\n message: parsed.message,\n retryable: RETRYABLE_STATUS_CODES.has(params.statusCode),\n };\n}\n\n/**\n * Convert a structured SdkError into a throwable Error that still carries the\n * category and retryable flag. Used by async operations that throw on\n * initiation failure (invalid key, etc.) so merchants can `catch (e)` and read\n * `e.category`.\n */\nexport function createSdkError(error: SdkError): Error & SdkError {\n return Object.assign(new Error(error.message), {\n category: error.category,\n retryable: error.retryable,\n });\n}\n\n/** Calculate exponential backoff delay with jitter. */\nfunction calculateBackoff(attempt: number): number {\n const base = 2 ** attempt * 1000;\n const jitter = Math.random() * 500;\n return base + jitter;\n}\n\n/** Promise-based delay. */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Strip _responseSignature from a payload and return it separately. */\nfunction stripResponseSignature<T>(payload: T): {\n data: T;\n responseSignature: string | null;\n} {\n if (\n !payload ||\n typeof payload !== \"object\" ||\n !(\"_responseSignature\" in payload)\n ) {\n return { data: payload, responseSignature: null };\n }\n\n const { _responseSignature, ...rest } = payload as Record<string, unknown>;\n\n return {\n data: rest as T,\n responseSignature:\n typeof _responseSignature === \"string\" ? _responseSignature : null,\n };\n}\n\n/** Build the Nile.js request envelope. */\nfunction buildEnvelope({\n action,\n payload,\n}: TransportRequest): Record<string, unknown> {\n return {\n intent: \"execute\",\n service: SDK_SERVICE,\n action,\n payload: {\n ...(payload as Record<string, unknown>),\n _fingerprint: CACHED_FINGERPRINT,\n },\n };\n}\n\n/**\n * Build auth headers for a request.\n *\n * The signature is computed over the inner `payload` (the operation input plus\n * `_fingerprint`), NOT the full Nile envelope. This matches the server, which\n * verifies the signature against the raw request payload — see the Transport\n * Contract in the Nylon Pay SDK Spec (https://github.com/nile-squad/specs).\n */\nfunction buildAuthHeaders({\n apiKey,\n apiSecret,\n payload,\n}: {\n apiKey: string;\n apiSecret: string;\n payload: unknown;\n}): Record<string, string> {\n const nonce = generateNonce();\n const timestamp = createTimestamp();\n const signature = createSignature({\n fingerprint: CACHED_FINGERPRINT,\n nonce,\n timestamp,\n payload,\n secret: apiSecret,\n });\n\n return {\n \"content-type\": \"application/json\",\n \"x-nylon-key\": apiKey,\n \"x-nylon-nonce\": nonce,\n \"x-nylon-signature\": signature,\n \"x-nylon-timestamp\": timestamp,\n };\n}\n\n/** Create an AbortController with a timeout. Returns cleanup to clear the timer. */\nfunction withTimeout(timeoutMs: number): {\n controller: AbortController;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n return { controller, cleanup: () => clearTimeout(timeoutId) };\n}\n\n/**\n * Create the transport layer for SDK requests.\n *\n * @param config - Resolved SDK configuration\n * @returns Transport functions\n *\n * @internal\n */\nexport function createTransport({\n apiKey,\n apiSecret,\n baseUrl = DEFAULT_BASE_URL,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n maxRetries = DEFAULT_MAX_RETRIES,\n fetch: fetchImpl,\n}: {\n apiKey: string;\n apiSecret: string;\n baseUrl?: string;\n timeoutMs?: number;\n maxRetries?: number;\n fetch: typeof globalThis.fetch;\n}) {\n /**\n * Send a request to the backend.\n * Builds the envelope and headers once, then retries only the fetch call.\n */\n async function send<T>(\n request: TransportRequest,\n ): Promise<Result<T, string>> {\n const envelope = buildEnvelope(request);\n const signedPayload = (envelope as { payload: unknown }).payload;\n const headers = buildAuthHeaders({\n apiKey,\n apiSecret,\n payload: signedPayload,\n });\n const bodyString = JSON.stringify(envelope);\n\n async function attempt(currentAttempt: number): Promise<Result<T, string>> {\n const { controller, cleanup } = withTimeout(timeoutMs);\n\n try {\n const response = await fetchImpl(baseUrl, {\n method: \"POST\",\n headers,\n body: bodyString,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n const retryable = RETRYABLE_STATUS_CODES.has(statusCode);\n\n let errorMessage = `HTTP ${statusCode}`;\n try {\n const errorBody = await response.json();\n if (\n errorBody &&\n typeof errorBody === \"object\" &&\n \"message\" in errorBody\n ) {\n errorMessage = String(errorBody.message);\n }\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n\n if (retryable && currentAttempt < maxRetries) {\n cleanup();\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n cleanup();\n return Err(\n JSON.stringify(\n buildHttpError({ message: errorMessage, statusCode }),\n ),\n );\n }\n\n const responseBody = await response.json();\n\n if (\n !responseBody ||\n typeof responseBody !== \"object\" ||\n !(\"status\" in responseBody)\n ) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response missing status field\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const { status, message, data } = responseBody as {\n status: boolean;\n message: string;\n data: unknown;\n };\n\n if (status === true) {\n const { data: strippedData, responseSignature } =\n stripResponseSignature(data);\n\n // Fail closed. Every authenticated success response from the backend\n // is signed (see backend signSdkResponse). A missing signature means\n // the response was tampered with — e.g. a MITM stripped the field — or\n // did not originate from the backend. Reject rather than trust\n // unverified data; a prior version skipped verification when the field\n // was absent, which let a stripped-signature response through.\n if (!responseSignature) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature missing\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature verification failed\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n cleanup();\n return Ok(strippedData as T);\n }\n\n // status === false\n const parsedError = parseError(message);\n cleanup();\n return Err(JSON.stringify(parsedError));\n } catch (error) {\n cleanup();\n\n const isAbort =\n error instanceof DOMException && error.name === \"AbortError\";\n const sdkError: SdkError = {\n category: isAbort ? \"timeout\" : \"network\",\n message: isAbort\n ? `Request timed out after ${timeoutMs}ms`\n : String(error),\n retryable: true,\n };\n\n if (currentAttempt < maxRetries) {\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n return Err(JSON.stringify(sdkError));\n }\n }\n\n return attempt(0);\n }\n\n return { send, parseError };\n}\n\n/**\n * Parse an error string into a structured SdkError with a `category`.\n * Tries the JSON envelope first; otherwise pulls the server's\n * ` -- error-type: <category>` suffix off a raw message, falling back to\n * category `internal` when untagged.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-2026-001\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.category, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n // Sync helper: `safeTry` is async-only. The try/catch is the sync\n // boundary for JSON.parse and stays as-is (mirrors the pre-existing\n // contract that the SDK always exposes `parseError` synchronously).\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"category\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).category === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not our JSON envelope — fall through to suffix parsing.\n }\n\n // Raw server message: pull the ` -- error-type: <category>` suffix if present.\n const fromSuffix = parseCategoryFromMessage(error);\n return {\n category: fromSuffix.category ?? \"internal\",\n message: fromSuffix.message,\n };\n}\n","/**\n * Payment instance with event emission for transaction lifecycle.\n * Handles polling, event emission, and wait-for-completion.\n *\n * @see Spec 2 section 2 - \".collectPayment() returns a payment instance that they have to listen for events on\"\n * @see Spec 2 section 9 - \"sdk on merchant side internally calls another action to our backend to get transaction status updates by polling\"\n */\n\nimport type { Result } from \"slang-ts\";\nimport { createEmitter, type Emitter } from \"./pubsub\";\nimport { POLL_JITTER_MS } from \"./sdk.config\";\nimport { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\n SdkError,\n StatusResponse,\n Transaction,\n TransactionStatus,\n} from \"./types\";\n\n/**\n * Internal state for a payment instance.\n * @internal\n */\ntype PaymentState = {\n reference: string;\n status: TransactionStatus;\n transaction: Transaction | null;\n pollingTimer: ReturnType<typeof setTimeout> | null;\n resolved: boolean;\n pollAttempts: number;\n pollStartTime: number;\n emitter: Emitter<PaymentEvent>;\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs: number;\n maxPollDuration: number;\n maxPollAttempts: number;\n};\n\n/** Map transaction status to payment event. */\nconst STATUS_TO_EVENT: Partial<Record<TransactionStatus, PaymentEvent>> = {\n successful: \"success\",\n failed: \"failed\",\n processing: \"processing\",\n cancelled: \"cancelled\",\n};\n\nfunction statusToEvent(status: TransactionStatus): PaymentEvent | null {\n return STATUS_TO_EVENT[status] ?? null;\n}\n\n/** Terminal states that stop polling. */\nconst TERMINAL_STATES = new Set<TransactionStatus>([\n \"successful\",\n \"failed\",\n \"cancelled\",\n]);\n\n/**\n * Normalise raw backend status strings to TransactionStatus.\n * The backend may return \"completed\" for successful payments — map it to\n * \"successful\" so SDK events fire correctly.\n */\nfunction normalizeStatus(raw: string): TransactionStatus {\n if (raw === \"completed\") return \"successful\";\n return raw as TransactionStatus;\n}\n\n/**\n * Create a new payment instance.\n *\n * @param initialResponse - Response with reference and initial status\n * @param deps - Dependencies injected by the SDK\n * @returns Payment instance with event subscription\n *\n * @internal\n */\nexport function createPaymentInstance(\n initialResponse: { reference: string; status: TransactionStatus },\n deps: {\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs?: number;\n maxPollDuration?: number;\n maxPollAttempts?: number;\n /**\n * When set, the operation never started (the backend rejected initiation).\n * The instance emits this as an `\"error\"` event on the next tick instead of\n * polling — so a server-side rejection surfaces as an event, not a throw.\n */\n initialError?: SdkError;\n },\n): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: normalizeStatus(initialResponse.status),\n transaction: null,\n pollingTimer: null,\n resolved: false,\n pollAttempts: 0,\n pollStartTime: Date.now(),\n emitter: createEmitter<PaymentEvent>(),\n fetchStatus: deps.fetchStatus,\n fetchTransaction: deps.fetchTransaction,\n pollIntervalMs: deps.pollIntervalMs ?? 2000,\n maxPollDuration: deps.maxPollDuration ?? 300000,\n maxPollAttempts: deps.maxPollAttempts ?? 150,\n };\n\n function resolveWithError(error: string): void {\n state.resolved = true;\n stopUpdates();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(\n event: PaymentEvent,\n error?: string,\n category?: SdkError[\"category\"],\n retryable?: boolean,\n ): void {\n const data: EventData = {\n event,\n transaction: state.transaction ?? undefined,\n error,\n category,\n retryable,\n timestamp: new Date().toISOString(),\n };\n state.emitter.emit(event, data);\n }\n\n /**\n * Handle terminal state by fetching full transaction record.\n * @internal\n */\n async function handleTerminalState(status: TransactionStatus): Promise<void> {\n const txResult = await state.fetchTransaction({\n reference: state.reference,\n });\n if (txResult.isOk) {\n state.transaction = txResult.value;\n const event = statusToEvent(status);\n if (event) {\n const error =\n status === \"failed\"\n ? (state.transaction.failureReason ?? undefined)\n : undefined;\n emitEvent(event, error);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\n // Once the instance has resolved (terminal state, error, or timeout), no\n // further events may fire. A late status — e.g. an SSE chunk buffered before\n // the stream closed on fallback, or an in-flight poll — must be ignored so\n // it cannot emit a duplicate terminal event or a spurious out-of-order one.\n // The guard runs before any await, so the first caller to resolve wins.\n if (state.resolved) {\n return;\n }\n\n if (response.reference !== state.reference) {\n resolveWithError(\n `Reference mismatch: expected ${state.reference} but got ${response.reference}`,\n );\n return;\n }\n\n const newStatus = normalizeStatus(response.status);\n const oldStatus = state.status;\n\n state.status = newStatus;\n\n if (newStatus !== oldStatus) {\n const event = statusToEvent(newStatus);\n if (event) {\n if (TERMINAL_STATES.has(newStatus)) {\n await handleTerminalState(newStatus);\n return;\n }\n emitEvent(event);\n }\n }\n }\n\n /**\n * Handle polling error.\n * A `not_found` category during early polling is expected (the transaction\n * may not have propagated yet) — keep polling. Any other category is a real\n * failure that stops polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const parsed = parseError(error);\n if (parsed.category === \"not_found\") {\n return;\n }\n emitEvent(\"error\", parsed.message);\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one\n * finishes (no overlap). A random jitter is added to the interval so many\n * concurrent payments don't synchronise into a thundering herd on the status\n * endpoint.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n const delay = state.pollIntervalMs + Math.random() * POLL_JITTER_MS;\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, delay);\n }\n\n /**\n * Execute one polling cycle and queue the next one when appropriate.\n * @internal\n */\n async function pollStatus(): Promise<void> {\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n if (state.pollAttempts >= state.maxPollAttempts) {\n resolveWithError(\"Polling timeout: exceeded maximum attempts\");\n return;\n }\n\n if (Date.now() - state.pollStartTime >= state.maxPollDuration) {\n resolveWithError(\"Polling timeout: exceeded maximum duration\");\n return;\n }\n\n state.pollAttempts += 1;\n\n const result = await state.fetchStatus({ reference: state.reference });\n\n if (result.isOk) {\n await handleStatusUpdate(result.value);\n } else {\n handlePollError(result.error);\n }\n\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start status updates. If the initial status is already terminal (e.g. sandbox\n * resolves synchronously), emit the terminal event after a tick so handlers\n * registered after instance creation still fire. Otherwise begin polling.\n * @internal\n */\n function startUpdates(): void {\n if (TERMINAL_STATES.has(state.status)) {\n setTimeout(() => {\n void handleTerminalState(state.status);\n }, 0);\n return;\n }\n scheduleNextPoll();\n }\n\n /**\n * Stop all status updates (the poll timer).\n * @internal\n */\n function stopUpdates(): void {\n if (state.pollingTimer) {\n clearTimeout(state.pollingTimer);\n state.pollingTimer = null;\n }\n }\n\n /**\n * Subscribe to payment events.\n */\n function on(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.on(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Unsubscribe from payment events.\n */\n function off(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.off(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Subscribe to a payment event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal events like \"success\" or \"failed\".\n */\n function once(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.once(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Wait for payment to reach a terminal state.\n * Resolves with the full Transaction on success, null on failure/cancel/error.\n * Never rejects — check the return value to determine outcome.\n */\n function wait(): Promise<Transaction | null> {\n return new Promise((resolve) => {\n if (state.resolved) {\n resolve(\n state.status === \"successful\" && state.transaction\n ? state.transaction\n : null,\n );\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n resolve(state.transaction ?? null);\n }\n\n function onFailed(): void {\n cleanup();\n resolve(null);\n }\n\n function onCancelled(): void {\n cleanup();\n resolve(null);\n }\n\n function onError(): void {\n cleanup();\n resolve(null);\n }\n\n function cleanup(): void {\n state.emitter.off(\"success\", onSuccess);\n state.emitter.off(\"failed\", onFailed);\n state.emitter.off(\"cancelled\", onCancelled);\n state.emitter.off(\"error\", onError);\n }\n\n state.emitter.on(\"success\", onSuccess);\n state.emitter.on(\"failed\", onFailed);\n state.emitter.on(\"cancelled\", onCancelled);\n state.emitter.on(\"error\", onError);\n });\n }\n\n const paymentInstance: PaymentInstance = {\n get reference() {\n return state.reference;\n },\n get status() {\n return state.status;\n },\n on,\n once,\n off,\n wait,\n };\n\n // When the backend rejected initiation, there is nothing to poll.\n // Emit an \"error\" event on the next tick so handlers registered after\n // creation still fire, and mark resolved so wait() returns null.\n if (deps.initialError) {\n state.resolved = true;\n const err = deps.initialError;\n setTimeout(() => {\n emitEvent(\"error\", err.message, err.category, err.retryable);\n }, 0);\n } else {\n startUpdates();\n }\n\n return paymentInstance;\n}\n","/**\n * Normalize a phone number to international format without leading +.\n *\n * - Strips all whitespace\n * - Strips leading +\n * - If starts with \"0\" and length is 10 → prepend \"256\"\n *\n * WHY: Phone numbers like \"0768499027\" reach the backend unnormalized.\n * SDK normalizing first means the wire payload is already correct,\n * providing defense-in-depth even though the backend also normalizes.\n */\nexport function normalizePhone(phone: string): string {\n let normalized = phone.replace(/\\s+/g, \"\").replace(/^\\+/, \"\");\n\n if (normalized.startsWith(\"0\") && normalized.length === 10) {\n normalized = `256${normalized.slice(1)}`;\n }\n\n return normalized;\n}\n","/**\n * Standalone webhook signature verification utility.\n * Merchants use this to confirm that incoming webhook payloads\n * were genuinely sent by Nylon Pay before acting on them.\n */\n\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { VerifyWebhookInput } from \"./types\";\n\n/** Default replay-protection window: the signed timestamp must be this fresh. */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/** Decode the (already signature-verified) payload to a UTF-8 string. */\nfunction decodePayload(payload: string | Uint8Array): string {\n return typeof payload === \"string\"\n ? payload\n : Buffer.from(payload).toString(\"utf8\");\n}\n\n/**\n * Pull the signed `timestamp` out of a verified webhook body and return it as\n * epoch milliseconds. The timestamp lives inside the HMAC-signed body (the\n * backend stamps every delivery and every retry fresh), so it cannot be forged\n * or refreshed by a replay attacker without the secret. Returns `null` when the\n * body is not JSON or carries no parseable timestamp.\n */\nfunction extractSignedTimestampMs(payloadString: string): number | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(payloadString);\n } catch {\n return null;\n }\n\n if (!parsed || typeof parsed !== \"object\") {\n return null;\n }\n\n const raw = (parsed as Record<string, unknown>).timestamp;\n\n if (typeof raw === \"number\" && Number.isFinite(raw)) {\n // Accept epoch seconds or milliseconds — values below ~1e12 are seconds.\n return raw < 1e12 ? raw * 1000 : raw;\n }\n\n if (typeof raw === \"string\") {\n const ms = Date.parse(raw);\n return Number.isNaN(ms) ? null : ms;\n }\n\n return null;\n}\n\n/**\n * Verify that a webhook payload was genuinely sent by Nylon Pay.\n *\n * Two checks, both must pass:\n * 1. **Authenticity** — HMAC-SHA256 over the raw payload bytes (NOT parsed\n * JSON, spec invariant #8) matches the provided signature.\n * 2. **Freshness** — the `timestamp` carried inside the signed body is within\n * `toleranceSeconds` of now (default 300s). This is what stops a replay: a\n * captured `(body, signature)` pair stays cryptographically valid forever,\n * but its embedded timestamp goes stale. Every genuine delivery, including\n * retries hours later, is re-stamped and re-signed, so this never rejects\n * legitimate traffic. Pass `toleranceSeconds: 0` to skip this check.\n *\n * @returns True when the signature is valid and (when enforced) the webhook is fresh\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadString = decodePayload(input.payload);\n const payloadBytes = Buffer.from(payloadString, \"utf8\");\n\n const expectedSignature = createHmac(\"sha256\", input.secret)\n .update(payloadBytes)\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(input.signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n if (!timingSafeEqual(providedBuffer, expectedBuffer)) {\n return false;\n }\n\n // Signature is authentic — now enforce freshness using the signed timestamp.\n const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (toleranceSeconds <= 0) {\n return true;\n }\n\n const timestampMs = extractSignedTimestampMs(payloadString);\n if (timestampMs === null) {\n // Fail closed: a valid signature with no verifiable timestamp cannot be\n // proven fresh, so it cannot be distinguished from a replay.\n return false;\n }\n\n const ageMs = Math.abs(Date.now() - timestampMs);\n return ageMs <= toleranceSeconds * 1000;\n}\n","/**\n * SDK instance providing all merchant-facing payment operations.\n * Created via createNylonPay factory and returned as NylonPaySdk.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { Err, Ok, type Result, safeTry } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { normalizePhone } from \"./phone\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createSdkError, createTransport, parseError } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\n SdkHook,\n SdkHooks,\n StatusResponse,\n Transaction,\n TransactionStatus,\n VerifyPhoneInput,\n VerifyWebhookInput,\n} from \"./types\";\nimport { verifyWebhookSignature } from \"./verify-webhook\";\n\nexport type { NylonPaySdk } from \"./types\";\n\ntype ResolvedConfig = {\n apiKey: string;\n apiSecret: string;\n baseUrl: string;\n timeoutMs: number;\n maxRetries: number;\n maxPollIntervalMs: number;\n maxPollDurationMs: number;\n maxPollAttempts: number;\n fetch: typeof globalThis.fetch;\n hooks?: SdkHooks;\n};\n\n/** Generate a random 15-character hex reference for idempotency. */\nfunction generateReference(): string {\n return randomBytes(16).toString(\"hex\").slice(0, 15);\n}\n\n/**\n * PivotPay caps the `merchantTransactionId` (our reference) at 13–15 characters.\n * The backend echoes the reference verbatim as that id, so an out-of-range\n * reference is rejected server-side (and historically surfaced as an opaque\n * provider error). Auto-generated references are always 15 chars; this only\n * bites when a merchant supplies their own (e.g. a 36-char UUID order id).\n */\nconst REFERENCE_MIN_LENGTH = 13;\nconst REFERENCE_MAX_LENGTH = 15;\n\n/**\n * Resolve the idempotency reference for a create call: auto-generate when the\n * merchant omits it, otherwise validate their value against the 13–15 char\n * limit *synchronously* (like validateAmount) so a bad reference throws locally\n * instead of costing a backend round-trip.\n */\nfunction resolveReference(reference?: string): string {\n if (reference === undefined) {\n return generateReference();\n }\n if (\n reference.length < REFERENCE_MIN_LENGTH ||\n reference.length > REFERENCE_MAX_LENGTH\n ) {\n throwValidation(\n `reference must be ${REFERENCE_MIN_LENGTH}–${REFERENCE_MAX_LENGTH} characters`,\n );\n }\n return reference;\n}\n\n/**\n * Run a lifecycle hook safely. A disabled or unset hook is a no-op. The hook's\n * `fn` runs inside `safeTry` so a throw/rejection in merchant code never bubbles\n * into the payment flow — it is routed to the hook's `onError` (which is itself\n * wrapped, so a faulty handler can't crash us either).\n *\n * Returns the hook's resolved value on success, or `undefined` when the hook was\n * skipped or failed. Callers treat `undefined` as \"no override\" — for before\n * hooks that means the original payload is used unchanged.\n */\nasync function runHook<TFn extends (...args: never[]) => unknown>(\n hook: SdkHook<TFn> | undefined,\n ...args: Parameters<TFn>\n): Promise<Awaited<ReturnType<TFn>> | undefined> {\n if (!hook || hook.enabled === false) return undefined;\n\n const result = await safeTry(async () => hook.fn(...args));\n // safeTry widens the success value to `unknown` through the generic bound;\n // by construction it is the hook's resolved return type.\n if (result.isOk) return result.value as Awaited<ReturnType<TFn>>;\n\n await safeTry(async () => hook.onError(result.error));\n return undefined;\n}\n\n/**\n * Throw a categorized input-validation error. Keeps thrown errors consistent\n * with transport-init failures so a merchant's `catch (e)` can always read\n * `e.category` (here always `\"validation\"`).\n */\nfunction throwValidation(message: string): never {\n throw createSdkError({ category: \"validation\", message });\n}\n\n/** Validate collection amount is a positive integer >= 500. */\nfunction validateCollectionAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 500) {\n throwValidation(\"Collection amount must be at least 500 UGX\");\n }\n}\n\n/** Validate payout amount is a positive integer >= 5000. */\nfunction validatePayoutAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 5000) {\n throwValidation(\"Payout amount must be at least 5000 UGX\");\n }\n}\n\n/** Validate that a string value is non-empty. */\nfunction validateNonEmpty(value: string, fieldName: string): void {\n if (!value || value.trim() === \"\") {\n throwValidation(`${fieldName} is required`);\n }\n}\n\n/**\n * Create an SDK instance with resolved configuration.\n * Returns an object implementing the NylonPaySdk interface.\n */\nexport function createSdkInstance(config: ResolvedConfig): NylonPaySdk {\n const transport = createTransport({\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl: config.baseUrl,\n timeoutMs: config.timeoutMs,\n maxRetries: config.maxRetries,\n fetch: config.fetch,\n });\n\n const commonDeps = {\n fetchStatus: (input: GetStatusInput) =>\n transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n }),\n fetchTransaction: (input: GetTransactionInput) =>\n transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n }),\n pollIntervalMs: config.maxPollIntervalMs,\n maxPollDuration: config.maxPollDurationMs,\n maxPollAttempts: config.maxPollAttempts,\n };\n\n /**\n * Initiate a collection payment.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function collectPayment(\n input: CollectPaymentInput,\n ): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed (invalid key, signature, limit, provider reject). The\n // transaction never started — return a PaymentInstance that emits an\n // \"error\" event instead of throwing, so merchants handle it via events.\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a collection and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function collectPaymentAndResolve(\n input: CollectPaymentInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Initiate a payout.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function makePayout(input: MakePayoutInput): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed — return a PaymentInstance that emits an \"error\"\n // event instead of throwing (see collectPayment for rationale).\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a payout and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function makePayoutAndResolve(\n input: MakePayoutInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the current status of a transaction.\n * Lightweight check that returns only status fields.\n */\n async function getStatus(\n input: GetStatusInput,\n ): Promise<Result<StatusResponse, string>> {\n validateNonEmpty(input.reference, \"reference\");\n\n const result = await transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the full transaction record.\n * Requires at least one of id or reference.\n */\n async function getTransaction(\n input: GetTransactionInput,\n ): Promise<Result<Transaction, string>> {\n if (!input.id && !input.reference) {\n throwValidation(\"id or reference is required\");\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a phone number with the provider.\n * Returns the registered name for identity confirmation.\n */\n async function verifyPhone(\n input: VerifyPhoneInput,\n ): Promise<Result<PhoneVerification, string>> {\n validateNonEmpty(input.phoneNumber, \"phoneNumber\");\n const normalizedPhone = normalizePhone(input.phoneNumber);\n\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: { ...input, phoneNumber: normalizedPhone },\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Create a hosted invoice.\n * Auto-generates reference if omitted. Returns payment link and token.\n */\n async function createInvoice(\n input: CreateInvoiceInput,\n ): Promise<Result<InvoiceResponse, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throwValidation(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throwValidation(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throwValidation(\"item unitPrice must be a positive integer\");\n }\n }\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<InvoiceResponse>({\n action: SDK_ACTIONS.createInvoice,\n payload,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a webhook payload signature.\n * Delegates to the standalone verifyWebhookSignature utility.\n */\n function verifyWebhook(input: VerifyWebhookInput): boolean {\n return verifyWebhookSignature(input);\n }\n\n return {\n collectPayment,\n collectPaymentAndResolve,\n makePayout,\n makePayoutAndResolve,\n getStatus,\n getTransaction,\n verifyPhone,\n createInvoice,\n verifyWebhookSignature: verifyWebhook,\n };\n}\n","/**\n * Factory function to create a Nylon Pay SDK instance.\n * This is the main entry point for merchants.\n *\n * Calling createNylonPay with the same apiKey, apiSecret and baseUrl returns the\n * same instance (singleton per key+secret+url). Rotating the secret yields a\n * fresh instance. Pass { force: true } to force a new instance regardless.\n *\n * @example\n * ```ts\n * import { createNylonPay } from \"@nile-squad/nylonpay-ts\";\n *\n * export const nylonpay = createNylonPay({\n * apiKey: \"npk_...\",\n * apiSecret: \"nps_...\",\n * });\n * ```\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createSdkInstance, type NylonPaySdk } from \"./sdk\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_POLL_ATTEMPTS,\n DEFAULT_MAX_POLL_DURATION_MS,\n DEFAULT_MAX_POLL_INTERVAL_MS,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n} from \"./sdk.config\";\nimport type { NylonPayConfig } from \"./types\";\n\nconst instances = new Map<string, NylonPaySdk>();\n\n/**\n * Create a Nylon Pay SDK instance.\n *\n * Returns the same instance for the same apiKey + apiSecret + baseUrl\n * combination unless { force: true } is passed. Use your test keys for sandbox,\n * production keys for live.\n *\n * @param config - SDK configuration with apiKey and apiSecret\n * @returns SDK instance with all payment operations\n *\n * @throws Error if required config is missing or invalid\n */\nexport function createNylonPay(config: NylonPayConfig): NylonPaySdk {\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n if (!config.apiKey.startsWith(\"npk_\")) {\n throw new Error('apiKey must start with \"npk_\"');\n }\n if (!config.apiSecret) {\n throw new Error(\"apiSecret is required\");\n }\n if (!config.apiSecret.startsWith(\"nps_\")) {\n throw new Error('apiSecret must start with \"nps_\"');\n }\n\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n // Include a hash of the secret in the cache key so rotating apiSecret in a\n // long-running process returns a fresh instance instead of a stale one signing\n // with the old secret. Hashed (not raw) so the secret never sits in a Map key.\n const secretHash = createHash(\"sha256\")\n .update(config.apiSecret)\n .digest(\"hex\")\n .slice(0, 16);\n const instanceKey = `${config.apiKey}:${baseUrl}:${secretHash}`;\n\n if (!config.force) {\n const existing = instances.get(instanceKey);\n if (existing) return existing;\n }\n\n const resolvedConfig = {\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,\n maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,\n maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n hooks: config.hooks,\n };\n\n const instance = createSdkInstance(resolvedConfig);\n instances.set(instanceKey, instance);\n return instance;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/pubsub.ts","../src/sdk.config.ts","../src/fingerprint.ts","../src/nonce.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.ts","../src/phone.ts","../src/verify-webhook.ts","../src/sdk.ts","../src/create-nylon-pay.ts"],"names":["createHmac","delay","timingSafeEqual","randomBytes","Ok","Err","createHash"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Simple internal pubsub/event emitter for SDK payment lifecycle events.\n * Functional implementation without classes.\n *\n * @see Spec 2 section 2 - \"emits events such as nylonpay.on('success', (data) => {})\"\n *\n * @example\n * ```ts\n * const emitter = createEmitter<PaymentEvent>();\n * emitter.on(\"success\", (data) => console.log(data));\n * emitter.emit(\"success\", { event: \"success\", timestamp: \"...\" });\n * emitter.off(\"success\", handler);\n * ```\n */\n\n/**\n * Handler function type for event listeners.\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\n/**\n * Internal state for the emitter.\n * @internal\n */\ninterface EmitterState<T> {\n listeners: Map<T, Set<EventHandler<T>>>;\n}\n\n/**\n * Create a new event emitter instance.\n *\n * @returns Emitter with on/off/emit methods\n *\n * @example\n * ```ts\n * const emitter = createEmitter<string>();\n * const unsub = emitter.on(\"hello\", (msg) => console.log(msg));\n * emitter.emit(\"hello\", \"world\");\n * unsub(); // remove listener\n * ```\n */\nexport function createEmitter<T extends string>() {\n const state: EmitterState<T> = {\n listeners: new Map(),\n };\n\n /**\n * Subscribe to an event.\n * Returns an unsubscribe function for convenience.\n */\n function on(event: T, handler: EventHandler): () => void {\n if (!state.listeners.has(event)) {\n state.listeners.set(event, new Set());\n }\n state.listeners.get(event)?.add(handler as EventHandler<unknown>);\n return () => off(event, handler);\n }\n\n /**\n * Subscribe to an event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal payment events (e.g. \"successful\", \"failed\").\n * Returns the emitter for chaining.\n */\n function once(event: T, handler: EventHandler): typeof emitter {\n const wrapper: EventHandler = (data) => {\n off(event, wrapper);\n handler(data);\n };\n on(event, wrapper);\n return emitter;\n }\n\n /**\n * Unsubscribe from an event.\n */\n function off(event: T, handler: EventHandler): void {\n const handlers = state.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<unknown>);\n }\n }\n\n /**\n * Emit an event with data to all listeners.\n * Handlers are called synchronously in subscription order.\n */\n function emit(event: T, data: unknown): void {\n const handlers = state.listeners.get(event);\n if (!handlers || handlers.size === 0) return;\n for (const handler of handlers) {\n try {\n (handler as EventHandler<unknown>)(data);\n } catch {\n // Swallow handler errors to prevent one bad handler\n // from breaking the entire event chain\n }\n }\n }\n\n /**\n * Remove all listeners for a specific event, or all events if no event specified.\n */\n function clear(event?: T): void {\n if (event) {\n state.listeners.delete(event);\n } else {\n state.listeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event.\n */\n function listenerCount(event: T): number {\n return state.listeners.get(event)?.size ?? 0;\n }\n\n const emitter = { on, once, off, emit, clear, listenerCount };\n return emitter;\n}\n\n/**\n * Type for the emitter interface returned by createEmitter.\n */\nexport type Emitter<T extends string> = ReturnType<typeof createEmitter<T>>;\n","/** Default production backend URL */\nexport const DEFAULT_BASE_URL =\n \"https://api.nylonpay.nilesquad.com/api/services\";\n\n/** Default request timeout (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default max retry attempts for transport failures */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** Default polling interval between status checks (2 seconds) */\nexport const DEFAULT_MAX_POLL_INTERVAL_MS = 2_000;\n\n/** Default max total polling duration before timing out (5 minutes) */\nexport const DEFAULT_MAX_POLL_DURATION_MS = 300_000;\n\n/** Default max polling attempts before giving up */\nexport const DEFAULT_MAX_POLL_ATTEMPTS = 150;\n\n/**\n * Random jitter (ms) added to each poll interval so many concurrent payments\n * don't synchronise into a thundering herd on the status endpoint.\n */\nexport const POLL_JITTER_MS = 250;\n\n/** Nile.js service name for all SDK operations */\nexport const SDK_SERVICE = \"sdk\";\n\n/** Maps SDK operation names to backend action names */\nexport const SDK_ACTIONS = {\n collectPayment: \"sdk-collect-payment\",\n collectPaymentAndResolve: \"sdk-collect-payment-and-resolve\",\n makePayout: \"sdk-make-payout\",\n makePayoutAndResolve: \"sdk-make-payout-and-resolve\",\n getStatus: \"sdk-get-status\",\n getTransaction: \"sdk-get-transaction\",\n verifyPhone: \"sdk-verify-phone\",\n createInvoice: \"sdk-create-invoice\",\n} as const;\n\n/** HTTP status codes that trigger retries */\nexport const RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\n","/**\n * Server fingerprint generation for SDK requests.\n * Provides a stable identifier based on runtime environment.\n *\n * @see Spec 2 section 1 - \"a server fingerprint based on runtime, os, etc\"\n */\n\nimport { createHash } from \"node:crypto\";\nimport { arch, hostname, platform, release, type } from \"node:os\";\n\n/**\n * Generate a server fingerprint based on runtime environment.\n * This provides a stable identifier for the server making requests.\n * The fingerprint is a SHA-256 hash of system characteristics.\n *\n * @returns Hex-encoded SHA-256 hash of system info\n *\n * @example\n * ```ts\n * const fingerprint = generateFingerprint();\n * // => \"e3b0c44298fc1c149afbf4c8996fb924...\"\n * ```\n */\nexport function generateFingerprint(): string {\n const components = [\n `type:${type()}`,\n `platform:${platform()}`,\n `arch:${arch()}`,\n `release:${release()}`,\n `hostname:${hostname()}`,\n `node:${process.versions.node}`,\n `v8:${process.versions.v8}`,\n ].join(\"|\");\n\n return createHash(\"sha256\").update(components).digest(\"hex\");\n}\n","/**\n * Cryptographically secure nonce generation for SDK requests.\n *\n * @see Spec 2 section 1 - \"Internally the sdk generates a nounce\"\n */\n\nimport { randomBytes } from \"node:crypto\";\n\n/**\n * Generate a cryptographically secure random nonce.\n * Uses Node.js crypto.randomBytes for security.\n *\n * @param length - Byte length of the nonce (default: 16 = 32 hex chars)\n * @returns Hex-encoded random string\n *\n * @example\n * ```ts\n * const nonce = generateNonce();\n * // => \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"\n * ```\n */\nexport function generateNonce(length = 16): string {\n return randomBytes(length).toString(\"hex\");\n}\n","/**\n * HMAC-SHA256 signature creation for SDK requests.\n * Must match the backend's verification logic in verify-signature.ts.\n *\n * Signature payload format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * @see backend/src/services/sdk/verify-signature.ts\n * @see Spec 2 section 1 - \"creates a signature using these values and the api secret (HMAC 256)\"\n */\n\nimport { createHmac } from \"node:crypto\";\n\n/**\n * Recursively sort object keys by Unicode code point for deterministic JSON.\n *\n * The comparison MUST be by UTF-16 code unit (the JavaScript `<` operator), the\n * canonicalization rule from RFC 8785 (JSON Canonicalization Scheme). A\n * locale-sensitive comparison (e.g. `localeCompare`) is forbidden: its order\n * depends on the runtime's locale/ICU data, so two parties could canonicalize\n * the same payload to different bytes and fail signature verification on valid\n * traffic. Must match backend's createCanonicalPayload function byte-for-byte.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\n */\n/** Compare two keys by UTF-16 code unit (RFC 8785), never by locale. */\nfunction compareByCodePoint(first: string, second: string): number {\n if (first < second) {\n return -1;\n }\n if (first > second) {\n return 1;\n }\n return 0;\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => sortValue(entry));\n }\n\n if (value && typeof value === \"object\") {\n const sortedEntries = Object.entries(value as Record<string, unknown>).sort(\n ([firstKey], [secondKey]) => compareByCodePoint(firstKey, secondKey),\n );\n\n return Object.fromEntries(\n sortedEntries.map(([entryKey, entryValue]) => [\n entryKey,\n sortValue(entryValue),\n ]),\n );\n }\n\n return value;\n}\n\n/**\n * Create a canonical JSON string from a payload, per RFC 8785 (JCS): object keys\n * sorted by Unicode code point, no insignificant whitespace. Numbers and strings\n * serialize via `JSON.stringify`, whose V8 output already matches the JCS rules\n * (ECMAScript number-to-string and minimal JSON string escaping).\n */\nexport function createCanonicalPayload(payload: unknown): string {\n return JSON.stringify(sortValue(payload));\n}\n\n/**\n * Build the signature payload string.\n * Format: fingerprint.nonce.timestamp.canonicalPayload\n *\n * The fingerprint is included in the signature to prevent tampering\n * with server identity information.\n *\n * @see backend/src/services/sdk/verify-signature.ts:createSignaturePayload\n */\nexport function createSignaturePayload(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n timestamp: string;\n}): string {\n return `${input.fingerprint}.${input.nonce}.${input.timestamp}.${createCanonicalPayload(input.payload)}`;\n}\n\n/**\n * Create an HMAC-SHA256 signature for SDK request authentication.\n *\n * The signature includes the server fingerprint to ensure the request\n * origin cannot be spoofed. The fingerprint contains runtime/OS info\n * that is bound to this specific server instance.\n *\n * @param input.fingerprint - Server fingerprint (included in signature)\n * @param input.nonce - Random nonce for replay protection\n * @param input.timestamp - Unix timestamp in milliseconds\n * @param input.payload - Request body (will be canonicalized)\n * @param input.secret - API secret for signing\n * @returns Hex-encoded HMAC-SHA256 signature\n */\nexport function createSignature(input: {\n fingerprint: string;\n nonce: string;\n payload: unknown;\n secret: string;\n timestamp: string;\n}): string {\n const payload = createSignaturePayload(input);\n\n return createHmac(\"sha256\", input.secret).update(payload).digest(\"hex\");\n}\n\n/**\n * Create a timestamp string in milliseconds.\n * Used as part of the signature payload.\n */\nexport function createTimestamp(): string {\n return Date.now().toString();\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { createCanonicalPayload } from \"./signature\";\n\n/**\n * Verify an authenticated backend response body before exposing it to SDK\n * consumers so tampered payloads are rejected consistently.\n *\n * @param data - Response payload without the `_responseSignature` field\n * @param signature - Hex-encoded HMAC-SHA256 signature from the backend\n * @param secret - API secret used for request authentication\n * @returns True when the signature matches the payload\n */\nexport function verifyResponseSignature(\n data: unknown,\n signature: string,\n secret: string,\n): boolean {\n const expectedSignature = createHmac(\"sha256\", secret)\n .update(createCanonicalPayload(data))\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(providedBuffer, expectedBuffer);\n}\n","/**\n * HTTP transport layer for SDK communication with the Nylon Pay backend.\n * Handles the Nile.js envelope format, HMAC request signing, response\n * signature verification, retries, and timeouts.\n *\n * @internal\n */\n\nimport { Err, Ok, type Result } from \"slang-ts\";\nimport { generateFingerprint } from \"./fingerprint\";\nimport { generateNonce } from \"./nonce\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n RETRYABLE_STATUS_CODES,\n SDK_SERVICE,\n} from \"./sdk.config\";\nimport { createSignature, createTimestamp } from \"./signature\";\nimport type { SdkError, SdkErrorCategory, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\n\n/** Known failure categories the server tags onto error messages. */\nconst KNOWN_CATEGORIES = new Set<SdkErrorCategory>([\n \"auth\",\n \"validation\",\n \"limit\",\n \"rate_limit\",\n \"account\",\n \"provider\",\n \"duplicate\",\n \"not_found\",\n \"internal\",\n \"network\",\n \"timeout\",\n]);\n\n/** HTTP status → category for errors that aren't server-tagged. */\nconst STATUS_CATEGORY: Record<number, SdkErrorCategory> = {\n 408: \"timeout\",\n 429: \"rate_limit\",\n};\n\n/** Matches the server's ` -- error-type: <category>` message suffix. */\nconst ERROR_TYPE_SUFFIX = /^(.*?)\\s*--\\s*error-type:\\s*([a-z_]+)\\s*$/is;\n\n/**\n * Split the server's tagged category off an error message. The backend appends\n * ` -- error-type: <category>` to every SDK error (the only channel available —\n * Nile returns 200/400 only and drops the response `data` on failures). The\n * leading `[logId]` and human text are preserved as the message.\n */\nfunction parseCategoryFromMessage(message: string): {\n category: SdkErrorCategory | null;\n message: string;\n} {\n const match = ERROR_TYPE_SUFFIX.exec(message);\n if (match?.[2] && KNOWN_CATEGORIES.has(match[2] as SdkErrorCategory)) {\n return {\n category: match[2] as SdkErrorCategory,\n message: match[1] ?? message,\n };\n }\n return { category: null, message };\n}\n\n/** Build a structured SdkError from an HTTP error body's message + status. */\nfunction buildHttpError(params: {\n message: string;\n statusCode: number;\n}): SdkError {\n const parsed = parseCategoryFromMessage(params.message);\n const category: SdkErrorCategory =\n parsed.category ??\n STATUS_CATEGORY[params.statusCode] ??\n (params.statusCode >= 500 ? \"internal\" : \"validation\");\n return {\n category,\n message: parsed.message,\n retryable: RETRYABLE_STATUS_CODES.has(params.statusCode),\n };\n}\n\n/**\n * Convert a structured SdkError into a throwable Error that still carries the\n * category and retryable flag. Used by async operations that throw on\n * initiation failure (invalid key, etc.) so merchants can `catch (e)` and read\n * `e.category`.\n */\nexport function createSdkError(error: SdkError): Error & SdkError {\n return Object.assign(new Error(error.message), {\n category: error.category,\n retryable: error.retryable,\n });\n}\n\n/** Calculate exponential backoff delay with jitter. */\nfunction calculateBackoff(attempt: number): number {\n const base = 2 ** attempt * 1000;\n const jitter = Math.random() * 500;\n return base + jitter;\n}\n\n/** Promise-based delay. */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Strip _responseSignature from a payload and return it separately. */\nfunction stripResponseSignature<T>(payload: T): {\n data: T;\n responseSignature: string | null;\n} {\n if (\n !payload ||\n typeof payload !== \"object\" ||\n !(\"_responseSignature\" in payload)\n ) {\n return { data: payload, responseSignature: null };\n }\n\n const { _responseSignature, ...rest } = payload as Record<string, unknown>;\n\n return {\n data: rest as T,\n responseSignature:\n typeof _responseSignature === \"string\" ? _responseSignature : null,\n };\n}\n\n/** Build the Nile.js request envelope. */\nfunction buildEnvelope({\n action,\n payload,\n}: TransportRequest): Record<string, unknown> {\n return {\n intent: \"execute\",\n service: SDK_SERVICE,\n action,\n payload: {\n ...(payload as Record<string, unknown>),\n _fingerprint: CACHED_FINGERPRINT,\n },\n };\n}\n\n/**\n * Build auth headers for a request.\n *\n * The signature is computed over the inner `payload` (the operation input plus\n * `_fingerprint`), NOT the full Nile envelope. This matches the server, which\n * verifies the signature against the raw request payload — see the Transport\n * Contract in the Nylon Pay SDK Spec (https://github.com/nile-squad/specs).\n */\nfunction buildAuthHeaders({\n apiKey,\n apiSecret,\n payload,\n}: {\n apiKey: string;\n apiSecret: string;\n payload: unknown;\n}): Record<string, string> {\n const nonce = generateNonce();\n const timestamp = createTimestamp();\n const signature = createSignature({\n fingerprint: CACHED_FINGERPRINT,\n nonce,\n timestamp,\n payload,\n secret: apiSecret,\n });\n\n return {\n \"content-type\": \"application/json\",\n \"x-nylon-key\": apiKey,\n \"x-nylon-nonce\": nonce,\n \"x-nylon-signature\": signature,\n \"x-nylon-timestamp\": timestamp,\n };\n}\n\n/** Create an AbortController with a timeout. Returns cleanup to clear the timer. */\nfunction withTimeout(timeoutMs: number): {\n controller: AbortController;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n return { controller, cleanup: () => clearTimeout(timeoutId) };\n}\n\n/**\n * Create the transport layer for SDK requests.\n *\n * @param config - Resolved SDK configuration\n * @returns Transport functions\n *\n * @internal\n */\nexport function createTransport({\n apiKey,\n apiSecret,\n baseUrl = DEFAULT_BASE_URL,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n maxRetries = DEFAULT_MAX_RETRIES,\n fetch: fetchImpl,\n}: {\n apiKey: string;\n apiSecret: string;\n baseUrl?: string;\n timeoutMs?: number;\n maxRetries?: number;\n fetch: typeof globalThis.fetch;\n}) {\n /**\n * Send a request to the backend.\n * Builds the envelope and headers once, then retries only the fetch call.\n */\n async function send<T>(\n request: TransportRequest,\n ): Promise<Result<T, string>> {\n const envelope = buildEnvelope(request);\n const signedPayload = (envelope as { payload: unknown }).payload;\n const headers = buildAuthHeaders({\n apiKey,\n apiSecret,\n payload: signedPayload,\n });\n const bodyString = JSON.stringify(envelope);\n\n async function attempt(currentAttempt: number): Promise<Result<T, string>> {\n const { controller, cleanup } = withTimeout(timeoutMs);\n\n try {\n const response = await fetchImpl(baseUrl, {\n method: \"POST\",\n headers,\n body: bodyString,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n const retryable = RETRYABLE_STATUS_CODES.has(statusCode);\n\n let errorMessage = `HTTP ${statusCode}`;\n try {\n const errorBody = await response.json();\n if (\n errorBody &&\n typeof errorBody === \"object\" &&\n \"message\" in errorBody\n ) {\n errorMessage = String(errorBody.message);\n }\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n\n if (retryable && currentAttempt < maxRetries) {\n cleanup();\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n cleanup();\n return Err(\n JSON.stringify(\n buildHttpError({ message: errorMessage, statusCode }),\n ),\n );\n }\n\n const responseBody = await response.json();\n\n if (\n !responseBody ||\n typeof responseBody !== \"object\" ||\n !(\"status\" in responseBody)\n ) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response missing status field\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const { status, message, data } = responseBody as {\n status: boolean;\n message: string;\n data: unknown;\n };\n\n if (status === true) {\n const { data: strippedData, responseSignature } =\n stripResponseSignature(data);\n\n // Fail closed. Every authenticated success response from the backend\n // is signed (see backend signSdkResponse). A missing signature means\n // the response was tampered with — e.g. a MITM stripped the field — or\n // did not originate from the backend. Reject rather than trust\n // unverified data; a prior version skipped verification when the field\n // was absent, which let a stripped-signature response through.\n if (!responseSignature) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature missing\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n category: \"internal\",\n message: \"Response signature verification failed\",\n retryable: false,\n } satisfies SdkError),\n );\n }\n\n cleanup();\n return Ok(strippedData as T);\n }\n\n // status === false\n const parsedError = parseError(message);\n cleanup();\n return Err(JSON.stringify(parsedError));\n } catch (error) {\n cleanup();\n\n const isAbort =\n error instanceof DOMException && error.name === \"AbortError\";\n const sdkError: SdkError = {\n category: isAbort ? \"timeout\" : \"network\",\n message: isAbort\n ? `Request timed out after ${timeoutMs}ms`\n : String(error),\n retryable: true,\n };\n\n if (currentAttempt < maxRetries) {\n await delay(calculateBackoff(currentAttempt));\n return attempt(currentAttempt + 1);\n }\n\n return Err(JSON.stringify(sdkError));\n }\n }\n\n return attempt(0);\n }\n\n return { send, parseError };\n}\n\n/**\n * Parse an error string into a structured SdkError with a `category`.\n * Tries the JSON envelope first; otherwise pulls the server's\n * ` -- error-type: <category>` suffix off a raw message, falling back to\n * category `internal` when untagged.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-2026-001\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.category, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n // Sync helper: `safeTry` is async-only. The try/catch is the sync\n // boundary for JSON.parse and stays as-is (mirrors the pre-existing\n // contract that the SDK always exposes `parseError` synchronously).\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"category\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).category === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not our JSON envelope — fall through to suffix parsing.\n }\n\n // Raw server message: pull the ` -- error-type: <category>` suffix if present.\n const fromSuffix = parseCategoryFromMessage(error);\n return {\n category: fromSuffix.category ?? \"internal\",\n message: fromSuffix.message,\n };\n}\n","/**\n * Payment instance with event emission for transaction lifecycle.\n * Handles polling, event emission, and wait-for-completion.\n *\n * @see Spec 2 section 2 - \".collectPayment() returns a payment instance that they have to listen for events on\"\n * @see Spec 2 section 9 - \"sdk on merchant side internally calls another action to our backend to get transaction status updates by polling\"\n */\n\nimport type { Result } from \"slang-ts\";\nimport { createEmitter, type Emitter } from \"./pubsub\";\nimport { POLL_JITTER_MS } from \"./sdk.config\";\nimport { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\n SdkError,\n StatusResponse,\n Transaction,\n TransactionStatus,\n} from \"./types\";\n\n/**\n * Internal state for a payment instance.\n * @internal\n */\ntype PaymentState = {\n reference: string;\n status: TransactionStatus;\n transaction: Transaction | null;\n pollingTimer: ReturnType<typeof setTimeout> | null;\n /** Last lifecycle event emitted from a status (dedupes repeat emissions). */\n lastStatusEvent: PaymentEvent | null;\n resolved: boolean;\n pollAttempts: number;\n pollStartTime: number;\n emitter: Emitter<PaymentEvent>;\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs: number;\n maxPollDuration: number;\n maxPollAttempts: number;\n};\n\n/**\n * Map transaction status to payment event. Both \"pending\" and \"processing\"\n * map to the \"processing\" event — to the merchant they are the same lifecycle\n * moment (payment accepted, in flight, awaiting the customer/provider).\n * Emission is deduped by event, so pending → processing never double-fires.\n */\nconst STATUS_TO_EVENT: Partial<Record<TransactionStatus, PaymentEvent>> = {\n pending: \"processing\",\n successful: \"success\",\n failed: \"failed\",\n processing: \"processing\",\n cancelled: \"cancelled\",\n};\n\nfunction statusToEvent(status: TransactionStatus): PaymentEvent | null {\n return STATUS_TO_EVENT[status] ?? null;\n}\n\n/** Terminal states that stop polling. */\nconst TERMINAL_STATES = new Set<TransactionStatus>([\n \"successful\",\n \"failed\",\n \"cancelled\",\n]);\n\n/**\n * Normalise raw backend status strings to TransactionStatus.\n * The backend may return \"completed\" for successful payments — map it to\n * \"successful\" so SDK events fire correctly.\n */\nfunction normalizeStatus(raw: string): TransactionStatus {\n if (raw === \"completed\") return \"successful\";\n return raw as TransactionStatus;\n}\n\n/**\n * Create a new payment instance.\n *\n * @param initialResponse - Response with reference and initial status\n * @param deps - Dependencies injected by the SDK\n * @returns Payment instance with event subscription\n *\n * @internal\n */\nexport function createPaymentInstance(\n initialResponse: { reference: string; status: TransactionStatus },\n deps: {\n fetchStatus: (\n input: GetStatusInput,\n ) => Promise<Result<StatusResponse, string>>;\n fetchTransaction: (\n input: GetTransactionInput,\n ) => Promise<Result<Transaction, string>>;\n pollIntervalMs?: number;\n maxPollDuration?: number;\n maxPollAttempts?: number;\n /**\n * When set, the operation never started (the backend rejected initiation).\n * The instance emits this as an `\"error\"` event on the next tick instead of\n * polling — so a server-side rejection surfaces as an event, not a throw.\n */\n initialError?: SdkError;\n },\n): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: normalizeStatus(initialResponse.status),\n transaction: null,\n pollingTimer: null,\n lastStatusEvent: null,\n resolved: false,\n pollAttempts: 0,\n pollStartTime: Date.now(),\n emitter: createEmitter<PaymentEvent>(),\n fetchStatus: deps.fetchStatus,\n fetchTransaction: deps.fetchTransaction,\n pollIntervalMs: deps.pollIntervalMs ?? 2000,\n maxPollDuration: deps.maxPollDuration ?? 300000,\n maxPollAttempts: deps.maxPollAttempts ?? 150,\n };\n\n function resolveWithError(error: string): void {\n state.resolved = true;\n stopUpdates();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(\n event: PaymentEvent,\n error?: string,\n category?: SdkError[\"category\"],\n retryable?: boolean,\n ): void {\n const data: EventData = {\n event,\n reference: state.reference,\n transaction: state.transaction ?? undefined,\n error,\n category,\n retryable,\n timestamp: new Date().toISOString(),\n };\n state.emitter.emit(event, data);\n }\n\n /**\n * Handle terminal state by fetching full transaction record.\n * @internal\n */\n async function handleTerminalState(status: TransactionStatus): Promise<void> {\n const txResult = await state.fetchTransaction({\n reference: state.reference,\n });\n if (txResult.isOk) {\n state.transaction = txResult.value;\n const event = statusToEvent(status);\n if (event) {\n const error =\n status === \"failed\"\n ? (state.transaction.failureReason ?? undefined)\n : undefined;\n emitEvent(event, error);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\n // Once the instance has resolved (terminal state, error, or timeout), no\n // further events may fire. A late status — e.g. an SSE chunk buffered before\n // the stream closed on fallback, or an in-flight poll — must be ignored so\n // it cannot emit a duplicate terminal event or a spurious out-of-order one.\n // The guard runs before any await, so the first caller to resolve wins.\n if (state.resolved) {\n return;\n }\n\n if (response.reference !== state.reference) {\n resolveWithError(\n `Reference mismatch: expected ${state.reference} but got ${response.reference}`,\n );\n return;\n }\n\n const newStatus = normalizeStatus(response.status);\n state.status = newStatus;\n\n // Dedupe by *event*, not raw status — \"pending\" and \"processing\" both map\n // to the \"processing\" event, and a status flap (processing → pending) must\n // not re-fire it. Each lifecycle event fires at most once per instance.\n const event = statusToEvent(newStatus);\n if (!event || event === state.lastStatusEvent) {\n return;\n }\n state.lastStatusEvent = event;\n\n if (TERMINAL_STATES.has(newStatus)) {\n await handleTerminalState(newStatus);\n return;\n }\n emitEvent(event);\n }\n\n /**\n * Handle polling error.\n * A `not_found` category during early polling is expected (the transaction\n * may not have propagated yet) — keep polling. Any other category is a real\n * failure that stops polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const parsed = parseError(error);\n if (parsed.category === \"not_found\") {\n return;\n }\n emitEvent(\"error\", parsed.message);\n state.resolved = true;\n stopUpdates();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one\n * finishes (no overlap). A random jitter is added to the interval so many\n * concurrent payments don't synchronise into a thundering herd on the status\n * endpoint.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n const delay = state.pollIntervalMs + Math.random() * POLL_JITTER_MS;\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, delay);\n }\n\n /**\n * Execute one polling cycle and queue the next one when appropriate.\n * @internal\n */\n async function pollStatus(): Promise<void> {\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n if (state.pollAttempts >= state.maxPollAttempts) {\n resolveWithError(\"Polling timeout: exceeded maximum attempts\");\n return;\n }\n\n if (Date.now() - state.pollStartTime >= state.maxPollDuration) {\n resolveWithError(\"Polling timeout: exceeded maximum duration\");\n return;\n }\n\n state.pollAttempts += 1;\n\n const result = await state.fetchStatus({ reference: state.reference });\n\n if (result.isOk) {\n await handleStatusUpdate(result.value);\n } else {\n handlePollError(result.error);\n }\n\n if (state.resolved) {\n stopUpdates();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start status updates. If the initial status is already terminal (e.g. sandbox\n * resolves synchronously), emit the terminal event after a tick so handlers\n * registered after instance creation still fire. Otherwise emit the initial\n * in-flight event (\"processing\") on the next tick — the initiation response\n * is typically \"pending\", and a fast payment can jump straight to a terminal\n * status between polls, which previously meant \"processing\" never fired —\n * then begin polling.\n * @internal\n */\n function startUpdates(): void {\n if (TERMINAL_STATES.has(state.status)) {\n setTimeout(() => {\n void handleTerminalState(state.status);\n }, 0);\n return;\n }\n\n const initialEvent = statusToEvent(state.status);\n if (initialEvent) {\n // Mark as emitted synchronously so a poll result mapping to the same\n // event cannot race a duplicate in before the timeout fires.\n state.lastStatusEvent = initialEvent;\n setTimeout(() => {\n if (!state.resolved) {\n emitEvent(initialEvent);\n }\n }, 0);\n }\n scheduleNextPoll();\n }\n\n /**\n * Stop all status updates (the poll timer).\n * @internal\n */\n function stopUpdates(): void {\n if (state.pollingTimer) {\n clearTimeout(state.pollingTimer);\n state.pollingTimer = null;\n }\n }\n\n /**\n * Subscribe to payment events.\n */\n function on(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.on(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Unsubscribe from payment events.\n */\n function off(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.off(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Subscribe to a payment event for a single invocation, then auto-unsubscribe.\n * Useful for one-shot handlers on terminal events like \"success\" or \"failed\".\n */\n function once(\n event: PaymentEvent,\n handler: PaymentEventHandler,\n ): PaymentInstance {\n state.emitter.once(event, handler as (data: unknown) => void);\n return paymentInstance;\n }\n\n /**\n * Wait for payment to reach a terminal state.\n * Resolves with the full Transaction on success, null on failure/cancel/error.\n * Never rejects — check the return value to determine outcome.\n */\n function wait(): Promise<Transaction | null> {\n return new Promise((resolve) => {\n if (state.resolved) {\n resolve(\n state.status === \"successful\" && state.transaction\n ? state.transaction\n : null,\n );\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n resolve(state.transaction ?? null);\n }\n\n function onFailed(): void {\n cleanup();\n resolve(null);\n }\n\n function onCancelled(): void {\n cleanup();\n resolve(null);\n }\n\n function onError(): void {\n cleanup();\n resolve(null);\n }\n\n function cleanup(): void {\n state.emitter.off(\"success\", onSuccess);\n state.emitter.off(\"failed\", onFailed);\n state.emitter.off(\"cancelled\", onCancelled);\n state.emitter.off(\"error\", onError);\n }\n\n state.emitter.on(\"success\", onSuccess);\n state.emitter.on(\"failed\", onFailed);\n state.emitter.on(\"cancelled\", onCancelled);\n state.emitter.on(\"error\", onError);\n });\n }\n\n const paymentInstance: PaymentInstance = {\n get reference() {\n return state.reference;\n },\n get status() {\n return state.status;\n },\n on,\n once,\n off,\n wait,\n };\n\n // When the backend rejected initiation, there is nothing to poll.\n // Emit an \"error\" event on the next tick so handlers registered after\n // creation still fire, and mark resolved so wait() returns null.\n if (deps.initialError) {\n state.resolved = true;\n const err = deps.initialError;\n setTimeout(() => {\n emitEvent(\"error\", err.message, err.category, err.retryable);\n }, 0);\n } else {\n startUpdates();\n }\n\n return paymentInstance;\n}\n","/**\n * Normalize a phone number to international format without leading +.\n *\n * - Strips all whitespace\n * - Strips leading +\n * - If starts with \"0\" and length is 10 → prepend \"256\"\n *\n * WHY: Phone numbers like \"0768499027\" reach the backend unnormalized.\n * SDK normalizing first means the wire payload is already correct,\n * providing defense-in-depth even though the backend also normalizes.\n */\nexport function normalizePhone(phone: string): string {\n let normalized = phone.replace(/\\s+/g, \"\").replace(/^\\+/, \"\");\n\n if (normalized.startsWith(\"0\") && normalized.length === 10) {\n normalized = `256${normalized.slice(1)}`;\n }\n\n return normalized;\n}\n","/**\n * Standalone webhook signature verification utility.\n * Merchants use this to confirm that incoming webhook payloads\n * were genuinely sent by Nylon Pay before acting on them.\n */\n\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { VerifyWebhookInput } from \"./types\";\n\n/** Default replay-protection window: the signed timestamp must be this fresh. */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/** Decode the (already signature-verified) payload to a UTF-8 string. */\nfunction decodePayload(payload: string | Uint8Array): string {\n return typeof payload === \"string\"\n ? payload\n : Buffer.from(payload).toString(\"utf8\");\n}\n\n/**\n * Pull the signed `timestamp` out of a verified webhook body and return it as\n * epoch milliseconds. The timestamp lives inside the HMAC-signed body (the\n * backend stamps every delivery and every retry fresh), so it cannot be forged\n * or refreshed by a replay attacker without the secret. Returns `null` when the\n * body is not JSON or carries no parseable timestamp.\n */\nfunction extractSignedTimestampMs(payloadString: string): number | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(payloadString);\n } catch {\n return null;\n }\n\n if (!parsed || typeof parsed !== \"object\") {\n return null;\n }\n\n const raw = (parsed as Record<string, unknown>).timestamp;\n\n if (typeof raw === \"number\" && Number.isFinite(raw)) {\n // Accept epoch seconds or milliseconds — values below ~1e12 are seconds.\n return raw < 1e12 ? raw * 1000 : raw;\n }\n\n if (typeof raw === \"string\") {\n const ms = Date.parse(raw);\n return Number.isNaN(ms) ? null : ms;\n }\n\n return null;\n}\n\n/**\n * Verify that a webhook payload was genuinely sent by Nylon Pay.\n *\n * Two checks, both must pass:\n * 1. **Authenticity** — HMAC-SHA256 over the raw payload bytes (NOT parsed\n * JSON, spec invariant #8) matches the provided signature.\n * 2. **Freshness** — the `timestamp` carried inside the signed body is within\n * `toleranceSeconds` of now (default 300s). This is what stops a replay: a\n * captured `(body, signature)` pair stays cryptographically valid forever,\n * but its embedded timestamp goes stale. Every genuine delivery, including\n * retries hours later, is re-stamped and re-signed, so this never rejects\n * legitimate traffic. Pass `toleranceSeconds: 0` to skip this check.\n *\n * @returns True when the signature is valid and (when enforced) the webhook is fresh\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadString = decodePayload(input.payload);\n const payloadBytes = Buffer.from(payloadString, \"utf8\");\n\n const expectedSignature = createHmac(\"sha256\", input.secret)\n .update(payloadBytes)\n .digest(\"hex\");\n\n const providedBuffer = Buffer.from(input.signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (providedBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n if (!timingSafeEqual(providedBuffer, expectedBuffer)) {\n return false;\n }\n\n // Signature is authentic — now enforce freshness using the signed timestamp.\n const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (toleranceSeconds <= 0) {\n return true;\n }\n\n const timestampMs = extractSignedTimestampMs(payloadString);\n if (timestampMs === null) {\n // Fail closed: a valid signature with no verifiable timestamp cannot be\n // proven fresh, so it cannot be distinguished from a replay.\n return false;\n }\n\n const ageMs = Math.abs(Date.now() - timestampMs);\n return ageMs <= toleranceSeconds * 1000;\n}\n","/**\n * SDK instance providing all merchant-facing payment operations.\n * Created via createNylonPay factory and returned as NylonPaySdk.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { Err, Ok, type Result, safeTry } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { normalizePhone } from \"./phone\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createSdkError, createTransport, parseError } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\n SdkHook,\n SdkHooks,\n StatusResponse,\n Transaction,\n TransactionStatus,\n VerifyPhoneInput,\n VerifyWebhookInput,\n} from \"./types\";\nimport { verifyWebhookSignature } from \"./verify-webhook\";\n\nexport type { NylonPaySdk } from \"./types\";\n\ntype ResolvedConfig = {\n apiKey: string;\n apiSecret: string;\n baseUrl: string;\n timeoutMs: number;\n maxRetries: number;\n maxPollIntervalMs: number;\n maxPollDurationMs: number;\n maxPollAttempts: number;\n fetch: typeof globalThis.fetch;\n hooks?: SdkHooks;\n};\n\n/** Generate a random 15-character hex reference for idempotency. */\nfunction generateReference(): string {\n return randomBytes(16).toString(\"hex\").slice(0, 15);\n}\n\n/**\n * PivotPay caps the `merchantTransactionId` (our reference) at 13–15 characters.\n * The backend echoes the reference verbatim as that id, so an out-of-range\n * reference is rejected server-side (and historically surfaced as an opaque\n * provider error). Auto-generated references are always 15 chars; this only\n * bites when a merchant supplies their own (e.g. a 36-char UUID order id).\n */\nconst REFERENCE_MIN_LENGTH = 13;\nconst REFERENCE_MAX_LENGTH = 15;\n\n/**\n * Resolve the idempotency reference for a create call: auto-generate when the\n * merchant omits it, otherwise validate their value against the 13–15 char\n * limit *synchronously* (like validateAmount) so a bad reference throws locally\n * instead of costing a backend round-trip.\n */\nfunction resolveReference(reference?: string): string {\n if (reference === undefined) {\n return generateReference();\n }\n if (\n reference.length < REFERENCE_MIN_LENGTH ||\n reference.length > REFERENCE_MAX_LENGTH\n ) {\n throwValidation(\n `reference must be ${REFERENCE_MIN_LENGTH}–${REFERENCE_MAX_LENGTH} characters`,\n );\n }\n return reference;\n}\n\n/**\n * Run a lifecycle hook safely. A disabled or unset hook is a no-op. The hook's\n * `fn` runs inside `safeTry` so a throw/rejection in merchant code never bubbles\n * into the payment flow — it is routed to the hook's `onError` (which is itself\n * wrapped, so a faulty handler can't crash us either).\n *\n * Returns the hook's resolved value on success, or `undefined` when the hook was\n * skipped or failed. Callers treat `undefined` as \"no override\" — for before\n * hooks that means the original payload is used unchanged.\n */\nasync function runHook<TFn extends (...args: never[]) => unknown>(\n hook: SdkHook<TFn> | undefined,\n ...args: Parameters<TFn>\n): Promise<Awaited<ReturnType<TFn>> | undefined> {\n if (!hook || hook.enabled === false) return undefined;\n\n const result = await safeTry(async () => hook.fn(...args));\n // safeTry widens the success value to `unknown` through the generic bound;\n // by construction it is the hook's resolved return type.\n if (result.isOk) return result.value as Awaited<ReturnType<TFn>>;\n\n await safeTry(async () => hook.onError(result.error));\n return undefined;\n}\n\n/**\n * Throw a categorized input-validation error. Keeps thrown errors consistent\n * with transport-init failures so a merchant's `catch (e)` can always read\n * `e.category` (here always `\"validation\"`).\n */\nfunction throwValidation(message: string): never {\n throw createSdkError({ category: \"validation\", message });\n}\n\n/** Validate collection amount is a positive integer >= 500. */\nfunction validateCollectionAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 500) {\n throwValidation(\"Collection amount must be at least 500 UGX\");\n }\n}\n\n/** Validate payout amount is a positive integer >= 5000. */\nfunction validatePayoutAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throwValidation(\"amount must be a positive integer\");\n }\n if (amount < 5000) {\n throwValidation(\"Payout amount must be at least 5000 UGX\");\n }\n}\n\n/** Validate that a string value is non-empty. */\nfunction validateNonEmpty(value: string, fieldName: string): void {\n if (!value || value.trim() === \"\") {\n throwValidation(`${fieldName} is required`);\n }\n}\n\n/**\n * Create an SDK instance with resolved configuration.\n * Returns an object implementing the NylonPaySdk interface.\n */\nexport function createSdkInstance(config: ResolvedConfig): NylonPaySdk {\n const transport = createTransport({\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl: config.baseUrl,\n timeoutMs: config.timeoutMs,\n maxRetries: config.maxRetries,\n fetch: config.fetch,\n });\n\n const commonDeps = {\n fetchStatus: (input: GetStatusInput) =>\n transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n }),\n fetchTransaction: (input: GetTransactionInput) =>\n transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n }),\n pollIntervalMs: config.maxPollIntervalMs,\n maxPollDuration: config.maxPollDurationMs,\n maxPollAttempts: config.maxPollAttempts,\n };\n\n /**\n * Initiate a collection payment.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function collectPayment(\n input: CollectPaymentInput,\n ): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed (invalid key, signature, limit, provider reject). The\n // transaction never started — return a PaymentInstance that emits an\n // \"error\" event instead of throwing, so merchants handle it via events.\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a collection and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function collectPaymentAndResolve(\n input: CollectPaymentInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throwValidation('bank details are required when method is \"bank\"');\n }\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforeCollect, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterCollect,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Initiate a payout.\n * Auto-generates reference if omitted. Returns a PaymentInstance\n * that emits events as the transaction progresses.\n */\n async function makePayout(input: MakePayoutInput): Promise<PaymentInstance> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n // Initiation failed — return a PaymentInstance that emits an \"error\"\n // event instead of throwing (see collectPayment for rationale).\n if (result.isErr) {\n const sdkErr = parseError(result.error);\n return createPaymentInstance(\n { reference, status: \"pending\" },\n { ...commonDeps, initialError: sdkErr },\n );\n }\n\n return createPaymentInstance(result.value, commonDeps);\n }\n\n /**\n * Initiate a payout and block until terminal state.\n * Server polls internally; merchant gets the full transaction record.\n */\n async function makePayoutAndResolve(\n input: MakePayoutInput,\n ): Promise<Result<Transaction, string>> {\n const reference = resolveReference(input.reference);\n validatePayoutAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n const normalizedPhone = normalizePhone(input.customer.phoneNumber);\n validateNonEmpty(input.description, \"description\");\n validateNonEmpty(\n input.destination.accountHolderName,\n \"destination.accountHolderName\",\n );\n validateNonEmpty(\n input.destination.accountNumber,\n \"destination.accountNumber\",\n );\n\n let payload = {\n ...input,\n reference,\n customer: { ...input.customer, phoneNumber: normalizedPhone },\n };\n const mutated = await runHook(config.hooks?.beforePayout, payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\n payload,\n });\n\n await runHook(\n config.hooks?.afterPayout,\n result.isOk\n ? Ok({ reference: result.value.reference, status: result.value.status })\n : Err(result.error),\n payload,\n );\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the current status of a transaction.\n * Lightweight check that returns only status fields.\n */\n async function getStatus(\n input: GetStatusInput,\n ): Promise<Result<StatusResponse, string>> {\n validateNonEmpty(input.reference, \"reference\");\n\n const result = await transport.send<StatusResponse>({\n action: SDK_ACTIONS.getStatus,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Get the full transaction record.\n * Requires at least one of id or reference.\n */\n async function getTransaction(\n input: GetTransactionInput,\n ): Promise<Result<Transaction, string>> {\n if (!input.id && !input.reference) {\n throwValidation(\"id or reference is required\");\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.getTransaction,\n payload: input,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a phone number with the provider.\n * Returns the registered name for identity confirmation.\n */\n async function verifyPhone(\n input: VerifyPhoneInput,\n ): Promise<Result<PhoneVerification, string>> {\n validateNonEmpty(input.phoneNumber, \"phoneNumber\");\n const normalizedPhone = normalizePhone(input.phoneNumber);\n\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: { ...input, phoneNumber: normalizedPhone },\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Create a hosted invoice.\n * Auto-generates reference if omitted. Returns payment link and token.\n */\n async function createInvoice(\n input: CreateInvoiceInput,\n ): Promise<Result<InvoiceResponse, string>> {\n const reference = resolveReference(input.reference);\n validateCollectionAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throwValidation(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throwValidation(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throwValidation(\"item unitPrice must be a positive integer\");\n }\n }\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<InvoiceResponse>({\n action: SDK_ACTIONS.createInvoice,\n payload,\n });\n\n if (result.isOk) {\n return Ok(result.value);\n }\n return Err(result.error);\n }\n\n /**\n * Verify a webhook payload signature.\n * Delegates to the standalone verifyWebhookSignature utility.\n */\n function verifyWebhook(input: VerifyWebhookInput): boolean {\n return verifyWebhookSignature(input);\n }\n\n return {\n collectPayment,\n collectPaymentAndResolve,\n makePayout,\n makePayoutAndResolve,\n getStatus,\n getTransaction,\n verifyPhone,\n createInvoice,\n verifyWebhookSignature: verifyWebhook,\n };\n}\n","/**\n * Factory function to create a Nylon Pay SDK instance.\n * This is the main entry point for merchants.\n *\n * Calling createNylonPay with the same apiKey, apiSecret and baseUrl returns the\n * same instance (singleton per key+secret+url). Rotating the secret yields a\n * fresh instance. Pass { force: true } to force a new instance regardless.\n *\n * @example\n * ```ts\n * import { createNylonPay } from \"@nile-squad/nylonpay-ts\";\n *\n * export const nylonpay = createNylonPay({\n * apiKey: \"npk_...\",\n * apiSecret: \"nps_...\",\n * });\n * ```\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createSdkInstance, type NylonPaySdk } from \"./sdk\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_MAX_POLL_ATTEMPTS,\n DEFAULT_MAX_POLL_DURATION_MS,\n DEFAULT_MAX_POLL_INTERVAL_MS,\n DEFAULT_MAX_RETRIES,\n DEFAULT_TIMEOUT_MS,\n} from \"./sdk.config\";\nimport type { NylonPayConfig } from \"./types\";\n\nconst instances = new Map<string, NylonPaySdk>();\n\n/**\n * Create a Nylon Pay SDK instance.\n *\n * Returns the same instance for the same apiKey + apiSecret + baseUrl\n * combination unless { force: true } is passed. Use your test keys for sandbox,\n * production keys for live.\n *\n * @param config - SDK configuration with apiKey and apiSecret\n * @returns SDK instance with all payment operations\n *\n * @throws Error if required config is missing or invalid\n */\nexport function createNylonPay(config: NylonPayConfig): NylonPaySdk {\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n if (!config.apiKey.startsWith(\"npk_\")) {\n throw new Error('apiKey must start with \"npk_\"');\n }\n if (!config.apiSecret) {\n throw new Error(\"apiSecret is required\");\n }\n if (!config.apiSecret.startsWith(\"nps_\")) {\n throw new Error('apiSecret must start with \"nps_\"');\n }\n\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n // Include a hash of the secret in the cache key so rotating apiSecret in a\n // long-running process returns a fresh instance instead of a stale one signing\n // with the old secret. Hashed (not raw) so the secret never sits in a Map key.\n const secretHash = createHash(\"sha256\")\n .update(config.apiSecret)\n .digest(\"hex\")\n .slice(0, 16);\n const instanceKey = `${config.apiKey}:${baseUrl}:${secretHash}`;\n\n if (!config.force) {\n const existing = instances.get(instanceKey);\n if (existing) return existing;\n }\n\n const resolvedConfig = {\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,\n maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,\n maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n hooks: config.hooks,\n };\n\n const instance = createSdkInstance(resolvedConfig);\n instances.set(instanceKey, instance);\n return instance;\n}\n"]}
|