wasm-idle 1.0.12 → 1.1.2
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 +150 -37
- package/dist/playground/applicationAssets.js +2 -0
- package/dist/playground/assetBridge.js +106 -31
- package/dist/playground/assets.d.ts +2 -2
- package/dist/playground/c3.js +22 -0
- package/dist/playground/c3Memory.d.ts +19 -0
- package/dist/playground/c3Memory.js +117 -0
- package/dist/playground/cachedClang.js +143 -34
- package/dist/playground/clangAssetIntegrity.js +6 -6
- package/dist/playground/clangWorkerProtocol.d.ts +12 -1
- package/dist/playground/cobol.d.ts +3 -0
- package/dist/playground/cobol.js +10 -1
- package/dist/playground/commonlisp.d.ts +8 -0
- package/dist/playground/commonlisp.js +33 -0
- package/dist/playground/commonlispAssets.d.ts +30 -0
- package/dist/playground/commonlispAssets.js +184 -0
- package/dist/playground/compiledArtifactCache.d.ts +3 -1
- package/dist/playground/compiledArtifactCache.js +31 -5
- package/dist/playground/container/ContainerExplorer.svelte +307 -0
- package/dist/playground/container/ContainerExplorer.svelte.d.ts +14 -0
- package/dist/playground/container/binding.d.ts +26 -0
- package/dist/playground/container/binding.js +247 -0
- package/dist/playground/container/clang-runtime.d.ts +38 -0
- package/dist/playground/container/clang-runtime.js +343 -0
- package/dist/playground/container/client.d.ts +15 -0
- package/dist/playground/container/client.js +189 -0
- package/dist/playground/container/explorer.d.ts +31 -0
- package/dist/playground/container/explorer.js +112 -0
- package/dist/playground/container/owner.worker.d.ts +1 -0
- package/dist/playground/container/owner.worker.js +390 -0
- package/dist/playground/container/protocol.d.ts +73 -0
- package/dist/playground/container/protocol.js +28 -0
- package/dist/playground/container/release.d.ts +31 -0
- package/dist/playground/container/release.js +612 -0
- package/dist/playground/container/runtime-adapter.d.ts +73 -0
- package/dist/playground/container/runtime-adapter.js +474 -0
- package/dist/playground/container/shell-control.d.ts +49 -0
- package/dist/playground/container/shell-control.js +303 -0
- package/dist/playground/container/workspace.d.ts +8 -0
- package/dist/playground/container/workspace.js +29 -0
- package/dist/playground/d.d.ts +6 -1
- package/dist/playground/d.js +83 -5
- package/dist/playground/dotnet.js +6 -8
- package/dist/playground/fortran.d.ts +3 -0
- package/dist/playground/fortran.js +10 -1
- package/dist/playground/go.js +14 -3
- package/dist/playground/goDebugInstrumentation.js +184 -54
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +14 -0
- package/dist/playground/java.js +3 -2
- package/dist/playground/javaRuntimeErrors.d.ts +9 -0
- package/dist/playground/javaRuntimeErrors.js +60 -0
- package/dist/playground/javaRuntimeStdin.d.ts +9 -0
- package/dist/playground/javaRuntimeStdin.js +145 -0
- package/dist/playground/lean4.d.ts +13 -0
- package/dist/playground/lean4.js +50 -0
- package/dist/playground/lean4Assets.d.ts +25 -0
- package/dist/playground/lean4Assets.js +123 -0
- package/dist/playground/lfortran.js +10 -0
- package/dist/playground/lfortranAssets.d.ts +2 -2
- package/dist/playground/loadingProgress.js +4 -1
- package/dist/playground/nim.js +22 -0
- package/dist/playground/objectivec.d.ts +3 -0
- package/dist/playground/objectivec.js +11 -2
- package/dist/playground/options.d.ts +2 -0
- package/dist/playground/python.js +8 -0
- package/dist/playground/runtimeAssetCache.d.ts +1 -32
- package/dist/playground/runtimeAssetCache.js +1 -193
- package/dist/playground/runtimeSession.d.ts +2 -2
- package/dist/playground/runtimeSession.js +11 -11
- package/dist/playground/rust.d.ts +6 -0
- package/dist/playground/rust.js +103 -6
- package/dist/playground/staticStdinRing.d.ts +2 -1
- package/dist/playground/staticStdinRing.js +21 -10
- package/dist/playground/staticWorkerRuntime.d.ts +15 -1
- package/dist/playground/staticWorkerRuntime.js +119 -17
- package/dist/playground/tinygo.d.ts +3 -0
- package/dist/playground/tinygo.js +81 -6
- package/dist/playground/v.d.ts +3 -0
- package/dist/playground/v.js +10 -1
- package/dist/playground/wasmAwkVersion.d.ts +13 -13
- package/dist/playground/wasmAwkVersion.js +4 -4
- package/dist/playground/wasmBqnVersion.d.ts +2 -2
- package/dist/playground/wasmBqnVersion.js +2 -2
- package/dist/playground/wasmC3Version.d.ts +2 -2
- package/dist/playground/wasmC3Version.js +2 -2
- package/dist/playground/wasmClojureScriptVersion.d.ts +2 -2
- package/dist/playground/wasmClojureScriptVersion.js +2 -2
- package/dist/playground/wasmCommonLispVersion.d.ts +32 -0
- package/dist/playground/wasmCommonLispVersion.js +33 -0
- package/dist/playground/wasmDIntegrity.d.ts +5 -5
- package/dist/playground/wasmDIntegrity.js +5 -5
- package/dist/playground/wasmDVersion.d.ts +16 -1
- package/dist/playground/wasmDVersion.js +16 -1
- package/dist/playground/wasmDebugVersion.d.ts +1 -1
- package/dist/playground/wasmDebugVersion.js +1 -1
- package/dist/playground/wasmForthVersion.d.ts +2 -2
- package/dist/playground/wasmForthVersion.js +2 -2
- package/dist/playground/wasmGleamVersion.d.ts +2 -2
- package/dist/playground/wasmGleamVersion.js +2 -2
- package/dist/playground/wasmGrainVersion.d.ts +2 -2
- package/dist/playground/wasmGrainVersion.js +2 -2
- package/dist/playground/wasmJVersion.d.ts +2 -2
- package/dist/playground/wasmJVersion.js +2 -2
- package/dist/playground/wasmJanetVersion.js +2 -2
- package/dist/playground/wasmJuliaVersion.js +2 -2
- package/dist/playground/wasmLean4Version.d.ts +110 -0
- package/dist/playground/wasmLean4Version.js +111 -0
- package/dist/playground/wasmLfortranVersion.d.ts +2 -2
- package/dist/playground/wasmLfortranVersion.js +2 -2
- package/dist/playground/wasmNimVersion.d.ts +9 -9
- package/dist/playground/wasmNimVersion.js +6 -6
- package/dist/playground/wasmOcamlVersion.d.ts +2 -2
- package/dist/playground/wasmOcamlVersion.js +1 -1
- package/dist/playground/wasmPascalVersion.js +2 -2
- package/dist/playground/wasmPerlVersion.js +2 -2
- package/dist/playground/wasmPrologVersion.d.ts +2 -2
- package/dist/playground/wasmPrologVersion.js +2 -2
- package/dist/playground/wasmReScriptVersion.d.ts +2 -2
- package/dist/playground/wasmReScriptVersion.js +2 -2
- package/dist/playground/wasmRustVersion.d.ts +8 -8
- package/dist/playground/wasmRustVersion.js +7 -7
- package/dist/playground/wasmTclVersion.d.ts +4 -4
- package/dist/playground/wasmTclVersion.js +2 -2
- package/dist/playground/wasmTinyGoVersion.d.ts +14 -14
- package/dist/playground/wasmTinyGoVersion.js +14 -14
- package/dist/playground/wasmTypeScriptVersion.d.ts +5 -5
- package/dist/playground/wasmTypeScriptVersion.js +5 -5
- package/dist/playground/worker/cachedClangCompile.js +52 -4
- package/dist/playground/worker/cachedClangExecute.js +6 -5
- package/dist/playground/worker/clang.js +32 -10
- package/dist/playground/worker/cobol.js +2 -2
- package/dist/playground/worker/d.js +12 -5
- package/dist/playground/worker/fortran.js +2 -2
- package/dist/playground/worker/go.js +16 -5
- package/dist/playground/worker/haskell.js +10 -7
- package/dist/playground/worker/java.js +92 -39
- package/dist/playground/worker/lua.js +2 -3
- package/dist/playground/worker/php.js +15 -9
- package/dist/playground/worker/python.js +131 -131
- package/dist/playground/worker/pythonDebugPreview.d.ts +2 -0
- package/dist/playground/worker/pythonDebugPreview.js +55 -0
- package/dist/playground/worker/pythonExecution.d.ts +8 -0
- package/dist/playground/worker/pythonExecution.js +183 -0
- package/dist/playground/worker/pythonStdio.d.ts +32 -0
- package/dist/playground/worker/pythonStdio.js +253 -0
- package/dist/playground/worker/pythonWorkspaceFiles.d.ts +6 -0
- package/dist/playground/worker/pythonWorkspaceFiles.js +26 -0
- package/dist/playground/worker/pythonWorkspaceImports.d.ts +4 -0
- package/dist/playground/worker/pythonWorkspaceImports.js +129 -0
- package/dist/playground/worker/r.js +13 -6
- package/dist/playground/worker/rust.js +34 -2
- package/dist/playground/worker/sqlite.js +4 -3
- package/dist/playground/worker/tinygo.js +11 -3
- package/dist/playground/worker/typescript.js +2 -3
- package/dist/playground/worker/v.js +2 -2
- package/dist/playground/worker/wat.js +2 -3
- package/dist/playground/worker/zig.js +20 -6
- package/dist/playground/workerSession.d.ts +1 -28
- package/dist/playground/workerSession.js +1 -164
- package/package.json +30 -15
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { createContainer } from '@wasm-idle/container';
|
|
2
|
+
import { installWasixWorkerGroup } from '@wasm-idle/container/adapters/wasix';
|
|
3
|
+
import { createBashProfile } from '../../../../examples/container/bash-profile.mjs';
|
|
4
|
+
import { createWebsiteBashConfiguration } from './release';
|
|
5
|
+
import { createShellControl } from './shell-control';
|
|
6
|
+
import { playgroundLanguages } from '../../../routes/language-registry';
|
|
7
|
+
import { WebsiteRuntimeAdapter } from './runtime-adapter';
|
|
8
|
+
import { WebsiteClangRuntime } from './clang-runtime';
|
|
9
|
+
import { CONTAINER_WORKER_PROTOCOL, serializeContainerWorkerError } from './protocol';
|
|
10
|
+
const scope = globalThis;
|
|
11
|
+
let channel = '', initialized = false, retired = false;
|
|
12
|
+
let container, engines, clang;
|
|
13
|
+
let profile;
|
|
14
|
+
let shellControl;
|
|
15
|
+
let shell;
|
|
16
|
+
let shellStarting, shellClosed = false;
|
|
17
|
+
let shellWriter;
|
|
18
|
+
let shellWrites = Promise.resolve();
|
|
19
|
+
let watcher;
|
|
20
|
+
const lifetime = new AbortController();
|
|
21
|
+
const requests = new Map();
|
|
22
|
+
const executionMode = new Map();
|
|
23
|
+
const NativeWorker = globalThis.Worker, children = new Set();
|
|
24
|
+
let childrenClosed = false;
|
|
25
|
+
class ApplicationWorker extends NativeWorker {
|
|
26
|
+
constructor(url, options) {
|
|
27
|
+
if (childrenClosed || children.size >= 64)
|
|
28
|
+
throw new Error('Application worker admission limit reached');
|
|
29
|
+
super(url, options);
|
|
30
|
+
children.add(this);
|
|
31
|
+
}
|
|
32
|
+
terminate() {
|
|
33
|
+
if (!children.delete(this))
|
|
34
|
+
return;
|
|
35
|
+
super.terminate();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Every engine Worker remains owned even after the one-shot SDK shell realm retires.
|
|
39
|
+
globalThis.Worker = ApplicationWorker;
|
|
40
|
+
const respond = (id, result) => scope.postMessage({ version: CONTAINER_WORKER_PROTOCOL, channel, id, ...result });
|
|
41
|
+
const emit = (event) => {
|
|
42
|
+
if (!retired)
|
|
43
|
+
respond(event.requestId ?? 0, { type: 'event', event });
|
|
44
|
+
};
|
|
45
|
+
function absoluteAssets(value, root, key = '') {
|
|
46
|
+
if (typeof value === 'string')
|
|
47
|
+
return key === '' || /(?:urls?|URLs?)$/i.test(key) ? new URL(value, root).href : value;
|
|
48
|
+
if (Array.isArray(value))
|
|
49
|
+
return value.map((item) => absoluteAssets(item, root, key));
|
|
50
|
+
if (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype)
|
|
51
|
+
return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, absoluteAssets(item, root, name)]));
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
async function initialize(settings) {
|
|
55
|
+
if (typeof settings.workspaceId !== 'string' || settings.workspaceId.length > 4096)
|
|
56
|
+
throw new Error('Invalid workspace identifier');
|
|
57
|
+
const root = new URL(settings.applicationRootURL);
|
|
58
|
+
if (root.origin !== location.origin || !root.pathname.endsWith('/'))
|
|
59
|
+
throw new Error('Invalid application asset root');
|
|
60
|
+
engines = new WebsiteRuntimeAdapter({
|
|
61
|
+
runtimeAssets: absoluteAssets(settings.runtimeAssets, root.href),
|
|
62
|
+
emit
|
|
63
|
+
});
|
|
64
|
+
if (crossOriginIsolated && typeof SharedArrayBuffer === 'function') {
|
|
65
|
+
const { config, sdk } = await createWebsiteBashConfiguration(root.href);
|
|
66
|
+
const sdkScope = { Worker: ApplicationWorker };
|
|
67
|
+
const group = installWasixWorkerGroup({ scope: sdkScope, maxWorkers: 32 });
|
|
68
|
+
const sdkWorkerURL = new URL(config.sdkWorkerUrl).href;
|
|
69
|
+
// Only the fixed SDK thread entry belongs to the SDK's irrevocable lifetime.
|
|
70
|
+
// Its late allocations keep hitting the closed constructor after shell exit.
|
|
71
|
+
const RoutedWorker = function (url, options) {
|
|
72
|
+
const Constructor = new URL(String(url), location.href).href === sdkWorkerURL
|
|
73
|
+
? sdkScope.Worker
|
|
74
|
+
: ApplicationWorker;
|
|
75
|
+
return new Constructor(url, options);
|
|
76
|
+
};
|
|
77
|
+
Object.setPrototypeOf(RoutedWorker, NativeWorker);
|
|
78
|
+
Object.defineProperty(RoutedWorker, 'prototype', { value: NativeWorker.prototype });
|
|
79
|
+
globalThis.Worker = RoutedWorker;
|
|
80
|
+
shellControl = createShellControl({ languages: playgroundLanguages });
|
|
81
|
+
profile = await createBashProfile({
|
|
82
|
+
config,
|
|
83
|
+
sdk,
|
|
84
|
+
workerGroup: group,
|
|
85
|
+
adapters: [engines.adapter, shellControl.adapter],
|
|
86
|
+
commands: { ...engines.commands, ...shellControl.commands },
|
|
87
|
+
shellRoutes: { [shellControl.route.path]: { command: shellControl.route.command } },
|
|
88
|
+
onInvocation: (invocation) => {
|
|
89
|
+
shellControl?.onInvocation(invocation);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
container = profile.container;
|
|
93
|
+
clang = new WebsiteClangRuntime(profile, engines, emit);
|
|
94
|
+
}
|
|
95
|
+
else
|
|
96
|
+
container = createContainer({
|
|
97
|
+
adapters: [engines.adapter],
|
|
98
|
+
commands: engines.commands,
|
|
99
|
+
maxBytes: 256 * 1024 * 1024,
|
|
100
|
+
maxInodes: 16384,
|
|
101
|
+
maxProcesses: 8,
|
|
102
|
+
maxMemoryBytes: 2 ** 32
|
|
103
|
+
});
|
|
104
|
+
engines.attach(container);
|
|
105
|
+
watcher = container.fs.watch({ maxQueuedEvents: 32, signal: lifetime.signal }).getReader();
|
|
106
|
+
void (async () => {
|
|
107
|
+
try {
|
|
108
|
+
for (;;) {
|
|
109
|
+
const { value, done } = await watcher.read();
|
|
110
|
+
if (done)
|
|
111
|
+
break;
|
|
112
|
+
emit({ name: 'workspace', data: value });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (!lifetime.signal.aborted)
|
|
117
|
+
emit({ name: 'shell-output', data: { error: String(error) } });
|
|
118
|
+
}
|
|
119
|
+
})();
|
|
120
|
+
}
|
|
121
|
+
async function startShell(options = {}) {
|
|
122
|
+
if (!profile)
|
|
123
|
+
throw new Error('Interactive shell requires cross-origin isolation. Batch Run is still available.');
|
|
124
|
+
if (shellClosed)
|
|
125
|
+
throw new Error('Bash has exited. Reload this workspace to open a fresh shell.');
|
|
126
|
+
if (shellStarting)
|
|
127
|
+
return shellStarting;
|
|
128
|
+
shellStarting = (async () => {
|
|
129
|
+
const cwd = options.cwd ?? '/workspace';
|
|
130
|
+
if (!/^\/workspace(?:\/[A-Z][A-Z0-9_]*)?$/.test(cwd))
|
|
131
|
+
throw new Error('Invalid shell directory');
|
|
132
|
+
container.fs.mkdir(cwd, { recursive: true });
|
|
133
|
+
const control = shellControl.setup(container.fs);
|
|
134
|
+
const initialDirectory = cwd === '/workspace'
|
|
135
|
+
? Promise.resolve()
|
|
136
|
+
: shellControl.requestDirectory(cwd.slice('/workspace/'.length));
|
|
137
|
+
// Keep a rejection observed while the actual SDK startup is still pending.
|
|
138
|
+
void initialDirectory.catch(() => { });
|
|
139
|
+
try {
|
|
140
|
+
shell = await profile.startShell({
|
|
141
|
+
cwd,
|
|
142
|
+
args: [...control.args],
|
|
143
|
+
mounts: ['/workspace', '/tmp', '/home/user', control.mountPath],
|
|
144
|
+
env: { ...options.env, ...control.env }
|
|
145
|
+
}, lifetime.signal);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
shellControl?.dispose();
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
shellWriter = shell.stdin.getWriter();
|
|
152
|
+
const drain = async (stream, name) => {
|
|
153
|
+
const reader = stream.getReader();
|
|
154
|
+
try {
|
|
155
|
+
for (;;) {
|
|
156
|
+
const { value, done } = await reader.read();
|
|
157
|
+
if (done)
|
|
158
|
+
break;
|
|
159
|
+
emit({ name: 'shell-output', data: { stream: name, bytes: value } });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
reader.releaseLock();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
void Promise.all([
|
|
167
|
+
shell.exited,
|
|
168
|
+
drain(shell.stdout, 'stdout'),
|
|
169
|
+
drain(shell.stderr, 'stderr')
|
|
170
|
+
])
|
|
171
|
+
.then(([result]) => {
|
|
172
|
+
shellClosed = true;
|
|
173
|
+
shellControl?.dispose();
|
|
174
|
+
emit({
|
|
175
|
+
name: 'shell-output',
|
|
176
|
+
data: {
|
|
177
|
+
stream: 'stderr',
|
|
178
|
+
bytes: new TextEncoder().encode(`\nShell ${result.reason}; reload to open a new shell.\n`)
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
})
|
|
182
|
+
.catch((error) => {
|
|
183
|
+
shellClosed = true;
|
|
184
|
+
shellControl?.dispose();
|
|
185
|
+
emit({
|
|
186
|
+
name: 'shell-output',
|
|
187
|
+
data: { error: error instanceof Error ? error.message : String(error) }
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
let readyTimeout;
|
|
191
|
+
try {
|
|
192
|
+
await Promise.race([
|
|
193
|
+
initialDirectory,
|
|
194
|
+
new Promise((_, reject) => {
|
|
195
|
+
readyTimeout = setTimeout(() => reject(new Error('Bash workspace control did not become ready within 10 seconds')), 10_000);
|
|
196
|
+
})
|
|
197
|
+
]);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
shellControl?.dispose();
|
|
201
|
+
await shell?.dispose();
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
clearTimeout(readyTimeout);
|
|
206
|
+
}
|
|
207
|
+
})();
|
|
208
|
+
return shellStarting;
|
|
209
|
+
}
|
|
210
|
+
async function shellWrite(text) {
|
|
211
|
+
if (!shellWriter || shellClosed)
|
|
212
|
+
throw new Error('Shell is not running');
|
|
213
|
+
const bytes = typeof text === 'string'
|
|
214
|
+
? new TextEncoder().encode(text.replaceAll('\r\n', '\n').replaceAll('\r', '\n'))
|
|
215
|
+
: text;
|
|
216
|
+
if (bytes.length > 65536)
|
|
217
|
+
throw new Error('Terminal input exceeds 64 KiB');
|
|
218
|
+
const next = shellWrites.catch(() => { }).then(() => shellWriter.write(bytes));
|
|
219
|
+
shellWrites = next;
|
|
220
|
+
await next;
|
|
221
|
+
}
|
|
222
|
+
async function dispose() {
|
|
223
|
+
if (retired)
|
|
224
|
+
return;
|
|
225
|
+
retired = true;
|
|
226
|
+
lifetime.abort();
|
|
227
|
+
shellControl?.dispose();
|
|
228
|
+
for (const request of requests.values())
|
|
229
|
+
request.abort();
|
|
230
|
+
await Promise.allSettled([
|
|
231
|
+
shell?.dispose(),
|
|
232
|
+
clang?.dispose(),
|
|
233
|
+
engines?.dispose(),
|
|
234
|
+
profile?.dispose(),
|
|
235
|
+
watcher?.cancel()
|
|
236
|
+
]);
|
|
237
|
+
await container?.dispose();
|
|
238
|
+
childrenClosed = true;
|
|
239
|
+
for (const child of [...children])
|
|
240
|
+
child.terminate();
|
|
241
|
+
}
|
|
242
|
+
const debugMethods = new Set([
|
|
243
|
+
'debugCommand',
|
|
244
|
+
'debugPause',
|
|
245
|
+
'setBreakpoints',
|
|
246
|
+
'debugEvaluate',
|
|
247
|
+
'debugVariables',
|
|
248
|
+
'debugScopes',
|
|
249
|
+
'debugFrameScopes',
|
|
250
|
+
'debugFrameName',
|
|
251
|
+
'debugReadMemory',
|
|
252
|
+
'debugWriteMemory',
|
|
253
|
+
'debugDataBreakpointInfo',
|
|
254
|
+
'debugSetDataBreakpoints'
|
|
255
|
+
]);
|
|
256
|
+
async function call(method, args, signal, id) {
|
|
257
|
+
if (retired && method !== 'dispose')
|
|
258
|
+
throw new Error('Container owner has been disposed');
|
|
259
|
+
const language = args[0];
|
|
260
|
+
const progress = {
|
|
261
|
+
set: (value, stage) => respond(id, { type: 'progress', progress: { kind: 'set', value, stage } }),
|
|
262
|
+
report: (event) => respond(id, { type: 'progress', progress: { kind: 'report', event } })
|
|
263
|
+
};
|
|
264
|
+
if (['load', 'prepare', 'run'].includes(method)) {
|
|
265
|
+
const [, code = '', log = true, argv = [], rawOptions = {}] = args;
|
|
266
|
+
const options = rawOptions ?? {};
|
|
267
|
+
const useClang = !!clang &&
|
|
268
|
+
['C', 'CPP'].includes(language) &&
|
|
269
|
+
!options.debug &&
|
|
270
|
+
(!options.debugMode || options.debugMode === 'none');
|
|
271
|
+
executionMode.set(language, useClang ? 'clang' : 'engine');
|
|
272
|
+
if (useClang) {
|
|
273
|
+
if (method === 'load') {
|
|
274
|
+
engines.inputs(language, code, options);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
return await clang[method](language, code, argv, options, signal, progress, id);
|
|
278
|
+
}
|
|
279
|
+
return await engines.execute(method, language, code, log, argv, options, signal, progress, id);
|
|
280
|
+
}
|
|
281
|
+
if (debugMethods.has(method))
|
|
282
|
+
return await engines.debug(language, method, args.slice(1));
|
|
283
|
+
if (method === 'write' || method === 'eof') {
|
|
284
|
+
const target = executionMode.get(language) === 'clang' && clang ? clang : engines;
|
|
285
|
+
return method === 'write'
|
|
286
|
+
? await target.write(language, args[1])
|
|
287
|
+
: await target.eof(language);
|
|
288
|
+
}
|
|
289
|
+
if (method === 'stop') {
|
|
290
|
+
await Promise.all([clang?.stop(language), engines.stop(language)]);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (method === 'clear') {
|
|
294
|
+
clang?.clear(language);
|
|
295
|
+
if (executionMode.get(language) === 'engine')
|
|
296
|
+
await engines.clear(language);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (method === 'restart') {
|
|
300
|
+
await clang?.stop(language);
|
|
301
|
+
clang?.clear(language);
|
|
302
|
+
await engines.restart(language);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (method === 'syncWorkspace')
|
|
306
|
+
return engines.syncWorkspace(language, args[1], args[2]);
|
|
307
|
+
if (method === 'readWorkspace')
|
|
308
|
+
return engines.readWorkspace(language);
|
|
309
|
+
if (method === 'listWorkspaceFiles')
|
|
310
|
+
return engines.listWorkspaceFiles();
|
|
311
|
+
if (method === 'inspect')
|
|
312
|
+
return {
|
|
313
|
+
...(await container.inspect()),
|
|
314
|
+
runtimeJobs: [...engines.inspect(), ...(clang?.inspect() ?? [])],
|
|
315
|
+
shell: {
|
|
316
|
+
running: !!shell && !shellClosed,
|
|
317
|
+
closed: shellClosed,
|
|
318
|
+
control: shellControl?.inspect()
|
|
319
|
+
},
|
|
320
|
+
ownedWorkers: children.size
|
|
321
|
+
};
|
|
322
|
+
if (method === 'shellStart')
|
|
323
|
+
return await startShell(args[0]);
|
|
324
|
+
if (method === 'shellSetDirectory') {
|
|
325
|
+
await shellStarting;
|
|
326
|
+
if (!shell || shellClosed || !shellControl)
|
|
327
|
+
throw new Error('Shell is not running');
|
|
328
|
+
return await shellControl.requestDirectory(language);
|
|
329
|
+
}
|
|
330
|
+
if (method === 'shellWrite')
|
|
331
|
+
return await shellWrite(args[0]);
|
|
332
|
+
if (method === 'shellEof') {
|
|
333
|
+
await shellWrites;
|
|
334
|
+
await shellWriter?.close();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (method === 'shellInterrupt') {
|
|
338
|
+
const interrupted = shell?.interrupt() ?? 0;
|
|
339
|
+
if (!interrupted)
|
|
340
|
+
await shellWrite('\x03');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (method === 'shellDispose') {
|
|
344
|
+
await shell?.dispose();
|
|
345
|
+
shellControl?.dispose();
|
|
346
|
+
shellClosed = true;
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (method === 'dispose')
|
|
350
|
+
return await dispose();
|
|
351
|
+
throw new Error('Unknown container operation');
|
|
352
|
+
}
|
|
353
|
+
scope.onmessage = (event) => {
|
|
354
|
+
const request = event.data;
|
|
355
|
+
if (!request ||
|
|
356
|
+
request.version !== CONTAINER_WORKER_PROTOCOL ||
|
|
357
|
+
typeof request.channel !== 'string' ||
|
|
358
|
+
!Number.isSafeInteger(request.id))
|
|
359
|
+
return;
|
|
360
|
+
if (request.type === 'init') {
|
|
361
|
+
if (initialized)
|
|
362
|
+
return;
|
|
363
|
+
initialized = true;
|
|
364
|
+
channel = request.channel;
|
|
365
|
+
void initialize(request.settings).then(() => respond(0, { type: 'result', value: undefined }), (error) => {
|
|
366
|
+
respond(0, { type: 'error', error: serializeContainerWorkerError(error) });
|
|
367
|
+
void dispose();
|
|
368
|
+
});
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (!initialized || request.channel !== channel)
|
|
372
|
+
return;
|
|
373
|
+
if (request.type === 'cancel') {
|
|
374
|
+
requests.get(request.id)?.abort(new DOMException('Operation cancelled', 'AbortError'));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (request.type !== 'call' ||
|
|
378
|
+
typeof request.method !== 'string' ||
|
|
379
|
+
!Array.isArray(request.args) ||
|
|
380
|
+
requests.has(request.id))
|
|
381
|
+
return;
|
|
382
|
+
const controller = new AbortController();
|
|
383
|
+
requests.set(request.id, controller);
|
|
384
|
+
void call(request.method, request.args, controller.signal, request.id)
|
|
385
|
+
.then((value) => respond(request.id, { type: 'result', value }), (error) => respond(request.id, {
|
|
386
|
+
type: 'error',
|
|
387
|
+
error: serializeContainerWorkerError(error)
|
|
388
|
+
}))
|
|
389
|
+
.finally(() => requests.delete(request.id));
|
|
390
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ProgressLike, RuntimeProgressEvent, WorkspaceFile } from '@wasm-idle/core';
|
|
2
|
+
import type { SandboxRuntimeAssets } from '../sandbox';
|
|
3
|
+
export declare const CONTAINER_WORKER_PROTOCOL = 1;
|
|
4
|
+
export declare const OWNER_CLEANUP_DEADLINE_MS = 2000;
|
|
5
|
+
export interface ContainerWorkerInitialization {
|
|
6
|
+
runtimeAssets: SandboxRuntimeAssets;
|
|
7
|
+
applicationRootURL: string;
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
}
|
|
10
|
+
export type ContainerWorkspaceFile = WorkspaceFile;
|
|
11
|
+
export interface ContainerWorkspaceEntry {
|
|
12
|
+
/** Path relative to /workspace, independent of the selected language. */
|
|
13
|
+
path: string;
|
|
14
|
+
type: 'file' | 'directory' | 'symlink';
|
|
15
|
+
size: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ContainerWorkerEvent {
|
|
18
|
+
language?: string;
|
|
19
|
+
name: 'output' | 'debug' | 'diagnostic' | 'image' | 'shell-output' | 'workspace';
|
|
20
|
+
data: unknown;
|
|
21
|
+
requestId?: number;
|
|
22
|
+
}
|
|
23
|
+
export type ContainerWorkerProgress = {
|
|
24
|
+
kind: 'set';
|
|
25
|
+
value: number;
|
|
26
|
+
stage?: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'report';
|
|
29
|
+
event: RuntimeProgressEvent;
|
|
30
|
+
};
|
|
31
|
+
export interface ContainerWorkerCallOptions {
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
progress?: ProgressLike;
|
|
34
|
+
}
|
|
35
|
+
export interface ContainerWorkerError {
|
|
36
|
+
name: string;
|
|
37
|
+
message: string;
|
|
38
|
+
code?: string;
|
|
39
|
+
}
|
|
40
|
+
export type ContainerWorkerRequest = {
|
|
41
|
+
version: typeof CONTAINER_WORKER_PROTOCOL;
|
|
42
|
+
channel: string;
|
|
43
|
+
id: number;
|
|
44
|
+
} & ({
|
|
45
|
+
type: 'init';
|
|
46
|
+
settings: ContainerWorkerInitialization;
|
|
47
|
+
} | {
|
|
48
|
+
type: 'call';
|
|
49
|
+
method: string;
|
|
50
|
+
args: unknown[];
|
|
51
|
+
} | {
|
|
52
|
+
type: 'cancel';
|
|
53
|
+
});
|
|
54
|
+
export type ContainerWorkerResponse = {
|
|
55
|
+
version: typeof CONTAINER_WORKER_PROTOCOL;
|
|
56
|
+
channel: string;
|
|
57
|
+
id: number;
|
|
58
|
+
} & ({
|
|
59
|
+
type: 'result';
|
|
60
|
+
value: unknown;
|
|
61
|
+
} | {
|
|
62
|
+
type: 'error';
|
|
63
|
+
error: ContainerWorkerError;
|
|
64
|
+
} | {
|
|
65
|
+
type: 'event';
|
|
66
|
+
event: ContainerWorkerEvent;
|
|
67
|
+
} | {
|
|
68
|
+
type: 'progress';
|
|
69
|
+
progress: ContainerWorkerProgress;
|
|
70
|
+
});
|
|
71
|
+
export declare function serializeContainerWorkerError(error: unknown): ContainerWorkerError;
|
|
72
|
+
/** A worker receives data snapshots; AbortSignal is transferred as cancellation messages. */
|
|
73
|
+
export declare function snapshotContainerArguments<T>(value: T): T;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const CONTAINER_WORKER_PROTOCOL = 1;
|
|
2
|
+
export const OWNER_CLEANUP_DEADLINE_MS = 2_000;
|
|
3
|
+
export function serializeContainerWorkerError(error) {
|
|
4
|
+
const value = error;
|
|
5
|
+
return {
|
|
6
|
+
name: typeof value?.name === 'string' ? value.name : 'Error',
|
|
7
|
+
message: typeof value?.message === 'string' ? value.message : String(error),
|
|
8
|
+
...(typeof value?.code === 'string' ? { code: value.code } : {})
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** A worker receives data snapshots; AbortSignal is transferred as cancellation messages. */
|
|
12
|
+
export function snapshotContainerArguments(value) {
|
|
13
|
+
const clean = (input) => {
|
|
14
|
+
if (Array.isArray(input))
|
|
15
|
+
return input.map(clean);
|
|
16
|
+
if (input &&
|
|
17
|
+
typeof input === 'object' &&
|
|
18
|
+
Object.getPrototypeOf(input) === Object.prototype) {
|
|
19
|
+
return Object.fromEntries(Object.entries(input)
|
|
20
|
+
.filter(([key, entry]) => key !== 'signal' ||
|
|
21
|
+
typeof AbortSignal === 'undefined' ||
|
|
22
|
+
!(entry instanceof AbortSignal))
|
|
23
|
+
.map(([key, entry]) => [key, clean(entry)]));
|
|
24
|
+
}
|
|
25
|
+
return input;
|
|
26
|
+
};
|
|
27
|
+
return structuredClone(clean(value));
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare function createWebsiteBashConfiguration(applicationRootURL: string): Promise<{
|
|
2
|
+
config: {
|
|
3
|
+
manifest: string;
|
|
4
|
+
manifestSha256: string;
|
|
5
|
+
assetURLs: string[];
|
|
6
|
+
sdkUrl: string;
|
|
7
|
+
sdkWorkerUrl: string;
|
|
8
|
+
liveWorkerUrl: string;
|
|
9
|
+
clangWorkerUrl: string;
|
|
10
|
+
commandTimeoutMs: undefined;
|
|
11
|
+
sdkAsset: {
|
|
12
|
+
packageId: string;
|
|
13
|
+
assetId: string;
|
|
14
|
+
};
|
|
15
|
+
shellAsset: {
|
|
16
|
+
packageId: string;
|
|
17
|
+
assetId: string;
|
|
18
|
+
};
|
|
19
|
+
bashWasmSha256: string;
|
|
20
|
+
memory: {
|
|
21
|
+
initial: number;
|
|
22
|
+
maximum: number;
|
|
23
|
+
shared: boolean;
|
|
24
|
+
};
|
|
25
|
+
clangSha256: string;
|
|
26
|
+
linkerSha256: string;
|
|
27
|
+
cacheNamespace: string;
|
|
28
|
+
clangFilesystem: string;
|
|
29
|
+
};
|
|
30
|
+
sdk: any;
|
|
31
|
+
}>;
|