export-runtime 0.0.18 → 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.
- package/bin/generate-types.mjs +40 -20
- package/handler.js +5 -0
- package/package.json +1 -1
- package/rpc.js +22 -0
package/bin/generate-types.mjs
CHANGED
|
@@ -10,40 +10,55 @@ import { fileURLToPath } from "url";
|
|
|
10
10
|
const cwd = process.cwd();
|
|
11
11
|
|
|
12
12
|
// --- Read package.json for configuration ---
|
|
13
|
+
// First check local package.json, then parent (for exportc-style projects)
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const localPkgPath = path.join(cwd, "package.json");
|
|
16
|
+
const parentPkgPath = path.join(cwd, "..", "package.json");
|
|
17
|
+
|
|
18
|
+
let pkg = null;
|
|
19
|
+
let rootPkg = null;
|
|
20
|
+
let isExportcProject = false;
|
|
21
|
+
|
|
22
|
+
if (fs.existsSync(localPkgPath)) {
|
|
23
|
+
pkg = JSON.parse(fs.readFileSync(localPkgPath, "utf8"));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check if parent has cloudflare config (exportc-style project)
|
|
27
|
+
if (fs.existsSync(parentPkgPath)) {
|
|
28
|
+
rootPkg = JSON.parse(fs.readFileSync(parentPkgPath, "utf8"));
|
|
29
|
+
if (rootPkg.cloudflare) {
|
|
30
|
+
isExportcProject = true;
|
|
31
|
+
}
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
|
|
34
|
+
// Use root package.json's cloudflare config if available (exportc project)
|
|
35
|
+
const cloudflareConfig = isExportcProject ? (rootPkg.cloudflare || {}) : (pkg?.cloudflare || {});
|
|
36
|
+
const securityConfig = isExportcProject ? (rootPkg.security || {}) : (pkg?.security || {});
|
|
21
37
|
|
|
22
|
-
//
|
|
23
|
-
const workerName =
|
|
38
|
+
// Worker name - from cloudflare.name, or package name
|
|
39
|
+
const workerName = cloudflareConfig.name || pkg?.name;
|
|
24
40
|
if (!workerName) {
|
|
25
|
-
console.error("
|
|
41
|
+
console.error("Worker name required: set 'cloudflare.name' in package.json or provide a package 'name'");
|
|
26
42
|
process.exit(1);
|
|
27
43
|
}
|
|
28
44
|
|
|
29
|
-
|
|
45
|
+
// Source entry - from cloudflare.exports or package exports
|
|
46
|
+
const exportsEntry = cloudflareConfig.exports || pkg?.exports;
|
|
30
47
|
if (!exportsEntry) {
|
|
31
|
-
console.error("package.json must have
|
|
48
|
+
console.error("package.json must have 'cloudflare.exports' or 'exports' field pointing to the source entry (e.g., './src' or './')");
|
|
32
49
|
process.exit(1);
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
// Optional: static assets directory
|
|
36
|
-
const assetsDir =
|
|
52
|
+
// Optional: static assets directory (from cloudflare.assets only, not main)
|
|
53
|
+
const assetsDir = cloudflareConfig.assets || null;
|
|
37
54
|
|
|
38
|
-
//
|
|
39
|
-
const cloudflareConfig = pkg.cloudflare || {};
|
|
55
|
+
// Cloudflare bindings configuration (d1, r2, kv, auth)
|
|
40
56
|
const d1Bindings = cloudflareConfig.d1 || [];
|
|
41
57
|
const r2Bindings = cloudflareConfig.r2 || [];
|
|
42
58
|
const kvBindings = cloudflareConfig.kv || [];
|
|
43
59
|
const authConfig = cloudflareConfig.auth || null;
|
|
44
60
|
|
|
45
|
-
//
|
|
46
|
-
const securityConfig = pkg.security || {};
|
|
61
|
+
// Security configuration
|
|
47
62
|
const accessConfig = securityConfig.access || {};
|
|
48
63
|
const allowedOrigins = accessConfig.origin || []; // empty = allow all (default Workers behavior)
|
|
49
64
|
|
|
@@ -68,7 +83,9 @@ validateBindings(kvBindings, "KV");
|
|
|
68
83
|
|
|
69
84
|
// --- Resolve source directory from exports field ---
|
|
70
85
|
|
|
71
|
-
|
|
86
|
+
// For exportc projects, resolve relative to parent directory
|
|
87
|
+
const baseDir = isExportcProject ? path.join(cwd, "..") : cwd;
|
|
88
|
+
const exportsPath = path.resolve(baseDir, exportsEntry.replace(/^\.\//, ""));
|
|
72
89
|
const srcDir = fs.existsSync(exportsPath) && fs.statSync(exportsPath).isDirectory()
|
|
73
90
|
? exportsPath
|
|
74
91
|
: path.dirname(exportsPath);
|
|
@@ -397,14 +414,17 @@ const wranglerLines = [
|
|
|
397
414
|
``,
|
|
398
415
|
];
|
|
399
416
|
|
|
400
|
-
// Add static assets configuration if
|
|
417
|
+
// Add static assets configuration if assets is specified and directory exists
|
|
401
418
|
if (assetsDir) {
|
|
419
|
+
// For exportc projects, assets path is relative to parent directory
|
|
402
420
|
const normalizedAssetsDir = assetsDir.startsWith("./") ? assetsDir : `./${assetsDir}`;
|
|
403
|
-
const absoluteAssetsDir = path.resolve(
|
|
421
|
+
const absoluteAssetsDir = path.resolve(baseDir, normalizedAssetsDir);
|
|
422
|
+
// In wrangler.toml, path should be relative to export/ directory for exportc projects
|
|
423
|
+
const wranglerAssetsPath = isExportcProject ? `../${normalizedAssetsDir.replace(/^\.\//, "")}` : normalizedAssetsDir;
|
|
404
424
|
if (fs.existsSync(absoluteAssetsDir)) {
|
|
405
425
|
wranglerLines.push(
|
|
406
426
|
`[assets]`,
|
|
407
|
-
`directory = "${
|
|
427
|
+
`directory = "${wranglerAssetsPath}"`,
|
|
408
428
|
`binding = "ASSETS"`,
|
|
409
429
|
`run_worker_first = true`,
|
|
410
430
|
``,
|
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
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();
|