@robota-sdk/agent-transport-ws 3.0.0-beta.62 → 3.0.0-beta.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,94 +1,11 @@
1
1
  # @robota-sdk/agent-transport-ws
2
2
 
3
- Framework-agnostic WebSocket transport adapter for exposing `InteractiveSession` over real-time bidirectional connections. Works with any WebSocket implementation (Node.js `ws`, browser `WebSocket`, uWebSockets, etc.) via send/onMessage callbacks — no WebSocket library dependency.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pnpm add @robota-sdk/agent-transport-ws
9
- ```
10
-
11
- ## Usage
12
-
13
- ```typescript
14
- import { createWsHandler } from '@robota-sdk/agent-transport-ws';
15
- import type { InteractiveSession } from '@robota-sdk/agent-sdk';
16
- import { WebSocketServer } from 'ws';
17
-
18
- const wss = new WebSocketServer({ port: 8080 });
19
-
20
- wss.on('connection', (ws) => {
21
- const { onMessage, cleanup } = createWsHandler({
22
- session: interactiveSession,
23
- send: (msg) => ws.send(JSON.stringify(msg)),
24
- });
25
-
26
- ws.on('message', (data) => onMessage(String(data)));
27
- ws.on('close', cleanup);
28
- });
29
- ```
30
-
31
- ## Message Protocol
32
-
33
- All messages are JSON-encoded objects with a `type` field.
34
-
35
- ### Client to Server
36
-
37
- | type | payload | maps to |
38
- | --------------- | --------------------------------- | ---------------------------- |
39
- | `submit` | `{ prompt: string }` | `session.submit(prompt)` |
40
- | `command` | `{ name: string, args?: string }` | `session.executeCommand()` |
41
- | `abort` | — | `session.abort()` |
42
- | `cancel-queue` | — | `session.cancelQueue()` |
43
- | `get-messages` | — | `session.getMessages()` |
44
- | `get-context` | — | `session.getContextState()` |
45
- | `get-executing` | — | `session.isExecuting()` |
46
- | `get-pending` | — | `session.getPendingPrompt()` |
47
-
48
- ### Server to Client (pushed events)
49
-
50
- | type | payload | source |
51
- | ----------------------- | ----------------------------------- | ---------------------------------------- |
52
- | `text_delta` | `{ delta: string }` | InteractiveSession event |
53
- | `tool_start` | `{ state: IToolState }` | InteractiveSession event |
54
- | `tool_end` | `{ state: IToolState }` | InteractiveSession event |
55
- | `background_task_event` | `{ event: TBackgroundTaskEvent }` | InteractiveSession background task event |
56
- | `thinking` | `{ isThinking: boolean }` | InteractiveSession event |
57
- | `complete` | `{ result: IExecutionResult }` | InteractiveSession event |
58
- | `interrupted` | `{ result: IExecutionResult }` | InteractiveSession event |
59
- | `error` | `{ message: string }` | InteractiveSession event |
60
- | `command_result` | `{ name, message, success, data? }` | command response |
61
- | `messages` | `{ messages: TUniversalMessage[] }` | get-messages response |
62
- | `context` | `{ state: IContextWindowState }` | get-context response |
63
- | `executing` | `{ executing: boolean }` | get-executing response |
64
- | `pending` | `{ pending: string\|null }` | get-pending response |
65
- | `protocol_error` | `{ message: string }` | invalid client message |
66
-
67
- ## ITransportAdapter
68
-
69
- The WebSocket transport implements the `ITransportAdapter` interface from `@robota-sdk/agent-sdk`:
3
+ WebSocket transport and wire protocol for the Robota SDK. Consumers that only need the WS message
4
+ types (e.g. browser monitors) depend on this package without pulling React/Ink/Hono.
70
5
 
71
6
  ```typescript
