@inodra/sui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +237 -0
  3. package/bin/inodra-sui.mjs +2 -0
  4. package/dist/chunk-3CBLVI6J.js +426 -0
  5. package/dist/chunk-3CBLVI6J.js.map +1 -0
  6. package/dist/chunk-4HKKW5QN.js +80 -0
  7. package/dist/chunk-4HKKW5QN.js.map +1 -0
  8. package/dist/chunk-74XGJJJI.js +33 -0
  9. package/dist/chunk-74XGJJJI.js.map +1 -0
  10. package/dist/chunk-D6FZYWG7.js +99 -0
  11. package/dist/chunk-D6FZYWG7.js.map +1 -0
  12. package/dist/chunk-LZZMTSLH.js +31 -0
  13. package/dist/chunk-LZZMTSLH.js.map +1 -0
  14. package/dist/chunk-M3M2L6BW.js +29 -0
  15. package/dist/chunk-M3M2L6BW.js.map +1 -0
  16. package/dist/chunk-NSXRC5XW.js +298 -0
  17. package/dist/chunk-NSXRC5XW.js.map +1 -0
  18. package/dist/chunk-OGMBYWTG.js +537 -0
  19. package/dist/chunk-OGMBYWTG.js.map +1 -0
  20. package/dist/chunk-U6D5LGNF.js +111 -0
  21. package/dist/chunk-U6D5LGNF.js.map +1 -0
  22. package/dist/chunk-ZSW3EWGF.js +539 -0
  23. package/dist/chunk-ZSW3EWGF.js.map +1 -0
  24. package/dist/cli.js +665 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/events.cjs +3273 -0
  27. package/dist/events.cjs.map +1 -0
  28. package/dist/events.d.cts +47 -0
  29. package/dist/events.d.ts +47 -0
  30. package/dist/events.js +2578 -0
  31. package/dist/events.js.map +1 -0
  32. package/dist/graphql.cjs +129 -0
  33. package/dist/graphql.cjs.map +1 -0
  34. package/dist/graphql.d.cts +36 -0
  35. package/dist/graphql.d.ts +36 -0
  36. package/dist/graphql.js +10 -0
  37. package/dist/graphql.js.map +1 -0
  38. package/dist/grpc-web.cjs +129 -0
  39. package/dist/grpc-web.cjs.map +1 -0
  40. package/dist/grpc-web.d.cts +31 -0
  41. package/dist/grpc-web.d.ts +31 -0
  42. package/dist/grpc-web.js +10 -0
  43. package/dist/grpc-web.js.map +1 -0
  44. package/dist/grpc.cjs +131 -0
  45. package/dist/grpc.cjs.map +1 -0
  46. package/dist/grpc.d.cts +34 -0
  47. package/dist/grpc.d.ts +34 -0
  48. package/dist/grpc.js +10 -0
  49. package/dist/grpc.js.map +1 -0
  50. package/dist/index-CGBN_EI5.d.ts +4800 -0
  51. package/dist/index-CVO2Kj8a.d.cts +4800 -0
  52. package/dist/index.cjs +4723 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.cts +504 -0
  55. package/dist/index.d.ts +504 -0
  56. package/dist/index.js +59 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/manage.cjs +376 -0
  59. package/dist/manage.cjs.map +1 -0
  60. package/dist/manage.d.cts +2 -0
  61. package/dist/manage.d.ts +2 -0
  62. package/dist/manage.js +8 -0
  63. package/dist/manage.js.map +1 -0
  64. package/dist/network-CEg2MJY3.d.cts +60 -0
  65. package/dist/network-CEg2MJY3.d.ts +60 -0
  66. package/dist/node.cjs +4759 -0
  67. package/dist/node.cjs.map +1 -0
  68. package/dist/node.d.cts +28 -0
  69. package/dist/node.d.ts +28 -0
  70. package/dist/node.js +73 -0
  71. package/dist/node.js.map +1 -0
  72. package/dist/reflection-Bx44-Fs1.d.ts +4639 -0
  73. package/dist/reflection-Cf7WFH6H.d.cts +4639 -0
  74. package/dist/reflection-FEGYA7DU.js +9 -0
  75. package/dist/reflection-FEGYA7DU.js.map +1 -0
  76. package/dist/runtime-OWKF3LZ7.js +37 -0
  77. package/dist/runtime-OWKF3LZ7.js.map +1 -0
  78. package/dist/warp.cjs +633 -0
  79. package/dist/warp.cjs.map +1 -0
  80. package/dist/warp.d.cts +195 -0
  81. package/dist/warp.d.ts +195 -0
  82. package/dist/warp.js +12 -0
  83. package/dist/warp.js.map +1 -0
  84. package/dist/webhooks.cjs +104 -0
  85. package/dist/webhooks.cjs.map +1 -0
  86. package/dist/webhooks.d.cts +35 -0
  87. package/dist/webhooks.d.ts +35 -0
  88. package/dist/webhooks.js +7 -0
  89. package/dist/webhooks.js.map +1 -0
  90. package/llms.txt +189 -0
  91. package/package.json +119 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/warp/index.ts","../src/warp/iterate.ts","../src/core/auth.ts","../src/core/version.ts","../src/core/network.ts","../src/warp/emitter.ts","../src/warp/sse-parser.ts","../src/warp/types.ts","../src/warp/sse.ts","../src/warp/ws.ts"],"sourcesContent":["export {\n\ttype IterateStreamOptions,\n\titerateStream,\n} from \"./iterate.js\";\nexport { WarpSseStream, type WarpSseStreamOptions } from \"./sse.js\";\nexport {\n\tWarpWebSocketStream,\n\ttype WarpWebSocketStreamOptions,\n} from \"./ws.js\";\nexport type {\n\tWarpConnectedInfo,\n\tWarpEvent,\n\tWarpStreamEvents,\n\tWarpStreamOptions,\n} from \"./types.js\";\n","import type { Emitter } from \"./emitter.js\";\nimport type { WarpEvent, WarpStreamEvents } from \"./types.js\";\n\ninterface WarpStreamLike extends Emitter<WarpStreamEvents> {\n\tclose(): void;\n}\n\nexport interface IterateStreamOptions {\n\t/**\n\t * Close the stream when iteration ends (loop break, return, or throw).\n\t * Defaults to true — an abandoned open stream keeps billing connection\n\t * time.\n\t */\n\tcloseOnReturn?: boolean;\n}\n\n/**\n * Consume a Warp stream as an async iterable of data events.\n *\n * Ends normally when the stream is closed by the client; throws when the\n * stream closes for any other reason (quota exceeded, reconnect budget\n * exhausted, terminal server error). Transient transport errors that the\n * stream retries internally do not interrupt iteration.\n *\n * ```ts\n * for await (const event of stream) {\n * console.log(event.type, event.data);\n * }\n * ```\n */\nexport async function* iterateStream(\n\tstream: WarpStreamLike,\n\toptions: IterateStreamOptions = {},\n): AsyncGenerator<WarpEvent, void, undefined> {\n\tconst queue: WarpEvent[] = [];\n\tlet notify: (() => void) | undefined;\n\tlet closed = false;\n\tlet failure: Error | undefined;\n\n\tconst unsubscribes = [\n\t\tstream.on(\"message\", (event) => {\n\t\t\tqueue.push(event);\n\t\t\tnotify?.();\n\t\t}),\n\t\tstream.on(\"close\", ({ reason }) => {\n\t\t\tclosed = true;\n\t\t\tif (reason !== \"client closed\") {\n\t\t\t\tfailure = new Error(`Warp stream closed: ${reason}`);\n\t\t\t}\n\t\t\tnotify?.();\n\t\t}),\n\t];\n\n\ttry {\n\t\tfor (;;) {\n\t\t\twhile (queue.length > 0) {\n\t\t\t\tyield queue.shift() as WarpEvent;\n\t\t\t}\n\t\t\tif (closed) {\n\t\t\t\tif (failure) {\n\t\t\t\t\tthrow failure;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tnotify = resolve;\n\t\t\t});\n\t\t\tnotify = undefined;\n\t\t}\n\t} finally {\n\t\tfor (const unsubscribe of unsubscribes) {\n\t\t\tunsubscribe();\n\t\t}\n\t\tif (options.closeOnReturn ?? true) {\n\t\t\tstream.close();\n\t\t}\n\t}\n}\n","/**\n * Pluggable authentication for every Inodra transport.\n *\n * Most users pass an API key. The provider shape exists so future credential\n * types (x402 wallet session tokens, refreshing vault-issued keys) slot in\n * without changing any client constructor.\n */\n\nexport interface AuthCredentials {\n\t/** Sent as HTTP headers (REST, SSE, GraphQL) and gRPC metadata. */\n\theaders: Record<string, string>;\n\t/**\n\t * Sent as URL query parameters on transports that cannot carry headers\n\t * (WebSocket upgrades in browsers). Omit to disallow such transports.\n\t */\n\tqueryParams?: Record<string, string>;\n}\n\nexport type InodraAuth =\n\t| string\n\t| { apiKey: string }\n\t| { sessionToken: string }\n\t| {\n\t\t\tgetCredentials: () => AuthCredentials | Promise<AuthCredentials>;\n\t };\n\n/** Normalized auth handle used internally by every transport. */\nexport interface ResolvedAuth {\n\t/** Resolve credentials. Called per request on REST/SSE, per connect on WS. */\n\tcredentials(): Promise<AuthCredentials>;\n\t/**\n\t * Resolve credentials synchronously, or undefined for dynamic providers.\n\t * Used by clients whose underlying transport takes static headers\n\t * (gRPC, GraphQL).\n\t */\n\tstaticCredentials(): AuthCredentials | undefined;\n}\n\nexport function resolveAuth(auth: InodraAuth): ResolvedAuth {\n\tif (typeof auth === \"string\") {\n\t\treturn staticAuth(apiKeyCredentials(auth));\n\t}\n\tif (\"apiKey\" in auth) {\n\t\treturn staticAuth(apiKeyCredentials(auth.apiKey));\n\t}\n\tif (\"sessionToken\" in auth) {\n\t\treturn staticAuth({\n\t\t\theaders: { authorization: `Bearer ${auth.sessionToken}` },\n\t\t});\n\t}\n\treturn {\n\t\tcredentials: async () => auth.getCredentials(),\n\t\tstaticCredentials: () => undefined,\n\t};\n}\n\n/**\n * Resolve auth from an options bag that accepts both the modern `auth` field\n * and the original `apiKey` shorthand.\n */\nexport function authFromOptions(\n\toptions: { auth?: InodraAuth; apiKey?: string },\n\tcontext: string,\n): ResolvedAuth {\n\tif (options.auth !== undefined) {\n\t\treturn resolveAuth(options.auth);\n\t}\n\tif (options.apiKey) {\n\t\treturn resolveAuth(options.apiKey);\n\t}\n\tthrow new Error(`${context} requires auth (or the apiKey shorthand)`);\n}\n\n/**\n * Headers for clients whose transports take static headers (gRPC, GraphQL).\n * Dynamic providers are rejected: the underlying Mysten clients cannot\n * re-resolve credentials per call, so a snapshot would silently go stale.\n */\nexport function staticAuthHeaders(\n\toptions: { auth?: InodraAuth; apiKey?: string },\n\tcontext: string,\n): Record<string, string> {\n\tconst credentials = authFromOptions(options, context).staticCredentials();\n\tif (!credentials) {\n\t\tthrow new Error(\n\t\t\t`${context} does not support dynamic credential providers — pass an apiKey or sessionToken`,\n\t\t);\n\t}\n\treturn credentials.headers;\n}\n\nfunction apiKeyCredentials(apiKey: string): AuthCredentials {\n\tif (!apiKey) {\n\t\tthrow new Error(\"Inodra auth: apiKey must be a non-empty string\");\n\t}\n\treturn {\n\t\theaders: { \"x-api-key\": apiKey },\n\t\tqueryParams: { api_key: apiKey },\n\t};\n}\n\nfunction staticAuth(credentials: AuthCredentials): ResolvedAuth {\n\treturn {\n\t\tcredentials: async () => credentials,\n\t\tstaticCredentials: () => credentials,\n\t};\n}\n","export const SDK_VERSION = \"0.1.0\";\n\n/**\n * Identifies the SDK to Inodra on every request, alongside the API key.\n * Sent on REST, GraphQL, SSE (headers) and gRPC (metadata). Browsers cannot\n * attach headers to WebSocket upgrades, so the Warp WS client omits it.\n */\nexport const SDK_HEADER_NAME = \"x-inodra-sdk\";\nexport const SDK_HEADER_VALUE = `inodra-sdk-ts/${SDK_VERSION}`;\n","export type InodraNetwork = \"mainnet\" | \"testnet\";\n\n/**\n * Canonical Inodra endpoints per network and protocol.\n */\nexport const INODRA_ENDPOINTS = {\n\tmainnet: {\n\t\trest: \"https://mainnet-api.inodra.com/v1\",\n\t\tgraphql: \"https://mainnet-api.inodra.com/v1/graphql\",\n\t\t/** host:port for native gRPC transports */\n\t\tgrpc: \"mainnet-grpc.inodra.com:443\",\n\t\t/** base URL for gRPC-Web transports */\n\t\tgrpcWeb: \"https://mainnet-grpc.inodra.com\",\n\t\twarpWs: \"wss://mainnet-api.inodra.com/v1\",\n\t},\n\ttestnet: {\n\t\trest: \"https://testnet-api.inodra.com/v1\",\n\t\tgraphql: \"https://testnet-api.inodra.com/v1/graphql\",\n\t\tgrpc: \"testnet-grpc.inodra.com:443\",\n\t\tgrpcWeb: \"https://testnet-grpc.inodra.com\",\n\t\twarpWs: \"wss://testnet-api.inodra.com/v1\",\n\t},\n} as const satisfies Record<\n\tInodraNetwork,\n\t{ rest: string; graphql: string; grpc: string; grpcWeb: string; warpWs: string }\n>;\n\nexport function restBaseUrl(network: InodraNetwork): string {\n\treturn INODRA_ENDPOINTS[network].rest;\n}\n\nexport function graphqlUrl(network: InodraNetwork): string {\n\treturn INODRA_ENDPOINTS[network].graphql;\n}\n\n/** Base URL for gRPC-Web / Connect transports. */\nexport function grpcBaseUrl(network: InodraNetwork): string {\n\treturn INODRA_ENDPOINTS[network].grpcWeb;\n}\n\n/** host:port for native gRPC transports. */\nexport function grpcHost(network: InodraNetwork): string {\n\treturn INODRA_ENDPOINTS[network].grpc;\n}\n\nexport function warpStreamUrl(\n\tnetwork: InodraNetwork,\n\tsubscriptionId: string,\n): string {\n\treturn `${INODRA_ENDPOINTS[network].rest}/warp/${subscriptionId}/stream`;\n}\n\nexport function warpWebSocketUrl(\n\tnetwork: InodraNetwork,\n\tsubscriptionId: string,\n): string {\n\treturn `${INODRA_ENDPOINTS[network].warpWs}/warp/${subscriptionId}/ws`;\n}\n","/** Minimal typed event emitter that works in every runtime (no node:events). */\nexport class Emitter<Events extends Record<string, unknown>> {\n\tprivate readonly handlers = new Map<keyof Events, Set<(payload: never) => void>>();\n\n\ton<K extends keyof Events>(\n\t\tevent: K,\n\t\thandler: (payload: Events[K]) => void,\n\t): () => void {\n\t\tlet set = this.handlers.get(event);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\tthis.handlers.set(event, set);\n\t\t}\n\t\tset.add(handler as (payload: never) => void);\n\t\treturn () => set?.delete(handler as (payload: never) => void);\n\t}\n\n\toff<K extends keyof Events>(\n\t\tevent: K,\n\t\thandler: (payload: Events[K]) => void,\n\t): void {\n\t\tthis.handlers.get(event)?.delete(handler as (payload: never) => void);\n\t}\n\n\t/** Returns false if any handler threw. */\n\temit<K extends keyof Events>(event: K, payload: Events[K]): boolean {\n\t\tlet ok = true;\n\t\tfor (const handler of this.handlers.get(event) ?? []) {\n\t\t\ttry {\n\t\t\t\t(handler as (payload: Events[K]) => void)(payload);\n\t\t\t} catch {\n\t\t\t\tok = false;\n\t\t\t}\n\t\t}\n\t\treturn ok;\n\t}\n}\n","export interface SseMessage {\n\t/** SSE event name; defaults to \"message\" per the SSE spec. */\n\tevent: string;\n\tid?: string;\n\tdata: string;\n\tretryMs?: number;\n}\n\n/**\n * Incremental parser for a text/event-stream byte stream.\n * Feed it decoded chunks in any split; it yields complete messages.\n */\nexport class SseParser {\n\tprivate buffer = \"\";\n\tprivate eventName = \"\";\n\tprivate dataLines: string[] = [];\n\tprivate id: string | undefined;\n\tprivate retryMs: number | undefined;\n\n\tfeed(chunk: string): SseMessage[] {\n\t\tthis.buffer += chunk;\n\t\tconst messages: SseMessage[] = [];\n\n\t\tfor (;;) {\n\t\t\tconst newline = this.buffer.search(/\\r\\n|\\r|\\n/);\n\t\t\tif (newline === -1) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst line = this.buffer.slice(0, newline);\n\t\t\tconst sep = this.buffer.slice(newline, newline + 2);\n\t\t\tthis.buffer = this.buffer.slice(newline + (sep === \"\\r\\n\" ? 2 : 1));\n\n\t\t\tif (line === \"\") {\n\t\t\t\tconst message = this.flush();\n\t\t\t\tif (message) {\n\t\t\t\t\tmessages.push(message);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.parseLine(line);\n\t\t}\n\n\t\treturn messages;\n\t}\n\n\tprivate parseLine(line: string): void {\n\t\tif (line.startsWith(\":\")) {\n\t\t\treturn; // comment / keep-alive\n\t\t}\n\t\tconst colon = line.indexOf(\":\");\n\t\tconst field = colon === -1 ? line : line.slice(0, colon);\n\t\tlet value = colon === -1 ? \"\" : line.slice(colon + 1);\n\t\tif (value.startsWith(\" \")) {\n\t\t\tvalue = value.slice(1);\n\t\t}\n\n\t\tswitch (field) {\n\t\t\tcase \"event\":\n\t\t\t\tthis.eventName = value;\n\t\t\t\tbreak;\n\t\t\tcase \"data\":\n\t\t\t\tthis.dataLines.push(value);\n\t\t\t\tbreak;\n\t\t\tcase \"id\":\n\t\t\t\t// Per spec, ids containing NUL are ignored\n\t\t\t\tif (!value.includes(\"\\0\")) {\n\t\t\t\t\tthis.id = value;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"retry\": {\n\t\t\t\tconst ms = Number(value);\n\t\t\t\tif (Number.isInteger(ms) && ms >= 0) {\n\t\t\t\t\tthis.retryMs = ms;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tbreak; // unknown fields are ignored per spec\n\t\t}\n\t}\n\n\tprivate flush(): SseMessage | undefined {\n\t\tif (this.dataLines.length === 0 && this.eventName === \"\") {\n\t\t\t// Nothing dispatched, but retry/id still apply\n\t\t\tconst retryOnly = this.retryMs;\n\t\t\tthis.retryMs = undefined;\n\t\t\treturn retryOnly === undefined\n\t\t\t\t? undefined\n\t\t\t\t: { event: \"\", data: \"\", retryMs: retryOnly };\n\t\t}\n\t\tconst message: SseMessage = {\n\t\t\tevent: this.eventName || \"message\",\n\t\t\tdata: this.dataLines.join(\"\\n\"),\n\t\t\tid: this.id,\n\t\t\tretryMs: this.retryMs,\n\t\t};\n\t\tthis.eventName = \"\";\n\t\tthis.dataLines = [];\n\t\tthis.retryMs = undefined;\n\t\treturn message;\n\t}\n}\n","import type { InodraAuth } from \"../core/auth.js\";\nimport type { InodraNetwork } from \"../core/network.js\";\n\n/** A data event delivered on a Warp stream. */\nexport interface WarpEvent {\n\t/** Server-side event type (e.g. \"event\", \"address_activity\"). */\n\ttype: string;\n\t/** Event ID — pass as lastEventId / Last-Event-ID to resume after disconnect. */\n\tid?: string;\n\t/** Parsed JSON payload. */\n\tdata: unknown;\n}\n\n/** Sent by the server when the stream is established. */\nexport interface WarpConnectedInfo {\n\tconnId?: string;\n\tsubscriptionId?: string;\n\tsubscriptionType?: string;\n\tprotocol?: string;\n\t[key: string]: unknown;\n}\n\nexport interface WarpStreamEvents extends Record<string, unknown> {\n\tconnected: WarpConnectedInfo;\n\tmessage: WarpEvent;\n\tquota_exceeded: unknown;\n\terror: Error;\n\treconnecting: { attempt: number; delayMs: number };\n\tclose: { reason: string };\n}\n\nexport interface WarpStreamOptions {\n\t/** Credentials: an API key string, {apiKey}, {sessionToken}, or a provider. */\n\tauth?: InodraAuth;\n\t/** Shorthand for `auth: { apiKey }`. */\n\tapiKey?: string;\n\t/** The Warp stream/subscription ID (from the management API). */\n\tsubscriptionId: string;\n\t/** Defaults to \"mainnet\". Ignored when url is set. */\n\tnetwork?: InodraNetwork;\n\t/** Full connection URL override (e.g. local development). */\n\turl?: string;\n\t/**\n\t * Connect mode. \"live\" (default): events from connect-time forward, any\n\t * buffered backlog is dropped. \"resume\": replay the buffered backlog (up\n\t * to 30 min / 2,000 events). The server treats mode as per-connection,\n\t * but SDK reconnects always pass the last delivered event ID, which\n\t * implies resume — so transient drops never lose events in either mode.\n\t */\n\tmode?: \"live\" | \"resume\";\n\t/** Resume after the given event ID on first connect (implies resume mode). */\n\tlastEventId?: string;\n\t/** Reconnect automatically on transport failures. Defaults to true. */\n\treconnect?: boolean;\n\t/** Defaults to 10. */\n\tmaxReconnectAttempts?: number;\n}\n\n/** Control events the server emits; everything else is a data event. */\nexport const CONTROL_EVENTS = new Set([\"connected\", \"error\", \"quota_exceeded\"]);\n\nexport function backoffDelayMs(attempt: number): number {\n\treturn Math.min(1000 * 2 ** (attempt - 1), 30_000) + Math.random() * 250;\n}\n","import { authFromOptions, type ResolvedAuth } from \"../core/auth.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../core/version.js\";\nimport { warpStreamUrl } from \"../core/network.js\";\nimport { Emitter } from \"./emitter.js\";\nimport { iterateStream } from \"./iterate.js\";\nimport { SseParser } from \"./sse-parser.js\";\nimport {\n\tbackoffDelayMs,\n\tCONTROL_EVENTS,\n\ttype WarpConnectedInfo,\n\ttype WarpEvent,\n\ttype WarpStreamEvents,\n\ttype WarpStreamOptions,\n} from \"./types.js\";\n\nexport interface WarpSseStreamOptions extends WarpStreamOptions {\n\t/** Custom fetch implementation. */\n\tfetch?: typeof globalThis.fetch;\n}\n\n/**\n * Server-Sent Events connection to a Warp stream.\n *\n * Delivery is at-least-once. On disconnect the client reconnects with the\n * `Last-Event-ID` header so no events are missed.\n *\n * The first connect is live by default: events flow from connect-time forward\n * and any backlog retained while disconnected is dropped. Pass\n * `mode: \"resume\"` (or `lastEventId`) to replay the retained backlog instead.\n *\n * ```ts\n * const stream = new WarpSseStream({ apiKey, subscriptionId });\n * stream.on(\"message\", (event) => console.log(event.type, event.data));\n * stream.connect();\n * ```\n */\nexport class WarpSseStream extends Emitter<WarpStreamEvents> {\n\tlastEventId: string | undefined;\n\n\tprivate readonly options: WarpSseStreamOptions;\n\tprivate readonly auth: ResolvedAuth;\n\tprivate readonly url: string;\n\tprivate readonly fetchImpl: typeof globalThis.fetch;\n\tprivate abort: AbortController | undefined;\n\tprivate reconnectAttempt = 0;\n\tprivate serverRetryMs: number | undefined;\n\tprivate closed = false;\n\tprivate closeEmitted = false;\n\n\tconstructor(options: WarpSseStreamOptions) {\n\t\tsuper();\n\t\tthis.options = options;\n\t\tthis.auth = authFromOptions(options, \"WarpSseStream\");\n\t\tconst base =\n\t\t\toptions.url ??\n\t\t\twarpStreamUrl(options.network ?? \"mainnet\", options.subscriptionId);\n\t\tif (options.mode !== undefined) {\n\t\t\tconst url = new URL(base);\n\t\t\turl.searchParams.set(\"mode\", options.mode);\n\t\t\tthis.url = url.toString();\n\t\t} else {\n\t\t\tthis.url = base;\n\t\t}\n\t\tthis.fetchImpl = options.fetch ?? globalThis.fetch;\n\t\tthis.lastEventId = options.lastEventId;\n\t}\n\n\tconnect(): void {\n\t\tif (this.abort) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = false;\n\t\tthis.closeEmitted = false;\n\t\tthis.abort = new AbortController();\n\t\tvoid this.run(this.abort.signal);\n\t}\n\n\tclose(): void {\n\t\tconst wasActive = this.abort !== undefined;\n\t\tthis.closed = true;\n\t\tthis.abort?.abort();\n\t\tthis.abort = undefined;\n\t\tif (wasActive) {\n\t\t\tthis.emitClose(\"client closed\");\n\t\t}\n\t}\n\n\t/** Emit \"close\" exactly once per connection lifecycle. */\n\tprivate emitClose(reason: string): void {\n\t\tif (this.closeEmitted) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closeEmitted = true;\n\t\tthis.emit(\"close\", { reason });\n\t}\n\n\t/** Iterate data events; ends when the stream closes (throws unless client-initiated). */\n\t[Symbol.asyncIterator](): AsyncGenerator<WarpEvent, void, undefined> {\n\t\treturn iterateStream(this);\n\t}\n\n\tprivate async run(signal: AbortSignal): Promise<void> {\n\t\tfor (;;) {\n\t\t\ttry {\n\t\t\t\tawait this.consume(signal);\n\t\t\t\tif (this.closed || signal.aborted) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Server ended the stream without a terminal event — reconnect.\n\t\t\t} catch (error) {\n\t\t\t\tif (this.closed || signal.aborted) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (error instanceof TerminalStreamError) {\n\t\t\t\t\tthis.emit(\"error\", error);\n\t\t\t\t\tthis.emitClose(error.message);\n\t\t\t\t\tthis.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"error\",\n\t\t\t\t\terror instanceof Error ? error : new Error(String(error)),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!(this.options.reconnect ?? true)) {\n\t\t\t\tthis.emitClose(\"disconnected\");\n\t\t\t\tthis.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.reconnectAttempt += 1;\n\t\t\tif (this.reconnectAttempt > (this.options.maxReconnectAttempts ?? 10)) {\n\t\t\t\tthis.emitClose(\"max reconnect attempts exceeded\");\n\t\t\t\tthis.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst delayMs = this.serverRetryMs ?? backoffDelayMs(this.reconnectAttempt);\n\t\t\tthis.emit(\"reconnecting\", { attempt: this.reconnectAttempt, delayMs });\n\t\t\tawait sleep(delayMs);\n\t\t\tif (this.closed || signal.aborted) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async consume(signal: AbortSignal): Promise<void> {\n\t\tconst { headers: authHeaders } = await this.auth.credentials();\n\t\tconst headers: Record<string, string> = {\n\t\t\taccept: \"text/event-stream\",\n\t\t\t...authHeaders,\n\t\t\t[SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n\t\t};\n\t\tif (this.lastEventId !== undefined) {\n\t\t\theaders[\"Last-Event-ID\"] = this.lastEventId;\n\t\t}\n\n\t\tconst response = await this.fetchImpl(this.url, { headers, signal });\n\t\tif (!response.ok || !response.body) {\n\t\t\tconst retryable = response.status >= 500;\n\t\t\tconst message = `SSE connection failed with status ${response.status}`;\n\t\t\tif (retryable) {\n\t\t\t\tthrow new Error(message);\n\t\t\t}\n\t\t\tthrow new TerminalStreamError(message);\n\t\t}\n\n\t\tconst parser = new SseParser();\n\t\tconst decoder = new TextDecoder();\n\t\tconst reader = response.body.getReader();\n\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const message of parser.feed(decoder.decode(value, { stream: true }))) {\n\t\t\t\tif (message.retryMs !== undefined) {\n\t\t\t\t\tthis.serverRetryMs = message.retryMs;\n\t\t\t\t}\n\t\t\t\tif (message.event === \"\" && message.data === \"\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.dispatch(message.event, message.id, message.data);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate dispatch(event: string, id: string | undefined, raw: string): void {\n\t\tlet data: unknown = raw;\n\t\ttry {\n\t\t\tdata = JSON.parse(raw);\n\t\t} catch {\n\t\t\t// keep raw string for non-JSON payloads\n\t\t}\n\n\t\tif (id !== undefined) {\n\t\t\tthis.lastEventId = id;\n\t\t}\n\n\t\tswitch (event) {\n\t\t\tcase \"connected\":\n\t\t\t\t// Successful connection: reset backoff\n\t\t\t\tthis.reconnectAttempt = 0;\n\t\t\t\tthis.emit(\"connected\", data as WarpConnectedInfo);\n\t\t\t\treturn;\n\t\t\tcase \"quota_exceeded\":\n\t\t\t\tthis.emit(\"quota_exceeded\", data);\n\t\t\t\tthis.emitClose(\"quota_exceeded\");\n\t\t\t\tthis.close();\n\t\t\t\treturn;\n\t\t\tcase \"error\": {\n\t\t\t\tconst message =\n\t\t\t\t\ttypeof data === \"object\" && data !== null && \"error\" in data\n\t\t\t\t\t\t? String((data as { error: unknown }).error)\n\t\t\t\t\t\t: raw;\n\t\t\t\tthis.emit(\"error\", new Error(message));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif (!CONTROL_EVENTS.has(event)) {\n\t\t\t\t\tthis.emit(\"message\", { type: event, id, data });\n\t\t\t\t}\n\t\t}\n\t}\n}\n\nclass TerminalStreamError extends Error {}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { authFromOptions, type ResolvedAuth } from \"../core/auth.js\";\nimport { warpWebSocketUrl } from \"../core/network.js\";\nimport { Emitter } from \"./emitter.js\";\nimport { iterateStream } from \"./iterate.js\";\nimport {\n\tbackoffDelayMs,\n\ttype WarpConnectedInfo,\n\ttype WarpEvent,\n\ttype WarpStreamEvents,\n\ttype WarpStreamOptions,\n} from \"./types.js\";\n\ntype WebSocketLike = {\n\tsend(data: string): void;\n\tclose(code?: number, reason?: string): void;\n\taddEventListener(type: string, listener: (event: never) => void): void;\n};\n\ntype WebSocketConstructor = new (url: string) => WebSocketLike;\n\nexport interface WarpWebSocketStreamOptions extends WarpStreamOptions {\n\t/**\n\t * Acknowledge each event automatically after all message handlers ran\n\t * without throwing. Defaults to true. Set false and call ack() yourself\n\t * for full control over the exactly-once window.\n\t */\n\tautoAck?: boolean;\n\t/** Custom WebSocket constructor (defaults to globalThis.WebSocket). */\n\twebSocket?: WebSocketConstructor;\n}\n\n/**\n * WebSocket connection to a Warp stream with exactly-once delivery.\n *\n * Each event must be acknowledged; unacknowledged events are redelivered\n * after reconnect. By default the client acks automatically once all\n * \"message\" handlers complete without throwing.\n *\n * The first connect is live by default: events flow from connect-time forward\n * and any backlog retained while disconnected is dropped. Pass\n * `mode: \"resume\"` (or `lastEventId`) to replay the retained backlog instead.\n *\n * ```ts\n * const stream = new WarpWebSocketStream({ apiKey, subscriptionId });\n * stream.on(\"message\", (event) => process(event)); // acked automatically\n * stream.connect();\n * ```\n */\nexport class WarpWebSocketStream extends Emitter<WarpStreamEvents> {\n\tlastEventId: string | undefined;\n\n\tprivate readonly options: WarpWebSocketStreamOptions;\n\tprivate readonly auth: ResolvedAuth;\n\tprivate readonly wsCtor: WebSocketConstructor;\n\tprivate ws: WebSocketLike | undefined;\n\tprivate reconnectAttempt = 0;\n\tprivate closed = false;\n\n\tconstructor(options: WarpWebSocketStreamOptions) {\n\t\tsuper();\n\t\tthis.options = options;\n\t\tthis.auth = authFromOptions(options, \"WarpWebSocketStream\");\n\t\tconst ctor =\n\t\t\toptions.webSocket ??\n\t\t\t(globalThis.WebSocket as unknown as WebSocketConstructor | undefined);\n\t\tif (!ctor) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No WebSocket implementation available — pass one via the webSocket option\",\n\t\t\t);\n\t\t}\n\t\tthis.wsCtor = ctor;\n\t\tthis.lastEventId = options.lastEventId;\n\t}\n\n\tconnect(): void {\n\t\tif (this.ws) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = false;\n\t\tthis.open();\n\t}\n\n\tclose(): void {\n\t\tthis.closed = true;\n\t\tthis.ws?.close(1000, \"client closed\");\n\t\tthis.ws = undefined;\n\t}\n\n\t/** Acknowledge an event by ID (only needed with autoAck: false). */\n\tack(id: string): void {\n\t\tthis.ws?.send(JSON.stringify({ type: \"ack\", id }));\n\t}\n\n\t/** Iterate data events; ends when the stream closes (throws unless client-initiated). */\n\t[Symbol.asyncIterator](): AsyncGenerator<WarpEvent, void, undefined> {\n\t\treturn iterateStream(this);\n\t}\n\n\tprivate buildUrl(authParams: Record<string, string>): string {\n\t\tconst base =\n\t\t\tthis.options.url ??\n\t\t\twarpWebSocketUrl(\n\t\t\t\tthis.options.network ?? \"mainnet\",\n\t\t\t\tthis.options.subscriptionId,\n\t\t\t);\n\t\tconst url = new URL(base);\n\t\t// Browsers cannot set headers on WebSocket upgrades, so credentials\n\t\t// travel as query parameters (and the SDK header is omitted).\n\t\tfor (const [key, value] of Object.entries(authParams)) {\n\t\t\turl.searchParams.set(key, value);\n\t\t}\n\t\tif (this.options.mode !== undefined) {\n\t\t\turl.searchParams.set(\"mode\", this.options.mode);\n\t\t}\n\t\tif (this.lastEventId !== undefined) {\n\t\t\turl.searchParams.set(\"lastEventId\", this.lastEventId);\n\t\t}\n\t\treturn url.toString();\n\t}\n\n\tprivate open(): void {\n\t\t// Static credentials (API keys) open synchronously — dynamic providers\n\t\t// resolve first, then open unless the stream was closed meanwhile.\n\t\tconst credentials = this.auth.staticCredentials();\n\t\tif (credentials) {\n\t\t\tthis.openWith(credentials.queryParams);\n\t\t\treturn;\n\t\t}\n\t\tvoid this.auth.credentials().then(\n\t\t\t(resolved) => {\n\t\t\t\tif (!this.closed && !this.ws) {\n\t\t\t\t\tthis.openWith(resolved.queryParams);\n\t\t\t\t}\n\t\t\t},\n\t\t\t(error: unknown) => {\n\t\t\t\tthis.failTerminally(\n\t\t\t\t\terror instanceof Error ? error : new Error(String(error)),\n\t\t\t\t\t\"credential resolution failed\",\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate failTerminally(error: Error, reason: string): void {\n\t\tthis.closed = true;\n\t\tthis.emit(\"error\", error);\n\t\tthis.emit(\"close\", { reason });\n\t}\n\n\tprivate openWith(authParams: Record<string, string> | undefined): void {\n\t\tif (!authParams) {\n\t\t\tthis.failTerminally(\n\t\t\t\tnew Error(\n\t\t\t\t\t\"These credentials cannot authenticate a WebSocket (no header support on upgrades) — use an API key or the SSE stream\",\n\t\t\t\t),\n\t\t\t\t\"unsupported credentials\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tconst ws = new this.wsCtor(this.buildUrl(authParams));\n\t\tthis.ws = ws;\n\n\t\tws.addEventListener(\"message\", (event: MessageEvent) => {\n\t\t\tthis.handleMessage(event);\n\t\t});\n\t\tws.addEventListener(\"error\", () => {\n\t\t\tthis.emit(\"error\", new Error(\"WebSocket transport error\"));\n\t\t});\n\t\tws.addEventListener(\"close\", (event: CloseEvent) => {\n\t\t\tif (this.ws !== ws) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.ws = undefined;\n\t\t\tthis.handleClose(event.code, event.reason);\n\t\t});\n\t}\n\n\tprivate handleMessage(event: MessageEvent): void {\n\t\tlet parsed: { event?: unknown; id?: unknown; data?: unknown };\n\t\ttry {\n\t\t\tparsed = JSON.parse(\n\t\t\t\ttypeof event.data === \"string\" ? event.data : String(event.data),\n\t\t\t);\n\t\t} catch {\n\t\t\tthis.emit(\"error\", new Error(\"Received malformed WebSocket message\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst type = typeof parsed.event === \"string\" ? parsed.event : \"message\";\n\t\tconst id = typeof parsed.id === \"string\" ? parsed.id : undefined;\n\n\t\tswitch (type) {\n\t\t\tcase \"connected\":\n\t\t\t\tthis.reconnectAttempt = 0;\n\t\t\t\tthis.emit(\"connected\", parsed.data as WarpConnectedInfo);\n\t\t\t\treturn;\n\t\t\tcase \"quota_exceeded\":\n\t\t\t\tthis.emit(\"quota_exceeded\", parsed.data);\n\t\t\t\treturn; // server closes with 1008; handleClose makes it terminal\n\t\t\tcase \"error\": {\n\t\t\t\tconst message =\n\t\t\t\t\ttypeof parsed.data === \"object\" &&\n\t\t\t\t\tparsed.data !== null &&\n\t\t\t\t\t\"error\" in parsed.data\n\t\t\t\t\t\t? String((parsed.data as { error: unknown }).error)\n\t\t\t\t\t\t: \"Server error\";\n\t\t\t\tthis.emit(\"error\", new Error(message));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tif (id !== undefined) {\n\t\t\t\t\tthis.lastEventId = id;\n\t\t\t\t}\n\t\t\t\tconst handlersSucceeded = this.emit(\"message\", {\n\t\t\t\t\ttype,\n\t\t\t\t\tid,\n\t\t\t\t\tdata: parsed.data,\n\t\t\t\t});\n\t\t\t\tif ((this.options.autoAck ?? true) && id !== undefined) {\n\t\t\t\t\tif (handlersSucceeded) {\n\t\t\t\t\t\tthis.ack(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t`Message handler threw; event ${id} not acked and will be redelivered`,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleClose(code: number, reason: string): void {\n\t\tif (this.closed) {\n\t\t\tthis.emit(\"close\", { reason: \"client closed\" });\n\t\t\treturn;\n\t\t}\n\t\t// 1008 is a policy close (QUOTA_EXCEEDED, STREAM_ALREADY_CONNECTED) —\n\t\t// reconnecting would fail again immediately.\n\t\tif (code === 1008) {\n\t\t\tthis.emit(\"close\", { reason: reason || \"policy violation\" });\n\t\t\tthis.closed = true;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!(this.options.reconnect ?? true)) {\n\t\t\tthis.emit(\"close\", { reason: reason || \"disconnected\" });\n\t\t\tthis.closed = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.reconnectAttempt += 1;\n\t\tif (this.reconnectAttempt > (this.options.maxReconnectAttempts ?? 10)) {\n\t\t\tthis.emit(\"close\", { reason: \"max reconnect attempts exceeded\" });\n\t\t\tthis.closed = true;\n\t\t\treturn;\n\t\t}\n\t\tconst delayMs = backoffDelayMs(this.reconnectAttempt);\n\t\tthis.emit(\"reconnecting\", { attempt: this.reconnectAttempt, delayMs });\n\t\tsetTimeout(() => {\n\t\t\tif (!this.closed && !this.ws) {\n\t\t\t\tthis.open();\n\t\t\t}\n\t\t}, delayMs);\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,195 @@
