wasm-idle 0.6.0 → 0.7.0
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 +85 -11
- package/dist/playground/assets.d.ts +43 -0
- package/dist/playground/assets.js +164 -0
- package/dist/playground/elixir.d.ts +32 -0
- package/dist/playground/elixir.js +173 -0
- package/dist/playground/go.d.ts +31 -0
- package/dist/playground/go.js +166 -0
- package/dist/playground/index.js +36 -1
- package/dist/playground/ocaml.d.ts +32 -0
- package/dist/playground/ocaml.js +341 -0
- package/dist/playground/options.d.ts +4 -0
- package/dist/playground/tinygo.d.ts +75 -0
- package/dist/playground/tinygo.js +510 -0
- package/dist/playground/wasmElixirVersion.d.ts +1 -0
- package/dist/playground/wasmElixirVersion.js +1 -0
- package/dist/playground/wasmGoVersion.d.ts +1 -0
- package/dist/playground/wasmGoVersion.js +1 -0
- package/dist/playground/wasmOcamlVersion.d.ts +1 -0
- package/dist/playground/wasmOcamlVersion.js +1 -0
- package/dist/playground/wasmRustVersion.d.ts +1 -1
- package/dist/playground/wasmRustVersion.js +1 -1
- package/dist/playground/wasmTinyGoVersion.d.ts +1 -0
- package/dist/playground/wasmTinyGoVersion.js +1 -0
- package/dist/playground/worker/elixir.d.ts +1 -0
- package/dist/playground/worker/elixir.js +317 -0
- package/dist/playground/worker/go.d.ts +1 -0
- package/dist/playground/worker/go.js +163 -0
- package/dist/playground/worker/ocaml.d.ts +1 -0
- package/dist/playground/worker/ocaml.js +449 -0
- package/dist/playground/worker/tinygo.d.ts +1 -0
- package/dist/playground/worker/tinygo.js +137 -0
- package/dist/terminal/Terminal.svelte +69 -29
- package/package.json +35 -22
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import atomVmWasmUrl from '../../../../node_modules/@swmansion/popcorn/dist/AtomVM.wasm?url';
|
|
2
|
+
import initAtomVm from '../../../../node_modules/@swmansion/popcorn/dist/AtomVM.mjs';
|
|
3
|
+
import { waitForBufferedStdin } from '../stdinBuffer';
|
|
4
|
+
const workerDocument = {
|
|
5
|
+
querySelectorAll() {
|
|
6
|
+
return [];
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
const workerHost = {
|
|
10
|
+
document: workerDocument,
|
|
11
|
+
postMessage(message) {
|
|
12
|
+
postMessage(message);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const popcornBrowserGlobal = ['globalThis', 'window'].join('.');
|
|
16
|
+
const popcornParentGlobal = [popcornBrowserGlobal, 'parent'].join('.');
|
|
17
|
+
const workerHostGlobal = 'globalThis.__wasmIdleElixirWorkerHost';
|
|
18
|
+
self.document = workerDocument;
|
|
19
|
+
globalThis.__wasmIdleElixirWorkerHost = workerHost;
|
|
20
|
+
class TrackedValue {
|
|
21
|
+
key;
|
|
22
|
+
value;
|
|
23
|
+
constructor({ key, value }) {
|
|
24
|
+
if (typeof key !== 'number') {
|
|
25
|
+
throw new Error('key property in TrackedValue must be a number');
|
|
26
|
+
}
|
|
27
|
+
this.key = key;
|
|
28
|
+
this.value = value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
globalThis.TrackedValue = TrackedValue;
|
|
32
|
+
let bundleUrl = '';
|
|
33
|
+
let loadedBundleUrl = '';
|
|
34
|
+
let runtimePromise = null;
|
|
35
|
+
let stdinBufferElixir = null;
|
|
36
|
+
function deserialize(module, message) {
|
|
37
|
+
return JSON.parse(message, (_key, value) => {
|
|
38
|
+
const isRef = typeof value === 'object' &&
|
|
39
|
+
value !== null &&
|
|
40
|
+
Object.hasOwn(value, 'popcorn_ref') &&
|
|
41
|
+
Object.getOwnPropertyNames(value).length === 1;
|
|
42
|
+
if (!isRef) {
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
return module.trackedObjectsMap.get(value.popcorn_ref);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function ensureFunctionEval(maybeFunction) {
|
|
49
|
+
if (typeof maybeFunction !== 'function') {
|
|
50
|
+
throw new Error('Script passed to onRunTrackedJs() is not wrapped in a function');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function ensureResultKeyList(result) {
|
|
54
|
+
if (!Array.isArray(result) && result !== undefined) {
|
|
55
|
+
throw new Error('Script passed to onRunTrackedJs() returned invalid value, accepted values are arrays and undefined');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function configureTrackedObjectBridge(module, resolveReadyProcess) {
|
|
59
|
+
let appReadyProcess;
|
|
60
|
+
let elixirReady = false;
|
|
61
|
+
module.serialize = JSON.stringify;
|
|
62
|
+
module.deserialize = (message) => deserialize(module, message);
|
|
63
|
+
module.cleanupFunctions = new Map();
|
|
64
|
+
module.sendEvent = (eventName, payload) => {
|
|
65
|
+
if (eventName === 'popcorn_app_ready') {
|
|
66
|
+
const readyPayload = typeof payload === 'object' && payload !== null && Object.hasOwn(payload, 'name')
|
|
67
|
+
? payload.name
|
|
68
|
+
: payload;
|
|
69
|
+
appReadyProcess =
|
|
70
|
+
readyPayload === null || readyPayload === undefined ? null : String(readyPayload);
|
|
71
|
+
if (elixirReady) {
|
|
72
|
+
resolveReadyProcess(appReadyProcess);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (eventName === 'popcorn_elixir_ready') {
|
|
77
|
+
elixirReady = true;
|
|
78
|
+
if (appReadyProcess !== undefined) {
|
|
79
|
+
resolveReadyProcess(appReadyProcess);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
module.onElixirReady = (process) => {
|
|
84
|
+
module.onElixirReady = null;
|
|
85
|
+
resolveReadyProcess(process);
|
|
86
|
+
};
|
|
87
|
+
module.onTrackedObjectDelete = (key) => {
|
|
88
|
+
const cleanup = module.cleanupFunctions.get(key);
|
|
89
|
+
module.cleanupFunctions.delete(key);
|
|
90
|
+
try {
|
|
91
|
+
cleanup?.();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error(error);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
module.trackedObjectsMap.delete(key);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
module.onRunTrackedJs = (scriptString, isDebug) => {
|
|
101
|
+
const trackValue = (tracked) => {
|
|
102
|
+
if (tracked instanceof TrackedValue) {
|
|
103
|
+
module.trackedObjectsMap.set(tracked.key, tracked.value);
|
|
104
|
+
return tracked.key;
|
|
105
|
+
}
|
|
106
|
+
const key = module.nextTrackedObjectKey();
|
|
107
|
+
module.trackedObjectsMap.set(key, tracked);
|
|
108
|
+
return key;
|
|
109
|
+
};
|
|
110
|
+
let fn;
|
|
111
|
+
try {
|
|
112
|
+
const indirectEval = globalThis.eval;
|
|
113
|
+
const workerScript = scriptString
|
|
114
|
+
.replaceAll(`${popcornParentGlobal}.document`, `${workerHostGlobal}.document`)
|
|
115
|
+
.replaceAll(popcornParentGlobal, workerHostGlobal)
|
|
116
|
+
.replaceAll(popcornBrowserGlobal, workerHostGlobal);
|
|
117
|
+
fn = indirectEval(workerScript);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.error(error);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
if (isDebug) {
|
|
124
|
+
ensureFunctionEval(fn);
|
|
125
|
+
}
|
|
126
|
+
let result;
|
|
127
|
+
try {
|
|
128
|
+
result = fn?.(module);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error(error);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
if (isDebug) {
|
|
135
|
+
ensureResultKeyList(result);
|
|
136
|
+
}
|
|
137
|
+
return result?.map(trackValue) ?? [];
|
|
138
|
+
};
|
|
139
|
+
module.onGetTrackedObjects = (keys) => keys.map((key) => module.serialize(module.trackedObjectsMap.get(key)));
|
|
140
|
+
}
|
|
141
|
+
function configureMessagingBridge(module) {
|
|
142
|
+
const originalCast = module.cast.bind(module);
|
|
143
|
+
const originalCall = module.call.bind(module);
|
|
144
|
+
module.cast = (process, args) => {
|
|
145
|
+
originalCast(process, module.serialize(args));
|
|
146
|
+
};
|
|
147
|
+
module.call = (process, args) => originalCall(process, module.serialize(args));
|
|
148
|
+
}
|
|
149
|
+
async function startVm(avmBundle, log) {
|
|
150
|
+
let resolveProcess = null;
|
|
151
|
+
const processPromise = new Promise((resolve, reject) => {
|
|
152
|
+
const timeout = setTimeout(() => {
|
|
153
|
+
resolveProcess = null;
|
|
154
|
+
reject(new Error('Elixir runtime did not become ready'));
|
|
155
|
+
}, 30_000);
|
|
156
|
+
resolveProcess = (process) => {
|
|
157
|
+
clearTimeout(timeout);
|
|
158
|
+
resolveProcess = null;
|
|
159
|
+
resolve(process);
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
const module = (await initAtomVm({
|
|
163
|
+
locateFile(path) {
|
|
164
|
+
if (path === 'AtomVM.wasm') {
|
|
165
|
+
return atomVmWasmUrl;
|
|
166
|
+
}
|
|
167
|
+
return path;
|
|
168
|
+
},
|
|
169
|
+
preRun: [
|
|
170
|
+
({ FS }) => {
|
|
171
|
+
FS.mkdir('/data');
|
|
172
|
+
FS.writeFile('/data/bundle.avm', avmBundle);
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
arguments: ['/data/bundle.avm'],
|
|
176
|
+
print(text) {
|
|
177
|
+
postMessage({ output: text });
|
|
178
|
+
},
|
|
179
|
+
printErr(text) {
|
|
180
|
+
postMessage({ output: text });
|
|
181
|
+
},
|
|
182
|
+
onAbort() {
|
|
183
|
+
if (log) {
|
|
184
|
+
console.error('[wasm-idle:elixir-worker] AtomVM aborted');
|
|
185
|
+
}
|
|
186
|
+
setTimeout(() => postMessage({ error: 'Elixir runtime aborted' }), 100);
|
|
187
|
+
}
|
|
188
|
+
}));
|
|
189
|
+
configureTrackedObjectBridge(module, (process) => resolveProcess?.(process));
|
|
190
|
+
configureMessagingBridge(module);
|
|
191
|
+
return {
|
|
192
|
+
module,
|
|
193
|
+
process: await processPromise
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
async function loadRuntime(nextBundleUrl, log) {
|
|
197
|
+
if (!nextBundleUrl) {
|
|
198
|
+
throw new Error('Elixir runtime is not configured. Set PUBLIC_WASM_ELIXIR_BUNDLE_URL or runtimeAssets.elixir.bundleUrl.');
|
|
199
|
+
}
|
|
200
|
+
if (loadedBundleUrl === nextBundleUrl && runtimePromise) {
|
|
201
|
+
return await runtimePromise;
|
|
202
|
+
}
|
|
203
|
+
loadedBundleUrl = nextBundleUrl;
|
|
204
|
+
runtimePromise = (async () => {
|
|
205
|
+
if (log) {
|
|
206
|
+
console.log(`[wasm-idle:elixir-worker] load bundleUrl=${nextBundleUrl}`);
|
|
207
|
+
}
|
|
208
|
+
const bundleBuffer = await fetch(nextBundleUrl).then((response) => {
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new Error(`Failed to fetch Elixir bundle: ${response.status} ${response.statusText}`);
|
|
211
|
+
}
|
|
212
|
+
return response.arrayBuffer();
|
|
213
|
+
});
|
|
214
|
+
return await startVm(new Int8Array(bundleBuffer), log);
|
|
215
|
+
})();
|
|
216
|
+
return await runtimePromise;
|
|
217
|
+
}
|
|
218
|
+
function normalizeCallError(module, error) {
|
|
219
|
+
if (error === 'noproc') {
|
|
220
|
+
runtimePromise = null;
|
|
221
|
+
loadedBundleUrl = '';
|
|
222
|
+
return 'Elixir runtime process is unavailable';
|
|
223
|
+
}
|
|
224
|
+
if (typeof error === 'string') {
|
|
225
|
+
try {
|
|
226
|
+
const value = module.deserialize(error);
|
|
227
|
+
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (error instanceof Error) {
|
|
234
|
+
return error.message;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
return JSON.stringify(error);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return String(error);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
self.onmessage = async (event) => {
|
|
244
|
+
const { load, bundleUrl: nextBundleUrl, buffer, code, prepare, log = true } = event.data;
|
|
245
|
+
try {
|
|
246
|
+
if (load) {
|
|
247
|
+
bundleUrl = nextBundleUrl;
|
|
248
|
+
await loadRuntime(bundleUrl, log);
|
|
249
|
+
postMessage({ load: true });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (!bundleUrl) {
|
|
253
|
+
throw new Error('Elixir runtime not loaded');
|
|
254
|
+
}
|
|
255
|
+
stdinBufferElixir = buffer ? new Int32Array(buffer) : null;
|
|
256
|
+
if (prepare) {
|
|
257
|
+
postMessage({ results: true });
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const runtime = await loadRuntime(bundleUrl, log);
|
|
261
|
+
if (!runtime.process) {
|
|
262
|
+
throw new Error('Elixir runtime did not expose a default process');
|
|
263
|
+
}
|
|
264
|
+
if (log) {
|
|
265
|
+
console.log(`[wasm-idle:elixir-worker] eval bytes=${code.length}`);
|
|
266
|
+
}
|
|
267
|
+
let evalCode = code;
|
|
268
|
+
if (stdinBufferElixir && /\bIO\.(?:gets|read)\s*\(/.test(code)) {
|
|
269
|
+
const chunk = waitForBufferedStdin(stdinBufferElixir, () => postMessage({ buffer: true }));
|
|
270
|
+
const stdinLines = chunk == null ? [] : chunk.match(/[^\n]*\n|[^\n]+$/g) || [];
|
|
271
|
+
let stdinLineOffset = 0;
|
|
272
|
+
evalCode = code
|
|
273
|
+
.replace(/\bIO\.gets\s*\([^)]*\)/g, () => {
|
|
274
|
+
const line = stdinLines[stdinLineOffset++];
|
|
275
|
+
return line === undefined ? 'nil' : JSON.stringify(line);
|
|
276
|
+
})
|
|
277
|
+
.replace(/\bIO\.read\s*\(\s*(?::stdio\s*,\s*)?:line\s*\)/g, () => {
|
|
278
|
+
const line = stdinLines[stdinLineOffset++];
|
|
279
|
+
return line === undefined ? 'nil' : JSON.stringify(line);
|
|
280
|
+
})
|
|
281
|
+
.replace(/\bIO\.read\s*\(\s*(?::stdio\s*,\s*)?:all\s*\)/g, () => {
|
|
282
|
+
const remainingInput = stdinLines.slice(stdinLineOffset).join('');
|
|
283
|
+
stdinLineOffset = stdinLines.length;
|
|
284
|
+
return JSON.stringify(remainingInput);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
const response = await runtime.module.call(runtime.process, ['eval_elixir', evalCode]);
|
|
288
|
+
const rendered = runtime.module.deserialize(response);
|
|
289
|
+
if (typeof rendered === 'string') {
|
|
290
|
+
postMessage({ results: rendered });
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (rendered === undefined) {
|
|
294
|
+
postMessage({ results: true });
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
postMessage({ results: JSON.stringify(rendered) });
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
if (log) {
|
|
301
|
+
console.error('[wasm-idle:elixir-worker] failed', error);
|
|
302
|
+
}
|
|
303
|
+
if (runtimePromise) {
|
|
304
|
+
try {
|
|
305
|
+
const runtime = await runtimePromise;
|
|
306
|
+
postMessage({ error: normalizeCallError(runtime.module, error) });
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// Ignore secondary runtime load errors and surface the original failure instead.
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
postMessage({
|
|
314
|
+
error: error instanceof Error ? error.message : String(error)
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { waitForBufferedStdin } from '../stdinBuffer';
|
|
2
|
+
self.document = {
|
|
3
|
+
querySelectorAll() {
|
|
4
|
+
return [];
|
|
5
|
+
}
|
|
6
|
+
};
|
|
7
|
+
let stdinBufferGo = null;
|
|
8
|
+
let compilerUrl = '';
|
|
9
|
+
let loadedCompilerUrl = '';
|
|
10
|
+
let compilerPromise = null;
|
|
11
|
+
let compiledArtifact = null;
|
|
12
|
+
let compiledCacheKey = '';
|
|
13
|
+
async function loadCompiler(url) {
|
|
14
|
+
if (!url) {
|
|
15
|
+
throw new Error('Go runtime is not configured. Set PUBLIC_WASM_GO_COMPILER_URL or runtimeAssets.go.compilerUrl.');
|
|
16
|
+
}
|
|
17
|
+
if (loadedCompilerUrl === url && compilerPromise) {
|
|
18
|
+
return await compilerPromise;
|
|
19
|
+
}
|
|
20
|
+
loadedCompilerUrl = url;
|
|
21
|
+
compiledArtifact = null;
|
|
22
|
+
compiledCacheKey = '';
|
|
23
|
+
compilerPromise = (async () => {
|
|
24
|
+
const module = await import(/* @vite-ignore */ url);
|
|
25
|
+
const factory = typeof module.createGoCompiler === 'function'
|
|
26
|
+
? module.createGoCompiler
|
|
27
|
+
: typeof module.default === 'function'
|
|
28
|
+
? module.default
|
|
29
|
+
: null;
|
|
30
|
+
if (!factory) {
|
|
31
|
+
throw new Error('wasm-go module must export createGoCompiler or a default factory');
|
|
32
|
+
}
|
|
33
|
+
if (typeof module.executeBrowserGoArtifact !== 'function') {
|
|
34
|
+
throw new Error('wasm-go module must export executeBrowserGoArtifact');
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
compiler: await factory(),
|
|
38
|
+
executeBrowserGoArtifact: module.executeBrowserGoArtifact
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
return await compilerPromise;
|
|
42
|
+
}
|
|
43
|
+
function normalizeDiagnostic(diagnostic) {
|
|
44
|
+
return {
|
|
45
|
+
fileName: diagnostic?.fileName ?? null,
|
|
46
|
+
lineNumber: Math.max(1, Number(diagnostic?.lineNumber || 1)),
|
|
47
|
+
columnNumber: typeof diagnostic?.columnNumber === 'number'
|
|
48
|
+
? Math.max(1, diagnostic.columnNumber)
|
|
49
|
+
: undefined,
|
|
50
|
+
severity: diagnostic?.severity === 'warning' || diagnostic?.severity === 'other'
|
|
51
|
+
? diagnostic.severity
|
|
52
|
+
: 'error',
|
|
53
|
+
message: String(diagnostic?.message || '')
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
self.onmessage = async (event) => {
|
|
57
|
+
const { load, compilerUrl: nextCompilerUrl, buffer, code, prepare, args = [], target = 'wasip1/wasm', log } = event.data;
|
|
58
|
+
try {
|
|
59
|
+
if (load) {
|
|
60
|
+
compilerUrl = nextCompilerUrl;
|
|
61
|
+
if (log) {
|
|
62
|
+
console.log(`[wasm-idle:go-worker] load compilerUrl=${compilerUrl}`);
|
|
63
|
+
}
|
|
64
|
+
await loadCompiler(compilerUrl);
|
|
65
|
+
postMessage({ load: true });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
stdinBufferGo = new Int32Array(buffer);
|
|
69
|
+
const runtime = await loadCompiler(compilerUrl);
|
|
70
|
+
const compileCacheKey = `${target}\n${code}`;
|
|
71
|
+
if (!compiledArtifact || compiledCacheKey !== compileCacheKey) {
|
|
72
|
+
if (log) {
|
|
73
|
+
console.log(`[wasm-idle:go-worker] compile start prepare=${String(prepare)} target=${target} bytes=${code.length}`);
|
|
74
|
+
}
|
|
75
|
+
const result = await runtime.compiler.compile({
|
|
76
|
+
code,
|
|
77
|
+
target,
|
|
78
|
+
prepare,
|
|
79
|
+
log,
|
|
80
|
+
onProgress(progress) {
|
|
81
|
+
postMessage({ progress });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
if (log) {
|
|
85
|
+
console.log(`[wasm-idle:go-worker] compile settled success=${String(result.success)} hasWasm=${String(Boolean(result.artifact?.wasm))} stdout=${String(Boolean(result.stdout))} stderr=${String(Boolean(result.stderr))}`);
|
|
86
|
+
}
|
|
87
|
+
for (const diagnostic of result.diagnostics || []) {
|
|
88
|
+
postMessage({ diagnostic: normalizeDiagnostic(diagnostic) });
|
|
89
|
+
}
|
|
90
|
+
if (result.stdout)
|
|
91
|
+
postMessage({ output: result.stdout });
|
|
92
|
+
if (!result.success) {
|
|
93
|
+
throw new Error(result.stderr ||
|
|
94
|
+
result.diagnostics?.map((diagnostic) => diagnostic.message).join('\n') ||
|
|
95
|
+
'Go compilation failed');
|
|
96
|
+
}
|
|
97
|
+
if (result.stderr)
|
|
98
|
+
postMessage({ output: result.stderr });
|
|
99
|
+
if (!result.artifact?.wasm) {
|
|
100
|
+
throw new Error('wasm-go did not return a wasm artifact');
|
|
101
|
+
}
|
|
102
|
+
compiledArtifact = result.artifact;
|
|
103
|
+
compiledCacheKey = compileCacheKey;
|
|
104
|
+
if (log) {
|
|
105
|
+
console.log(`[wasm-idle:go-worker] cached artifact target=${compiledArtifact.target} format=${compiledArtifact.format}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (prepare) {
|
|
109
|
+
if (log) {
|
|
110
|
+
console.log('[wasm-idle:go-worker] prepare complete');
|
|
111
|
+
}
|
|
112
|
+
postMessage({ results: true });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (log) {
|
|
116
|
+
console.log(`[wasm-idle:go-worker] runtime start target=${compiledArtifact.target} format=${compiledArtifact.format}`);
|
|
117
|
+
}
|
|
118
|
+
const execution = await runtime.executeBrowserGoArtifact(compiledArtifact, {
|
|
119
|
+
args,
|
|
120
|
+
env: {
|
|
121
|
+
USER: 'jungol'
|
|
122
|
+
},
|
|
123
|
+
stdin: () => {
|
|
124
|
+
const chunk = waitForBufferedStdin(stdinBufferGo, () => postMessage({ buffer: true }));
|
|
125
|
+
if (chunk == null) {
|
|
126
|
+
if (log) {
|
|
127
|
+
console.log('[wasm-idle:go-stdin] fd_read(bytes=0, eof=true)');
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
if (log) {
|
|
132
|
+
console.log(`[wasm-idle:go-stdin] fd_fill(bytes=${new TextEncoder().encode(chunk).byteLength}, text=${JSON.stringify(chunk)})`);
|
|
133
|
+
}
|
|
134
|
+
return chunk;
|
|
135
|
+
},
|
|
136
|
+
stdout: (output) => {
|
|
137
|
+
if (output) {
|
|
138
|
+
postMessage({ output });
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
stderr: (output) => {
|
|
142
|
+
if (output) {
|
|
143
|
+
postMessage({ output });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
if (log) {
|
|
148
|
+
console.log(`[wasm-idle:go-worker] wasi run complete exitCode=${String(execution.exitCode)}`);
|
|
149
|
+
}
|
|
150
|
+
if (execution.exitCode !== 0) {
|
|
151
|
+
throw new Error(execution.stderr
|
|
152
|
+
? `Go program exited with code ${execution.exitCode}\n${execution.stderr}`
|
|
153
|
+
: `Go program exited with code ${execution.exitCode}`);
|
|
154
|
+
}
|
|
155
|
+
postMessage({ results: true });
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (log) {
|
|
159
|
+
console.error('[wasm-idle:go-worker] failed', error);
|
|
160
|
+
}
|
|
161
|
+
postMessage({ error: error?.message || String(error) });
|
|
162
|
+
}
|
|
163
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|