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,75 @@
|
|
|
1
|
+
import { type PlaygroundRuntimeAssets, type TinyGoRuntimeAssetLoader, type TinyGoRuntimeAssetPackReference } from './assets';
|
|
2
|
+
import { type SandboxExecutionOptions } from './options';
|
|
3
|
+
import type { Sandbox } from './sandbox';
|
|
4
|
+
type TinyGoRuntimeHooks = {
|
|
5
|
+
boot(): Promise<void>;
|
|
6
|
+
plan(): Promise<unknown>;
|
|
7
|
+
execute(): Promise<void>;
|
|
8
|
+
reset(): void;
|
|
9
|
+
readActivityLog(): string;
|
|
10
|
+
readBuildArtifact(): {
|
|
11
|
+
path: string;
|
|
12
|
+
bytes: Uint8Array;
|
|
13
|
+
artifactKind?: 'probe' | 'bootstrap' | 'execution';
|
|
14
|
+
runnable?: boolean;
|
|
15
|
+
entrypoint?: '_start' | '_initialize' | 'main' | null;
|
|
16
|
+
reason?: 'bootstrap-artifact' | 'missing-wasi-entrypoint';
|
|
17
|
+
} | null;
|
|
18
|
+
setWorkspaceFiles(files: Record<string, string> | null): void;
|
|
19
|
+
dispose?(): void;
|
|
20
|
+
};
|
|
21
|
+
declare class TinyGo implements Sandbox {
|
|
22
|
+
output: any;
|
|
23
|
+
worker?: Worker;
|
|
24
|
+
buffer: SharedArrayBuffer;
|
|
25
|
+
pendingInput: string[];
|
|
26
|
+
begin: number;
|
|
27
|
+
elapse: number;
|
|
28
|
+
uid: number;
|
|
29
|
+
exit: boolean;
|
|
30
|
+
moduleUrl: string;
|
|
31
|
+
hostCompileUrl: string;
|
|
32
|
+
hostCompileUrls: string[];
|
|
33
|
+
rustRuntimeBaseUrl: string;
|
|
34
|
+
assetLoader: TinyGoRuntimeAssetLoader | undefined;
|
|
35
|
+
assetPacks: TinyGoRuntimeAssetPackReference[] | undefined;
|
|
36
|
+
runtime: TinyGoRuntimeHooks | null;
|
|
37
|
+
runtimePromise: Promise<TinyGoRuntimeHooks> | null;
|
|
38
|
+
loadPromise: Promise<void> | null;
|
|
39
|
+
compiledArtifact: Uint8Array | null;
|
|
40
|
+
compiledArtifactExecutionError: string;
|
|
41
|
+
compiledCacheKey: string;
|
|
42
|
+
activeReject: ((reason: string) => void) | null;
|
|
43
|
+
waitingForInput: boolean;
|
|
44
|
+
pendingEof: boolean;
|
|
45
|
+
lastActivityLog: string;
|
|
46
|
+
runtimeProgress: {
|
|
47
|
+
set?: (value: number) => void;
|
|
48
|
+
} | import('svelte/store').Writable<number> | undefined;
|
|
49
|
+
runtimeProgressStart: number;
|
|
50
|
+
runtimeProgressEnd: number;
|
|
51
|
+
runtimeProgressValue: number;
|
|
52
|
+
runtimeProgressAssets: Map<string, {
|
|
53
|
+
loaded: number;
|
|
54
|
+
total: number;
|
|
55
|
+
}>;
|
|
56
|
+
load(runtimeAssets?: string | PlaygroundRuntimeAssets, _code?: string, _log?: boolean, _args?: string[], _options?: SandboxExecutionOptions, progress?: {
|
|
57
|
+
set?: (value: number) => void;
|
|
58
|
+
} | import('svelte/store').Writable<number>): Promise<void>;
|
|
59
|
+
write(input: string): void;
|
|
60
|
+
eof(): void;
|
|
61
|
+
private flushPendingInput;
|
|
62
|
+
private ensureWorker;
|
|
63
|
+
private disposeRuntime;
|
|
64
|
+
private ensureRuntime;
|
|
65
|
+
private emitActivityLog;
|
|
66
|
+
private extractCompileFailure;
|
|
67
|
+
private compileArtifact;
|
|
68
|
+
run(code: string, prepare: boolean, _log?: boolean, _prog?: {
|
|
69
|
+
set?: (value: number) => void;
|
|
70
|
+
} | import('svelte/store').Writable<number>, args?: string[], options?: SandboxExecutionOptions): Promise<boolean | string>;
|
|
71
|
+
kill(): void;
|
|
72
|
+
terminate(): void;
|
|
73
|
+
clear(): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
export default TinyGo;
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
import { resolveRustCompilerUrl, resolveTinyGoHostCompileUrls, resolveTinyGoModuleUrl } from './assets';
|
|
2
|
+
import { resolveSandboxExecutionArgs } from './options';
|
|
3
|
+
import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
|
|
4
|
+
const ACTIVITY_PREFIX_PATTERN = /^\[\d{2}:\d{2}:\d{2}\]\s?/gm;
|
|
5
|
+
class TinyGo {
|
|
6
|
+
output = null;
|
|
7
|
+
worker = null;
|
|
8
|
+
buffer = new SharedArrayBuffer(1024);
|
|
9
|
+
pendingInput = [];
|
|
10
|
+
begin = 0;
|
|
11
|
+
elapse = 0;
|
|
12
|
+
uid = 0;
|
|
13
|
+
exit = true;
|
|
14
|
+
moduleUrl = '';
|
|
15
|
+
hostCompileUrl = '';
|
|
16
|
+
hostCompileUrls = [];
|
|
17
|
+
rustRuntimeBaseUrl = '';
|
|
18
|
+
assetLoader = undefined;
|
|
19
|
+
assetPacks = undefined;
|
|
20
|
+
runtime = null;
|
|
21
|
+
runtimePromise = null;
|
|
22
|
+
loadPromise = null;
|
|
23
|
+
compiledArtifact = null;
|
|
24
|
+
compiledArtifactExecutionError = '';
|
|
25
|
+
compiledCacheKey = '';
|
|
26
|
+
activeReject = null;
|
|
27
|
+
waitingForInput = false;
|
|
28
|
+
pendingEof = false;
|
|
29
|
+
lastActivityLog = '';
|
|
30
|
+
runtimeProgress = undefined;
|
|
31
|
+
runtimeProgressStart = 0;
|
|
32
|
+
runtimeProgressEnd = 0;
|
|
33
|
+
runtimeProgressValue = 0;
|
|
34
|
+
runtimeProgressAssets = new Map();
|
|
35
|
+
load(runtimeAssets = '', _code = '', _log = true, _args = [], _options = {}, progress) {
|
|
36
|
+
return new Promise(async (resolve, reject) => {
|
|
37
|
+
this.pendingInput = [];
|
|
38
|
+
this.waitingForInput = false;
|
|
39
|
+
this.pendingEof = false;
|
|
40
|
+
const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
|
|
41
|
+
const nextModuleUrl = resolveTinyGoModuleUrl(runtimeAssets, currentUrl);
|
|
42
|
+
const nextHostCompileUrls = resolveTinyGoHostCompileUrls(runtimeAssets, currentUrl);
|
|
43
|
+
const nextRustCompilerUrl = resolveRustCompilerUrl(runtimeAssets, currentUrl);
|
|
44
|
+
const nextRustRuntimeBaseUrl = nextRustCompilerUrl
|
|
45
|
+
? new URL('./runtime/', nextRustCompilerUrl).toString()
|
|
46
|
+
: '';
|
|
47
|
+
if (!nextModuleUrl && nextHostCompileUrls.length === 0) {
|
|
48
|
+
return reject('TinyGo runtime is not configured. Set PUBLIC_WASM_TINYGO_MODULE_URL, PUBLIC_WASM_TINYGO_HOST_COMPILE_URL, runtimeAssets.tinygo.moduleUrl, or runtimeAssets.tinygo.hostCompileUrl.');
|
|
49
|
+
}
|
|
50
|
+
if ((this.moduleUrl && this.moduleUrl !== nextModuleUrl) ||
|
|
51
|
+
this.hostCompileUrls.join('\n') !== nextHostCompileUrls.join('\n') ||
|
|
52
|
+
this.rustRuntimeBaseUrl !== nextRustRuntimeBaseUrl) {
|
|
53
|
+
this.disposeRuntime();
|
|
54
|
+
this.compiledArtifact = null;
|
|
55
|
+
this.compiledArtifactExecutionError = '';
|
|
56
|
+
this.compiledCacheKey = '';
|
|
57
|
+
}
|
|
58
|
+
const nextAssetLoader = typeof runtimeAssets === 'object' ? runtimeAssets?.tinygo?.assetLoader : undefined;
|
|
59
|
+
const nextAssetPacks = typeof runtimeAssets === 'object' ? runtimeAssets?.tinygo?.assetPacks : undefined;
|
|
60
|
+
this.moduleUrl = nextModuleUrl;
|
|
61
|
+
this.hostCompileUrl = nextHostCompileUrls[0] || '';
|
|
62
|
+
this.hostCompileUrls = nextHostCompileUrls;
|
|
63
|
+
this.rustRuntimeBaseUrl = nextRustRuntimeBaseUrl;
|
|
64
|
+
this.assetLoader = nextAssetLoader;
|
|
65
|
+
this.assetPacks = nextAssetPacks;
|
|
66
|
+
try {
|
|
67
|
+
progress?.set?.(0.25);
|
|
68
|
+
await this.ensureWorker();
|
|
69
|
+
progress?.set?.(0.5);
|
|
70
|
+
if (nextHostCompileUrls.length === 0 && nextModuleUrl) {
|
|
71
|
+
await this.ensureRuntime();
|
|
72
|
+
}
|
|
73
|
+
progress?.set?.(1);
|
|
74
|
+
resolve();
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
reject(error instanceof Error ? error.message : String(error));
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
write(input) {
|
|
82
|
+
this.pendingInput.push(input);
|
|
83
|
+
this.pendingEof = false;
|
|
84
|
+
this.flushPendingInput();
|
|
85
|
+
}
|
|
86
|
+
eof() {
|
|
87
|
+
this.pendingEof = true;
|
|
88
|
+
this.flushPendingInput();
|
|
89
|
+
}
|
|
90
|
+
flushPendingInput() {
|
|
91
|
+
if (!this.waitingForInput)
|
|
92
|
+
return;
|
|
93
|
+
if (flushQueuedStdin(this.pendingInput, this.buffer)) {
|
|
94
|
+
this.waitingForInput = false;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (this.pendingEof) {
|
|
98
|
+
flushBufferedEof(this.buffer);
|
|
99
|
+
this.pendingEof = false;
|
|
100
|
+
this.waitingForInput = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async ensureWorker() {
|
|
104
|
+
if (this.worker)
|
|
105
|
+
return;
|
|
106
|
+
if (this.loadPromise) {
|
|
107
|
+
await this.loadPromise;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.loadPromise = new Promise(async (resolve, reject) => {
|
|
111
|
+
this.worker = new (await import('./worker/tinygo?worker')).default();
|
|
112
|
+
this.worker.onerror = (event) => {
|
|
113
|
+
const location = event.filename && event.lineno
|
|
114
|
+
? ` (${event.filename}:${event.lineno}:${event.colno})`
|
|
115
|
+
: '';
|
|
116
|
+
reject(`TinyGo worker script error: ${event.message || 'unknown error'}${location}`);
|
|
117
|
+
};
|
|
118
|
+
this.worker.onmessageerror = () => {
|
|
119
|
+
reject('TinyGo worker message deserialization failed');
|
|
120
|
+
};
|
|
121
|
+
this.worker.onmessage = (event) => {
|
|
122
|
+
if (event.data?.load)
|
|
123
|
+
resolve();
|
|
124
|
+
if (event.data?.error)
|
|
125
|
+
reject(event.data.error);
|
|
126
|
+
};
|
|
127
|
+
this.worker.postMessage({ load: true });
|
|
128
|
+
}).finally(() => {
|
|
129
|
+
this.loadPromise = null;
|
|
130
|
+
});
|
|
131
|
+
await this.loadPromise;
|
|
132
|
+
}
|
|
133
|
+
disposeRuntime() {
|
|
134
|
+
this.runtime?.dispose?.();
|
|
135
|
+
this.runtime = null;
|
|
136
|
+
this.runtimePromise = null;
|
|
137
|
+
this.lastActivityLog = '';
|
|
138
|
+
this.compiledArtifactExecutionError = '';
|
|
139
|
+
}
|
|
140
|
+
async ensureRuntime() {
|
|
141
|
+
if (this.runtime) {
|
|
142
|
+
return this.runtime;
|
|
143
|
+
}
|
|
144
|
+
if (this.runtimePromise) {
|
|
145
|
+
return await this.runtimePromise;
|
|
146
|
+
}
|
|
147
|
+
const moduleUrl = this.moduleUrl;
|
|
148
|
+
this.runtimePromise = (async () => {
|
|
149
|
+
const runtimeModule = (await import(/* @vite-ignore */ moduleUrl));
|
|
150
|
+
if (typeof runtimeModule.createBundledTinyGoRuntime === 'function') {
|
|
151
|
+
this.runtime = runtimeModule.createBundledTinyGoRuntime({
|
|
152
|
+
assetLoader: this.assetLoader,
|
|
153
|
+
assetPacks: this.assetPacks,
|
|
154
|
+
rustRuntimeBaseUrl: this.rustRuntimeBaseUrl || undefined,
|
|
155
|
+
onProgress: (progress) => {
|
|
156
|
+
if (!this.runtimeProgress)
|
|
157
|
+
return;
|
|
158
|
+
const total = progress.total && progress.total > 0 ? progress.total : progress.loaded;
|
|
159
|
+
const key = progress.assetUrl || progress.assetPath;
|
|
160
|
+
this.runtimeProgressAssets.set(key, {
|
|
161
|
+
loaded: Math.max(0, progress.loaded),
|
|
162
|
+
total: Math.max(1, total)
|
|
163
|
+
});
|
|
164
|
+
let loaded = 0;
|
|
165
|
+
let size = 0;
|
|
166
|
+
for (const entry of this.runtimeProgressAssets.values()) {
|
|
167
|
+
loaded += Math.min(entry.loaded, entry.total);
|
|
168
|
+
size += entry.total;
|
|
169
|
+
}
|
|
170
|
+
if (size <= 0)
|
|
171
|
+
return;
|
|
172
|
+
const nextValue = this.runtimeProgressStart +
|
|
173
|
+
((this.runtimeProgressEnd - this.runtimeProgressStart) * loaded) / size;
|
|
174
|
+
if (nextValue <= this.runtimeProgressValue)
|
|
175
|
+
return;
|
|
176
|
+
this.runtimeProgressValue = nextValue;
|
|
177
|
+
this.runtimeProgress.set?.(nextValue);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return this.runtime;
|
|
181
|
+
}
|
|
182
|
+
if (typeof runtimeModule.createTinyGoRuntime === 'function') {
|
|
183
|
+
this.runtime = runtimeModule.createTinyGoRuntime({
|
|
184
|
+
assetBaseUrl: new URL('./', moduleUrl).toString(),
|
|
185
|
+
assetLoader: this.assetLoader,
|
|
186
|
+
assetPacks: this.assetPacks,
|
|
187
|
+
rustRuntimeBaseUrl: this.rustRuntimeBaseUrl || undefined,
|
|
188
|
+
onProgress: (progress) => {
|
|
189
|
+
if (!this.runtimeProgress)
|
|
190
|
+
return;
|
|
191
|
+
const total = progress.total && progress.total > 0 ? progress.total : progress.loaded;
|
|
192
|
+
const key = progress.assetUrl || progress.assetPath;
|
|
193
|
+
this.runtimeProgressAssets.set(key, {
|
|
194
|
+
loaded: Math.max(0, progress.loaded),
|
|
195
|
+
total: Math.max(1, total)
|
|
196
|
+
});
|
|
197
|
+
let loaded = 0;
|
|
198
|
+
let size = 0;
|
|
199
|
+
for (const entry of this.runtimeProgressAssets.values()) {
|
|
200
|
+
loaded += Math.min(entry.loaded, entry.total);
|
|
201
|
+
size += entry.total;
|
|
202
|
+
}
|
|
203
|
+
if (size <= 0)
|
|
204
|
+
return;
|
|
205
|
+
const nextValue = this.runtimeProgressStart +
|
|
206
|
+
((this.runtimeProgressEnd - this.runtimeProgressStart) * loaded) / size;
|
|
207
|
+
if (nextValue <= this.runtimeProgressValue)
|
|
208
|
+
return;
|
|
209
|
+
this.runtimeProgressValue = nextValue;
|
|
210
|
+
this.runtimeProgress.set?.(nextValue);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return this.runtime;
|
|
214
|
+
}
|
|
215
|
+
;
|
|
216
|
+
throw new Error('TinyGo runtime module must export createBundledTinyGoRuntime or createTinyGoRuntime');
|
|
217
|
+
})().catch((error) => {
|
|
218
|
+
this.disposeRuntime();
|
|
219
|
+
throw error;
|
|
220
|
+
});
|
|
221
|
+
return await this.runtimePromise;
|
|
222
|
+
}
|
|
223
|
+
emitActivityLog(hooks) {
|
|
224
|
+
const nextActivityLog = hooks.readActivityLog();
|
|
225
|
+
const delta = nextActivityLog.startsWith(this.lastActivityLog)
|
|
226
|
+
? nextActivityLog.slice(this.lastActivityLog.length)
|
|
227
|
+
: nextActivityLog;
|
|
228
|
+
this.lastActivityLog = nextActivityLog;
|
|
229
|
+
if (!delta)
|
|
230
|
+
return;
|
|
231
|
+
const sanitized = delta.replace(ACTIVITY_PREFIX_PATTERN, '');
|
|
232
|
+
if (sanitized)
|
|
233
|
+
this.output?.(sanitized);
|
|
234
|
+
}
|
|
235
|
+
extractCompileFailure() {
|
|
236
|
+
const sanitized = this.lastActivityLog.replace(ACTIVITY_PREFIX_PATTERN, '');
|
|
237
|
+
const lines = sanitized
|
|
238
|
+
.split('\n')
|
|
239
|
+
.map((line) => line.trim())
|
|
240
|
+
.filter(Boolean);
|
|
241
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
242
|
+
if (/(failed|error)/i.test(lines[index] || '')) {
|
|
243
|
+
return lines[index];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return 'TinyGo compilation failed';
|
|
247
|
+
}
|
|
248
|
+
async compileArtifact(code, log = true, prog) {
|
|
249
|
+
const compileCacheKey = JSON.stringify({
|
|
250
|
+
code,
|
|
251
|
+
hostCompileUrls: this.hostCompileUrls,
|
|
252
|
+
moduleUrl: this.moduleUrl
|
|
253
|
+
});
|
|
254
|
+
if (this.compiledArtifact && this.compiledCacheKey === compileCacheKey) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const unavailableHostCompileUrls = [];
|
|
258
|
+
if (this.hostCompileUrls.length > 0) {
|
|
259
|
+
prog?.set?.(0.05);
|
|
260
|
+
for (const hostCompileUrl of this.hostCompileUrls) {
|
|
261
|
+
let hostCompileResponse = null;
|
|
262
|
+
try {
|
|
263
|
+
hostCompileResponse = await fetch(hostCompileUrl, {
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: {
|
|
266
|
+
'content-type': 'application/json'
|
|
267
|
+
},
|
|
268
|
+
body: JSON.stringify({
|
|
269
|
+
source: code
|
|
270
|
+
})
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
unavailableHostCompileUrls.push(hostCompileUrl);
|
|
275
|
+
if (!this.moduleUrl && hostCompileUrl === this.hostCompileUrls.at(-1)) {
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (hostCompileResponse?.ok) {
|
|
281
|
+
const payload = (await hostCompileResponse.json());
|
|
282
|
+
const artifactBase64 = payload.artifact?.bytesBase64 || '';
|
|
283
|
+
if (!payload.artifact?.path || !artifactBase64) {
|
|
284
|
+
throw new Error('TinyGo host compile did not return a wasm artifact');
|
|
285
|
+
}
|
|
286
|
+
const artifactBytes = Uint8Array.from(atob(artifactBase64), (char) => char.charCodeAt(0));
|
|
287
|
+
this.compiledArtifact = artifactBytes;
|
|
288
|
+
this.compiledArtifactExecutionError =
|
|
289
|
+
payload.artifact.runnable === false
|
|
290
|
+
? payload.artifact.artifactKind === 'probe'
|
|
291
|
+
? 'TinyGo host compile returned a non-runnable probe artifact without a supported WASI entrypoint.'
|
|
292
|
+
: payload.artifact.reason === 'bootstrap-artifact'
|
|
293
|
+
? 'TinyGo host compile returned a bootstrap artifact and cannot execute it yet.'
|
|
294
|
+
: 'TinyGo host compile returned a non-runnable artifact without a supported WASI entrypoint.'
|
|
295
|
+
: '';
|
|
296
|
+
this.compiledCacheKey = compileCacheKey;
|
|
297
|
+
prog?.set?.(0.95);
|
|
298
|
+
if (log) {
|
|
299
|
+
for (const line of payload.logs || []) {
|
|
300
|
+
this.output?.(line.endsWith('\n') ? line : `${line}\n`);
|
|
301
|
+
}
|
|
302
|
+
this.output?.(`tinygo artifact ready: ${payload.artifact.path}\n`);
|
|
303
|
+
}
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (hostCompileResponse &&
|
|
307
|
+
hostCompileResponse.status !== 404 &&
|
|
308
|
+
hostCompileResponse.status !== 405 &&
|
|
309
|
+
hostCompileResponse.status !== 501) {
|
|
310
|
+
let failureMessage = 'TinyGo host compile failed';
|
|
311
|
+
try {
|
|
312
|
+
const payload = await hostCompileResponse.json();
|
|
313
|
+
if (typeof payload?.error === 'string' && payload.error) {
|
|
314
|
+
failureMessage = payload.error;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
const responseText = await hostCompileResponse.text();
|
|
319
|
+
if (responseText.trim()) {
|
|
320
|
+
failureMessage = responseText.trim();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
throw new Error(failureMessage);
|
|
324
|
+
}
|
|
325
|
+
if (hostCompileResponse) {
|
|
326
|
+
unavailableHostCompileUrls.push(hostCompileUrl);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (!this.moduleUrl) {
|
|
331
|
+
if (unavailableHostCompileUrls.length > 0) {
|
|
332
|
+
throw new Error(`TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}.`);
|
|
333
|
+
}
|
|
334
|
+
throw new Error('TinyGo host compile endpoint is unavailable.');
|
|
335
|
+
}
|
|
336
|
+
const runtime = await this.ensureRuntime();
|
|
337
|
+
runtime.reset();
|
|
338
|
+
this.lastActivityLog = runtime.readActivityLog();
|
|
339
|
+
runtime.setWorkspaceFiles({ 'main.go': code });
|
|
340
|
+
this.runtimeProgress = prog;
|
|
341
|
+
this.runtimeProgressAssets.clear();
|
|
342
|
+
this.runtimeProgressStart = 0.05;
|
|
343
|
+
this.runtimeProgressEnd = 0.35;
|
|
344
|
+
this.runtimeProgressValue = 0.05;
|
|
345
|
+
try {
|
|
346
|
+
prog?.set?.(0.05);
|
|
347
|
+
await runtime.boot();
|
|
348
|
+
this.emitActivityLog(runtime);
|
|
349
|
+
this.runtimeProgressAssets.clear();
|
|
350
|
+
this.runtimeProgressStart = 0.35;
|
|
351
|
+
this.runtimeProgressEnd = 0.65;
|
|
352
|
+
this.runtimeProgressValue = Math.max(this.runtimeProgressValue, 0.35);
|
|
353
|
+
prog?.set?.(this.runtimeProgressValue);
|
|
354
|
+
await runtime.plan();
|
|
355
|
+
this.emitActivityLog(runtime);
|
|
356
|
+
this.runtimeProgressAssets.clear();
|
|
357
|
+
this.runtimeProgressStart = 0.65;
|
|
358
|
+
this.runtimeProgressEnd = 0.92;
|
|
359
|
+
this.runtimeProgressValue = Math.max(this.runtimeProgressValue, 0.65);
|
|
360
|
+
prog?.set?.(this.runtimeProgressValue);
|
|
361
|
+
await runtime.execute();
|
|
362
|
+
this.emitActivityLog(runtime);
|
|
363
|
+
prog?.set?.(0.95);
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
this.runtimeProgress = undefined;
|
|
367
|
+
this.runtimeProgressAssets.clear();
|
|
368
|
+
}
|
|
369
|
+
const artifact = runtime.readBuildArtifact();
|
|
370
|
+
if (!artifact) {
|
|
371
|
+
const compileFailure = this.extractCompileFailure();
|
|
372
|
+
if (/(?:probe-only|supported WASI entrypoint|no host compile seam is configured)/i.test(compileFailure)) {
|
|
373
|
+
throw new Error(unavailableHostCompileUrls.length > 0
|
|
374
|
+
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime could not produce a runnable execution artifact: ${compileFailure}.`
|
|
375
|
+
: `TinyGo browser runtime could not produce a runnable execution artifact: ${compileFailure}.`);
|
|
376
|
+
}
|
|
377
|
+
throw new Error(compileFailure);
|
|
378
|
+
}
|
|
379
|
+
const runtimeLogLines = runtime
|
|
380
|
+
.readActivityLog()
|
|
381
|
+
.replace(ACTIVITY_PREFIX_PATTERN, '')
|
|
382
|
+
.split('\n')
|
|
383
|
+
.map((line) => line.trim())
|
|
384
|
+
.filter(Boolean);
|
|
385
|
+
let browserRuntimeFailure = '';
|
|
386
|
+
for (let index = runtimeLogLines.length - 1; index >= 0; index -= 1) {
|
|
387
|
+
const line = runtimeLogLines[index] || '';
|
|
388
|
+
if (/^(?:build execution failed:|artifact probe failed:)/.test(line)) {
|
|
389
|
+
browserRuntimeFailure = line.replace(/^(?:build execution failed:|artifact probe failed:)\s*/, '');
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
this.compiledArtifact = new Uint8Array(artifact.bytes);
|
|
394
|
+
this.compiledArtifactExecutionError =
|
|
395
|
+
artifact.runnable === false
|
|
396
|
+
? browserRuntimeFailure !== ''
|
|
397
|
+
? unavailableHostCompileUrls.length > 0
|
|
398
|
+
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime could not produce a runnable execution artifact: ${browserRuntimeFailure}.`
|
|
399
|
+
: `TinyGo browser runtime could not produce a runnable execution artifact: ${browserRuntimeFailure}.`
|
|
400
|
+
: artifact.reason === 'bootstrap-artifact'
|
|
401
|
+
? unavailableHostCompileUrls.length > 0
|
|
402
|
+
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime produced a bootstrap artifact and cannot execute it yet.`
|
|
403
|
+
: 'TinyGo browser runtime produced a bootstrap artifact and cannot execute it yet.'
|
|
404
|
+
: artifact.artifactKind === 'probe'
|
|
405
|
+
? unavailableHostCompileUrls.length > 0
|
|
406
|
+
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime produced a non-runnable probe artifact without a supported WASI entrypoint.`
|
|
407
|
+
: 'TinyGo browser runtime produced a non-runnable probe artifact without a supported WASI entrypoint.'
|
|
408
|
+
: unavailableHostCompileUrls.length > 0
|
|
409
|
+
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime produced a non-runnable artifact without a supported WASI entrypoint.`
|
|
410
|
+
: 'TinyGo browser runtime produced a non-runnable artifact without a supported WASI entrypoint.'
|
|
411
|
+
: '';
|
|
412
|
+
this.compiledCacheKey = compileCacheKey;
|
|
413
|
+
if (log) {
|
|
414
|
+
this.output?.(`tinygo artifact ready: ${artifact.path}\n`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
run(code, prepare, _log = true, _prog, args = [], options = {}) {
|
|
418
|
+
this.exit = false;
|
|
419
|
+
return new Promise(async (resolve, reject) => {
|
|
420
|
+
try {
|
|
421
|
+
this.begin = Date.now();
|
|
422
|
+
await this.ensureWorker();
|
|
423
|
+
await this.compileArtifact(code, _log, prepare ? _prog : undefined);
|
|
424
|
+
if (prepare) {
|
|
425
|
+
this.elapse = Date.now() - this.begin;
|
|
426
|
+
this.exit = true;
|
|
427
|
+
resolve(true);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (this.compiledArtifactExecutionError) {
|
|
431
|
+
throw new Error(this.compiledArtifactExecutionError);
|
|
432
|
+
}
|
|
433
|
+
if (!this.worker || !this.compiledArtifact) {
|
|
434
|
+
throw new Error('TinyGo runtime did not prepare an artifact');
|
|
435
|
+
}
|
|
436
|
+
const { programArgs } = resolveSandboxExecutionArgs('TINYGO', args, options);
|
|
437
|
+
const _uid = ++this.uid;
|
|
438
|
+
this.activeReject = reject;
|
|
439
|
+
this.worker.onmessage = (event) => {
|
|
440
|
+
if (!this.worker)
|
|
441
|
+
return reject('Worker not loaded');
|
|
442
|
+
if (_uid !== this.uid)
|
|
443
|
+
return (this.worker.onmessage = null);
|
|
444
|
+
const { output, results, error, buffer } = event.data;
|
|
445
|
+
if (buffer) {
|
|
446
|
+
this.waitingForInput = true;
|
|
447
|
+
this.flushPendingInput();
|
|
448
|
+
}
|
|
449
|
+
if (output)
|
|
450
|
+
this.output?.(output);
|
|
451
|
+
if (results) {
|
|
452
|
+
this.elapse = Date.now() - this.begin;
|
|
453
|
+
this.exit = true;
|
|
454
|
+
this.waitingForInput = false;
|
|
455
|
+
this.pendingEof = false;
|
|
456
|
+
this.activeReject = null;
|
|
457
|
+
resolve(results);
|
|
458
|
+
}
|
|
459
|
+
if (error) {
|
|
460
|
+
this.elapse = Date.now() - this.begin;
|
|
461
|
+
this.exit = true;
|
|
462
|
+
this.waitingForInput = false;
|
|
463
|
+
this.pendingEof = false;
|
|
464
|
+
this.activeReject = null;
|
|
465
|
+
reject(error);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
this.worker.postMessage({
|
|
469
|
+
artifact: new Uint8Array(this.compiledArtifact),
|
|
470
|
+
buffer: this.buffer,
|
|
471
|
+
args: programArgs,
|
|
472
|
+
log: _log
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
this.elapse = Date.now() - this.begin;
|
|
477
|
+
this.exit = true;
|
|
478
|
+
this.waitingForInput = false;
|
|
479
|
+
this.pendingEof = false;
|
|
480
|
+
this.activeReject = null;
|
|
481
|
+
reject(error instanceof Error ? error.message : String(error));
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
kill() {
|
|
486
|
+
this.terminate();
|
|
487
|
+
}
|
|
488
|
+
terminate() {
|
|
489
|
+
this.activeReject?.('Process terminated');
|
|
490
|
+
this.activeReject = null;
|
|
491
|
+
this.waitingForInput = false;
|
|
492
|
+
this.pendingEof = false;
|
|
493
|
+
this.uid += 1;
|
|
494
|
+
this.worker?.terminate?.();
|
|
495
|
+
delete this.worker;
|
|
496
|
+
this.exit = true;
|
|
497
|
+
}
|
|
498
|
+
async clear() {
|
|
499
|
+
this.pendingInput = [];
|
|
500
|
+
this.waitingForInput = false;
|
|
501
|
+
this.pendingEof = false;
|
|
502
|
+
if (this.worker)
|
|
503
|
+
this.worker.onmessage = null;
|
|
504
|
+
resetBufferedStdin(this.buffer);
|
|
505
|
+
if (!this.exit) {
|
|
506
|
+
this.terminate();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
export default TinyGo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const WASM_ELIXIR_ASSET_VERSION = "e848c7b1e0d73af2";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WASM_ELIXIR_ASSET_VERSION = 'e848c7b1e0d73af2';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const WASM_GO_ASSET_VERSION = "af750a633c515e0c";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WASM_GO_ASSET_VERSION = "af750a633c515e0c";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const WASM_OCAML_ASSET_VERSION = "bd4c85620ead3426";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WASM_OCAML_ASSET_VERSION = "bd4c85620ead3426";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const WASM_RUST_ASSET_VERSION = "
|
|
1
|
+
export declare const WASM_RUST_ASSET_VERSION = "1179d35ef825e266";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const WASM_RUST_ASSET_VERSION = "
|
|
1
|
+
export const WASM_RUST_ASSET_VERSION = "1179d35ef825e266";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const WASM_TINYGO_ASSET_VERSION = "c45e1d6b3e297250";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WASM_TINYGO_ASSET_VERSION = "c45e1d6b3e297250";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|