72
- import { createWsTransport } from '@robota-sdk/agent-transport-ws';
73
- import type { ITransportAdapter } from '@robota-sdk/agent-sdk';
74
-
75
- const transport: ITransportAdapter = createWsTransport({
76
- send: (msg) => ws.send(JSON.stringify(msg)),
77
- });
78
-
79
- transport.attach(interactiveSession);
80
- await transport.start();
81
-
82
- // Wire incoming messages
83
- ws.on('message', (data) => transport.onMessage(String(data)));
84
- ws.on('close', () => transport.stop());
7
+ import { WsTransport, createWsHandler } from '@robota-sdk/agent-transport-ws';
8
+ import type { TServerMessage, TClientMessage } from '@robota-sdk/agent-transport-ws';
85
9
  ```
86
10
 
87
- ## Dependencies
88
-
89
- - `@robota-sdk/agent-sdk` — `InteractiveSession`
90
- - No WebSocket library dependency (framework-agnostic)
91
-
92
- ## Background Work
93
-
94
- When the attached `InteractiveSession` emits background task updates, the WebSocket transport forwards them as protocol messages so clients can render subagent jobs, transcript references, and terminal states without polling session JSON.
11
+ See [docs/SPEC.md](./docs/SPEC.md) for the full contract.
@@ -1,299 +1 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- createWsHandler: () => createWsHandler,
24
- createWsTransport: () => createWsTransport
25
- });
26
- module.exports = __toCommonJS(index_exports);
27
-
28
- // src/ws-background-messages.ts
29
- function handleBackgroundQueryMessage(session, send, msg) {
30
- if (msg.type === "get-background-tasks") {
31
- send({ type: "background_tasks", tasks: session.listBackgroundTasks(msg.filter) });
32
- return;
33
- }
34
- if (msg.type === "get-background-task") {
35
- sendBackgroundTaskSnapshot(session, send, msg);
36
- return;
37
- }
38
- if (msg.type === "get-background-job-groups") {
39
- send({ type: "background_job_groups", groups: session.listBackgroundJobGroups() });
40
- return;
41
- }
42
- if (msg.type === "get-background-job-group") {
43
- sendBackgroundJobGroupSnapshot(session, send, msg);
44
- return;
45
- }
46
- if (msg.type === "wait-background-job-group") {
47
- sendBackgroundJobGroupWaitResult(session, send, msg);
48
- return;
49
- }
50
- sendBackgroundTaskLogPage(session, send, msg);
51
- }
52
- function handleBackgroundControlMessage(session, send, msg) {
53
- if (!msg.taskId) {
54
- send({ type: "protocol_error", message: "taskId is required" });
55
- return;
56
- }
57
- if (msg.type === "cancel-background-task") {
58
- sendBackgroundTaskControlResult(
59
- send,
60
- "cancel",
61
- msg.taskId,
62
- session.cancelBackgroundTask(msg.taskId, msg.reason)
63
- );
64
- return;
65
- }
66
- if (msg.type === "close-background-task") {
67
- sendBackgroundTaskControlResult(
68
- send,
69
- "close",
70
- msg.taskId,
71
- session.closeBackgroundTask(msg.taskId)
72
- );
73
- return;
74
- }
75
- sendBackgroundTaskInput(session, send, msg);
76
- }
77
- function sendBackgroundTaskSnapshot(session, send, msg) {
78
- if (!msg.taskId) {
79
- send({ type: "protocol_error", message: "taskId is required" });
80
- return;
81
- }
82
- send({
83
- type: "background_task",
84
- taskId: msg.taskId,
85
- task: session.getBackgroundTask(msg.taskId) ?? null
86
- });
87
- }
88
- function sendBackgroundTaskLogPage(session, send, msg) {
89
- if (!msg.taskId) {
90
- send({ type: "protocol_error", message: "taskId is required" });
91
- return;
92
- }
93
- session.readBackgroundTaskLog(msg.taskId, msg.cursor).then(
94
- (page) => send({ type: "background_task_log", taskId: msg.taskId, page }),
95
- (error) => send({ type: "protocol_error", message: error.message })
96
- );
97
- }
98
- function sendBackgroundJobGroupSnapshot(session, send, msg) {
99
- if (!msg.groupId) {
100
- send({ type: "protocol_error", message: "groupId is required" });
101
- return;
102
- }
103
- send({
104
- type: "background_job_group",
105
- groupId: msg.groupId,
106
- group: session.getBackgroundJobGroup(msg.groupId) ?? null
107
- });
108
- }
109
- function sendBackgroundJobGroupWaitResult(session, send, msg) {
110
- if (!msg.groupId) {
111
- send({ type: "protocol_error", message: "groupId is required" });
112
- return;
113
- }
114
- session.waitBackgroundJobGroup(msg.groupId).then(
115
- (group) => send({ type: "background_job_group", groupId: msg.groupId, group }),
116
- (error) => send({ type: "protocol_error", message: error.message })
117
- );
118
- }
119
- function sendBackgroundTaskInput(session, send, msg) {
120
- if (!msg.input) {
121
- send({ type: "protocol_error", message: "input is required" });
122
- return;
123
- }
124
- sendBackgroundTaskControlResult(
125
- send,
126
- "send",
127
- msg.taskId,
128
- session.sendBackgroundTask(msg.taskId, msg.input)
129
- );
130
- }
131
- function sendBackgroundTaskControlResult(send, action, taskId, operation) {
132
- operation.then(
133
- () => send({ type: "background_task_control_result", action, taskId, success: true }),
134
- (error) => send({
135
- type: "background_task_control_result",
136
- action,
137
- taskId,
138
- success: false,
139
- message: error.message
140
- })
141
- );
142
- }
143
-
144
- // src/ws-handler.ts
145
- function createWsHandler(options) {
146
- const cleanup = subscribeSessionEvents(options.session, options.send);
147
- const onMessage = createWsMessageHandler(options.session, options.send);
148
- return { onMessage, cleanup };
149
- }
150
- function subscribeSessionEvents(session, send) {
151
- const onUserMessage = (content) => send({ type: "user_message", content });
152
- const onTextDelta = (delta) => send({ type: "text_delta", delta });
153
- const onToolStart = (state) => send({ type: "tool_start", state });
154
- const onToolEnd = (state) => send({ type: "tool_end", state });
155
- const onThinking = (isThinking) => send({ type: "thinking", isThinking });
156
- const onComplete = (result) => send({ type: "complete", result });
157
- const onInterrupted = (result) => send({ type: "interrupted", result });
158
- const onError = (error) => send({ type: "error", message: error.message });
159
- const onBackgroundTaskEvent = (event) => send({ type: "background_task_event", event });
160
- const onBackgroundJobGroupEvent = (event) => send({ type: "background_job_group_event", event });
161
- session.on("user_message", onUserMessage);
162
- session.on("text_delta", onTextDelta);
163
- session.on("tool_start", onToolStart);
164
- session.on("tool_end", onToolEnd);
165
- session.on("thinking", onThinking);
166
- session.on("complete", onComplete);
167
- session.on("interrupted", onInterrupted);
168
- session.on("error", onError);
169
- session.on("background_task_event", onBackgroundTaskEvent);
170
- session.on("background_job_group_event", onBackgroundJobGroupEvent);
171
- return () => {
172
- session.off("user_message", onUserMessage);
173
- session.off("text_delta", onTextDelta);
174
- session.off("tool_start", onToolStart);
175
- session.off("tool_end", onToolEnd);
176
- session.off("thinking", onThinking);
177
- session.off("complete", onComplete);
178
- session.off("interrupted", onInterrupted);
179
- session.off("error", onError);
180
- session.off("background_task_event", onBackgroundTaskEvent);
181
- session.off("background_job_group_event", onBackgroundJobGroupEvent);
182
- };
183
- }
184
- function createWsMessageHandler(session, send) {
185
- return (data) => {
186
- const msg = parseClientMessage(data, send);
187
- if (!msg) return;
188
- handleClientMessage(session, send, msg);
189
- };
190
- }
191
- function parseClientMessage(data, send) {
192
- try {
193
- return JSON.parse(data);
194
- } catch {
195
- send({ type: "protocol_error", message: "Invalid JSON" });
196
- return null;
197
- }
198
- }
199
- function handleClientMessage(session, send, msg) {
200
- if (isSessionControlMessage(msg)) {
201
- handleSessionControlMessage(session, send, msg);
202
- return;
203
- }
204
- if (isSessionQueryMessage(msg)) {
205
- handleSessionQueryMessage(session, send, msg);
206
- return;
207
- }
208
- if (isBackgroundQueryMessage(msg)) {
209
- handleBackgroundQueryMessage(session, send, msg);
210
- return;
211
- }
212
- if (isBackgroundControlMessage(msg)) {
213
- handleBackgroundControlMessage(session, send, msg);
214
- return;
215
- }
216
- send({ type: "protocol_error", message: `Unknown message type: ${getMessageType(msg)}` });
217
- }
218
- function getMessageType(msg) {
219
- return msg.type;
220
- }
221
- function isSessionControlMessage(msg) {
222
- return msg.type === "submit" || msg.type === "command" || msg.type === "abort" || msg.type === "cancel-queue";
223
- }
224
- function isSessionQueryMessage(msg) {
225
- return msg.type === "get-messages" || msg.type === "get-context" || msg.type === "get-executing" || msg.type === "get-pending";
226
- }
227
- function isBackgroundQueryMessage(msg) {
228
- return msg.type === "get-background-tasks" || msg.type === "get-background-task" || msg.type === "read-background-task-log" || msg.type === "get-background-job-groups" || msg.type === "get-background-job-group" || msg.type === "wait-background-job-group";
229
- }
230
- function isBackgroundControlMessage(msg) {
231
- return msg.type === "cancel-background-task" || msg.type === "close-background-task" || msg.type === "send-background-task";
232
- }
233
- function handleSessionControlMessage(session, send, msg) {
234
- if (msg.type === "submit") {
235
- if (!msg.prompt) {
236
- send({ type: "protocol_error", message: "prompt is required" });
237
- return;
238
- }
239
- session.submit(msg.prompt);
240
- } else if (msg.type === "command") {
241
- if (!msg.name) {
242
- send({ type: "protocol_error", message: "name is required" });
243
- return;
244
- }
245
- session.executeCommand(msg.name, msg.args ?? "").then((result) => {
246
- send({
247
- type: "command_result",
248
- name: msg.name,
249
- message: result?.message ?? `Unknown command: ${msg.name}`,
250
- success: result?.success ?? false,
251
- data: result?.data
252
- });
253
- });
254
- } else if (msg.type === "abort") {
255
- session.abort();
256
- } else {
257
- session.cancelQueue();
258
- }
259
- }
260
- function handleSessionQueryMessage(session, send, msg) {
261
- if (msg.type === "get-messages") {
262
- send({ type: "messages", messages: session.getMessages() });
263
- } else if (msg.type === "get-context") {
264
- send({ type: "context", state: session.getContextState() });
265
- } else if (msg.type === "get-executing") {
266
- send({ type: "executing", executing: session.isExecuting() });
267
- } else {
268
- send({ type: "pending", pending: session.getPendingPrompt() });
269
- }
270
- }
271
-
272
- // src/ws-transport.ts
273
- function createWsTransport(options) {
274
- let session = null;
275
- let cleanup = null;
276
- return {
277
- name: "ws",
278
- onMessage: null,
279
- attach(s) {
280
- session = s;
281
- },
282
- async start() {
283
- if (!session) throw new Error("No session attached. Call attach() first.");
284
- const handler = createWsHandler({ session, send: options.send });
285
- cleanup = handler.cleanup;
286
- this.onMessage = handler.onMessage;
287
- },
288
- async stop() {
289
- cleanup?.();
290
- cleanup = null;
291
- this.onMessage = null;
292
- }
293
- };
294
- }
295
- // Annotate the CommonJS export names for ESM import in node:
296
- 0 && (module.exports = {
297
- createWsHandler,
298
- createWsTransport
299
- });
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:http"),t=require("ws");function n(e,t,n){if(n.type===`get-background-tasks`){t({type:`background_tasks`,tasks:e.listBackgroundTasks(n.filter)});return}if(n.type===`get-background-task`){i(e,t,n);return}if(n.type===`get-background-job-groups`){t({type:`background_job_groups`,groups:e.listBackgroundJobGroups()});return}if(n.type===`get-background-job-group`){o(e,t,n);return}if(n.type===`wait-background-job-group`){s(e,t,n);return}a(e,t,n)}function r(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}if(n.type===`cancel-background-task`){l(t,`cancel`,n.taskId,e.cancelBackgroundTask(n.taskId,n.reason));return}if(n.type===`close-background-task`){l(t,`close`,n.taskId,e.closeBackgroundTask(n.taskId));return}c(e,t,n)}function i(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}t({type:`background_task`,taskId:n.taskId,task:e.getBackgroundTask(n.taskId)??null})}function a(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}e.readBackgroundTaskLog(n.taskId,n.cursor).then(e=>t({type:`background_task_log`,taskId:n.taskId,page:e}),e=>t({type:`protocol_error`,message:e.message}))}function o(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}t({type:`background_job_group`,groupId:n.groupId,group:e.getBackgroundJobGroup(n.groupId)??null})}function s(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}e.waitBackgroundJobGroup(n.groupId).then(e=>t({type:`background_job_group`,groupId:n.groupId,group:e}),e=>t({type:`protocol_error`,message:e.message}))}function c(e,t,n){if(!n.input){t({type:`protocol_error`,message:`input is required`});return}l(t,`send`,n.taskId,e.sendBackgroundTask(n.taskId,n.input))}function l(e,t,n,r){r.then(()=>e({type:`background_task_control_result`,action:t,taskId:n,success:!0}),r=>e({type:`background_task_control_result`,action:t,taskId:n,success:!1,message:r.message}))}function u(e){let t=d(e.session,e.send);return{onMessage:f(e.session,e.send),cleanup:t}}function d(e,t){let n=e=>t({type:`user_message`,content:e}),r=e=>t({type:`text_delta`,delta:e}),i=e=>t({type:`tool_start`,state:e}),a=e=>t({type:`tool_end`,state:e}),o=e=>t({type:`thinking`,isThinking:e}),s=e=>t({type:`complete`,result:e}),c=e=>t({type:`interrupted`,result:e}),l=e=>t({type:`error`,message:e.message}),u=e=>t({type:`background_task_event`,event:e}),d=e=>t({type:`background_job_group_event`,event:e}),f=e=>t({type:`execution_workspace_event`,snapshot:e.snapshot});return e.on(`user_message`,n),e.on(`text_delta`,r),e.on(`tool_start`,i),e.on(`tool_end`,a),e.on(`thinking`,o),e.on(`complete`,s),e.on(`interrupted`,c),e.on(`error`,l),e.on(`background_task_event`,u),e.on(`background_job_group_event`,d),e.on(`execution_workspace_event`,f),()=>{e.off(`user_message`,n),e.off(`text_delta`,r),e.off(`tool_start`,i),e.off(`tool_end`,a),e.off(`thinking`,o),e.off(`complete`,s),e.off(`interrupted`,c),e.off(`error`,l),e.off(`background_task_event`,u),e.off(`background_job_group_event`,d),e.off(`execution_workspace_event`,f)}}function f(e,t){return n=>{let r=p(n,t);r&&m(e,t,r)}}function p(e,t){try{return JSON.parse(e)}catch{return t({type:`protocol_error`,message:`Invalid JSON`}),null}}function m(e,t,i){if(g(i)){b(e,t,i);return}if(_(i)){x(e,t,i);return}if(v(i)){n(e,t,i);return}if(y(i)){r(e,t,i);return}t({type:`protocol_error`,message:`Unknown message type: ${h(i)}`})}function h(e){return e.type}function g(e){return e.type===`submit`||e.type===`command`||e.type===`abort`||e.type===`cancel-queue`}function _(e){return e.type===`get-messages`||e.type===`get-context`||e.type===`get-executing`||e.type===`get-pending`||e.type===`get-execution-workspace`}function v(e){return e.type===`get-background-tasks`||e.type===`get-background-task`||e.type===`read-background-task-log`||e.type===`get-background-job-groups`||e.type===`get-background-job-group`||e.type===`wait-background-job-group`}function y(e){return e.type===`cancel-background-task`||e.type===`close-background-task`||e.type===`send-background-task`}function b(e,t,n){if(n.type===`submit`){if(!n.prompt){t({type:`protocol_error`,message:`prompt is required`});return}e.submit(n.prompt)}else if(n.type===`command`){if(!n.name){t({type:`protocol_error`,message:`name is required`});return}e.executeCommand(n.name,n.args??``).then(e=>{t({type:`command_result`,name:n.name,message:e?.message??`Unknown command: ${n.name}`,success:e?.success??!1,data:e?.data})})}else n.type===`abort`?e.abort():e.cancelQueue()}function x(e,t,n){n.type===`get-messages`?t({type:`messages`,messages:e.getMessages()}):n.type===`get-context`?t({type:`context`,state:e.getContextState()}):n.type===`get-executing`?t({type:`executing`,executing:e.isExecuting()}):n.type===`get-execution-workspace`?t({type:`execution_workspace_event`,snapshot:e.getExecutionWorkspaceSnapshot()}):t({type:`pending`,pending:e.getPendingPrompt()})}function S(e){let t=null,n=null;return{name:`ws`,onMessage:null,attach(e){t=e},async start(){if(!t)throw Error(`No session attached. Call attach() first.`);let r=u({session:t,send:e.send});n=r.cleanup,this.onMessage=r.onMessage},async stop(){n?.(),n=null,this.onMessage=null}}}const C=7070;var w=class{name=`ws`;defaultEnabled=!0;optionsSchema={port:{type:`number`,description:`WebSocket server port`,default:C},maxRetries:{type:`number`,description:`Port retry attempts when port is occupied`,default:20}};session=null;stopFn=null;port;maxRetries;constructor(e={}){this.port=e.port??C,this.maxRetries=e.maxRetries??20}attach(e){this.session=e}async start(){if(!this.session)throw Error(`WsTransport: attach() must be called before start()`);let e=await this.bindWithRetry(this.session,this.port,this.maxRetries);this.stopFn=e.stop}async stop(){await this.stopFn?.(),this.stopFn=null}validateOptions(e){let{port:t,maxRetries:n}=e;return!(t!==void 0&&(typeof t!=`number`||t<1||t>65535)||n!==void 0&&(typeof n!=`number`||n<0))}bindWithRetry(e,t,n){return this.tryBind(e,t).catch(r=>{if(r.code===`EADDRINUSE`&&n>0)return this.bindWithRetry(e,t+1,n-1);throw r})}tryBind(n,r){return new Promise((i,a)=>{let o=(0,e.createServer)((e,t)=>{t.writeHead(400).end(`WebSocket endpoint`)});o.on(`error`,e=>{o.close(),a(e)}),o.listen(r,`127.0.0.1`,()=>{let e=new t.WebSocketServer({server:o});e.on(`connection`,e=>{let r=n=>{e.readyState===t.WebSocket.OPEN&&e.send(JSON.stringify(n))},{onMessage:i,cleanup:a}=u({session:n,send:r});e.on(`message`,e=>i(String(e))),e.on(`close`,a),e.on(`error`,a),r({type:`messages`,messages:n.getMessages()}),r({type:`execution_workspace_event`,snapshot:n.getExecutionWorkspaceSnapshot()})}),i({stop:()=>new Promise(t=>{e.close(()=>o.close(()=>t()))})})})})}};exports.WsTransport=w,exports.createWsHandler=u,exports.createWsTransport=S;