export-runtime 0.0.19 → 0.0.21
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/handler.js +43 -22
- package/package.json +1 -1
- package/rpc.js +22 -0
package/handler.js
CHANGED
|
@@ -323,6 +323,7 @@ export const createHandler = (moduleMap, generatedTypes, minifiedCore, coreId, m
|
|
|
323
323
|
// Track session state and connection state for this WebSocket connection
|
|
324
324
|
const wsSession = { token: null };
|
|
325
325
|
let isClosed = false;
|
|
326
|
+
const pendingOps = new Set();
|
|
326
327
|
|
|
327
328
|
// Safe send that ignores errors when connection is closed
|
|
328
329
|
const safeSend = (data) => {
|
|
@@ -334,32 +335,51 @@ export const createHandler = (moduleMap, generatedTypes, minifiedCore, coreId, m
|
|
|
334
335
|
}
|
|
335
336
|
};
|
|
336
337
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
338
|
+
// Wrap async operations to track them
|
|
339
|
+
const trackOp = async (op) => {
|
|
340
|
+
const promise = op();
|
|
341
|
+
pendingOps.add(promise);
|
|
340
342
|
try {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// Direct token send on reconnect - just update session
|
|
347
|
-
wsSession.token = msg.token;
|
|
348
|
-
safeSend(stringify({ type: "auth-result", id, success: true }));
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
343
|
+
return await promise;
|
|
344
|
+
} finally {
|
|
345
|
+
pendingOps.delete(promise);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
351
348
|
|
|
352
|
-
|
|
349
|
+
server.addEventListener("message", (event) => {
|
|
350
|
+
if (isClosed) return;
|
|
353
351
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
352
|
+
// Handle message asynchronously but don't await it
|
|
353
|
+
trackOp(async () => {
|
|
354
|
+
let id;
|
|
355
|
+
try {
|
|
356
|
+
if (isClosed) return;
|
|
357
|
+
const msg = parse(event.data);
|
|
358
|
+
id = msg.id;
|
|
359
|
+
|
|
360
|
+
// Handle auth token updates (on reconnect or explicit setToken)
|
|
361
|
+
if (msg.type === "auth" && msg.token && !msg.method) {
|
|
362
|
+
wsSession.token = msg.token;
|
|
363
|
+
safeSend(stringify({ type: "auth-result", id, success: true }));
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
358
366
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
if (isClosed) return;
|
|
368
|
+
const result = await dispatchMessage(dispatcher, msg, env, wsSession);
|
|
369
|
+
|
|
370
|
+
if (isClosed) return;
|
|
371
|
+
|
|
372
|
+
// Extract token from auth responses
|
|
373
|
+
if (result?.value?.token && msg.type === "auth") {
|
|
374
|
+
wsSession.token = result.value.token;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (result) safeSend(stringify({ ...result, id }));
|
|
378
|
+
} catch (err) {
|
|
379
|
+
if (isClosed || String(err).includes("Connection closed")) return;
|
|
380
|
+
if (id !== undefined) safeSend(stringify({ type: "error", id, error: String(err) }));
|
|
381
|
+
}
|
|
382
|
+
});
|
|
363
383
|
});
|
|
364
384
|
|
|
365
385
|
server.addEventListener("close", () => {
|
|
@@ -369,6 +389,7 @@ export const createHandler = (moduleMap, generatedTypes, minifiedCore, coreId, m
|
|
|
369
389
|
|
|
370
390
|
server.addEventListener("error", () => {
|
|
371
391
|
isClosed = true;
|
|
392
|
+
if (onClose) onClose();
|
|
372
393
|
});
|
|
373
394
|
};
|
|
374
395
|
|
package/package.json
CHANGED
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();
|