@cnstra/devtools-transport-ws 1.2.0 → 2.0.1
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 +5 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -19
- package/dist/index.js.map +1 -1
- package/package.json +10 -5
package/dist/index.cjs
CHANGED
|
@@ -20,12 +20,6 @@ var CNSDevToolsTransportWs = class {
|
|
|
20
20
|
this.pendingBatches.push(message);
|
|
21
21
|
await this.flush();
|
|
22
22
|
}
|
|
23
|
-
onReplayStart(handler) {
|
|
24
|
-
this.onReplayHandler = handler;
|
|
25
|
-
return () => {
|
|
26
|
-
this.onReplayHandler = void 0;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
23
|
onStimulationCommand(handler) {
|
|
30
24
|
this.onCommandHandler = handler;
|
|
31
25
|
return () => {
|
|
@@ -38,7 +32,7 @@ var CNSDevToolsTransportWs = class {
|
|
|
38
32
|
if (!impl) throw new Error("No WebSocket implementation. Pass webSocketImpl option.");
|
|
39
33
|
return impl;
|
|
40
34
|
}
|
|
41
|
-
|
|
35
|
+
openSocket() {
|
|
42
36
|
if (this.ws?.readyState === 1) return Promise.resolve();
|
|
43
37
|
if (this.connecting) {
|
|
44
38
|
return new Promise((resolve) => {
|
|
@@ -67,7 +61,7 @@ var CNSDevToolsTransportWs = class {
|
|
|
67
61
|
if (this.opts.consoleLogEnabled) {
|
|
68
62
|
console.log(`[DevTools] Disconnected, reconnecting (attempt ${this.reconnectAttempts})`);
|
|
69
63
|
}
|
|
70
|
-
setTimeout(() => this.
|
|
64
|
+
setTimeout(() => this.openSocket().catch(() => {
|
|
71
65
|
}), this.opts.reconnectDelayMs ?? 1e3);
|
|
72
66
|
} else if (this.reconnectAttempts >= (this.opts.maxReconnectAttempts ?? Infinity)) {
|
|
73
67
|
if (this.opts.consoleLogEnabled) console.log("[DevTools] Max reconnect attempts reached");
|
|
@@ -82,15 +76,8 @@ var CNSDevToolsTransportWs = class {
|
|
|
82
76
|
ws.onmessage = (ev) => {
|
|
83
77
|
try {
|
|
84
78
|
const msg = JSON.parse(typeof ev.data === "string" ? ev.data : String(ev.data));
|
|
85
|
-
if (msg?.type === "
|
|
86
|
-
const result = devtoolsDto.
|
|
87
|
-
if (result.success) {
|
|
88
|
-
this.onReplayHandler?.(result.data);
|
|
89
|
-
} else if (this.opts.consoleLogEnabled) {
|
|
90
|
-
console.warn("[DevTools] Invalid replay.start message:", result.error.message);
|
|
91
|
-
}
|
|
92
|
-
} else if (msg?.type === "cns.stimulation.resume" || msg?.type === "cns.stimulation.launch") {
|
|
93
|
-
const result = devtoolsDto.CNSDTOAppCommandSchema.safeParse(msg);
|
|
79
|
+
if (msg?.type === "cns.stimulation.resume" || msg?.type === "cns.stimulation.launch") {
|
|
80
|
+
const result = devtoolsDto.CNSAppCommandDTOSchema.safeParse(msg);
|
|
94
81
|
if (result.success) {
|
|
95
82
|
this.onCommandHandler?.(result.data);
|
|
96
83
|
} else if (this.opts.consoleLogEnabled) {
|
|
@@ -104,7 +91,7 @@ var CNSDevToolsTransportWs = class {
|
|
|
104
91
|
}
|
|
105
92
|
async flush() {
|
|
106
93
|
if (this.pendingBatches.length === 0) return;
|
|
107
|
-
await this.
|
|
94
|
+
await this.openSocket();
|
|
108
95
|
if (this.ws?.readyState !== 1) return;
|
|
109
96
|
const batches = this.pendingBatches.splice(0, this.pendingBatches.length);
|
|
110
97
|
if (batches.length === 0) return;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["CNSDTOReplayStartMessageSchema","CNSDTOAppCommandSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ICNSDevToolsTransport } from '@cnstra/devtools';\nimport {\n CNSDTOReplayStartMessageSchema,\n CNSDTOAppCommandSchema,\n type CNSDTOAppBatchMessage,\n} from '@cnstra/devtools-dto';\n\nexport type CNSDevToolsTransportWsOptions = {\n /** WebSocket URL, e.g. ws://localhost:3141 */\n url: string;\n protocols?: string | string[];\n /** Reconnect delay in ms (default: 1000) */\n reconnectDelayMs?: number;\n /** Max buffered batch items before force flush (default: 100) */\n batchMaxSize?: number;\n /** Provide a WebSocket implementation for Node.js (e.g. `ws`) */\n webSocketImpl?: typeof WebSocket;\n /** Max reconnect attempts (default: Infinity) */\n maxReconnectAttempts?: number;\n consoleLogEnabled?: boolean;\n};\n\nexport class CNSDevToolsTransportWs implements ICNSDevToolsTransport {\n private ws?: WebSocket;\n private connecting = false;\n private closed = false;\n private reconnectAttempts = 0;\n private hasConnectedOnce = false;\n\n private readonly pendingBatches: CNSDTOAppBatchMessage[] = [];\n private lastTopologyBatch?: CNSDTOAppBatchMessage;\n private onReplayHandler?: (cmd: any) => void;\n private onCommandHandler?: (cmd: any) => void;\n\n constructor(private readonly opts: CNSDevToolsTransportWsOptions) {}\n\n // ─── ICNSDevToolsTransport ────────────────────────────────────────────────────\n\n async sendBatch(message: CNSDTOAppBatchMessage): Promise<void> {\n if (message.items.some(i => i.type === 'topology')) {\n this.lastTopologyBatch = message;\n }\n this.pendingBatches.push(message);\n await this.flush();\n }\n\n onReplayStart(handler: (cmd: any) => void): () => void {\n this.onReplayHandler = handler;\n return () => { this.onReplayHandler = undefined; };\n }\n\n onStimulationCommand(handler: (cmd: any) => void): () => void {\n this.onCommandHandler = handler;\n return () => { this.onCommandHandler = undefined; };\n }\n\n // ─── Connection management ────────────────────────────────────────────────────\n\n private get WS(): typeof WebSocket {\n const impl = this.opts.webSocketImpl\n ?? (typeof WebSocket !== 'undefined' ? WebSocket : undefined);\n if (!impl) throw new Error('No WebSocket implementation. Pass webSocketImpl option.');\n return impl;\n }\n\n private ensureSocket(): Promise<void> {\n if (this.ws?.readyState === 1) return Promise.resolve();\n if (this.connecting) {\n return new Promise(resolve => {\n const poll = () => this.ws?.readyState === 1 ? resolve() : setTimeout(poll, 50);\n poll();\n });\n }\n this.connecting = true;\n return new Promise(resolve => {\n const ws = new this.WS(this.opts.url, this.opts.protocols) as WebSocket;\n this.ws = ws;\n\n ws.onopen = () => {\n this.connecting = false;\n this.reconnectAttempts = 0;\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Connected');\n\n if (this.hasConnectedOnce && this.lastTopologyBatch) {\n this.pendingBatches.unshift(this.lastTopologyBatch);\n }\n this.hasConnectedOnce = true;\n this.flush().then(resolve);\n };\n\n ws.onclose = () => {\n this.connecting = false;\n if (!this.closed && this.reconnectAttempts < (this.opts.maxReconnectAttempts ?? Infinity)) {\n this.reconnectAttempts++;\n if (this.opts.consoleLogEnabled) {\n console.log(`[DevTools] Disconnected, reconnecting (attempt ${this.reconnectAttempts})`);\n }\n setTimeout(() => this.ensureSocket().catch(() => {}), this.opts.reconnectDelayMs ?? 1000);\n } else if (this.reconnectAttempts >= (this.opts.maxReconnectAttempts ?? Infinity)) {\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Max reconnect attempts reached');\n }\n };\n\n ws.onerror = () => { try { ws.close(); } catch {} };\n\n ws.onmessage = (ev: MessageEvent) => {\n try {\n const msg = JSON.parse(typeof ev.data === 'string' ? ev.data : String(ev.data));\n if (msg?.type === 'replay.start') {\n const result = CNSDTOReplayStartMessageSchema.safeParse(msg);\n if (result.success) {\n this.onReplayHandler?.(result.data);\n } else if (this.opts.consoleLogEnabled) {\n console.warn('[DevTools] Invalid replay.start message:', result.error.message);\n }\n } else if (\n msg?.type === 'cns.stimulation.resume' ||\n msg?.type === 'cns.stimulation.launch'\n ) {\n const result = CNSDTOAppCommandSchema.safeParse(msg);\n if (result.success) {\n this.onCommandHandler?.(result.data);\n } else if (this.opts.consoleLogEnabled) {\n console.warn('[DevTools] Invalid stimulation command:', result.error.message);\n }\n }\n } catch {}\n };\n });\n }\n\n private async flush(): Promise<void> {\n if (this.pendingBatches.length === 0) return;\n await this.ensureSocket();\n if (this.ws?.readyState !== 1) return;\n\n const batches = this.pendingBatches.splice(0, this.pendingBatches.length);\n if (batches.length === 0) return;\n try {\n const items = batches.flatMap(b => b.items);\n if (items.length === 0) return;\n this.ws.send(JSON.stringify({ type: 'batch', items }));\n } catch {\n this.pendingBatches.unshift(...batches);\n }\n }\n\n close(): void {\n this.closed = true;\n try { this.ws?.close(); } catch {}\n this.ws = undefined;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === 1;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["CNSAppCommandDTOSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ICNSDevToolsTransport } from '@cnstra/devtools';\nimport {\n CNSAppCommandDTOSchema,\n type TCNSAppBatchMessageDTO,\n} from '@cnstra/devtools-dto';\n\nexport type TCNSDevToolsTransportWsOptions = {\n /** WebSocket URL, e.g. ws://localhost:3141 */\n url: string;\n protocols?: string | string[];\n /** Reconnect delay in ms (default: 1000) */\n reconnectDelayMs?: number;\n /** Max buffered batch items before force flush (default: 100) */\n batchMaxSize?: number;\n /** Provide a WebSocket implementation for Node.js (e.g. `ws`) */\n webSocketImpl?: typeof WebSocket;\n /** Max reconnect attempts (default: Infinity) */\n maxReconnectAttempts?: number;\n consoleLogEnabled?: boolean;\n};\n\nexport class CNSDevToolsTransportWs implements ICNSDevToolsTransport {\n private ws?: WebSocket;\n private connecting = false;\n private closed = false;\n private reconnectAttempts = 0;\n private hasConnectedOnce = false;\n\n private readonly pendingBatches: TCNSAppBatchMessageDTO[] = [];\n private lastTopologyBatch?: TCNSAppBatchMessageDTO;\n private onCommandHandler?: (cmd: any) => void;\n\n constructor(private readonly opts: TCNSDevToolsTransportWsOptions) {}\n\n // ─── ICNSDevToolsTransport ────────────────────────────────────────────────────\n\n async sendBatch(message: TCNSAppBatchMessageDTO): Promise<void> {\n if (message.items.some(i => i.type === 'topology')) {\n this.lastTopologyBatch = message;\n }\n this.pendingBatches.push(message);\n await this.flush();\n }\n\n onStimulationCommand(handler: (cmd: any) => void): () => void {\n this.onCommandHandler = handler;\n return () => { this.onCommandHandler = undefined; };\n }\n\n // ─── Connection management ────────────────────────────────────────────────────\n\n private get WS(): typeof WebSocket {\n const impl = this.opts.webSocketImpl\n ?? (typeof WebSocket !== 'undefined' ? WebSocket : undefined);\n if (!impl) throw new Error('No WebSocket implementation. Pass webSocketImpl option.');\n return impl;\n }\n\n private openSocket(): Promise<void> {\n if (this.ws?.readyState === 1) return Promise.resolve();\n if (this.connecting) {\n return new Promise(resolve => {\n const poll = () => this.ws?.readyState === 1 ? resolve() : setTimeout(poll, 50);\n poll();\n });\n }\n this.connecting = true;\n return new Promise(resolve => {\n const ws = new this.WS(this.opts.url, this.opts.protocols) as WebSocket;\n this.ws = ws;\n\n ws.onopen = () => {\n this.connecting = false;\n this.reconnectAttempts = 0;\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Connected');\n\n if (this.hasConnectedOnce && this.lastTopologyBatch) {\n this.pendingBatches.unshift(this.lastTopologyBatch);\n }\n this.hasConnectedOnce = true;\n this.flush().then(resolve);\n };\n\n ws.onclose = () => {\n this.connecting = false;\n if (!this.closed && this.reconnectAttempts < (this.opts.maxReconnectAttempts ?? Infinity)) {\n this.reconnectAttempts++;\n if (this.opts.consoleLogEnabled) {\n console.log(`[DevTools] Disconnected, reconnecting (attempt ${this.reconnectAttempts})`);\n }\n setTimeout(() => this.openSocket().catch(() => {}), this.opts.reconnectDelayMs ?? 1000);\n } else if (this.reconnectAttempts >= (this.opts.maxReconnectAttempts ?? Infinity)) {\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Max reconnect attempts reached');\n }\n };\n\n ws.onerror = () => { try { ws.close(); } catch {} };\n\n ws.onmessage = (ev: MessageEvent) => {\n try {\n const msg = JSON.parse(typeof ev.data === 'string' ? ev.data : String(ev.data));\n if (\n msg?.type === 'cns.stimulation.resume' ||\n msg?.type === 'cns.stimulation.launch'\n ) {\n const result = CNSAppCommandDTOSchema.safeParse(msg);\n if (result.success) {\n this.onCommandHandler?.(result.data);\n } else if (this.opts.consoleLogEnabled) {\n console.warn('[DevTools] Invalid stimulation command:', result.error.message);\n }\n }\n } catch {}\n };\n });\n }\n\n private async flush(): Promise<void> {\n if (this.pendingBatches.length === 0) return;\n await this.openSocket();\n if (this.ws?.readyState !== 1) return;\n\n const batches = this.pendingBatches.splice(0, this.pendingBatches.length);\n if (batches.length === 0) return;\n try {\n const items = batches.flatMap(b => b.items);\n if (items.length === 0) return;\n this.ws.send(JSON.stringify({ type: 'batch', items }));\n } catch {\n this.pendingBatches.unshift(...batches);\n }\n }\n\n close(): void {\n this.closed = true;\n try { this.ws?.close(); } catch {}\n this.ws = undefined;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === 1;\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ICNSDevToolsTransport } from '@cnstra/devtools';
|
|
2
|
-
import { type
|
|
3
|
-
export type
|
|
2
|
+
import { type TCNSAppBatchMessageDTO } from '@cnstra/devtools-dto';
|
|
3
|
+
export type TCNSDevToolsTransportWsOptions = {
|
|
4
4
|
/** WebSocket URL, e.g. ws://localhost:3141 */
|
|
5
5
|
url: string;
|
|
6
6
|
protocols?: string | string[];
|
|
@@ -23,14 +23,12 @@ export declare class CNSDevToolsTransportWs implements ICNSDevToolsTransport {
|
|
|
23
23
|
private hasConnectedOnce;
|
|
24
24
|
private readonly pendingBatches;
|
|
25
25
|
private lastTopologyBatch?;
|
|
26
|
-
private onReplayHandler?;
|
|
27
26
|
private onCommandHandler?;
|
|
28
|
-
constructor(opts:
|
|
29
|
-
sendBatch(message:
|
|
30
|
-
onReplayStart(handler: (cmd: any) => void): () => void;
|
|
27
|
+
constructor(opts: TCNSDevToolsTransportWsOptions);
|
|
28
|
+
sendBatch(message: TCNSAppBatchMessageDTO): Promise<void>;
|
|
31
29
|
onStimulationCommand(handler: (cmd: any) => void): () => void;
|
|
32
30
|
private get WS();
|
|
33
|
-
private
|
|
31
|
+
private openSocket;
|
|
34
32
|
private flush;
|
|
35
33
|
close(): void;
|
|
36
34
|
get isConnected(): boolean;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAEH,KAAK,sBAAsB,EAC9B,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,8BAA8B,GAAG;IACzC,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC9B,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,SAAS,CAAC;IACjC,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,qBAAa,sBAAuB,YAAW,qBAAqB;IAWpD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAVjC,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgC;IAC/D,OAAO,CAAC,iBAAiB,CAAC,CAAyB;IACnD,OAAO,CAAC,gBAAgB,CAAC,CAAqB;gBAEjB,IAAI,EAAE,8BAA8B;IAI3D,SAAS,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D,oBAAoB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7D,OAAO,KAAK,EAAE,GAKb;IAED,OAAO,CAAC,UAAU;YA2DJ,KAAK;IAgBnB,KAAK,IAAI,IAAI;IAMb,IAAI,WAAW,IAAI,OAAO,CAEzB;CACJ"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CNSAppCommandDTOSchema } from '@cnstra/devtools-dto';
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
var CNSDevToolsTransportWs = class {
|
|
@@ -18,12 +18,6 @@ var CNSDevToolsTransportWs = class {
|
|
|
18
18
|
this.pendingBatches.push(message);
|
|
19
19
|
await this.flush();
|
|
20
20
|
}
|
|
21
|
-
onReplayStart(handler) {
|
|
22
|
-
this.onReplayHandler = handler;
|
|
23
|
-
return () => {
|
|
24
|
-
this.onReplayHandler = void 0;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
21
|
onStimulationCommand(handler) {
|
|
28
22
|
this.onCommandHandler = handler;
|
|
29
23
|
return () => {
|
|
@@ -36,7 +30,7 @@ var CNSDevToolsTransportWs = class {
|
|
|
36
30
|
if (!impl) throw new Error("No WebSocket implementation. Pass webSocketImpl option.");
|
|
37
31
|
return impl;
|
|
38
32
|
}
|
|
39
|
-
|
|
33
|
+
openSocket() {
|
|
40
34
|
if (this.ws?.readyState === 1) return Promise.resolve();
|
|
41
35
|
if (this.connecting) {
|
|
42
36
|
return new Promise((resolve) => {
|
|
@@ -65,7 +59,7 @@ var CNSDevToolsTransportWs = class {
|
|
|
65
59
|
if (this.opts.consoleLogEnabled) {
|
|
66
60
|
console.log(`[DevTools] Disconnected, reconnecting (attempt ${this.reconnectAttempts})`);
|
|
67
61
|
}
|
|
68
|
-
setTimeout(() => this.
|
|
62
|
+
setTimeout(() => this.openSocket().catch(() => {
|
|
69
63
|
}), this.opts.reconnectDelayMs ?? 1e3);
|
|
70
64
|
} else if (this.reconnectAttempts >= (this.opts.maxReconnectAttempts ?? Infinity)) {
|
|
71
65
|
if (this.opts.consoleLogEnabled) console.log("[DevTools] Max reconnect attempts reached");
|
|
@@ -80,15 +74,8 @@ var CNSDevToolsTransportWs = class {
|
|
|
80
74
|
ws.onmessage = (ev) => {
|
|
81
75
|
try {
|
|
82
76
|
const msg = JSON.parse(typeof ev.data === "string" ? ev.data : String(ev.data));
|
|
83
|
-
if (msg?.type === "
|
|
84
|
-
const result =
|
|
85
|
-
if (result.success) {
|
|
86
|
-
this.onReplayHandler?.(result.data);
|
|
87
|
-
} else if (this.opts.consoleLogEnabled) {
|
|
88
|
-
console.warn("[DevTools] Invalid replay.start message:", result.error.message);
|
|
89
|
-
}
|
|
90
|
-
} else if (msg?.type === "cns.stimulation.resume" || msg?.type === "cns.stimulation.launch") {
|
|
91
|
-
const result = CNSDTOAppCommandSchema.safeParse(msg);
|
|
77
|
+
if (msg?.type === "cns.stimulation.resume" || msg?.type === "cns.stimulation.launch") {
|
|
78
|
+
const result = CNSAppCommandDTOSchema.safeParse(msg);
|
|
92
79
|
if (result.success) {
|
|
93
80
|
this.onCommandHandler?.(result.data);
|
|
94
81
|
} else if (this.opts.consoleLogEnabled) {
|
|
@@ -102,7 +89,7 @@ var CNSDevToolsTransportWs = class {
|
|
|
102
89
|
}
|
|
103
90
|
async flush() {
|
|
104
91
|
if (this.pendingBatches.length === 0) return;
|
|
105
|
-
await this.
|
|
92
|
+
await this.openSocket();
|
|
106
93
|
if (this.ws?.readyState !== 1) return;
|
|
107
94
|
const batches = this.pendingBatches.splice(0, this.pendingBatches.length);
|
|
108
95
|
if (batches.length === 0) return;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ICNSDevToolsTransport } from '@cnstra/devtools';\nimport {\n CNSDTOReplayStartMessageSchema,\n CNSDTOAppCommandSchema,\n type CNSDTOAppBatchMessage,\n} from '@cnstra/devtools-dto';\n\nexport type CNSDevToolsTransportWsOptions = {\n /** WebSocket URL, e.g. ws://localhost:3141 */\n url: string;\n protocols?: string | string[];\n /** Reconnect delay in ms (default: 1000) */\n reconnectDelayMs?: number;\n /** Max buffered batch items before force flush (default: 100) */\n batchMaxSize?: number;\n /** Provide a WebSocket implementation for Node.js (e.g. `ws`) */\n webSocketImpl?: typeof WebSocket;\n /** Max reconnect attempts (default: Infinity) */\n maxReconnectAttempts?: number;\n consoleLogEnabled?: boolean;\n};\n\nexport class CNSDevToolsTransportWs implements ICNSDevToolsTransport {\n private ws?: WebSocket;\n private connecting = false;\n private closed = false;\n private reconnectAttempts = 0;\n private hasConnectedOnce = false;\n\n private readonly pendingBatches: CNSDTOAppBatchMessage[] = [];\n private lastTopologyBatch?: CNSDTOAppBatchMessage;\n private onReplayHandler?: (cmd: any) => void;\n private onCommandHandler?: (cmd: any) => void;\n\n constructor(private readonly opts: CNSDevToolsTransportWsOptions) {}\n\n // ─── ICNSDevToolsTransport ────────────────────────────────────────────────────\n\n async sendBatch(message: CNSDTOAppBatchMessage): Promise<void> {\n if (message.items.some(i => i.type === 'topology')) {\n this.lastTopologyBatch = message;\n }\n this.pendingBatches.push(message);\n await this.flush();\n }\n\n onReplayStart(handler: (cmd: any) => void): () => void {\n this.onReplayHandler = handler;\n return () => { this.onReplayHandler = undefined; };\n }\n\n onStimulationCommand(handler: (cmd: any) => void): () => void {\n this.onCommandHandler = handler;\n return () => { this.onCommandHandler = undefined; };\n }\n\n // ─── Connection management ────────────────────────────────────────────────────\n\n private get WS(): typeof WebSocket {\n const impl = this.opts.webSocketImpl\n ?? (typeof WebSocket !== 'undefined' ? WebSocket : undefined);\n if (!impl) throw new Error('No WebSocket implementation. Pass webSocketImpl option.');\n return impl;\n }\n\n private ensureSocket(): Promise<void> {\n if (this.ws?.readyState === 1) return Promise.resolve();\n if (this.connecting) {\n return new Promise(resolve => {\n const poll = () => this.ws?.readyState === 1 ? resolve() : setTimeout(poll, 50);\n poll();\n });\n }\n this.connecting = true;\n return new Promise(resolve => {\n const ws = new this.WS(this.opts.url, this.opts.protocols) as WebSocket;\n this.ws = ws;\n\n ws.onopen = () => {\n this.connecting = false;\n this.reconnectAttempts = 0;\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Connected');\n\n if (this.hasConnectedOnce && this.lastTopologyBatch) {\n this.pendingBatches.unshift(this.lastTopologyBatch);\n }\n this.hasConnectedOnce = true;\n this.flush().then(resolve);\n };\n\n ws.onclose = () => {\n this.connecting = false;\n if (!this.closed && this.reconnectAttempts < (this.opts.maxReconnectAttempts ?? Infinity)) {\n this.reconnectAttempts++;\n if (this.opts.consoleLogEnabled) {\n console.log(`[DevTools] Disconnected, reconnecting (attempt ${this.reconnectAttempts})`);\n }\n setTimeout(() => this.ensureSocket().catch(() => {}), this.opts.reconnectDelayMs ?? 1000);\n } else if (this.reconnectAttempts >= (this.opts.maxReconnectAttempts ?? Infinity)) {\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Max reconnect attempts reached');\n }\n };\n\n ws.onerror = () => { try { ws.close(); } catch {} };\n\n ws.onmessage = (ev: MessageEvent) => {\n try {\n const msg = JSON.parse(typeof ev.data === 'string' ? ev.data : String(ev.data));\n if (msg?.type === 'replay.start') {\n const result = CNSDTOReplayStartMessageSchema.safeParse(msg);\n if (result.success) {\n this.onReplayHandler?.(result.data);\n } else if (this.opts.consoleLogEnabled) {\n console.warn('[DevTools] Invalid replay.start message:', result.error.message);\n }\n } else if (\n msg?.type === 'cns.stimulation.resume' ||\n msg?.type === 'cns.stimulation.launch'\n ) {\n const result = CNSDTOAppCommandSchema.safeParse(msg);\n if (result.success) {\n this.onCommandHandler?.(result.data);\n } else if (this.opts.consoleLogEnabled) {\n console.warn('[DevTools] Invalid stimulation command:', result.error.message);\n }\n }\n } catch {}\n };\n });\n }\n\n private async flush(): Promise<void> {\n if (this.pendingBatches.length === 0) return;\n await this.ensureSocket();\n if (this.ws?.readyState !== 1) return;\n\n const batches = this.pendingBatches.splice(0, this.pendingBatches.length);\n if (batches.length === 0) return;\n try {\n const items = batches.flatMap(b => b.items);\n if (items.length === 0) return;\n this.ws.send(JSON.stringify({ type: 'batch', items }));\n } catch {\n this.pendingBatches.unshift(...batches);\n }\n }\n\n close(): void {\n this.closed = true;\n try { this.ws?.close(); } catch {}\n this.ws = undefined;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === 1;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ICNSDevToolsTransport } from '@cnstra/devtools';\nimport {\n CNSAppCommandDTOSchema,\n type TCNSAppBatchMessageDTO,\n} from '@cnstra/devtools-dto';\n\nexport type TCNSDevToolsTransportWsOptions = {\n /** WebSocket URL, e.g. ws://localhost:3141 */\n url: string;\n protocols?: string | string[];\n /** Reconnect delay in ms (default: 1000) */\n reconnectDelayMs?: number;\n /** Max buffered batch items before force flush (default: 100) */\n batchMaxSize?: number;\n /** Provide a WebSocket implementation for Node.js (e.g. `ws`) */\n webSocketImpl?: typeof WebSocket;\n /** Max reconnect attempts (default: Infinity) */\n maxReconnectAttempts?: number;\n consoleLogEnabled?: boolean;\n};\n\nexport class CNSDevToolsTransportWs implements ICNSDevToolsTransport {\n private ws?: WebSocket;\n private connecting = false;\n private closed = false;\n private reconnectAttempts = 0;\n private hasConnectedOnce = false;\n\n private readonly pendingBatches: TCNSAppBatchMessageDTO[] = [];\n private lastTopologyBatch?: TCNSAppBatchMessageDTO;\n private onCommandHandler?: (cmd: any) => void;\n\n constructor(private readonly opts: TCNSDevToolsTransportWsOptions) {}\n\n // ─── ICNSDevToolsTransport ────────────────────────────────────────────────────\n\n async sendBatch(message: TCNSAppBatchMessageDTO): Promise<void> {\n if (message.items.some(i => i.type === 'topology')) {\n this.lastTopologyBatch = message;\n }\n this.pendingBatches.push(message);\n await this.flush();\n }\n\n onStimulationCommand(handler: (cmd: any) => void): () => void {\n this.onCommandHandler = handler;\n return () => { this.onCommandHandler = undefined; };\n }\n\n // ─── Connection management ────────────────────────────────────────────────────\n\n private get WS(): typeof WebSocket {\n const impl = this.opts.webSocketImpl\n ?? (typeof WebSocket !== 'undefined' ? WebSocket : undefined);\n if (!impl) throw new Error('No WebSocket implementation. Pass webSocketImpl option.');\n return impl;\n }\n\n private openSocket(): Promise<void> {\n if (this.ws?.readyState === 1) return Promise.resolve();\n if (this.connecting) {\n return new Promise(resolve => {\n const poll = () => this.ws?.readyState === 1 ? resolve() : setTimeout(poll, 50);\n poll();\n });\n }\n this.connecting = true;\n return new Promise(resolve => {\n const ws = new this.WS(this.opts.url, this.opts.protocols) as WebSocket;\n this.ws = ws;\n\n ws.onopen = () => {\n this.connecting = false;\n this.reconnectAttempts = 0;\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Connected');\n\n if (this.hasConnectedOnce && this.lastTopologyBatch) {\n this.pendingBatches.unshift(this.lastTopologyBatch);\n }\n this.hasConnectedOnce = true;\n this.flush().then(resolve);\n };\n\n ws.onclose = () => {\n this.connecting = false;\n if (!this.closed && this.reconnectAttempts < (this.opts.maxReconnectAttempts ?? Infinity)) {\n this.reconnectAttempts++;\n if (this.opts.consoleLogEnabled) {\n console.log(`[DevTools] Disconnected, reconnecting (attempt ${this.reconnectAttempts})`);\n }\n setTimeout(() => this.openSocket().catch(() => {}), this.opts.reconnectDelayMs ?? 1000);\n } else if (this.reconnectAttempts >= (this.opts.maxReconnectAttempts ?? Infinity)) {\n if (this.opts.consoleLogEnabled) console.log('[DevTools] Max reconnect attempts reached');\n }\n };\n\n ws.onerror = () => { try { ws.close(); } catch {} };\n\n ws.onmessage = (ev: MessageEvent) => {\n try {\n const msg = JSON.parse(typeof ev.data === 'string' ? ev.data : String(ev.data));\n if (\n msg?.type === 'cns.stimulation.resume' ||\n msg?.type === 'cns.stimulation.launch'\n ) {\n const result = CNSAppCommandDTOSchema.safeParse(msg);\n if (result.success) {\n this.onCommandHandler?.(result.data);\n } else if (this.opts.consoleLogEnabled) {\n console.warn('[DevTools] Invalid stimulation command:', result.error.message);\n }\n }\n } catch {}\n };\n });\n }\n\n private async flush(): Promise<void> {\n if (this.pendingBatches.length === 0) return;\n await this.openSocket();\n if (this.ws?.readyState !== 1) return;\n\n const batches = this.pendingBatches.splice(0, this.pendingBatches.length);\n if (batches.length === 0) return;\n try {\n const items = batches.flatMap(b => b.items);\n if (items.length === 0) return;\n this.ws.send(JSON.stringify({ type: 'batch', items }));\n } catch {\n this.pendingBatches.unshift(...batches);\n }\n }\n\n close(): void {\n this.closed = true;\n try { this.ws?.close(); } catch {}\n this.ws = undefined;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === 1;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cnstra/devtools-transport-ws",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "WebSocket transport for CNStra DevTools",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/abaikov/cnstra.git",
|
|
8
|
+
"directory": "packages/devtools-transport-ws"
|
|
9
|
+
},
|
|
5
10
|
"keywords": [
|
|
6
11
|
"devtools",
|
|
7
12
|
"cnstra",
|
|
@@ -27,19 +32,19 @@
|
|
|
27
32
|
"test": "jest",
|
|
28
33
|
"test:watch": "jest --watch",
|
|
29
34
|
"test:coverage": "jest --coverage",
|
|
30
|
-
"prepublishOnly": "npm run test && npm run build"
|
|
35
|
+
"prepublishOnly": "node ../../scripts/check-drift.mjs --gate && npm run test && npm run build"
|
|
31
36
|
},
|
|
32
37
|
"files": [
|
|
33
38
|
"dist"
|
|
34
39
|
],
|
|
35
40
|
"dependencies": {
|
|
36
|
-
"@cnstra/devtools-dto": "^
|
|
41
|
+
"@cnstra/devtools-dto": "^3.0.0"
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
39
|
-
"@cnstra/devtools": "^
|
|
44
|
+
"@cnstra/devtools": "^3.0.0"
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
|
-
"@cnstra/devtools": "^
|
|
47
|
+
"@cnstra/devtools": "^3.0.0",
|
|
43
48
|
"@types/jest": "^29.5.5",
|
|
44
49
|
"jest": "^29.7.0",
|
|
45
50
|
"jest-environment-jsdom": "^29.7.0",
|