export-runtime 0.0.19 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/handler.js +5 -0
  2. package/package.json +1 -1
  3. package/rpc.js +22 -0
package/handler.js CHANGED
@@ -351,6 +351,9 @@ export const createHandler = (moduleMap, generatedTypes, minifiedCore, coreId, m
351
351
 
352
352
  const result = await dispatchMessage(dispatcher, msg, env, wsSession);
353
353
 
354
+ // Don't send if connection closed during dispatch
355
+ if (isClosed) return;
356
+
354
357
  // Extract token from auth responses
355
358
  if (result?.value?.token && msg.type === "auth") {
356
359
  wsSession.token = result.value.token;
@@ -358,6 +361,8 @@ export const createHandler = (moduleMap, generatedTypes, minifiedCore, coreId, m
358
361
 
359
362
  if (result) safeSend(stringify({ ...result, id }));
360
363
  } catch (err) {
364
+ // Don't send errors if connection is closed or error is about closed connection
365
+ if (isClosed || String(err).includes("Connection closed")) return;
361
366
  if (id !== undefined) safeSend(stringify({ type: "error", id, error: String(err) }));
362
367
  }
363
368
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "export-runtime",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "Cloudflare Workers ESM Export Framework Runtime",
5
5
  "keywords": [
6
6
  "cloudflare",
package/rpc.js CHANGED
@@ -38,6 +38,7 @@ export function createRpcDispatcher(moduleMap) {
38
38
  const iterators = new Map();
39
39
  const streams = new Map();
40
40
  let nextId = 1;
41
+ let closed = false;
41
42
 
42
43
  const requireInstance = (id) => {
43
44
  const inst = instances.get(id);
@@ -115,9 +116,11 @@ export function createRpcDispatcher(moduleMap) {
115
116
  },
116
117
 
117
118
  async rpcIterateNext(iteratorId) {
119
+ if (closed) throw new Error("Connection closed");
118
120
  const iter = iterators.get(iteratorId);
119
121
  if (!iter) throw new Error("Iterator not found");
120
122
  const { value, done } = await iter.next();
123
+ if (closed) throw new Error("Connection closed");
121
124
  if (done) iterators.delete(iteratorId);
122
125
  return { type: "iterate-result", value, done: !!done };
123
126
  },
@@ -130,10 +133,12 @@ export function createRpcDispatcher(moduleMap) {
130
133
  },
131
134
 
132
135
  async rpcStreamRead(streamId) {
136
+ if (closed) throw new Error("Connection closed");
133
137
  const entry = streams.get(streamId);
134
138
  if (!entry) throw new Error("Stream not found");
135
139
  if (!entry.reader) entry.reader = entry.stream.getReader();
136
140
  const { value, done } = await entry.reader.read();
141
+ if (closed) throw new Error("Connection closed");
137
142
  if (done) streams.delete(streamId);
138
143
  const v = value instanceof Uint8Array ? Array.from(value) : value;
139
144
  return { type: "stream-result", value: v, done: !!done };
@@ -149,6 +154,23 @@ export function createRpcDispatcher(moduleMap) {
149
154
  },
150
155
 
151
156
  clearAll() {
157
+ closed = true;
158
+ // Cancel all active iterators
159
+ for (const iter of iterators.values()) {
160
+ try {
161
+ if (iter?.return) iter.return(undefined);
162
+ } catch {}
163
+ }
164
+ // Cancel all active streams
165
+ for (const entry of streams.values()) {
166
+ try {
167
+ if (entry.reader) {
168
+ entry.reader.cancel();
169
+ } else if (entry.stream) {
170
+ entry.stream.cancel();
171
+ }
172
+ } catch {}
173
+ }
152
174
  instances.clear();
153
175
  iterators.clear();
154
176
  streams.clear();