@nile-squad/nylonpay-ts 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -196,6 +196,19 @@ payment.off("success", handler);
196
196
  const tx = await payment.wait();
197
197
  ```
198
198
 
199
+ Use `safeTry` from `slang-ts` to handle the promise without try/catch:
200
+
201
+ ```ts
202
+ import { safeTry } from "slang-ts";
203
+
204
+ const result = await safeTry(() => payment.wait());
205
+ if (result.isOk) {
206
+ console.log("paid:", result.value.reference);
207
+ } else {
208
+ console.log("failed or timed out:", result.error);
209
+ }
210
+ ```
211
+
199
212
  ## Error Handling
200
213
 
201
214
  All operations return `Result<T, string>` from [slang-ts](https://github.com/nile-squad/slang-ts). Use `parseError` to get structured error objects.
@@ -207,7 +220,7 @@ const result = await nylonpay.getStatus({ reference: "ORDER-123" });
207
220
  if (!result.isOk) {
208
221
  const error = parseError(result.error);
209
222
  if (error.retryable) {
210
- // Retry the request
223
+ // retry
211
224
  }
212
225
  }
213
226
  ```
package/dist/index.cjs CHANGED
@@ -573,11 +573,25 @@ function createSdkInstance(config) {
573
573
  if (input.method === "bank" && !input.bank) {
574
574
  throw new Error('bank details are required when method is "bank"');
575
575
  }
576
- const payload = { ...input, reference };
576
+ let payload = { ...input, reference };
577
+ if (config.hooks?.beforeCollect) {
578
+ const mutated = await config.hooks.beforeCollect(payload);
579
+ if (mutated != null)
580
+ payload = { ...mutated, reference: mutated.reference ?? reference };
581
+ }
577
582
  const result = await transport.send({
578
583
  action: SDK_ACTIONS.collectPayment,
579
584
  payload
580
585
  });
586
+ if (config.hooks?.afterCollect) {
587
+ await config.hooks.afterCollect(
588
+ result.isOk ? slangTs.Ok({
589
+ reference: result.value.reference,
590
+ status: result.value.status
591
+ }) : slangTs.Err(result.error),
592
+ payload
593
+ );
594
+ }
581
595
  if (result.isOk) {
582
596
  return createPaymentInstance(result.value, commonDeps);
583
597
  }
@@ -601,11 +615,25 @@ function createSdkInstance(config) {
601
615
  if (input.method === "bank" && !input.bank) {
602
616
  throw new Error('bank details are required when method is "bank"');
603
617
  }
604
- const payload = { ...input, reference };
618
+ let payload = { ...input, reference };
619
+ if (config.hooks?.beforeCollect) {
620
+ const mutated = await config.hooks.beforeCollect(payload);
621
+ if (mutated != null)
622
+ payload = { ...mutated, reference: mutated.reference ?? reference };
623
+ }
605
624
  const result = await transport.send({
606
625
  action: SDK_ACTIONS.collectPaymentAndResolve,
607
626
  payload
608
627
  });
628
+ if (config.hooks?.afterCollect) {
629
+ await config.hooks.afterCollect(
630
+ result.isOk ? slangTs.Ok({
631
+ reference: result.value.reference,
632
+ status: result.value.status
633
+ }) : slangTs.Err(result.error),
634
+ payload
635
+ );
636
+ }
609
637
  if (result.isOk) {
610
638
  return slangTs.Ok(result.value);
611
639
  }
@@ -625,11 +653,25 @@ function createSdkInstance(config) {
625
653
  input.destination.accountNumber,
626
654
  "destination.accountNumber"
627
655
  );
628
- const payload = { ...input, reference };
656
+ let payload = { ...input, reference };
657
+ if (config.hooks?.beforePayout) {
658
+ const mutated = await config.hooks.beforePayout(payload);
659
+ if (mutated != null)
660
+ payload = { ...mutated, reference: mutated.reference ?? reference };
661
+ }
629
662
  const result = await transport.send({
630
663
  action: SDK_ACTIONS.makePayout,
631
664
  payload
632
665
  });
666
+ if (config.hooks?.afterPayout) {
667
+ await config.hooks.afterPayout(
668
+ result.isOk ? slangTs.Ok({
669
+ reference: result.value.reference,
670
+ status: result.value.status
671
+ }) : slangTs.Err(result.error),
672
+ payload
673
+ );
674
+ }
633
675
  if (result.isOk) {
634
676
  return createPaymentInstance(result.value, commonDeps);
635
677
  }
@@ -658,11 +700,25 @@ function createSdkInstance(config) {
658
700
  input.destination.accountNumber,
659
701
  "destination.accountNumber"
660
702
  );
661
- const payload = { ...input, reference };
703
+ let payload = { ...input, reference };
704
+ if (config.hooks?.beforePayout) {
705
+ const mutated = await config.hooks.beforePayout(payload);
706
+ if (mutated != null)
707
+ payload = { ...mutated, reference: mutated.reference ?? reference };
708
+ }
662
709
  const result = await transport.send({
663
710
  action: SDK_ACTIONS.makePayoutAndResolve,
664
711
  payload
665
712
  });
713
+ if (config.hooks?.afterPayout) {
714
+ await config.hooks.afterPayout(
715
+ result.isOk ? slangTs.Ok({
716
+ reference: result.value.reference,
717
+ status: result.value.status
718
+ }) : slangTs.Err(result.error),
719
+ payload
720
+ );
721
+ }
666
722
  if (result.isOk) {
667
723
  return slangTs.Ok(result.value);
668
724
  }
@@ -747,6 +803,7 @@ function createSdkInstance(config) {
747
803
  }
748
804
 
749
805
  // src/create-nylon-pay.ts
806
+ var instances = /* @__PURE__ */ new Map();
750
807
  function createNylonPay(config) {
751
808
  if (!config.apiKey) {
752
809
  throw new Error("apiKey is required");
@@ -760,18 +817,27 @@ function createNylonPay(config) {
760
817
  if (!config.apiSecret.startsWith("nps_")) {
761
818
  throw new Error('apiSecret must start with "nps_"');
762
819
  }
820
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
821
+ const instanceKey = `${config.apiKey}:${baseUrl}`;
822
+ if (!config.force) {
823
+ const existing = instances.get(instanceKey);
824
+ if (existing) return existing;
825
+ }
763
826
  const resolvedConfig = {
764
827
  apiKey: config.apiKey,
765
828
  apiSecret: config.apiSecret,
766
- baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
829
+ baseUrl,
767
830
  timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
768
831
  maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
769
832
  maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,
770
833
  maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,
771
834
  maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,
772
- fetch: config.fetch ?? globalThis.fetch.bind(globalThis)
835
+ fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
836
+ hooks: config.hooks
773
837
  };
774
- return createSdkInstance(resolvedConfig);
838
+ const instance = createSdkInstance(resolvedConfig);
839
+ instances.set(instanceKey, instance);
840
+ return instance;
775
841
  }
776
842
 
777
843
  exports.createNylonPay = createNylonPay;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pubsub.ts","../src/fingerprint.ts","../src/nonce.ts","../src/sdk.config.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.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"],"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","/**\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","/** 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/** 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 * 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 alphabetically for deterministic JSON.\n * Must match backend's createCanonicalPayload function.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\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]) => firstKey.localeCompare(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.\n * Keys are sorted alphabetically for deterministic serialization.\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, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\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 const sdkError: SdkError = {\n code: `HTTP_${statusCode}`,\n message: errorMessage,\n statusCode,\n retryable,\n };\n\n cleanup();\n return Err(JSON.stringify(sdkError));\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 code: \"INVALID_RESPONSE\",\n message: \"Response missing status field\",\n retryable: false,\n }),\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 if (responseSignature) {\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n code: \"RESPONSE_TAMPERED\",\n message: \"Response signature verification failed\",\n retryable: false,\n }),\n );\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 code: isAbort ? \"TIMEOUT\" : \"NETWORK_ERROR\",\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 an SdkError object.\n * Tries JSON.parse first; falls back to a generic UNKNOWN error.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-123\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.code, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"code\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).code === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not JSON, fall through\n }\n\n return { code: \"UNKNOWN\", message: error };\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 { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\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 | null;\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 * 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): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: 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 stopPolling();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(event: PaymentEvent, error?: string): void {\n const data: EventData = {\n event,\n transaction: state.transaction ?? undefined,\n error,\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 emitEvent(event);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\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 = 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 * \"Not found\" during early polling is expected; other errors stop polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const isNotFound =\n error.includes(\"not found\") || error.includes(\"NOT_FOUND\");\n if (isNotFound) {\n return;\n }\n emitEvent(\"error\", parseError(error).message);\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one finishes.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, state.pollIntervalMs);\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 stopPolling();\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 stopPolling();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start polling for status updates.\n * @internal\n */\n function startPolling(): void {\n scheduleNextPoll();\n }\n\n /**\n * Stop polling.\n * @internal\n */\n function stopPolling(): 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 on success, rejects on failure/cancel/error.\n */\n function wait(): Promise<Transaction> {\n return new Promise((resolve, reject) => {\n if (state.resolved) {\n if (state.status === \"successful\" && state.transaction) {\n resolve(state.transaction);\n } else {\n reject(new Error(`Payment ${state.status ?? \"error\"}`));\n }\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n if (state.transaction) {\n resolve(state.transaction);\n } else {\n reject(\n new Error(\"Payment successful but transaction data unavailable\"),\n );\n }\n }\n\n function onFailed(): void {\n cleanup();\n reject(new Error(\"Payment failed\"));\n }\n\n function onCancelled(): void {\n cleanup();\n reject(new Error(\"Payment cancelled\"));\n }\n\n function onError(data: unknown): void {\n cleanup();\n const eventData = data as EventData;\n reject(new Error(eventData.error ?? \"Payment error\"));\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 startPolling();\n\n return paymentInstance;\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/**\n * Verify that a webhook payload was signed by Nylon Pay.\n * Operates on raw payload bytes, NOT parsed JSON (spec invariant #8).\n *\n * @param input.payload - Raw request body as string or Uint8Array\n * @param input.signature - Signature from the webhook header\n * @param input.secret - Merchant's webhook secret\n * @returns True when the signature is valid\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadBytes =\n typeof input.payload === \"string\"\n ? Buffer.from(input.payload, \"utf8\")\n : Buffer.from(input.payload);\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 return timingSafeEqual(providedBuffer, expectedBuffer);\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 } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createTransport } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\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};\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/** Validate that amount is a positive integer. */\nfunction validateAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throw new Error(\"amount must be a positive integer\");\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 throw new Error(`${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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 const payload = { ...input, reference };\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 const payload = { ...input, reference };\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\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 throw new Error(\"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\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: input,\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throw new Error(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throw new Error(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throw new Error(\"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 * @example\n * ```ts\n * import { createNylonPay } from \"@nile-squad/nylonpay-ts\";\n *\n * export const nylonpay = createNylonPay({\n * apiKey: process.env.NYLONPAY_API_KEY!,\n * apiSecret: process.env.NYLONPAY_API_SECRET!,\n * });\n * ```\n */\n\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\n/**\n * Create a Nylon Pay SDK instance.\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 resolvedConfig = {\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\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 };\n\n return createSdkInstance(resolvedConfig);\n}\n"]}
1
+ {"version":3,"sources":["../src/pubsub.ts","../src/fingerprint.ts","../src/nonce.ts","../src/sdk.config.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.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"],"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","/**\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","/** 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/** 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 * 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 alphabetically for deterministic JSON.\n * Must match backend's createCanonicalPayload function.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\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]) => firstKey.localeCompare(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.\n * Keys are sorted alphabetically for deterministic serialization.\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, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\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 const sdkError: SdkError = {\n code: `HTTP_${statusCode}`,\n message: errorMessage,\n statusCode,\n retryable,\n };\n\n cleanup();\n return Err(JSON.stringify(sdkError));\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 code: \"INVALID_RESPONSE\",\n message: \"Response missing status field\",\n retryable: false,\n }),\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 if (responseSignature) {\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n code: \"RESPONSE_TAMPERED\",\n message: \"Response signature verification failed\",\n retryable: false,\n }),\n );\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 code: isAbort ? \"TIMEOUT\" : \"NETWORK_ERROR\",\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 an SdkError object.\n * Tries JSON.parse first; falls back to a generic UNKNOWN error.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-123\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.code, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"code\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).code === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not JSON, fall through\n }\n\n return { code: \"UNKNOWN\", message: error };\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 { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\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 | null;\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 * 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): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: 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 stopPolling();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(event: PaymentEvent, error?: string): void {\n const data: EventData = {\n event,\n transaction: state.transaction ?? undefined,\n error,\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 emitEvent(event);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\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 = 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 * \"Not found\" during early polling is expected; other errors stop polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const isNotFound =\n error.includes(\"not found\") || error.includes(\"NOT_FOUND\");\n if (isNotFound) {\n return;\n }\n emitEvent(\"error\", parseError(error).message);\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one finishes.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, state.pollIntervalMs);\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 stopPolling();\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 stopPolling();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start polling for status updates.\n * @internal\n */\n function startPolling(): void {\n scheduleNextPoll();\n }\n\n /**\n * Stop polling.\n * @internal\n */\n function stopPolling(): 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 on success, rejects on failure/cancel/error.\n */\n function wait(): Promise<Transaction> {\n return new Promise((resolve, reject) => {\n if (state.resolved) {\n if (state.status === \"successful\" && state.transaction) {\n resolve(state.transaction);\n } else {\n reject(new Error(`Payment ${state.status ?? \"error\"}`));\n }\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n if (state.transaction) {\n resolve(state.transaction);\n } else {\n reject(\n new Error(\"Payment successful but transaction data unavailable\"),\n );\n }\n }\n\n function onFailed(): void {\n cleanup();\n reject(new Error(\"Payment failed\"));\n }\n\n function onCancelled(): void {\n cleanup();\n reject(new Error(\"Payment cancelled\"));\n }\n\n function onError(data: unknown): void {\n cleanup();\n const eventData = data as EventData;\n reject(new Error(eventData.error ?? \"Payment error\"));\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 startPolling();\n\n return paymentInstance;\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/**\n * Verify that a webhook payload was signed by Nylon Pay.\n * Operates on raw payload bytes, NOT parsed JSON (spec invariant #8).\n *\n * @param input.payload - Raw request body as string or Uint8Array\n * @param input.signature - Signature from the webhook header\n * @param input.secret - Merchant's webhook secret\n * @returns True when the signature is valid\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadBytes =\n typeof input.payload === \"string\"\n ? Buffer.from(input.payload, \"utf8\")\n : Buffer.from(input.payload);\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 return timingSafeEqual(providedBuffer, expectedBuffer);\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 } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createTransport } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\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/** Validate that amount is a positive integer. */\nfunction validateAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throw new Error(\"amount must be a positive integer\");\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 throw new Error(`${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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n let payload = { ...input, reference };\n if (config.hooks?.beforeCollect) {\n const mutated = await config.hooks.beforeCollect(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n if (config.hooks?.afterCollect) {\n await config.hooks.afterCollect(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\n }\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n let payload = { ...input, reference };\n if (config.hooks?.beforeCollect) {\n const mutated = await config.hooks.beforeCollect(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\n payload,\n });\n\n if (config.hooks?.afterCollect) {\n await config.hooks.afterCollect(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 = { ...input, reference };\n if (config.hooks?.beforePayout) {\n const mutated = await config.hooks.beforePayout(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n if (config.hooks?.afterPayout) {\n await config.hooks.afterPayout(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\n }\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 = { ...input, reference };\n if (config.hooks?.beforePayout) {\n const mutated = await config.hooks.beforePayout(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\n payload,\n });\n\n if (config.hooks?.afterPayout) {\n await config.hooks.afterPayout(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\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 throw new Error(\"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\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: input,\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throw new Error(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throw new Error(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throw new Error(\"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 and baseUrl returns the same\n * instance (singleton per key+url pair). Pass { force: true } to create a\n * fresh instance and replace the cached one.\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 { 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 + baseUrl combination unless\n * { force: true } is passed. Use your test keys for sandbox, production keys\n * 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 const instanceKey = `${config.apiKey}:${baseUrl}`;\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
@@ -214,6 +214,48 @@ type WebhookPayload = {
214
214
  timestamp: string;
215
215
  signature: string;
216
216
  };
217
+ /**
218
+ * Called before a collect or payout payload is sent to the server.
219
+ * Receives the full input (reference already set). Return a mutated copy to
220
+ * override the payload, or return void/undefined to leave it unchanged.
221
+ * Async hooks are awaited before the transport call proceeds.
222
+ */
223
+ type BeforeCollectHook = (input: CollectPaymentInput) => CollectPaymentInput | undefined | Promise<CollectPaymentInput | undefined>;
224
+ /**
225
+ * Called after every collect call (both fire-and-forget and resolve variants)
226
+ * regardless of outcome. Use for logging, analytics, or side-effects.
227
+ * The result is normalized to `{ reference, status }` across both variants.
228
+ * Return value is ignored.
229
+ */
230
+ type AfterCollectHook = (result: Result<{
231
+ reference: string;
232
+ status: string;
233
+ }, string>, input: CollectPaymentInput) => void | Promise<void>;
234
+ /**
235
+ * Called before a payout payload is sent to the server.
236
+ * Same semantics as {@link BeforeCollectHook}.
237
+ */
238
+ type BeforePayoutHook = (input: MakePayoutInput) => MakePayoutInput | undefined | Promise<MakePayoutInput | undefined>;
239
+ /**
240
+ * Called after every payout call (both fire-and-forget and resolve variants)
241
+ * regardless of outcome.
242
+ * Same semantics as {@link AfterCollectHook}.
243
+ */
244
+ type AfterPayoutHook = (result: Result<{
245
+ reference: string;
246
+ status: string;
247
+ }, string>, input: MakePayoutInput) => void | Promise<void>;
248
+ /**
249
+ * Lifecycle hooks registered once at SDK creation. Each hook fires on every
250
+ * matching operation — use them for cross-cutting concerns like logging,
251
+ * audit trails, and payload enrichment.
252
+ */
253
+ type SdkHooks = {
254
+ beforeCollect?: BeforeCollectHook;
255
+ afterCollect?: AfterCollectHook;
256
+ beforePayout?: BeforePayoutHook;
257
+ afterPayout?: AfterPayoutHook;
258
+ };
217
259
  /**
218
260
  * SDK configuration supplied by the merchant at initialization.
219
261
  * All timeouts and retry limits are configurable for different
@@ -232,6 +274,10 @@ type NylonPayConfig = {
232
274
  maxPollDurationMs?: number;
233
275
  maxPollAttempts?: number;
234
276
  fetch?: typeof globalThis.fetch;
277
+ /** Force a new instance even if one already exists for this key+url pair. */
278
+ force?: boolean;
279
+ /** Lifecycle hooks for cross-cutting concerns (logging, enrichment, etc.). */
280
+ hooks?: SdkHooks;
235
281
  };
236
282
  /**
237
283
  * Structured error returned by SDK operations. `code` is machine-readable
@@ -509,13 +555,17 @@ interface PaymentInstance {
509
555
  * Factory function to create a Nylon Pay SDK instance.
510
556
  * This is the main entry point for merchants.
511
557
  *
558
+ * Calling createNylonPay with the same apiKey and baseUrl returns the same
559
+ * instance (singleton per key+url pair). Pass { force: true } to create a
560
+ * fresh instance and replace the cached one.
561
+ *
512
562
  * @example
513
563
  * ```ts
514
564
  * import { createNylonPay } from "@nile-squad/nylonpay-ts";
515
565
  *
516
566
  * export const nylonpay = createNylonPay({
517
- * apiKey: process.env.NYLONPAY_API_KEY!,
518
- * apiSecret: process.env.NYLONPAY_API_SECRET!,
567
+ * apiKey: "npk_...",
568
+ * apiSecret: "nps_...",
519
569
  * });
520
570
  * ```
521
571
  */
@@ -523,6 +573,10 @@ interface PaymentInstance {
523
573
  /**
524
574
  * Create a Nylon Pay SDK instance.
525
575
  *
576
+ * Returns the same instance for the same apiKey + baseUrl combination unless
577
+ * { force: true } is passed. Use your test keys for sandbox, production keys
578
+ * for live.
579
+ *
526
580
  * @param config - SDK configuration with apiKey and apiSecret
527
581
  * @returns SDK instance with all payment operations
528
582
  *
@@ -570,4 +624,4 @@ declare function parseError(error: string): SdkError;
570
624
  */
571
625
  declare function verifyWebhookSignature(input: VerifyWebhookInput): boolean;
572
626
 
573
- export { type BankDetails, type CollectPaymentInput, type CreateInvoiceInput, type Currency, type Customer, type Destination, type EventData, type GetStatusInput, type GetTransactionInput, type InvoiceItem, type InvoiceResponse, type MakePayoutInput, type NylonPayConfig, type NylonPaySdk, type PaymentEvent, type PaymentEventHandler, type PaymentInstance, type PaymentMethod, type PhoneVerification, type SdkError, type StatusResponse, type Transaction, type TransactionMode, type TransactionStatus, type TransactionType, type VerifyPhoneInput, type VerifyWebhookInput, type WebhookEventType, type WebhookPayload, createNylonPay, parseError, verifyWebhookSignature };
627
+ export { type AfterCollectHook, type AfterPayoutHook, type BankDetails, type BeforeCollectHook, type BeforePayoutHook, type CollectPaymentInput, type CreateInvoiceInput, type Currency, type Customer, type Destination, type EventData, type GetStatusInput, type GetTransactionInput, type InvoiceItem, type InvoiceResponse, type MakePayoutInput, type NylonPayConfig, type NylonPaySdk, type PaymentEvent, type PaymentEventHandler, type PaymentInstance, type PaymentMethod, type PhoneVerification, type SdkError, type SdkHooks, type StatusResponse, type Transaction, type TransactionMode, type TransactionStatus, type TransactionType, type VerifyPhoneInput, type VerifyWebhookInput, type WebhookEventType, type WebhookPayload, createNylonPay, parseError, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -214,6 +214,48 @@ type WebhookPayload = {
214
214
  timestamp: string;
215
215
  signature: string;
216
216
  };
217
+ /**
218
+ * Called before a collect or payout payload is sent to the server.
219
+ * Receives the full input (reference already set). Return a mutated copy to
220
+ * override the payload, or return void/undefined to leave it unchanged.
221
+ * Async hooks are awaited before the transport call proceeds.
222
+ */
223
+ type BeforeCollectHook = (input: CollectPaymentInput) => CollectPaymentInput | undefined | Promise<CollectPaymentInput | undefined>;
224
+ /**
225
+ * Called after every collect call (both fire-and-forget and resolve variants)
226
+ * regardless of outcome. Use for logging, analytics, or side-effects.
227
+ * The result is normalized to `{ reference, status }` across both variants.
228
+ * Return value is ignored.
229
+ */
230
+ type AfterCollectHook = (result: Result<{
231
+ reference: string;
232
+ status: string;
233
+ }, string>, input: CollectPaymentInput) => void | Promise<void>;
234
+ /**
235
+ * Called before a payout payload is sent to the server.
236
+ * Same semantics as {@link BeforeCollectHook}.
237
+ */
238
+ type BeforePayoutHook = (input: MakePayoutInput) => MakePayoutInput | undefined | Promise<MakePayoutInput | undefined>;
239
+ /**
240
+ * Called after every payout call (both fire-and-forget and resolve variants)
241
+ * regardless of outcome.
242
+ * Same semantics as {@link AfterCollectHook}.
243
+ */
244
+ type AfterPayoutHook = (result: Result<{
245
+ reference: string;
246
+ status: string;
247
+ }, string>, input: MakePayoutInput) => void | Promise<void>;
248
+ /**
249
+ * Lifecycle hooks registered once at SDK creation. Each hook fires on every
250
+ * matching operation — use them for cross-cutting concerns like logging,
251
+ * audit trails, and payload enrichment.
252
+ */
253
+ type SdkHooks = {
254
+ beforeCollect?: BeforeCollectHook;
255
+ afterCollect?: AfterCollectHook;
256
+ beforePayout?: BeforePayoutHook;
257
+ afterPayout?: AfterPayoutHook;
258
+ };
217
259
  /**
218
260
  * SDK configuration supplied by the merchant at initialization.
219
261
  * All timeouts and retry limits are configurable for different
@@ -232,6 +274,10 @@ type NylonPayConfig = {
232
274
  maxPollDurationMs?: number;
233
275
  maxPollAttempts?: number;
234
276
  fetch?: typeof globalThis.fetch;
277
+ /** Force a new instance even if one already exists for this key+url pair. */
278
+ force?: boolean;
279
+ /** Lifecycle hooks for cross-cutting concerns (logging, enrichment, etc.). */
280
+ hooks?: SdkHooks;
235
281
  };
236
282
  /**
237
283
  * Structured error returned by SDK operations. `code` is machine-readable
@@ -509,13 +555,17 @@ interface PaymentInstance {
509
555
  * Factory function to create a Nylon Pay SDK instance.
510
556
  * This is the main entry point for merchants.
511
557
  *
558
+ * Calling createNylonPay with the same apiKey and baseUrl returns the same
559
+ * instance (singleton per key+url pair). Pass { force: true } to create a
560
+ * fresh instance and replace the cached one.
561
+ *
512
562
  * @example
513
563
  * ```ts
514
564
  * import { createNylonPay } from "@nile-squad/nylonpay-ts";
515
565
  *
516
566
  * export const nylonpay = createNylonPay({
517
- * apiKey: process.env.NYLONPAY_API_KEY!,
518
- * apiSecret: process.env.NYLONPAY_API_SECRET!,
567
+ * apiKey: "npk_...",
568
+ * apiSecret: "nps_...",
519
569
  * });
520
570
  * ```
521
571
  */
@@ -523,6 +573,10 @@ interface PaymentInstance {
523
573
  /**
524
574
  * Create a Nylon Pay SDK instance.
525
575
  *
576
+ * Returns the same instance for the same apiKey + baseUrl combination unless
577
+ * { force: true } is passed. Use your test keys for sandbox, production keys
578
+ * for live.
579
+ *
526
580
  * @param config - SDK configuration with apiKey and apiSecret
527
581
  * @returns SDK instance with all payment operations
528
582
  *
@@ -570,4 +624,4 @@ declare function parseError(error: string): SdkError;
570
624
  */
571
625
  declare function verifyWebhookSignature(input: VerifyWebhookInput): boolean;
572
626
 
573
- export { type BankDetails, type CollectPaymentInput, type CreateInvoiceInput, type Currency, type Customer, type Destination, type EventData, type GetStatusInput, type GetTransactionInput, type InvoiceItem, type InvoiceResponse, type MakePayoutInput, type NylonPayConfig, type NylonPaySdk, type PaymentEvent, type PaymentEventHandler, type PaymentInstance, type PaymentMethod, type PhoneVerification, type SdkError, type StatusResponse, type Transaction, type TransactionMode, type TransactionStatus, type TransactionType, type VerifyPhoneInput, type VerifyWebhookInput, type WebhookEventType, type WebhookPayload, createNylonPay, parseError, verifyWebhookSignature };
627
+ export { type AfterCollectHook, type AfterPayoutHook, type BankDetails, type BeforeCollectHook, type BeforePayoutHook, type CollectPaymentInput, type CreateInvoiceInput, type Currency, type Customer, type Destination, type EventData, type GetStatusInput, type GetTransactionInput, type InvoiceItem, type InvoiceResponse, type MakePayoutInput, type NylonPayConfig, type NylonPaySdk, type PaymentEvent, type PaymentEventHandler, type PaymentInstance, type PaymentMethod, type PhoneVerification, type SdkError, type SdkHooks, type StatusResponse, type Transaction, type TransactionMode, type TransactionStatus, type TransactionType, type VerifyPhoneInput, type VerifyWebhookInput, type WebhookEventType, type WebhookPayload, createNylonPay, parseError, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -571,11 +571,25 @@ function createSdkInstance(config) {
571
571
  if (input.method === "bank" && !input.bank) {
572
572
  throw new Error('bank details are required when method is "bank"');
573
573
  }
574
- const payload = { ...input, reference };
574
+ let payload = { ...input, reference };
575
+ if (config.hooks?.beforeCollect) {
576
+ const mutated = await config.hooks.beforeCollect(payload);
577
+ if (mutated != null)
578
+ payload = { ...mutated, reference: mutated.reference ?? reference };
579
+ }
575
580
  const result = await transport.send({
576
581
  action: SDK_ACTIONS.collectPayment,
577
582
  payload
578
583
  });
584
+ if (config.hooks?.afterCollect) {
585
+ await config.hooks.afterCollect(
586
+ result.isOk ? Ok({
587
+ reference: result.value.reference,
588
+ status: result.value.status
589
+ }) : Err(result.error),
590
+ payload
591
+ );
592
+ }
579
593
  if (result.isOk) {
580
594
  return createPaymentInstance(result.value, commonDeps);
581
595
  }
@@ -599,11 +613,25 @@ function createSdkInstance(config) {
599
613
  if (input.method === "bank" && !input.bank) {
600
614
  throw new Error('bank details are required when method is "bank"');
601
615
  }
602
- const payload = { ...input, reference };
616
+ let payload = { ...input, reference };
617
+ if (config.hooks?.beforeCollect) {
618
+ const mutated = await config.hooks.beforeCollect(payload);
619
+ if (mutated != null)
620
+ payload = { ...mutated, reference: mutated.reference ?? reference };
621
+ }
603
622
  const result = await transport.send({
604
623
  action: SDK_ACTIONS.collectPaymentAndResolve,
605
624
  payload
606
625
  });
626
+ if (config.hooks?.afterCollect) {
627
+ await config.hooks.afterCollect(
628
+ result.isOk ? Ok({
629
+ reference: result.value.reference,
630
+ status: result.value.status
631
+ }) : Err(result.error),
632
+ payload
633
+ );
634
+ }
607
635
  if (result.isOk) {
608
636
  return Ok(result.value);
609
637
  }
@@ -623,11 +651,25 @@ function createSdkInstance(config) {
623
651
  input.destination.accountNumber,
624
652
  "destination.accountNumber"
625
653
  );
626
- const payload = { ...input, reference };
654
+ let payload = { ...input, reference };
655
+ if (config.hooks?.beforePayout) {
656
+ const mutated = await config.hooks.beforePayout(payload);
657
+ if (mutated != null)
658
+ payload = { ...mutated, reference: mutated.reference ?? reference };
659
+ }
627
660
  const result = await transport.send({
628
661
  action: SDK_ACTIONS.makePayout,
629
662
  payload
630
663
  });
664
+ if (config.hooks?.afterPayout) {
665
+ await config.hooks.afterPayout(
666
+ result.isOk ? Ok({
667
+ reference: result.value.reference,
668
+ status: result.value.status
669
+ }) : Err(result.error),
670
+ payload
671
+ );
672
+ }
631
673
  if (result.isOk) {
632
674
  return createPaymentInstance(result.value, commonDeps);
633
675
  }
@@ -656,11 +698,25 @@ function createSdkInstance(config) {
656
698
  input.destination.accountNumber,
657
699
  "destination.accountNumber"
658
700
  );
659
- const payload = { ...input, reference };
701
+ let payload = { ...input, reference };
702
+ if (config.hooks?.beforePayout) {
703
+ const mutated = await config.hooks.beforePayout(payload);
704
+ if (mutated != null)
705
+ payload = { ...mutated, reference: mutated.reference ?? reference };
706
+ }
660
707
  const result = await transport.send({
661
708
  action: SDK_ACTIONS.makePayoutAndResolve,
662
709
  payload
663
710
  });
711
+ if (config.hooks?.afterPayout) {
712
+ await config.hooks.afterPayout(
713
+ result.isOk ? Ok({
714
+ reference: result.value.reference,
715
+ status: result.value.status
716
+ }) : Err(result.error),
717
+ payload
718
+ );
719
+ }
664
720
  if (result.isOk) {
665
721
  return Ok(result.value);
666
722
  }
@@ -745,6 +801,7 @@ function createSdkInstance(config) {
745
801
  }
746
802
 
747
803
  // src/create-nylon-pay.ts
804
+ var instances = /* @__PURE__ */ new Map();
748
805
  function createNylonPay(config) {
749
806
  if (!config.apiKey) {
750
807
  throw new Error("apiKey is required");
@@ -758,18 +815,27 @@ function createNylonPay(config) {
758
815
  if (!config.apiSecret.startsWith("nps_")) {
759
816
  throw new Error('apiSecret must start with "nps_"');
760
817
  }
818
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
819
+ const instanceKey = `${config.apiKey}:${baseUrl}`;
820
+ if (!config.force) {
821
+ const existing = instances.get(instanceKey);
822
+ if (existing) return existing;
823
+ }
761
824
  const resolvedConfig = {
762
825
  apiKey: config.apiKey,
763
826
  apiSecret: config.apiSecret,
764
- baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
827
+ baseUrl,
765
828
  timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
766
829
  maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
767
830
  maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,
768
831
  maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,
769
832
  maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,
770
- fetch: config.fetch ?? globalThis.fetch.bind(globalThis)
833
+ fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
834
+ hooks: config.hooks
771
835
  };
772
- return createSdkInstance(resolvedConfig);
836
+ const instance = createSdkInstance(resolvedConfig);
837
+ instances.set(instanceKey, instance);
838
+ return instance;
773
839
  }
774
840
 
775
841
  export { createNylonPay, parseError, verifyWebhookSignature };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pubsub.ts","../src/fingerprint.ts","../src/nonce.ts","../src/sdk.config.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.ts","../src/verify-webhook.ts","../src/sdk.ts","../src/create-nylon-pay.ts"],"names":["createHmac","timingSafeEqual","randomBytes","Err","Ok"],"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","/**\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","/** 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/** 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 * 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 alphabetically for deterministic JSON.\n * Must match backend's createCanonicalPayload function.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\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]) => firstKey.localeCompare(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.\n * Keys are sorted alphabetically for deterministic serialization.\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, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\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 const sdkError: SdkError = {\n code: `HTTP_${statusCode}`,\n message: errorMessage,\n statusCode,\n retryable,\n };\n\n cleanup();\n return Err(JSON.stringify(sdkError));\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 code: \"INVALID_RESPONSE\",\n message: \"Response missing status field\",\n retryable: false,\n }),\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 if (responseSignature) {\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n code: \"RESPONSE_TAMPERED\",\n message: \"Response signature verification failed\",\n retryable: false,\n }),\n );\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 code: isAbort ? \"TIMEOUT\" : \"NETWORK_ERROR\",\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 an SdkError object.\n * Tries JSON.parse first; falls back to a generic UNKNOWN error.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-123\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.code, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"code\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).code === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not JSON, fall through\n }\n\n return { code: \"UNKNOWN\", message: error };\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 { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\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 | null;\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 * 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): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: 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 stopPolling();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(event: PaymentEvent, error?: string): void {\n const data: EventData = {\n event,\n transaction: state.transaction ?? undefined,\n error,\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 emitEvent(event);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\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 = 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 * \"Not found\" during early polling is expected; other errors stop polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const isNotFound =\n error.includes(\"not found\") || error.includes(\"NOT_FOUND\");\n if (isNotFound) {\n return;\n }\n emitEvent(\"error\", parseError(error).message);\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one finishes.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, state.pollIntervalMs);\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 stopPolling();\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 stopPolling();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start polling for status updates.\n * @internal\n */\n function startPolling(): void {\n scheduleNextPoll();\n }\n\n /**\n * Stop polling.\n * @internal\n */\n function stopPolling(): 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 on success, rejects on failure/cancel/error.\n */\n function wait(): Promise<Transaction> {\n return new Promise((resolve, reject) => {\n if (state.resolved) {\n if (state.status === \"successful\" && state.transaction) {\n resolve(state.transaction);\n } else {\n reject(new Error(`Payment ${state.status ?? \"error\"}`));\n }\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n if (state.transaction) {\n resolve(state.transaction);\n } else {\n reject(\n new Error(\"Payment successful but transaction data unavailable\"),\n );\n }\n }\n\n function onFailed(): void {\n cleanup();\n reject(new Error(\"Payment failed\"));\n }\n\n function onCancelled(): void {\n cleanup();\n reject(new Error(\"Payment cancelled\"));\n }\n\n function onError(data: unknown): void {\n cleanup();\n const eventData = data as EventData;\n reject(new Error(eventData.error ?? \"Payment error\"));\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 startPolling();\n\n return paymentInstance;\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/**\n * Verify that a webhook payload was signed by Nylon Pay.\n * Operates on raw payload bytes, NOT parsed JSON (spec invariant #8).\n *\n * @param input.payload - Raw request body as string or Uint8Array\n * @param input.signature - Signature from the webhook header\n * @param input.secret - Merchant's webhook secret\n * @returns True when the signature is valid\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadBytes =\n typeof input.payload === \"string\"\n ? Buffer.from(input.payload, \"utf8\")\n : Buffer.from(input.payload);\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 return timingSafeEqual(providedBuffer, expectedBuffer);\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 } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createTransport } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\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};\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/** Validate that amount is a positive integer. */\nfunction validateAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throw new Error(\"amount must be a positive integer\");\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 throw new Error(`${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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n const payload = { ...input, reference };\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 const payload = { ...input, reference };\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 const payload = { ...input, reference };\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\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 throw new Error(\"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\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: input,\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throw new Error(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throw new Error(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throw new Error(\"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 * @example\n * ```ts\n * import { createNylonPay } from \"@nile-squad/nylonpay-ts\";\n *\n * export const nylonpay = createNylonPay({\n * apiKey: process.env.NYLONPAY_API_KEY!,\n * apiSecret: process.env.NYLONPAY_API_SECRET!,\n * });\n * ```\n */\n\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\n/**\n * Create a Nylon Pay SDK instance.\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 resolvedConfig = {\n apiKey: config.apiKey,\n apiSecret: config.apiSecret,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\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 };\n\n return createSdkInstance(resolvedConfig);\n}\n"]}
1
+ {"version":3,"sources":["../src/pubsub.ts","../src/fingerprint.ts","../src/nonce.ts","../src/sdk.config.ts","../src/signature.ts","../src/verify-response.ts","../src/transport.ts","../src/payment.ts","../src/verify-webhook.ts","../src/sdk.ts","../src/create-nylon-pay.ts"],"names":["createHmac","timingSafeEqual","randomBytes","Ok","Err"],"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","/**\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","/** 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/** 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 * 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 alphabetically for deterministic JSON.\n * Must match backend's createCanonicalPayload function.\n *\n * @see backend/src/services/sdk/create-canonical-payload.ts\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]) => firstKey.localeCompare(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.\n * Keys are sorted alphabetically for deterministic serialization.\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, TransportRequest } from \"./types\";\nimport { verifyResponseSignature } from \"./verify-response\";\n\n/** Cached fingerprint for this server instance. */\nconst CACHED_FINGERPRINT = generateFingerprint();\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 const sdkError: SdkError = {\n code: `HTTP_${statusCode}`,\n message: errorMessage,\n statusCode,\n retryable,\n };\n\n cleanup();\n return Err(JSON.stringify(sdkError));\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 code: \"INVALID_RESPONSE\",\n message: \"Response missing status field\",\n retryable: false,\n }),\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 if (responseSignature) {\n const isValid = verifyResponseSignature(\n strippedData,\n responseSignature,\n apiSecret,\n );\n if (!isValid) {\n cleanup();\n return Err(\n JSON.stringify({\n code: \"RESPONSE_TAMPERED\",\n message: \"Response signature verification failed\",\n retryable: false,\n }),\n );\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 code: isAbort ? \"TIMEOUT\" : \"NETWORK_ERROR\",\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 an SdkError object.\n * Tries JSON.parse first; falls back to a generic UNKNOWN error.\n *\n * @example\n * ```ts\n * const result = await sdk.getStatus({ reference: \"ORDER-123\" });\n * if (!result.isOk) {\n * const error = parseError(result.error);\n * console.log(error.code, error.message);\n * }\n * ```\n */\nexport function parseError(error: string): SdkError {\n try {\n const parsed = JSON.parse(error) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"code\" in parsed &&\n \"message\" in parsed &&\n typeof (parsed as Record<string, unknown>).code === \"string\" &&\n typeof (parsed as Record<string, unknown>).message === \"string\"\n ) {\n return parsed as SdkError;\n }\n } catch {\n // Not JSON, fall through\n }\n\n return { code: \"UNKNOWN\", message: error };\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 { parseError } from \"./transport\";\nimport type {\n EventData,\n GetStatusInput,\n GetTransactionInput,\n PaymentEvent,\n PaymentEventHandler,\n PaymentInstance,\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 | null;\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 * 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): PaymentInstance {\n const state: PaymentState = {\n reference: initialResponse.reference,\n status: 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 stopPolling();\n emitEvent(\"error\", parseError(error).message);\n }\n\n /**\n * Emit an event with current transaction data.\n * @internal\n */\n function emitEvent(event: PaymentEvent, error?: string): void {\n const data: EventData = {\n event,\n transaction: state.transaction ?? undefined,\n error,\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 emitEvent(event);\n }\n } else {\n emitEvent(\"error\", `Failed to fetch transaction: ${txResult.error}`);\n }\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Handle a status response from polling.\n * @internal\n */\n async function handleStatusUpdate(response: StatusResponse): Promise<void> {\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 = 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 * \"Not found\" during early polling is expected; other errors stop polling.\n * @internal\n */\n function handlePollError(error: string): void {\n const isNotFound =\n error.includes(\"not found\") || error.includes(\"NOT_FOUND\");\n if (isNotFound) {\n return;\n }\n emitEvent(\"error\", parseError(error).message);\n state.resolved = true;\n stopPolling();\n }\n\n /**\n * Schedule the next poll tick.\n * Uses a single timeout so the next request only starts after the current one finishes.\n * @internal\n */\n function scheduleNextPoll(): void {\n if (state.resolved || state.pollingTimer) {\n return;\n }\n\n state.pollingTimer = setTimeout(() => {\n state.pollingTimer = null;\n void pollStatus();\n }, state.pollIntervalMs);\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 stopPolling();\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 stopPolling();\n return;\n }\n\n scheduleNextPoll();\n }\n\n /**\n * Start polling for status updates.\n * @internal\n */\n function startPolling(): void {\n scheduleNextPoll();\n }\n\n /**\n * Stop polling.\n * @internal\n */\n function stopPolling(): 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 on success, rejects on failure/cancel/error.\n */\n function wait(): Promise<Transaction> {\n return new Promise((resolve, reject) => {\n if (state.resolved) {\n if (state.status === \"successful\" && state.transaction) {\n resolve(state.transaction);\n } else {\n reject(new Error(`Payment ${state.status ?? \"error\"}`));\n }\n return;\n }\n\n function onSuccess(): void {\n cleanup();\n if (state.transaction) {\n resolve(state.transaction);\n } else {\n reject(\n new Error(\"Payment successful but transaction data unavailable\"),\n );\n }\n }\n\n function onFailed(): void {\n cleanup();\n reject(new Error(\"Payment failed\"));\n }\n\n function onCancelled(): void {\n cleanup();\n reject(new Error(\"Payment cancelled\"));\n }\n\n function onError(data: unknown): void {\n cleanup();\n const eventData = data as EventData;\n reject(new Error(eventData.error ?? \"Payment error\"));\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 startPolling();\n\n return paymentInstance;\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/**\n * Verify that a webhook payload was signed by Nylon Pay.\n * Operates on raw payload bytes, NOT parsed JSON (spec invariant #8).\n *\n * @param input.payload - Raw request body as string or Uint8Array\n * @param input.signature - Signature from the webhook header\n * @param input.secret - Merchant's webhook secret\n * @returns True when the signature is valid\n */\nexport function verifyWebhookSignature(input: VerifyWebhookInput): boolean {\n const payloadBytes =\n typeof input.payload === \"string\"\n ? Buffer.from(input.payload, \"utf8\")\n : Buffer.from(input.payload);\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 return timingSafeEqual(providedBuffer, expectedBuffer);\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 } from \"slang-ts\";\nimport { createPaymentInstance } from \"./payment\";\nimport { SDK_ACTIONS } from \"./sdk.config\";\nimport { createTransport } from \"./transport\";\nimport type {\n CollectPaymentInput,\n CreateInvoiceInput,\n GetStatusInput,\n GetTransactionInput,\n InvoiceResponse,\n MakePayoutInput,\n NylonPaySdk,\n PaymentInstance,\n PhoneVerification,\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/** Validate that amount is a positive integer. */\nfunction validateAmount(amount: number): void {\n if (!Number.isInteger(amount) || amount <= 0) {\n throw new Error(\"amount must be a positive integer\");\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 throw new Error(`${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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n let payload = { ...input, reference };\n if (config.hooks?.beforeCollect) {\n const mutated = await config.hooks.beforeCollect(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.collectPayment,\n payload,\n });\n\n if (config.hooks?.afterCollect) {\n await config.hooks.afterCollect(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\n }\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"customer.phoneNumber\");\n validateNonEmpty(input.description, \"description\");\n if (input.method === \"bank\" && !input.bank) {\n throw new Error('bank details are required when method is \"bank\"');\n }\n\n let payload = { ...input, reference };\n if (config.hooks?.beforeCollect) {\n const mutated = await config.hooks.beforeCollect(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.collectPaymentAndResolve,\n payload,\n });\n\n if (config.hooks?.afterCollect) {\n await config.hooks.afterCollect(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 = { ...input, reference };\n if (config.hooks?.beforePayout) {\n const mutated = await config.hooks.beforePayout(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<{\n reference: string;\n status: TransactionStatus;\n }>({\n action: SDK_ACTIONS.makePayout,\n payload,\n });\n\n if (config.hooks?.afterPayout) {\n await config.hooks.afterPayout(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\n }\n\n if (result.isOk) {\n return createPaymentInstance(result.value, commonDeps);\n }\n\n return createPaymentInstance(\n { reference, status: \"pending\" },\n {\n ...commonDeps,\n fetchStatus: async () => Err(result.error),\n fetchTransaction: async () => Err(result.error),\n pollIntervalMs: 0,\n maxPollAttempts: 1,\n maxPollDuration: Number.MAX_SAFE_INTEGER,\n },\n );\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.customer.name, \"customer.name\");\n validateNonEmpty(input.customer.phoneNumber, \"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 = { ...input, reference };\n if (config.hooks?.beforePayout) {\n const mutated = await config.hooks.beforePayout(payload);\n if (mutated != null)\n payload = { ...mutated, reference: mutated.reference ?? reference };\n }\n\n const result = await transport.send<Transaction>({\n action: SDK_ACTIONS.makePayoutAndResolve,\n payload,\n });\n\n if (config.hooks?.afterPayout) {\n await config.hooks.afterPayout(\n result.isOk\n ? Ok({\n reference: result.value.reference,\n status: result.value.status,\n })\n : Err(result.error),\n payload,\n );\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 throw new Error(\"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\n const result = await transport.send<PhoneVerification>({\n action: SDK_ACTIONS.verifyPhone,\n payload: input,\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 = input.reference ?? generateReference();\n validateAmount(input.amount);\n validateNonEmpty(input.description, \"description\");\n\n if (input.items) {\n if (input.items.length > 50) {\n throw new Error(\"items must not exceed 50\");\n }\n for (const item of input.items) {\n if (!Number.isInteger(item.quantity) || item.quantity <= 0) {\n throw new Error(\"item quantity must be a positive integer\");\n }\n if (!Number.isInteger(item.unitPrice) || item.unitPrice <= 0) {\n throw new Error(\"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 and baseUrl returns the same\n * instance (singleton per key+url pair). Pass { force: true } to create a\n * fresh instance and replace the cached one.\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 { 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 + baseUrl combination unless\n * { force: true } is passed. Use your test keys for sandbox, production keys\n * 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 const instanceKey = `${config.apiKey}:${baseUrl}`;\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.1",
3
+ "version": "1.0.3",
4
4
  "description": "Nylon Pay SDK for merchant integrations",
5
5
  "keywords": [
6
6
  "nylonpay",
@@ -52,6 +52,7 @@
52
52
  "devDependencies": {
53
53
  "@biomejs/biome": "^2.2.0",
54
54
  "@types/node": "^22.0.0",
55
+ "dotenv": "^17.3.1",
55
56
  "tsup": "^8.4.0",
56
57
  "typescript": "^5.7.0",
57
58
  "vitest": "^3.2.4"
@@ -67,6 +68,7 @@
67
68
  "typecheck": "tsc --noEmit",
68
69
  "lint": "biome check .",
69
70
  "lint:fix": "biome check --write .",
71
+ "test:integration": "vitest run --config vitest.config.integration.ts",
70
72
  "export": "tsc --noEmit && biome check . && tsup"
71
73
  }
72
74
  }