1
+ import { I as InodraAuth, a as InodraNetwork } from './network-CEg2MJY3.cjs';
2
+
3
+ /** Minimal typed event emitter that works in every runtime (no node:events). */
4
+ declare class Emitter<Events extends Record<string, unknown>> {
5
+ private readonly handlers;
6
+ on<K extends keyof Events>(event: K, handler: (payload: Events[K]) => void): () => void;
7
+ off<K extends keyof Events>(event: K, handler: (payload: Events[K]) => void): void;
8
+ /** Returns false if any handler threw. */
9
+ emit<K extends keyof Events>(event: K, payload: Events[K]): boolean;
10
+ }
11
+
12
+ /** A data event delivered on a Warp stream. */
13
+ interface WarpEvent {
14
+ /** Server-side event type (e.g. "event", "address_activity"). */
15
+ type: string;
16
+ /** Event ID — pass as lastEventId / Last-Event-ID to resume after disconnect. */
17
+ id?: string;
18
+ /** Parsed JSON payload. */
19
+ data: unknown;
20
+ }
21
+ /** Sent by the server when the stream is established. */
22
+ interface WarpConnectedInfo {
23
+ connId?: string;
24
+ subscriptionId?: string;
25
+ subscriptionType?: string;
26
+ protocol?: string;
27
+ [key: string]: unknown;
28
+ }
29
+ interface WarpStreamEvents extends Record<string, unknown> {
30
+ connected: WarpConnectedInfo;
31
+ message: WarpEvent;
32
+ quota_exceeded: unknown;
33
+ error: Error;
34
+ reconnecting: {
35
+ attempt: number;
36
+ delayMs: number;
37
+ };
38
+ close: {
39
+ reason: string;
40
+ };
41
+ }
42
+ interface WarpStreamOptions {
43
+ /** Credentials: an API key string, {apiKey}, {sessionToken}, or a provider. */
44
+ auth?: InodraAuth;
45
+ /** Shorthand for `auth: { apiKey }`. */
46
+ apiKey?: string;
47
+ /** The Warp stream/subscription ID (from the management API). */
48
+ subscriptionId: string;
49
+ /** Defaults to "mainnet". Ignored when url is set. */
50
+ network?: InodraNetwork;
51
+ /** Full connection URL override (e.g. local development). */
52
+ url?: string;
53
+ /**
54
+ * Connect mode. "live" (default): events from connect-time forward, any
55
+ * buffered backlog is dropped. "resume": replay the buffered backlog (up
56
+ * to 30 min / 2,000 events). The server treats mode as per-connection,
57
+ * but SDK reconnects always pass the last delivered event ID, which
58
+ * implies resume — so transient drops never lose events in either mode.
59
+ */
60
+ mode?: "live" | "resume";
61
+ /** Resume after the given event ID on first connect (implies resume mode). */
62
+ lastEventId?: string;
63
+ /** Reconnect automatically on transport failures. Defaults to true. */
64
+ reconnect?: boolean;
65
+ /** Defaults to 10. */
66
+ maxReconnectAttempts?: number;
67
+ }
68
+
69
+ interface WarpSseStreamOptions extends WarpStreamOptions {
70
+ /** Custom fetch implementation. */
71
+ fetch?: typeof globalThis.fetch;
72
+ }
73
+ /**
74
+ * Server-Sent Events connection to a Warp stream.
75
+ *
76
+ * Delivery is at-least-once. On disconnect the client reconnects with the
77
+ * `Last-Event-ID` header so no events are missed.
78
+ *
79
+ * The first connect is live by default: events flow from connect-time forward
80
+ * and any backlog retained while disconnected is dropped. Pass
81
+ * `mode: "resume"` (or `lastEventId`) to replay the retained backlog instead.
82
+ *
83
+ * ```ts
84
+ * const stream = new WarpSseStream({ apiKey, subscriptionId });
85
+ * stream.on("message", (event) => console.log(event.type, event.data));
86
+ * stream.connect();
87
+ * ```
88
+ */
89
+ declare class WarpSseStream extends Emitter<WarpStreamEvents> {
90
+ lastEventId: string | undefined;
91
+ private readonly options;
92
+ private readonly auth;
93
+ private readonly url;
94
+ private readonly fetchImpl;
95
+ private abort;
96
+ private reconnectAttempt;
97
+ private serverRetryMs;
98
+ private closed;
99
+ private closeEmitted;
100
+ constructor(options: WarpSseStreamOptions);
101
+ connect(): void;
102
+ close(): void;
103
+ /** Emit "close" exactly once per connection lifecycle. */
104
+ private emitClose;
105
+ /** Iterate data events; ends when the stream closes (throws unless client-initiated). */
106
+ [Symbol.asyncIterator](): AsyncGenerator<WarpEvent, void, undefined>;
107
+ private run;
108
+ private consume;
109
+ private dispatch;
110
+ }
111
+
112
+ type WebSocketLike = {
113
+ send(data: string): void;
114
+ close(code?: number, reason?: string): void;
115
+ addEventListener(type: string, listener: (event: never) => void): void;
116
+ };
117
+ type WebSocketConstructor = new (url: string) => WebSocketLike;
118
+ interface WarpWebSocketStreamOptions extends WarpStreamOptions {
119
+ /**
120
+ * Acknowledge each event automatically after all message handlers ran
121
+ * without throwing. Defaults to true. Set false and call ack() yourself
122
+ * for full control over the exactly-once window.
123
+ */
124
+ autoAck?: boolean;
125
+ /** Custom WebSocket constructor (defaults to globalThis.WebSocket). */
126
+ webSocket?: WebSocketConstructor;
127
+ }
128
+ /**
129
+ * WebSocket connection to a Warp stream with exactly-once delivery.
130
+ *
131
+ * Each event must be acknowledged; unacknowledged events are redelivered
132
+ * after reconnect. By default the client acks automatically once all
133
+ * "message" handlers complete without throwing.
134
+ *
135
+ * The first connect is live by default: events flow from connect-time forward
136
+ * and any backlog retained while disconnected is dropped. Pass
137
+ * `mode: "resume"` (or `lastEventId`) to replay the retained backlog instead.
138
+ *
139
+ * ```ts
140
+ * const stream = new WarpWebSocketStream({ apiKey, subscriptionId });
141
+ * stream.on("message", (event) => process(event)); // acked automatically
142
+ * stream.connect();
143
+ * ```
144
+ */
145
+ declare class WarpWebSocketStream extends Emitter<WarpStreamEvents> {
146
+ lastEventId: string | undefined;
147
+ private readonly options;
148
+ private readonly auth;
149
+ private readonly wsCtor;
150
+ private ws;
151
+ private reconnectAttempt;
152
+ private closed;
153
+ constructor(options: WarpWebSocketStreamOptions);
154
+ connect(): void;
155
+ close(): void;
156
+ /** Acknowledge an event by ID (only needed with autoAck: false). */
157
+ ack(id: string): void;
158
+ /** Iterate data events; ends when the stream closes (throws unless client-initiated). */
159
+ [Symbol.asyncIterator](): AsyncGenerator<WarpEvent, void, undefined>;
160
+ private buildUrl;
161
+ private open;
162
+ private failTerminally;
163
+ private openWith;
164
+ private handleMessage;
165
+ private handleClose;
166
+ }
167
+
168
+ interface WarpStreamLike extends Emitter<WarpStreamEvents> {
169
+ close(): void;
170
+ }
171
+ interface IterateStreamOptions {
172
+ /**
173
+ * Close the stream when iteration ends (loop break, return, or throw).
174
+ * Defaults to true — an abandoned open stream keeps billing connection
175
+ * time.
176
+ */
177
+ closeOnReturn?: boolean;
178
+ }
179
+ /**
180
+ * Consume a Warp stream as an async iterable of data events.
181
+ *
182
+ * Ends normally when the stream is closed by the client; throws when the
183
+ * stream closes for any other reason (quota exceeded, reconnect budget
184
+ * exhausted, terminal server error). Transient transport errors that the
185
+ * stream retries internally do not interrupt iteration.
186
+ *
187
+ * ```ts
188
+ * for await (const event of stream) {
189
+ * console.log(event.type, event.data);
190
+ * }
191
+ * ```
192
+ */
193
+ declare function iterateStream(stream: WarpStreamLike, options?: IterateStreamOptions): AsyncGenerator<WarpEvent, void, undefined>;
194
+
195
+ export { type IterateStreamOptions, type WarpConnectedInfo, type WarpEvent, WarpSseStream, type WarpSseStreamOptions, type WarpStreamEvents, type WarpStreamOptions, WarpWebSocketStream, type WarpWebSocketStreamOptions, iterateStream };
package/dist/warp.d.ts ADDED
@@ -0,0 +1,195 @@
1
+ import { I as InodraAuth, a as InodraNetwork } from './network-CEg2MJY3.js';
2
+
3
+ /** Minimal typed event emitter that works in every runtime (no node:events). */
4
+ declare class Emitter<Events extends Record<string, unknown>> {
5
+ private readonly handlers;
6
+ on<K extends keyof Events>(event: K, handler: (payload: Events[K]) => void): () => void;
7
+ off<K extends keyof Events>(event: K, handler: (payload: Events[K]) => void): void;
8
+ /** Returns false if any handler threw. */
9
+ emit<K extends keyof Events>(event: K, payload: Events[K]): boolean;
10
+ }
11
+
12
+ /** A data event delivered on a Warp stream. */
13
+ interface WarpEvent {
14
+ /** Server-side event type (e.g. "event", "address_activity"). */
15
+ type: string;
16
+ /** Event ID — pass as lastEventId / Last-Event-ID to resume after disconnect. */
17
+ id?: string;
18
+ /** Parsed JSON payload. */
19
+ data: unknown;
20
+ }
21
+ /** Sent by the server when the stream is established. */
22
+ interface WarpConnectedInfo {
23
+ connId?: string;
24
+ subscriptionId?: string;
25
+ subscriptionType?: string;
26
+ protocol?: string;
27
+ [key: string]: unknown;
28
+ }
29
+ interface WarpStreamEvents extends Record<string, unknown> {
30
+ connected: WarpConnectedInfo;
31
+ message: WarpEvent;
32
+ quota_exceeded: unknown;
33
+ error: Error;
34
+ reconnecting: {
35
+ attempt: number;
36
+ delayMs: number;
37
+ };
38
+ close: {
39
+ reason: string;
40
+ };
41
+ }
42
+ interface WarpStreamOptions {
43
+ /** Credentials: an API key string, {apiKey}, {sessionToken}, or a provider. */
44
+ auth?: InodraAuth;
45
+ /** Shorthand for `auth: { apiKey }`. */
46
+ apiKey?: string;
47
+ /** The Warp stream/subscription ID (from the management API). */
48
+ subscriptionId: string;
49
+ /** Defaults to "mainnet". Ignored when url is set. */
50
+ network?: InodraNetwork;
51
+ /** Full connection URL override (e.g. local development). */
52
+ url?: string;
53
+ /**
54
+ * Connect mode. "live" (default): events from connect-time forward, any
55
+ * buffered backlog is dropped. "resume": replay the buffered backlog (up
56
+ * to 30 min / 2,000 events). The server treats mode as per-connection,
57
+ * but SDK reconnects always pass the last delivered event ID, which
58
+ * implies resume — so transient drops never lose events in either mode.
59
+ */
60
+ mode?: "live" | "resume";
61
+ /** Resume after the given event ID on first connect (implies resume mode). */
62
+ lastEventId?: string;
63
+ /** Reconnect automatically on transport failures. Defaults to true. */
64
+ reconnect?: boolean;
65
+ /** Defaults to 10. */
66
+ maxReconnectAttempts?: number;
67
+ }
68
+
69
+ interface WarpSseStreamOptions extends WarpStreamOptions {
70
+ /** Custom fetch implementation. */
71
+ fetch?: typeof globalThis.fetch;
72
+ }
73
+ /**
74
+ * Server-Sent Events connection to a Warp stream.
75
+ *
76
+ * Delivery is at-least-once. On disconnect the client reconnects with the
77
+ * `Last-Event-ID` header so no events are missed.
78
+ *
79
+ * The first connect is live by default: events flow from connect-time forward
80
+ * and any backlog retained while disconnected is dropped. Pass
81
+ * `mode: "resume"` (or `lastEventId`) to replay the retained backlog instead.
82
+ *
83
+ * ```ts
84
+ * const stream = new WarpSseStream({ apiKey, subscriptionId });
85
+ * stream.on("message", (event) => console.log(event.type, event.data));
86
+ * stream.connect();
87
+ * ```
88
+ */
89
+ declare class WarpSseStream extends Emitter<WarpStreamEvents> {
90
+ lastEventId: string | undefined;
91
+ private readonly options;
92
+ private readonly auth;
93
+ private readonly url;
94
+ private readonly fetchImpl;
95
+ private abort;
96
+ private reconnectAttempt;
97
+ private serverRetryMs;
98
+ private closed;
99
+ private closeEmitted;
100
+ constructor(options: WarpSseStreamOptions);
101
+ connect(): void;
102
+ close(): void;
103
+ /** Emit "close" exactly once per connection lifecycle. */
104
+ private emitClose;
105
+ /** Iterate data events; ends when the stream closes (throws unless client-initiated). */
106
+ [Symbol.asyncIterator](): AsyncGenerator<WarpEvent, void, undefined>;
107
+ private run;
108
+ private consume;
109
+ private dispatch;
110
+ }
111
+
112
+ type WebSocketLike = {
113
+ send(data: string): void;
114
+ close(code?: number, reason?: string): void;
115
+ addEventListener(type: string, listener: (event: never) => void): void;
116
+ };
117
+ type WebSocketConstructor = new (url: string) => WebSocketLike;
118
+ interface WarpWebSocketStreamOptions extends WarpStreamOptions {
119
+ /**
120
+ * Acknowledge each event automatically after all message handlers ran
121
+ * without throwing. Defaults to true. Set false and call ack() yourself
122
+ * for full control over the exactly-once window.
123
+ */
124
+ autoAck?: boolean;
125
+ /** Custom WebSocket constructor (defaults to globalThis.WebSocket). */
126
+ webSocket?: WebSocketConstructor;
127
+ }
128
+ /**
129
+ * WebSocket connection to a Warp stream with exactly-once delivery.
130
+ *
131
+ * Each event must be acknowledged; unacknowledged events are redelivered
132
+ * after reconnect. By default the client acks automatically once all
133
+ * "message" handlers complete without throwing.
134
+ *
135
+ * The first connect is live by default: events flow from connect-time forward
136
+ * and any backlog retained while disconnected is dropped. Pass
137
+ * `mode: "resume"` (or `lastEventId`) to replay the retained backlog instead.
138
+ *
139
+ * ```ts
140
+ * const stream = new WarpWebSocketStream({ apiKey, subscriptionId });
141
+ * stream.on("message", (event) => process(event)); // acked automatically
142
+ * stream.connect();
143
+ * ```
144
+ */
145
+ declare class WarpWebSocketStream extends Emitter<WarpStreamEvents> {
146
+ lastEventId: string | undefined;
147
+ private readonly options;
148
+ private readonly auth;
149
+ private readonly wsCtor;
150
+ private ws;
151
+ private reconnectAttempt;
152
+ private closed;
153
+ constructor(options: WarpWebSocketStreamOptions);
154
+ connect(): void;
155
+ close(): void;
156
+ /** Acknowledge an event by ID (only needed with autoAck: false). */
157
+ ack(id: string): void;
158
+ /** Iterate data events; ends when the stream closes (throws unless client-initiated). */
159
+ [Symbol.asyncIterator](): AsyncGenerator<WarpEvent, void, undefined>;
160
+ private buildUrl;
161
+ private open;
162
+ private failTerminally;
163
+ private openWith;
164
+ private handleMessage;
165
+ private handleClose;
166
+ }
167
+
168
+ interface WarpStreamLike extends Emitter<WarpStreamEvents> {
169
+ close(): void;
170
+ }
171
+ interface IterateStreamOptions {
172
+ /**
173
+ * Close the stream when iteration ends (loop break, return, or throw).
174
+ * Defaults to true — an abandoned open stream keeps billing connection
175
+ * time.
176
+ */
177
+ closeOnReturn?: boolean;
178
+ }
179
+ /**
180
+ * Consume a Warp stream as an async iterable of data events.
181
+ *
182
+ * Ends normally when the stream is closed by the client; throws when the
183
+ * stream closes for any other reason (quota exceeded, reconnect budget
184
+ * exhausted, terminal server error). Transient transport errors that the
185
+ * stream retries internally do not interrupt iteration.
186
+ *
187
+ * ```ts
188
+ * for await (const event of stream) {
189
+ * console.log(event.type, event.data);
190
+ * }
191
+ * ```
192
+ */
193
+ declare function iterateStream(stream: WarpStreamLike, options?: IterateStreamOptions): AsyncGenerator<WarpEvent, void, undefined>;
194
+
195
+ export { type IterateStreamOptions, type WarpConnectedInfo, type WarpEvent, WarpSseStream, type WarpSseStreamOptions, type WarpStreamEvents, type WarpStreamOptions, WarpWebSocketStream, type WarpWebSocketStreamOptions, iterateStream };
package/dist/warp.js ADDED
@@ -0,0 +1,12 @@
1
+ import {
2
+ WarpSseStream,
3
+ WarpWebSocketStream,
4
+ iterateStream
5
+ } from "./chunk-ZSW3EWGF.js";
6
+ import "./chunk-U6D5LGNF.js";
7
+ export {
8
+ WarpSseStream,
9
+ WarpWebSocketStream,
10
+ iterateStream
11
+ };
12
+ //# sourceMappingURL=warp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/webhooks/index.ts
21
+ var webhooks_exports = {};
22
+ __export(webhooks_exports, {
23
+ verifyWebhookSignature: () => verifyWebhookSignature
24
+ });
25
+ module.exports = __toCommonJS(webhooks_exports);
26
+ async function verifyWebhookSignature(options) {
27
+ const parsed = parseSignatureHeader(options.signature);
28
+ if (!parsed) {
29
+ return false;
30
+ }
31
+ const now = options.now ?? Math.floor(Date.now() / 1e3);
32
+ const tolerance = options.toleranceSeconds ?? 300;
33
+ if (Math.abs(now - parsed.timestamp) > tolerance) {
34
+ return false;
35
+ }
36
+ const expected = await hmacSha256Hex(
37
+ options.secret,
38
+ `${parsed.timestamp}.${options.payload}`
39
+ );
40
+ return parsed.signatures.some(
41
+ (candidate) => timingSafeEqualHex(candidate, expected)
42
+ );
43
+ }
44
+ function parseSignatureHeader(header) {
45
+ if (typeof header !== "string" || header.length === 0) {
46
+ return void 0;
47
+ }
48
+ let timestamp;
49
+ const signatures = [];
50
+ for (const part of header.split(",")) {
51
+ const eq = part.indexOf("=");
52
+ if (eq === -1) {
53
+ continue;
54
+ }
55
+ const key = part.slice(0, eq).trim();
56
+ const value = part.slice(eq + 1).trim();
57
+ if (key === "t") {
58
+ const ts = Number(value);
59
+ if (Number.isInteger(ts)) {
60
+ timestamp = ts;
61
+ }
62
+ } else if (key === "v1" && /^[0-9a-f]+$/i.test(value)) {
63
+ signatures.push(value.toLowerCase());
64
+ }
65
+ }
66
+ if (timestamp === void 0 || signatures.length === 0) {
67
+ return void 0;
68
+ }
69
+ return { timestamp, signatures };
70
+ }
71
+ async function hmacSha256Hex(secret, message) {
72
+ const encoder = new TextEncoder();
73
+ const key = await crypto.subtle.importKey(
74
+ "raw",
75
+ encoder.encode(secret),
76
+ { name: "HMAC", hash: "SHA-256" },
77
+ false,
78
+ ["sign"]
79
+ );
80
+ const signature = await crypto.subtle.sign(
81
+ "HMAC",
82
+ key,
83
+ encoder.encode(message)
84
+ );
85
+ return Array.from(
86
+ new Uint8Array(signature),
87
+ (byte) => byte.toString(16).padStart(2, "0")
88
+ ).join("");
89
+ }
90
+ function timingSafeEqualHex(a, b) {
91
+ if (a.length !== b.length) {
92
+ return false;
93
+ }
94
+ let diff = 0;
95
+ for (let i = 0; i < a.length; i++) {
96
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
97
+ }
98
+ return diff === 0;
99
+ }
100
+ // Annotate the CommonJS export names for ESM import in node:
101
+ 0 && (module.exports = {
102
+ verifyWebhookSignature
103
+ });
104
+ //# sourceMappingURL=webhooks.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/webhooks/index.ts"],"sourcesContent":["/**\n * Verification for Inodra webhook signatures.\n *\n * Inodra signs webhook deliveries with HMAC-SHA256 when the webhook has a\n * secret configured. The signature arrives in the `X-Inodra-Signature`\n * header as `t=<unix-seconds>,v1=<hex-hmac>` where the HMAC is computed\n * over `<timestamp>.<raw-body>`.\n */\n\nexport interface VerifyWebhookSignatureOptions {\n\t/** Raw request body, exactly as received (before any JSON parsing). */\n\tpayload: string;\n\t/** Value of the X-Inodra-Signature header. */\n\tsignature: string;\n\t/** The webhook's secret. */\n\tsecret: string;\n\t/** Max allowed age of the signature. Defaults to 300 seconds. */\n\ttoleranceSeconds?: number;\n\t/** Current unix time in seconds (for testing). */\n\tnow?: number;\n}\n\n/**\n * Verify a webhook delivery. Returns false for malformed, mismatched, or\n * expired signatures — never throws on bad input.\n *\n * ```ts\n * const valid = await verifyWebhookSignature({\n * payload: rawBody,\n * signature: req.headers[\"x-inodra-signature\"],\n * secret: process.env.INODRA_WEBHOOK_SECRET,\n * });\n * ```\n */\nexport async function verifyWebhookSignature(\n\toptions: VerifyWebhookSignatureOptions,\n): Promise<boolean> {\n\tconst parsed = parseSignatureHeader(options.signature);\n\tif (!parsed) {\n\t\treturn false;\n\t}\n\n\tconst now = options.now ?? Math.floor(Date.now() / 1000);\n\tconst tolerance = options.toleranceSeconds ?? 300;\n\tif (Math.abs(now - parsed.timestamp) > tolerance) {\n\t\treturn false;\n\t}\n\n\tconst expected = await hmacSha256Hex(\n\t\toptions.secret,\n\t\t`${parsed.timestamp}.${options.payload}`,\n\t);\n\treturn parsed.signatures.some((candidate) =>\n\t\ttimingSafeEqualHex(candidate, expected),\n\t);\n}\n\nfunction parseSignatureHeader(\n\theader: string,\n): { timestamp: number; signatures: string[] } | undefined {\n\tif (typeof header !== \"string\" || header.length === 0) {\n\t\treturn undefined;\n\t}\n\tlet timestamp: number | undefined;\n\tconst signatures: string[] = [];\n\n\tfor (const part of header.split(\",\")) {\n\t\tconst eq = part.indexOf(\"=\");\n\t\tif (eq === -1) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = part.slice(0, eq).trim();\n\t\tconst value = part.slice(eq + 1).trim();\n\t\tif (key === \"t\") {\n\t\t\tconst ts = Number(value);\n\t\t\tif (Number.isInteger(ts)) {\n\t\t\t\ttimestamp = ts;\n\t\t\t}\n\t\t} else if (key === \"v1\" && /^[0-9a-f]+$/i.test(value)) {\n\t\t\tsignatures.push(value.toLowerCase());\n\t\t}\n\t}\n\n\tif (timestamp === undefined || signatures.length === 0) {\n\t\treturn undefined;\n\t}\n\treturn { timestamp, signatures };\n}\n\nasync function hmacSha256Hex(secret: string, message: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"sign\"],\n\t);\n\tconst signature = await crypto.subtle.sign(\n\t\t\"HMAC\",\n\t\tkey,\n\t\tencoder.encode(message),\n\t);\n\treturn Array.from(new Uint8Array(signature), (byte) =>\n\t\tbyte.toString(16).padStart(2, \"0\"),\n\t).join(\"\");\n}\n\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n\tif (a.length !== b.length) {\n\t\treturn false;\n\t}\n\tlet diff = 0;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tdiff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n\t}\n\treturn diff === 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCA,eAAsB,uBACrB,SACmB;AACnB,QAAM,SAAS,qBAAqB,QAAQ,SAAS;AACrD,MAAI,CAAC,QAAQ;AACZ,WAAO;AAAA,EACR;AAEA,QAAM,MAAM,QAAQ,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACvD,QAAM,YAAY,QAAQ,oBAAoB;AAC9C,MAAI,KAAK,IAAI,MAAM,OAAO,SAAS,IAAI,WAAW;AACjD,WAAO;AAAA,EACR;AAEA,QAAM,WAAW,MAAM;AAAA,IACtB,QAAQ;AAAA,IACR,GAAG,OAAO,SAAS,IAAI,QAAQ,OAAO;AAAA,EACvC;AACA,SAAO,OAAO,WAAW;AAAA,IAAK,CAAC,cAC9B,mBAAmB,WAAW,QAAQ;AAAA,EACvC;AACD;AAEA,SAAS,qBACR,QAC0D;AAC1D,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,GAAG;AACtD,WAAO;AAAA,EACR;AACA,MAAI;AACJ,QAAM,aAAuB,CAAC;AAE9B,aAAW,QAAQ,OAAO,MAAM,GAAG,GAAG;AACrC,UAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,QAAI,OAAO,IAAI;AACd;AAAA,IACD;AACA,UAAM,MAAM,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AACnC,UAAM,QAAQ,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK;AACtC,QAAI,QAAQ,KAAK;AAChB,YAAM,KAAK,OAAO,KAAK;AACvB,UAAI,OAAO,UAAU,EAAE,GAAG;AACzB,oBAAY;AAAA,MACb;AAAA,IACD,WAAW,QAAQ,QAAQ,eAAe,KAAK,KAAK,GAAG;AACtD,iBAAW,KAAK,MAAM,YAAY,CAAC;AAAA,IACpC;AAAA,EACD;AAEA,MAAI,cAAc,UAAa,WAAW,WAAW,GAAG;AACvD,WAAO;AAAA,EACR;AACA,SAAO,EAAE,WAAW,WAAW;AAChC;AAEA,eAAe,cAAc,QAAgB,SAAkC;AAC9E,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,MAAM,MAAM,OAAO,OAAO;AAAA,IAC/B;AAAA,IACA,QAAQ,OAAO,MAAM;AAAA,IACrB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AACA,QAAM,YAAY,MAAM,OAAO,OAAO;AAAA,IACrC;AAAA,IACA;AAAA,IACA,QAAQ,OAAO,OAAO;AAAA,EACvB;AACA,SAAO,MAAM;AAAA,IAAK,IAAI,WAAW,SAAS;AAAA,IAAG,CAAC,SAC7C,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,EAClC,EAAE,KAAK,EAAE;AACV;AAEA,SAAS,mBAAmB,GAAW,GAAoB;AAC1D,MAAI,EAAE,WAAW,EAAE,QAAQ;AAC1B,WAAO;AAAA,EACR;AACA,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AAClC,YAAQ,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;AAAA,EACzC;AACA,SAAO,SAAS;AACjB;","names":[]}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Verification for Inodra webhook signatures.
3
+ *
4
+ * Inodra signs webhook deliveries with HMAC-SHA256 when the webhook has a
5
+ * secret configured. The signature arrives in the `X-Inodra-Signature`
6
+ * header as `t=<unix-seconds>,v1=<hex-hmac>` where the HMAC is computed
7
+ * over `<timestamp>.<raw-body>`.
8
+ */
9
+ interface VerifyWebhookSignatureOptions {
10
+ /** Raw request body, exactly as received (before any JSON parsing). */
11
+ payload: string;
12
+ /** Value of the X-Inodra-Signature header. */
13
+ signature: string;
14
+ /** The webhook's secret. */
15
+ secret: string;
16
+ /** Max allowed age of the signature. Defaults to 300 seconds. */
17
+ toleranceSeconds?: number;
18
+ /** Current unix time in seconds (for testing). */
19
+ now?: number;
20
+ }
21
+ /**
22
+ * Verify a webhook delivery. Returns false for malformed, mismatched, or
23
+ * expired signatures — never throws on bad input.
24
+ *
25
+ * ```ts
26
+ * const valid = await verifyWebhookSignature({
27
+ * payload: rawBody,
28
+ * signature: req.headers["x-inodra-signature"],
29
+ * secret: process.env.INODRA_WEBHOOK_SECRET,
30
+ * });
31
+ * ```
32
+ */
33
+ declare function verifyWebhookSignature(options: VerifyWebhookSignatureOptions): Promise<boolean>;
34
+
35
+ export { type VerifyWebhookSignatureOptions, verifyWebhookSignature };