@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 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
- if (newStatus !== oldStatus) {
458
- const event = statusToEvent(newStatus);
459
- if (event) {
460
- if (TERMINAL_STATES.has(newStatus)) {
461
- await handleTerminalState(newStatus);
462
- return;
463
- }
464
- emitEvent(event);
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() {
@@ -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. `transaction` is populated
352
- * for status-change events (`processing`, `success`, `failed`, `cancelled`);
353
- * `error` is populated for the `"error"` event (network failure, timeout,
354
- * reference mismatch).
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.transaction?.reference); // "ORDER-2026-001"
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
- /** Full transaction record. Present for status-change events. */
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. `transaction` is populated
352
- * for status-change events (`processing`, `success`, `failed`, `cancelled`);
353
- * `error` is populated for the `"error"` event (network failure, timeout,
354
- * reference mismatch).
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.transaction?.reference); // "ORDER-2026-001"
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
- /** Full transaction record. Present for status-change events. */
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
- if (newStatus !== oldStatus) {
456
- const event = statusToEvent(newStatus);
457
- if (event) {
458
- if (TERMINAL_STATES.has(newStatus)) {
459
- await handleTerminalState(newStatus);
460
- return;
461
- }
462
- emitEvent(event);
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":"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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 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nile-squad/nylonpay-ts",
3
- "version": "1.0.10",
3
+ "version": "1.1.0",
4
4
  "description": "Nylon Pay SDK for merchant integrations",
5
5
  "keywords": [
6
6
  "nylonpay",