@statewalker/cellb 0.8.9 → 0.9.1
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 +10 -6
- package/dist/adapters/node-sqlite-module.d.ts +6 -0
- package/dist/adapters/node-sqlite-module.js +12 -0
- package/dist/adapters/node-sqlite-module.js.map +1 -1
- package/dist/adapters/node-sqlite.js +3 -3
- package/dist/adapters/node-sqlite.js.map +1 -1
- package/dist/adapters/wasm-sqlite.d.ts +2 -0
- package/dist/adapters/wasm-sqlite.js +15 -0
- package/dist/adapters/wasm-sqlite.js.map +1 -1
- package/dist/bindings/cron.js +9 -2
- package/dist/bindings/cron.js.map +1 -1
- package/dist/bindings/module-registry.d.ts +19 -9
- package/dist/bindings/module-registry.js +42 -30
- package/dist/bindings/module-registry.js.map +1 -1
- package/dist/bucket/sqlite-object-store.js +2 -2
- package/dist/bucket/sqlite-object-store.js.map +1 -1
- package/dist/core/alarms.js +12 -2
- package/dist/core/alarms.js.map +1 -1
- package/dist/isolate/function-imports.d.ts +10 -0
- package/dist/isolate/function-imports.js +93 -0
- package/dist/isolate/function-imports.js.map +1 -0
- package/dist/isolate/isolate-worker.js +5 -1
- package/dist/isolate/isolate-worker.js.map +1 -1
- package/dist/isolate/protocol.js +17 -3
- package/dist/isolate/protocol.js.map +1 -1
- package/dist/project/browser-host.d.ts +2 -0
- package/dist/project/browser-host.js +2 -0
- package/dist/project/browser-host.js.map +1 -1
- package/dist/project/browser-load.js +1 -0
- package/dist/project/browser-load.js.map +1 -1
- package/dist/project/browser-modules.d.ts +7 -1
- package/dist/project/browser-modules.js +5 -1
- package/dist/project/browser-modules.js.map +1 -1
- package/dist/project/built-project.d.ts +7 -0
- package/dist/project/built-project.js.map +1 -1
- package/dist/project/node-project.js +9 -6
- package/dist/project/node-project.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,14 +29,11 @@ export const RESOLVE_MODULE_NAME_SOURCE = `(spec, importer, names) => {
|
|
|
29
29
|
/** The identifier rewritten calls use. */
|
|
30
30
|
export const IMPORT_FROM = "__cellbImportFrom";
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* reports its syntax error).
|
|
32
|
+
* One parse of ES module `source` (named `name`): its text with each `import(spec)` the bundler
|
|
33
|
+
* cannot link routed through `__cellbImportFrom` (`routed`, undefined when there is none), and
|
|
34
|
+
* its exports. `undefined` when it does not parse (the loader then reports its syntax error).
|
|
36
35
|
*/
|
|
37
|
-
export function
|
|
38
|
-
if (!source.includes("import"))
|
|
39
|
-
return undefined;
|
|
36
|
+
export function analyzeModule(source, name) {
|
|
40
37
|
let ast;
|
|
41
38
|
try {
|
|
42
39
|
ast = parse(source, { ecmaVersion: "latest", sourceType: "module", allowHashBang: true });
|
|
@@ -44,6 +41,24 @@ export function routeDynamicImports(source, name) {
|
|
|
44
41
|
catch {
|
|
45
42
|
return undefined;
|
|
46
43
|
}
|
|
44
|
+
return { routed: routed(ast, source, name), exports: exportsOf(ast) };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* `source` (an ES module named `name`) with each `import(spec)` that the bundler cannot link (a
|
|
48
|
+
* computed specifier, or a literal that is not a relative path) calling `__cellbImportFrom(spec,
|
|
49
|
+
* name)`. Returns `undefined` when there is none (or the module does not parse: the loader then
|
|
50
|
+
* reports its syntax error).
|
|
51
|
+
*/
|
|
52
|
+
export function routeDynamicImports(source, name) {
|
|
53
|
+
if (!source.includes("import"))
|
|
54
|
+
return undefined;
|
|
55
|
+
return analyzeModule(source, name)?.routed;
|
|
56
|
+
}
|
|
57
|
+
/** The exports of ES module `source` (`undefined` if it does not parse). */
|
|
58
|
+
export function moduleExports(source) {
|
|
59
|
+
return analyzeModule(source, "")?.exports;
|
|
60
|
+
}
|
|
61
|
+
function routed(ast, source, name) {
|
|
47
62
|
const calls = [];
|
|
48
63
|
const visit = (n) => {
|
|
49
64
|
if (!n || typeof n.type !== "string")
|
|
@@ -64,7 +79,8 @@ export function routeDynamicImports(source, name) {
|
|
|
64
79
|
visit(v);
|
|
65
80
|
}
|
|
66
81
|
};
|
|
67
|
-
|
|
82
|
+
if (source.includes("import"))
|
|
83
|
+
visit(ast);
|
|
68
84
|
if (!calls.length)
|
|
69
85
|
return undefined;
|
|
70
86
|
let out = source;
|
|
@@ -78,24 +94,7 @@ export function routeDynamicImports(source, name) {
|
|
|
78
94
|
out.slice(sourceEnd);
|
|
79
95
|
return out;
|
|
80
96
|
}
|
|
81
|
-
|
|
82
|
-
export function prefixModule(source, prelude) {
|
|
83
|
-
if (!source.startsWith("#!"))
|
|
84
|
-
return prelude + source;
|
|
85
|
-
const nl = source.indexOf("\n");
|
|
86
|
-
return nl < 0
|
|
87
|
-
? `${source}\n${prelude}`
|
|
88
|
-
: `${source.slice(0, nl + 1)}${prelude}${source.slice(nl + 1)}`;
|
|
89
|
-
}
|
|
90
|
-
/** The exports of ES module `source` (`undefined` if it does not parse). */
|
|
91
|
-
export function moduleExports(source) {
|
|
92
|
-
let ast;
|
|
93
|
-
try {
|
|
94
|
-
ast = parse(source, { ecmaVersion: "latest", sourceType: "module", allowHashBang: true });
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
return undefined;
|
|
98
|
-
}
|
|
97
|
+
function exportsOf(ast) {
|
|
99
98
|
const names = new Set();
|
|
100
99
|
const stars = [];
|
|
101
100
|
const nameOf = (n) => (n.type === "Identifier" ? n.name : String(n.value));
|
|
@@ -137,14 +136,27 @@ export function moduleExports(source) {
|
|
|
137
136
|
}
|
|
138
137
|
return { names: [...names], stars };
|
|
139
138
|
}
|
|
139
|
+
/** `prelude` put in front of `source` on its first line (after a hashbang), so lines keep their numbers. */
|
|
140
|
+
export function prefixModule(source, prelude) {
|
|
141
|
+
if (!source.startsWith("#!"))
|
|
142
|
+
return prelude + source;
|
|
143
|
+
const nl = source.indexOf("\n");
|
|
144
|
+
return nl < 0
|
|
145
|
+
? `${source}\n${prelude}`
|
|
146
|
+
: `${source.slice(0, nl + 1)}${prelude}${source.slice(nl + 1)}`;
|
|
147
|
+
}
|
|
140
148
|
/**
|
|
141
149
|
* Each module's export names, `export *` followed within the modules (as far as they resolve).
|
|
142
|
-
* A module that does not parse, or a star from outside them, adds nothing.
|
|
150
|
+
* A module that does not parse, or a star from outside them, adds nothing. `modules` are the
|
|
151
|
+
* modules' texts, or their exports already found (`analyzeModule`).
|
|
143
152
|
*/
|
|
144
153
|
export function exportNamesByModule(modules) {
|
|
145
|
-
const own =
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
const own = modules instanceof Map
|
|
155
|
+
? modules
|
|
156
|
+
: new Map(Object.entries(modules).map(([n, text]) => [
|
|
157
|
+
n,
|
|
158
|
+
moduleExports(text) ?? { names: [], stars: [] },
|
|
159
|
+
]));
|
|
148
160
|
const names = new Set(own.keys());
|
|
149
161
|
const all = (name, seen) => {
|
|
150
162
|
const out = new Set(own.get(name)?.names ?? []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-registry.js","sourceRoot":"","sources":["../../src/bindings/module-registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `import()` in a loaded Worker resolves against its own modules, as on workerd: the specifier\n * names a module of the `WorkerCode` exactly (Kitesurf names page modules by their URL), or is\n * a path relative to the importing module. The loaders bundle (esbuild on Node) or link (Blob URLs\n * in a browser) the modules, which handles a literal relative `import(\"./x.js\")`; a computed\n * specifier, or one that is a module's whole name, is resolved at run time instead.\n *\n * `routeDynamicImports` rewrites those `import(spec)` calls of a module to\n * `__cellbImportFrom(spec, \"<module name>\")`; each loader defines `__cellbImportFrom` with\n * `resolveModuleName` over its own modules, falling back to the realm's `import()`.\n */\nimport { parse } from \"acorn\";\n\n/** The name of the loaded module `spec` names from module `importer`, or `undefined`. */\nexport function resolveModuleName(\n spec: string,\n importer: string,\n names: ReadonlySet<string>,\n): string | undefined {\n if (names.has(spec)) return spec;\n if (!/^\\.{0,2}\\//.test(spec)) return undefined;\n const name = new URL(spec, `file:///${importer}`).pathname.slice(1);\n return names.has(name) ? name : undefined;\n}\n\n/** The same function as source text, for a registry module generated into a bundle. */\nexport const RESOLVE_MODULE_NAME_SOURCE = `(spec, importer, names) => {\n if (names.has(spec)) return spec;\n if (!/^\\\\.{0,2}\\\\//.test(spec)) return undefined;\n const name = new URL(spec, \"file:///\" + importer).pathname.slice(1);\n return names.has(name) ? name : undefined;\n}`;\n\n/** The identifier rewritten calls use. */\nexport const IMPORT_FROM = \"__cellbImportFrom\";\n\n/**\n * `source` (an ES module named `name`) with each `import(spec)` that the bundler cannot link (a\n * computed specifier, or a literal that is not a relative path) calling `__cellbImportFrom(spec,\n * name)`. Returns `undefined` when there is none (or the module does not parse: the loader then\n * reports its syntax error).\n */\nexport function routeDynamicImports(source: string, name: string): string | undefined {\n if (!source.includes(\"import\")) return undefined;\n let ast: any;\n try {\n ast = parse(source, { ecmaVersion: \"latest\", sourceType: \"module\", allowHashBang: true });\n } catch {\n return undefined;\n }\n const calls: { start: number; sourceEnd: number }[] = [];\n const visit = (n: any) => {\n if (!n || typeof n.type !== \"string\") return;\n if (n.type === \"ImportExpression\") {\n const literal =\n n.source.type === \"Literal\" && typeof n.source.value === \"string\"\n ? (n.source.value as string)\n : undefined;\n if (literal === undefined || !/^\\.{1,2}\\//.test(literal))\n calls.push({ start: n.start, sourceEnd: n.source.end });\n }\n for (const key of Object.keys(n)) {\n const v = n[key];\n if (Array.isArray(v)) for (const c of v) visit(c);\n else if (v && typeof v === \"object\" && typeof v.type === \"string\") visit(v);\n }\n };\n visit(ast);\n if (!calls.length) return undefined;\n let out = source;\n // From the end, so earlier positions stay valid: `import(spec` → `__cellbImportFrom(spec, name`.\n for (const { start, sourceEnd } of calls.sort((a, b) => b.start - a.start))\n out =\n out.slice(0, start) +\n IMPORT_FROM +\n out.slice(start + \"import\".length, sourceEnd) +\n `, ${JSON.stringify(name)}` +\n out.slice(sourceEnd);\n return out;\n}\n\n/** `prelude` put in front of `source` on its first line (after a hashbang), so lines keep their numbers. */\nexport function prefixModule(source: string, prelude: string): string {\n if (!source.startsWith(\"#!\")) return prelude + source;\n const nl = source.indexOf(\"\\n\");\n return nl < 0\n ? `${source}\\n${prelude}`\n : `${source.slice(0, nl + 1)}${prelude}${source.slice(nl + 1)}`;\n}\n\n/** What an ES module exports by name, and the specifiers it re-exports everything from. */\nexport interface ModuleExports {\n names: string[];\n stars: string[];\n}\n\n/** The exports of ES module `source` (`undefined` if it does not parse). */\nexport function moduleExports(source: string): ModuleExports | undefined {\n let ast: any;\n try {\n ast = parse(source, { ecmaVersion: \"latest\", sourceType: \"module\", allowHashBang: true });\n } catch {\n return undefined;\n }\n const names = new Set<string>();\n const stars: string[] = [];\n const nameOf = (n: any) => (n.type === \"Identifier\" ? n.name : String(n.value));\n const bound = (p: any) => {\n if (!p) return;\n if (p.type === \"Identifier\") names.add(p.name);\n else if (p.type === \"ObjectPattern\")\n for (const q of p.properties) bound(q.type === \"RestElement\" ? q.argument : q.value);\n else if (p.type === \"ArrayPattern\") for (const q of p.elements) bound(q);\n else if (p.type === \"RestElement\") bound(p.argument);\n else if (p.type === \"AssignmentPattern\") bound(p.left);\n };\n for (const node of ast.body) {\n if (node.type === \"ExportDefaultDeclaration\") names.add(\"default\");\n else if (node.type === \"ExportAllDeclaration\") {\n if (node.exported) names.add(nameOf(node.exported));\n else stars.push(String(node.source.value));\n } else if (node.type === \"ExportNamedDeclaration\") {\n const d = node.declaration;\n if (d?.type === \"VariableDeclaration\") for (const v of d.declarations) bound(v.id);\n else if (d?.id) names.add(d.id.name);\n for (const s of node.specifiers ?? []) names.add(nameOf(s.exported));\n }\n }\n return { names: [...names], stars };\n}\n\n/**\n * Each module's export names, `export *` followed within the modules (as far as they resolve).\n * A module that does not parse, or a star from outside them, adds nothing.\n */\nexport function exportNamesByModule(modules: Record<string, string>): Record<string, string[]> {\n const own = new Map<string, ModuleExports>();\n for (const [name, text] of Object.entries(modules))\n own.set(name, moduleExports(text) ?? { names: [], stars: [] });\n const names = new Set(own.keys());\n const all = (name: string, seen: Set<string>): Set<string> => {\n const out = new Set(own.get(name)?.names ?? []);\n if (seen.has(name)) return out;\n seen.add(name);\n for (const spec of own.get(name)?.stars ?? []) {\n const target = resolveModuleName(spec, name, names);\n if (target === undefined) continue;\n for (const n of all(target, seen)) if (n !== \"default\") out.add(n);\n }\n return out;\n };\n return Object.fromEntries([...names].map((n) => [n, [...all(n, new Set())]]));\n}\n\n/**\n * An ES module that stands for loaded module `name` where code imports it by a specifier no\n * bundler saw (an `import()` in code built with `Function`): it takes the bundled module's\n * namespace from the realm's registry (`globalThis.__cellbLoadedModules`) and re-exports it.\n */\nexport function loadedModuleShim(name: string, exportNames: string[]): string {\n const ident = /^[A-Za-z_$][\\w$]*$/;\n const named = exportNames.filter((n) => n !== \"default\" && ident.test(n));\n return [\n `const ns = await globalThis.__cellbLoadedModules.load(${JSON.stringify(name)});`,\n ...(exportNames.includes(\"default\") ? [\"export default ns.default;\"] : []),\n ...(named.length ? [`export const { ${named.join(\", \")} } = ns;`] : []),\n ].join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"module-registry.js","sourceRoot":"","sources":["../../src/bindings/module-registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `import()` in a loaded Worker resolves against its own modules, as on workerd: the specifier\n * names a module of the `WorkerCode` exactly (Kitesurf names page modules by their URL), or is\n * a path relative to the importing module. The loaders bundle (esbuild on Node) or link (Blob URLs\n * in a browser) the modules, which handles a literal relative `import(\"./x.js\")`; a computed\n * specifier, or one that is a module's whole name, is resolved at run time instead.\n *\n * `routeDynamicImports` rewrites those `import(spec)` calls of a module to\n * `__cellbImportFrom(spec, \"<module name>\")`; each loader defines `__cellbImportFrom` with\n * `resolveModuleName` over its own modules, falling back to the realm's `import()`.\n */\nimport { parse } from \"acorn\";\n\n/** The name of the loaded module `spec` names from module `importer`, or `undefined`. */\nexport function resolveModuleName(\n spec: string,\n importer: string,\n names: ReadonlySet<string>,\n): string | undefined {\n if (names.has(spec)) return spec;\n if (!/^\\.{0,2}\\//.test(spec)) return undefined;\n const name = new URL(spec, `file:///${importer}`).pathname.slice(1);\n return names.has(name) ? name : undefined;\n}\n\n/** The same function as source text, for a registry module generated into a bundle. */\nexport const RESOLVE_MODULE_NAME_SOURCE = `(spec, importer, names) => {\n if (names.has(spec)) return spec;\n if (!/^\\\\.{0,2}\\\\//.test(spec)) return undefined;\n const name = new URL(spec, \"file:///\" + importer).pathname.slice(1);\n return names.has(name) ? name : undefined;\n}`;\n\n/** The identifier rewritten calls use. */\nexport const IMPORT_FROM = \"__cellbImportFrom\";\n\n/** What an ES module exports by name, and the specifiers it re-exports everything from. */\nexport interface ModuleExports {\n names: string[];\n stars: string[];\n}\n\n/**\n * One parse of ES module `source` (named `name`): its text with each `import(spec)` the bundler\n * cannot link routed through `__cellbImportFrom` (`routed`, undefined when there is none), and\n * its exports. `undefined` when it does not parse (the loader then reports its syntax error).\n */\nexport function analyzeModule(\n source: string,\n name: string,\n): { routed: string | undefined; exports: ModuleExports } | undefined {\n let ast: any;\n try {\n ast = parse(source, { ecmaVersion: \"latest\", sourceType: \"module\", allowHashBang: true });\n } catch {\n return undefined;\n }\n return { routed: routed(ast, source, name), exports: exportsOf(ast) };\n}\n\n/**\n * `source` (an ES module named `name`) with each `import(spec)` that the bundler cannot link (a\n * computed specifier, or a literal that is not a relative path) calling `__cellbImportFrom(spec,\n * name)`. Returns `undefined` when there is none (or the module does not parse: the loader then\n * reports its syntax error).\n */\nexport function routeDynamicImports(source: string, name: string): string | undefined {\n if (!source.includes(\"import\")) return undefined;\n return analyzeModule(source, name)?.routed;\n}\n\n/** The exports of ES module `source` (`undefined` if it does not parse). */\nexport function moduleExports(source: string): ModuleExports | undefined {\n return analyzeModule(source, \"\")?.exports;\n}\n\nfunction routed(ast: any, source: string, name: string): string | undefined {\n const calls: { start: number; sourceEnd: number }[] = [];\n const visit = (n: any) => {\n if (!n || typeof n.type !== \"string\") return;\n if (n.type === \"ImportExpression\") {\n const literal =\n n.source.type === \"Literal\" && typeof n.source.value === \"string\"\n ? (n.source.value as string)\n : undefined;\n if (literal === undefined || !/^\\.{1,2}\\//.test(literal))\n calls.push({ start: n.start, sourceEnd: n.source.end });\n }\n for (const key of Object.keys(n)) {\n const v = n[key];\n if (Array.isArray(v)) for (const c of v) visit(c);\n else if (v && typeof v === \"object\" && typeof v.type === \"string\") visit(v);\n }\n };\n if (source.includes(\"import\")) visit(ast);\n if (!calls.length) return undefined;\n let out = source;\n // From the end, so earlier positions stay valid: `import(spec` → `__cellbImportFrom(spec, name`.\n for (const { start, sourceEnd } of calls.sort((a, b) => b.start - a.start))\n out =\n out.slice(0, start) +\n IMPORT_FROM +\n out.slice(start + \"import\".length, sourceEnd) +\n `, ${JSON.stringify(name)}` +\n out.slice(sourceEnd);\n return out;\n}\n\nfunction exportsOf(ast: any): ModuleExports {\n const names = new Set<string>();\n const stars: string[] = [];\n const nameOf = (n: any) => (n.type === \"Identifier\" ? n.name : String(n.value));\n const bound = (p: any) => {\n if (!p) return;\n if (p.type === \"Identifier\") names.add(p.name);\n else if (p.type === \"ObjectPattern\")\n for (const q of p.properties) bound(q.type === \"RestElement\" ? q.argument : q.value);\n else if (p.type === \"ArrayPattern\") for (const q of p.elements) bound(q);\n else if (p.type === \"RestElement\") bound(p.argument);\n else if (p.type === \"AssignmentPattern\") bound(p.left);\n };\n for (const node of ast.body) {\n if (node.type === \"ExportDefaultDeclaration\") names.add(\"default\");\n else if (node.type === \"ExportAllDeclaration\") {\n if (node.exported) names.add(nameOf(node.exported));\n else stars.push(String(node.source.value));\n } else if (node.type === \"ExportNamedDeclaration\") {\n const d = node.declaration;\n if (d?.type === \"VariableDeclaration\") for (const v of d.declarations) bound(v.id);\n else if (d?.id) names.add(d.id.name);\n for (const s of node.specifiers ?? []) names.add(nameOf(s.exported));\n }\n }\n return { names: [...names], stars };\n}\n\n/** `prelude` put in front of `source` on its first line (after a hashbang), so lines keep their numbers. */\nexport function prefixModule(source: string, prelude: string): string {\n if (!source.startsWith(\"#!\")) return prelude + source;\n const nl = source.indexOf(\"\\n\");\n return nl < 0\n ? `${source}\\n${prelude}`\n : `${source.slice(0, nl + 1)}${prelude}${source.slice(nl + 1)}`;\n}\n\n/**\n * Each module's export names, `export *` followed within the modules (as far as they resolve).\n * A module that does not parse, or a star from outside them, adds nothing. `modules` are the\n * modules' texts, or their exports already found (`analyzeModule`).\n */\nexport function exportNamesByModule(\n modules: Record<string, string> | Map<string, ModuleExports>,\n): Record<string, string[]> {\n const own =\n modules instanceof Map\n ? modules\n : new Map(\n Object.entries(modules).map(([n, text]) => [\n n,\n moduleExports(text) ?? { names: [], stars: [] },\n ]),\n );\n const names = new Set(own.keys());\n const all = (name: string, seen: Set<string>): Set<string> => {\n const out = new Set(own.get(name)?.names ?? []);\n if (seen.has(name)) return out;\n seen.add(name);\n for (const spec of own.get(name)?.stars ?? []) {\n const target = resolveModuleName(spec, name, names);\n if (target === undefined) continue;\n for (const n of all(target, seen)) if (n !== \"default\") out.add(n);\n }\n return out;\n };\n return Object.fromEntries([...names].map((n) => [n, [...all(n, new Set())]]));\n}\n\n/**\n * An ES module that stands for loaded module `name` where code imports it by a specifier no\n * bundler saw (an `import()` in code built with `Function`): it takes the bundled module's\n * namespace from the realm's registry (`globalThis.__cellbLoadedModules`) and re-exports it.\n */\nexport function loadedModuleShim(name: string, exportNames: string[]): string {\n const ident = /^[A-Za-z_$][\\w$]*$/;\n const named = exportNames.filter((n) => n !== \"default\" && ident.test(n));\n return [\n `const ns = await globalThis.__cellbLoadedModules.load(${JSON.stringify(name)});`,\n ...(exportNames.includes(\"default\") ? [\"export default ns.default;\"] : []),\n ...(named.length ? [`export const { ${named.join(\", \")} } = ns;`] : []),\n ].join(\"\\n\");\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { requireNodeSqlite } from "../adapters/node-sqlite-module.js";
|
|
1
|
+
import { nodeSqliteBytes, requireNodeSqlite } from "../adapters/node-sqlite-module.js";
|
|
2
2
|
import { PreconditionFailedError } from "./object-store.js";
|
|
3
3
|
const { DatabaseSync } = requireNodeSqlite();
|
|
4
4
|
/**
|
|
@@ -42,7 +42,7 @@ export function sqliteObjectStore(file) {
|
|
|
42
42
|
.prepare("SELECT next_etag FROM store_sequence WHERE singleton = 1")
|
|
43
43
|
.get();
|
|
44
44
|
db.prepare("UPDATE store_sequence SET next_etag = ? WHERE singleton = 1").run(next_etag + 1);
|
|
45
|
-
db.prepare("INSERT OR REPLACE INTO objects (key, body, etag, modified_ms, attributes) VALUES (?, ?, ?, ?, ?)").run(key, body, next_etag, Date.now(), toAttributes(attrs));
|
|
45
|
+
db.prepare("INSERT OR REPLACE INTO objects (key, body, etag, modified_ms, attributes) VALUES (?, ?, ?, ?, ?)").run(key, nodeSqliteBytes(body), next_etag, Date.now(), toAttributes(attrs));
|
|
46
46
|
db.exec("COMMIT");
|
|
47
47
|
return String(next_etag);
|
|
48
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-object-store.js","sourceRoot":"","sources":["../../src/bucket/sqlite-object-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite-object-store.js","sourceRoot":"","sources":["../../src/bucket/sqlite-object-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { nodeSqliteBytes, requireNodeSqlite } from \"../adapters/node-sqlite-module.js\";\nimport type { ObjectAttributes, ObjectStore } from \"./object-store.js\";\nimport { PreconditionFailedError } from \"./object-store.js\";\n\nconst { DatabaseSync } = requireNodeSqlite();\n\n/**\n * celld dev's local bucket: `<project>/.celld/dev/objects.sqlite3` (objects(key, body, etag\n * INTEGER, modified_ms, attributes) + store_sequence). Reading and writing it lets a\n * cellb node and `celld dev` share one bucket, so cells move between them.\n * Conditional writes are real (one SQLite transaction).\n */\nexport function sqliteObjectStore(file: string): ObjectStore & { close(): void } {\n const db = new DatabaseSync(file);\n db.exec(`CREATE TABLE IF NOT EXISTS objects (\n key TEXT PRIMARY KEY, body BLOB NOT NULL, etag INTEGER NOT NULL,\n modified_ms INTEGER NOT NULL, attributes TEXT NOT NULL)`);\n db.exec(`CREATE TABLE IF NOT EXISTS store_sequence (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1), next_etag INTEGER NOT NULL)`);\n db.exec(\"INSERT OR IGNORE INTO store_sequence (singleton, next_etag) VALUES (1, 1)\");\n db.exec(\"PRAGMA busy_timeout = 5000\");\n return {\n async get(key) {\n const r = db\n .prepare(\"SELECT body, etag, modified_ms, attributes FROM objects WHERE key = ?\")\n .get(key) as\n | { body: Uint8Array; etag: number; modified_ms: number; attributes: string }\n | undefined;\n return r\n ? {\n body: new Uint8Array(r.body),\n etag: String(r.etag),\n modifiedMs: Number(r.modified_ms),\n attrs: fromAttributes(r.attributes),\n }\n : undefined;\n },\n async put(key, body, cond, attrs) {\n db.exec(\"BEGIN IMMEDIATE\");\n try {\n const cur = db.prepare(\"SELECT etag FROM objects WHERE key = ?\").get(key) as\n | { etag: number }\n | undefined;\n if (cond?.ifNoneMatch === \"*\" && cur) throw new PreconditionFailedError(key);\n if (cond?.ifMatch !== undefined && String(cur?.etag) !== cond.ifMatch)\n throw new PreconditionFailedError(key);\n const { next_etag } = db\n .prepare(\"SELECT next_etag FROM store_sequence WHERE singleton = 1\")\n .get() as {\n next_etag: number;\n };\n db.prepare(\"UPDATE store_sequence SET next_etag = ? WHERE singleton = 1\").run(\n next_etag + 1,\n );\n db.prepare(\n \"INSERT OR REPLACE INTO objects (key, body, etag, modified_ms, attributes) VALUES (?, ?, ?, ?, ?)\",\n ).run(key, nodeSqliteBytes(body), next_etag, Date.now(), toAttributes(attrs));\n db.exec(\"COMMIT\");\n return String(next_etag);\n } catch (e) {\n db.exec(\"ROLLBACK\");\n throw e;\n }\n },\n async list(prefix) {\n return (\n db\n .prepare(\"SELECT key FROM objects WHERE key >= ? AND key < ? ORDER BY key\")\n .all(prefix, `${prefix}\\uffff`) as {\n key: string;\n }[]\n ).map((r) => r.key);\n },\n async delete(key) {\n db.prepare(\"DELETE FROM objects WHERE key = ?\").run(key);\n },\n close() {\n db.close();\n },\n };\n}\n\n// celld dev's `attributes` column: a JSON array of {kind, name, value} — \"metadata\" entries\n// (user metadata, name = key) and one entry per content header (\"content-type\", …).\ntype HeaderField =\n | \"contentType\"\n | \"contentLanguage\"\n | \"contentDisposition\"\n | \"contentEncoding\"\n | \"cacheControl\";\nconst HEADERS: [HeaderField, string][] = [\n [\"contentType\", \"content-type\"],\n [\"contentLanguage\", \"content-language\"],\n [\"contentDisposition\", \"content-disposition\"],\n [\"contentEncoding\", \"content-encoding\"],\n [\"cacheControl\", \"cache-control\"],\n];\nfunction toAttributes(attrs?: ObjectAttributes): string {\n const out: { kind: string; name: string | null; value: string }[] = [];\n for (const [name, value] of Object.entries(attrs?.metadata ?? {}))\n out.push({ kind: \"metadata\", name, value });\n for (const [field, kind] of HEADERS) {\n const v = attrs?.[field];\n if (typeof v === \"string\") out.push({ kind, name: null, value: v });\n }\n return JSON.stringify(out);\n}\nfunction fromAttributes(raw: string): ObjectAttributes | undefined {\n let list: { kind: string; name: string | null; value: string }[];\n try {\n list = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!Array.isArray(list) || !list.length) return undefined;\n const attrs: ObjectAttributes = {};\n for (const e of list) {\n if (e.kind === \"metadata\" && e.name) {\n attrs.metadata = attrs.metadata ?? {};\n attrs.metadata[e.name] = e.value;\n }\n const h = HEADERS.find(([, kind]) => kind === e.kind);\n if (h) (attrs as Record<string, unknown>)[h[0]] = e.value;\n }\n return attrs;\n}\n"]}
|
package/dist/core/alarms.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** The longest delay setTimeout takes (2^31 - 1 ms, about 24.8 days). */
|
|
2
|
+
const MAX_TIMER_MS = 2 ** 31 - 1;
|
|
1
3
|
/**
|
|
2
4
|
* Runtime-wide alarm scheduler. Every object's alarm lives in its own `_cf_METADATA`
|
|
3
5
|
* (the truth); this index — one small SQLite database next to the cells — lets a
|
|
@@ -58,13 +60,21 @@ export class AlarmScheduler {
|
|
|
58
60
|
]);
|
|
59
61
|
this.#arm({ ...entry, at });
|
|
60
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* A timer waits at most `MAX_TIMER_MS`: Node's setTimeout fires a longer delay after 1 ms,
|
|
65
|
+
* which woke an alarm set weeks ahead every millisecond. Further-off alarms wait in steps
|
|
66
|
+
* and fire once, when due.
|
|
67
|
+
*/
|
|
61
68
|
#arm(e) {
|
|
62
69
|
this.#clear(e.cellKey);
|
|
63
70
|
const delay = Math.max(0, e.at - this.#clock.now());
|
|
64
71
|
this.#timers.set(e.cellKey, this.#clock.setTimeout(() => {
|
|
65
72
|
this.#timers.delete(e.cellKey);
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
if (this.#clock.now() < e.at)
|
|
74
|
+
this.#arm(e);
|
|
75
|
+
else
|
|
76
|
+
void this.#fire(e);
|
|
77
|
+
}, Math.min(delay, MAX_TIMER_MS)));
|
|
68
78
|
}
|
|
69
79
|
#clear(cellKey) {
|
|
70
80
|
const t = this.#timers.get(cellKey);
|
package/dist/core/alarms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alarms.js","sourceRoot":"","sources":["../../src/core/alarms.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"alarms.js","sourceRoot":"","sources":["../../src/core/alarms.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Clock, SyncSqlDriver } from \"../ports.js\";\n\n/** The longest delay setTimeout takes (2^31 - 1 ms, about 24.8 days). */\nconst MAX_TIMER_MS = 2 ** 31 - 1;\n\nexport interface AlarmEntry {\n cellKey: string;\n className: string;\n idHex: string;\n at: number;\n}\n\n/**\n * Runtime-wide alarm scheduler. Every object's alarm lives in its own `_cf_METADATA`\n * (the truth); this index — one small SQLite database next to the cells — lets a\n * restarted runtime wake objects whose alarms are due without anyone touching them\n * (catch-up after a crash, a closed tab or a frozen page).\n */\nexport class AlarmScheduler {\n readonly #timers = new Map<string, unknown>();\n readonly #clock: Clock;\n readonly #openIndex?: () => SyncSqlDriver;\n #indexDb: SyncSqlDriver | null | undefined;\n readonly #fire: (e: AlarmEntry) => Promise<void>;\n\n constructor(opts: {\n clock: Clock;\n openIndex?: () => SyncSqlDriver;\n fire: (e: AlarmEntry) => Promise<void>;\n }) {\n this.#clock = opts.clock;\n this.#openIndex = opts.openIndex;\n this.#fire = opts.fire;\n }\n\n /**\n * The index is opened lazily and is best effort: if it cannot be opened (e.g. another\n * process holds it in EXCLUSIVE locking mode) alarms still fire for live objects; only\n * the catch-up after a restart is lost for this runtime.\n */\n get #index(): SyncSqlDriver | undefined {\n if (this.#indexDb === undefined) {\n try {\n const db = this.#openIndex?.() ?? null;\n db?.exec(\n \"CREATE TABLE IF NOT EXISTS alarms (cell_key TEXT PRIMARY KEY, class_name TEXT, id_hex TEXT, at INTEGER)\",\n [],\n );\n this.#indexDb = db;\n } catch {\n this.#indexDb = null;\n }\n }\n return this.#indexDb ?? undefined;\n }\n\n /** Re-arms every alarm recorded in the index (due ones fire at once). */\n restore(): void {\n for (const [cellKey, className, idHex, at] of this.#index?.exec(\"SELECT * FROM alarms\", [])\n .rows ?? [])\n this.#arm({\n cellKey: String(cellKey),\n className: String(className),\n idHex: String(idHex),\n at: Number(at),\n });\n }\n\n set(entry: Omit<AlarmEntry, \"at\">, at: number | null): void {\n this.#clear(entry.cellKey);\n if (at === null) {\n this.#index?.exec(\"DELETE FROM alarms WHERE cell_key = ?\", [entry.cellKey]);\n return;\n }\n this.#index?.exec(\"INSERT OR REPLACE INTO alarms VALUES (?, ?, ?, ?)\", [\n entry.cellKey,\n entry.className,\n entry.idHex,\n at,\n ]);\n this.#arm({ ...entry, at });\n }\n\n /**\n * A timer waits at most `MAX_TIMER_MS`: Node's setTimeout fires a longer delay after 1 ms,\n * which woke an alarm set weeks ahead every millisecond. Further-off alarms wait in steps\n * and fire once, when due.\n */\n #arm(e: AlarmEntry): void {\n this.#clear(e.cellKey);\n const delay = Math.max(0, e.at - this.#clock.now());\n this.#timers.set(\n e.cellKey,\n this.#clock.setTimeout(\n () => {\n this.#timers.delete(e.cellKey);\n if (this.#clock.now() < e.at) this.#arm(e);\n else void this.#fire(e);\n },\n Math.min(delay, MAX_TIMER_MS),\n ),\n );\n }\n\n #clear(cellKey: string): void {\n const t = this.#timers.get(cellKey);\n if (t !== undefined) this.#clock.clearTimeout(t);\n this.#timers.delete(cellKey);\n }\n\n stop(): void {\n for (const t of this.#timers.values()) this.#clock.clearTimeout(t);\n this.#timers.clear();\n }\n\n /** Closes the index database (after the objects that record into it have closed). */\n close(): void {\n this.stop();\n const db = this.#indexDb;\n this.#indexDb = null; // stays closed: later records are dropped\n db?.close();\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The global that rewritten bodies call: `(spec) => Promise<namespace>`. */
|
|
2
|
+
export declare const FUNCTION_IMPORT = "__cellbFunctionImport";
|
|
3
|
+
/** A body's `import(` calls made into `__cellbFunctionImport(` calls, or the body unchanged. */
|
|
4
|
+
export declare function routeBodyImports(params: string[], body: string, kind: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Wraps this realm's function constructors (`Function`, and the constructors reached through
|
|
7
|
+
* `.constructor` of async and generator functions) so that bodies built at run time route their
|
|
8
|
+
* `import()` through `globalThis.__cellbFunctionImport`. Once per realm.
|
|
9
|
+
*/
|
|
10
|
+
export declare function routeFunctionImports(): void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `import()` in code a loaded Worker builds at run time with `Function` (or `AsyncFunction` and the
|
|
3
|
+
* generator constructors): Kitesurf imports page modules through
|
|
4
|
+
* `new (async () => {}).constructor("spec", "return await import(spec)")`. On workerd that resolves
|
|
5
|
+
* against the loaded Worker's modules. In a browser isolate it would resolve against the isolate
|
|
6
|
+
* worker's own URL, and no bundler or module hook sees such code.
|
|
7
|
+
*
|
|
8
|
+
* The isolate's realm is the loaded Worker's, so its function constructors are wrapped: a body
|
|
9
|
+
* that contains `import(` is parsed, and each `import(` becomes a call of
|
|
10
|
+
* `globalThis.__cellbFunctionImport`, which the loader binds to the loaded Worker's module
|
|
11
|
+
* resolution (browser-modules.ts). Bodies without `import`, and bodies that do not parse (the
|
|
12
|
+
* constructor reports their syntax error), are left as they are.
|
|
13
|
+
*/
|
|
14
|
+
import { parse } from "acorn";
|
|
15
|
+
/** The global that rewritten bodies call: `(spec) => Promise<namespace>`. */
|
|
16
|
+
export const FUNCTION_IMPORT = "__cellbFunctionImport";
|
|
17
|
+
const kinds = [
|
|
18
|
+
[Function, "function"],
|
|
19
|
+
[(async () => { }).constructor, "async function"],
|
|
20
|
+
[function* () { }.constructor, "function*"],
|
|
21
|
+
[async function* () { }.constructor, "async function*"],
|
|
22
|
+
];
|
|
23
|
+
/** A body's `import(` calls made into `__cellbFunctionImport(` calls, or the body unchanged. */
|
|
24
|
+
export function routeBodyImports(params, body, kind) {
|
|
25
|
+
if (!body.includes("import"))
|
|
26
|
+
return body;
|
|
27
|
+
// The constructor's own wrapping (ECMA-262 CreateDynamicFunction), so positions match the body.
|
|
28
|
+
const head = `(${kind} anonymous(${params.join(",")}\n) {\n`;
|
|
29
|
+
let ast;
|
|
30
|
+
try {
|
|
31
|
+
ast = parse(`${head}${body}\n})`, { ecmaVersion: "latest", sourceType: "script" });
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return body;
|
|
35
|
+
}
|
|
36
|
+
const starts = [];
|
|
37
|
+
const visit = (n) => {
|
|
38
|
+
if (!n || typeof n.type !== "string")
|
|
39
|
+
return;
|
|
40
|
+
if (n.type === "ImportExpression")
|
|
41
|
+
starts.push(n.start - head.length);
|
|
42
|
+
for (const key of Object.keys(n)) {
|
|
43
|
+
const v = n[key];
|
|
44
|
+
if (Array.isArray(v))
|
|
45
|
+
for (const c of v)
|
|
46
|
+
visit(c);
|
|
47
|
+
else if (v && typeof v === "object" && typeof v.type === "string")
|
|
48
|
+
visit(v);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
visit(ast);
|
|
52
|
+
let out = body;
|
|
53
|
+
for (const at of starts.sort((a, b) => b - a))
|
|
54
|
+
if (at >= 0)
|
|
55
|
+
out = `${out.slice(0, at)}${FUNCTION_IMPORT}${out.slice(at + "import".length)}`;
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
let installed = false;
|
|
59
|
+
/**
|
|
60
|
+
* Wraps this realm's function constructors (`Function`, and the constructors reached through
|
|
61
|
+
* `.constructor` of async and generator functions) so that bodies built at run time route their
|
|
62
|
+
* `import()` through `globalThis.__cellbFunctionImport`. Once per realm.
|
|
63
|
+
*/
|
|
64
|
+
export function routeFunctionImports() {
|
|
65
|
+
if (installed)
|
|
66
|
+
return;
|
|
67
|
+
installed = true;
|
|
68
|
+
const rewrite = (args, kind) => {
|
|
69
|
+
if (!args.length)
|
|
70
|
+
return args;
|
|
71
|
+
const params = args.slice(0, -1).map(String);
|
|
72
|
+
return [...params, routeBodyImports(params, String(args[args.length - 1]), kind)];
|
|
73
|
+
};
|
|
74
|
+
for (const [Ctor, kind] of kinds) {
|
|
75
|
+
const wrapped = new Proxy(Ctor, {
|
|
76
|
+
apply: (target, thisArg, args) => Reflect.apply(target, thisArg, rewrite(args, kind)),
|
|
77
|
+
construct: (target, args, newTarget) => Reflect.construct(target, rewrite(args, kind), newTarget === wrapped ? target : newTarget),
|
|
78
|
+
});
|
|
79
|
+
// `fn.constructor` (how code reaches AsyncFunction) and, for Function, the global itself.
|
|
80
|
+
Object.defineProperty(Ctor.prototype, "constructor", {
|
|
81
|
+
value: wrapped,
|
|
82
|
+
writable: true,
|
|
83
|
+
configurable: true,
|
|
84
|
+
});
|
|
85
|
+
if (Ctor === Function)
|
|
86
|
+
Object.defineProperty(globalThis, "Function", {
|
|
87
|
+
value: wrapped,
|
|
88
|
+
writable: true,
|
|
89
|
+
configurable: true,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=function-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-imports.js","sourceRoot":"","sources":["../../src/isolate/function-imports.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `import()` in code a loaded Worker builds at run time with `Function` (or `AsyncFunction` and the\n * generator constructors): Kitesurf imports page modules through\n * `new (async () => {}).constructor(\"spec\", \"return await import(spec)\")`. On workerd that resolves\n * against the loaded Worker's modules. In a browser isolate it would resolve against the isolate\n * worker's own URL, and no bundler or module hook sees such code.\n *\n * The isolate's realm is the loaded Worker's, so its function constructors are wrapped: a body\n * that contains `import(` is parsed, and each `import(` becomes a call of\n * `globalThis.__cellbFunctionImport`, which the loader binds to the loaded Worker's module\n * resolution (browser-modules.ts). Bodies without `import`, and bodies that do not parse (the\n * constructor reports their syntax error), are left as they are.\n */\nimport { parse } from \"acorn\";\n\n/** The global that rewritten bodies call: `(spec) => Promise<namespace>`. */\nexport const FUNCTION_IMPORT = \"__cellbFunctionImport\";\n\nconst kinds: [Function, string][] = [\n [Function, \"function\"],\n [(async () => {}).constructor, \"async function\"],\n [function* () {}.constructor, \"function*\"],\n [async function* () {}.constructor, \"async function*\"],\n];\n\n/** A body's `import(` calls made into `__cellbFunctionImport(` calls, or the body unchanged. */\nexport function routeBodyImports(params: string[], body: string, kind: string): string {\n if (!body.includes(\"import\")) return body;\n // The constructor's own wrapping (ECMA-262 CreateDynamicFunction), so positions match the body.\n const head = `(${kind} anonymous(${params.join(\",\")}\\n) {\\n`;\n let ast: any;\n try {\n ast = parse(`${head}${body}\\n})`, { ecmaVersion: \"latest\", sourceType: \"script\" });\n } catch {\n return body;\n }\n const starts: number[] = [];\n const visit = (n: any) => {\n if (!n || typeof n.type !== \"string\") return;\n if (n.type === \"ImportExpression\") starts.push(n.start - head.length);\n for (const key of Object.keys(n)) {\n const v = n[key];\n if (Array.isArray(v)) for (const c of v) visit(c);\n else if (v && typeof v === \"object\" && typeof v.type === \"string\") visit(v);\n }\n };\n visit(ast);\n let out = body;\n for (const at of starts.sort((a, b) => b - a))\n if (at >= 0) out = `${out.slice(0, at)}${FUNCTION_IMPORT}${out.slice(at + \"import\".length)}`;\n return out;\n}\n\nlet installed = false;\n\n/**\n * Wraps this realm's function constructors (`Function`, and the constructors reached through\n * `.constructor` of async and generator functions) so that bodies built at run time route their\n * `import()` through `globalThis.__cellbFunctionImport`. Once per realm.\n */\nexport function routeFunctionImports(): void {\n if (installed) return;\n installed = true;\n const rewrite = (args: unknown[], kind: string) => {\n if (!args.length) return args;\n const params = args.slice(0, -1).map(String);\n return [...params, routeBodyImports(params, String(args[args.length - 1]), kind)];\n };\n for (const [Ctor, kind] of kinds) {\n const wrapped: Function = new Proxy(Ctor, {\n apply: (target, thisArg, args) => Reflect.apply(target, thisArg, rewrite(args, kind)),\n construct: (target, args, newTarget) =>\n Reflect.construct(target, rewrite(args, kind), newTarget === wrapped ? target : newTarget),\n });\n // `fn.constructor` (how code reaches AsyncFunction) and, for Function, the global itself.\n Object.defineProperty(Ctor.prototype, \"constructor\", {\n value: wrapped,\n writable: true,\n configurable: true,\n });\n if (Ctor === Function)\n Object.defineProperty(globalThis, \"Function\", {\n value: wrapped,\n writable: true,\n configurable: true,\n });\n }\n}\n"]}
|
|
@@ -8,6 +8,7 @@ import * as workersModule from "../project/cloudflare-workers.js";
|
|
|
8
8
|
import { workersHostRegistry } from "../project/site-loader.js";
|
|
9
9
|
import { realmWorkerScope } from "../project/worker-scope.js";
|
|
10
10
|
import * as workersGlobals from "../project/workers-globals-module.js";
|
|
11
|
+
import { routeFunctionImports } from "./function-imports.js";
|
|
11
12
|
import { serveIsolate } from "./isolate.js";
|
|
12
13
|
import { makeGlobalsWritable } from "./writable-globals.js";
|
|
13
14
|
// The channel to the host, from this worker's own methods, taken before the loaded code runs:
|
|
@@ -36,6 +37,9 @@ workersHostRegistry({
|
|
|
36
37
|
// workerd lets Worker code assign its globals (Kitesurf's DOM shim sets `navigator` and
|
|
37
38
|
// `location`); this realm's getter-only ones become writable (writable-globals.ts).
|
|
38
39
|
makeGlobalsWritable();
|
|
40
|
+
// An `import()` in code the loaded Worker builds with `Function` resolves against its modules
|
|
41
|
+
// (function-imports.ts; the loader binds the resolution once the code is loaded).
|
|
42
|
+
routeFunctionImports();
|
|
39
43
|
// This worker is the loaded Worker's realm: its globals are the Workers ones (as on Node,
|
|
40
44
|
// src/isolate/node-entry.ts). Loaded code reads them as free names (partyserver builds its
|
|
41
45
|
// `new WebSocketPair()` and its 101 `Response` that way).
|
|
@@ -63,7 +67,7 @@ serveIsolate(hostChannel, async (load, logs) => {
|
|
|
63
67
|
g.__cellsLoadedConsoles[load.consoleId] = own;
|
|
64
68
|
return (await import(/* @vite-ignore */ load.url));
|
|
65
69
|
}
|
|
66
|
-
return browserModuleLoader(PROJECT_WORKERS_MODULE_SHIM)("isolate", { mainModule: load.mainModule, modules: load.modules }, (level, args) => logs(level, args));
|
|
70
|
+
return browserModuleLoader(PROJECT_WORKERS_MODULE_SHIM, { functionImports: true })("isolate", { mainModule: load.mainModule, modules: load.modules }, (level, args) => logs(level, args));
|
|
67
71
|
}, {
|
|
68
72
|
patchConsole: false,
|
|
69
73
|
// Facets of the loaded code: SQLite on OPFS, one sahpool per loaded Worker.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolate-worker.js","sourceRoot":"","sources":["../../src/isolate/isolate-worker.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"isolate-worker.js","sourceRoot":"","sources":["../../src/isolate/isolate-worker.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"webworker\" />\n// One loaded Worker in its own realm (a Dedicated Worker), served over its port.\n\nimport sqlite3InitModule from \"@sqlite.org/sqlite-wasm\";\nimport { sahpoolOpener } from \"../adapters/wasm-sqlite.js\";\nimport { browserModuleLoader, PROJECT_WORKERS_MODULE_SHIM } from \"../project/browser-modules.js\";\nimport * as emailModule from \"../project/cloudflare-email.js\";\nimport * as workersModule from \"../project/cloudflare-workers.js\";\nimport { workersHostRegistry } from \"../project/site-loader.js\";\nimport { realmWorkerScope } from \"../project/worker-scope.js\";\nimport * as workersGlobals from \"../project/workers-globals-module.js\";\nimport { routeFunctionImports } from \"./function-imports.js\";\nimport { serveIsolate } from \"./isolate.js\";\nimport type { PortLike } from \"./protocol.js\";\nimport { makeGlobalsWritable } from \"./writable-globals.js\";\n\n// The channel to the host, from this worker's own methods, taken before the loaded code runs:\n// Worker code may define a global `postMessage` (Kitesurf's window emulation does), and a port\n// that looked `self.postMessage` up on each send would then post into it.\nconst hostChannel: PortLike = {\n postMessage: self.postMessage.bind(self) as PortLike[\"postMessage\"],\n addEventListener: self.addEventListener.bind(self) as PortLike[\"addEventListener\"],\n removeEventListener: self.removeEventListener.bind(self) as PortLike[\"removeEventListener\"],\n};\n\n(globalThis as Record<string, unknown>).__cellsWorkersModule = workersModule;\n// The loaded Worker's own `env` and `exports` (serveIsolate binds the realm's scope to them).\nconst scope = realmWorkerScope();\nworkersHostRegistry({\n workersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n emailModule,\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n});\n\n// workerd lets Worker code assign its globals (Kitesurf's DOM shim sets `navigator` and\n// `location`); this realm's getter-only ones become writable (writable-globals.ts).\nmakeGlobalsWritable();\n\n// An `import()` in code the loaded Worker builds with `Function` resolves against its modules\n// (function-imports.ts; the loader binds the resolution once the code is loaded).\nrouteFunctionImports();\n\n// This worker is the loaded Worker's realm: its globals are the Workers ones (as on Node,\n// src/isolate/node-entry.ts). Loaded code reads them as free names (partyserver builds its\n// `new WebSocketPair()` and its 101 `Response` that way).\nObject.assign(globalThis, {\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocket: workersGlobals.WebSocket,\n WebSocketPair: workersGlobals.WebSocketPair,\n WebSocketRequestResponsePair: workersGlobals.WebSocketRequestResponsePair,\n});\n\n// The global console is left alone (the dev server's client logs here too): loaded modules\n// get a console of their own that reports to the host.\nserveIsolate(\n hostChannel,\n async (load: any, logs) => {\n const own = Object.assign(Object.create(console), {\n log: (...a: unknown[]) => logs(\"log\", a),\n info: (...a: unknown[]) => logs(\"info\", a),\n warn: (...a: unknown[]) => logs(\"warn\", a),\n error: (...a: unknown[]) => logs(\"error\", a),\n debug: (...a: unknown[]) => logs(\"debug\", a),\n });\n if (load.url) {\n // The site's per-id module server binds `console` to __cellsLoadedConsoles[id].\n const g = globalThis as Record<string, any>;\n g.__cellsLoadedConsoles ??= {};\n g.__cellsLoadedConsoles[load.consoleId] = own;\n return (await import(/* @vite-ignore */ load.url)) as Record<string, unknown>;\n }\n return browserModuleLoader(PROJECT_WORKERS_MODULE_SHIM, { functionImports: true })(\n \"isolate\",\n { mainModule: load.mainModule, modules: load.modules },\n (level, args) => logs(level, args),\n );\n },\n {\n patchConsole: false,\n // Facets of the loaded code: SQLite on OPFS, one sahpool per loaded Worker.\n openSql: async (load: any) => {\n const sqlite3 = await (sqlite3InitModule as any)({ print() {}, printErr() {} });\n return sahpoolOpener(sqlite3, { name: load?.storageName ?? \"isolate\" });\n },\n },\n);\n"]}
|
package/dist/isolate/protocol.js
CHANGED
|
@@ -322,13 +322,27 @@ function fromWire(v, mux, release) {
|
|
|
322
322
|
case "stream":
|
|
323
323
|
return body(v.body);
|
|
324
324
|
case "response": {
|
|
325
|
-
|
|
325
|
+
// `Response.error()` (status 0) is rebuilt as one.
|
|
326
|
+
if (v.status === 0) {
|
|
327
|
+
if (v.body !== null)
|
|
328
|
+
release(v.body);
|
|
329
|
+
return NativeResponse.error();
|
|
330
|
+
}
|
|
331
|
+
// The constructor takes statuses 200-599 only: another one (a 1xx) comes back as a response
|
|
332
|
+
// with no body that still reports its status.
|
|
333
|
+
const constructible = v.status >= 200 && v.status <= 599;
|
|
334
|
+
const noBody = !constructible || NULL_BODY.includes(v.status);
|
|
335
|
+
if (noBody && v.body !== null)
|
|
326
336
|
release(v.body);
|
|
327
|
-
const res = new Response(
|
|
328
|
-
status: v.status,
|
|
337
|
+
const res = new Response(noBody ? null : body(v.body), {
|
|
338
|
+
status: constructible ? v.status : 200,
|
|
329
339
|
statusText: v.statusText,
|
|
330
340
|
headers: v.headers,
|
|
331
341
|
});
|
|
342
|
+
if (!constructible) {
|
|
343
|
+
Object.defineProperty(res, "status", { value: v.status, enumerable: true });
|
|
344
|
+
Object.defineProperty(res, "ok", { value: false, enumerable: true });
|
|
345
|
+
}
|
|
332
346
|
if (v.url)
|
|
333
347
|
Object.defineProperty(res, "url", { value: v.url, enumerable: true });
|
|
334
348
|
return res;
|