export-runtime 0.0.6 → 0.0.7

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.
@@ -220,25 +220,88 @@ lines.push("}>;");
220
220
 
221
221
  const typeDefinitions = lines.join("\n");
222
222
 
223
- // --- Minify core module ---
223
+ // --- Minify core modules ---
224
224
 
225
225
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
226
- const { CORE_CODE } = await import(path.join(__dirname, "..", "client.js"));
226
+ const { CORE_CODE, SHARED_CORE_CODE } = await import(path.join(__dirname, "..", "client.js"));
227
227
 
228
- // CORE_CODE uses import.meta.url for WS URL — no placeholders needed.
229
228
  const minified = minifySync("_core.js", CORE_CODE);
230
229
  if (minified.errors?.length) {
231
- console.error("Minification errors:", minified.errors);
230
+ console.error("Minification errors (core):", minified.errors);
231
+ }
232
+
233
+ const minifiedShared = minifySync("_core-shared.js", SHARED_CORE_CODE);
234
+ if (minifiedShared.errors?.length) {
235
+ console.error("Minification errors (shared core):", minifiedShared.errors);
232
236
  }
233
237
 
234
238
  // Generate a unique ID per build for cache-busting the core module path
235
239
  const coreId = crypto.randomUUID();
236
240
 
237
- // Write as a JS module that exports type definitions, minified core, and core ID
241
+ // Write as a JS module
238
242
  const outPath = path.join(cwd, ".export-types.js");
239
243
  fs.writeFileSync(outPath, [
240
244
  `export default ${JSON.stringify(typeDefinitions)};`,
241
245
  `export const minifiedCore = ${JSON.stringify(minified.code)};`,
246
+ `export const minifiedSharedCore = ${JSON.stringify(minifiedShared.code)};`,
242
247
  `export const coreId = ${JSON.stringify(coreId)};`,
243
248
  ].join("\n") + "\n");
249
+
250
+ // Generate Worker-side shared import module (.export-shared.js)
251
+ const exportNames = [];
252
+ for (const node of program.body) {
253
+ if (node.type !== "ExportNamedDeclaration" || !node.declaration) continue;
254
+ const decl = node.declaration;
255
+ if (decl.id?.name) exportNames.push(decl.id.name);
256
+ else if (decl.declarations) {
257
+ for (const d of decl.declarations) {
258
+ if (d.id?.name) exportNames.push(d.id.name);
259
+ }
260
+ }
261
+ }
262
+
263
+ const sharedModulePath = path.join(cwd, ".export-shared.js");
264
+ const sharedModuleLines = [
265
+ `import { env } from "cloudflare:workers";`,
266
+ ``,
267
+ `const getStub = (room = "default") =>`,
268
+ ` env.SHARED_EXPORT.get(env.SHARED_EXPORT.idFromName(room));`,
269
+ ``,
270
+ `const createSharedInstanceProxy = (stub, instanceId, path = []) =>`,
271
+ ` new Proxy(function(){}, {`,
272
+ ` get(_, prop) {`,
273
+ ` if (prop === "then" || prop === Symbol.toStringTag) return undefined;`,
274
+ ` if (prop === Symbol.dispose || prop === Symbol.asyncDispose || prop === "[release]")`,
275
+ ` return () => stub.rpcRelease(instanceId);`,
276
+ ` return createSharedInstanceProxy(stub, instanceId, [...path, prop]);`,
277
+ ` },`,
278
+ ` async apply(_, __, args) {`,
279
+ ` const r = await stub.rpcInstanceCall(instanceId, path, args);`,
280
+ ` return r.value;`,
281
+ ` },`,
282
+ ` });`,
283
+ ``,
284
+ `const createSharedProxy = (stub, path = []) =>`,
285
+ ` new Proxy(function(){}, {`,
286
+ ` get(_, prop) {`,
287
+ ` if (prop === "then" || prop === Symbol.toStringTag) return undefined;`,
288
+ ` return createSharedProxy(stub, [...path, prop]);`,
289
+ ` },`,
290
+ ` async apply(_, __, args) {`,
291
+ ` const r = await stub.rpcCall(path, args);`,
292
+ ` return r.value;`,
293
+ ` },`,
294
+ ` async construct(_, args) {`,
295
+ ` const r = await stub.rpcConstruct(path, args);`,
296
+ ` return createSharedInstanceProxy(stub, r.instanceId);`,
297
+ ` },`,
298
+ ` });`,
299
+ ``,
300
+ `const _stub = getStub();`,
301
+ ...exportNames.map(n => `export const ${n} = createSharedProxy(_stub, [${JSON.stringify(n)}]);`),
302
+ `export { getStub };`,
303
+ ];
304
+ fs.writeFileSync(sharedModulePath, sharedModuleLines.join("\n") + "\n");
305
+
244
306
  console.log("Generated type definitions + minified core →", outPath);
