wasm-idle 1.0.7 → 1.0.9
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 +48 -11
- package/dist/playground/applicationAssets.js +18 -0
- package/dist/playground/assetBridge.js +7 -0
- package/dist/playground/assets.d.ts +70 -0
- package/dist/playground/assets.js +120 -0
- package/dist/playground/cachedClang.js +43 -5
- package/dist/playground/clang.d.ts +5 -0
- package/dist/playground/clang.js +96 -0
- package/dist/playground/clangAssetIntegrity.d.ts +6 -0
- package/dist/playground/clangAssetIntegrity.js +3 -2
- package/dist/playground/clangWorkerProtocol.d.ts +12 -1
- package/dist/playground/fennel.d.ts +9 -0
- package/dist/playground/fennel.js +30 -0
- package/dist/playground/fennelBootstrap.d.ts +31 -0
- package/dist/playground/fennelBootstrap.js +118 -0
- package/dist/playground/grain.d.ts +9 -0
- package/dist/playground/grain.js +127 -0
- package/dist/playground/hy.d.ts +21 -0
- package/dist/playground/hy.js +24 -0
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +49 -0
- package/dist/playground/lua.d.ts +19 -0
- package/dist/playground/lua.js +64 -39
- package/dist/playground/objectivec.d.ts +3 -1
- package/dist/playground/objectivec.js +6 -2
- package/dist/playground/options.js +1 -1
- package/dist/playground/postgresql.d.ts +36 -0
- package/dist/playground/postgresql.js +543 -0
- package/dist/playground/python.d.ts +5 -0
- package/dist/playground/python.js +13 -0
- package/dist/playground/rescript.d.ts +5 -0
- package/dist/playground/rescript.js +58 -0
- package/dist/playground/rescriptPreflight.d.ts +26 -0
- package/dist/playground/rescriptPreflight.js +381 -0
- package/dist/playground/staticRuntimeModuleVersion.d.ts +1 -1
- package/dist/playground/staticRuntimeModuleVersion.js +1 -1
- package/dist/playground/staticRuntimePreflightExecute.d.ts +2 -1
- package/dist/playground/staticRuntimePreflightExecute.js +9 -0
- package/dist/playground/staticRuntimePreflightProtocol.d.ts +1 -1
- package/dist/playground/v.d.ts +46 -0
- package/dist/playground/v.js +703 -0
- package/dist/playground/wasmFennelVersion.d.ts +23 -0
- package/dist/playground/wasmFennelVersion.js +16 -0
- package/dist/playground/wasmGrainVersion.d.ts +24 -0
- package/dist/playground/wasmGrainVersion.js +25 -0
- package/dist/playground/wasmHyVersion.d.ts +7 -0
- package/dist/playground/wasmHyVersion.js +15 -0
- package/dist/playground/wasmReScriptVersion.d.ts +20 -0
- package/dist/playground/wasmReScriptVersion.js +20 -0
- package/dist/playground/worker/cachedClangCompile.js +37 -4
- package/dist/playground/worker/clang.js +35 -7
- package/dist/playground/worker/lua.js +48 -11
- package/dist/playground/worker/postgresql.d.ts +1 -0
- package/dist/playground/worker/postgresql.js +205 -0
- package/dist/playground/worker/python.js +106 -9
- package/dist/playground/worker/staticRuntimePreflight.js +2 -1
- package/dist/playground/worker/v.d.ts +1 -0
- package/dist/playground/worker/v.js +106 -0
- package/package.json +18 -7
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinned receipt for the official single-file Fennel compiler (`fennel.lua`).
|
|
3
|
+
*
|
|
4
|
+
* The asset is the unmodified upstream release from https://fennel-lang.org/downloads/
|
|
5
|
+
* (MIT), gzip-compressed with `gzip -9 -n`. Fennel runs on the bundled wasm-lua
|
|
6
|
+
* (wasmoon) Lua VM, so this receipt only covers the compiler source.
|
|
7
|
+
*/
|
|
8
|
+
export declare const WASM_FENNEL_COMPILER_RECEIPT: Readonly<{
|
|
9
|
+
fennelVersion: "1.6.1";
|
|
10
|
+
path: "wasm-fennel/fennel-1.6.1.lua.gz";
|
|
11
|
+
bytes: 62385;
|
|
12
|
+
sha256: "108b12fe2acb5c47c74c461d7ecbf5e00fb72102a9b927df985b9b4b858e49c0";
|
|
13
|
+
uncompressedBytes: 301522;
|
|
14
|
+
uncompressedSha256: "c3d45602041e7d8ef8a212563573df040c48a85c648a29fb4597ebed4bc38ec2";
|
|
15
|
+
}>;
|
|
16
|
+
export type WasmFennelCompilerReceipt = {
|
|
17
|
+
readonly fennelVersion: string;
|
|
18
|
+
readonly bytes: number;
|
|
19
|
+
readonly sha256: string;
|
|
20
|
+
readonly uncompressedBytes: number;
|
|
21
|
+
readonly uncompressedSha256: string;
|
|
22
|
+
};
|
|
23
|
+
export declare const WASM_FENNEL_ASSET_VERSION: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinned receipt for the official single-file Fennel compiler (`fennel.lua`).
|
|
3
|
+
*
|
|
4
|
+
* The asset is the unmodified upstream release from https://fennel-lang.org/downloads/
|
|
5
|
+
* (MIT), gzip-compressed with `gzip -9 -n`. Fennel runs on the bundled wasm-lua
|
|
6
|
+
* (wasmoon) Lua VM, so this receipt only covers the compiler source.
|
|
7
|
+
*/
|
|
8
|
+
export const WASM_FENNEL_COMPILER_RECEIPT = Object.freeze({
|
|
9
|
+
fennelVersion: '1.6.1',
|
|
10
|
+
path: 'wasm-fennel/fennel-1.6.1.lua.gz',
|
|
11
|
+
bytes: 62385,
|
|
12
|
+
sha256: '108b12fe2acb5c47c74c461d7ecbf5e00fb72102a9b927df985b9b4b858e49c0',
|
|
13
|
+
uncompressedBytes: 301522,
|
|
14
|
+
uncompressedSha256: 'c3d45602041e7d8ef8a212563573df040c48a85c648a29fb4597ebed4bc38ec2'
|
|
15
|
+
});
|
|
16
|
+
export const WASM_FENNEL_ASSET_VERSION = WASM_FENNEL_COMPILER_RECEIPT.sha256.slice(0, 16);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const bundledGrainProfile: {
|
|
2
|
+
readonly profileId: "grain-0.7.2-jsoo-wasi-v1";
|
|
3
|
+
readonly grainVersion: "0.7.2";
|
|
4
|
+
readonly compilerJavaScript: {
|
|
5
|
+
readonly bytes: 20872240;
|
|
6
|
+
readonly sha256: "0a85cf0120aafd873e41eb901a18090453010f8f819074b77c14e1c359cafd1e";
|
|
7
|
+
};
|
|
8
|
+
readonly compilerStorage: {
|
|
9
|
+
readonly bytes: 3417153;
|
|
10
|
+
readonly sha256: "38cf8c42ed83447287e0bc54c768661a110b7becf1b93bdfdd6da30537c4e289";
|
|
11
|
+
};
|
|
12
|
+
readonly stdlibPack: {
|
|
13
|
+
readonly bytes: 5066092;
|
|
14
|
+
readonly sha256: "c56e83cbea649be5dd94ce98ae648b8f98e40203761ef7b1ad0a799048ee08eb";
|
|
15
|
+
};
|
|
16
|
+
readonly stdlibStorage: {
|
|
17
|
+
readonly bytes: 1653344;
|
|
18
|
+
readonly sha256: "7180475667a3129821be12aa787f449e58de62b0bb5c0e5472077b73b9e5cafa";
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare const bundledGrainWorkerReceipt: {
|
|
22
|
+
readonly bytes: 28127;
|
|
23
|
+
readonly sha256: "c36b478c25f000a9a9ecdb186490cf8fce07ece9b5ac271031aa2e97f75cabab";
|
|
24
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Generated by scripts/sync-wasm-grain.mjs from the pinned upstream Grain release.
|
|
2
|
+
export const bundledGrainProfile = {
|
|
3
|
+
profileId: 'grain-0.7.2-jsoo-wasi-v1',
|
|
4
|
+
grainVersion: '0.7.2',
|
|
5
|
+
compilerJavaScript: {
|
|
6
|
+
bytes: 20872240,
|
|
7
|
+
sha256: '0a85cf0120aafd873e41eb901a18090453010f8f819074b77c14e1c359cafd1e'
|
|
8
|
+
},
|
|
9
|
+
compilerStorage: {
|
|
10
|
+
bytes: 3417153,
|
|
11
|
+
sha256: '38cf8c42ed83447287e0bc54c768661a110b7becf1b93bdfdd6da30537c4e289'
|
|
12
|
+
},
|
|
13
|
+
stdlibPack: {
|
|
14
|
+
bytes: 5066092,
|
|
15
|
+
sha256: 'c56e83cbea649be5dd94ce98ae648b8f98e40203761ef7b1ad0a799048ee08eb'
|
|
16
|
+
},
|
|
17
|
+
stdlibStorage: {
|
|
18
|
+
bytes: 1653344,
|
|
19
|
+
sha256: '7180475667a3129821be12aa787f449e58de62b0bb5c0e5472077b73b9e5cafa'
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const bundledGrainWorkerReceipt = {
|
|
23
|
+
bytes: 28127,
|
|
24
|
+
sha256: 'c36b478c25f000a9a9ecdb186490cf8fce07ece9b5ac271031aa2e97f75cabab'
|
|
25
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Pinned by scripts/sync-wasm-hy.mjs. Both wheels are pure Python and install into the bundled
|
|
2
|
+
// Pyodide runtime; they are served from static/wasm-hy/ and never fetched from PyPI at runtime.
|
|
3
|
+
export const WASM_HY_VERSION = '1.3.1';
|
|
4
|
+
export const WASM_HY_WHEELS = Object.freeze([
|
|
5
|
+
Object.freeze({
|
|
6
|
+
fileName: 'funcparserlib-1.0.1-py2.py3-none-any.whl',
|
|
7
|
+
bytes: 17842,
|
|
8
|
+
sha256: '95da15d3f0d00b9b6f4bf04005c708af3faa115f7b45692ace064ebe758c68e8'
|
|
9
|
+
}),
|
|
10
|
+
Object.freeze({
|
|
11
|
+
fileName: 'hy-1.3.1-py3-none-any.whl',
|
|
12
|
+
bytes: 122343,
|
|
13
|
+
sha256: 'fef54e98b2080cd3993d5ce5a4310ef2b0fc756c972203b86fedc0e0f2908f53'
|
|
14
|
+
})
|
|
15
|
+
]);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const WASM_RESCRIPT_RUNTIME_PROFILE: {
|
|
2
|
+
readonly profileId: "rescript-12.3.1-playground-commonjs";
|
|
3
|
+
readonly sourceRevision: "v12.3.1";
|
|
4
|
+
readonly manifestFingerprint: "c5cfee09555006071de09a4793ff080f9c49ef901fdb66d76ca16470dab7efc5";
|
|
5
|
+
readonly manifestReceipt: {
|
|
6
|
+
readonly bytes: 1406;
|
|
7
|
+
readonly sha256: "dddbbbdf2da0c91280267004875023ff9949c8815c6edff7057444cfcff25e61";
|
|
8
|
+
};
|
|
9
|
+
readonly compilerReceipt: {
|
|
10
|
+
readonly bytes: 1245489;
|
|
11
|
+
readonly sha256: "9d6988eff528fb577c10aa76f720e59c8737dc91c5a4a2f17496930b848ff51d";
|
|
12
|
+
readonly uncompressedBytes: 6496768;
|
|
13
|
+
readonly uncompressedSha256: "17b16598b473bcd56367f29fb76d300ffe0073c814af68710d3b46964b200202";
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare const WASM_RESCRIPT_ASSET_VERSION: "c5cfee09555006071de09a4793ff080f9c49ef901fdb66d76ca16470dab7efc5";
|
|
17
|
+
export declare const WASM_RESCRIPT_RUNNER_RECEIPT: {
|
|
18
|
+
readonly bytes: 22497;
|
|
19
|
+
readonly sha256: "9ed95127f988333a79c7591771c40f2d0fde07e5cb79da2543082582ffdd276d";
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const WASM_RESCRIPT_RUNTIME_PROFILE = {
|
|
2
|
+
profileId: 'rescript-12.3.1-playground-commonjs',
|
|
3
|
+
sourceRevision: 'v12.3.1',
|
|
4
|
+
manifestFingerprint: 'c5cfee09555006071de09a4793ff080f9c49ef901fdb66d76ca16470dab7efc5',
|
|
5
|
+
manifestReceipt: {
|
|
6
|
+
bytes: 1406,
|
|
7
|
+
sha256: 'dddbbbdf2da0c91280267004875023ff9949c8815c6edff7057444cfcff25e61'
|
|
8
|
+
},
|
|
9
|
+
compilerReceipt: {
|
|
10
|
+
bytes: 1245489,
|
|
11
|
+
sha256: '9d6988eff528fb577c10aa76f720e59c8737dc91c5a4a2f17496930b848ff51d',
|
|
12
|
+
uncompressedBytes: 6496768,
|
|
13
|
+
uncompressedSha256: '17b16598b473bcd56367f29fb76d300ffe0073c814af68710d3b46964b200202'
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export const WASM_RESCRIPT_ASSET_VERSION = WASM_RESCRIPT_RUNTIME_PROFILE.manifestFingerprint;
|
|
17
|
+
export const WASM_RESCRIPT_RUNNER_RECEIPT = {
|
|
18
|
+
bytes: 22497,
|
|
19
|
+
sha256: '9ed95127f988333a79c7591771c40f2d0fde07e5cb79da2543082582ffdd276d'
|
|
20
|
+
};
|
|
@@ -11,6 +11,7 @@ worker.onmessage = async ({ data }) => {
|
|
|
11
11
|
return;
|
|
12
12
|
started = true;
|
|
13
13
|
const output = [];
|
|
14
|
+
let runtime;
|
|
14
15
|
try {
|
|
15
16
|
if (data.request.debug || (data.request.debugMode && data.request.debugMode !== 'none')) {
|
|
16
17
|
throw new Error('Cached C/C++ execution does not support debug artifacts.');
|
|
@@ -43,7 +44,7 @@ worker.onmessage = async ({ data }) => {
|
|
|
43
44
|
}
|
|
44
45
|
// Every source cache miss gets fresh compiler memory and files. The host
|
|
45
46
|
// session keeps the immutable tool Modules and verified asset bytes alive.
|
|
46
|
-
|
|
47
|
+
runtime = new CachedRuntime({
|
|
47
48
|
runtimeBaseUrl: data.runtimeBaseUrl,
|
|
48
49
|
maxAssetBytes: data.maxAssetBytes,
|
|
49
50
|
manifest,
|
|
@@ -71,15 +72,47 @@ worker.onmessage = async ({ data }) => {
|
|
|
71
72
|
message: 'Compiling source'
|
|
72
73
|
}
|
|
73
74
|
});
|
|
74
|
-
const artifact = await runtime.compileArtifact(data.request.code,
|
|
75
|
-
|
|
75
|
+
const artifact = await runtime.compileArtifact(data.request.code, {
|
|
76
|
+
...data.request,
|
|
77
|
+
precompiledHeader: data.precompiledHeader
|
|
78
|
+
});
|
|
79
|
+
if (runtime.usedPrecompiledHeader)
|
|
80
|
+
worker.postMessage({
|
|
81
|
+
type: 'progress',
|
|
82
|
+
progress: {
|
|
83
|
+
stage: 'compile',
|
|
84
|
+
completed: 100,
|
|
85
|
+
total: 100,
|
|
86
|
+
percent: 100,
|
|
87
|
+
message: 'Compiled with precompiled <bits/stdc++.h>'
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
worker.postMessage({
|
|
91
|
+
type: 'compiled',
|
|
92
|
+
artifact,
|
|
93
|
+
stdout: output.join(''),
|
|
94
|
+
stderr: '',
|
|
95
|
+
...buildingPrecompiledHeader(runtime)
|
|
96
|
+
});
|
|
76
97
|
}
|
|
77
98
|
catch (error) {
|
|
78
99
|
worker.postMessage({
|
|
79
100
|
type: 'error',
|
|
80
101
|
error: error instanceof Error ? error.message : String(error),
|
|
81
102
|
stdout: output.join(''),
|
|
82
|
-
stderr: ''
|
|
103
|
+
stderr: '',
|
|
104
|
+
...buildingPrecompiledHeader(runtime)
|
|
83
105
|
});
|
|
84
106
|
}
|
|
107
|
+
// The program runs in another worker while this one, already holding the compiler and
|
|
108
|
+
// headers, prepares <bits/stdc++.h> for the next compile.
|
|
109
|
+
if (runtime && buildingPrecompiledHeader(runtime).precompiledHeader) {
|
|
110
|
+
const header = await runtime.buildPrecompiledHeader().catch(() => undefined);
|
|
111
|
+
worker.postMessage({ type: 'precompiled-header', header }, header ? [header.bytes.buffer] : []);
|
|
112
|
+
}
|
|
85
113
|
};
|
|
114
|
+
function buildingPrecompiledHeader(runtime) {
|
|
115
|
+
return runtime?.precompiledHeaderPlan && !runtime.usedPrecompiledHeader
|
|
116
|
+
? { precompiledHeader: 'building' }
|
|
117
|
+
: {};
|
|
118
|
+
}
|
|
@@ -8,6 +8,14 @@ import { BUNDLED_CLANG_LANGUAGE_SYSROOT_PROFILES } from '../clangAssetIntegrity'
|
|
|
8
8
|
let stdinBufferClang, debugBufferClang, watchBufferClang, watchResultBufferClang, interruptBufferClang, clang;
|
|
9
9
|
let hasInitialStdinClang = false;
|
|
10
10
|
let initialStdinClang = null;
|
|
11
|
+
// Sent once per worker by the host; the runtime mounts it only for matching compiles.
|
|
12
|
+
let precompiledHeaderClang;
|
|
13
|
+
/** Ask the host to build the header in a helper worker when this compile could have used one. */
|
|
14
|
+
function missingPrecompiledHeader() {
|
|
15
|
+
return clang?.precompiledHeaderPlan && !clang.usedPrecompiledHeader
|
|
16
|
+
? { precompiledHeaderKey: clang.precompiledHeaderPlan.key }
|
|
17
|
+
: {};
|
|
18
|
+
}
|
|
11
19
|
function postProgress(percent, stage) {
|
|
12
20
|
postMessage({ progress: { percent, stage } });
|
|
13
21
|
}
|
|
@@ -51,6 +59,8 @@ self.onmessage = async (event) => {
|
|
|
51
59
|
return;
|
|
52
60
|
const { code, buffer, debugBuffer, watchBuffer, watchResultBuffer, load, interrupt, log, path, assets, prepare, language, compileArgs, programArgs, activePath, workspaceFiles, cppVersion, cVersion, debugMode, debug, breakpoints, pauseOnEntry, stdin, maxAssetBytes } = event.data;
|
|
53
61
|
const resolvedDebugMode = debugMode || (debug ? 'trace' : 'none');
|
|
62
|
+
if (event.data.precompiledHeader)
|
|
63
|
+
precompiledHeaderClang = event.data.precompiledHeader;
|
|
54
64
|
if (load) {
|
|
55
65
|
try {
|
|
56
66
|
const runtimeAssets = assets;
|
|
@@ -62,6 +72,19 @@ self.onmessage = async (event) => {
|
|
|
62
72
|
self.postMessage({ error: error.message || 'Unable to load the C/C++ runtime.' });
|
|
63
73
|
}
|
|
64
74
|
}
|
|
75
|
+
else if (event.data.precompileHeader) {
|
|
76
|
+
const header = await clang
|
|
77
|
+
.buildPrecompiledHeaderFor(code, {
|
|
78
|
+
language,
|
|
79
|
+
compileArgs,
|
|
80
|
+
activePath,
|
|
81
|
+
cppVersion,
|
|
82
|
+
cVersion,
|
|
83
|
+
debugMode: resolvedDebugMode
|
|
84
|
+
})
|
|
85
|
+
.catch(() => undefined);
|
|
86
|
+
self.postMessage({ precompiledHeader: header ?? null }, header ? [header.bytes.buffer] : []);
|
|
87
|
+
}
|
|
65
88
|
else if (prepare) {
|
|
66
89
|
stdinBufferClang = new Int32Array(buffer);
|
|
67
90
|
debugBufferClang = new Int32Array(debugBuffer);
|
|
@@ -90,13 +113,16 @@ self.onmessage = async (event) => {
|
|
|
90
113
|
debugBuffer: debugBufferClang,
|
|
91
114
|
interruptBuffer: interruptBufferClang,
|
|
92
115
|
watchBuffer: watchBufferClang,
|
|
93
|
-
watchResultBuffer: watchResultBufferClang
|
|
116
|
+
watchResultBuffer: watchResultBufferClang,
|
|
117
|
+
precompiledHeader: precompiledHeaderClang
|
|
94
118
|
});
|
|
119
|
+
if (clang.usedPrecompiledHeader)
|
|
120
|
+
postProgress(95, 'Compiled with precompiled <bits/stdc++.h>');
|
|
95
121
|
postProgress(100, `${language === 'C' ? 'C' : 'C++'} program ready`);
|
|
96
|
-
self.postMessage({ results: true });
|
|
122
|
+
self.postMessage({ results: true, ...missingPrecompiledHeader() });
|
|
97
123
|
}
|
|
98
124
|
catch (error) {
|
|
99
|
-
self.postMessage({ error: error.message });
|
|
125
|
+
self.postMessage({ error: error.message, ...missingPrecompiledHeader() });
|
|
100
126
|
}
|
|
101
127
|
}
|
|
102
128
|
else if (code) {
|
|
@@ -122,7 +148,8 @@ self.onmessage = async (event) => {
|
|
|
122
148
|
workspaceFiles,
|
|
123
149
|
cppVersion,
|
|
124
150
|
cVersion,
|
|
125
|
-
debugMode: 'lldb'
|
|
151
|
+
debugMode: 'lldb',
|
|
152
|
+
precompiledHeader: precompiledHeaderClang
|
|
126
153
|
});
|
|
127
154
|
if (!artifact.debug) {
|
|
128
155
|
throw new Error('wasm-clang did not return an LLDB DWARF descriptor');
|
|
@@ -164,12 +191,13 @@ self.onmessage = async (event) => {
|
|
|
164
191
|
debugBuffer: debugBufferClang,
|
|
165
192
|
interruptBuffer: interruptBufferClang,
|
|
166
193
|
watchBuffer: watchBufferClang,
|
|
167
|
-
watchResultBuffer: watchResultBufferClang
|
|
194
|
+
watchResultBuffer: watchResultBufferClang,
|
|
195
|
+
precompiledHeader: precompiledHeaderClang
|
|
168
196
|
});
|
|
169
|
-
self.postMessage({ results: true });
|
|
197
|
+
self.postMessage({ results: true, ...missingPrecompiledHeader() });
|
|
170
198
|
}
|
|
171
199
|
catch (error) {
|
|
172
|
-
self.postMessage({ error: error.message });
|
|
200
|
+
self.postMessage({ error: error.message, ...missingPrecompiledHeader() });
|
|
173
201
|
}
|
|
174
202
|
}
|
|
175
203
|
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { waitForBufferedStdin } from '../stdinBuffer';
|
|
2
|
+
import { buildFennelCompileChunk, buildFennelRunChunk, loadFennelCompilerSource, parseFennelDiagnostic, stripHostLuaTraceback } from '../fennelBootstrap';
|
|
2
3
|
let stdinBufferLua = null;
|
|
3
4
|
let moduleUrl = '';
|
|
4
5
|
let loadedModuleUrl = '';
|
|
5
6
|
let runtimePromise = null;
|
|
6
7
|
let compiledArtifact = null;
|
|
7
8
|
let compiledCacheKey = '';
|
|
9
|
+
// Set when this worker hosts Fennel: the verified official fennel.lua compiler source.
|
|
10
|
+
let fennelSource = null;
|
|
11
|
+
let runtimeLabel = 'Lua';
|
|
8
12
|
async function loadRuntime(url) {
|
|
9
13
|
if (!url) {
|
|
10
14
|
throw new Error('Lua runtime is not configured. Set PUBLIC_WASM_LUA_MODULE_URL or runtimeAssets.lua.moduleUrl.');
|
|
@@ -51,8 +55,29 @@ function normalizeDiagnostic(diagnostic) {
|
|
|
51
55
|
message: String(diagnostic?.message || '')
|
|
52
56
|
};
|
|
53
57
|
}
|
|
58
|
+
async function compileFennel(runtime, fennel, code, fileName) {
|
|
59
|
+
// Run the official Fennel compiler once without stdin so syntax and compile errors are
|
|
60
|
+
// reported before execution starts.
|
|
61
|
+
const check = await runtime.executeBrowserLuaArtifact({ source: buildFennelCompileChunk(fennel, code, fileName), fileName }, { stdin: () => null });
|
|
62
|
+
if (check.exitCode !== 0) {
|
|
63
|
+
const message = stripHostLuaTraceback(check.stderr);
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
diagnostics: [parseFennelDiagnostic(message, fileName)],
|
|
67
|
+
stdout: '',
|
|
68
|
+
stderr: message
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
artifact: { source: buildFennelRunChunk(fennel, code, fileName), fileName },
|
|
74
|
+
diagnostics: [],
|
|
75
|
+
stdout: '',
|
|
76
|
+
stderr: ''
|
|
77
|
+
};
|
|
78
|
+
}
|
|
54
79
|
self.onmessage = async (event) => {
|
|
55
|
-
const { load, moduleUrl: nextModuleUrl, buffer, code, prepare, args = [], stdin, activePath = 'main.lua', workspaceFiles = [], log } = event.data;
|
|
80
|
+
const { load, moduleUrl: nextModuleUrl, fennelCompiler, buffer, code, prepare, args = [], stdin, activePath = 'main.lua', workspaceFiles = [], log } = event.data;
|
|
56
81
|
try {
|
|
57
82
|
if (load) {
|
|
58
83
|
moduleUrl = nextModuleUrl;
|
|
@@ -60,6 +85,12 @@ self.onmessage = async (event) => {
|
|
|
60
85
|
console.log(`[wasm-idle:lua-worker] load moduleUrl=${moduleUrl}`);
|
|
61
86
|
}
|
|
62
87
|
await loadRuntime(moduleUrl);
|
|
88
|
+
if (fennelCompiler) {
|
|
89
|
+
fennelSource = await loadFennelCompilerSource(fennelCompiler);
|
|
90
|
+
runtimeLabel = 'Fennel';
|
|
91
|
+
compiledArtifact = null;
|
|
92
|
+
compiledCacheKey = '';
|
|
93
|
+
}
|
|
63
94
|
postMessage({ load: true });
|
|
64
95
|
return;
|
|
65
96
|
}
|
|
@@ -74,11 +105,13 @@ self.onmessage = async (event) => {
|
|
|
74
105
|
if (log) {
|
|
75
106
|
console.log(`[wasm-idle:lua-worker] compile start prepare=${String(prepare)} bytes=${code.length}`);
|
|
76
107
|
}
|
|
77
|
-
const result =
|
|
78
|
-
code,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
108
|
+
const result = fennelSource
|
|
109
|
+
? await compileFennel(runtime, fennelSource, code, activePath)
|
|
110
|
+
: await runtime.compiler.compile({
|
|
111
|
+
code,
|
|
112
|
+
fileName: activePath,
|
|
113
|
+
log
|
|
114
|
+
});
|
|
82
115
|
if (log) {
|
|
83
116
|
console.log(`[wasm-idle:lua-worker] compile settled success=${String(result.success)} stdout=${String(Boolean(result.stdout))} stderr=${String(Boolean(result.stderr))}`);
|
|
84
117
|
}
|
|
@@ -92,7 +125,7 @@ self.onmessage = async (event) => {
|
|
|
92
125
|
result.diagnostics
|
|
93
126
|
?.map((diagnostic) => diagnostic.message)
|
|
94
127
|
.join('\n') ||
|
|
95
|
-
|
|
128
|
+
`${runtimeLabel} compilation failed`);
|
|
96
129
|
}
|
|
97
130
|
if (result.stderr)
|
|
98
131
|
postMessage({ output: result.stderr });
|
|
@@ -143,14 +176,18 @@ self.onmessage = async (event) => {
|
|
|
143
176
|
postMessage({ output });
|
|
144
177
|
},
|
|
145
178
|
stderr: (output) => {
|
|
146
|
-
|
|
179
|
+
// Fennel errors are reported once, without the host Lua traceback, below.
|
|
180
|
+
if (output && !fennelSource)
|
|
147
181
|
postMessage({ output });
|
|
148
182
|
}
|
|
149
183
|
});
|
|
150
184
|
if (execution.exitCode !== 0) {
|
|
151
|
-
|
|
152
|
-
?
|
|
153
|
-
:
|
|
185
|
+
const stderr = fennelSource
|
|
186
|
+
? stripHostLuaTraceback(execution.stderr)
|
|
187
|
+
: execution.stderr;
|
|
188
|
+
throw new Error(stderr
|
|
189
|
+
? `${runtimeLabel} program exited with code ${execution.exitCode}\n${stderr}`
|
|
190
|
+
: `${runtimeLabel} program exited with code ${execution.exitCode}`);
|
|
154
191
|
}
|
|
155
192
|
postMessage({ results: true });
|
|
156
193
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { importRuntimeModule } from '../runtimeModule';
|
|
2
|
+
const encoder = new TextEncoder();
|
|
3
|
+
const decoder = new TextDecoder();
|
|
4
|
+
let runtimeModuleUrl = '';
|
|
5
|
+
let runtimePromise = null;
|
|
6
|
+
async function fetchBytes(url) {
|
|
7
|
+
const response = await fetch(url);
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error(`PostgreSQL runtime asset request failed (${response.status}): ${url}`);
|
|
10
|
+
}
|
|
11
|
+
return await response.arrayBuffer();
|
|
12
|
+
}
|
|
13
|
+
async function loadPostgresql(moduleUrl) {
|
|
14
|
+
if (!moduleUrl)
|
|
15
|
+
throw new Error('PostgreSQL runtime module URL is not configured.');
|
|
16
|
+
if (runtimeModuleUrl !== moduleUrl) {
|
|
17
|
+
runtimeModuleUrl = moduleUrl;
|
|
18
|
+
runtimePromise = null;
|
|
19
|
+
}
|
|
20
|
+
if (runtimePromise)
|
|
21
|
+
return await runtimePromise;
|
|
22
|
+
const pending = (async () => {
|
|
23
|
+
const runtime = await importRuntimeModule(moduleUrl);
|
|
24
|
+
const [PGlite, pgliteWasmModule, initdbWasmModule, fsBundle] = await Promise.all([
|
|
25
|
+
runtime.loadPGlite(),
|
|
26
|
+
fetchBytes(runtime.pgliteWasmUrl).then((bytes) => WebAssembly.compile(bytes)),
|
|
27
|
+
fetchBytes(runtime.pgliteInitdbWasmUrl).then((bytes) => WebAssembly.compile(bytes)),
|
|
28
|
+
fetchBytes(runtime.pgliteDataUrl).then((bytes) => new Blob([bytes]))
|
|
29
|
+
]);
|
|
30
|
+
const options = { pgliteWasmModule, initdbWasmModule, fsBundle };
|
|
31
|
+
const template = await PGlite.create(options);
|
|
32
|
+
try {
|
|
33
|
+
const snapshot = await template.dumpDataDir('none');
|
|
34
|
+
return { PGlite, options, snapshot };
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await template.close().catch(() => { });
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
runtimePromise = pending;
|
|
41
|
+
pending.catch(() => {
|
|
42
|
+
if (runtimePromise === pending)
|
|
43
|
+
runtimePromise = null;
|
|
44
|
+
});
|
|
45
|
+
return await pending;
|
|
46
|
+
}
|
|
47
|
+
function normalizeWorkspacePath(path) {
|
|
48
|
+
return path
|
|
49
|
+
.replace(/^\/+/, '')
|
|
50
|
+
.split('/')
|
|
51
|
+
.filter((part) => part && part !== '.' && part !== '..' && !part.includes('\0'))
|
|
52
|
+
.join('/');
|
|
53
|
+
}
|
|
54
|
+
function collectSetupSql(activePath, workspaceFiles) {
|
|
55
|
+
const setupSql = [];
|
|
56
|
+
for (const file of workspaceFiles) {
|
|
57
|
+
if (!file || typeof file.path !== 'string' || typeof file.content !== 'string')
|
|
58
|
+
continue;
|
|
59
|
+
const normalizedPath = normalizeWorkspacePath(file.path);
|
|
60
|
+
if (!normalizedPath || normalizedPath === activePath)
|
|
61
|
+
continue;
|
|
62
|
+
if (!normalizedPath.toLowerCase().endsWith('.sql'))
|
|
63
|
+
continue;
|
|
64
|
+
setupSql.push({ path: normalizedPath, content: file.content });
|
|
65
|
+
}
|
|
66
|
+
return setupSql.sort((left, right) => left.path.localeCompare(right.path));
|
|
67
|
+
}
|
|
68
|
+
/** Frame one simple-query protocol message; the server runs the script exactly as written. */
|
|
69
|
+
function simpleQueryMessage(sql) {
|
|
70
|
+
const text = encoder.encode(sql);
|
|
71
|
+
const message = new Uint8Array(text.byteLength + 6);
|
|
72
|
+
message[0] = 0x51; // 'Q'
|
|
73
|
+
new DataView(message.buffer).setInt32(1, text.byteLength + 5);
|
|
74
|
+
message.set(text, 5);
|
|
75
|
+
return message;
|
|
76
|
+
}
|
|
77
|
+
function stringifyCell(value) {
|
|
78
|
+
if (value == null)
|
|
79
|
+
return 'NULL';
|
|
80
|
+
return String(value);
|
|
81
|
+
}
|
|
82
|
+
function lineAndColumn(source, position) {
|
|
83
|
+
// The server reports a 1-based character (code point) offset into the query text.
|
|
84
|
+
const before = Array.from(source)
|
|
85
|
+
.slice(0, position - 1)
|
|
86
|
+
.join('');
|
|
87
|
+
const lines = before.split('\n');
|
|
88
|
+
return { lineNumber: lines.length, columnNumber: lines[lines.length - 1].length + 1 };
|
|
89
|
+
}
|
|
90
|
+
function formatServerMessage(message) {
|
|
91
|
+
const lines = [`${message.severity || 'ERROR'}: ${message.message || ''}`];
|
|
92
|
+
if (message.detail)
|
|
93
|
+
lines.push(`DETAIL: ${message.detail}`);
|
|
94
|
+
if (message.hint)
|
|
95
|
+
lines.push(`HINT: ${message.hint}`);
|
|
96
|
+
return lines.join('\n');
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Converts the backend's protocol replies into terminal text in server order. Rows use the
|
|
100
|
+
* server's own text representation, matching the tab-separated SQLite/DuckDB output.
|
|
101
|
+
*/
|
|
102
|
+
function renderMessages(messages) {
|
|
103
|
+
const chunks = [];
|
|
104
|
+
let error = null;
|
|
105
|
+
for (const message of messages) {
|
|
106
|
+
switch (message.name) {
|
|
107
|
+
case 'rowDescription':
|
|
108
|
+
chunks.push(`${(message.fields || []).map((field) => field.name).join('\t')}\n`);
|
|
109
|
+
break;
|
|
110
|
+
case 'dataRow':
|
|
111
|
+
chunks.push(`${(message.fields || []).map(stringifyCell).join('\t')}\n`);
|
|
112
|
+
break;
|
|
113
|
+
case 'copyData':
|
|
114
|
+
if (message.chunk)
|
|
115
|
+
chunks.push(decoder.decode(message.chunk));
|
|
116
|
+
break;
|
|
117
|
+
case 'notice':
|
|
118
|
+
chunks.push(`${formatServerMessage(message)}\n`);
|
|
119
|
+
break;
|
|
120
|
+
case 'error':
|
|
121
|
+
error = message;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return { output: chunks.join(''), error };
|
|
126
|
+
}
|
|
127
|
+
self.onmessage = async (event) => {
|
|
128
|
+
const { load, moduleUrl: nextModuleUrl, code, prepare, activePath = 'main.sql', workspaceFiles = [], stdin, log } = event.data;
|
|
129
|
+
try {
|
|
130
|
+
if (load) {
|
|
131
|
+
if (log)
|
|
132
|
+
console.log('[wasm-idle:postgresql-worker] load');
|
|
133
|
+
await loadPostgresql(nextModuleUrl || runtimeModuleUrl);
|
|
134
|
+
postMessage({ load: true });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const runtime = await loadPostgresql(runtimeModuleUrl);
|
|
138
|
+
if (prepare) {
|
|
139
|
+
postMessage({ results: true });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const db = await runtime.PGlite.create({
|
|
143
|
+
...runtime.options,
|
|
144
|
+
loadDataDir: runtime.snapshot
|
|
145
|
+
});
|
|
146
|
+
try {
|
|
147
|
+
const normalizedActivePath = normalizeWorkspacePath(activePath || 'main.sql');
|
|
148
|
+
for (const setup of collectSetupSql(normalizedActivePath, workspaceFiles)) {
|
|
149
|
+
await db.exec(setup.content);
|
|
150
|
+
}
|
|
151
|
+
// PGlite exposes caller-provided bytes as the server-side file /dev/blob, so
|
|
152
|
+
// `COPY ... FROM '/dev/blob'` and `pg_read_file('/dev/blob')` read program stdin.
|
|
153
|
+
await db._handleBlob(new Blob([typeof stdin === 'string' ? stdin : '']));
|
|
154
|
+
postMessage({
|
|
155
|
+
progress: {
|
|
156
|
+
kind: 'ready',
|
|
157
|
+
state: 'running',
|
|
158
|
+
reason: 'started',
|
|
159
|
+
label: 'PostgreSQL query started'
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
if (log) {
|
|
163
|
+
console.log(`[wasm-idle:postgresql-worker] exec start bytes=${code.length} activePath=${normalizedActivePath}`);
|
|
164
|
+
}
|
|
165
|
+
let rendered;
|
|
166
|
+
try {
|
|
167
|
+
const result = await db.execProtocol(simpleQueryMessage(code), {
|
|
168
|
+
throwOnError: false
|
|
169
|
+
});
|
|
170
|
+
rendered = renderMessages(result.messages);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
await db._cleanupBlob().catch(() => { });
|
|
174
|
+
}
|
|
175
|
+
if (rendered.output)
|
|
176
|
+
postMessage({ output: rendered.output });
|
|
177
|
+
if (rendered.error) {
|
|
178
|
+
const position = Number(rendered.error.position);
|
|
179
|
+
if (Number.isSafeInteger(position) && position > 0) {
|
|
180
|
+
postMessage({
|
|
181
|
+
diagnostic: {
|
|
182
|
+
fileName: normalizedActivePath,
|
|
183
|
+
...lineAndColumn(code, position),
|
|
184
|
+
severity: 'error',
|
|
185
|
+
message: rendered.error.message || 'PostgreSQL error'
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
postMessage({ error: formatServerMessage(rendered.error) });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (log)
|
|
193
|
+
console.log('[wasm-idle:postgresql-worker] exec settled');
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
await db.close().catch(() => { });
|
|
197
|
+
}
|
|
198
|
+
postMessage({ results: true });
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
if (log)
|
|
202
|
+
console.error('[wasm-idle:postgresql-worker] failed', error);
|
|
203
|
+
postMessage({ error: error?.message || String(error) });
|
|
204
|
+
}
|
|
205
|
+
};
|