@restless-stream/node 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.
package/dist/index.cjs ADDED
@@ -0,0 +1,507 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ buildNodeSseUrl: () => buildNodeSseUrl,
35
+ createNodeRestlessClient: () => createNodeRestlessClient,
36
+ subscribeSse: () => subscribeSse,
37
+ subscribeWebSocket: () => subscribeWebSocket
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+ __reExport(index_exports, require("@restless-stream/core"), module.exports);
41
+
42
+ // src/client.ts
43
+ var import_core2 = require("@restless-stream/core");
44
+
45
+ // src/sse.ts
46
+ var import_core = require("@restless-stream/core");
47
+
48
+ // src/url.ts
49
+ function appendResumeParams(inputUrl, params) {
50
+ const url = new URL(inputUrl);
51
+ appendResumeParam(url.searchParams, "since", params.since);
52
+ appendResumeParam(url.searchParams, "cursor", params.cursor);
53
+ return url.toString();
54
+ }
55
+ function appendResumeParam(searchParams, key, value) {
56
+ const normalizedValue = value?.toString().trim();
57
+ if (normalizedValue !== void 0 && normalizedValue !== "") searchParams.set(key, normalizedValue);
58
+ }
59
+
60
+ // src/sse.ts
61
+ function buildNodeSseUrl(options) {
62
+ return appendResumeParams(options.sseUrl, {
63
+ cursor: options.cursor,
64
+ since: options.since
65
+ });
66
+ }
67
+ function subscribeSse(clientOrOptions, maybeOptions) {
68
+ const client = maybeOptions ? clientOrOptions : clientOrOptions.client ?? (0, import_core.createRestlessClient)(clientOrOptions.clientOptions);
69
+ const options = maybeOptions ?? clientOrOptions;
70
+ const { iterableOptions, urlOptions } = splitSseOptions(options);
71
+ return client.sse(buildNodeSseUrl(urlOptions), iterableOptions);
72
+ }
73
+ function splitSseOptions(options) {
74
+ const { cursor, since, sseUrl } = options;
75
+ const urlOptions = { sseUrl };
76
+ if (cursor !== void 0) urlOptions.cursor = cursor;
77
+ if (since !== void 0) urlOptions.since = since;
78
+ return { iterableOptions: removeUnsafeSseOptions(options), urlOptions };
79
+ }
80
+ function removeUnsafeSseOptions(options) {
81
+ const iterableOptions = {};
82
+ if (options.signal !== void 0) iterableOptions.signal = options.signal;
83
+ if (options.reconnect !== void 0) iterableOptions.reconnect = options.reconnect;
84
+ if (options.reconnectDelayMs !== void 0) iterableOptions.reconnectDelayMs = options.reconnectDelayMs;
85
+ if (options.maxReconnectDelayMs !== void 0) iterableOptions.maxReconnectDelayMs = options.maxReconnectDelayMs;
86
+ return iterableOptions;
87
+ }
88
+
89
+ // src/websocket-subscription.ts
90
+ var import_ws2 = __toESM(require("ws"), 1);
91
+
92
+ // src/websocket-message.ts
93
+ var import_ws = __toESM(require("ws"), 1);
94
+ function parseSocketMessage(data, options, socket) {
95
+ const text = rawDataToText(data);
96
+ const heartbeat = normalizeHeartbeat(text);
97
+ if (heartbeat === "ping") {
98
+ sendApplicationPong(socket);
99
+ return void 0;
100
+ }
101
+ if (heartbeat === "pong") {
102
+ return void 0;
103
+ }
104
+ if (options.parse === false) {
105
+ return text;
106
+ }
107
+ const parser = options.parser ?? defaultParseSocketEvent;
108
+ try {
109
+ return parser(text);
110
+ } catch (textError) {
111
+ try {
112
+ return parser(JSON.parse(text));
113
+ } catch {
114
+ throw textError;
115
+ }
116
+ }
117
+ }
118
+ function extractCursor(event) {
119
+ if (event === null || event === void 0 || typeof event !== "object") {
120
+ return void 0;
121
+ }
122
+ const record = event;
123
+ const cursor = record.cursor ?? record.id ?? record.eventId ?? record.lastEventId;
124
+ if (typeof cursor === "string" && cursor.length > 0) {
125
+ return cursor;
126
+ }
127
+ if (typeof cursor === "number" && Number.isFinite(cursor) && cursor >= 0) {
128
+ return String(Math.trunc(cursor));
129
+ }
130
+ return extractMetaTimestampCursor(record);
131
+ }
132
+ function defaultParseSocketEvent(message) {
133
+ if (typeof message === "string") {
134
+ return JSON.parse(message);
135
+ }
136
+ return message;
137
+ }
138
+ function rawDataToText(data) {
139
+ if (Buffer.isBuffer(data)) {
140
+ return data.toString("utf8");
141
+ }
142
+ if (data instanceof ArrayBuffer) {
143
+ return Buffer.from(data).toString("utf8");
144
+ }
145
+ if (Array.isArray(data)) {
146
+ return Buffer.concat(data).toString("utf8");
147
+ }
148
+ return Buffer.from(data).toString("utf8");
149
+ }
150
+ function extractMetaTimestampCursor(record) {
151
+ const { meta } = record;
152
+ if (meta === null || meta === void 0 || typeof meta !== "object") {
153
+ return void 0;
154
+ }
155
+ const { timestamp } = meta;
156
+ if (typeof timestamp !== "string") {
157
+ return void 0;
158
+ }
159
+ const timestampMs = Date.parse(timestamp);
160
+ return Number.isFinite(timestampMs) && timestampMs >= 0 ? String(Math.trunc(timestampMs)) : void 0;
161
+ }
162
+ function normalizeHeartbeat(text) {
163
+ const trimmed = text.trim().toLowerCase();
164
+ if (trimmed === "ping" || trimmed === '{"type":"ping"}' || trimmed === '{"event":"ping"}') {
165
+ return "ping";
166
+ }
167
+ if (trimmed === "pong" || trimmed === '{"type":"pong"}' || trimmed === '{"event":"pong"}') {
168
+ return "pong";
169
+ }
170
+ return void 0;
171
+ }
172
+ function sendApplicationPong(socket) {
173
+ if (socket.readyState === import_ws.default.OPEN) {
174
+ socket.send("pong", { binary: false });
175
+ }
176
+ }
177
+
178
+ // src/websocket-options.ts
179
+ var DEFAULT_RECONNECT_OPTIONS = {
180
+ enabled: true,
181
+ factor: 2,
182
+ initialDelayMs: 250,
183
+ maxDelayMs: 5e3,
184
+ maxRetries: Number.POSITIVE_INFINITY
185
+ };
186
+ function normalizeReconnectOptions(reconnect) {
187
+ if (reconnect === false) {
188
+ return { ...DEFAULT_RECONNECT_OPTIONS, enabled: false };
189
+ }
190
+ if (reconnect === true || reconnect === void 0) {
191
+ return DEFAULT_RECONNECT_OPTIONS;
192
+ }
193
+ return {
194
+ enabled: reconnect.enabled ?? DEFAULT_RECONNECT_OPTIONS.enabled,
195
+ factor: reconnect.factor ?? DEFAULT_RECONNECT_OPTIONS.factor,
196
+ initialDelayMs: reconnect.initialDelayMs ?? DEFAULT_RECONNECT_OPTIONS.initialDelayMs,
197
+ maxDelayMs: reconnect.maxDelayMs ?? DEFAULT_RECONNECT_OPTIONS.maxDelayMs,
198
+ maxRetries: reconnect.maxRetries ?? DEFAULT_RECONNECT_OPTIONS.maxRetries
199
+ };
200
+ }
201
+ function resolveWebSocketUrl(options) {
202
+ const url = options.wsUrl ?? options.websocketUrl ?? options.url;
203
+ if (url === void 0 || url === "") {
204
+ throw new TypeError("A WebSocket URL is required. Pass wsUrl, websocketUrl, or url.");
205
+ }
206
+ return url;
207
+ }
208
+ function buildClientOptions(options) {
209
+ const clientOptions = { ...options.clientOptions };
210
+ const headers = {
211
+ ...coerceHeaders(options.clientOptions?.headers),
212
+ ...options.headers
213
+ };
214
+ const apiKey = options.apiKey?.trim();
215
+ if (apiKey !== void 0 && apiKey !== "" && !hasAuthorizationHeader(headers)) {
216
+ headers.Authorization = `Bearer ${apiKey}`;
217
+ }
218
+ if (Object.keys(headers).length > 0) {
219
+ clientOptions.headers = headers;
220
+ }
221
+ return clientOptions;
222
+ }
223
+ function coerceHeaders(headers) {
224
+ if (headers === void 0) {
225
+ return {};
226
+ }
227
+ return Object.fromEntries(
228
+ Object.entries(headers).map(([key, value]) => [key, Array.isArray(value) ? value.join(", ") : String(value)])
229
+ );
230
+ }
231
+ function hasAuthorizationHeader(headers) {
232
+ return Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
233
+ }
234
+ async function sleep(delayMs) {
235
+ return new Promise((resolve) => {
236
+ const timeout = setTimeout(resolve, delayMs);
237
+ timeout.unref?.();
238
+ });
239
+ }
240
+
241
+ // src/websocket-subscription.ts
242
+ var WebSocketSubscription = class {
243
+ options;
244
+ reconnectOptions;
245
+ pending = [];
246
+ queue = [];
247
+ abortHandler;
248
+ closed = false;
249
+ currentSocket;
250
+ failure;
251
+ lastCursor;
252
+ reconnectAttempts = 0;
253
+ started = false;
254
+ constructor(options) {
255
+ this.options = options;
256
+ this.reconnectOptions = normalizeReconnectOptions(options.reconnect);
257
+ this.lastCursor = options.cursor;
258
+ }
259
+ async next() {
260
+ this.start();
261
+ if (this.queue.length > 0) return { done: false, value: this.queue.shift() };
262
+ if (this.failure !== void 0) throw this.failure;
263
+ if (this.closed) return { done: true, value: void 0 };
264
+ return new Promise((resolve, reject) => {
265
+ this.pending.push({ reject, resolve });
266
+ });
267
+ }
268
+ async return() {
269
+ this.close();
270
+ return done();
271
+ }
272
+ async throw(error) {
273
+ this.fail(error ?? new Error("WebSocket subscription iterator was interrupted."));
274
+ return done();
275
+ }
276
+ start() {
277
+ if (this.started) return;
278
+ this.started = true;
279
+ if (this.options.signal?.aborted) {
280
+ this.close();
281
+ return;
282
+ }
283
+ if (this.options.signal) {
284
+ this.abortHandler = () => {
285
+ this.close();
286
+ };
287
+ this.options.signal.addEventListener("abort", this.abortHandler, {
288
+ once: true
289
+ });
290
+ }
291
+ void this.run();
292
+ }
293
+ async run() {
294
+ while (!this.closed) {
295
+ const socket = this.createSocket();
296
+ this.currentSocket = socket;
297
+ const closeInfo = await this.consumeSocket(socket);
298
+ this.currentSocket = void 0;
299
+ if (this.closed) {
300
+ break;
301
+ }
302
+ if (!this.shouldReconnect(closeInfo)) {
303
+ if (closeInfo.error !== void 0) {
304
+ this.fail(closeInfo.error);
305
+ } else {
306
+ this.close();
307
+ }
308
+ return;
309
+ }
310
+ this.reconnectAttempts += 1;
311
+ await sleep(this.reconnectDelayMs(this.reconnectAttempts));
312
+ }
313
+ this.close();
314
+ }
315
+ createSocket() {
316
+ const url = appendResumeParams(resolveWebSocketUrl(this.options), {
317
+ cursor: this.lastCursor,
318
+ since: this.lastCursor !== void 0 && this.lastCursor !== "" ? void 0 : this.options.since
319
+ });
320
+ const clientOptions = buildClientOptions(this.options);
321
+ return this.options.protocols === void 0 ? new import_ws2.default(url, clientOptions) : new import_ws2.default(url, this.options.protocols, clientOptions);
322
+ }
323
+ async consumeSocket(socket) {
324
+ return new Promise((resolve) => {
325
+ this.attachSocketHandlers(socket, resolve);
326
+ });
327
+ }
328
+ attachSocketHandlers(socket, resolve) {
329
+ let settled = false;
330
+ let opened = false;
331
+ let lastError;
332
+ const settle = (info) => {
333
+ if (settled) return;
334
+ settled = true;
335
+ socket.off("close", onClose);
336
+ socket.off("error", onError);
337
+ socket.off("message", onMessage);
338
+ socket.off("open", onOpen);
339
+ socket.off("ping", onPing);
340
+ socket.off("pong", onPong);
341
+ resolve(info);
342
+ };
343
+ const onOpen = () => {
344
+ opened = true;
345
+ };
346
+ const onError = (error) => {
347
+ lastError = error;
348
+ if (!opened) settle({ error });
349
+ };
350
+ const onClose = (code) => {
351
+ settle({ code, error: lastError });
352
+ };
353
+ const onMessage = (data) => {
354
+ this.handleMessage(data, socket);
355
+ };
356
+ const onPing = () => {
357
+ };
358
+ const onPong = () => {
359
+ };
360
+ socket.on("open", onOpen);
361
+ socket.on("error", onError);
362
+ socket.on("close", onClose);
363
+ socket.on("message", onMessage);
364
+ socket.on("ping", onPing);
365
+ socket.on("pong", onPong);
366
+ }
367
+ handleMessage(data, socket) {
368
+ try {
369
+ const event = parseSocketMessage(data, this.options, socket);
370
+ if (event === void 0) return;
371
+ this.lastCursor = extractCursor(event) ?? this.lastCursor;
372
+ this.push(event);
373
+ } catch (error) {
374
+ this.fail(error);
375
+ }
376
+ }
377
+ push(event) {
378
+ const pending = this.pending.shift();
379
+ if (pending !== void 0) {
380
+ pending.resolve({ done: false, value: event });
381
+ return;
382
+ }
383
+ this.queue.push(event);
384
+ }
385
+ fail(error) {
386
+ this.closed = true;
387
+ this.failure = error;
388
+ this.closeSocket();
389
+ this.removeAbortHandler();
390
+ for (const pending of this.pending.splice(0)) {
391
+ pending.reject(error);
392
+ }
393
+ }
394
+ close() {
395
+ if (this.closed) {
396
+ return;
397
+ }
398
+ this.closed = true;
399
+ this.closeSocket();
400
+ this.removeAbortHandler();
401
+ for (const pending of this.pending.splice(0)) {
402
+ pending.resolve({ done: true, value: void 0 });
403
+ }
404
+ }
405
+ closeSocket() {
406
+ if (this.currentSocket === void 0) {
407
+ return;
408
+ }
409
+ const socket = this.currentSocket;
410
+ if (socket.readyState === import_ws2.default.CONNECTING || socket.readyState === import_ws2.default.OPEN) {
411
+ socket.close();
412
+ }
413
+ this.currentSocket = void 0;
414
+ }
415
+ removeAbortHandler() {
416
+ if (this.abortHandler !== void 0 && this.options.signal !== void 0) {
417
+ this.options.signal.removeEventListener("abort", this.abortHandler);
418
+ }
419
+ }
420
+ shouldReconnect(info) {
421
+ if (!this.reconnectOptions.enabled || this.closed) {
422
+ return false;
423
+ }
424
+ if (this.reconnectAttempts >= this.reconnectOptions.maxRetries) {
425
+ return false;
426
+ }
427
+ return info.error !== void 0 ? true : info.code !== void 0 && info.code !== 1e3 && info.code !== 1001;
428
+ }
429
+ reconnectDelayMs(attempt) {
430
+ return Math.min(
431
+ this.reconnectOptions.maxDelayMs,
432
+ this.reconnectOptions.initialDelayMs * this.reconnectOptions.factor ** Math.max(0, attempt - 1)
433
+ );
434
+ }
435
+ };
436
+ var done = () => ({
437
+ done: true,
438
+ value: void 0
439
+ });
440
+
441
+ // src/websocket.ts
442
+ function subscribeWebSocket(options) {
443
+ return {
444
+ [Symbol.asyncIterator]() {
445
+ return new WebSocketSubscription(options);
446
+ }
447
+ };
448
+ }
449
+
450
+ // src/client.ts
451
+ function createNodeRestlessClient(options) {
452
+ const coreClient = (0, import_core2.createRestlessClient)(options);
453
+ const subscribeWebSocketWithDefaults = (subscriptionOptions) => {
454
+ const mergedOptions = {
455
+ ...subscriptionOptions
456
+ };
457
+ if (mergedOptions.apiKey === void 0 && options.apiKey !== void 0) {
458
+ mergedOptions.apiKey = options.apiKey;
459
+ }
460
+ return subscribeWebSocket(mergedOptions);
461
+ };
462
+ const streams = {
463
+ ...coreClient.streams,
464
+ subscribeSse: (subscriptionOptions) => subscribeSse(coreClient, subscriptionOptions),
465
+ subscribeWebSocket: subscribeWebSocketWithDefaults,
466
+ subscribeWs: subscribeWebSocketWithDefaults
467
+ };
468
+ const direct = {
469
+ ...coreClient.direct,
470
+ subscribeWebSocket(input, directOptions = {}) {
471
+ const { cursor, since, ...websocketOptions } = directOptions;
472
+ const nodeOptions = {
473
+ ...websocketOptions,
474
+ wsUrl: coreClient.urls.directWebSocket(input)
475
+ };
476
+ if (cursor !== void 0) nodeOptions.cursor = cursor.toString();
477
+ if (since !== void 0) nodeOptions.since = since.toString();
478
+ return subscribeWebSocketWithDefaults(nodeOptions);
479
+ }
480
+ };
481
+ return new Proxy(coreClient, {
482
+ get(target, property, receiver) {
483
+ if (property === "streams") {
484
+ return streams;
485
+ }
486
+ if (property === "direct") {
487
+ return direct;
488
+ }
489
+ if (property === "subscribeWebSocket" || property === "subscribeWs") {
490
+ return subscribeWebSocketWithDefaults;
491
+ }
492
+ if (property === "subscribeSse") {
493
+ return (subscriptionOptions) => subscribeSse(coreClient, subscriptionOptions);
494
+ }
495
+ return Reflect.get(target, property, receiver);
496
+ }
497
+ });
498
+ }
499
+ // Annotate the CommonJS export names for ESM import in node:
500
+ 0 && (module.exports = {
501
+ buildNodeSseUrl,
502
+ createNodeRestlessClient,
503
+ subscribeSse,
504
+ subscribeWebSocket,
505
+ ...require("@restless-stream/core")
506
+ });
507
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/sse.ts","../src/url.ts","../src/websocket-subscription.ts","../src/websocket-message.ts","../src/websocket-options.ts","../src/websocket.ts"],"sourcesContent":["export * from '@restless-stream/core';\nexport { createNodeRestlessClient } from './client.js';\nexport { buildNodeSseUrl, subscribeSse } from './sse.js';\nexport type {\n CoreRestlessClientOptions,\n NodeRestlessClient,\n NodeRestlessClientOptions,\n NodeDirectClient,\n NodeSseHelperOptions,\n NodeSseSubscriptionOptions,\n NodeStreamsClient,\n NodeWebSocketReconnectOptions,\n NodeWebSocketSubscriptionOptions,\n} from './types.js';\nexport { subscribeWebSocket } from './websocket.js';\n","import {\n createRestlessClient,\n type DirectRuntimeUrlInput,\n type DirectSubscribeWebSocketOptions,\n} from '@restless-stream/core';\n\nimport type { NodeRestlessClient, NodeRestlessClientOptions, NodeWebSocketSubscriptionOptions } from './types.js';\n\nimport { subscribeSse } from './sse.js';\nimport { subscribeWebSocket } from './websocket.js';\n\nexport function createNodeRestlessClient(options: NodeRestlessClientOptions): NodeRestlessClient {\n const coreClient = createRestlessClient(options);\n\n const subscribeWebSocketWithDefaults = <TEvent>(subscriptionOptions: NodeWebSocketSubscriptionOptions<TEvent>) => {\n const mergedOptions: NodeWebSocketSubscriptionOptions<TEvent> = {\n ...subscriptionOptions,\n };\n\n if (mergedOptions.apiKey === undefined && options.apiKey !== undefined) {\n mergedOptions.apiKey = options.apiKey;\n }\n\n return subscribeWebSocket<TEvent>(mergedOptions);\n };\n\n const streams = {\n ...coreClient.streams,\n subscribeSse: (subscriptionOptions: Parameters<NodeRestlessClient['streams']['subscribeSse']>[0]) =>\n subscribeSse(coreClient, subscriptionOptions),\n subscribeWebSocket: subscribeWebSocketWithDefaults,\n subscribeWs: subscribeWebSocketWithDefaults,\n } satisfies NodeRestlessClient['streams'];\n\n const direct = {\n ...coreClient.direct,\n subscribeWebSocket<TEvent = unknown>(\n input: DirectRuntimeUrlInput,\n directOptions: DirectSubscribeWebSocketOptions = {},\n ) {\n const { cursor, since, ...websocketOptions } = directOptions;\n const nodeOptions: NodeWebSocketSubscriptionOptions<TEvent> = {\n ...websocketOptions,\n wsUrl: coreClient.urls.directWebSocket(input),\n };\n if (cursor !== undefined) nodeOptions.cursor = cursor.toString();\n if (since !== undefined) nodeOptions.since = since.toString();\n return subscribeWebSocketWithDefaults<TEvent>(nodeOptions);\n },\n } satisfies NodeRestlessClient['direct'];\n\n return new Proxy(coreClient, {\n get(target, property, receiver) {\n if (property === 'streams') {\n return streams;\n }\n\n if (property === 'direct') {\n return direct;\n }\n\n if (property === 'subscribeWebSocket' || property === 'subscribeWs') {\n return subscribeWebSocketWithDefaults;\n }\n\n if (property === 'subscribeSse') {\n return (subscriptionOptions: Parameters<NodeRestlessClient['subscribeSse']>[0]) =>\n subscribeSse(coreClient, subscriptionOptions);\n }\n\n return Reflect.get(target, property, receiver);\n },\n }) as NodeRestlessClient;\n}\n","import {\n createRestlessClient,\n type RestlessClient,\n type SseIterableOptions,\n type SseMessage,\n type StreamEvent,\n} from '@restless-stream/core';\n\nimport type { NodeSseHelperOptions, NodeSseSubscriptionOptions } from './types.js';\n\nimport { appendResumeParams } from './url.js';\n\ntype UnsafeSseOptions = Partial<Pick<SseIterableOptions, 'fetch' | 'headers' | 'url'>>;\ntype SafeSseIterableOptions = Omit<SseIterableOptions, 'cursor' | 'fetch' | 'headers' | 'since' | 'url'>;\ntype NodeSseUrlOptions = Pick<NodeSseSubscriptionOptions, 'sseUrl' | 'cursor' | 'since'>;\n\nexport function buildNodeSseUrl(options: NodeSseUrlOptions): string {\n return appendResumeParams(options.sseUrl, {\n cursor: options.cursor,\n since: options.since,\n });\n}\n\nexport function subscribeSse<TData = StreamEvent>(\n client: RestlessClient,\n options: NodeSseSubscriptionOptions,\n): AsyncIterable<SseMessage<TData>>;\nexport function subscribeSse<TData = StreamEvent>(options: NodeSseHelperOptions): AsyncIterable<SseMessage<TData>>;\nexport function subscribeSse<TData = StreamEvent>(\n clientOrOptions: RestlessClient | NodeSseHelperOptions,\n maybeOptions?: NodeSseSubscriptionOptions,\n): AsyncIterable<SseMessage<TData>> {\n const client = maybeOptions\n ? (clientOrOptions as RestlessClient)\n : ((clientOrOptions as NodeSseHelperOptions).client ??\n createRestlessClient((clientOrOptions as NodeSseHelperOptions).clientOptions));\n const options = maybeOptions ?? (clientOrOptions as NodeSseHelperOptions);\n const { iterableOptions, urlOptions } = splitSseOptions(options);\n\n return client.sse<TData>(buildNodeSseUrl(urlOptions), iterableOptions);\n}\n\nfunction splitSseOptions(options: NodeSseHelperOptions): {\n iterableOptions: SafeSseIterableOptions;\n urlOptions: NodeSseUrlOptions;\n} {\n const { cursor, since, sseUrl } = options;\n const urlOptions: NodeSseUrlOptions = { sseUrl };\n if (cursor !== undefined) urlOptions.cursor = cursor;\n if (since !== undefined) urlOptions.since = since;\n\n return { iterableOptions: removeUnsafeSseOptions(options), urlOptions };\n}\n\nfunction removeUnsafeSseOptions(options: NodeSseHelperOptions & UnsafeSseOptions): SafeSseIterableOptions {\n const iterableOptions: SafeSseIterableOptions = {};\n if (options.signal !== undefined) iterableOptions.signal = options.signal;\n if (options.reconnect !== undefined) iterableOptions.reconnect = options.reconnect;\n if (options.reconnectDelayMs !== undefined) iterableOptions.reconnectDelayMs = options.reconnectDelayMs;\n if (options.maxReconnectDelayMs !== undefined) iterableOptions.maxReconnectDelayMs = options.maxReconnectDelayMs;\n return iterableOptions;\n}\n","type ResumeParam = number | string | undefined;\n\ninterface ResumeParams {\n cursor?: ResumeParam;\n since?: ResumeParam;\n}\n\nexport function appendResumeParams(inputUrl: string, params: ResumeParams): string {\n const url = new URL(inputUrl);\n\n appendResumeParam(url.searchParams, 'since', params.since);\n appendResumeParam(url.searchParams, 'cursor', params.cursor);\n\n return url.toString();\n}\n\nfunction appendResumeParam(searchParams: URLSearchParams, key: string, value: ResumeParam): void {\n const normalizedValue = value?.toString().trim();\n if (normalizedValue !== undefined && normalizedValue !== '') searchParams.set(key, normalizedValue);\n}\n\nexport function normalizeWebSocketUrl(inputUrl: string): string {\n if (inputUrl.startsWith('https://')) {\n return `wss://${inputUrl.slice('https://'.length)}`;\n }\n\n if (inputUrl.startsWith('http://')) {\n return `ws://${inputUrl.slice('http://'.length)}`;\n }\n\n return inputUrl;\n}\n","import WebSocket from 'ws';\n\nimport type { NodeWebSocketReconnectOptions, NodeWebSocketSubscriptionOptions } from './types.js';\nimport type { CloseInfo, PendingNext } from './websocket-types.js';\n\nimport { appendResumeParams } from './url.js';\nimport { extractCursor, parseSocketMessage } from './websocket-message.js';\nimport { buildClientOptions, normalizeReconnectOptions, resolveWebSocketUrl, sleep } from './websocket-options.js';\n\nexport class WebSocketSubscription<TEvent> implements AsyncIterator<TEvent> {\n private readonly options: NodeWebSocketSubscriptionOptions<TEvent>;\n private readonly reconnectOptions: Required<NodeWebSocketReconnectOptions>;\n private readonly pending: Array<PendingNext<TEvent>> = [];\n private readonly queue: TEvent[] = [];\n private abortHandler?: () => void;\n private closed = false;\n private currentSocket: WebSocket | undefined;\n private failure?: unknown;\n private lastCursor: string | undefined;\n private reconnectAttempts = 0;\n private started = false;\n\n constructor(options: NodeWebSocketSubscriptionOptions<TEvent>) {\n this.options = options;\n this.reconnectOptions = normalizeReconnectOptions(options.reconnect);\n this.lastCursor = options.cursor;\n }\n\n async next(): Promise<IteratorResult<TEvent>> {\n this.start();\n\n if (this.queue.length > 0) return { done: false, value: this.queue.shift() as TEvent };\n if (this.failure !== undefined) throw this.failure;\n if (this.closed) return { done: true, value: undefined };\n\n return new Promise<IteratorResult<TEvent>>((resolve, reject) => {\n this.pending.push({ reject, resolve });\n });\n }\n\n async return(): Promise<IteratorResult<TEvent>> {\n this.close();\n return done();\n }\n\n async throw(error?: unknown): Promise<IteratorResult<TEvent>> {\n this.fail(error ?? new Error('WebSocket subscription iterator was interrupted.'));\n return done();\n }\n\n private start(): void {\n if (this.started) return;\n this.started = true;\n\n if (this.options.signal?.aborted) {\n this.close();\n return;\n }\n\n if (this.options.signal) {\n this.abortHandler = () => {\n this.close();\n };\n\n this.options.signal.addEventListener('abort', this.abortHandler, {\n once: true,\n });\n }\n\n void this.run();\n }\n\n private async run(): Promise<void> {\n while (!this.closed) {\n const socket = this.createSocket();\n this.currentSocket = socket;\n const closeInfo = await this.consumeSocket(socket);\n this.currentSocket = undefined;\n\n if (this.closed) {\n break;\n }\n\n if (!this.shouldReconnect(closeInfo)) {\n if (closeInfo.error !== undefined) {\n this.fail(closeInfo.error);\n } else {\n this.close();\n }\n\n return;\n }\n\n this.reconnectAttempts += 1;\n await sleep(this.reconnectDelayMs(this.reconnectAttempts));\n }\n\n this.close();\n }\n\n private createSocket(): WebSocket {\n const url = appendResumeParams(resolveWebSocketUrl(this.options), {\n cursor: this.lastCursor,\n since: this.lastCursor !== undefined && this.lastCursor !== '' ? undefined : this.options.since,\n });\n const clientOptions = buildClientOptions(this.options);\n\n return this.options.protocols === undefined\n ? new WebSocket(url, clientOptions)\n : new WebSocket(url, this.options.protocols, clientOptions);\n }\n\n private async consumeSocket(socket: WebSocket): Promise<CloseInfo> {\n return new Promise<CloseInfo>((resolve) => {\n this.attachSocketHandlers(socket, resolve);\n });\n }\n\n private attachSocketHandlers(socket: WebSocket, resolve: (info: CloseInfo) => void): void {\n let settled = false;\n let opened = false;\n let lastError: unknown;\n\n const settle = (info: CloseInfo) => {\n if (settled) return;\n settled = true;\n socket.off('close', onClose);\n socket.off('error', onError);\n socket.off('message', onMessage);\n socket.off('open', onOpen);\n socket.off('ping', onPing);\n socket.off('pong', onPong);\n resolve(info);\n };\n\n const onOpen = () => {\n opened = true;\n };\n\n const onError = (error: unknown) => {\n lastError = error;\n if (!opened) settle({ error });\n };\n\n const onClose = (code: number) => {\n settle({ code, error: lastError });\n };\n\n const onMessage = (data: WebSocket.RawData) => {\n this.handleMessage(data, socket);\n };\n\n const onPing = () => {};\n const onPong = () => {};\n\n socket.on('open', onOpen);\n socket.on('error', onError);\n socket.on('close', onClose);\n socket.on('message', onMessage);\n socket.on('ping', onPing);\n socket.on('pong', onPong);\n }\n\n private handleMessage(data: WebSocket.RawData, socket: WebSocket): void {\n try {\n const event = parseSocketMessage(data, this.options, socket);\n if (event === undefined) return;\n\n this.lastCursor = extractCursor(event) ?? this.lastCursor;\n this.push(event);\n } catch (error) {\n this.fail(error);\n }\n }\n\n private push(event: TEvent): void {\n const pending = this.pending.shift();\n if (pending !== undefined) {\n pending.resolve({ done: false, value: event });\n return;\n }\n\n this.queue.push(event);\n }\n\n private fail(error: unknown): void {\n this.closed = true;\n this.failure = error;\n this.closeSocket();\n this.removeAbortHandler();\n\n for (const pending of this.pending.splice(0)) {\n pending.reject(error);\n }\n }\n\n private close(): void {\n if (this.closed) {\n return;\n }\n\n this.closed = true;\n this.closeSocket();\n this.removeAbortHandler();\n\n for (const pending of this.pending.splice(0)) {\n pending.resolve({ done: true, value: undefined });\n }\n }\n\n private closeSocket(): void {\n if (this.currentSocket === undefined) {\n return;\n }\n\n const socket = this.currentSocket;\n\n if (socket.readyState === WebSocket.CONNECTING || socket.readyState === WebSocket.OPEN) {\n socket.close();\n }\n\n this.currentSocket = undefined;\n }\n\n private removeAbortHandler(): void {\n if (this.abortHandler !== undefined && this.options.signal !== undefined) {\n this.options.signal.removeEventListener('abort', this.abortHandler);\n }\n }\n\n private shouldReconnect(info: CloseInfo): boolean {\n if (!this.reconnectOptions.enabled || this.closed) {\n return false;\n }\n\n if (this.reconnectAttempts >= this.reconnectOptions.maxRetries) {\n return false;\n }\n\n return info.error !== undefined ? true : info.code !== undefined && info.code !== 1000 && info.code !== 1001;\n }\n\n private reconnectDelayMs(attempt: number): number {\n return Math.min(\n this.reconnectOptions.maxDelayMs,\n this.reconnectOptions.initialDelayMs * this.reconnectOptions.factor ** Math.max(0, attempt - 1),\n );\n }\n}\n\nconst done = <TEvent>(): IteratorResult<TEvent> => ({\n done: true,\n value: undefined,\n});\n","import WebSocket, { type RawData } from 'ws';\n\nimport type { NodeWebSocketSubscriptionOptions } from './types.js';\n\nexport function parseSocketMessage<TEvent>(\n data: RawData,\n options: NodeWebSocketSubscriptionOptions<TEvent>,\n socket: WebSocket,\n): TEvent | undefined {\n const text = rawDataToText(data);\n const heartbeat = normalizeHeartbeat(text);\n\n if (heartbeat === 'ping') {\n sendApplicationPong(socket);\n return undefined;\n }\n\n if (heartbeat === 'pong') {\n return undefined;\n }\n\n if (options.parse === false) {\n return text as TEvent;\n }\n\n const parser = options.parser ?? defaultParseSocketEvent<TEvent>;\n\n try {\n return parser(text);\n } catch (textError) {\n try {\n return parser(JSON.parse(text));\n } catch {\n throw textError;\n }\n }\n}\n\nexport function extractCursor(event: unknown): string | undefined {\n if (event === null || event === undefined || typeof event !== 'object') {\n return undefined;\n }\n\n const record = event as Record<string, unknown>;\n const cursor = record.cursor ?? record.id ?? record.eventId ?? record.lastEventId;\n\n if (typeof cursor === 'string' && cursor.length > 0) {\n return cursor;\n }\n\n if (typeof cursor === 'number' && Number.isFinite(cursor) && cursor >= 0) {\n return String(Math.trunc(cursor));\n }\n\n return extractMetaTimestampCursor(record);\n}\n\nfunction defaultParseSocketEvent<TEvent>(message: unknown): TEvent {\n if (typeof message === 'string') {\n return JSON.parse(message) as TEvent;\n }\n\n return message as TEvent;\n}\n\nfunction rawDataToText(data: RawData): string {\n if (Buffer.isBuffer(data)) {\n return data.toString('utf8');\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data).toString('utf8');\n }\n\n if (Array.isArray(data)) {\n return Buffer.concat(data).toString('utf8');\n }\n\n return Buffer.from(data).toString('utf8');\n}\n\nfunction extractMetaTimestampCursor(record: Record<string, unknown>): string | undefined {\n const { meta } = record;\n if (meta === null || meta === undefined || typeof meta !== 'object') {\n return undefined;\n }\n\n const { timestamp } = meta as Record<string, unknown>;\n if (typeof timestamp !== 'string') {\n return undefined;\n }\n\n const timestampMs = Date.parse(timestamp);\n return Number.isFinite(timestampMs) && timestampMs >= 0 ? String(Math.trunc(timestampMs)) : undefined;\n}\n\nfunction normalizeHeartbeat(text: string): 'ping' | 'pong' | undefined {\n const trimmed = text.trim().toLowerCase();\n\n if (trimmed === 'ping' || trimmed === '{\"type\":\"ping\"}' || trimmed === '{\"event\":\"ping\"}') {\n return 'ping';\n }\n\n if (trimmed === 'pong' || trimmed === '{\"type\":\"pong\"}' || trimmed === '{\"event\":\"pong\"}') {\n return 'pong';\n }\n\n return undefined;\n}\n\nfunction sendApplicationPong(socket: WebSocket): void {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send('pong', { binary: false });\n }\n}\n","import type { ClientOptions } from 'ws';\n\nimport type { NodeWebSocketReconnectOptions, NodeWebSocketSubscriptionOptions } from './types.js';\n\nexport const DEFAULT_RECONNECT_OPTIONS: Required<NodeWebSocketReconnectOptions> = {\n enabled: true,\n factor: 2,\n initialDelayMs: 250,\n maxDelayMs: 5000,\n maxRetries: Number.POSITIVE_INFINITY,\n};\n\nexport function normalizeReconnectOptions(\n reconnect: boolean | NodeWebSocketReconnectOptions | undefined,\n): Required<NodeWebSocketReconnectOptions> {\n if (reconnect === false) {\n return { ...DEFAULT_RECONNECT_OPTIONS, enabled: false };\n }\n\n if (reconnect === true || reconnect === undefined) {\n return DEFAULT_RECONNECT_OPTIONS;\n }\n\n return {\n enabled: reconnect.enabled ?? DEFAULT_RECONNECT_OPTIONS.enabled,\n factor: reconnect.factor ?? DEFAULT_RECONNECT_OPTIONS.factor,\n initialDelayMs: reconnect.initialDelayMs ?? DEFAULT_RECONNECT_OPTIONS.initialDelayMs,\n maxDelayMs: reconnect.maxDelayMs ?? DEFAULT_RECONNECT_OPTIONS.maxDelayMs,\n maxRetries: reconnect.maxRetries ?? DEFAULT_RECONNECT_OPTIONS.maxRetries,\n };\n}\n\nexport function resolveWebSocketUrl(options: NodeWebSocketSubscriptionOptions<unknown>): string {\n const url = options.wsUrl ?? options.websocketUrl ?? options.url;\n\n if (url === undefined || url === '') {\n throw new TypeError('A WebSocket URL is required. Pass wsUrl, websocketUrl, or url.');\n }\n\n return url;\n}\n\nexport function buildClientOptions(options: NodeWebSocketSubscriptionOptions<unknown>): ClientOptions {\n const clientOptions: ClientOptions = { ...options.clientOptions };\n const headers = {\n ...coerceHeaders(options.clientOptions?.headers),\n ...options.headers,\n };\n\n const apiKey = options.apiKey?.trim();\n if (apiKey !== undefined && apiKey !== '' && !hasAuthorizationHeader(headers)) {\n headers.Authorization = `Bearer ${apiKey}`;\n }\n\n if (Object.keys(headers).length > 0) {\n clientOptions.headers = headers;\n }\n\n return clientOptions;\n}\n\nfunction coerceHeaders(headers: ClientOptions['headers']): Record<string, string> {\n if (headers === undefined) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(headers).map(([key, value]) => [key, Array.isArray(value) ? value.join(', ') : String(value)]),\n );\n}\n\nfunction hasAuthorizationHeader(headers: Record<string, string>): boolean {\n return Object.keys(headers).some((key) => key.toLowerCase() === 'authorization');\n}\n\nexport async function sleep(delayMs: number): Promise<void> {\n return new Promise((resolve) => {\n const timeout = setTimeout(resolve, delayMs);\n timeout.unref?.();\n });\n}\n","import type { StreamEvent } from '@restless-stream/core';\n\nimport type { NodeWebSocketSubscriptionOptions } from './types.js';\n\nimport { WebSocketSubscription } from './websocket-subscription.js';\n\nexport function subscribeWebSocket<TEvent = StreamEvent>(\n options: NodeWebSocketSubscriptionOptions<TEvent>,\n): AsyncIterable<TEvent> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<TEvent> {\n return new WebSocketSubscription(options);\n },\n };\n}\n"],"mappings":"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","names":["import_core","import_ws","WebSocket","WebSocket"]}
@@ -0,0 +1,85 @@
1
+ import { createRestlessClient, RestlessClient, StreamEvent, DirectRuntimeUrlInput, DirectSubscribeWebSocketOptions, SseIterableOptions, SseMessage } from '@restless-stream/core';
2
+ export * from '@restless-stream/core';
3
+ import { ClientOptions } from 'ws';
4
+
5
+ type CoreRestlessClientOptions = Parameters<typeof createRestlessClient>[0];
6
+ type NodeRestlessClientOptions = CoreRestlessClientOptions & {
7
+ /** API key used as the default Bearer token for Node WebSocket subscriptions. */
8
+ apiKey?: string;
9
+ };
10
+ interface NodeWebSocketReconnectOptions {
11
+ /** Enables reconnects after abnormal closes and connection errors. Defaults to true. */
12
+ enabled?: boolean;
13
+ /** Maximum reconnect attempts. Use `Infinity` for an unbounded stream. Defaults to Infinity. */
14
+ maxRetries?: number;
15
+ /** First reconnect delay in milliseconds. Defaults to 250. */
16
+ initialDelayMs?: number;
17
+ /** Maximum reconnect delay in milliseconds. Defaults to 5000. */
18
+ maxDelayMs?: number;
19
+ /** Exponential backoff multiplier. Defaults to 2. */
20
+ factor?: number;
21
+ }
22
+ interface NodeWebSocketSubscriptionOptions<TEvent = StreamEvent> {
23
+ /** WebSocket URL returned by Restless Stream. */
24
+ wsUrl?: string;
25
+ /** Alias for `wsUrl`. */
26
+ websocketUrl?: string;
27
+ /** Alias for `wsUrl`; useful when adapting generic stream records. */
28
+ url?: string;
29
+ /** API key sent as `Authorization: Bearer <apiKey>` unless an Authorization header is provided. */
30
+ apiKey?: string;
31
+ /** Optional WebSocket subprotocol or subprotocol list. */
32
+ protocols?: string | string[];
33
+ /** Additional headers for the Node WebSocket handshake. */
34
+ headers?: Record<string, string>;
35
+ /** Abort signal used to cancel the async iterator and close the socket. */
36
+ signal?: AbortSignal;
37
+ /** Initial cursor to resume from. Updated automatically from yielded events on reconnect. */
38
+ cursor?: string;
39
+ /** Initial timestamp/id to resume from when no cursor has been observed yet. */
40
+ since?: string;
41
+ /** Reconnect policy for abnormal closes and connection errors. */
42
+ reconnect?: boolean | NodeWebSocketReconnectOptions;
43
+ /** Extra options passed to the `ws` client. */
44
+ clientOptions?: ClientOptions;
45
+ /** Disable core parsing and yield raw text frames instead. Defaults to true. */
46
+ parse?: boolean;
47
+ /** Override event parsing while keeping reconnect/cancellation behavior. */
48
+ parser?: (message: unknown) => TEvent;
49
+ }
50
+ interface NodeSseSubscriptionOptions extends Omit<SseIterableOptions, 'fetch' | 'headers' | 'url'> {
51
+ /** SSE URL returned by Restless Stream. */
52
+ sseUrl: string;
53
+ }
54
+ interface NodeSseHelperOptions extends NodeSseSubscriptionOptions {
55
+ /** Existing core client to delegate to. */
56
+ client?: RestlessClient;
57
+ /** Options used to create a core client when `client` is omitted. */
58
+ clientOptions?: CoreRestlessClientOptions;
59
+ }
60
+ interface NodeStreamsClient extends Omit<RestlessClient['streams'], 'subscribeSse' | 'subscribeWebSocket'> {
61
+ subscribeWebSocket<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
62
+ subscribeWs<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
63
+ subscribeSse<TData = StreamEvent>(options: NodeSseSubscriptionOptions): AsyncIterable<SseMessage<TData>>;
64
+ }
65
+ interface NodeDirectClient extends Omit<RestlessClient['direct'], 'subscribeWebSocket'> {
66
+ subscribeWebSocket<TEvent = StreamEvent>(input: DirectRuntimeUrlInput, options?: DirectSubscribeWebSocketOptions): AsyncIterable<TEvent>;
67
+ }
68
+ type NodeRestlessClient = Omit<RestlessClient, 'streams' | 'subscribeSse' | 'subscribeWebSocket'> & {
69
+ readonly direct: NodeDirectClient;
70
+ readonly streams: NodeStreamsClient;
71
+ subscribeWebSocket<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
72
+ subscribeWs<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
73
+ subscribeSse<TData = StreamEvent>(options: NodeSseSubscriptionOptions): AsyncIterable<SseMessage<TData>>;
74
+ };
75
+
76
+ declare function createNodeRestlessClient(options: NodeRestlessClientOptions): NodeRestlessClient;
77
+
78
+ type NodeSseUrlOptions = Pick<NodeSseSubscriptionOptions, 'sseUrl' | 'cursor' | 'since'>;
79
+ declare function buildNodeSseUrl(options: NodeSseUrlOptions): string;
80
+ declare function subscribeSse<TData = StreamEvent>(client: RestlessClient, options: NodeSseSubscriptionOptions): AsyncIterable<SseMessage<TData>>;
81
+ declare function subscribeSse<TData = StreamEvent>(options: NodeSseHelperOptions): AsyncIterable<SseMessage<TData>>;
82
+
83
+ declare function subscribeWebSocket<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
84
+
85
+ export { type CoreRestlessClientOptions, type NodeDirectClient, type NodeRestlessClient, type NodeRestlessClientOptions, type NodeSseHelperOptions, type NodeSseSubscriptionOptions, type NodeStreamsClient, type NodeWebSocketReconnectOptions, type NodeWebSocketSubscriptionOptions, buildNodeSseUrl, createNodeRestlessClient, subscribeSse, subscribeWebSocket };
@@ -0,0 +1,85 @@
1
+ import { createRestlessClient, RestlessClient, StreamEvent, DirectRuntimeUrlInput, DirectSubscribeWebSocketOptions, SseIterableOptions, SseMessage } from '@restless-stream/core';
2
+ export * from '@restless-stream/core';
3
+ import { ClientOptions } from 'ws';
4
+
5
+ type CoreRestlessClientOptions = Parameters<typeof createRestlessClient>[0];
6
+ type NodeRestlessClientOptions = CoreRestlessClientOptions & {
7
+ /** API key used as the default Bearer token for Node WebSocket subscriptions. */
8
+ apiKey?: string;
9
+ };
10
+ interface NodeWebSocketReconnectOptions {
11
+ /** Enables reconnects after abnormal closes and connection errors. Defaults to true. */
12
+ enabled?: boolean;
13
+ /** Maximum reconnect attempts. Use `Infinity` for an unbounded stream. Defaults to Infinity. */
14
+ maxRetries?: number;
15
+ /** First reconnect delay in milliseconds. Defaults to 250. */
16
+ initialDelayMs?: number;
17
+ /** Maximum reconnect delay in milliseconds. Defaults to 5000. */
18
+ maxDelayMs?: number;
19
+ /** Exponential backoff multiplier. Defaults to 2. */
20
+ factor?: number;
21
+ }
22
+ interface NodeWebSocketSubscriptionOptions<TEvent = StreamEvent> {
23
+ /** WebSocket URL returned by Restless Stream. */
24
+ wsUrl?: string;
25
+ /** Alias for `wsUrl`. */
26
+ websocketUrl?: string;
27
+ /** Alias for `wsUrl`; useful when adapting generic stream records. */
28
+ url?: string;
29
+ /** API key sent as `Authorization: Bearer <apiKey>` unless an Authorization header is provided. */
30
+ apiKey?: string;
31
+ /** Optional WebSocket subprotocol or subprotocol list. */
32
+ protocols?: string | string[];
33
+ /** Additional headers for the Node WebSocket handshake. */
34
+ headers?: Record<string, string>;
35
+ /** Abort signal used to cancel the async iterator and close the socket. */
36
+ signal?: AbortSignal;
37
+ /** Initial cursor to resume from. Updated automatically from yielded events on reconnect. */
38
+ cursor?: string;
39
+ /** Initial timestamp/id to resume from when no cursor has been observed yet. */
40
+ since?: string;
41
+ /** Reconnect policy for abnormal closes and connection errors. */
42
+ reconnect?: boolean | NodeWebSocketReconnectOptions;
43
+ /** Extra options passed to the `ws` client. */
44
+ clientOptions?: ClientOptions;
45
+ /** Disable core parsing and yield raw text frames instead. Defaults to true. */
46
+ parse?: boolean;
47
+ /** Override event parsing while keeping reconnect/cancellation behavior. */
48
+ parser?: (message: unknown) => TEvent;
49
+ }
50
+ interface NodeSseSubscriptionOptions extends Omit<SseIterableOptions, 'fetch' | 'headers' | 'url'> {
51
+ /** SSE URL returned by Restless Stream. */
52
+ sseUrl: string;
53
+ }
54
+ interface NodeSseHelperOptions extends NodeSseSubscriptionOptions {
55
+ /** Existing core client to delegate to. */
56
+ client?: RestlessClient;
57
+ /** Options used to create a core client when `client` is omitted. */
58
+ clientOptions?: CoreRestlessClientOptions;
59
+ }
60
+ interface NodeStreamsClient extends Omit<RestlessClient['streams'], 'subscribeSse' | 'subscribeWebSocket'> {
61
+ subscribeWebSocket<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
62
+ subscribeWs<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
63
+ subscribeSse<TData = StreamEvent>(options: NodeSseSubscriptionOptions): AsyncIterable<SseMessage<TData>>;
64
+ }
65
+ interface NodeDirectClient extends Omit<RestlessClient['direct'], 'subscribeWebSocket'> {
66
+ subscribeWebSocket<TEvent = StreamEvent>(input: DirectRuntimeUrlInput, options?: DirectSubscribeWebSocketOptions): AsyncIterable<TEvent>;
67
+ }
68
+ type NodeRestlessClient = Omit<RestlessClient, 'streams' | 'subscribeSse' | 'subscribeWebSocket'> & {
69
+ readonly direct: NodeDirectClient;
70
+ readonly streams: NodeStreamsClient;
71
+ subscribeWebSocket<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
72
+ subscribeWs<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
73
+ subscribeSse<TData = StreamEvent>(options: NodeSseSubscriptionOptions): AsyncIterable<SseMessage<TData>>;
74
+ };
75
+
76
+ declare function createNodeRestlessClient(options: NodeRestlessClientOptions): NodeRestlessClient;
77
+
78
+ type NodeSseUrlOptions = Pick<NodeSseSubscriptionOptions, 'sseUrl' | 'cursor' | 'since'>;
79
+ declare function buildNodeSseUrl(options: NodeSseUrlOptions): string;
80
+ declare function subscribeSse<TData = StreamEvent>(client: RestlessClient, options: NodeSseSubscriptionOptions): AsyncIterable<SseMessage<TData>>;
81
+ declare function subscribeSse<TData = StreamEvent>(options: NodeSseHelperOptions): AsyncIterable<SseMessage<TData>>;
82
+
83
+ declare function subscribeWebSocket<TEvent = StreamEvent>(options: NodeWebSocketSubscriptionOptions<TEvent>): AsyncIterable<TEvent>;
84
+
85
+ export { type CoreRestlessClientOptions, type NodeDirectClient, type NodeRestlessClient, type NodeRestlessClientOptions, type NodeSseHelperOptions, type NodeSseSubscriptionOptions, type NodeStreamsClient, type NodeWebSocketReconnectOptions, type NodeWebSocketSubscriptionOptions, buildNodeSseUrl, createNodeRestlessClient, subscribeSse, subscribeWebSocket };
package/dist/index.js ADDED
@@ -0,0 +1,471 @@
1
+ // src/index.ts
2
+ export * from "@restless-stream/core";
3
+
4
+ // src/client.ts
5
+ import {
6
+ createRestlessClient as createRestlessClient2
7
+ } from "@restless-stream/core";
8
+
9
+ // src/sse.ts
10
+ import {
11
+ createRestlessClient
12
+ } from "@restless-stream/core";
13
+
14
+ // src/url.ts
15
+ function appendResumeParams(inputUrl, params) {
16
+ const url = new URL(inputUrl);
17
+ appendResumeParam(url.searchParams, "since", params.since);
18
+ appendResumeParam(url.searchParams, "cursor", params.cursor);
19
+ return url.toString();
20
+ }
21
+ function appendResumeParam(searchParams, key, value) {
22
+ const normalizedValue = value?.toString().trim();
23
+ if (normalizedValue !== void 0 && normalizedValue !== "") searchParams.set(key, normalizedValue);
24
+ }
25
+
26
+ // src/sse.ts
27
+ function buildNodeSseUrl(options) {
28
+ return appendResumeParams(options.sseUrl, {
29
+ cursor: options.cursor,
30
+ since: options.since
31
+ });
32
+ }
33
+ function subscribeSse(clientOrOptions, maybeOptions) {
34
+ const client = maybeOptions ? clientOrOptions : clientOrOptions.client ?? createRestlessClient(clientOrOptions.clientOptions);
35
+ const options = maybeOptions ?? clientOrOptions;
36
+ const { iterableOptions, urlOptions } = splitSseOptions(options);
37
+ return client.sse(buildNodeSseUrl(urlOptions), iterableOptions);
38
+ }
39
+ function splitSseOptions(options) {
40
+ const { cursor, since, sseUrl } = options;
41
+ const urlOptions = { sseUrl };
42
+ if (cursor !== void 0) urlOptions.cursor = cursor;
43
+ if (since !== void 0) urlOptions.since = since;
44
+ return { iterableOptions: removeUnsafeSseOptions(options), urlOptions };
45
+ }
46
+ function removeUnsafeSseOptions(options) {
47
+ const iterableOptions = {};
48
+ if (options.signal !== void 0) iterableOptions.signal = options.signal;
49
+ if (options.reconnect !== void 0) iterableOptions.reconnect = options.reconnect;
50
+ if (options.reconnectDelayMs !== void 0) iterableOptions.reconnectDelayMs = options.reconnectDelayMs;
51
+ if (options.maxReconnectDelayMs !== void 0) iterableOptions.maxReconnectDelayMs = options.maxReconnectDelayMs;
52
+ return iterableOptions;
53
+ }
54
+
55
+ // src/websocket-subscription.ts
56
+ import WebSocket2 from "ws";
57
+
58
+ // src/websocket-message.ts
59
+ import WebSocket from "ws";
60
+ function parseSocketMessage(data, options, socket) {
61
+ const text = rawDataToText(data);
62
+ const heartbeat = normalizeHeartbeat(text);
63
+ if (heartbeat === "ping") {
64
+ sendApplicationPong(socket);
65
+ return void 0;
66
+ }
67
+ if (heartbeat === "pong") {
68
+ return void 0;
69
+ }
70
+ if (options.parse === false) {
71
+ return text;
72
+ }
73
+ const parser = options.parser ?? defaultParseSocketEvent;
74
+ try {
75
+ return parser(text);
76
+ } catch (textError) {
77
+ try {
78
+ return parser(JSON.parse(text));
79
+ } catch {
80
+ throw textError;
81
+ }
82
+ }
83
+ }
84
+ function extractCursor(event) {
85
+ if (event === null || event === void 0 || typeof event !== "object") {
86
+ return void 0;
87
+ }
88
+ const record = event;
89
+ const cursor = record.cursor ?? record.id ?? record.eventId ?? record.lastEventId;
90
+ if (typeof cursor === "string" && cursor.length > 0) {
91
+ return cursor;
92
+ }
93
+ if (typeof cursor === "number" && Number.isFinite(cursor) && cursor >= 0) {
94
+ return String(Math.trunc(cursor));
95
+ }
96
+ return extractMetaTimestampCursor(record);
97
+ }
98
+ function defaultParseSocketEvent(message) {
99
+ if (typeof message === "string") {
100
+ return JSON.parse(message);
101
+ }
102
+ return message;
103
+ }
104
+ function rawDataToText(data) {
105
+ if (Buffer.isBuffer(data)) {
106
+ return data.toString("utf8");
107
+ }
108
+ if (data instanceof ArrayBuffer) {
109
+ return Buffer.from(data).toString("utf8");
110
+ }
111
+ if (Array.isArray(data)) {
112
+ return Buffer.concat(data).toString("utf8");
113
+ }
114
+ return Buffer.from(data).toString("utf8");
115
+ }
116
+ function extractMetaTimestampCursor(record) {
117
+ const { meta } = record;
118
+ if (meta === null || meta === void 0 || typeof meta !== "object") {
119
+ return void 0;
120
+ }
121
+ const { timestamp } = meta;
122
+ if (typeof timestamp !== "string") {
123
+ return void 0;
124
+ }
125
+ const timestampMs = Date.parse(timestamp);
126
+ return Number.isFinite(timestampMs) && timestampMs >= 0 ? String(Math.trunc(timestampMs)) : void 0;
127
+ }
128
+ function normalizeHeartbeat(text) {
129
+ const trimmed = text.trim().toLowerCase();
130
+ if (trimmed === "ping" || trimmed === '{"type":"ping"}' || trimmed === '{"event":"ping"}') {
131
+ return "ping";
132
+ }
133
+ if (trimmed === "pong" || trimmed === '{"type":"pong"}' || trimmed === '{"event":"pong"}') {
134
+ return "pong";
135
+ }
136
+ return void 0;
137
+ }
138
+ function sendApplicationPong(socket) {
139
+ if (socket.readyState === WebSocket.OPEN) {
140
+ socket.send("pong", { binary: false });
141
+ }
142
+ }
143
+
144
+ // src/websocket-options.ts
145
+ var DEFAULT_RECONNECT_OPTIONS = {
146
+ enabled: true,
147
+ factor: 2,
148
+ initialDelayMs: 250,
149
+ maxDelayMs: 5e3,
150
+ maxRetries: Number.POSITIVE_INFINITY
151
+ };
152
+ function normalizeReconnectOptions(reconnect) {
153
+ if (reconnect === false) {
154
+ return { ...DEFAULT_RECONNECT_OPTIONS, enabled: false };
155
+ }
156
+ if (reconnect === true || reconnect === void 0) {
157
+ return DEFAULT_RECONNECT_OPTIONS;
158
+ }
159
+ return {
160
+ enabled: reconnect.enabled ?? DEFAULT_RECONNECT_OPTIONS.enabled,
161
+ factor: reconnect.factor ?? DEFAULT_RECONNECT_OPTIONS.factor,
162
+ initialDelayMs: reconnect.initialDelayMs ?? DEFAULT_RECONNECT_OPTIONS.initialDelayMs,
163
+ maxDelayMs: reconnect.maxDelayMs ?? DEFAULT_RECONNECT_OPTIONS.maxDelayMs,
164
+ maxRetries: reconnect.maxRetries ?? DEFAULT_RECONNECT_OPTIONS.maxRetries
165
+ };
166
+ }
167
+ function resolveWebSocketUrl(options) {
168
+ const url = options.wsUrl ?? options.websocketUrl ?? options.url;
169
+ if (url === void 0 || url === "") {
170
+ throw new TypeError("A WebSocket URL is required. Pass wsUrl, websocketUrl, or url.");
171
+ }
172
+ return url;
173
+ }
174
+ function buildClientOptions(options) {
175
+ const clientOptions = { ...options.clientOptions };
176
+ const headers = {
177
+ ...coerceHeaders(options.clientOptions?.headers),
178
+ ...options.headers
179
+ };
180
+ const apiKey = options.apiKey?.trim();
181
+ if (apiKey !== void 0 && apiKey !== "" && !hasAuthorizationHeader(headers)) {
182
+ headers.Authorization = `Bearer ${apiKey}`;
183
+ }
184
+ if (Object.keys(headers).length > 0) {
185
+ clientOptions.headers = headers;
186
+ }
187
+ return clientOptions;
188
+ }
189
+ function coerceHeaders(headers) {
190
+ if (headers === void 0) {
191
+ return {};
192
+ }
193
+ return Object.fromEntries(
194
+ Object.entries(headers).map(([key, value]) => [key, Array.isArray(value) ? value.join(", ") : String(value)])
195
+ );
196
+ }
197
+ function hasAuthorizationHeader(headers) {
198
+ return Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
199
+ }
200
+ async function sleep(delayMs) {
201
+ return new Promise((resolve) => {
202
+ const timeout = setTimeout(resolve, delayMs);
203
+ timeout.unref?.();
204
+ });
205
+ }
206
+
207
+ // src/websocket-subscription.ts
208
+ var WebSocketSubscription = class {
209
+ options;
210
+ reconnectOptions;
211
+ pending = [];
212
+ queue = [];
213
+ abortHandler;
214
+ closed = false;
215
+ currentSocket;
216
+ failure;
217
+ lastCursor;
218
+ reconnectAttempts = 0;
219
+ started = false;
220
+ constructor(options) {
221
+ this.options = options;
222
+ this.reconnectOptions = normalizeReconnectOptions(options.reconnect);
223
+ this.lastCursor = options.cursor;
224
+ }
225
+ async next() {
226
+ this.start();
227
+ if (this.queue.length > 0) return { done: false, value: this.queue.shift() };
228
+ if (this.failure !== void 0) throw this.failure;
229
+ if (this.closed) return { done: true, value: void 0 };
230
+ return new Promise((resolve, reject) => {
231
+ this.pending.push({ reject, resolve });
232
+ });
233
+ }
234
+ async return() {
235
+ this.close();
236
+ return done();
237
+ }
238
+ async throw(error) {
239
+ this.fail(error ?? new Error("WebSocket subscription iterator was interrupted."));
240
+ return done();
241
+ }
242
+ start() {
243
+ if (this.started) return;
244
+ this.started = true;
245
+ if (this.options.signal?.aborted) {
246
+ this.close();
247
+ return;
248
+ }
249
+ if (this.options.signal) {
250
+ this.abortHandler = () => {
251
+ this.close();
252
+ };
253
+ this.options.signal.addEventListener("abort", this.abortHandler, {
254
+ once: true
255
+ });
256
+ }
257
+ void this.run();
258
+ }
259
+ async run() {
260
+ while (!this.closed) {
261
+ const socket = this.createSocket();
262
+ this.currentSocket = socket;
263
+ const closeInfo = await this.consumeSocket(socket);
264
+ this.currentSocket = void 0;
265
+ if (this.closed) {
266
+ break;
267
+ }
268
+ if (!this.shouldReconnect(closeInfo)) {
269
+ if (closeInfo.error !== void 0) {
270
+ this.fail(closeInfo.error);
271
+ } else {
272
+ this.close();
273
+ }
274
+ return;
275
+ }
276
+ this.reconnectAttempts += 1;
277
+ await sleep(this.reconnectDelayMs(this.reconnectAttempts));
278
+ }
279
+ this.close();
280
+ }
281
+ createSocket() {
282
+ const url = appendResumeParams(resolveWebSocketUrl(this.options), {
283
+ cursor: this.lastCursor,
284
+ since: this.lastCursor !== void 0 && this.lastCursor !== "" ? void 0 : this.options.since
285
+ });
286
+ const clientOptions = buildClientOptions(this.options);
287
+ return this.options.protocols === void 0 ? new WebSocket2(url, clientOptions) : new WebSocket2(url, this.options.protocols, clientOptions);
288
+ }
289
+ async consumeSocket(socket) {
290
+ return new Promise((resolve) => {
291
+ this.attachSocketHandlers(socket, resolve);
292
+ });
293
+ }
294
+ attachSocketHandlers(socket, resolve) {
295
+ let settled = false;
296
+ let opened = false;
297
+ let lastError;
298
+ const settle = (info) => {
299
+ if (settled) return;
300
+ settled = true;
301
+ socket.off("close", onClose);
302
+ socket.off("error", onError);
303
+ socket.off("message", onMessage);
304
+ socket.off("open", onOpen);
305
+ socket.off("ping", onPing);
306
+ socket.off("pong", onPong);
307
+ resolve(info);
308
+ };
309
+ const onOpen = () => {
310
+ opened = true;
311
+ };
312
+ const onError = (error) => {
313
+ lastError = error;
314
+ if (!opened) settle({ error });
315
+ };
316
+ const onClose = (code) => {
317
+ settle({ code, error: lastError });
318
+ };
319
+ const onMessage = (data) => {
320
+ this.handleMessage(data, socket);
321
+ };
322
+ const onPing = () => {
323
+ };
324
+ const onPong = () => {
325
+ };
326
+ socket.on("open", onOpen);
327
+ socket.on("error", onError);
328
+ socket.on("close", onClose);
329
+ socket.on("message", onMessage);
330
+ socket.on("ping", onPing);
331
+ socket.on("pong", onPong);
332
+ }
333
+ handleMessage(data, socket) {
334
+ try {
335
+ const event = parseSocketMessage(data, this.options, socket);
336
+ if (event === void 0) return;
337
+ this.lastCursor = extractCursor(event) ?? this.lastCursor;
338
+ this.push(event);
339
+ } catch (error) {
340
+ this.fail(error);
341
+ }
342
+ }
343
+ push(event) {
344
+ const pending = this.pending.shift();
345
+ if (pending !== void 0) {
346
+ pending.resolve({ done: false, value: event });
347
+ return;
348
+ }
349
+ this.queue.push(event);
350
+ }
351
+ fail(error) {
352
+ this.closed = true;
353
+ this.failure = error;
354
+ this.closeSocket();
355
+ this.removeAbortHandler();
356
+ for (const pending of this.pending.splice(0)) {
357
+ pending.reject(error);
358
+ }
359
+ }
360
+ close() {
361
+ if (this.closed) {
362
+ return;
363
+ }
364
+ this.closed = true;
365
+ this.closeSocket();
366
+ this.removeAbortHandler();
367
+ for (const pending of this.pending.splice(0)) {
368
+ pending.resolve({ done: true, value: void 0 });
369
+ }
370
+ }
371
+ closeSocket() {
372
+ if (this.currentSocket === void 0) {
373
+ return;
374
+ }
375
+ const socket = this.currentSocket;
376
+ if (socket.readyState === WebSocket2.CONNECTING || socket.readyState === WebSocket2.OPEN) {
377
+ socket.close();
378
+ }
379
+ this.currentSocket = void 0;
380
+ }
381
+ removeAbortHandler() {
382
+ if (this.abortHandler !== void 0 && this.options.signal !== void 0) {
383
+ this.options.signal.removeEventListener("abort", this.abortHandler);
384
+ }
385
+ }
386
+ shouldReconnect(info) {
387
+ if (!this.reconnectOptions.enabled || this.closed) {
388
+ return false;
389
+ }
390
+ if (this.reconnectAttempts >= this.reconnectOptions.maxRetries) {
391
+ return false;
392
+ }
393
+ return info.error !== void 0 ? true : info.code !== void 0 && info.code !== 1e3 && info.code !== 1001;
394
+ }
395
+ reconnectDelayMs(attempt) {
396
+ return Math.min(
397
+ this.reconnectOptions.maxDelayMs,
398
+ this.reconnectOptions.initialDelayMs * this.reconnectOptions.factor ** Math.max(0, attempt - 1)
399
+ );
400
+ }
401
+ };
402
+ var done = () => ({
403
+ done: true,
404
+ value: void 0
405
+ });
406
+
407
+ // src/websocket.ts
408
+ function subscribeWebSocket(options) {
409
+ return {
410
+ [Symbol.asyncIterator]() {
411
+ return new WebSocketSubscription(options);
412
+ }
413
+ };
414
+ }
415
+
416
+ // src/client.ts
417
+ function createNodeRestlessClient(options) {
418
+ const coreClient = createRestlessClient2(options);
419
+ const subscribeWebSocketWithDefaults = (subscriptionOptions) => {
420
+ const mergedOptions = {
421
+ ...subscriptionOptions
422
+ };
423
+ if (mergedOptions.apiKey === void 0 && options.apiKey !== void 0) {
424
+ mergedOptions.apiKey = options.apiKey;
425
+ }
426
+ return subscribeWebSocket(mergedOptions);
427
+ };
428
+ const streams = {
429
+ ...coreClient.streams,
430
+ subscribeSse: (subscriptionOptions) => subscribeSse(coreClient, subscriptionOptions),
431
+ subscribeWebSocket: subscribeWebSocketWithDefaults,
432
+ subscribeWs: subscribeWebSocketWithDefaults
433
+ };
434
+ const direct = {
435
+ ...coreClient.direct,
436
+ subscribeWebSocket(input, directOptions = {}) {
437
+ const { cursor, since, ...websocketOptions } = directOptions;
438
+ const nodeOptions = {
439
+ ...websocketOptions,
440
+ wsUrl: coreClient.urls.directWebSocket(input)
441
+ };
442
+ if (cursor !== void 0) nodeOptions.cursor = cursor.toString();
443
+ if (since !== void 0) nodeOptions.since = since.toString();
444
+ return subscribeWebSocketWithDefaults(nodeOptions);
445
+ }
446
+ };
447
+ return new Proxy(coreClient, {
448
+ get(target, property, receiver) {
449
+ if (property === "streams") {
450
+ return streams;
451
+ }
452
+ if (property === "direct") {
453
+ return direct;
454
+ }
455
+ if (property === "subscribeWebSocket" || property === "subscribeWs") {
456
+ return subscribeWebSocketWithDefaults;
457
+ }
458
+ if (property === "subscribeSse") {
459
+ return (subscriptionOptions) => subscribeSse(coreClient, subscriptionOptions);
460
+ }
461
+ return Reflect.get(target, property, receiver);
462
+ }
463
+ });
464
+ }
465
+ export {
466
+ buildNodeSseUrl,
467
+ createNodeRestlessClient,
468
+ subscribeSse,
469
+ subscribeWebSocket
470
+ };
471
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/sse.ts","../src/url.ts","../src/websocket-subscription.ts","../src/websocket-message.ts","../src/websocket-options.ts","../src/websocket.ts"],"sourcesContent":["export * from '@restless-stream/core';\nexport { createNodeRestlessClient } from './client.js';\nexport { buildNodeSseUrl, subscribeSse } from './sse.js';\nexport type {\n CoreRestlessClientOptions,\n NodeRestlessClient,\n NodeRestlessClientOptions,\n NodeDirectClient,\n NodeSseHelperOptions,\n NodeSseSubscriptionOptions,\n NodeStreamsClient,\n NodeWebSocketReconnectOptions,\n NodeWebSocketSubscriptionOptions,\n} from './types.js';\nexport { subscribeWebSocket } from './websocket.js';\n","import {\n createRestlessClient,\n type DirectRuntimeUrlInput,\n type DirectSubscribeWebSocketOptions,\n} from '@restless-stream/core';\n\nimport type { NodeRestlessClient, NodeRestlessClientOptions, NodeWebSocketSubscriptionOptions } from './types.js';\n\nimport { subscribeSse } from './sse.js';\nimport { subscribeWebSocket } from './websocket.js';\n\nexport function createNodeRestlessClient(options: NodeRestlessClientOptions): NodeRestlessClient {\n const coreClient = createRestlessClient(options);\n\n const subscribeWebSocketWithDefaults = <TEvent>(subscriptionOptions: NodeWebSocketSubscriptionOptions<TEvent>) => {\n const mergedOptions: NodeWebSocketSubscriptionOptions<TEvent> = {\n ...subscriptionOptions,\n };\n\n if (mergedOptions.apiKey === undefined && options.apiKey !== undefined) {\n mergedOptions.apiKey = options.apiKey;\n }\n\n return subscribeWebSocket<TEvent>(mergedOptions);\n };\n\n const streams = {\n ...coreClient.streams,\n subscribeSse: (subscriptionOptions: Parameters<NodeRestlessClient['streams']['subscribeSse']>[0]) =>\n subscribeSse(coreClient, subscriptionOptions),\n subscribeWebSocket: subscribeWebSocketWithDefaults,\n subscribeWs: subscribeWebSocketWithDefaults,\n } satisfies NodeRestlessClient['streams'];\n\n const direct = {\n ...coreClient.direct,\n subscribeWebSocket<TEvent = unknown>(\n input: DirectRuntimeUrlInput,\n directOptions: DirectSubscribeWebSocketOptions = {},\n ) {\n const { cursor, since, ...websocketOptions } = directOptions;\n const nodeOptions: NodeWebSocketSubscriptionOptions<TEvent> = {\n ...websocketOptions,\n wsUrl: coreClient.urls.directWebSocket(input),\n };\n if (cursor !== undefined) nodeOptions.cursor = cursor.toString();\n if (since !== undefined) nodeOptions.since = since.toString();\n return subscribeWebSocketWithDefaults<TEvent>(nodeOptions);\n },\n } satisfies NodeRestlessClient['direct'];\n\n return new Proxy(coreClient, {\n get(target, property, receiver) {\n if (property === 'streams') {\n return streams;\n }\n\n if (property === 'direct') {\n return direct;\n }\n\n if (property === 'subscribeWebSocket' || property === 'subscribeWs') {\n return subscribeWebSocketWithDefaults;\n }\n\n if (property === 'subscribeSse') {\n return (subscriptionOptions: Parameters<NodeRestlessClient['subscribeSse']>[0]) =>\n subscribeSse(coreClient, subscriptionOptions);\n }\n\n return Reflect.get(target, property, receiver);\n },\n }) as NodeRestlessClient;\n}\n","import {\n createRestlessClient,\n type RestlessClient,\n type SseIterableOptions,\n type SseMessage,\n type StreamEvent,\n} from '@restless-stream/core';\n\nimport type { NodeSseHelperOptions, NodeSseSubscriptionOptions } from './types.js';\n\nimport { appendResumeParams } from './url.js';\n\ntype UnsafeSseOptions = Partial<Pick<SseIterableOptions, 'fetch' | 'headers' | 'url'>>;\ntype SafeSseIterableOptions = Omit<SseIterableOptions, 'cursor' | 'fetch' | 'headers' | 'since' | 'url'>;\ntype NodeSseUrlOptions = Pick<NodeSseSubscriptionOptions, 'sseUrl' | 'cursor' | 'since'>;\n\nexport function buildNodeSseUrl(options: NodeSseUrlOptions): string {\n return appendResumeParams(options.sseUrl, {\n cursor: options.cursor,\n since: options.since,\n });\n}\n\nexport function subscribeSse<TData = StreamEvent>(\n client: RestlessClient,\n options: NodeSseSubscriptionOptions,\n): AsyncIterable<SseMessage<TData>>;\nexport function subscribeSse<TData = StreamEvent>(options: NodeSseHelperOptions): AsyncIterable<SseMessage<TData>>;\nexport function subscribeSse<TData = StreamEvent>(\n clientOrOptions: RestlessClient | NodeSseHelperOptions,\n maybeOptions?: NodeSseSubscriptionOptions,\n): AsyncIterable<SseMessage<TData>> {\n const client = maybeOptions\n ? (clientOrOptions as RestlessClient)\n : ((clientOrOptions as NodeSseHelperOptions).client ??\n createRestlessClient((clientOrOptions as NodeSseHelperOptions).clientOptions));\n const options = maybeOptions ?? (clientOrOptions as NodeSseHelperOptions);\n const { iterableOptions, urlOptions } = splitSseOptions(options);\n\n return client.sse<TData>(buildNodeSseUrl(urlOptions), iterableOptions);\n}\n\nfunction splitSseOptions(options: NodeSseHelperOptions): {\n iterableOptions: SafeSseIterableOptions;\n urlOptions: NodeSseUrlOptions;\n} {\n const { cursor, since, sseUrl } = options;\n const urlOptions: NodeSseUrlOptions = { sseUrl };\n if (cursor !== undefined) urlOptions.cursor = cursor;\n if (since !== undefined) urlOptions.since = since;\n\n return { iterableOptions: removeUnsafeSseOptions(options), urlOptions };\n}\n\nfunction removeUnsafeSseOptions(options: NodeSseHelperOptions & UnsafeSseOptions): SafeSseIterableOptions {\n const iterableOptions: SafeSseIterableOptions = {};\n if (options.signal !== undefined) iterableOptions.signal = options.signal;\n if (options.reconnect !== undefined) iterableOptions.reconnect = options.reconnect;\n if (options.reconnectDelayMs !== undefined) iterableOptions.reconnectDelayMs = options.reconnectDelayMs;\n if (options.maxReconnectDelayMs !== undefined) iterableOptions.maxReconnectDelayMs = options.maxReconnectDelayMs;\n return iterableOptions;\n}\n","type ResumeParam = number | string | undefined;\n\ninterface ResumeParams {\n cursor?: ResumeParam;\n since?: ResumeParam;\n}\n\nexport function appendResumeParams(inputUrl: string, params: ResumeParams): string {\n const url = new URL(inputUrl);\n\n appendResumeParam(url.searchParams, 'since', params.since);\n appendResumeParam(url.searchParams, 'cursor', params.cursor);\n\n return url.toString();\n}\n\nfunction appendResumeParam(searchParams: URLSearchParams, key: string, value: ResumeParam): void {\n const normalizedValue = value?.toString().trim();\n if (normalizedValue !== undefined && normalizedValue !== '') searchParams.set(key, normalizedValue);\n}\n\nexport function normalizeWebSocketUrl(inputUrl: string): string {\n if (inputUrl.startsWith('https://')) {\n return `wss://${inputUrl.slice('https://'.length)}`;\n }\n\n if (inputUrl.startsWith('http://')) {\n return `ws://${inputUrl.slice('http://'.length)}`;\n }\n\n return inputUrl;\n}\n","import WebSocket from 'ws';\n\nimport type { NodeWebSocketReconnectOptions, NodeWebSocketSubscriptionOptions } from './types.js';\nimport type { CloseInfo, PendingNext } from './websocket-types.js';\n\nimport { appendResumeParams } from './url.js';\nimport { extractCursor, parseSocketMessage } from './websocket-message.js';\nimport { buildClientOptions, normalizeReconnectOptions, resolveWebSocketUrl, sleep } from './websocket-options.js';\n\nexport class WebSocketSubscription<TEvent> implements AsyncIterator<TEvent> {\n private readonly options: NodeWebSocketSubscriptionOptions<TEvent>;\n private readonly reconnectOptions: Required<NodeWebSocketReconnectOptions>;\n private readonly pending: Array<PendingNext<TEvent>> = [];\n private readonly queue: TEvent[] = [];\n private abortHandler?: () => void;\n private closed = false;\n private currentSocket: WebSocket | undefined;\n private failure?: unknown;\n private lastCursor: string | undefined;\n private reconnectAttempts = 0;\n private started = false;\n\n constructor(options: NodeWebSocketSubscriptionOptions<TEvent>) {\n this.options = options;\n this.reconnectOptions = normalizeReconnectOptions(options.reconnect);\n this.lastCursor = options.cursor;\n }\n\n async next(): Promise<IteratorResult<TEvent>> {\n this.start();\n\n if (this.queue.length > 0) return { done: false, value: this.queue.shift() as TEvent };\n if (this.failure !== undefined) throw this.failure;\n if (this.closed) return { done: true, value: undefined };\n\n return new Promise<IteratorResult<TEvent>>((resolve, reject) => {\n this.pending.push({ reject, resolve });\n });\n }\n\n async return(): Promise<IteratorResult<TEvent>> {\n this.close();\n return done();\n }\n\n async throw(error?: unknown): Promise<IteratorResult<TEvent>> {\n this.fail(error ?? new Error('WebSocket subscription iterator was interrupted.'));\n return done();\n }\n\n private start(): void {\n if (this.started) return;\n this.started = true;\n\n if (this.options.signal?.aborted) {\n this.close();\n return;\n }\n\n if (this.options.signal) {\n this.abortHandler = () => {\n this.close();\n };\n\n this.options.signal.addEventListener('abort', this.abortHandler, {\n once: true,\n });\n }\n\n void this.run();\n }\n\n private async run(): Promise<void> {\n while (!this.closed) {\n const socket = this.createSocket();\n this.currentSocket = socket;\n const closeInfo = await this.consumeSocket(socket);\n this.currentSocket = undefined;\n\n if (this.closed) {\n break;\n }\n\n if (!this.shouldReconnect(closeInfo)) {\n if (closeInfo.error !== undefined) {\n this.fail(closeInfo.error);\n } else {\n this.close();\n }\n\n return;\n }\n\n this.reconnectAttempts += 1;\n await sleep(this.reconnectDelayMs(this.reconnectAttempts));\n }\n\n this.close();\n }\n\n private createSocket(): WebSocket {\n const url = appendResumeParams(resolveWebSocketUrl(this.options), {\n cursor: this.lastCursor,\n since: this.lastCursor !== undefined && this.lastCursor !== '' ? undefined : this.options.since,\n });\n const clientOptions = buildClientOptions(this.options);\n\n return this.options.protocols === undefined\n ? new WebSocket(url, clientOptions)\n : new WebSocket(url, this.options.protocols, clientOptions);\n }\n\n private async consumeSocket(socket: WebSocket): Promise<CloseInfo> {\n return new Promise<CloseInfo>((resolve) => {\n this.attachSocketHandlers(socket, resolve);\n });\n }\n\n private attachSocketHandlers(socket: WebSocket, resolve: (info: CloseInfo) => void): void {\n let settled = false;\n let opened = false;\n let lastError: unknown;\n\n const settle = (info: CloseInfo) => {\n if (settled) return;\n settled = true;\n socket.off('close', onClose);\n socket.off('error', onError);\n socket.off('message', onMessage);\n socket.off('open', onOpen);\n socket.off('ping', onPing);\n socket.off('pong', onPong);\n resolve(info);\n };\n\n const onOpen = () => {\n opened = true;\n };\n\n const onError = (error: unknown) => {\n lastError = error;\n if (!opened) settle({ error });\n };\n\n const onClose = (code: number) => {\n settle({ code, error: lastError });\n };\n\n const onMessage = (data: WebSocket.RawData) => {\n this.handleMessage(data, socket);\n };\n\n const onPing = () => {};\n const onPong = () => {};\n\n socket.on('open', onOpen);\n socket.on('error', onError);\n socket.on('close', onClose);\n socket.on('message', onMessage);\n socket.on('ping', onPing);\n socket.on('pong', onPong);\n }\n\n private handleMessage(data: WebSocket.RawData, socket: WebSocket): void {\n try {\n const event = parseSocketMessage(data, this.options, socket);\n if (event === undefined) return;\n\n this.lastCursor = extractCursor(event) ?? this.lastCursor;\n this.push(event);\n } catch (error) {\n this.fail(error);\n }\n }\n\n private push(event: TEvent): void {\n const pending = this.pending.shift();\n if (pending !== undefined) {\n pending.resolve({ done: false, value: event });\n return;\n }\n\n this.queue.push(event);\n }\n\n private fail(error: unknown): void {\n this.closed = true;\n this.failure = error;\n this.closeSocket();\n this.removeAbortHandler();\n\n for (const pending of this.pending.splice(0)) {\n pending.reject(error);\n }\n }\n\n private close(): void {\n if (this.closed) {\n return;\n }\n\n this.closed = true;\n this.closeSocket();\n this.removeAbortHandler();\n\n for (const pending of this.pending.splice(0)) {\n pending.resolve({ done: true, value: undefined });\n }\n }\n\n private closeSocket(): void {\n if (this.currentSocket === undefined) {\n return;\n }\n\n const socket = this.currentSocket;\n\n if (socket.readyState === WebSocket.CONNECTING || socket.readyState === WebSocket.OPEN) {\n socket.close();\n }\n\n this.currentSocket = undefined;\n }\n\n private removeAbortHandler(): void {\n if (this.abortHandler !== undefined && this.options.signal !== undefined) {\n this.options.signal.removeEventListener('abort', this.abortHandler);\n }\n }\n\n private shouldReconnect(info: CloseInfo): boolean {\n if (!this.reconnectOptions.enabled || this.closed) {\n return false;\n }\n\n if (this.reconnectAttempts >= this.reconnectOptions.maxRetries) {\n return false;\n }\n\n return info.error !== undefined ? true : info.code !== undefined && info.code !== 1000 && info.code !== 1001;\n }\n\n private reconnectDelayMs(attempt: number): number {\n return Math.min(\n this.reconnectOptions.maxDelayMs,\n this.reconnectOptions.initialDelayMs * this.reconnectOptions.factor ** Math.max(0, attempt - 1),\n );\n }\n}\n\nconst done = <TEvent>(): IteratorResult<TEvent> => ({\n done: true,\n value: undefined,\n});\n","import WebSocket, { type RawData } from 'ws';\n\nimport type { NodeWebSocketSubscriptionOptions } from './types.js';\n\nexport function parseSocketMessage<TEvent>(\n data: RawData,\n options: NodeWebSocketSubscriptionOptions<TEvent>,\n socket: WebSocket,\n): TEvent | undefined {\n const text = rawDataToText(data);\n const heartbeat = normalizeHeartbeat(text);\n\n if (heartbeat === 'ping') {\n sendApplicationPong(socket);\n return undefined;\n }\n\n if (heartbeat === 'pong') {\n return undefined;\n }\n\n if (options.parse === false) {\n return text as TEvent;\n }\n\n const parser = options.parser ?? defaultParseSocketEvent<TEvent>;\n\n try {\n return parser(text);\n } catch (textError) {\n try {\n return parser(JSON.parse(text));\n } catch {\n throw textError;\n }\n }\n}\n\nexport function extractCursor(event: unknown): string | undefined {\n if (event === null || event === undefined || typeof event !== 'object') {\n return undefined;\n }\n\n const record = event as Record<string, unknown>;\n const cursor = record.cursor ?? record.id ?? record.eventId ?? record.lastEventId;\n\n if (typeof cursor === 'string' && cursor.length > 0) {\n return cursor;\n }\n\n if (typeof cursor === 'number' && Number.isFinite(cursor) && cursor >= 0) {\n return String(Math.trunc(cursor));\n }\n\n return extractMetaTimestampCursor(record);\n}\n\nfunction defaultParseSocketEvent<TEvent>(message: unknown): TEvent {\n if (typeof message === 'string') {\n return JSON.parse(message) as TEvent;\n }\n\n return message as TEvent;\n}\n\nfunction rawDataToText(data: RawData): string {\n if (Buffer.isBuffer(data)) {\n return data.toString('utf8');\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data).toString('utf8');\n }\n\n if (Array.isArray(data)) {\n return Buffer.concat(data).toString('utf8');\n }\n\n return Buffer.from(data).toString('utf8');\n}\n\nfunction extractMetaTimestampCursor(record: Record<string, unknown>): string | undefined {\n const { meta } = record;\n if (meta === null || meta === undefined || typeof meta !== 'object') {\n return undefined;\n }\n\n const { timestamp } = meta as Record<string, unknown>;\n if (typeof timestamp !== 'string') {\n return undefined;\n }\n\n const timestampMs = Date.parse(timestamp);\n return Number.isFinite(timestampMs) && timestampMs >= 0 ? String(Math.trunc(timestampMs)) : undefined;\n}\n\nfunction normalizeHeartbeat(text: string): 'ping' | 'pong' | undefined {\n const trimmed = text.trim().toLowerCase();\n\n if (trimmed === 'ping' || trimmed === '{\"type\":\"ping\"}' || trimmed === '{\"event\":\"ping\"}') {\n return 'ping';\n }\n\n if (trimmed === 'pong' || trimmed === '{\"type\":\"pong\"}' || trimmed === '{\"event\":\"pong\"}') {\n return 'pong';\n }\n\n return undefined;\n}\n\nfunction sendApplicationPong(socket: WebSocket): void {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send('pong', { binary: false });\n }\n}\n","import type { ClientOptions } from 'ws';\n\nimport type { NodeWebSocketReconnectOptions, NodeWebSocketSubscriptionOptions } from './types.js';\n\nexport const DEFAULT_RECONNECT_OPTIONS: Required<NodeWebSocketReconnectOptions> = {\n enabled: true,\n factor: 2,\n initialDelayMs: 250,\n maxDelayMs: 5000,\n maxRetries: Number.POSITIVE_INFINITY,\n};\n\nexport function normalizeReconnectOptions(\n reconnect: boolean | NodeWebSocketReconnectOptions | undefined,\n): Required<NodeWebSocketReconnectOptions> {\n if (reconnect === false) {\n return { ...DEFAULT_RECONNECT_OPTIONS, enabled: false };\n }\n\n if (reconnect === true || reconnect === undefined) {\n return DEFAULT_RECONNECT_OPTIONS;\n }\n\n return {\n enabled: reconnect.enabled ?? DEFAULT_RECONNECT_OPTIONS.enabled,\n factor: reconnect.factor ?? DEFAULT_RECONNECT_OPTIONS.factor,\n initialDelayMs: reconnect.initialDelayMs ?? DEFAULT_RECONNECT_OPTIONS.initialDelayMs,\n maxDelayMs: reconnect.maxDelayMs ?? DEFAULT_RECONNECT_OPTIONS.maxDelayMs,\n maxRetries: reconnect.maxRetries ?? DEFAULT_RECONNECT_OPTIONS.maxRetries,\n };\n}\n\nexport function resolveWebSocketUrl(options: NodeWebSocketSubscriptionOptions<unknown>): string {\n const url = options.wsUrl ?? options.websocketUrl ?? options.url;\n\n if (url === undefined || url === '') {\n throw new TypeError('A WebSocket URL is required. Pass wsUrl, websocketUrl, or url.');\n }\n\n return url;\n}\n\nexport function buildClientOptions(options: NodeWebSocketSubscriptionOptions<unknown>): ClientOptions {\n const clientOptions: ClientOptions = { ...options.clientOptions };\n const headers = {\n ...coerceHeaders(options.clientOptions?.headers),\n ...options.headers,\n };\n\n const apiKey = options.apiKey?.trim();\n if (apiKey !== undefined && apiKey !== '' && !hasAuthorizationHeader(headers)) {\n headers.Authorization = `Bearer ${apiKey}`;\n }\n\n if (Object.keys(headers).length > 0) {\n clientOptions.headers = headers;\n }\n\n return clientOptions;\n}\n\nfunction coerceHeaders(headers: ClientOptions['headers']): Record<string, string> {\n if (headers === undefined) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(headers).map(([key, value]) => [key, Array.isArray(value) ? value.join(', ') : String(value)]),\n );\n}\n\nfunction hasAuthorizationHeader(headers: Record<string, string>): boolean {\n return Object.keys(headers).some((key) => key.toLowerCase() === 'authorization');\n}\n\nexport async function sleep(delayMs: number): Promise<void> {\n return new Promise((resolve) => {\n const timeout = setTimeout(resolve, delayMs);\n timeout.unref?.();\n });\n}\n","import type { StreamEvent } from '@restless-stream/core';\n\nimport type { NodeWebSocketSubscriptionOptions } from './types.js';\n\nimport { WebSocketSubscription } from './websocket-subscription.js';\n\nexport function subscribeWebSocket<TEvent = StreamEvent>(\n options: NodeWebSocketSubscriptionOptions<TEvent>,\n): AsyncIterable<TEvent> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<TEvent> {\n return new WebSocketSubscription(options);\n },\n };\n}\n"],"mappings":"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","names":["createRestlessClient","WebSocket","WebSocket","createRestlessClient"]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@restless-stream/node",
3
+ "version": "0.1.0",
4
+ "description": "Node.js SDK helpers for Restless Stream.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "dependencies": {
20
+ "ws": "^8.18.0",
21
+ "@restless-stream/core": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/ws": "^8.18.1"
25
+ },
26
+ "engines": {
27
+ "node": ">=20.19.0"
28
+ },
29
+ "sideEffects": false,
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "test": "vitest run",
33
+ "test:live": "vitest run tests/live.test.ts --config vitest.live.config.ts",
34
+ "typecheck": "tsc --noEmit"
35
+ }
36
+ }