307
+ console.log("Generated shared import module →", sharedModulePath);
package/client.js CHANGED
@@ -1,27 +1,19 @@
1
- // Core module code - self-contained ES module that derives WS URL from import.meta.url.
2
- // Served at /_core.js with long cache. Exports createProxy and createUploadStream.
3
- export const CORE_CODE = `
1
+ // Core module template. __WS_SUFFIX__ is replaced: "./" for normal, "./?shared" for shared.
2
+ const CORE_TEMPLATE = `
4
3
  const stringify = (value) => {
5
4
  const stringified = [];
6
5
  const indexes = new Map();
7
6
  let p = 0;
8
-
9
7
  const flatten = (thing) => {
10
- if (typeof thing === 'function') {
11
- throw new Error('Cannot stringify a function');
12
- }
13
-
8
+ if (typeof thing === 'function') throw new Error('Cannot stringify a function');
14
9
  if (indexes.has(thing)) return indexes.get(thing);
15
-
16
10
  if (thing === undefined) return -1;
17
11
  if (Number.isNaN(thing)) return -3;
18
12
  if (thing === Infinity) return -4;
19
13
  if (thing === -Infinity) return -5;
20
14
  if (thing === 0 && 1 / thing < 0) return -6;
21
-
22
15
  const index = p++;
23
16
  indexes.set(thing, index);
24
-
25
17
  if (typeof thing === 'boolean' || typeof thing === 'number' || typeof thing === 'string' || thing === null) {
26
18
  stringified[index] = thing;
27
19
  } else if (thing instanceof Date) {
@@ -38,73 +30,37 @@ const stringify = (value) => {
38
30
  stringified[index] = ['Set', ...[...thing].map(flatten)];
39
31
  } else if (thing instanceof Map) {
40
32
  stringified[index] = ['Map', ...[...thing].map(([k, v]) => [flatten(k), flatten(v)])];
41
- } else if (thing instanceof Int8Array) {
42
- stringified[index] = ['Int8Array', ...[...thing].map(flatten)];
43
- } else if (thing instanceof Uint8Array) {
44
- stringified[index] = ['Uint8Array', ...[...thing].map(flatten)];
45
- } else if (thing instanceof Uint8ClampedArray) {
46
- stringified[index] = ['Uint8ClampedArray', ...[...thing].map(flatten)];
47
- } else if (thing instanceof Int16Array) {
48
- stringified[index] = ['Int16Array', ...[...thing].map(flatten)];
49
- } else if (thing instanceof Uint16Array) {
50
- stringified[index] = ['Uint16Array', ...[...thing].map(flatten)];
51
- } else if (thing instanceof Int32Array) {
52
- stringified[index] = ['Int32Array', ...[...thing].map(flatten)];
53
- } else if (thing instanceof Uint32Array) {
54
- stringified[index] = ['Uint32Array', ...[...thing].map(flatten)];
55
- } else if (thing instanceof Float32Array) {
56
- stringified[index] = ['Float32Array', ...[...thing].map(flatten)];
57
- } else if (thing instanceof Float64Array) {
58
- stringified[index] = ['Float64Array', ...[...thing].map(flatten)];
59
- } else if (thing instanceof BigInt64Array) {
60
- stringified[index] = ['BigInt64Array', ...[...thing].map(flatten)];
61
- } else if (thing instanceof BigUint64Array) {
62
- stringified[index] = ['BigUint64Array', ...[...thing].map(flatten)];
33
+ } else if (ArrayBuffer.isView(thing)) {
34
+ stringified[index] = [thing[Symbol.toStringTag], ...[...thing].map(flatten)];
63
35
  } else if (thing instanceof ArrayBuffer) {
64
36
  stringified[index] = ['ArrayBuffer', ...[...new Uint8Array(thing)].map(flatten)];
65
37
  } else if (Array.isArray(thing)) {
66
38
  stringified[index] = thing.map(flatten);
67
39
  } else if (typeof thing === 'object') {
68
40
  const obj = {};
69
- for (const key of Object.keys(thing)) {
70
- obj[key] = flatten(thing[key]);
71
- }
41
+ for (const key of Object.keys(thing)) obj[key] = flatten(thing[key]);
72
42
  stringified[index] = obj;
73
43
  } else {
74
44
  throw new Error('Cannot stringify ' + typeof thing);
75
45
  }
76
-
77
46
  return index;
78
47
  };
79
-
80
48
  flatten(value);
81
49
  return JSON.stringify(stringified);
82
50
  };
83
51
 
84
- const UNDEFINED = -1;
85
- const HOLE = -2;
86
- const NAN = -3;
87
- const POSITIVE_INFINITY = -4;
88
- const NEGATIVE_INFINITY = -5;
89
- const NEGATIVE_ZERO = -6;
90
-
91
52
  const parse = (serialized) => {
92
53
  if (serialized === '') return undefined;
93
54
  const values = JSON.parse(serialized);
94
55
  const hydrated = new Array(values.length);
95
-
96
56
  const hydrate = (index) => {
97
- if (index === UNDEFINED) return undefined;
98
- if (index === HOLE) return undefined;
99
- if (index === NAN) return NaN;
100
- if (index === POSITIVE_INFINITY) return Infinity;
101
- if (index === NEGATIVE_INFINITY) return -Infinity;
102
- if (index === NEGATIVE_ZERO) return -0;
103
-
57
+ if (index === -1 || index === -2) return undefined;
58
+ if (index === -3) return NaN;
59
+ if (index === -4) return Infinity;
60
+ if (index === -5) return -Infinity;
61
+ if (index === -6) return -0;
104
62
  if (hydrated[index] !== undefined) return hydrated[index];
105
-
106
63
  const value = values[index];
107
-
108
64
  if (typeof value === 'number' || typeof value === 'string' || typeof value === 'boolean' || value === null) {
109
65
  hydrated[index] = value;
110
66
  } else if (Array.isArray(value)) {
@@ -125,15 +81,16 @@ const parse = (serialized) => {
125
81
  break;
126
82
  case 'ArrayBuffer': {
127
83
  const bytes = value.slice(1).map(hydrate);
128
- const buffer = new ArrayBuffer(bytes.length);
129
- new Uint8Array(buffer).set(bytes);
130
- hydrated[index] = buffer;
84
+ const buf = new ArrayBuffer(bytes.length);
85
+ new Uint8Array(buf).set(bytes);
86
+ hydrated[index] = buf;
131
87
  break;
132
88
  }
133
- default:
89
+ default: {
134
90
  const arr = new Array(value.length);
135
91
  hydrated[index] = arr;
136
92
  for (let i = 0; i < value.length; i++) arr[i] = hydrate(value[i]);
93
+ }
137
94
  }
138
95
  } else {
139
96
  const arr = new Array(value.length);
@@ -145,38 +102,29 @@ const parse = (serialized) => {
145
102
  hydrated[index] = obj;
146
103
  for (const key in value) obj[key] = hydrate(value[key]);
147
104
  }
148
-
149
105
  return hydrated[index];
150
106
  };
151
-
152
107
  return hydrate(0);
153
108
  };
154
109
 
155
- const _u = new URL("./", import.meta.url);
110
+ const _u = new URL("__WS_SUFFIX__", import.meta.url);
156
111
  _u.protocol = _u.protocol === "https:" ? "wss:" : "ws:";
157
112
  const ws = new WebSocket(_u.href);
158
113
  const pending = new Map();
159
114
  let nextId = 1;
160
- let keepaliveInterval = null;
115
+ let keepaliveInterval;
161
116
 
162
117
  const ready = new Promise((resolve, reject) => {
163
118
  ws.onopen = () => {
164
119
  keepaliveInterval = setInterval(() => {
165
- if (ws.readyState === WebSocket.OPEN) {
166
- ws.send(stringify({ type: "ping", id: 0 }));
167
- }
120
+ if (ws.readyState === WebSocket.OPEN) ws.send(stringify({ type: "ping", id: 0 }));
168
121
  }, 30000);
169
- resolve(undefined);
122
+ resolve();
170
123
  };
171
- ws.onerror = (e) => reject(e);
124
+ ws.onerror = reject;
172
125
  });
173
126
 
174
- ws.onclose = () => {
175
- if (keepaliveInterval) {
176
- clearInterval(keepaliveInterval);
177
- keepaliveInterval = null;
178
- }
179
- };
127
+ ws.onclose = () => { clearInterval(keepaliveInterval); };
180
128
 
181
129
  const sendRequest = async (msg) => {
182
130
  await ready;
@@ -187,135 +135,76 @@ const sendRequest = async (msg) => {
187
135
  });
188
136
  };
189
137
 
138
+ const makeWritable = (writableId) => new WritableStream({
139
+ async write(chunk) {
140
+ await sendRequest({ type: "writable-write", writableId, chunk: chunk instanceof Uint8Array ? Array.from(chunk) : chunk });
141
+ },
142
+ async close() { await sendRequest({ type: "writable-close", writableId }); },
143
+ async abort() { await sendRequest({ type: "writable-abort", writableId }); }
144
+ });
145
+
190
146
  ws.onmessage = (event) => {
191
147
  const msg = parse(event.data);
192
-
193
- if (msg.type === "pong") return;
194
-
195
148
  const resolver = pending.get(msg.id);
196
149
  if (!resolver) return;
150
+ pending.delete(msg.id);
197
151
 
198
152
  if (msg.type === "error") {
199
153
  resolver.reject(new Error(msg.error));
200
- pending.delete(msg.id);
201
154
  } else if (msg.type === "result") {
202
- if (msg.valueType === "function") {
203
- resolver.resolve(createProxy(msg.path));
204
- } else if (msg.valueType === "instance") {
205
- resolver.resolve(createInstanceProxy(msg.instanceId));
206
- } else if (msg.valueType === "asynciterator") {
207
- const iteratorProxy = {
208
- [Symbol.asyncIterator]() { return this; },
209
- async next() {
210
- return sendRequest({ type: "iterate-next", iteratorId: msg.iteratorId });
211
- },
212
- async return(value) {
213
- return sendRequest({ type: "iterate-return", iteratorId: msg.iteratorId, value });
214
- }
215
- };
216
- resolver.resolve(iteratorProxy);
217
- } else if (msg.valueType === "readablestream") {
218
- const streamId = msg.streamId;
219
- const stream = new ReadableStream({
220
- async pull(controller) {
221
- try {
222
- const result = await sendRequest({ type: "stream-read", streamId });
223
- if (result.done) {
224
- controller.close();
225
- } else {
226
- controller.enqueue(result.value);
227
- }
228
- } catch (err) {
229
- controller.error(err);
230
- }
231
- },
232
- async cancel() {
233
- await sendRequest({ type: "stream-cancel", streamId });
234
- }
235
- });
236
- resolver.resolve(stream);
237
- } else if (msg.valueType === "writablestream") {
238
- const writableId = msg.writableId;
239
- const stream = new WritableStream({
240
- async write(chunk) {
241
- const data = chunk instanceof Uint8Array ? Array.from(chunk) : chunk;
242
- await sendRequest({ type: "writable-write", writableId, chunk: data });
243
- },
244
- async close() {
245
- await sendRequest({ type: "writable-close", writableId });
246
- },
247
- async abort(reason) {
248
- await sendRequest({ type: "writable-abort", writableId });
249
- }
250
- });
251
- resolver.resolve(stream);
252
- } else {
253
- resolver.resolve(msg.value);
254
- }
255
- pending.delete(msg.id);
155
+ if (msg.valueType === "function") resolver.resolve(createProxy(msg.path));
156
+ else if (msg.valueType === "instance") resolver.resolve(createInstanceProxy(msg.instanceId));
157
+ else if (msg.valueType === "asynciterator") resolver.resolve({
158
+ [Symbol.asyncIterator]() { return this; },
159
+ next: () => sendRequest({ type: "iterate-next", iteratorId: msg.iteratorId }),
160
+ return: () => sendRequest({ type: "iterate-return", iteratorId: msg.iteratorId })
161
+ });
162
+ else if (msg.valueType === "readablestream") resolver.resolve(new ReadableStream({
163
+ async pull(c) {
164
+ try { const r = await sendRequest({ type: "stream-read", streamId: msg.streamId }); r.done ? c.close() : c.enqueue(r.value); }
165
+ catch (e) { c.error(e); }
166
+ },
167
+ cancel: () => sendRequest({ type: "stream-cancel", streamId: msg.streamId })
168
+ }));
169
+ else if (msg.valueType === "writablestream") resolver.resolve(makeWritable(msg.writableId));
170
+ else resolver.resolve(msg.value);
256
171
  } else if (msg.type === "iterate-result") {
257
172
  resolver.resolve({ value: msg.value, done: msg.done });
258
- pending.delete(msg.id);
259
173
  } else if (msg.type === "stream-result") {
260
- const value = Array.isArray(msg.value) ? new Uint8Array(msg.value) : msg.value;
261
- resolver.resolve({ value, done: msg.done });
262
- pending.delete(msg.id);
174
+ resolver.resolve({ value: Array.isArray(msg.value) ? new Uint8Array(msg.value) : msg.value, done: msg.done });
263
175
  }
264
176
  };
265
177
 
266
- const createInstanceProxy = (instanceId, path = []) => {
267
- const proxy = new Proxy(function(){}, {
268
- get(_, prop) {
269
- if (prop === "then" || prop === Symbol.toStringTag) return undefined;
270
- if (prop === Symbol.dispose || prop === Symbol.asyncDispose) {
271
- return () => sendRequest({ type: "release", instanceId });
272
- }
273
- if (prop === "[release]") {
274
- return () => sendRequest({ type: "release", instanceId });
275
- }
276
- return createInstanceProxy(instanceId, [...path, prop]);
277
- },
278
- set(_, prop, value) {
279
- sendRequest({ type: "set", instanceId, path: [...path, prop], args: [value] });
280
- return true;
281
- },
282
- async apply(_, __, args) {
283
- return sendRequest({ type: "call", instanceId, path, args });
284
- }
285
- });
286
- return proxy;
287
- };
178
+ const createInstanceProxy = (instanceId, path = []) => new Proxy(function(){}, {
179
+ get(_, prop) {
180
+ if (prop === "then" || prop === Symbol.toStringTag) return undefined;
181
+ if (prop === Symbol.dispose || prop === Symbol.asyncDispose || prop === "[release]")
182
+ return () => sendRequest({ type: "release", instanceId });
183
+ return createInstanceProxy(instanceId, [...path, prop]);
184
+ },
185
+ set(_, prop, value) {
186
+ sendRequest({ type: "set", instanceId, path: [...path, prop], args: [value] });
187
+ return true;
188
+ },
189
+ async apply(_, __, args) {
190
+ return sendRequest({ type: "call", instanceId, path, args });
191
+ }
192
+ });
288
193
 
289
194
  export const createProxy = (path = []) => new Proxy(function(){}, {
290
195
  get(_, prop) {
291
196
  if (prop === "then" || prop === Symbol.toStringTag) return undefined;
292
197
  return createProxy([...path, prop]);
293
198
  },
294
- async apply(_, __, args) {
295
- return sendRequest({ type: "call", path, args });
296
- },
297
- construct(_, args) {
298
- return sendRequest({ type: "construct", path, args });
299
- }
199
+ async apply(_, __, args) { return sendRequest({ type: "call", path, args }); },
200
+ construct(_, args) { return sendRequest({ type: "construct", path, args }); }
300
201
  });
301
202
 
302
203
  export const createUploadStream = async () => {
303
- const result = await sendRequest({ type: "writable-create" });
304
- const writableId = result.writableId;
305
-
306
- const stream = new WritableStream({
307
- async write(chunk) {
308
- const data = chunk instanceof Uint8Array ? Array.from(chunk) : chunk;
309
- await sendRequest({ type: "writable-write", writableId, chunk: data });
310
- },
311
- async close() {
312
- return sendRequest({ type: "writable-close", writableId });
313
- },
314
- async abort(reason) {
315
- await sendRequest({ type: "writable-abort", writableId });
316
- }
317
- });
318
-
319
- return { stream, writableId };
204
+ const { writableId } = await sendRequest({ type: "writable-create" });
205
+ return { stream: makeWritable(writableId), writableId };
320
206
  };
321
207
  `;
208
+
209
+ export const CORE_CODE = CORE_TEMPLATE.replace("__WS_SUFFIX__", "./");
210
+ export const SHARED_CORE_CODE = CORE_TEMPLATE.replace("__WS_SUFFIX__", "./?shared");
package/entry.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as userExports from "__USER_MODULE__";
2
- import generatedTypes, { minifiedCore, coreId } from "__GENERATED_TYPES__";
2
+ import generatedTypes, { minifiedCore, minifiedSharedCore, coreId } from "__GENERATED_TYPES__";
3
3
  import { createHandler } from "./handler.js";
4
+ export { SharedExportDO } from "./shared-do.js";
4
5
 
5
- export default createHandler(userExports, generatedTypes, minifiedCore, coreId);
6
+ export default createHandler(userExports, generatedTypes, minifiedCore, coreId, minifiedSharedCore);
package/handler.js CHANGED
@@ -1,395 +1,133 @@
1
1
  import { stringify, parse } from "devalue";
2
- import { CORE_CODE } from "./client.js";
3
-
4
- const getByPath = (obj, path) => {
5
- let current = obj;
6
- for (const key of path) {
7
- if (current == null) return undefined;
8
- current = current[key];
9
- }
10
- return current;
11
- };
12
-
13
- const isAsyncIterable = (value) =>
14
- value != null && typeof value[Symbol.asyncIterator] === "function";
15
-
16
- const isReadableStream = (value) =>
17
- value != null && typeof value.getReader === "function" && typeof value.pipeTo === "function";
18
-
19
- const isClass = (fn) =>
20
- typeof fn === "function" && /^class\s/.test(Function.prototype.toString.call(fn));
21
-
22
- // Runtime fallback: generate TypeScript type definitions from exports
23
- const generateTypeDefinitions = (exports, keys) => {
24
- const lines = [
25
- "// Auto-generated type definitions",
26
- "// All functions are async over the network",
27
- "",
28
- ];
29
-
30
- for (const name of keys) {
31
- const value = exports[name];
32
- if (isClass(value)) {
33
- const proto = value.prototype;
34
- const methodNames = Object.getOwnPropertyNames(proto).filter(
35
- (n) => n !== "constructor" && typeof proto[n] === "function"
36
- );
37
- lines.push(`export declare class ${name} {`);
38
- lines.push(` constructor(...args: any[]);`);
39
- for (const method of methodNames) {
40
- lines.push(` ${method}(...args: any[]): Promise<any>;`);
41
- }
42
- lines.push(` [Symbol.dispose](): Promise<void>;`);
43
- lines.push(` "[release]"(): Promise<void>;`);
44
- lines.push(`}`);
45
- } else if (typeof value === "function") {
46
- const fnStr = Function.prototype.toString.call(value);
47
- if (fnStr.startsWith("async function*") || fnStr.includes("async *")) {
48
- lines.push(`export declare function ${name}(...args: any[]): Promise<AsyncIterable<any>>;`);
49
- } else if (fnStr.includes("ReadableStream")) {
50
- lines.push(`export declare function ${name}(...args: any[]): Promise<ReadableStream<any>>;`);
51
- } else {
52
- lines.push(`export declare function ${name}(...args: any[]): Promise<any>;`);
53
- }
54
- } else if (typeof value === "object" && value !== null) {
55
- const keys = Object.keys(value);
56
- lines.push(`export declare const ${name}: {`);
57
- for (const key of keys) {
58
- const v = value[key];
59
- if (typeof v === "function") {
60
- lines.push(` ${key}(...args: any[]): Promise<any>;`);
61
- } else {
62
- lines.push(` ${key}: any;`);
63
- }
64
- }
65
- lines.push(`};`);
66
- } else {
67
- lines.push(`export declare const ${name}: any;`);
68
- }
69
- lines.push("");
70
- }
71
-
72
- lines.push("export declare function createUploadStream(): Promise<{");
73
- lines.push(" stream: WritableStream<any>;");
74
- lines.push(" writableId: number;");
75
- lines.push("}>;");
76
-
77
- return lines.join("\n");
78
- };
2
+ import { CORE_CODE, SHARED_CORE_CODE } from "./client.js";
3
+ import { createRpcDispatcher } from "./rpc.js";
79
4
 
5
+ const JS = "application/javascript; charset=utf-8";
6
+ const TS = "application/typescript; charset=utf-8";
7
+ const CORS = { "Access-Control-Allow-Origin": "*" };
8
+ const IMMUTABLE = "public, max-age=31536000, immutable";
80
9
 
81
- const jsHeaders = (extra = {}) => ({
82
- "Content-Type": "application/javascript; charset=utf-8",
83
- "Access-Control-Allow-Origin": "*",
84
- ...extra,
85
- });
10
+ const jsResponse = (body, extra = {}) =>
11
+ new Response(body, { headers: { "Content-Type": JS, ...CORS, ...extra } });
86
12
 
87
- const tsHeaders = () => ({
88
- "Content-Type": "application/typescript; charset=utf-8",
89
- "Access-Control-Allow-Origin": "*",
90
- "Cache-Control": "no-cache",
91
- });
13
+ const tsResponse = (body, status = 200) =>
14
+ new Response(body, { status, headers: { "Content-Type": TS, ...CORS, "Cache-Control": "no-cache" } });
92
15
 
93
- export const createHandler = (exports, generatedTypes, minifiedCore, coreId) => {
16
+ export const createHandler = (exports, generatedTypes, minifiedCore, coreId, minifiedSharedCore) => {
94
17
  const exportKeys = Object.keys(exports);
95
- const iteratorStore = new Map();
96
- const instanceStore = new Map();
97
- const streamStore = new Map();
98
- const writableStreamStore = new Map();
99
- let nextIteratorId = 1;
100
- let nextInstanceId = 1;
101
- let nextStreamId = 1;
102
-
103
- const send = (ws, data) => {
104
- ws.send(stringify(data));
105
- };
106
18
 
107
19
  const coreModuleCode = minifiedCore || CORE_CODE;
20
+ const sharedCoreModuleCode = minifiedSharedCore || SHARED_CORE_CODE;
108
21
  const corePath = `/${coreId || crypto.randomUUID()}.js`;
22
+ const sharedCorePath = corePath.replace(".js", "-shared.js");
23
+
24
+ // Pre-generate the named exports string (same for shared and normal, only import source differs)
25
+ const namedExportsCode = exportKeys
26
+ .map((key) => `export const ${key} = createProxy([${JSON.stringify(key)}]);`)
27
+ .join("\n");
28
+
29
+ const buildIndexModule = (cpath) =>
30
+ `import { createProxy, createUploadStream } from ".${cpath}";\n${namedExportsCode}\nexport { createUploadStream };`;
31
+
32
+ const buildExportModule = (cpath, name) =>
33
+ `import { createProxy } from ".${cpath}";\nconst _export = createProxy([${JSON.stringify(name)}]);\nexport default _export;\nexport { _export as ${name} };`;
34
+
35
+ // Dispatch a parsed devalue message to an RPC dispatcher
36
+ const dispatchMessage = async (dispatcher, msg) => {
37
+ const { type, path = [], args = [], instanceId, iteratorId, streamId, writableId, chunk } = msg;
38
+ switch (type) {
39
+ case "ping": return { type: "pong" };
40
+ case "call":
41
+ return instanceId !== undefined
42
+ ? dispatcher.rpcInstanceCall(instanceId, path, args)
43
+ : dispatcher.rpcCall(path, args);
44
+ case "construct": return dispatcher.rpcConstruct(path, args);
45
+ case "get": return dispatcher.rpcGet(instanceId, path);
46
+ case "set": return dispatcher.rpcSet(instanceId, path, args[0]);
47
+ case "release": return dispatcher.rpcRelease(instanceId);
48
+ case "iterate-next": return dispatcher.rpcIterateNext(iteratorId);
49
+ case "iterate-return": return dispatcher.rpcIterateReturn(iteratorId);
50
+ case "stream-read": return dispatcher.rpcStreamRead(streamId);
51
+ case "stream-cancel": return dispatcher.rpcStreamCancel(streamId);
52
+ case "writable-create": return dispatcher.rpcWritableCreate();
53
+ case "writable-write": return dispatcher.rpcWritableWrite(writableId, chunk);
54
+ case "writable-close": return dispatcher.rpcWritableClose(writableId);
55
+ case "writable-abort": return dispatcher.rpcWritableAbort(writableId);
56
+ }
57
+ };
58
+
59
+ const wireWebSocket = (server, dispatcher, onClose) => {
60
+ server.addEventListener("message", async (event) => {
61
+ let id;
62
+ try {
63
+ const msg = parse(event.data);
64
+ id = msg.id;
65
+ const result = await dispatchMessage(dispatcher, msg);
66
+ if (result) server.send(stringify({ ...result, id }));
67
+ } catch (err) {
68
+ if (id !== undefined) server.send(stringify({ type: "error", id, error: String(err) }));
69
+ }
70
+ });
71
+ if (onClose) server.addEventListener("close", onClose);
72
+ };
109
73
 
110
74
  return {
111
- async fetch(request) {
75
+ async fetch(request, env) {
112
76
  const url = new URL(request.url);
113
- const upgradeHeader = request.headers.get("Upgrade");
77
+ const isShared = url.searchParams.has("shared");
114
78
 
115
- // --- WebSocket upgrade (path-agnostic) ---
116
- if (upgradeHeader === "websocket") {
79
+ // --- WebSocket upgrade ---
80
+ if (request.headers.get("Upgrade") === "websocket") {
117
81
  const pair = new WebSocketPair();
118
82
  const [client, server] = Object.values(pair);
119
-
120
83
  server.accept();
121
84
 
122
- server.addEventListener("message", async (event) => {
123
- try {
124
- const msg = parse(event.data);
125
- const { type, id, path = [], args = [], iteratorId, instanceId } = msg;
126
-
127
- if (type === "ping") {
128
- send(server, { type: "pong", id });
129
- return;
130
- }
131
-
132
- if (type === "construct") {
133
- try {
134
- const Ctor = getByPath(exports, path);
135
- if (!isClass(Ctor)) {
136
- send(server, { type: "error", id, error: `${path.join(".")} is not a class` });
137
- return;
138
- }
139
- const instance = new Ctor(...args);
140
- const instId = nextInstanceId++;
141
- instanceStore.set(instId, instance);
142
- send(server, { type: "result", id, instanceId: instId, valueType: "instance" });
143
- } catch (err) {
144
- send(server, { type: "error", id, error: String(err) });
145
- }
146
- } else if (type === "call") {
147
- try {
148
- let target;
149
- let thisArg;
150
-
151
- if (instanceId !== undefined) {
152
- const instance = instanceStore.get(instanceId);
153
- if (!instance) {
154
- send(server, { type: "error", id, error: "Instance not found" });
155
- return;
156
- }
157
- target = getByPath(instance, path);
158
- thisArg = path.length > 1 ? getByPath(instance, path.slice(0, -1)) : instance;
159
- } else {
160
- target = getByPath(exports, path);
161
- thisArg = path.length > 1 ? getByPath(exports, path.slice(0, -1)) : undefined;
162
- }
163
-
164
- if (typeof target !== "function") {
165
- send(server, { type: "error", id, error: `${path.join(".")} is not a function` });
166
- return;
167
- }
168
-
169
- const result = await target.apply(thisArg, args);
170
-
171
- if (isReadableStream(result)) {
172
- const streamId = nextStreamId++;
173
- streamStore.set(streamId, { stream: result, reader: null });
174
- send(server, { type: "result", id, streamId, valueType: "readablestream" });
175
- } else if (isAsyncIterable(result)) {
176
- const iterId = nextIteratorId++;
177
- iteratorStore.set(iterId, result[Symbol.asyncIterator]());
178
- send(server, { type: "result", id, iteratorId: iterId, valueType: "asynciterator" });
179
- } else if (typeof result === "function") {
180
- send(server, { type: "result", id, path: [...path], valueType: "function" });
181
- } else {
182
- send(server, { type: "result", id, value: result });
183
- }
184
- } catch (err) {
185
- send(server, { type: "error", id, error: String(err) });
186
- }
187
- } else if (type === "get") {
188
- try {
189
- const instance = instanceStore.get(instanceId);
190
- if (!instance) {
191
- send(server, { type: "error", id, error: "Instance not found" });
192
- return;
193
- }
194
- const value = getByPath(instance, path);
195
- if (typeof value === "function") {
196
- send(server, { type: "result", id, valueType: "function" });
197
- } else {
198
- send(server, { type: "result", id, value });
199
- }
200
- } catch (err) {
201
- send(server, { type: "error", id, error: String(err) });
202
- }
203
- } else if (type === "set") {
204
- try {
205
- const instance = instanceStore.get(instanceId);
206
- if (!instance) {
207
- send(server, { type: "error", id, error: "Instance not found" });
208
- return;
209
- }
210
- const parent = path.length > 1 ? getByPath(instance, path.slice(0, -1)) : instance;
211
- const prop = path[path.length - 1];
212
- parent[prop] = args[0];
213
- send(server, { type: "result", id, value: true });
214
- } catch (err) {
215
- send(server, { type: "error", id, error: String(err) });
216
- }
217
- } else if (type === "release") {
218
- instanceStore.delete(instanceId);
219
- send(server, { type: "result", id, value: true });
220
- } else if (type === "iterate-next") {
221
- const iter = iteratorStore.get(iteratorId);
222
- if (!iter) {
223
- send(server, { type: "error", id, error: "Iterator not found" });
224
- return;
225
- }
226
- try {
227
- const { value, done } = await iter.next();
228
- if (done) iteratorStore.delete(iteratorId);
229
- send(server, { type: "iterate-result", id, value, done: !!done });
230
- } catch (err) {
231
- send(server, { type: "error", id, error: String(err) });
232
- }
233
- } else if (type === "iterate-return") {
234
- const iter = iteratorStore.get(iteratorId);
235
- if (iter?.return) await iter.return(undefined);
236
- iteratorStore.delete(iteratorId);
237
- send(server, { type: "iterate-result", id, value: undefined, done: true });
238
- } else if (type === "stream-read") {
239
- const { streamId } = msg;
240
- const entry = streamStore.get(streamId);
241
- if (!entry) {
242
- send(server, { type: "error", id, error: "Stream not found" });
243
- return;
244
- }
245
- try {
246
- let reader = entry.reader;
247
- if (!reader) {
248
- reader = entry.stream.getReader();
249
- entry.reader = reader;
250
- }
251
- const { value, done } = await reader.read();
252
- if (done) {
253
- streamStore.delete(streamId);
254
- }
255
- const serializedValue = value instanceof Uint8Array ? Array.from(value) : value;
256
- send(server, { type: "stream-result", id, value: serializedValue, done: !!done });
257
- } catch (err) {
258
- streamStore.delete(streamId);
259
- send(server, { type: "error", id, error: String(err) });
260
- }
261
- } else if (type === "stream-cancel") {
262
- const { streamId } = msg;
263
- const entry = streamStore.get(streamId);
264
- if (entry) {
265
- try {
266
- if (entry.reader) {
267
- await entry.reader.cancel();
268
- } else {
269
- await entry.stream.cancel();
270
- }
271
- } catch (e) { /* ignore */ }
272
- streamStore.delete(streamId);
273
- }
274
- send(server, { type: "result", id, value: true });
275
- } else if (type === "writable-create") {
276
- const { targetPath, targetInstanceId } = msg;
277
- let chunks = [];
278
- const writableId = nextStreamId++;
279
-
280
- const writable = new WritableStream({
281
- write(chunk) { chunks.push(chunk); },
282
- close() {},
283
- abort(reason) { chunks = []; }
284
- });
285
-
286
- writableStreamStore.set(writableId, { writable, chunks, targetPath, targetInstanceId });
287
- send(server, { type: "result", id, writableId, valueType: "writablestream" });
288
- } else if (type === "writable-write") {
289
- const { writableId, chunk } = msg;
290
- const entry = writableStreamStore.get(writableId);
291
- if (!entry) {
292
- send(server, { type: "error", id, error: "WritableStream not found" });
293
- return;
294
- }
295
- try {
296
- const data = Array.isArray(chunk) ? new Uint8Array(chunk) : chunk;
297
- entry.chunks.push(data);
298
- send(server, { type: "result", id, value: true });
299
- } catch (err) {
300
- send(server, { type: "error", id, error: String(err) });
301
- }
302
- } else if (type === "writable-close") {
303
- const { writableId } = msg;
304
- const entry = writableStreamStore.get(writableId);
305
- if (!entry) {
306
- send(server, { type: "error", id, error: "WritableStream not found" });
307
- return;
308
- }
309
- writableStreamStore.delete(writableId);
310
- send(server, { type: "result", id, value: entry.chunks });
311
- } else if (type === "writable-abort") {
312
- const { writableId } = msg;
313
- writableStreamStore.delete(writableId);
314
- send(server, { type: "result", id, value: true });
315
- }
316
- } catch (err) {
317
- console.error("WebSocket message error:", err);
318
- }
319
- });
320
-
321
- server.addEventListener("close", () => {
322
- iteratorStore.clear();
323
- instanceStore.clear();
324
- streamStore.clear();
325
- writableStreamStore.clear();
326
- });
85
+ if (isShared && env?.SHARED_EXPORT) {
86
+ const room = url.searchParams.get("room") || "default";
87
+ const stub = env.SHARED_EXPORT.get(env.SHARED_EXPORT.idFromName(room));
88
+ wireWebSocket(server, stub);
89
+ } else {
90
+ const dispatcher = createRpcDispatcher(exports);
91
+ wireWebSocket(server, dispatcher, () => dispatcher.clearAll());
92
+ }
327
93
 
328
94
  return new Response(null, { status: 101, webSocket: client });
329
95
  }
330
96
 
331
97
  // --- HTTP routing ---
332
-
333
- const fullTypes = generatedTypes || generateTypeDefinitions(exports, exportKeys);
334
98
  const pathname = url.pathname;
335
99
 
336
- // Serve core module — long-cached, content-independent of deployment URL
337
- if (pathname === corePath) {
338
- return new Response(coreModuleCode, {
339
- headers: jsHeaders({ "Cache-Control": "public, max-age=31536000, immutable" }),
340
- });
341
- }
100
+ // Core modules (cached immutably)
101
+ if (pathname === corePath) return jsResponse(coreModuleCode, { "Cache-Control": IMMUTABLE });
102
+ if (pathname === sharedCorePath) return jsResponse(sharedCoreModuleCode, { "Cache-Control": IMMUTABLE });
342
103
 
343
104
  // Type definitions
344
- if (url.searchParams.has("types") || pathname.endsWith(".d.ts")) {
345
- if (pathname === "/" || pathname.endsWith(".d.ts")) {
346
- return new Response(fullTypes, { headers: tsHeaders() });
347
- }
348
- // Per-export types — re-export from root to avoid duplication
105
+ if (url.searchParams.has("types")) {
106
+ if (pathname === "/") return tsResponse(generatedTypes || "");
349
107
  const name = pathname.slice(1);
350
- if (exportKeys.includes(name)) {
351
- const code = `export { ${name} as default, ${name} } from "./?types";`;
352
- return new Response(code, { headers: tsHeaders() });
353
- }
354
- return new Response("// Export not found", { status: 404, headers: tsHeaders() });
108
+ return exportKeys.includes(name)
109
+ ? tsResponse(`export { ${name} as default, ${name} } from "./?types";`)
110
+ : tsResponse("// Export not found", 404);
355
111
  }
112
+ if (pathname.endsWith(".d.ts")) return tsResponse(generatedTypes || "");
356
113
 
357
114
  const baseUrl = `${url.protocol}//${url.host}`;
115
+ const cpath = isShared ? sharedCorePath : corePath;
358
116
 
359
- // Root — re-exports all from ${corePath}
117
+ // Root module
360
118
  if (pathname === "/") {
361
- const namedExports = exportKeys
362
- .map((key) => `export const ${key} = createProxy([${JSON.stringify(key)}]);`)
363
- .join("\n");
364
- const code = [
365
- `import { createProxy, createUploadStream } from ".${corePath}";`,
366
- namedExports,
367
- `export { createUploadStream };`,
368
- ].join("\n");
369
-
370
- return new Response(code, {
371
- headers: jsHeaders({
372
- "Cache-Control": "no-cache",
373
- "X-TypeScript-Types": `${baseUrl}/?types`,
374
- }),
119
+ return jsResponse(buildIndexModule(cpath), {
120
+ "Cache-Control": "no-cache",
121
+ "X-TypeScript-Types": `${baseUrl}/?types`,
375
122
  });
376
123
  }
377
124
 
378
- // Per-export path — e.g. /greet, /Counter
125
+ // Per-export module
379
126
  const exportName = pathname.slice(1);
380
127
  if (exportKeys.includes(exportName)) {
381
- const code = [
382
- `import { createProxy } from ".${corePath}";`,
383
- `const _export = createProxy([${JSON.stringify(exportName)}]);`,
384
- `export default _export;`,
385
- `export { _export as ${exportName} };`,
386
- ].join("\n");
387
-
388
- return new Response(code, {
389
- headers: jsHeaders({
390
- "Cache-Control": "no-cache",
391
- "X-TypeScript-Types": `${baseUrl}/${exportName}?types`,
392
- }),
128
+ return jsResponse(buildExportModule(cpath, exportName), {
129
+ "Cache-Control": "no-cache",
130
+ "X-TypeScript-Types": `${baseUrl}/${exportName}?types`,
393
131
  });
394
132
  }
395
133
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "export-runtime",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Cloudflare Workers ESM Export Framework Runtime",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -29,6 +29,8 @@
29
29
  "entry.js",
30
30
  "handler.js",
31
31
  "client.js",
32
+ "rpc.js",
33
+ "shared-do.js",
32
34
  "bin/generate-types.mjs"
33
35
  ],
34
36
  "dependencies": {
package/rpc.js ADDED
@@ -0,0 +1,161 @@
1
+ export const getByPath = (obj, path) => {
2
+ let current = obj;
3
+ for (const key of path) {
4
+ if (current == null) return undefined;
5
+ current = current[key];
6
+ }
7
+ return current;
8
+ };
9
+
10
+ export const isAsyncIterable = (value) =>
11
+ value != null && typeof value[Symbol.asyncIterator] === "function";
12
+
13
+ export const isReadableStream = (value) =>
14
+ value != null && typeof value.getReader === "function" && typeof value.pipeTo === "function";
15
+
16
+ export const isClass = (fn) =>
17
+ typeof fn === "function" && /^class\s/.test(Function.prototype.toString.call(fn));
18
+
19
+ export const RPC_METHODS = [
20
+ "rpcCall", "rpcConstruct", "rpcInstanceCall", "rpcGet", "rpcSet", "rpcRelease",
21
+ "rpcIterateNext", "rpcIterateReturn", "rpcStreamRead", "rpcStreamCancel",
22
+ "rpcWritableCreate", "rpcWritableWrite", "rpcWritableClose", "rpcWritableAbort",
23
+ ];
24
+
25
+ export function createRpcDispatcher(exports) {
26
+ const instances = new Map();
27
+ const iterators = new Map();
28
+ const streams = new Map();
29
+ const writables = new Map();
30
+ let nextId = 1;
31
+
32
+ const requireInstance = (id) => {
33
+ const inst = instances.get(id);
34
+ if (!inst) throw new Error("Instance not found");
35
+ return inst;
36
+ };
37
+
38
+ const wrapResult = (result, path) => {
39
+ if (isReadableStream(result)) {
40
+ const id = nextId++;
41
+ streams.set(id, { stream: result, reader: null });
42
+ return { type: "result", streamId: id, valueType: "readablestream" };
43
+ }
44
+ if (isAsyncIterable(result)) {
45
+ const id = nextId++;
46
+ iterators.set(id, result[Symbol.asyncIterator]());
47
+ return { type: "result", iteratorId: id, valueType: "asynciterator" };
48
+ }
49
+ if (typeof result === "function") {
50
+ return { type: "result", path: [...path], valueType: "function" };
51
+ }
52
+ return { type: "result", value: result };
53
+ };
54
+
55
+ const callTarget = async (obj, path, args) => {
56
+ const target = getByPath(obj, path);
57
+ const thisArg = path.length > 1 ? getByPath(obj, path.slice(0, -1)) : (obj === exports ? undefined : obj);
58
+ if (typeof target !== "function") throw new Error(`${path.join(".")} is not a function`);
59
+ return wrapResult(await target.apply(thisArg, args), path);
60
+ };
61
+
62
+ return {
63
+ rpcCall: (path, args = []) => callTarget(exports, path, args),
64
+
65
+ async rpcConstruct(path, args = []) {
66
+ const Ctor = getByPath(exports, path);
67
+ if (!isClass(Ctor)) throw new Error(`${path.join(".")} is not a class`);
68
+ const id = nextId++;
69
+ instances.set(id, new Ctor(...args));
70
+ return { type: "result", instanceId: id, valueType: "instance" };
71
+ },
72
+
73
+ rpcInstanceCall: (instanceId, path, args = []) =>
74
+ callTarget(requireInstance(instanceId), path, args),
75
+
76
+ async rpcGet(instanceId, path) {
77
+ const value = getByPath(requireInstance(instanceId), path);
78
+ return typeof value === "function"
79
+ ? { type: "result", valueType: "function" }
80
+ : { type: "result", value };
81
+ },
82
+
83
+ async rpcSet(instanceId, path, value) {
84
+ const inst = requireInstance(instanceId);
85
+ const parent = path.length > 1 ? getByPath(inst, path.slice(0, -1)) : inst;
86
+ parent[path.at(-1)] = value;
87
+ return { type: "result", value: true };
88
+ },
89
+
90
+ async rpcRelease(instanceId) {
91
+ instances.delete(instanceId);
92
+ return { type: "result", value: true };
93
+ },
94
+
95
+ async rpcIterateNext(iteratorId) {
96
+ const iter = iterators.get(iteratorId);
97
+ if (!iter) throw new Error("Iterator not found");
98
+ const { value, done } = await iter.next();
99
+ if (done) iterators.delete(iteratorId);
100
+ return { type: "iterate-result", value, done: !!done };
101
+ },
102
+
103
+ async rpcIterateReturn(iteratorId) {
104
+ const iter = iterators.get(iteratorId);
105
+ if (iter?.return) await iter.return(undefined);
106
+ iterators.delete(iteratorId);
107
+ return { type: "iterate-result", value: undefined, done: true };
108
+ },
109
+
110
+ async rpcStreamRead(streamId) {
111
+ const entry = streams.get(streamId);
112
+ if (!entry) throw new Error("Stream not found");
113
+ if (!entry.reader) entry.reader = entry.stream.getReader();
114
+ const { value, done } = await entry.reader.read();
115
+ if (done) streams.delete(streamId);
116
+ const v = value instanceof Uint8Array ? Array.from(value) : value;
117
+ return { type: "stream-result", value: v, done: !!done };
118
+ },
119
+
120
+ async rpcStreamCancel(streamId) {
121
+ const entry = streams.get(streamId);
122
+ if (entry) {
123
+ try { await (entry.reader || entry.stream).cancel(); } catch {}
124
+ streams.delete(streamId);
125
+ }
126
+ return { type: "result", value: true };
127
+ },
128
+
129
+ async rpcWritableCreate() {
130
+ const id = nextId++;
131
+ writables.set(id, { chunks: [] });
132
+ return { type: "result", writableId: id, valueType: "writablestream" };
133
+ },
134
+
135
+ async rpcWritableWrite(writableId, chunk) {
136
+ const entry = writables.get(writableId);
137
+ if (!entry) throw new Error("WritableStream not found");
138
+ entry.chunks.push(Array.isArray(chunk) ? new Uint8Array(chunk) : chunk);
139
+ return { type: "result", value: true };
140
+ },
141
+
142
+ async rpcWritableClose(writableId) {
143
+ const entry = writables.get(writableId);
144
+ if (!entry) throw new Error("WritableStream not found");
145
+ writables.delete(writableId);
146
+ return { type: "result", value: entry.chunks };
147
+ },
148
+
149
+ async rpcWritableAbort(writableId) {
150
+ writables.delete(writableId);
151
+ return { type: "result", value: true };
152
+ },
153
+
154
+ clearAll() {
155
+ instances.clear();
156
+ iterators.clear();
157
+ streams.clear();
158
+ writables.clear();
159
+ },
160
+ };
161
+ }
package/shared-do.js ADDED
@@ -0,0 +1,25 @@
1
+ import { DurableObject } from "cloudflare:workers";
2
+ import * as userExports from "__USER_MODULE__";
3
+ import { createRpcDispatcher } from "./rpc.js";
4
+
5
+ export class SharedExportDO extends DurableObject {
6
+ #d;
7
+ constructor(ctx, env) {
8
+ super(ctx, env);
9
+ this.#d = createRpcDispatcher(userExports);
10
+ }
11
+ rpcCall(p, a) { return this.#d.rpcCall(p, a); }
12
+ rpcConstruct(p, a) { return this.#d.rpcConstruct(p, a); }
13
+ rpcInstanceCall(i, p, a) { return this.#d.rpcInstanceCall(i, p, a); }
14
+ rpcGet(i, p) { return this.#d.rpcGet(i, p); }
15
+ rpcSet(i, p, v) { return this.#d.rpcSet(i, p, v); }
16
+ rpcRelease(i) { return this.#d.rpcRelease(i); }
17
+ rpcIterateNext(i) { return this.#d.rpcIterateNext(i); }
18
+ rpcIterateReturn(i) { return this.#d.rpcIterateReturn(i); }
19
+ rpcStreamRead(s) { return this.#d.rpcStreamRead(s); }
20
+ rpcStreamCancel(s) { return this.#d.rpcStreamCancel(s); }
21
+ rpcWritableCreate() { return this.#d.rpcWritableCreate(); }
22
+ rpcWritableWrite(w, c) { return this.#d.rpcWritableWrite(w, c); }
23
+ rpcWritableClose(w) { return this.#d.rpcWritableClose(w); }
24
+ rpcWritableAbort(w) { return this.#d.rpcWritableAbort(w); }
25
+ }