wasm-idle 0.7.2 → 1.0.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 +760 -81
- package/dist/index.d.ts +4 -9
- package/dist/index.js +2 -4
- package/dist/playground/applicationAssets.d.ts +4 -0
- package/dist/playground/applicationAssets.js +277 -0
- package/dist/playground/assemblyscript.d.ts +41 -0
- package/dist/playground/assemblyscript.js +630 -0
- package/dist/playground/assetBridge.d.ts +18 -7
- package/dist/playground/assetBridge.js +824 -100
- package/dist/playground/assets.d.ts +813 -19
- package/dist/playground/assets.js +2096 -156
- package/dist/playground/awk.d.ts +5 -0
- package/dist/playground/awk.js +60 -0
- package/dist/playground/bash.d.ts +53 -0
- package/dist/playground/bash.js +1096 -0
- package/dist/playground/bashWorkerProtocol.d.ts +88 -0
- package/dist/playground/bashWorkerProtocol.js +135 -0
- package/dist/playground/bqn.d.ts +5 -0
- package/dist/playground/bqn.js +57 -0
- package/dist/playground/bqnPreflight.d.ts +26 -0
- package/dist/playground/bqnPreflight.js +399 -0
- package/dist/playground/c3.d.ts +15 -0
- package/dist/playground/c3.js +154 -0
- package/dist/playground/clang.d.ts +35 -19
- package/dist/playground/clang.js +241 -52
- package/dist/playground/clangAssetIntegrity.d.ts +32 -0
- package/dist/playground/clangAssetIntegrity.js +8 -0
- package/dist/playground/clojurescript.d.ts +5 -0
- package/dist/playground/clojurescript.js +59 -0
- package/dist/playground/clojurescriptPreflight.d.ts +26 -0
- package/dist/playground/clojurescriptPreflight.js +383 -0
- package/dist/playground/cobol.d.ts +46 -0
- package/dist/playground/cobol.js +703 -0
- package/dist/playground/d.d.ts +47 -0
- package/dist/playground/d.js +644 -0
- package/dist/playground/dOuterAssets.d.ts +16 -0
- package/dist/playground/dOuterAssets.js +163 -0
- package/dist/playground/dotnet.d.ts +99 -0
- package/dist/playground/dotnet.js +1131 -0
- package/dist/playground/duckdb.d.ts +36 -0
- package/dist/playground/duckdb.js +542 -0
- package/dist/playground/elixir.d.ts +18 -10
- package/dist/playground/elixir.js +630 -96
- package/dist/playground/elixirAssets.d.ts +6 -0
- package/dist/playground/elixirAssets.js +33 -0
- package/dist/playground/executionObservation.d.ts +22 -0
- package/dist/playground/executionObservation.js +65 -0
- package/dist/playground/forth.d.ts +5 -0
- package/dist/playground/forth.js +53 -0
- package/dist/playground/forthPreflight.d.ts +24 -0
- package/dist/playground/forthPreflight.js +198 -0
- package/dist/playground/fortran.d.ts +47 -0
- package/dist/playground/fortran.js +651 -0
- package/dist/playground/fortranAssets.d.ts +6 -0
- package/dist/playground/fortranAssets.js +27 -0
- package/dist/playground/gleam.d.ts +6 -0
- package/dist/playground/gleam.js +33 -0
- package/dist/playground/go.d.ts +17 -11
- package/dist/playground/go.js +376 -72
- package/dist/playground/goDebugInstrumentation.d.ts +1 -0
- package/dist/playground/goDebugInstrumentation.js +229 -0
- package/dist/playground/haskell.d.ts +44 -0
- package/dist/playground/haskell.js +678 -0
- package/dist/playground/haskellAssets.d.ts +24 -0
- package/dist/playground/haskellAssets.js +93 -0
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +360 -111
- package/dist/playground/j.d.ts +5 -0
- package/dist/playground/j.js +60 -0
- package/dist/playground/jPreflight.d.ts +26 -0
- package/dist/playground/jPreflight.js +372 -0
- package/dist/playground/janet.d.ts +5 -0
- package/dist/playground/janet.js +64 -0
- package/dist/playground/java.d.ts +24 -10
- package/dist/playground/java.js +706 -84
- package/dist/playground/javaSource.d.ts +5 -0
- package/dist/playground/javaSource.js +16 -0
- package/dist/playground/javaStdin.d.ts +1 -1
- package/dist/playground/javaStdin.js +13 -4
- package/dist/playground/julia.d.ts +5 -0
- package/dist/playground/julia.js +64 -0
- package/dist/playground/lfortran.d.ts +8 -0
- package/dist/playground/lfortran.js +30 -0
- package/dist/playground/lfortranAssets.d.ts +21 -0
- package/dist/playground/lfortranAssets.js +118 -0
- package/dist/playground/lisp.d.ts +45 -0
- package/dist/playground/lisp.js +640 -0
- package/dist/playground/lispAssets.d.ts +9 -0
- package/dist/playground/lispAssets.js +74 -0
- package/dist/playground/lldbManifest.d.ts +3 -0
- package/dist/playground/lldbManifest.js +155 -0
- package/dist/playground/lldbSession.d.ts +115 -0
- package/dist/playground/lldbSession.js +1347 -0
- package/dist/playground/loadingProgress.d.ts +16 -0
- package/dist/playground/loadingProgress.js +166 -0
- package/dist/playground/lua.d.ts +44 -0
- package/dist/playground/lua.js +630 -0
- package/dist/playground/nim.d.ts +5 -0
- package/dist/playground/nim.js +76 -0
- package/dist/playground/objectivec.d.ts +39 -0
- package/dist/playground/objectivec.js +288 -0
- package/dist/playground/ocaml.d.ts +28 -10
- package/dist/playground/ocaml.js +815 -253
- package/dist/playground/octave.d.ts +43 -0
- package/dist/playground/octave.js +783 -0
- package/dist/playground/options.d.ts +19 -40
- package/dist/playground/options.js +2 -1
- package/dist/playground/pascal.d.ts +5 -0
- package/dist/playground/pascal.js +60 -0
- package/dist/playground/perl.d.ts +5 -0
- package/dist/playground/perl.js +61 -0
- package/dist/playground/php.d.ts +44 -0
- package/dist/playground/php.js +665 -0
- package/dist/playground/prolog.d.ts +6 -0
- package/dist/playground/prolog.js +75 -0
- package/dist/playground/python.d.ts +20 -14
- package/dist/playground/python.js +445 -101
- package/dist/playground/pythonPackageLock.d.ts +6 -0
- package/dist/playground/pythonPackageLock.js +56 -0
- package/dist/playground/r.d.ts +44 -0
- package/dist/playground/r.js +637 -0
- package/dist/playground/ruby.d.ts +46 -0
- package/dist/playground/ruby.js +732 -0
- package/dist/playground/rubyAssets.d.ts +23 -0
- package/dist/playground/rubyAssets.js +68 -0
- package/dist/playground/rubyTestPreflight.d.ts +2 -0
- package/dist/playground/rubyTestPreflight.js +18 -0
- package/dist/playground/runtimeModule.d.ts +1 -0
- package/dist/playground/runtimeModule.js +5 -0
- package/dist/playground/rust.d.ts +44 -13
- package/dist/playground/rust.js +714 -76
- package/dist/playground/rustExecutableGraph.d.ts +85 -0
- package/dist/playground/rustExecutableGraph.js +946 -0
- package/dist/playground/rustWorkerLimits.d.ts +17 -0
- package/dist/playground/rustWorkerLimits.js +34 -0
- package/dist/playground/sandbox.d.ts +16 -10
- package/dist/playground/sharedBuffer.d.ts +6 -0
- package/dist/playground/sharedBuffer.js +12 -0
- package/dist/playground/sqlite.d.ts +38 -0
- package/dist/playground/sqlite.js +550 -0
- package/dist/playground/staticRuntimeModuleVersion.d.ts +1 -0
- package/dist/playground/staticRuntimeModuleVersion.js +2 -0
- package/dist/playground/staticRuntimePreflight.d.ts +13 -0
- package/dist/playground/staticRuntimePreflight.js +231 -0
- package/dist/playground/staticRuntimePreflightExecute.d.ts +8 -0
- package/dist/playground/staticRuntimePreflightExecute.js +66 -0
- package/dist/playground/staticRuntimePreflightProtocol.d.ts +68 -0
- package/dist/playground/staticRuntimePreflightProtocol.js +339 -0
- package/dist/playground/staticStdinRing.d.ts +45 -0
- package/dist/playground/staticStdinRing.js +158 -0
- package/dist/playground/staticWorkerRuntime.d.ts +154 -0
- package/dist/playground/staticWorkerRuntime.js +1917 -0
- package/dist/playground/stdinBuffer.d.ts +9 -7
- package/dist/playground/stdinBuffer.js +9 -18
- package/dist/playground/swift.d.ts +5 -0
- package/dist/playground/swift.js +17 -0
- package/dist/playground/tcl.d.ts +5 -0
- package/dist/playground/tcl.js +62 -0
- package/dist/playground/teavmConfig.d.ts +1 -1
- package/dist/playground/teavmConfig.js +2 -2
- package/dist/playground/tinygo.d.ts +48 -18
- package/dist/playground/tinygo.js +1202 -329
- package/dist/playground/tinygoExecutableGraph.d.ts +44 -0
- package/dist/playground/tinygoExecutableGraph.js +449 -0
- package/dist/playground/typescript.d.ts +55 -0
- package/dist/playground/typescript.js +924 -0
- package/dist/playground/wasm.d.ts +43 -0
- package/dist/playground/wasm.js +608 -0
- package/dist/playground/wasmAwkVersion.d.ts +59 -0
- package/dist/playground/wasmAwkVersion.js +31 -0
- package/dist/playground/wasmBashVersion.d.ts +63 -0
- package/dist/playground/wasmBashVersion.js +36 -0
- package/dist/playground/wasmBqnVersion.d.ts +24 -0
- package/dist/playground/wasmBqnVersion.js +24 -0
- package/dist/playground/wasmC3Version.d.ts +20 -0
- package/dist/playground/wasmC3Version.js +21 -0
- package/dist/playground/wasmClojureScriptVersion.d.ts +21 -0
- package/dist/playground/wasmClojureScriptVersion.js +21 -0
- package/dist/playground/wasmDIntegrity.d.ts +15 -0
- package/dist/playground/wasmDIntegrity.js +15 -0
- package/dist/playground/wasmDVersion.d.ts +1 -0
- package/dist/playground/wasmDVersion.js +1 -0
- package/dist/playground/wasmDebugVersion.d.ts +6 -0
- package/dist/playground/wasmDebugVersion.js +6 -0
- package/dist/playground/wasmDotnetVersion.d.ts +1 -0
- package/dist/playground/wasmDotnetVersion.js +1 -0
- package/dist/playground/wasmElixirVersion.d.ts +21 -1
- package/dist/playground/wasmElixirVersion.js +21 -1
- package/dist/playground/wasmForthVersion.d.ts +18 -0
- package/dist/playground/wasmForthVersion.js +18 -0
- package/dist/playground/wasmFortranExecutionAssets.d.ts +15 -0
- package/dist/playground/wasmFortranExecutionAssets.js +15 -0
- package/dist/playground/wasmFortranVersion.d.ts +1 -0
- package/dist/playground/wasmFortranVersion.js +1 -0
- package/dist/playground/wasmGleamVersion.d.ts +5 -0
- package/dist/playground/wasmGleamVersion.js +5 -0
- package/dist/playground/wasmGoVersion.d.ts +1 -1
- package/dist/playground/wasmGoVersion.js +1 -1
- package/dist/playground/wasmHaskellVersion.d.ts +1 -0
- package/dist/playground/wasmHaskellVersion.js +1 -0
- package/dist/playground/wasmJVersion.d.ts +24 -0
- package/dist/playground/wasmJVersion.js +24 -0
- package/dist/playground/wasmJanetVersion.d.ts +53 -0
- package/dist/playground/wasmJanetVersion.js +30 -0
- package/dist/playground/wasmJuliaVersion.d.ts +71 -0
- package/dist/playground/wasmJuliaVersion.js +39 -0
- package/dist/playground/wasmLfortranVersion.d.ts +28 -0
- package/dist/playground/wasmLfortranVersion.js +29 -0
- package/dist/playground/wasmLispVersion.d.ts +1 -0
- package/dist/playground/wasmLispVersion.js +1 -0
- package/dist/playground/wasmLuaVersion.d.ts +1 -0
- package/dist/playground/wasmLuaVersion.js +1 -0
- package/dist/playground/wasmNimVersion.d.ts +125 -0
- package/dist/playground/wasmNimVersion.js +66 -0
- package/dist/playground/wasmObjectiveCVersion.d.ts +27 -0
- package/dist/playground/wasmObjectiveCVersion.js +27 -0
- package/dist/playground/wasmOcamlVersion.d.ts +12 -1
- package/dist/playground/wasmOcamlVersion.js +12 -1
- package/dist/playground/wasmOctaveVersion.d.ts +1 -0
- package/dist/playground/wasmOctaveVersion.js +1 -0
- package/dist/playground/wasmPascalVersion.d.ts +61 -0
- package/dist/playground/wasmPascalVersion.js +34 -0
- package/dist/playground/wasmPerlVersion.d.ts +71 -0
- package/dist/playground/wasmPerlVersion.js +39 -0
- package/dist/playground/wasmPrologVersion.d.ts +31 -0
- package/dist/playground/wasmPrologVersion.js +31 -0
- package/dist/playground/wasmRVersion.d.ts +1 -0
- package/dist/playground/wasmRVersion.js +1 -0
- package/dist/playground/wasmRustVersion.d.ts +1306 -1
- package/dist/playground/wasmRustVersion.js +1458 -1
- package/dist/playground/wasmSwiftVersion.d.ts +1 -0
- package/dist/playground/wasmSwiftVersion.js +1 -0
- package/dist/playground/wasmTclVersion.d.ts +85 -0
- package/dist/playground/wasmTclVersion.js +46 -0
- package/dist/playground/wasmTinyGoVersion.d.ts +98 -1
- package/dist/playground/wasmTinyGoVersion.js +107 -1
- package/dist/playground/wasmTypeScriptVersion.d.ts +5 -0
- package/dist/playground/wasmTypeScriptVersion.js +5 -0
- package/dist/playground/wasmWatVersion.d.ts +1 -0
- package/dist/playground/wasmWatVersion.js +1 -0
- package/dist/playground/wasmZigVersion.d.ts +13 -0
- package/dist/playground/wasmZigVersion.js +13 -0
- package/dist/playground/wat.d.ts +44 -0
- package/dist/playground/wat.js +622 -0
- package/dist/playground/worker/assemblyscript.js +339 -0
- package/dist/playground/worker/assets.d.ts +7 -0
- package/dist/playground/worker/assets.js +288 -39
- package/dist/playground/worker/bash.js +338 -0
- package/dist/playground/worker/bashNestedBootstrap.d.ts +6 -0
- package/dist/playground/worker/bashNestedBootstrap.js +59 -0
- package/dist/playground/worker/bashRuntime.d.ts +89 -0
- package/dist/playground/worker/bashRuntime.js +982 -0
- package/dist/playground/worker/clang.js +92 -13
- package/dist/playground/worker/cobol.js +107 -0
- package/dist/playground/worker/d.js +199 -0
- package/dist/playground/worker/dotnet.js +141 -0
- package/dist/playground/worker/duckdb.d.ts +1 -0
- package/dist/playground/worker/duckdb.js +136 -0
- package/dist/playground/worker/elixir.js +307 -41
- package/dist/playground/worker/fortran.d.ts +1 -0
- package/dist/playground/worker/fortran.js +295 -0
- package/dist/playground/worker/go.js +246 -40
- package/dist/playground/worker/haskell.d.ts +7 -0
- package/dist/playground/worker/haskell.js +465 -0
- package/dist/playground/worker/java.js +59 -20
- package/dist/playground/worker/lisp.d.ts +1 -0
- package/dist/playground/worker/lisp.js +195 -0
- package/dist/playground/worker/lua.d.ts +1 -0
- package/dist/playground/worker/lua.js +163 -0
- package/dist/playground/worker/objectivec.d.ts +1 -0
- package/dist/playground/worker/objectivec.js +10 -0
- package/dist/playground/worker/ocaml.js +206 -58
- package/dist/playground/worker/php.d.ts +1 -0
- package/dist/playground/worker/php.js +261 -0
- package/dist/playground/worker/python.js +201 -44
- package/dist/playground/worker/r.d.ts +1 -0
- package/dist/playground/worker/r.js +192 -0
- package/dist/playground/worker/ruby.d.ts +1 -0
- package/dist/playground/worker/ruby.js +248 -0
- package/dist/playground/worker/runtimeAssetFetch.d.ts +15 -0
- package/dist/playground/worker/runtimeAssetFetch.js +375 -0
- package/dist/playground/worker/rust.js +546 -20
- package/dist/playground/worker/sqlite.d.ts +1 -0
- package/dist/playground/worker/sqlite.js +112 -0
- package/dist/playground/worker/staticRuntimePreflight.d.ts +1 -0
- package/dist/playground/worker/staticRuntimePreflight.js +56 -0
- package/dist/playground/worker/tinygo.js +34 -9
- package/dist/playground/worker/typescript.d.ts +1 -0
- package/dist/playground/worker/typescript.js +251 -0
- package/dist/playground/worker/wasm.d.ts +1 -0
- package/dist/playground/worker/wasm.js +273 -0
- package/dist/playground/worker/wat.d.ts +1 -0
- package/dist/playground/worker/wat.js +188 -0
- package/dist/playground/worker/zig.d.ts +8 -0
- package/dist/playground/worker/zig.js +578 -0
- package/dist/playground/workerProgress.d.ts +15 -0
- package/dist/playground/workerProgress.js +72 -0
- package/dist/playground/workerSession.d.ts +28 -0
- package/dist/playground/workerSession.js +164 -0
- package/dist/playground/zig.d.ts +46 -0
- package/dist/playground/zig.js +690 -0
- package/dist/playground/zigAssets.d.ts +6 -0
- package/dist/playground/zigAssets.js +49 -0
- package/package.json +234 -105
- package/dist/clang/app.d.ts +0 -75
- package/dist/clang/app.js +0 -744
- package/dist/clang/apply.d.ts +0 -2
- package/dist/clang/apply.js +0 -11
- package/dist/clang/color.d.ts +0 -3
- package/dist/clang/color.js +0 -3
- package/dist/clang/encode.d.ts +0 -4
- package/dist/clang/encode.js +0 -20
- package/dist/clang/error.d.ts +0 -14
- package/dist/clang/error.js +0 -27
- package/dist/clang/gccCompat.d.ts +0 -15
- package/dist/clang/gccCompat.js +0 -767
- package/dist/clang/index.d.ts +0 -85
- package/dist/clang/index.js +0 -1077
- package/dist/clang/memory/index.d.ts +0 -4
- package/dist/clang/memory/index.js +0 -4
- package/dist/clang/memory/memFs.d.ts +0 -35
- package/dist/clang/memory/memFs.js +0 -132
- package/dist/clang/memory/memory.d.ts +0 -22
- package/dist/clang/memory/memory.js +0 -73
- package/dist/clang/memory/tar.d.ts +0 -2
- package/dist/clang/memory/tar.js +0 -59
- package/dist/clang/url.d.ts +0 -4
- package/dist/clang/url.js +0 -5
- package/dist/clang/wasm.d.ts +0 -4
- package/dist/clang/wasm.js +0 -50
- package/dist/clangd/config.d.ts +0 -18
- package/dist/clangd/config.js +0 -14
- package/dist/clangd/jsonStream.d.ts +0 -9
- package/dist/clangd/jsonStream.js +0 -48
- package/dist/clangd/session.d.ts +0 -18
- package/dist/clangd/session.js +0 -112
- package/dist/clangd/worker.js +0 -131
- package/dist/debug/controller.svelte.d.ts +0 -43
- package/dist/debug/controller.svelte.js +0 -268
- package/dist/debug/editor/index.d.ts +0 -2
- package/dist/debug/editor/index.js +0 -1
- package/dist/debug/editor/monaco.d.ts +0 -26
- package/dist/debug/editor/monaco.js +0 -128
- package/dist/debug/expression.d.ts +0 -26
- package/dist/debug/expression.js +0 -547
- package/dist/debug/index.d.ts +0 -8
- package/dist/debug/index.js +0 -5
- package/dist/debug/language/cpp.d.ts +0 -2
- package/dist/debug/language/cpp.js +0 -7
- package/dist/debug/language/index.d.ts +0 -3
- package/dist/debug/language/index.js +0 -2
- package/dist/debug/language/python.d.ts +0 -2
- package/dist/debug/language/python.js +0 -14
- package/dist/debug/language/types.d.ts +0 -6
- package/dist/debug/locals.d.ts +0 -2
- package/dist/debug/locals.js +0 -8
- package/dist/lsp/cpp/server.d.ts +0 -2
- package/dist/lsp/cpp/server.js +0 -68
- package/dist/lsp/index.d.ts +0 -5
- package/dist/lsp/index.js +0 -4
- package/dist/lsp/python/main.worker.js +0 -92
- package/dist/lsp/python/package/arcturus_python_lsp/__init__.py +0 -3
- package/dist/lsp/python/package/arcturus_python_lsp/server.py +0 -462
- package/dist/lsp/python/server.d.ts +0 -2
- package/dist/lsp/python/server.js +0 -54
- package/dist/lsp/registry.d.ts +0 -2
- package/dist/lsp/registry.js +0 -12
- package/dist/lsp/runtime.d.ts +0 -5
- package/dist/lsp/runtime.js +0 -31
- package/dist/lsp/types.d.ts +0 -17
- package/dist/terminal/Terminal.svelte +0 -422
- package/dist/terminal/Terminal.svelte.d.ts +0 -26
- package/dist/terminal/index.d.ts +0 -7
- package/dist/terminal/index.js +0 -5
- package/dist/terminal/plugin/index.d.ts +0 -9
- package/dist/terminal/plugin/index.js +0 -19
- package/dist/terminal/theme.d.ts +0 -49
- package/dist/terminal/theme.js +0 -49
- package/dist/terminal/types.d.ts +0 -18
- package/dist/utils/vscodeJsonrpcBrowser.d.ts +0 -5
- package/dist/utils/vscodeJsonrpcBrowser.js +0 -4
- /package/dist/{clangd/worker.d.ts → playground/worker/assemblyscript.d.ts} +0 -0
- /package/dist/{debug/language/types.js → playground/worker/bash.d.ts} +0 -0
- /package/dist/{lsp/python/main.worker.d.ts → playground/worker/cobol.d.ts} +0 -0
- /package/dist/{lsp/types.js → playground/worker/d.d.ts} +0 -0
- /package/dist/{terminal/types.js → playground/worker/dotnet.d.ts} +0 -0
|
@@ -1,29 +1,88 @@
|
|
|
1
|
-
import { resolveRustCompilerUrl,
|
|
2
|
-
import {
|
|
1
|
+
import { resolveRustCompilerUrl, resolveTinyGoModuleUrl } from './assets';
|
|
2
|
+
import { loadVerifiedTinyGoExecutableGraph } from './tinygoExecutableGraph';
|
|
3
|
+
import { WASM_TINYGO_EXECUTABLE_GRAPH_PROFILE, WASM_TINYGO_RUNTIME_PROFILE } from './wasmTinyGoVersion';
|
|
3
4
|
import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
|
|
5
|
+
import { createWasmIdleSharedBuffer } from './sharedBuffer';
|
|
6
|
+
import { WorkerSession } from './workerSession';
|
|
7
|
+
import { reportWorkerProgress } from './workerProgress';
|
|
8
|
+
import { BusyError, CancelledError, DEFAULT_EXECUTION_LIMITS, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, WorkspaceValidationError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
|
|
4
9
|
const ACTIVITY_PREFIX_PATTERN = /^\[\d{2}:\d{2}:\d{2}\]\s?/gm;
|
|
10
|
+
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
11
|
+
const TINYGO_BROWSER_COMPILER_DEFAULT_MAX_WASM_MEMORY_BYTES = 2 * 1024 * 1024 * 1024;
|
|
12
|
+
const EXECUTION_LIMIT_KEYS = Object.keys(DEFAULT_EXECUTION_LIMITS);
|
|
13
|
+
const OUTPUT_ENCODER = new TextEncoder();
|
|
14
|
+
const TINYGO_TARGETS = new Set(['wasm', 'wasip1', 'wasip2', 'wasip3']);
|
|
15
|
+
function snapshotTinyGoRuntimeProfile(config) {
|
|
16
|
+
const profileFields = [
|
|
17
|
+
'profileId',
|
|
18
|
+
'protocolVersion',
|
|
19
|
+
'manifestPath',
|
|
20
|
+
'manifestFingerprint',
|
|
21
|
+
'manifestReceipt',
|
|
22
|
+
'assetReceipts'
|
|
23
|
+
];
|
|
24
|
+
const hasOverride = profileFields.some((field) => config?.[field] !== undefined);
|
|
25
|
+
const source = hasOverride ? config : WASM_TINYGO_RUNTIME_PROFILE;
|
|
26
|
+
if (!source ||
|
|
27
|
+
typeof source.profileId !== 'string' ||
|
|
28
|
+
typeof source.protocolVersion !== 'number' ||
|
|
29
|
+
typeof source.manifestPath !== 'string' ||
|
|
30
|
+
typeof source.manifestFingerprint !== 'string' ||
|
|
31
|
+
!source.manifestReceipt ||
|
|
32
|
+
!source.assetReceipts) {
|
|
33
|
+
throw new RuntimeConfigurationError('TinyGo runtime profile overrides must provide the complete profile and receipt set', { runtimeId: 'TINYGO' });
|
|
34
|
+
}
|
|
35
|
+
const assetReceipts = Object.fromEntries(Object.entries(source.assetReceipts).map(([assetPath, receipt]) => [
|
|
36
|
+
assetPath,
|
|
37
|
+
Object.freeze(typeof receipt === 'string' ? { sha256: receipt } : { ...receipt })
|
|
38
|
+
]));
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
profileId: source.profileId,
|
|
41
|
+
protocolVersion: source.protocolVersion,
|
|
42
|
+
manifestPath: source.manifestPath,
|
|
43
|
+
manifestFingerprint: source.manifestFingerprint,
|
|
44
|
+
manifestReceipt: Object.freeze({ ...source.manifestReceipt }),
|
|
45
|
+
assetReceipts: Object.freeze(assetReceipts)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function snapshotTinyGoExecutableGraphFingerprint(config) {
|
|
49
|
+
const configuredFingerprint = config?.executableGraphFingerprint;
|
|
50
|
+
if (configuredFingerprint !== undefined &&
|
|
51
|
+
configuredFingerprint !== WASM_TINYGO_EXECUTABLE_GRAPH_PROFILE.fingerprint) {
|
|
52
|
+
throw new RuntimeConfigurationError('TinyGo executable graph overrides must match the bundled receipt profile', { phase: 'asset', runtimeId: 'TINYGO' });
|
|
53
|
+
}
|
|
54
|
+
return WASM_TINYGO_EXECUTABLE_GRAPH_PROFILE.fingerprint;
|
|
55
|
+
}
|
|
56
|
+
const abortReason = (signal, phase) => {
|
|
57
|
+
const reason = signal.reason;
|
|
58
|
+
return reason !== undefined
|
|
59
|
+
? reason
|
|
60
|
+
: new DOMException(phase === 'startup' ? 'TinyGo startup aborted' : 'TinyGo execution aborted', 'AbortError');
|
|
61
|
+
};
|
|
5
62
|
class TinyGo {
|
|
6
63
|
output = null;
|
|
7
64
|
worker = null;
|
|
8
|
-
buffer =
|
|
65
|
+
buffer = createWasmIdleSharedBuffer(1024);
|
|
9
66
|
pendingInput = [];
|
|
10
67
|
begin = 0;
|
|
11
68
|
elapse = 0;
|
|
12
69
|
uid = 0;
|
|
13
70
|
exit = true;
|
|
14
71
|
moduleUrl = '';
|
|
15
|
-
|
|
16
|
-
hostCompileUrls = [];
|
|
72
|
+
executableGraphFingerprint = '';
|
|
17
73
|
rustRuntimeBaseUrl = '';
|
|
74
|
+
oncompilerdiagnostic;
|
|
18
75
|
assetLoader = undefined;
|
|
19
|
-
|
|
76
|
+
runtimeProfile = undefined;
|
|
77
|
+
executableGraph = null;
|
|
20
78
|
runtime = null;
|
|
79
|
+
runtimeToken = null;
|
|
21
80
|
runtimePromise = null;
|
|
81
|
+
runtimePromiseToken = null;
|
|
22
82
|
loadPromise = null;
|
|
23
83
|
compiledArtifact = null;
|
|
24
84
|
compiledArtifactExecutionError = '';
|
|
25
85
|
compiledCacheKey = '';
|
|
26
|
-
activeReject = null;
|
|
27
86
|
waitingForInput = false;
|
|
28
87
|
pendingEof = false;
|
|
29
88
|
lastActivityLog = '';
|
|
@@ -32,195 +91,817 @@ class TinyGo {
|
|
|
32
91
|
runtimeProgressEnd = 0;
|
|
33
92
|
runtimeProgressValue = 0;
|
|
34
93
|
runtimeProgressAssets = new Map();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.hostCompileUrl = nextHostCompileUrls[0] || '';
|
|
62
|
-
this.hostCompileUrls = nextHostCompileUrls;
|
|
63
|
-
this.rustRuntimeBaseUrl = nextRustRuntimeBaseUrl;
|
|
64
|
-
this.assetLoader = nextAssetLoader;
|
|
65
|
-
this.assetPacks = nextAssetPacks;
|
|
94
|
+
runtimeProgressOwner = null;
|
|
95
|
+
activeOperation = null;
|
|
96
|
+
disposed = false;
|
|
97
|
+
disposePromise = null;
|
|
98
|
+
disposeCancellation = new CancelledError('TinyGo sandbox disposed', {
|
|
99
|
+
phase: 'dispose',
|
|
100
|
+
runtimeId: 'TINYGO',
|
|
101
|
+
recoverable: false
|
|
102
|
+
});
|
|
103
|
+
workerSession = new WorkerSession({
|
|
104
|
+
label: 'TinyGo',
|
|
105
|
+
onDispose: (worker) => {
|
|
106
|
+
if (this.worker === worker)
|
|
107
|
+
delete this.worker;
|
|
108
|
+
this.exit = true;
|
|
109
|
+
this.clearPendingStdin();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
disposedConfigurationError() {
|
|
113
|
+
return new RuntimeConfigurationError('TinyGo sandbox is disposed', {
|
|
114
|
+
phase: 'dispose',
|
|
115
|
+
runtimeId: 'TINYGO'
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
load(runtimeAssets = '', _code = '', _log = true, _args = [], options = {}, progress) {
|
|
119
|
+
return this.executeOperation('startup', options, async (operation) => {
|
|
66
120
|
try {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
121
|
+
this.assertOperation(operation);
|
|
122
|
+
this.clearPendingStdin();
|
|
123
|
+
const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
|
|
124
|
+
this.assertOperation(operation);
|
|
125
|
+
const nextModuleUrl = resolveTinyGoModuleUrl(runtimeAssets, currentUrl);
|
|
126
|
+
this.assertOperation(operation);
|
|
127
|
+
const nextRustCompilerUrl = resolveRustCompilerUrl(runtimeAssets, currentUrl);
|
|
128
|
+
this.assertOperation(operation);
|
|
129
|
+
const nextRustRuntimeBaseUrl = nextRustCompilerUrl
|
|
130
|
+
? new URL('./runtime/', nextRustCompilerUrl).toString()
|
|
131
|
+
: '';
|
|
132
|
+
this.assertOperation(operation);
|
|
133
|
+
let nextAssetLoader;
|
|
134
|
+
let tinyGoAssets;
|
|
135
|
+
if (typeof runtimeAssets === 'object' && runtimeAssets !== null) {
|
|
136
|
+
tinyGoAssets = runtimeAssets.tinygo;
|
|
137
|
+
this.assertOperation(operation);
|
|
138
|
+
nextAssetLoader = tinyGoAssets?.assetLoader;
|
|
139
|
+
this.assertOperation(operation);
|
|
140
|
+
}
|
|
141
|
+
const nextRuntimeProfile = snapshotTinyGoRuntimeProfile(tinyGoAssets);
|
|
142
|
+
this.assertOperation(operation);
|
|
143
|
+
const nextExecutableGraphFingerprint = snapshotTinyGoExecutableGraphFingerprint(tinyGoAssets);
|
|
144
|
+
this.assertOperation(operation);
|
|
145
|
+
if (!nextModuleUrl) {
|
|
146
|
+
throw new Error('TinyGo runtime is not configured. Set PUBLIC_WASM_TINYGO_MODULE_URL or runtimeAssets.tinygo.moduleUrl.');
|
|
72
147
|
}
|
|
148
|
+
if ((this.moduleUrl && this.moduleUrl !== nextModuleUrl) ||
|
|
149
|
+
this.rustRuntimeBaseUrl !== nextRustRuntimeBaseUrl ||
|
|
150
|
+
this.assetLoader !== nextAssetLoader ||
|
|
151
|
+
this.executableGraphFingerprint !== nextExecutableGraphFingerprint ||
|
|
152
|
+
this.runtimeProfile?.manifestFingerprint !==
|
|
153
|
+
nextRuntimeProfile.manifestFingerprint) {
|
|
154
|
+
this.disposeRuntime();
|
|
155
|
+
this.assertOperation(operation);
|
|
156
|
+
this.compiledArtifact = null;
|
|
157
|
+
this.compiledArtifactExecutionError = '';
|
|
158
|
+
this.compiledCacheKey = '';
|
|
159
|
+
}
|
|
160
|
+
this.assetLoader = nextAssetLoader;
|
|
161
|
+
this.runtimeProfile = nextRuntimeProfile;
|
|
162
|
+
this.executableGraphFingerprint = nextExecutableGraphFingerprint;
|
|
163
|
+
this.moduleUrl = nextModuleUrl;
|
|
164
|
+
this.rustRuntimeBaseUrl = nextRustRuntimeBaseUrl;
|
|
165
|
+
progress?.set?.(0.25);
|
|
166
|
+
this.assertOperation(operation);
|
|
167
|
+
await this.ensureRuntime(operation);
|
|
168
|
+
this.assertOperation(operation);
|
|
169
|
+
progress?.set?.(0.75);
|
|
170
|
+
this.assertOperation(operation);
|
|
171
|
+
await this.ensureWorker(operation);
|
|
172
|
+
this.assertOperation(operation);
|
|
73
173
|
progress?.set?.(1);
|
|
74
|
-
|
|
174
|
+
this.assertOperation(operation);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
beginOperation(phase) {
|
|
182
|
+
if (this.disposed)
|
|
183
|
+
throw this.disposedConfigurationError();
|
|
184
|
+
if (this.activeOperation) {
|
|
185
|
+
throw new BusyError('TinyGo runtime already has an active operation', {
|
|
186
|
+
runtimeId: 'TINYGO',
|
|
187
|
+
phase: this.activeOperation.phase
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const operation = {
|
|
191
|
+
token: Symbol(phase),
|
|
192
|
+
phase,
|
|
193
|
+
controller: new AbortController(),
|
|
194
|
+
cancelled: false,
|
|
195
|
+
diagnosticCount: 0,
|
|
196
|
+
outputBytes: 0,
|
|
197
|
+
hasExplicitWasmMemoryLimit: false
|
|
198
|
+
};
|
|
199
|
+
this.activeOperation = operation;
|
|
200
|
+
return operation;
|
|
201
|
+
}
|
|
202
|
+
completeOperation(operation) {
|
|
203
|
+
if (this.activeOperation?.token === operation.token) {
|
|
204
|
+
this.activeOperation = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
isOperationActive(operation) {
|
|
208
|
+
return this.activeOperation?.token === operation.token && !operation.cancelled;
|
|
209
|
+
}
|
|
210
|
+
assertOperation(operation) {
|
|
211
|
+
if (!this.isOperationActive(operation)) {
|
|
212
|
+
throw operation.reason ?? 'Process terminated';
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
snapshotExecutionLimits(operation, configured) {
|
|
216
|
+
const snapshot = {};
|
|
217
|
+
if (configured) {
|
|
218
|
+
for (const key of EXECUTION_LIMIT_KEYS) {
|
|
219
|
+
this.assertOperation(operation);
|
|
220
|
+
const enumerable = Object.prototype.propertyIsEnumerable.call(configured, key);
|
|
221
|
+
this.assertOperation(operation);
|
|
222
|
+
if (!enumerable)
|
|
223
|
+
continue;
|
|
224
|
+
const value = configured[key];
|
|
225
|
+
this.assertOperation(operation);
|
|
226
|
+
if (value !== undefined)
|
|
227
|
+
snapshot[key] = value;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
operation.hasExplicitWasmMemoryLimit = Object.prototype.hasOwnProperty.call(snapshot, 'maxWasmMemoryBytes');
|
|
231
|
+
const limits = resolveExecutionLimits(snapshot);
|
|
232
|
+
this.assertOperation(operation);
|
|
233
|
+
return limits;
|
|
234
|
+
}
|
|
235
|
+
executeOperation(phase, options, execute, snapshot) {
|
|
236
|
+
let operation;
|
|
237
|
+
try {
|
|
238
|
+
operation = this.beginOperation(phase);
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
return Promise.reject(error);
|
|
242
|
+
}
|
|
243
|
+
return new Promise((resolve, reject) => {
|
|
244
|
+
let settled = false;
|
|
245
|
+
let signal;
|
|
246
|
+
let onAbort;
|
|
247
|
+
let deadline;
|
|
248
|
+
const cleanup = () => {
|
|
249
|
+
delete operation.reject;
|
|
250
|
+
this.completeOperation(operation);
|
|
251
|
+
if (deadline !== undefined) {
|
|
252
|
+
const settledDeadline = deadline;
|
|
253
|
+
deadline = undefined;
|
|
254
|
+
try {
|
|
255
|
+
clearTimeout(settledDeadline);
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Timer cleanup must not replace the operation result.
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (signal && onAbort) {
|
|
262
|
+
try {
|
|
263
|
+
signal.removeEventListener('abort', onAbort);
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// Cleanup must not replace the operation result.
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
const resolveOperation = (value) => {
|
|
271
|
+
if (settled)
|
|
272
|
+
return;
|
|
273
|
+
settled = true;
|
|
274
|
+
cleanup();
|
|
275
|
+
resolve(value);
|
|
276
|
+
};
|
|
277
|
+
const rejectOperation = (reason) => {
|
|
278
|
+
if (settled)
|
|
279
|
+
return;
|
|
280
|
+
settled = true;
|
|
281
|
+
cleanup();
|
|
282
|
+
reject(reason);
|
|
283
|
+
};
|
|
284
|
+
operation.reject = rejectOperation;
|
|
285
|
+
try {
|
|
286
|
+
signal = options.signal;
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
rejectOperation(operation.cancelled ? operation.reason : error);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (settled)
|
|
293
|
+
return;
|
|
294
|
+
let preAborted = false;
|
|
295
|
+
try {
|
|
296
|
+
preAborted = signal?.aborted === true;
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
rejectOperation(error);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (settled)
|
|
303
|
+
return;
|
|
304
|
+
if (preAborted && signal) {
|
|
305
|
+
try {
|
|
306
|
+
rejectOperation(abortReason(signal, phase));
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
rejectOperation(error);
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
onAbort = signal
|
|
314
|
+
? () => {
|
|
315
|
+
if (!this.isOperationActive(operation))
|
|
316
|
+
return;
|
|
317
|
+
let reason;
|
|
318
|
+
try {
|
|
319
|
+
reason = abortReason(signal, phase);
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
reason = error;
|
|
323
|
+
}
|
|
324
|
+
if (this.isOperationActive(operation)) {
|
|
325
|
+
this.cancelOperation(operation, reason);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
: undefined;
|
|
329
|
+
if (signal && onAbort) {
|
|
330
|
+
try {
|
|
331
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
rejectOperation(error);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (settled)
|
|
338
|
+
return;
|
|
339
|
+
try {
|
|
340
|
+
if (signal.aborted)
|
|
341
|
+
onAbort();
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
rejectOperation(error);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (settled)
|
|
349
|
+
return;
|
|
350
|
+
let limits;
|
|
351
|
+
try {
|
|
352
|
+
const configuredLimits = options.limits;
|
|
353
|
+
if (settled)
|
|
354
|
+
return;
|
|
355
|
+
limits = this.snapshotExecutionLimits(operation, configuredLimits);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
rejectOperation(operation.cancelled ? operation.reason : error);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (settled)
|
|
362
|
+
return;
|
|
363
|
+
operation.limits = limits;
|
|
364
|
+
const timeoutMs = Math.min(MAX_TIMER_DELAY_MS, phase === 'startup'
|
|
365
|
+
? limits.assetTimeoutMs + limits.startupTimeoutMs
|
|
366
|
+
: limits.compileTimeoutMs + limits.runTimeoutMs);
|
|
367
|
+
let scheduledDeadline;
|
|
368
|
+
try {
|
|
369
|
+
scheduledDeadline = setTimeout(() => {
|
|
370
|
+
if (!this.isOperationActive(operation))
|
|
371
|
+
return;
|
|
372
|
+
const label = phase === 'startup' ? 'runtime startup' : 'execution';
|
|
373
|
+
this.cancelOperation(operation, new TimeoutError(`TinyGo ${label} timed out after ${timeoutMs} ms`, {
|
|
374
|
+
phase,
|
|
375
|
+
runtimeId: 'TINYGO',
|
|
376
|
+
timeoutMs
|
|
377
|
+
}));
|
|
378
|
+
}, timeoutMs);
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
rejectOperation(error);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (settled || !this.isOperationActive(operation)) {
|
|
385
|
+
try {
|
|
386
|
+
clearTimeout(scheduledDeadline);
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
// A synchronously settled deadline is already detached.
|
|
390
|
+
}
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
deadline = scheduledDeadline;
|
|
394
|
+
let request;
|
|
395
|
+
try {
|
|
396
|
+
this.assertOperation(operation);
|
|
397
|
+
request = snapshot ? snapshot(operation) : undefined;
|
|
75
398
|
}
|
|
76
399
|
catch (error) {
|
|
77
|
-
|
|
400
|
+
rejectOperation(operation.cancelled ? operation.reason : error);
|
|
401
|
+
return;
|
|
78
402
|
}
|
|
403
|
+
if (settled || !this.isOperationActive(operation))
|
|
404
|
+
return;
|
|
405
|
+
void Promise.resolve()
|
|
406
|
+
.then(() => {
|
|
407
|
+
this.assertOperation(operation);
|
|
408
|
+
return execute(operation, request);
|
|
409
|
+
})
|
|
410
|
+
.then((value) => {
|
|
411
|
+
if (this.isOperationActive(operation))
|
|
412
|
+
resolveOperation(value);
|
|
413
|
+
}, (error) => {
|
|
414
|
+
if (this.isOperationActive(operation))
|
|
415
|
+
rejectOperation(error);
|
|
416
|
+
});
|
|
79
417
|
});
|
|
80
418
|
}
|
|
419
|
+
emitOutput(operation, data) {
|
|
420
|
+
this.assertOperation(operation);
|
|
421
|
+
const limit = operation.limits?.maxOutputBytes ?? DEFAULT_EXECUTION_LIMITS.maxOutputBytes;
|
|
422
|
+
const actual = operation.outputBytes + OUTPUT_ENCODER.encode(data).byteLength;
|
|
423
|
+
this.assertOperation(operation);
|
|
424
|
+
if (actual > limit) {
|
|
425
|
+
operation.outputBytes = actual;
|
|
426
|
+
this.cancelOperation(operation, new OutputLimitError(`TinyGo output exceeded ${limit} bytes`, {
|
|
427
|
+
actual,
|
|
428
|
+
limit,
|
|
429
|
+
phase: 'execute',
|
|
430
|
+
runtimeId: 'TINYGO'
|
|
431
|
+
}));
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
operation.outputBytes = actual;
|
|
435
|
+
try {
|
|
436
|
+
const output = this.output;
|
|
437
|
+
this.assertOperation(operation);
|
|
438
|
+
if (output)
|
|
439
|
+
Reflect.apply(output, this, [data]);
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
if (this.isOperationActive(operation))
|
|
443
|
+
this.cancelOperation(operation, error);
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
return this.isOperationActive(operation);
|
|
447
|
+
}
|
|
448
|
+
emitCompilerDiagnostic(operation, diagnostic) {
|
|
449
|
+
this.assertOperation(operation);
|
|
450
|
+
try {
|
|
451
|
+
if (!diagnostic || typeof diagnostic !== 'object') {
|
|
452
|
+
throw new RuntimeConfigurationError('TinyGo runtime emitted an invalid compiler diagnostic', { phase: operation.phase, runtimeId: 'TINYGO' });
|
|
453
|
+
}
|
|
454
|
+
const message = diagnostic.message;
|
|
455
|
+
this.assertOperation(operation);
|
|
456
|
+
const rawSeverity = diagnostic.severity;
|
|
457
|
+
this.assertOperation(operation);
|
|
458
|
+
const rawFileName = diagnostic.fileName;
|
|
459
|
+
this.assertOperation(operation);
|
|
460
|
+
const rawLineNumber = diagnostic.lineNumber;
|
|
461
|
+
this.assertOperation(operation);
|
|
462
|
+
const rawColumnNumber = diagnostic.columnNumber;
|
|
463
|
+
this.assertOperation(operation);
|
|
464
|
+
const rawEndColumnNumber = diagnostic.endColumnNumber;
|
|
465
|
+
this.assertOperation(operation);
|
|
466
|
+
if (typeof message !== 'string' || message.length === 0) {
|
|
467
|
+
throw new RuntimeConfigurationError('TinyGo runtime emitted a compiler diagnostic without a message', { phase: operation.phase, runtimeId: 'TINYGO' });
|
|
468
|
+
}
|
|
469
|
+
const actual = operation.diagnosticCount + 1;
|
|
470
|
+
const limit = operation.limits?.maxDiagnostics ?? DEFAULT_EXECUTION_LIMITS.maxDiagnostics;
|
|
471
|
+
if (actual > limit) {
|
|
472
|
+
operation.diagnosticCount = actual;
|
|
473
|
+
this.cancelOperation(operation, new DiagnosticLimitError(`TinyGo diagnostics exceeded ${limit} messages`, {
|
|
474
|
+
actual,
|
|
475
|
+
limit,
|
|
476
|
+
phase: operation.phase,
|
|
477
|
+
runtimeId: 'TINYGO'
|
|
478
|
+
}));
|
|
479
|
+
this.assertOperation(operation);
|
|
480
|
+
}
|
|
481
|
+
operation.diagnosticCount = actual;
|
|
482
|
+
const compilerDiagnostic = {
|
|
483
|
+
message,
|
|
484
|
+
severity: rawSeverity === 'error' || rawSeverity === 'warning' ? rawSeverity : 'other',
|
|
485
|
+
lineNumber: Number.isSafeInteger(rawLineNumber) && Number(rawLineNumber) >= 0
|
|
486
|
+
? Number(rawLineNumber)
|
|
487
|
+
: 1
|
|
488
|
+
};
|
|
489
|
+
if (rawFileName === null || typeof rawFileName === 'string') {
|
|
490
|
+
compilerDiagnostic.fileName = rawFileName;
|
|
491
|
+
}
|
|
492
|
+
if (Number.isSafeInteger(rawColumnNumber) && Number(rawColumnNumber) >= 0) {
|
|
493
|
+
compilerDiagnostic.columnNumber = Number(rawColumnNumber);
|
|
494
|
+
}
|
|
495
|
+
if (Number.isSafeInteger(rawEndColumnNumber) && Number(rawEndColumnNumber) >= 0) {
|
|
496
|
+
compilerDiagnostic.endColumnNumber = Number(rawEndColumnNumber);
|
|
497
|
+
}
|
|
498
|
+
const callback = this.oncompilerdiagnostic;
|
|
499
|
+
this.assertOperation(operation);
|
|
500
|
+
if (callback)
|
|
501
|
+
Reflect.apply(callback, this, [compilerDiagnostic]);
|
|
502
|
+
this.assertOperation(operation);
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
if (this.isOperationActive(operation))
|
|
506
|
+
this.cancelOperation(operation, error);
|
|
507
|
+
this.assertOperation(operation);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
clearPendingStdin() {
|
|
511
|
+
this.pendingInput = [];
|
|
512
|
+
this.pendingEof = false;
|
|
513
|
+
this.waitingForInput = false;
|
|
514
|
+
}
|
|
81
515
|
write(input) {
|
|
516
|
+
if (this.disposed)
|
|
517
|
+
return;
|
|
82
518
|
this.pendingInput.push(input);
|
|
83
519
|
this.pendingEof = false;
|
|
84
520
|
this.flushPendingInput();
|
|
85
521
|
}
|
|
86
522
|
eof() {
|
|
523
|
+
if (this.disposed)
|
|
524
|
+
return;
|
|
87
525
|
this.pendingEof = true;
|
|
88
526
|
this.flushPendingInput();
|
|
89
527
|
}
|
|
90
528
|
flushPendingInput() {
|
|
91
529
|
if (!this.waitingForInput)
|
|
92
530
|
return;
|
|
93
|
-
|
|
531
|
+
const buffer = this.activeOperation?.buffer ?? this.buffer;
|
|
532
|
+
if (flushQueuedStdin(this.pendingInput, buffer)) {
|
|
94
533
|
this.waitingForInput = false;
|
|
95
534
|
return;
|
|
96
535
|
}
|
|
97
536
|
if (this.pendingEof) {
|
|
98
|
-
flushBufferedEof(
|
|
537
|
+
flushBufferedEof(buffer);
|
|
99
538
|
this.pendingEof = false;
|
|
100
539
|
this.waitingForInput = false;
|
|
101
540
|
}
|
|
102
541
|
}
|
|
103
|
-
async ensureWorker() {
|
|
542
|
+
async ensureWorker(operation) {
|
|
543
|
+
this.assertOperation(operation);
|
|
104
544
|
if (this.worker)
|
|
105
545
|
return;
|
|
106
|
-
|
|
107
|
-
|
|
546
|
+
const pendingLoad = this.loadPromise;
|
|
547
|
+
if (pendingLoad) {
|
|
548
|
+
await pendingLoad;
|
|
549
|
+
this.assertOperation(operation);
|
|
108
550
|
return;
|
|
109
551
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
552
|
+
const loadPromise = (async () => {
|
|
553
|
+
const WorkerConstructor = (await import('./worker/tinygo?worker'))
|
|
554
|
+
.default;
|
|
555
|
+
this.assertOperation(operation);
|
|
556
|
+
const worker = new WorkerConstructor();
|
|
557
|
+
if (!this.isOperationActive(operation)) {
|
|
558
|
+
worker.terminate();
|
|
559
|
+
this.assertOperation(operation);
|
|
560
|
+
}
|
|
561
|
+
this.worker = worker;
|
|
562
|
+
const workerLoad = this.workerSession.waitForLoad(worker, (resolve, reject) => {
|
|
563
|
+
if (!this.isOperationActive(operation) || this.worker !== worker) {
|
|
564
|
+
return reject(operation.reason ?? 'Worker not loaded');
|
|
565
|
+
}
|
|
566
|
+
worker.onmessage = (event) => {
|
|
567
|
+
if (!this.isOperationActive(operation) || this.worker !== worker)
|
|
568
|
+
return;
|
|
569
|
+
const message = event.data ?? {};
|
|
570
|
+
if (message.load) {
|
|
571
|
+
resolve();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (Object.prototype.hasOwnProperty.call(message, 'error')) {
|
|
575
|
+
reject(message.error);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
worker.postMessage({ load: true });
|
|
579
|
+
});
|
|
580
|
+
if (!this.isOperationActive(operation) || this.worker !== worker) {
|
|
581
|
+
this.workerSession.terminate(operation.reason ?? 'Worker not loaded');
|
|
582
|
+
}
|
|
583
|
+
await workerLoad;
|
|
584
|
+
this.assertOperation(operation);
|
|
585
|
+
if (this.worker !== worker)
|
|
586
|
+
throw operation.reason ?? 'Worker not loaded';
|
|
587
|
+
})();
|
|
588
|
+
this.loadPromise = loadPromise;
|
|
589
|
+
try {
|
|
590
|
+
await loadPromise;
|
|
591
|
+
}
|
|
592
|
+
finally {
|
|
593
|
+
if (this.loadPromise === loadPromise)
|
|
594
|
+
this.loadPromise = null;
|
|
595
|
+
}
|
|
132
596
|
}
|
|
133
|
-
|
|
134
|
-
this.runtime
|
|
597
|
+
detachRuntime() {
|
|
598
|
+
const runtime = this.runtime;
|
|
599
|
+
const executableGraph = this.executableGraph;
|
|
135
600
|
this.runtime = null;
|
|
601
|
+
this.executableGraph = null;
|
|
602
|
+
this.runtimeToken = null;
|
|
136
603
|
this.runtimePromise = null;
|
|
604
|
+
this.runtimePromiseToken = null;
|
|
137
605
|
this.lastActivityLog = '';
|
|
138
606
|
this.compiledArtifactExecutionError = '';
|
|
607
|
+
this.runtimeProgress = undefined;
|
|
608
|
+
this.runtimeProgressOwner = null;
|
|
609
|
+
this.runtimeProgressAssets.clear();
|
|
610
|
+
try {
|
|
611
|
+
executableGraph?.dispose();
|
|
612
|
+
}
|
|
613
|
+
catch {
|
|
614
|
+
// Executable graph cleanup must not replace the lifecycle result.
|
|
615
|
+
}
|
|
616
|
+
return runtime;
|
|
617
|
+
}
|
|
618
|
+
disposeRuntimeHooks(runtime) {
|
|
619
|
+
try {
|
|
620
|
+
runtime?.dispose?.();
|
|
621
|
+
}
|
|
622
|
+
catch {
|
|
623
|
+
// Runtime cleanup must not replace the lifecycle result.
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
disposeRuntime() {
|
|
627
|
+
this.disposeRuntimeHooks(this.detachRuntime());
|
|
139
628
|
}
|
|
140
|
-
|
|
629
|
+
reportRuntimeProgress(runtimeToken, progress) {
|
|
630
|
+
const owner = this.runtimeProgressOwner;
|
|
631
|
+
if (!owner ||
|
|
632
|
+
owner.runtimeToken !== runtimeToken ||
|
|
633
|
+
this.activeOperation?.token !== owner.operationToken ||
|
|
634
|
+
!this.runtimeProgress) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const total = progress.total && progress.total > 0 ? progress.total : progress.loaded;
|
|
638
|
+
const key = progress.assetUrl || progress.assetPath;
|
|
639
|
+
this.runtimeProgressAssets.set(key, {
|
|
640
|
+
loaded: Math.max(0, progress.loaded),
|
|
641
|
+
total: Math.max(1, total)
|
|
642
|
+
});
|
|
643
|
+
let loaded = 0;
|
|
644
|
+
let size = 0;
|
|
645
|
+
for (const entry of this.runtimeProgressAssets.values()) {
|
|
646
|
+
loaded += Math.min(entry.loaded, entry.total);
|
|
647
|
+
size += entry.total;
|
|
648
|
+
}
|
|
649
|
+
if (size <= 0)
|
|
650
|
+
return;
|
|
651
|
+
const nextValue = this.runtimeProgressStart +
|
|
652
|
+
((this.runtimeProgressEnd - this.runtimeProgressStart) * loaded) / size;
|
|
653
|
+
if (nextValue <= this.runtimeProgressValue)
|
|
654
|
+
return;
|
|
655
|
+
this.runtimeProgressValue = nextValue;
|
|
656
|
+
this.runtimeProgress.set?.(nextValue);
|
|
657
|
+
}
|
|
658
|
+
requireRuntimeAssetLimitSetter(runtime) {
|
|
659
|
+
const setMaxAssetBytes = runtime.setMaxAssetBytes;
|
|
660
|
+
if (typeof setMaxAssetBytes !== 'function') {
|
|
661
|
+
throw new RuntimeConfigurationError('TinyGo runtime module must implement setMaxAssetBytes()', { runtimeId: 'TINYGO' });
|
|
662
|
+
}
|
|
663
|
+
return (maxAssetBytes) => setMaxAssetBytes.call(runtime, maxAssetBytes);
|
|
664
|
+
}
|
|
665
|
+
async ensureRuntime(operation) {
|
|
666
|
+
this.assertOperation(operation);
|
|
141
667
|
if (this.runtime) {
|
|
142
668
|
return this.runtime;
|
|
143
669
|
}
|
|
144
|
-
|
|
145
|
-
|
|
670
|
+
const pendingRuntime = this.runtimePromise;
|
|
671
|
+
if (pendingRuntime) {
|
|
672
|
+
const runtime = await pendingRuntime;
|
|
673
|
+
this.assertOperation(operation);
|
|
674
|
+
return runtime;
|
|
146
675
|
}
|
|
147
676
|
const moduleUrl = this.moduleUrl;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (size <= 0)
|
|
172
|
-
return;
|
|
173
|
-
const nextValue = this.runtimeProgressStart +
|
|
174
|
-
((this.runtimeProgressEnd - this.runtimeProgressStart) * loaded) / size;
|
|
175
|
-
if (nextValue <= this.runtimeProgressValue)
|
|
176
|
-
return;
|
|
177
|
-
this.runtimeProgressValue = nextValue;
|
|
178
|
-
this.runtimeProgress.set?.(nextValue);
|
|
179
|
-
}
|
|
677
|
+
const runtimeToken = Symbol('runtime');
|
|
678
|
+
const runtimePromiseToken = Symbol('runtime-startup');
|
|
679
|
+
this.runtimePromiseToken = runtimePromiseToken;
|
|
680
|
+
const assetLoader = this.assetLoader;
|
|
681
|
+
const runtimeProfile = this.runtimeProfile;
|
|
682
|
+
const rustRuntimeBaseUrl = this.rustRuntimeBaseUrl;
|
|
683
|
+
const maxAssetBytes = operation.limits?.maxAssetBytes ?? DEFAULT_EXECUTION_LIMITS.maxAssetBytes;
|
|
684
|
+
const assetTimeoutMs = operation.limits?.assetTimeoutMs ?? DEFAULT_EXECUTION_LIMITS.assetTimeoutMs;
|
|
685
|
+
let nextRuntime = null;
|
|
686
|
+
let nextExecutableGraph = null;
|
|
687
|
+
const runtimePromise = (async () => {
|
|
688
|
+
try {
|
|
689
|
+
if (!runtimeProfile) {
|
|
690
|
+
throw new RuntimeConfigurationError('TinyGo runtime profile is not configured', {
|
|
691
|
+
runtimeId: 'TINYGO'
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
nextExecutableGraph = await loadVerifiedTinyGoExecutableGraph({
|
|
695
|
+
moduleUrl,
|
|
696
|
+
profile: WASM_TINYGO_EXECUTABLE_GRAPH_PROFILE,
|
|
697
|
+
signal: operation.controller.signal,
|
|
698
|
+
maxAssetBytes,
|
|
699
|
+
assetTimeoutMs
|
|
180
700
|
});
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
701
|
+
this.assertOperation(operation);
|
|
702
|
+
const executableGraph = nextExecutableGraph;
|
|
703
|
+
const runtimeModule = (await import(
|
|
704
|
+
/* @vite-ignore */ executableGraph.entryUrl));
|
|
705
|
+
this.assertOperation(operation);
|
|
706
|
+
const commonOptions = {
|
|
707
|
+
assetLoader,
|
|
708
|
+
maxAssetBytes,
|
|
709
|
+
rustRuntimeBaseUrl: rustRuntimeBaseUrl || undefined,
|
|
710
|
+
onCompilerDiagnostic: (diagnostic) => {
|
|
711
|
+
const owner = this.runtimeProgressOwner;
|
|
712
|
+
const activeOperation = this.activeOperation;
|
|
713
|
+
const runtime = this.runtime;
|
|
714
|
+
if (!owner ||
|
|
715
|
+
!activeOperation ||
|
|
716
|
+
owner.operationToken !== activeOperation.token ||
|
|
717
|
+
owner.runtimeToken !== runtimeToken ||
|
|
718
|
+
this.runtimeToken !== runtimeToken ||
|
|
719
|
+
!runtime ||
|
|
720
|
+
!this.isOperationActive(activeOperation)) {
|
|
191
721
|
return;
|
|
192
|
-
const total = progress.total && progress.total > 0 ? progress.total : progress.loaded;
|
|
193
|
-
const key = progress.assetUrl || progress.assetPath;
|
|
194
|
-
this.runtimeProgressAssets.set(key, {
|
|
195
|
-
loaded: Math.max(0, progress.loaded),
|
|
196
|
-
total: Math.max(1, total)
|
|
197
|
-
});
|
|
198
|
-
let loaded = 0;
|
|
199
|
-
let size = 0;
|
|
200
|
-
for (const entry of this.runtimeProgressAssets.values()) {
|
|
201
|
-
loaded += Math.min(entry.loaded, entry.total);
|
|
202
|
-
size += entry.total;
|
|
203
722
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
723
|
+
this.emitCompilerDiagnostic(activeOperation, diagnostic);
|
|
724
|
+
},
|
|
725
|
+
onLogAppended: (_entry) => {
|
|
726
|
+
const owner = this.runtimeProgressOwner;
|
|
727
|
+
const activeOperation = this.activeOperation;
|
|
728
|
+
const runtime = this.runtime;
|
|
729
|
+
if (!owner ||
|
|
730
|
+
!activeOperation ||
|
|
731
|
+
owner.operationToken !== activeOperation.token ||
|
|
732
|
+
owner.runtimeToken !== runtimeToken ||
|
|
733
|
+
this.runtimeToken !== runtimeToken ||
|
|
734
|
+
!runtime ||
|
|
735
|
+
!this.isOperationActive(activeOperation)) {
|
|
209
736
|
return;
|
|
210
|
-
|
|
211
|
-
this.
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
737
|
+
}
|
|
738
|
+
this.emitActivityLog(runtime, activeOperation);
|
|
739
|
+
},
|
|
740
|
+
onProgress: (progress) => this.reportRuntimeProgress(runtimeToken, progress)
|
|
741
|
+
};
|
|
742
|
+
if (typeof runtimeModule.loadTinyGoUpstreamToolchainAssets === 'function' &&
|
|
743
|
+
typeof runtimeModule.compileTinyGoInDisposableWorker === 'function') {
|
|
744
|
+
let activityLog = '';
|
|
745
|
+
let artifact = null;
|
|
746
|
+
let workspaceFiles = null;
|
|
747
|
+
let target = 'wasip1';
|
|
748
|
+
let assetLimit = maxAssetBytes;
|
|
749
|
+
let wasmMemoryLimit = DEFAULT_EXECUTION_LIMITS.maxWasmMemoryBytes;
|
|
750
|
+
let controller = null;
|
|
751
|
+
let assetsPromise = null;
|
|
752
|
+
const loadUpstreamAssets = runtimeModule.loadTinyGoUpstreamToolchainAssets;
|
|
753
|
+
const compileUpstream = runtimeModule.compileTinyGoInDisposableWorker;
|
|
754
|
+
const appendLog = (line) => {
|
|
755
|
+
activityLog += `[${new Date().toTimeString().slice(0, 8)}] ${line}\n`;
|
|
756
|
+
commonOptions.onLogAppended({ line });
|
|
757
|
+
};
|
|
758
|
+
nextRuntime = {
|
|
759
|
+
async boot() {
|
|
760
|
+
if (!assetsPromise) {
|
|
761
|
+
controller = new AbortController();
|
|
762
|
+
assetsPromise = loadUpstreamAssets({
|
|
763
|
+
assetBaseUrl: executableGraph.assetBaseUrl,
|
|
764
|
+
profile: runtimeProfile,
|
|
765
|
+
...(assetLoader ? { loader: assetLoader } : {}),
|
|
766
|
+
onProgress: commonOptions.onProgress,
|
|
767
|
+
signal: controller.signal,
|
|
768
|
+
maxAssetBytes: assetLimit
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
const pendingAssets = assetsPromise;
|
|
772
|
+
try {
|
|
773
|
+
await pendingAssets;
|
|
774
|
+
}
|
|
775
|
+
catch (error) {
|
|
776
|
+
if (assetsPromise === pendingAssets)
|
|
777
|
+
assetsPromise = null;
|
|
778
|
+
throw error;
|
|
779
|
+
}
|
|
780
|
+
appendLog('upstream TinyGo toolchain assets loaded');
|
|
781
|
+
},
|
|
782
|
+
async plan() {
|
|
783
|
+
if (!assetsPromise)
|
|
784
|
+
throw new Error('upstream TinyGo assets are not loaded');
|
|
785
|
+
appendLog('upstream TinyGo receipt validation scheduled in compiler worker');
|
|
786
|
+
return { target: 'wasip1', implementation: 'upstream-tinygo-0.40.1' };
|
|
787
|
+
},
|
|
788
|
+
async execute() {
|
|
789
|
+
if (target !== 'wasip1') {
|
|
790
|
+
throw new Error('The upstream TinyGo browser compiler supports only wasip1');
|
|
791
|
+
}
|
|
792
|
+
if (!workspaceFiles)
|
|
793
|
+
throw new Error('TinyGo workspace is not configured');
|
|
794
|
+
const assets = await assetsPromise;
|
|
795
|
+
if (!assets)
|
|
796
|
+
throw new Error('upstream TinyGo assets are not loaded');
|
|
797
|
+
controller = new AbortController();
|
|
798
|
+
const compileFiles = { ...workspaceFiles };
|
|
799
|
+
if (!Object.prototype.hasOwnProperty.call(compileFiles, 'go.mod')) {
|
|
800
|
+
compileFiles['go.mod'] =
|
|
801
|
+
'module wasm-idle.local/main\n\ngo 1.24.0\n';
|
|
802
|
+
}
|
|
803
|
+
const result = await compileUpstream(assets, { workspaceFiles: compileFiles, package: '.' }, {
|
|
804
|
+
signal: controller.signal,
|
|
805
|
+
maxWasmMemoryBytes: wasmMemoryLimit,
|
|
806
|
+
onPhase: (phase) => appendLog(`upstream TinyGo phase: ${phase}`)
|
|
807
|
+
});
|
|
808
|
+
artifact = {
|
|
809
|
+
path: '/work/program.wasm',
|
|
810
|
+
bytes: Uint8Array.from(result.wasm),
|
|
811
|
+
artifactKind: 'execution',
|
|
812
|
+
runnable: true,
|
|
813
|
+
entrypoint: '_start'
|
|
814
|
+
};
|
|
815
|
+
appendLog(`upstream TinyGo artifact ready: ${artifact.path}`);
|
|
816
|
+
},
|
|
817
|
+
reset() {
|
|
818
|
+
controller?.abort(new Error('TinyGo runtime reset'));
|
|
819
|
+
controller = null;
|
|
820
|
+
artifact = null;
|
|
821
|
+
activityLog = '';
|
|
822
|
+
},
|
|
823
|
+
readActivityLog: () => activityLog,
|
|
824
|
+
readBuildArtifact: () => artifact,
|
|
825
|
+
setBuildRequestOverrides(overrides) {
|
|
826
|
+
target = overrides?.target ?? 'wasip1';
|
|
827
|
+
},
|
|
828
|
+
setMaxAssetBytes(value) {
|
|
829
|
+
if (assetLimit !== value) {
|
|
830
|
+
controller?.abort(new Error('TinyGo asset quota changed'));
|
|
831
|
+
controller = null;
|
|
832
|
+
assetsPromise = null;
|
|
833
|
+
}
|
|
834
|
+
assetLimit = value;
|
|
835
|
+
},
|
|
836
|
+
setMaxWasmMemoryBytes(value) {
|
|
837
|
+
wasmMemoryLimit = value;
|
|
838
|
+
},
|
|
839
|
+
setWorkspaceFiles(files) {
|
|
840
|
+
workspaceFiles = files ? { ...files } : null;
|
|
841
|
+
},
|
|
842
|
+
dispose() {
|
|
843
|
+
controller?.abort(new Error('TinyGo runtime disposed'));
|
|
844
|
+
controller = null;
|
|
845
|
+
workspaceFiles = null;
|
|
846
|
+
artifact = null;
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
else if (typeof runtimeModule.createBundledTinyGoRuntime === 'function') {
|
|
851
|
+
nextRuntime = runtimeModule.createBundledTinyGoRuntime(commonOptions);
|
|
852
|
+
}
|
|
853
|
+
else if (typeof runtimeModule.createTinyGoRuntime === 'function') {
|
|
854
|
+
nextRuntime = runtimeModule.createTinyGoRuntime({
|
|
855
|
+
assetBaseUrl: executableGraph.assetBaseUrl,
|
|
856
|
+
...commonOptions
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
throw new Error('TinyGo runtime module must export createBundledTinyGoRuntime or createTinyGoRuntime');
|
|
861
|
+
}
|
|
862
|
+
this.assertOperation(operation);
|
|
863
|
+
this.requireRuntimeAssetLimitSetter(nextRuntime);
|
|
864
|
+
this.assertOperation(operation);
|
|
865
|
+
if (this.runtimePromiseToken !== runtimePromiseToken) {
|
|
866
|
+
throw operation.reason ?? 'TinyGo runtime startup superseded';
|
|
867
|
+
}
|
|
868
|
+
const runtime = nextRuntime;
|
|
869
|
+
const committedExecutableGraph = nextExecutableGraph;
|
|
870
|
+
nextRuntime = null;
|
|
871
|
+
nextExecutableGraph = null;
|
|
872
|
+
this.runtime = runtime;
|
|
873
|
+
this.executableGraph = committedExecutableGraph;
|
|
874
|
+
this.runtimeToken = runtimeToken;
|
|
875
|
+
return runtime;
|
|
215
876
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
877
|
+
finally {
|
|
878
|
+
try {
|
|
879
|
+
nextRuntime?.dispose?.();
|
|
880
|
+
}
|
|
881
|
+
catch {
|
|
882
|
+
// A stale runtime must not replace the active lifecycle result.
|
|
883
|
+
}
|
|
884
|
+
try {
|
|
885
|
+
nextExecutableGraph?.dispose();
|
|
886
|
+
}
|
|
887
|
+
catch {
|
|
888
|
+
// A stale executable graph must not replace the active lifecycle result.
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
})();
|
|
892
|
+
this.runtimePromise = runtimePromise;
|
|
893
|
+
try {
|
|
894
|
+
return await runtimePromise;
|
|
895
|
+
}
|
|
896
|
+
finally {
|
|
897
|
+
if (this.runtimePromise === runtimePromise) {
|
|
898
|
+
this.runtimePromise = null;
|
|
899
|
+
this.runtimePromiseToken = null;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
222
902
|
}
|
|
223
|
-
emitActivityLog(hooks) {
|
|
903
|
+
emitActivityLog(hooks, operation) {
|
|
904
|
+
this.assertOperation(operation);
|
|
224
905
|
const nextActivityLog = hooks.readActivityLog();
|
|
225
906
|
const delta = nextActivityLog.startsWith(this.lastActivityLog)
|
|
226
907
|
? nextActivityLog.slice(this.lastActivityLog.length)
|
|
@@ -229,8 +910,10 @@ class TinyGo {
|
|
|
229
910
|
if (!delta)
|
|
230
911
|
return;
|
|
231
912
|
const sanitized = delta.replace(ACTIVITY_PREFIX_PATTERN, '');
|
|
232
|
-
if (sanitized)
|
|
233
|
-
this.
|
|
913
|
+
if (sanitized && !this.emitOutput(operation, sanitized)) {
|
|
914
|
+
this.assertOperation(operation);
|
|
915
|
+
}
|
|
916
|
+
this.assertOperation(operation);
|
|
234
917
|
}
|
|
235
918
|
extractCompileFailure() {
|
|
236
919
|
const sanitized = this.lastActivityLog.replace(ACTIVITY_PREFIX_PATTERN, '');
|
|
@@ -245,143 +928,96 @@ class TinyGo {
|
|
|
245
928
|
}
|
|
246
929
|
return 'TinyGo compilation failed';
|
|
247
930
|
}
|
|
248
|
-
async compileArtifact(
|
|
249
|
-
|
|
931
|
+
async compileArtifact(operation, workspaceFiles, target = 'wasm', log = true, prog) {
|
|
932
|
+
this.assertOperation(operation);
|
|
933
|
+
const maxWasmMemoryBytes = operation.hasExplicitWasmMemoryLimit
|
|
934
|
+
? (operation.limits?.maxWasmMemoryBytes ?? DEFAULT_EXECUTION_LIMITS.maxWasmMemoryBytes)
|
|
935
|
+
: TINYGO_BROWSER_COMPILER_DEFAULT_MAX_WASM_MEMORY_BYTES;
|
|
250
936
|
const compileCacheKey = JSON.stringify({
|
|
251
|
-
code,
|
|
252
|
-
hostCompileUrls: this.hostCompileUrls,
|
|
253
937
|
moduleUrl: this.moduleUrl,
|
|
254
|
-
|
|
938
|
+
executableGraphFingerprint: this.executableGraphFingerprint,
|
|
939
|
+
maxAssetBytes: operation.limits?.maxAssetBytes ?? DEFAULT_EXECUTION_LIMITS.maxAssetBytes,
|
|
940
|
+
maxWasmMemoryBytes,
|
|
941
|
+
target,
|
|
942
|
+
workspaceFiles
|
|
255
943
|
});
|
|
256
944
|
if (this.compiledArtifact && this.compiledCacheKey === compileCacheKey) {
|
|
257
945
|
return;
|
|
258
946
|
}
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
hostCompileResponse = await fetch(hostCompileUrl, {
|
|
266
|
-
method: 'POST',
|
|
267
|
-
headers: {
|
|
268
|
-
'content-type': 'application/json'
|
|
269
|
-
},
|
|
270
|
-
body: JSON.stringify({
|
|
271
|
-
source: code,
|
|
272
|
-
target: hostCompileTarget
|
|
273
|
-
})
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
catch (error) {
|
|
277
|
-
unavailableHostCompileUrls.push(hostCompileUrl);
|
|
278
|
-
if (!this.moduleUrl && hostCompileUrl === this.hostCompileUrls.at(-1)) {
|
|
279
|
-
throw error;
|
|
280
|
-
}
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
if (hostCompileResponse?.ok) {
|
|
284
|
-
const payload = (await hostCompileResponse.json());
|
|
285
|
-
const artifactBase64 = payload.artifact?.bytesBase64 || '';
|
|
286
|
-
if (!payload.artifact?.path || !artifactBase64) {
|
|
287
|
-
throw new Error('TinyGo host compile did not return a wasm artifact');
|
|
288
|
-
}
|
|
289
|
-
const artifactBytes = Uint8Array.from(atob(artifactBase64), (char) => char.charCodeAt(0));
|
|
290
|
-
this.compiledArtifact = artifactBytes;
|
|
291
|
-
this.compiledArtifactExecutionError =
|
|
292
|
-
payload.artifact.runnable === false
|
|
293
|
-
? payload.artifact.artifactKind === 'probe'
|
|
294
|
-
? 'TinyGo host compile returned a non-runnable probe artifact without a supported WASI entrypoint.'
|
|
295
|
-
: payload.artifact.reason === 'bootstrap-artifact'
|
|
296
|
-
? 'TinyGo host compile returned a bootstrap artifact and cannot execute it yet.'
|
|
297
|
-
: 'TinyGo host compile returned a non-runnable artifact without a supported WASI entrypoint.'
|
|
298
|
-
: '';
|
|
299
|
-
this.compiledCacheKey = compileCacheKey;
|
|
300
|
-
prog?.set?.(0.95);
|
|
301
|
-
if (log) {
|
|
302
|
-
for (const line of payload.logs || []) {
|
|
303
|
-
this.output?.(line.endsWith('\n') ? line : `${line}\n`);
|
|
304
|
-
}
|
|
305
|
-
this.output?.(`tinygo artifact ready: ${payload.artifact.path}\n`);
|
|
306
|
-
}
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
if (hostCompileResponse &&
|
|
310
|
-
hostCompileResponse.status !== 404 &&
|
|
311
|
-
hostCompileResponse.status !== 405 &&
|
|
312
|
-
hostCompileResponse.status !== 501) {
|
|
313
|
-
let failureMessage = 'TinyGo host compile failed';
|
|
314
|
-
try {
|
|
315
|
-
const payload = await hostCompileResponse.json();
|
|
316
|
-
if (typeof payload?.error === 'string' && payload.error) {
|
|
317
|
-
failureMessage = payload.error;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
catch {
|
|
321
|
-
const responseText = await hostCompileResponse.text();
|
|
322
|
-
if (responseText.trim()) {
|
|
323
|
-
failureMessage = responseText.trim();
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
throw new Error(failureMessage);
|
|
327
|
-
}
|
|
328
|
-
if (hostCompileResponse) {
|
|
329
|
-
unavailableHostCompileUrls.push(hostCompileUrl);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
947
|
+
const runtime = await this.ensureRuntime(operation);
|
|
948
|
+
this.assertOperation(operation);
|
|
949
|
+
const runtimeToken = this.runtimeToken;
|
|
950
|
+
if (!runtimeToken || this.runtime !== runtime) {
|
|
951
|
+
throw operation.reason ?? 'TinyGo compiler runtime is not available';
|
|
332
952
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
throw new Error('TinyGo host compile endpoint is unavailable.');
|
|
338
|
-
}
|
|
339
|
-
const runtime = await this.ensureRuntime();
|
|
953
|
+
this.requireRuntimeAssetLimitSetter(runtime)(operation.limits?.maxAssetBytes ?? DEFAULT_EXECUTION_LIMITS.maxAssetBytes);
|
|
954
|
+
runtime.setMaxWasmMemoryBytes?.(maxWasmMemoryBytes);
|
|
955
|
+
this.assertOperation(operation);
|
|
340
956
|
runtime.reset();
|
|
957
|
+
this.assertOperation(operation);
|
|
341
958
|
this.lastActivityLog = runtime.readActivityLog();
|
|
342
|
-
|
|
959
|
+
this.assertOperation(operation);
|
|
960
|
+
runtime.setWorkspaceFiles(workspaceFiles);
|
|
961
|
+
this.assertOperation(operation);
|
|
343
962
|
runtime.setBuildRequestOverrides?.({ target });
|
|
963
|
+
this.assertOperation(operation);
|
|
344
964
|
this.runtimeProgress = prog;
|
|
965
|
+
this.runtimeProgressOwner = {
|
|
966
|
+
operationToken: operation.token,
|
|
967
|
+
runtimeToken
|
|
968
|
+
};
|
|
345
969
|
this.runtimeProgressAssets.clear();
|
|
346
970
|
this.runtimeProgressStart = 0.05;
|
|
347
971
|
this.runtimeProgressEnd = 0.35;
|
|
348
972
|
this.runtimeProgressValue = 0.05;
|
|
349
973
|
try {
|
|
350
974
|
prog?.set?.(0.05);
|
|
975
|
+
this.assertOperation(operation);
|
|
351
976
|
await runtime.boot();
|
|
352
|
-
this.
|
|
977
|
+
this.assertOperation(operation);
|
|
978
|
+
this.emitActivityLog(runtime, operation);
|
|
353
979
|
this.runtimeProgressAssets.clear();
|
|
354
980
|
this.runtimeProgressStart = 0.35;
|
|
355
981
|
this.runtimeProgressEnd = 0.65;
|
|
356
982
|
this.runtimeProgressValue = Math.max(this.runtimeProgressValue, 0.35);
|
|
357
983
|
prog?.set?.(this.runtimeProgressValue);
|
|
984
|
+
this.assertOperation(operation);
|
|
358
985
|
await runtime.plan();
|
|
359
|
-
this.
|
|
986
|
+
this.assertOperation(operation);
|
|
987
|
+
this.emitActivityLog(runtime, operation);
|
|
360
988
|
this.runtimeProgressAssets.clear();
|
|
361
989
|
this.runtimeProgressStart = 0.65;
|
|
362
990
|
this.runtimeProgressEnd = 0.92;
|
|
363
991
|
this.runtimeProgressValue = Math.max(this.runtimeProgressValue, 0.65);
|
|
364
992
|
prog?.set?.(this.runtimeProgressValue);
|
|
993
|
+
this.assertOperation(operation);
|
|
365
994
|
await runtime.execute();
|
|
366
|
-
this.
|
|
995
|
+
this.assertOperation(operation);
|
|
996
|
+
this.emitActivityLog(runtime, operation);
|
|
367
997
|
prog?.set?.(0.95);
|
|
998
|
+
this.assertOperation(operation);
|
|
368
999
|
}
|
|
369
1000
|
finally {
|
|
370
|
-
this.
|
|
371
|
-
|
|
1001
|
+
if (this.runtimeProgressOwner?.operationToken === operation.token &&
|
|
1002
|
+
this.runtimeProgressOwner.runtimeToken === runtimeToken) {
|
|
1003
|
+
this.runtimeProgress = undefined;
|
|
1004
|
+
this.runtimeProgressOwner = null;
|
|
1005
|
+
this.runtimeProgressAssets.clear();
|
|
1006
|
+
}
|
|
372
1007
|
}
|
|
1008
|
+
this.assertOperation(operation);
|
|
373
1009
|
const artifact = runtime.readBuildArtifact();
|
|
1010
|
+
this.assertOperation(operation);
|
|
374
1011
|
if (!artifact) {
|
|
375
1012
|
const compileFailure = this.extractCompileFailure();
|
|
376
|
-
if (/(?:probe-only|supported WASI entrypoint
|
|
377
|
-
throw new Error(
|
|
378
|
-
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime could not produce a runnable execution artifact: ${compileFailure}.`
|
|
379
|
-
: `TinyGo browser runtime could not produce a runnable execution artifact: ${compileFailure}.`);
|
|
1013
|
+
if (/(?:probe-only|supported WASI entrypoint)/i.test(compileFailure)) {
|
|
1014
|
+
throw new Error(`TinyGo browser runtime could not produce a runnable execution artifact: ${compileFailure}.`);
|
|
380
1015
|
}
|
|
381
1016
|
throw new Error(compileFailure);
|
|
382
1017
|
}
|
|
383
|
-
const
|
|
384
|
-
|
|
1018
|
+
const runtimeActivityLog = runtime.readActivityLog();
|
|
1019
|
+
this.assertOperation(operation);
|
|
1020
|
+
const runtimeLogLines = runtimeActivityLog
|
|
385
1021
|
.replace(ACTIVITY_PREFIX_PATTERN, '')
|
|
386
1022
|
.split('\n')
|
|
387
1023
|
.map((line) => line.trim())
|
|
@@ -394,122 +1030,359 @@ class TinyGo {
|
|
|
394
1030
|
break;
|
|
395
1031
|
}
|
|
396
1032
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
?
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime produced a non-runnable probe artifact without a supported WASI entrypoint.`
|
|
411
|
-
: 'TinyGo browser runtime produced a non-runnable probe artifact without a supported WASI entrypoint.'
|
|
412
|
-
: unavailableHostCompileUrls.length > 0
|
|
413
|
-
? `TinyGo host compile endpoints were unavailable: ${unavailableHostCompileUrls.join(', ')}. TinyGo browser runtime produced a non-runnable artifact without a supported WASI entrypoint.`
|
|
414
|
-
: 'TinyGo browser runtime produced a non-runnable artifact without a supported WASI entrypoint.'
|
|
415
|
-
: '';
|
|
1033
|
+
const compiledArtifact = new Uint8Array(artifact.bytes);
|
|
1034
|
+
const compiledArtifactExecutionError = artifact.runnable === false
|
|
1035
|
+
? browserRuntimeFailure !== ''
|
|
1036
|
+
? `TinyGo browser runtime could not produce a runnable execution artifact: ${browserRuntimeFailure}.`
|
|
1037
|
+
: artifact.reason === 'bootstrap-artifact'
|
|
1038
|
+
? 'TinyGo browser runtime produced a bootstrap artifact and cannot execute it yet.'
|
|
1039
|
+
: artifact.artifactKind === 'probe'
|
|
1040
|
+
? 'TinyGo browser runtime produced a non-runnable probe artifact without a supported WASI entrypoint.'
|
|
1041
|
+
: 'TinyGo browser runtime produced a non-runnable artifact without a supported WASI entrypoint.'
|
|
1042
|
+
: '';
|
|
1043
|
+
this.assertOperation(operation);
|
|
1044
|
+
this.compiledArtifact = compiledArtifact;
|
|
1045
|
+
this.compiledArtifactExecutionError = compiledArtifactExecutionError;
|
|
416
1046
|
this.compiledCacheKey = compileCacheKey;
|
|
417
1047
|
if (log) {
|
|
418
|
-
this.
|
|
1048
|
+
this.emitOutput(operation, `tinygo artifact ready: ${artifact.path}\n`);
|
|
1049
|
+
this.assertOperation(operation);
|
|
419
1050
|
}
|
|
420
1051
|
}
|
|
421
1052
|
run(code, prepare, _log = true, _prog, args = [], options = {}) {
|
|
422
|
-
this.
|
|
423
|
-
|
|
1053
|
+
return this.executeOperation('execute', options, async (operation, request) => {
|
|
1054
|
+
this.exit = false;
|
|
424
1055
|
try {
|
|
425
1056
|
this.begin = Date.now();
|
|
426
|
-
await this.
|
|
427
|
-
|
|
428
|
-
await this.compileArtifact(code, target, _log, prepare ? _prog : undefined);
|
|
1057
|
+
await this.compileArtifact(operation, request.workspaceFiles, request.target, _log, prepare ? _prog : undefined);
|
|
1058
|
+
this.assertOperation(operation);
|
|
429
1059
|
if (prepare) {
|
|
430
1060
|
this.elapse = Date.now() - this.begin;
|
|
431
1061
|
this.exit = true;
|
|
432
|
-
|
|
433
|
-
return;
|
|
1062
|
+
return true;
|
|
434
1063
|
}
|
|
435
1064
|
if (this.compiledArtifactExecutionError) {
|
|
436
1065
|
throw new Error(this.compiledArtifactExecutionError);
|
|
437
1066
|
}
|
|
1067
|
+
await this.ensureWorker(operation);
|
|
1068
|
+
this.assertOperation(operation);
|
|
438
1069
|
if (!this.worker || !this.compiledArtifact) {
|
|
439
1070
|
throw new Error('TinyGo runtime did not prepare an artifact');
|
|
440
1071
|
}
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
this.
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
1072
|
+
const worker = this.worker;
|
|
1073
|
+
const compiledArtifact = this.compiledArtifact;
|
|
1074
|
+
const buffer = request.buffer;
|
|
1075
|
+
const hasExplicitStdin = request.stdin !== undefined;
|
|
1076
|
+
if (hasExplicitStdin) {
|
|
1077
|
+
this.clearPendingStdin();
|
|
1078
|
+
}
|
|
1079
|
+
const runUid = ++this.uid;
|
|
1080
|
+
return await new Promise((resolve, reject) => {
|
|
1081
|
+
const workerOperation = this.workerSession.beginRun(worker, reject);
|
|
1082
|
+
const handleMessage = (event) => {
|
|
1083
|
+
if (!this.isOperationActive(operation) ||
|
|
1084
|
+
this.worker !== worker ||
|
|
1085
|
+
runUid !== this.uid) {
|
|
1086
|
+
if (worker.onmessage === handleMessage)
|
|
1087
|
+
worker.onmessage = null;
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const message = event.data ?? {};
|
|
1091
|
+
const hasResults = Object.prototype.hasOwnProperty.call(message, 'results');
|
|
1092
|
+
const hasError = Object.prototype.hasOwnProperty.call(message, 'error');
|
|
1093
|
+
const { output, results, error, buffer, progress } = message;
|
|
1094
|
+
if (buffer && !hasExplicitStdin) {
|
|
1095
|
+
if (!prepare) {
|
|
1096
|
+
_prog?.report?.({
|
|
1097
|
+
kind: 'ready',
|
|
1098
|
+
state: 'waiting-input',
|
|
1099
|
+
reason: 'stdin-request',
|
|
1100
|
+
label: 'TinyGo program is waiting for input'
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
this.waitingForInput = true;
|
|
1104
|
+
this.flushPendingInput();
|
|
1105
|
+
}
|
|
1106
|
+
reportWorkerProgress(_prog, progress);
|
|
1107
|
+
if (!this.isOperationActive(operation) || this.worker !== worker)
|
|
1108
|
+
return;
|
|
1109
|
+
if (output) {
|
|
1110
|
+
if (!this.emitOutput(operation, output))
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
if (hasResults) {
|
|
1114
|
+
if (worker.onmessage === handleMessage)
|
|
1115
|
+
worker.onmessage = null;
|
|
1116
|
+
this.elapse = Date.now() - this.begin;
|
|
1117
|
+
this.exit = true;
|
|
1118
|
+
this.clearPendingStdin();
|
|
1119
|
+
this.workerSession.complete(workerOperation);
|
|
1120
|
+
resolve(results);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
if (hasError) {
|
|
1124
|
+
if (worker.onmessage === handleMessage)
|
|
1125
|
+
worker.onmessage = null;
|
|
1126
|
+
this.elapse = Date.now() - this.begin;
|
|
1127
|
+
this.exit = true;
|
|
1128
|
+
this.clearPendingStdin();
|
|
1129
|
+
this.workerSession.complete(workerOperation);
|
|
1130
|
+
reject(error);
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
worker.onmessage = handleMessage;
|
|
1134
|
+
try {
|
|
1135
|
+
worker.postMessage({
|
|
1136
|
+
artifact: new Uint8Array(compiledArtifact),
|
|
1137
|
+
buffer,
|
|
1138
|
+
args: request.programArgs,
|
|
1139
|
+
log: _log,
|
|
1140
|
+
stdin: request.stdin
|
|
1141
|
+
});
|
|
463
1142
|
}
|
|
464
|
-
|
|
465
|
-
this.
|
|
466
|
-
this.exit = true;
|
|
467
|
-
this.waitingForInput = false;
|
|
468
|
-
this.pendingEof = false;
|
|
469
|
-
this.activeReject = null;
|
|
470
|
-
reject(error);
|
|
1143
|
+
catch (error) {
|
|
1144
|
+
this.workerSession.terminate(error);
|
|
471
1145
|
}
|
|
472
|
-
};
|
|
473
|
-
this.worker.postMessage({
|
|
474
|
-
artifact: new Uint8Array(this.compiledArtifact),
|
|
475
|
-
buffer: this.buffer,
|
|
476
|
-
args: programArgs,
|
|
477
|
-
log: _log
|
|
478
1146
|
});
|
|
479
1147
|
}
|
|
480
1148
|
catch (error) {
|
|
481
|
-
this.
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
1149
|
+
if (this.isOperationActive(operation)) {
|
|
1150
|
+
this.elapse = Date.now() - this.begin;
|
|
1151
|
+
this.exit = true;
|
|
1152
|
+
this.clearPendingStdin();
|
|
1153
|
+
throw error instanceof Error ? error.message : String(error);
|
|
1154
|
+
}
|
|
1155
|
+
throw error;
|
|
1156
|
+
}
|
|
1157
|
+
}, (operation) => {
|
|
1158
|
+
this.assertOperation(operation);
|
|
1159
|
+
if (typeof code !== 'string') {
|
|
1160
|
+
throw new TypeError('TinyGo source code must be a string');
|
|
1161
|
+
}
|
|
1162
|
+
const configuredTarget = options.tinygoTarget;
|
|
1163
|
+
this.assertOperation(operation);
|
|
1164
|
+
const target = configuredTarget ?? 'wasip1';
|
|
1165
|
+
if (!TINYGO_TARGETS.has(target)) {
|
|
1166
|
+
throw new TypeError('TinyGo target must be wasm, wasip1, wasip2, or wasip3');
|
|
1167
|
+
}
|
|
1168
|
+
const workspaceLimitsSource = options.workspaceLimits;
|
|
1169
|
+
this.assertOperation(operation);
|
|
1170
|
+
let workspaceLimits = {};
|
|
1171
|
+
if (workspaceLimitsSource !== undefined) {
|
|
1172
|
+
if (workspaceLimitsSource === null ||
|
|
1173
|
+
typeof workspaceLimitsSource !== 'object' ||
|
|
1174
|
+
Array.isArray(workspaceLimitsSource)) {
|
|
1175
|
+
throw new TypeError('TinyGo workspace limits must be an object');
|
|
1176
|
+
}
|
|
1177
|
+
const maxFiles = workspaceLimitsSource.maxFiles;
|
|
1178
|
+
this.assertOperation(operation);
|
|
1179
|
+
const maxFileBytes = workspaceLimitsSource.maxFileBytes;
|
|
1180
|
+
this.assertOperation(operation);
|
|
1181
|
+
const maxTotalBytes = workspaceLimitsSource.maxTotalBytes;
|
|
1182
|
+
this.assertOperation(operation);
|
|
1183
|
+
const maxPathBytes = workspaceLimitsSource.maxPathBytes;
|
|
1184
|
+
this.assertOperation(operation);
|
|
1185
|
+
const caseSensitive = workspaceLimitsSource.caseSensitive;
|
|
1186
|
+
this.assertOperation(operation);
|
|
1187
|
+
workspaceLimits = {
|
|
1188
|
+
maxFiles,
|
|
1189
|
+
maxFileBytes,
|
|
1190
|
+
maxTotalBytes,
|
|
1191
|
+
maxPathBytes,
|
|
1192
|
+
caseSensitive
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
for (const name of [
|
|
1196
|
+
'maxFiles',
|
|
1197
|
+
'maxFileBytes',
|
|
1198
|
+
'maxTotalBytes',
|
|
1199
|
+
'maxPathBytes'
|
|
1200
|
+
]) {
|
|
1201
|
+
const value = workspaceLimits[name];
|
|
1202
|
+
if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {
|
|
1203
|
+
throw new WorkspaceValidationError('invalid-limit', `Workspace limit ${name} must be a non-negative safe integer`);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
if (workspaceLimits.caseSensitive !== undefined &&
|
|
1207
|
+
typeof workspaceLimits.caseSensitive !== 'boolean') {
|
|
1208
|
+
throw new WorkspaceValidationError('invalid-limit', 'Workspace limit caseSensitive must be a boolean');
|
|
1209
|
+
}
|
|
1210
|
+
const workspaceFilesSource = options.workspaceFiles;
|
|
1211
|
+
this.assertOperation(operation);
|
|
1212
|
+
const sourceFiles = workspaceFilesSource ?? [];
|
|
1213
|
+
if (!Array.isArray(sourceFiles)) {
|
|
1214
|
+
throw new TypeError('TinyGo workspace files must be an array');
|
|
1215
|
+
}
|
|
1216
|
+
const workspaceFileCount = sourceFiles.length;
|
|
1217
|
+
this.assertOperation(operation);
|
|
1218
|
+
const maxFiles = workspaceLimits.maxFiles ?? DEFAULT_WORKSPACE_LIMITS.maxFiles;
|
|
1219
|
+
if (workspaceFileCount > maxFiles) {
|
|
1220
|
+
throw new WorkspaceValidationError('file-count-limit', `Workspace contains ${workspaceFileCount} files; limit is ${maxFiles}`, { limit: maxFiles, actual: workspaceFileCount });
|
|
1221
|
+
}
|
|
1222
|
+
const workspaceFiles = [];
|
|
1223
|
+
for (let index = 0; index < workspaceFileCount; index += 1) {
|
|
1224
|
+
const file = sourceFiles[index];
|
|
1225
|
+
this.assertOperation(operation);
|
|
1226
|
+
if (file === null || typeof file !== 'object') {
|
|
1227
|
+
throw new TypeError('TinyGo workspace file must be an object');
|
|
1228
|
+
}
|
|
1229
|
+
const path = file.path;
|
|
1230
|
+
this.assertOperation(operation);
|
|
1231
|
+
const content = file.content;
|
|
1232
|
+
this.assertOperation(operation);
|
|
1233
|
+
if (typeof path !== 'string') {
|
|
1234
|
+
throw new TypeError('TinyGo workspace file path must be a string');
|
|
1235
|
+
}
|
|
1236
|
+
if (typeof content !== 'string') {
|
|
1237
|
+
throw new TypeError(`TinyGo workspace file ${path} must contain a string`);
|
|
1238
|
+
}
|
|
1239
|
+
workspaceFiles.push({ path, content });
|
|
1240
|
+
}
|
|
1241
|
+
const configuredActivePath = options.activePath;
|
|
1242
|
+
this.assertOperation(operation);
|
|
1243
|
+
const activePath = configuredActivePath ?? 'main.go';
|
|
1244
|
+
const maxWorkspaceBytes = operation.limits?.maxWorkspaceBytes ??
|
|
1245
|
+
DEFAULT_EXECUTION_LIMITS.maxWorkspaceBytes;
|
|
1246
|
+
const workspace = validateExecutionWorkspace(code, workspaceFiles, activePath, {
|
|
1247
|
+
...workspaceLimits,
|
|
1248
|
+
maxFileBytes: Math.min(workspaceLimits.maxFileBytes ?? DEFAULT_WORKSPACE_LIMITS.maxFileBytes, maxWorkspaceBytes),
|
|
1249
|
+
maxTotalBytes: Math.min(workspaceLimits.maxTotalBytes ?? DEFAULT_WORKSPACE_LIMITS.maxTotalBytes, maxWorkspaceBytes)
|
|
1250
|
+
});
|
|
1251
|
+
this.assertOperation(operation);
|
|
1252
|
+
if (workspace.activePath !== 'main.go') {
|
|
1253
|
+
throw new RuntimeConfigurationError('TinyGo runtime currently requires activePath to be main.go', { phase: 'execute', runtimeId: 'TINYGO' });
|
|
487
1254
|
}
|
|
1255
|
+
const runtimeWorkspace = Object.fromEntries([
|
|
1256
|
+
['main.go', code],
|
|
1257
|
+
...workspace.workspaceFiles.map((file) => [file.path, file.content])
|
|
1258
|
+
]);
|
|
1259
|
+
const configuredProgramArgs = options.programArgs;
|
|
1260
|
+
this.assertOperation(operation);
|
|
1261
|
+
const sourceArgs = configuredProgramArgs ?? args;
|
|
1262
|
+
if (!Array.isArray(sourceArgs)) {
|
|
1263
|
+
throw new TypeError('TinyGo program arguments must be an array');
|
|
1264
|
+
}
|
|
1265
|
+
const argCount = sourceArgs.length;
|
|
1266
|
+
this.assertOperation(operation);
|
|
1267
|
+
const programArgs = [];
|
|
1268
|
+
for (let index = 0; index < argCount; index += 1) {
|
|
1269
|
+
const argument = sourceArgs[index];
|
|
1270
|
+
this.assertOperation(operation);
|
|
1271
|
+
if (typeof argument !== 'string') {
|
|
1272
|
+
throw new TypeError(`TinyGo program argument ${index} must be a string`);
|
|
1273
|
+
}
|
|
1274
|
+
programArgs.push(argument);
|
|
1275
|
+
}
|
|
1276
|
+
const stdin = options.stdin;
|
|
1277
|
+
this.assertOperation(operation);
|
|
1278
|
+
if (stdin !== undefined && typeof stdin !== 'string') {
|
|
1279
|
+
throw new TypeError('TinyGo stdin must be a string');
|
|
1280
|
+
}
|
|
1281
|
+
const buffer = this.buffer;
|
|
1282
|
+
this.assertOperation(operation);
|
|
1283
|
+
operation.buffer = buffer;
|
|
1284
|
+
return { buffer, programArgs, stdin, target, workspaceFiles: runtimeWorkspace };
|
|
488
1285
|
});
|
|
489
1286
|
}
|
|
1287
|
+
resetOwnedBuffers(operationBuffer) {
|
|
1288
|
+
const buffers = new Set([this.buffer]);
|
|
1289
|
+
if (operationBuffer)
|
|
1290
|
+
buffers.add(operationBuffer);
|
|
1291
|
+
for (const buffer of buffers) {
|
|
1292
|
+
try {
|
|
1293
|
+
resetBufferedStdin(buffer);
|
|
1294
|
+
}
|
|
1295
|
+
catch {
|
|
1296
|
+
// Stdin cleanup must not replace the lifecycle result.
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
cancelOperation(operation, reason) {
|
|
1301
|
+
if (!this.isOperationActive(operation))
|
|
1302
|
+
return;
|
|
1303
|
+
operation.cancelled = true;
|
|
1304
|
+
operation.reason = reason;
|
|
1305
|
+
try {
|
|
1306
|
+
operation.controller.abort(reason);
|
|
1307
|
+
}
|
|
1308
|
+
catch {
|
|
1309
|
+
// Cancellation must continue even if AbortController cleanup fails.
|
|
1310
|
+
}
|
|
1311
|
+
const reject = operation.reject;
|
|
1312
|
+
this.completeOperation(operation);
|
|
1313
|
+
this.uid += 1;
|
|
1314
|
+
this.clearPendingStdin();
|
|
1315
|
+
this.exit = true;
|
|
1316
|
+
this.loadPromise = null;
|
|
1317
|
+
this.runtimeProgress = undefined;
|
|
1318
|
+
this.runtimeProgressOwner = null;
|
|
1319
|
+
this.runtimeProgressAssets.clear();
|
|
1320
|
+
this.compiledArtifact = null;
|
|
1321
|
+
this.compiledArtifactExecutionError = '';
|
|
1322
|
+
this.compiledCacheKey = '';
|
|
1323
|
+
this.resetOwnedBuffers(operation.buffer);
|
|
1324
|
+
this.workerSession.terminate(reason);
|
|
1325
|
+
this.disposeRuntime();
|
|
1326
|
+
reject?.(reason);
|
|
1327
|
+
}
|
|
490
1328
|
kill() {
|
|
491
1329
|
this.terminate();
|
|
492
1330
|
}
|
|
493
|
-
terminate() {
|
|
494
|
-
this.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
1331
|
+
terminate(reason = 'Process terminated') {
|
|
1332
|
+
if (this.disposed)
|
|
1333
|
+
return;
|
|
1334
|
+
const operation = this.activeOperation;
|
|
1335
|
+
if (operation) {
|
|
1336
|
+
this.cancelOperation(operation, reason);
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
this.clearPendingStdin();
|
|
498
1340
|
this.uid += 1;
|
|
499
|
-
this.
|
|
500
|
-
|
|
1341
|
+
this.resetOwnedBuffers();
|
|
1342
|
+
this.workerSession.terminate(reason);
|
|
501
1343
|
this.exit = true;
|
|
502
1344
|
}
|
|
503
1345
|
async clear() {
|
|
504
|
-
this.
|
|
505
|
-
|
|
506
|
-
this.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
1346
|
+
if (this.disposed)
|
|
1347
|
+
return;
|
|
1348
|
+
this.terminate();
|
|
1349
|
+
this.loadPromise = null;
|
|
1350
|
+
this.disposeRuntime();
|
|
1351
|
+
this.compiledArtifact = null;
|
|
1352
|
+
this.compiledArtifactExecutionError = '';
|
|
1353
|
+
this.compiledCacheKey = '';
|
|
1354
|
+
}
|
|
1355
|
+
dispose() {
|
|
1356
|
+
if (this.disposePromise)
|
|
1357
|
+
return this.disposePromise;
|
|
1358
|
+
this.disposed = true;
|
|
1359
|
+
this.disposePromise = Promise.resolve();
|
|
1360
|
+
const operation = this.activeOperation;
|
|
1361
|
+
const runtime = this.detachRuntime();
|
|
1362
|
+
delete this.worker;
|
|
1363
|
+
this.moduleUrl = '';
|
|
1364
|
+
this.executableGraphFingerprint = '';
|
|
1365
|
+
this.rustRuntimeBaseUrl = '';
|
|
1366
|
+
this.assetLoader = undefined;
|
|
1367
|
+
this.runtimeProfile = undefined;
|
|
1368
|
+
this.output = undefined;
|
|
1369
|
+
this.oncompilerdiagnostic = undefined;
|
|
1370
|
+
this.loadPromise = null;
|
|
1371
|
+
this.compiledArtifact = null;
|
|
1372
|
+
this.compiledArtifactExecutionError = '';
|
|
1373
|
+
this.compiledCacheKey = '';
|
|
1374
|
+
this.clearPendingStdin();
|
|
1375
|
+
this.resetOwnedBuffers(operation?.buffer);
|
|
1376
|
+
if (operation) {
|
|
1377
|
+
this.cancelOperation(operation, this.disposeCancellation);
|
|
1378
|
+
}
|
|
1379
|
+
else {
|
|
1380
|
+
this.uid += 1;
|
|
1381
|
+
this.workerSession.terminate(this.disposeCancellation);
|
|
1382
|
+
this.exit = true;
|
|
512
1383
|
}
|
|
1384
|
+
this.disposeRuntimeHooks(runtime);
|
|
1385
|
+
return this.disposePromise;
|
|
513
1386
|
}
|
|
514
1387
|
}
|
|
515
1388
|
export default TinyGo;
|