@wasm-oj/server 0.2.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.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -0
  3. package/THIRD_PARTY_NOTICES.md +302 -0
  4. package/crates/runtime-core/Cargo.lock +5099 -0
  5. package/crates/runtime-core/Cargo.toml +66 -0
  6. package/crates/runtime-core/README.md +47 -0
  7. package/crates/runtime-core/src/bin/wasm-oj-compiler.rs +418 -0
  8. package/crates/runtime-core/src/bin/wasm-oj-runner.rs +294 -0
  9. package/crates/runtime-core/src/capabilities.rs +118 -0
  10. package/crates/runtime-core/src/compiler.rs +658 -0
  11. package/crates/runtime-core/src/contract.rs +5 -0
  12. package/crates/runtime-core/src/deterministic.rs +1051 -0
  13. package/crates/runtime-core/src/error.rs +58 -0
  14. package/crates/runtime-core/src/filesystem.rs +547 -0
  15. package/crates/runtime-core/src/filesystem_quota.rs +167 -0
  16. package/crates/runtime-core/src/go_compiler_session.rs +297 -0
  17. package/crates/runtime-core/src/interactive.rs +1019 -0
  18. package/crates/runtime-core/src/judge_package.rs +1539 -0
  19. package/crates/runtime-core/src/lib.rs +98 -0
  20. package/crates/runtime-core/src/memory.rs +84 -0
  21. package/crates/runtime-core/src/meter.rs +549 -0
  22. package/crates/runtime-core/src/module_imports.rs +149 -0
  23. package/crates/runtime-core/src/module_policy.rs +714 -0
  24. package/crates/runtime-core/src/output.rs +204 -0
  25. package/crates/runtime-core/src/run/mod.rs +208 -0
  26. package/crates/runtime-core/src/run/native.rs +260 -0
  27. package/crates/runtime-core/src/run/web.rs +229 -0
  28. package/crates/runtime-core/src/run/web_runtime.rs +109 -0
  29. package/crates/runtime-core/src/types.rs +268 -0
  30. package/crates/runtime-core/src/web.rs +83 -0
  31. package/dist/chunks/go-toolchain-Dbt-lp2L.js +426 -0
  32. package/dist/chunks/java-toolchain-DajoRCHu.js +44 -0
  33. package/dist/chunks/python-toolchain-Dx834o2A.js +4 -0
  34. package/dist/chunks/rust-toolchain-CJ3sMxPE.js +252 -0
  35. package/dist/chunks/toolchains-C6KuA1yM.js +224 -0
  36. package/dist/go-stage.mjs +193 -0
  37. package/dist/index.d.ts +221 -0
  38. package/dist/index.js +4393 -0
  39. package/dist/java-stage.mjs +111 -0
  40. package/dist/python-stage.mjs +90 -0
  41. package/dist/rustc-stage.mjs +301 -0
  42. package/dist/server-build-stage.mjs +2564 -0
  43. package/dist/server-runner-stage.mjs +155 -0
  44. package/licenses/fflate-MIT.txt +21 -0
  45. package/licenses/runtime-core-dependencies.html +6253 -0
  46. package/licenses/runtime-core-dependencies.json +3041 -0
  47. package/licenses/wasmer-sdk-MIT.txt +21 -0
  48. package/licenses/wasmer-sdk-dependencies.html +6901 -0
  49. package/licenses/wasmer-sdk-dependencies.json +3013 -0
  50. package/package.json +70 -0
  51. package/rust-toolchain.toml +5 -0
  52. package/testdata/wojjdg02-v2-text.hex +1 -0
  53. package/vendor/shared-buffer/Cargo.toml +22 -0
  54. package/vendor/shared-buffer/LICENSE_APACHE.md +176 -0
  55. package/vendor/shared-buffer/LICENSE_MIT.md +25 -0
  56. package/vendor/shared-buffer/README.md +34 -0
  57. package/vendor/shared-buffer/src/lib.rs +58 -0
  58. package/vendor/shared-buffer/src/mmap.rs +250 -0
  59. package/vendor/shared-buffer/src/owned.rs +389 -0
  60. package/vendor/virtual-fs/Cargo.toml +181 -0
  61. package/vendor/virtual-fs/LICENSE +25 -0
  62. package/vendor/virtual-fs/src/arc_box_file.rs +142 -0
  63. package/vendor/virtual-fs/src/arc_file.rs +182 -0
  64. package/vendor/virtual-fs/src/arc_fs.rs +68 -0
  65. package/vendor/virtual-fs/src/buffer_file.rs +103 -0
  66. package/vendor/virtual-fs/src/builder.rs +232 -0
  67. package/vendor/virtual-fs/src/combine_file.rs +101 -0
  68. package/vendor/virtual-fs/src/cow_file.rs +345 -0
  69. package/vendor/virtual-fs/src/dual_write_file.rs +113 -0
  70. package/vendor/virtual-fs/src/empty_fs.rs +81 -0
  71. package/vendor/virtual-fs/src/filesystems.rs +108 -0
  72. package/vendor/virtual-fs/src/host_fs.rs +1390 -0
  73. package/vendor/virtual-fs/src/lib.rs +782 -0
  74. package/vendor/virtual-fs/src/limiter.rs +252 -0
  75. package/vendor/virtual-fs/src/mem_fs/file.rs +1799 -0
  76. package/vendor/virtual-fs/src/mem_fs/file_opener.rs +941 -0
  77. package/vendor/virtual-fs/src/mem_fs/filesystem.rs +2134 -0
  78. package/vendor/virtual-fs/src/mem_fs/mod.rs +245 -0
  79. package/vendor/virtual-fs/src/mem_fs/offloaded_file.rs +474 -0
  80. package/vendor/virtual-fs/src/mem_fs/stdio.rs +318 -0
  81. package/vendor/virtual-fs/src/mount_fs.rs +2225 -0
  82. package/vendor/virtual-fs/src/null_file.rs +87 -0
  83. package/vendor/virtual-fs/src/ops.rs +364 -0
  84. package/vendor/virtual-fs/src/overlay_fs.rs +2216 -0
  85. package/vendor/virtual-fs/src/passthru_fs.rs +119 -0
  86. package/vendor/virtual-fs/src/pipe.rs +603 -0
  87. package/vendor/virtual-fs/src/random_file.rs +88 -0
  88. package/vendor/virtual-fs/src/special_file.rs +108 -0
  89. package/vendor/virtual-fs/src/static_file.rs +133 -0
  90. package/vendor/virtual-fs/src/static_fs.rs +460 -0
  91. package/vendor/virtual-fs/src/tmp_fs.rs +95 -0
  92. package/vendor/virtual-fs/src/trace_fs.rs +258 -0
  93. package/vendor/virtual-fs/src/webc_volume_fs.rs +829 -0
  94. package/vendor/virtual-fs/src/zero_file.rs +90 -0
@@ -0,0 +1,111 @@
1
+ import { C as JAVA_COMPILE_CLASSLIB_ASSET_PATH, E as JAVA_RUNTIME_CLASSLIB_SHA256, S as JAVA_COMPILER_PACKAGE_SHA256, T as JAVA_RUNTIME_CLASSLIB_ASSET_PATH, b as JAVA_COMPILER_COMPRESSED_PACKAGE_SHA256, w as JAVA_COMPILE_CLASSLIB_SHA256, y as JAVA_COMPILER_ASSET_PATH } from "./chunks/toolchains-C6KuA1yM.js";
2
+ import { n as javaMainClass, r as parseJavaDiagnostics, t as JAVA_COMPILE_TIMEOUT_MS } from "./chunks/java-toolchain-DajoRCHu.js";
3
+ import { writeFileSync } from "node:fs";
4
+ import { readFile } from "node:fs/promises";
5
+ import { createHash } from "node:crypto";
6
+ import path from "node:path";
7
+ import { gunzipSync } from "node:zlib";
8
+ import { Directory, Runtime, Wasmer, init } from "@wasmer/sdk/node";
9
+ //#region src/server/java-stage.mjs
10
+ var runtime;
11
+ var packageHandle;
12
+ var project;
13
+ var toolchain;
14
+ var exitCode = 0;
15
+ try {
16
+ const encoded = JSON.parse(await readStdin());
17
+ if (encoded.request?.entry === void 0) throw new Error("The Java compiler stage received no entry file.");
18
+ await init({ log: "error" });
19
+ runtime = new Runtime({ registry: null });
20
+ const compilerBytes = await loadCompiler(requiredToolchainAsset(encoded, JAVA_COMPILER_ASSET_PATH), encoded.verifiedToolchain === true);
21
+ packageHandle = await Wasmer.fromFile(compilerBytes, runtime);
22
+ const command = packageHandle.commands["java-compiler"];
23
+ if (!command) throw new Error("The pinned Java compiler package does not expose java-compiler.");
24
+ project = new Directory(Object.fromEntries(encoded.request.files.map((file) => [`/${file.path}`, file.content])));
25
+ await project.createDir("/build");
26
+ toolchain = new Directory({
27
+ "/compile-classlib-teavm.bin": await loadRaw(requiredToolchainAsset(encoded, JAVA_COMPILE_CLASSLIB_ASSET_PATH), JAVA_COMPILE_CLASSLIB_SHA256, encoded.verifiedToolchain === true),
28
+ "/runtime-classlib-teavm.bin": await loadRaw(requiredToolchainAsset(encoded, JAVA_RUNTIME_CLASSLIB_ASSET_PATH), JAVA_RUNTIME_CLASSLIB_SHA256, encoded.verifiedToolchain === true)
29
+ });
30
+ const entrySource = encoded.request.files.find((file) => file.path === encoded.request.entry);
31
+ if (!entrySource) throw new Error(`Java entry '${encoded.request.entry}' does not exist.`);
32
+ const output = await withTimeout((await command.run({
33
+ args: [
34
+ "/toolchain/compile-classlib-teavm.bin",
35
+ "/toolchain/runtime-classlib-teavm.bin",
36
+ javaMainClass(encoded.request.entry, entrySource.content),
37
+ "/project/build/app.wasm",
38
+ ...encoded.request.files.filter((file) => file.path.endsWith(".java")).map((file) => `/project/${file.path}`)
39
+ ],
40
+ mount: {
41
+ "/project": project,
42
+ "/toolchain": toolchain
43
+ }
44
+ })).wait(), JAVA_COMPILE_TIMEOUT_MS);
45
+ const diagnostics = parseJavaDiagnostics(`${output.stderr}\n${output.stdout}`, encoded.request.entry);
46
+ let wasmBase64;
47
+ if (output.ok) {
48
+ const wasm = await project.readFile("/build/app.wasm");
49
+ await WebAssembly.compile(wasm);
50
+ wasmBase64 = Buffer.from(wasm).toString("base64");
51
+ }
52
+ writeResult({
53
+ success: output.ok && typeof wasmBase64 === "string",
54
+ wasmBase64,
55
+ stdout: output.stdout,
56
+ stderr: output.stderr,
57
+ diagnostics
58
+ });
59
+ } catch (error) {
60
+ writeResult(void 0, error instanceof Error ? error.message : String(error));
61
+ exitCode = 1;
62
+ } finally {
63
+ toolchain?.free();
64
+ project?.free();
65
+ packageHandle?.free();
66
+ runtime?.free();
67
+ setTimeout(() => process.exit(exitCode), 10);
68
+ }
69
+ async function loadCompiler(file, verified) {
70
+ const compressed = await readFile(file);
71
+ if (!verified) verifyDigest(file, compressed, JAVA_COMPILER_COMPRESSED_PACKAGE_SHA256);
72
+ const bytes = new Uint8Array(gunzipSync(compressed));
73
+ if (!verified) verifyDigest(file, bytes, JAVA_COMPILER_PACKAGE_SHA256);
74
+ return bytes;
75
+ }
76
+ async function loadRaw(file, expected, verified) {
77
+ const bytes = new Uint8Array(await readFile(file));
78
+ if (!verified) verifyDigest(file, bytes, expected);
79
+ return bytes;
80
+ }
81
+ function requiredToolchainAsset(encoded, assetPath) {
82
+ const file = encoded?.toolchainAssets?.[assetPath];
83
+ if (typeof file !== "string" || !path.isAbsolute(file)) throw new Error(`The Java compiler stage did not receive absolute asset '${assetPath}'.`);
84
+ return file;
85
+ }
86
+ function verifyDigest(label, bytes, expected) {
87
+ const actual = createHash("sha256").update(bytes).digest("hex");
88
+ if (actual !== expected) throw new Error(`Pinned Java asset '${label}' has digest ${actual}; expected ${expected}.`);
89
+ }
90
+ function withTimeout(promise, timeoutMs) {
91
+ let timer;
92
+ return Promise.race([promise, new Promise((_, reject) => {
93
+ timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Java compilation exceeded ${timeoutMs} ms.`)), timeoutMs);
94
+ })]).finally(() => clearTimeout(timer));
95
+ }
96
+ function writeResult(result, error) {
97
+ writeFileSync(3, JSON.stringify(result ? {
98
+ ok: true,
99
+ result
100
+ } : {
101
+ ok: false,
102
+ error
103
+ }));
104
+ }
105
+ async function readStdin() {
106
+ const chunks = [];
107
+ for await (const chunk of process.stdin) chunks.push(chunk);
108
+ return Buffer.concat(chunks).toString("utf8");
109
+ }
110
+ //#endregion
111
+ export {};
@@ -0,0 +1,90 @@
1
+ import { A as PYTHON_PACKAGE_ASSET_PATH, O as PYTHON_COMPRESSED_PACKAGE_SHA256, j as PYTHON_PACKAGE_SHA256, k as PYTHON_PACKAGE } from "./chunks/toolchains-C6KuA1yM.js";
2
+ import { t as PYTHON_COMPILE_TIMEOUT_MS } from "./chunks/python-toolchain-Dx834o2A.js";
3
+ import { writeFileSync } from "node:fs";
4
+ import { readFile } from "node:fs/promises";
5
+ import { createHash } from "node:crypto";
6
+ import path from "node:path";
7
+ import { gunzipSync } from "node:zlib";
8
+ import { Directory, Runtime, Wasmer, init } from "@wasmer/sdk/node";
9
+ //#region src/server/python-stage.mjs
10
+ var runtime;
11
+ var exitCode = 0;
12
+ try {
13
+ const encoded = JSON.parse(await readStdin());
14
+ await init({ log: "warn" });
15
+ runtime = new Runtime({ registry: null });
16
+ const pythonFiles = encoded.request.files.filter((file) => file.path.endsWith(".py"));
17
+ const project = new Directory(Object.fromEntries(encoded.request.files.map((file) => [`/${file.path}`, file.content])));
18
+ await project.createDir("/build");
19
+ const packagePath = encoded?.toolchainAssets?.[PYTHON_PACKAGE_ASSET_PATH];
20
+ if (typeof packagePath !== "string" || !path.isAbsolute(packagePath)) throw new Error(`The Python compiler stage did not receive absolute asset '${PYTHON_PACKAGE_ASSET_PATH}'.`);
21
+ const compressed = await readFile(packagePath);
22
+ if (encoded.verifiedToolchain !== true) verifyDigest(packagePath, compressed, PYTHON_COMPRESSED_PACKAGE_SHA256);
23
+ const packageBytes = uint8View(gunzipSync(compressed));
24
+ if (encoded.verifiedToolchain !== true) verifyDigest(packagePath, packageBytes, PYTHON_PACKAGE_SHA256);
25
+ const command = (await Wasmer.fromFile(packageBytes, runtime)).commands.python;
26
+ if (!command) throw new Error(`Package '${PYTHON_PACKAGE}' does not expose python.`);
27
+ const instance = await command.run({
28
+ args: ["-c", compileScript(pythonFiles.map((file) => file.path))],
29
+ cwd: "/project",
30
+ env: {
31
+ PYTHONHOME: "/usr/local",
32
+ PYTHONHASHSEED: "0",
33
+ PYTHONDONTWRITEBYTECODE: "1"
34
+ },
35
+ mount: { "/project": project }
36
+ });
37
+ let timer;
38
+ const output = await Promise.race([instance.wait(), new Promise((_, reject) => {
39
+ timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Python compilation exceeded ${PYTHON_COMPILE_TIMEOUT_MS} ms.`)), PYTHON_COMPILE_TIMEOUT_MS);
40
+ })]);
41
+ clearTimeout(timer);
42
+ const bytecodeBase64 = {};
43
+ if (output.ok) for (const file of pythonFiles) {
44
+ const compiledPath = `build/${file.path.replace(/\.py$/, ".pyc")}`;
45
+ bytecodeBase64[compiledPath] = Buffer.from(await project.readFile(`/${compiledPath}`)).toString("base64");
46
+ }
47
+ writeFileSync(3, JSON.stringify({
48
+ ok: true,
49
+ result: {
50
+ success: output.ok,
51
+ bytecodeBase64,
52
+ stdout: output.stdout,
53
+ stderr: output.stderr,
54
+ diagnostics: []
55
+ }
56
+ }));
57
+ } catch (error) {
58
+ writeFileSync(3, JSON.stringify({
59
+ ok: false,
60
+ error: error instanceof Error ? error.message : String(error)
61
+ }));
62
+ exitCode = 1;
63
+ } finally {
64
+ runtime?.free();
65
+ setTimeout(() => process.exit(exitCode), 10);
66
+ }
67
+ function verifyDigest(filename, bytes, expected) {
68
+ const actual = createHash("sha256").update(bytes).digest("hex");
69
+ if (actual !== expected) throw new Error(`Pinned Python package '${filename}' has digest ${actual}; expected ${expected}.`);
70
+ }
71
+ function uint8View(bytes) {
72
+ return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
73
+ }
74
+ function compileScript(files) {
75
+ return [
76
+ "import pathlib, py_compile",
77
+ `files = ${JSON.stringify(files)}`,
78
+ "for name in files:",
79
+ " output = pathlib.Path('/project/build') / pathlib.Path(name).with_suffix('.pyc')",
80
+ " output.parent.mkdir(parents=True, exist_ok=True)",
81
+ " py_compile.compile('/project/' + name, cfile=str(output), doraise=True, invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH)"
82
+ ].join("\n");
83
+ }
84
+ async function readStdin() {
85
+ const chunks = [];
86
+ for await (const chunk of process.stdin) chunks.push(chunk);
87
+ return Buffer.concat(chunks).toString("utf8");
88
+ }
89
+ //#endregion
90
+ export {};
@@ -0,0 +1,301 @@
1
+ import { a as deterministicRustLinkerEnvironment, c as RUST_FINAL_OUTPUT_PATH, d as instantiateRustLinkerArguments, f as MountedOutputStabilityObserver, i as deterministicRustCompilerEnvironment, l as RUST_LINKER_COMMAND, n as RUST_TOOLCHAIN, o as rustcDependencyArguments, r as decodeRustToolchainManifest, s as rustcObjectArguments, t as RUST_COMPILE_TIMEOUT_MS, u as RUST_OBJECT_PATH } from "./chunks/rust-toolchain-CJ3sMxPE.js";
2
+ import { writeFileSync } from "node:fs";
3
+ import { readFile } from "node:fs/promises";
4
+ import { createHash } from "node:crypto";
5
+ import path from "node:path";
6
+ import { gunzipSync } from "node:zlib";
7
+ import { Directory, Runtime, Wasmer, init } from "@wasmer/sdk/node";
8
+ //#region src/compiler/rust-allocator-bitcode.ts
9
+ var ALLOCATOR_BITCODE_BASENAME = /^main\.[a-z0-9]+\.rcgu\.bc$/i;
10
+ function selectRustAllocatorBitcodeName(names) {
11
+ const matches = names.filter((name) => ALLOCATOR_BITCODE_BASENAME.test(name)).sort();
12
+ if (matches.length > 1) throw new Error(`rustc emitted multiple allocator bitcode modules: ${matches.join(", ")}.`);
13
+ return matches[0];
14
+ }
15
+ function isLlvmBitcode(bytes) {
16
+ if (bytes.byteLength < 4) return false;
17
+ const rawBitcode = bytes[0] === 66 && bytes[1] === 67 && bytes[2] === 192 && bytes[3] === 222;
18
+ const bitcodeWrapper = bytes[0] === 222 && bytes[1] === 192 && bytes[2] === 23 && bytes[3] === 11;
19
+ return rawBitcode || bitcodeWrapper;
20
+ }
21
+ //#endregion
22
+ //#region src/server/rustc-stage.mjs
23
+ var OUTPUT_QUIET_PERIOD_MS = 50;
24
+ var runtime;
25
+ var pkg;
26
+ var rustc;
27
+ var linker;
28
+ var work;
29
+ var exitCode = 0;
30
+ try {
31
+ const encoded = JSON.parse(await readStdin());
32
+ await init({ log: "warn" });
33
+ runtime = new Runtime({ registry: null });
34
+ const [packageBytes, manifest] = await Promise.all([loadRustPackage(requiredToolchainAsset(encoded, RUST_TOOLCHAIN.packageAsset), encoded.verifiedToolchain === true), loadRustManifest(requiredToolchainAsset(encoded, RUST_TOOLCHAIN.manifestAsset), encoded.verifiedToolchain === true)]);
35
+ pkg = await Wasmer.fromFile(packageBytes, runtime);
36
+ rustc = pkg.commands.rustc;
37
+ if (!rustc) throw new Error("The pinned Rust WebC does not expose its rustc command.");
38
+ linker = pkg.commands[RUST_LINKER_COMMAND];
39
+ if (!linker) throw new Error(`The pinned Rust WebC does not expose its ${RUST_LINKER_COMMAND} command.`);
40
+ work = new Directory(Object.fromEntries(encoded.request.files.map((file) => [`/${file.path}`, file.content])));
41
+ await work.createDir("/build");
42
+ await work.createDir("/build/deps");
43
+ let dependencyStdout = "";
44
+ let dependencyStderr = "";
45
+ let dependencyFailed = false;
46
+ for (const dependency of encoded.request.dependencies ?? []) {
47
+ const output = await runObservedStage({
48
+ command: rustc,
49
+ args: rustcDependencyArguments(dependency, encoded.request.optimization),
50
+ env: deterministicRustCompilerEnvironment(),
51
+ work,
52
+ outputPath: dependency.outputPath,
53
+ stage: `rustc dependency ${dependency.id}`,
54
+ hasTerminalError: (stderr) => parseRustDiagnostics(stderr, encoded.request.entry).some((diagnostic) => diagnostic.severity === "error"),
55
+ outputValidator: isRustArchive
56
+ });
57
+ dependencyStdout += output.stdout;
58
+ dependencyStderr += output.stderr;
59
+ if (!output.success) {
60
+ dependencyFailed = true;
61
+ break;
62
+ }
63
+ }
64
+ if (dependencyFailed) writeResult({
65
+ success: false,
66
+ stdout: dependencyStdout,
67
+ stderr: dependencyStderr,
68
+ diagnostics: parseRustDiagnostics(dependencyStderr, encoded.request.entry)
69
+ });
70
+ else {
71
+ const compiled = await runObservedStage({
72
+ command: rustc,
73
+ args: rustcObjectArguments(encoded.request.entry, encoded.request.optimization, encoded.request.rootExterns),
74
+ env: deterministicRustCompilerEnvironment(),
75
+ work,
76
+ outputPath: RUST_OBJECT_PATH,
77
+ stage: "rustc",
78
+ hasTerminalError: (stderr) => parseRustDiagnostics(stderr, encoded.request.entry).some((diagnostic) => diagnostic.severity === "error"),
79
+ requiresAllocatorBitcode: true
80
+ });
81
+ const diagnostics = parseRustDiagnostics(`${dependencyStderr}${compiled.stderr}`, encoded.request.entry);
82
+ if (!compiled.success) writeResult({
83
+ success: false,
84
+ stdout: `${dependencyStdout}${compiled.stdout}`,
85
+ stderr: `${dependencyStderr}${compiled.stderr}`,
86
+ diagnostics
87
+ });
88
+ else {
89
+ const linkerArguments = instantiateRustLinkerArguments(manifest.linkerArguments, encoded.request.optimization, requireAllocatorBitcodePath(compiled));
90
+ const objectIndex = linkerArguments.indexOf(RUST_OBJECT_PATH);
91
+ if (objectIndex < 0) throw new Error("Pinned Rust linker arguments omit the submission object.");
92
+ const libraries = [...encoded.request.dependencies ?? []].reverse().map((item) => item.outputPath);
93
+ if (libraries.length > 0) linkerArguments.splice(objectIndex + 1, 0, ...libraries);
94
+ const linked = await runObservedStage({
95
+ command: linker,
96
+ args: linkerArguments,
97
+ env: deterministicRustLinkerEnvironment(),
98
+ work,
99
+ outputPath: RUST_FINAL_OUTPUT_PATH,
100
+ stage: "wasm-ld",
101
+ hasTerminalError: (stderr) => /(?:wasm-ld|lld): error:/i.test(stderr)
102
+ });
103
+ writeResult({
104
+ success: linked.success && Boolean(linked.bytes),
105
+ wasmBase64: linked.bytes ? Buffer.from(linked.bytes).toString("base64") : void 0,
106
+ stdout: `${dependencyStdout}${compiled.stdout}${linked.stdout}`,
107
+ stderr: `${dependencyStderr}${compiled.stderr}${linked.stderr}`,
108
+ diagnostics
109
+ });
110
+ }
111
+ }
112
+ } catch (error) {
113
+ writeFileSync(3, JSON.stringify({
114
+ ok: false,
115
+ error: error instanceof Error ? error.message : String(error)
116
+ }));
117
+ exitCode = 1;
118
+ } finally {
119
+ work?.free();
120
+ rustc?.free();
121
+ linker?.free();
122
+ pkg?.free();
123
+ runtime?.free();
124
+ setTimeout(() => process.exit(exitCode), 10);
125
+ }
126
+ function writeResult(result) {
127
+ writeFileSync(3, JSON.stringify({
128
+ ok: true,
129
+ result
130
+ }));
131
+ }
132
+ async function runObservedStage({ command, args, env, work, outputPath, stage, hasTerminalError, requiresAllocatorBitcode = false, outputValidator = (bytes) => WebAssembly.validate(bytes) }) {
133
+ const instance = await command.run({
134
+ args,
135
+ env,
136
+ mount: { "/work": work },
137
+ cwd: "/work"
138
+ });
139
+ const stdout = captureReadable(instance.stdout);
140
+ const stderr = captureReadable(instance.stderr);
141
+ const outputStability = new MountedOutputStabilityObserver();
142
+ let allocatorStability = new MountedOutputStabilityObserver();
143
+ let allocatorCandidatePath;
144
+ const deadline = performance.now() + RUST_COMPILE_TIMEOUT_MS;
145
+ try {
146
+ while (performance.now() < deadline) {
147
+ const stderrText = stderr.text();
148
+ const quiet = stdout.quietFor(OUTPUT_QUIET_PERIOD_MS) && stderr.quietFor(OUTPUT_QUIET_PERIOD_MS);
149
+ const observedAt = performance.now();
150
+ const bytes = outputStability.observe(await readValidOutput(work, outputPath, outputValidator), observedAt);
151
+ const allocator = requiresAllocatorBitcode ? await readRustAllocatorBitcode(work) : void 0;
152
+ if (allocator?.path !== allocatorCandidatePath) {
153
+ allocatorCandidatePath = allocator?.path;
154
+ allocatorStability = new MountedOutputStabilityObserver();
155
+ }
156
+ const allocatorBytes = requiresAllocatorBitcode ? allocatorStability.observe(allocator?.bytes, observedAt) : void 0;
157
+ if (bytes && (!requiresAllocatorBitcode || Boolean(allocatorBytes && allocatorCandidatePath)) && quiet) {
158
+ await new Promise((resolve) => setTimeout(resolve, 0));
159
+ return {
160
+ success: true,
161
+ bytes,
162
+ allocatorBitcodePath: allocatorCandidatePath,
163
+ stdout: stdout.text(),
164
+ stderr: stderr.text()
165
+ };
166
+ }
167
+ if (quiet && hasTerminalError(stderrText)) return {
168
+ success: false,
169
+ stdout: stdout.text(),
170
+ stderr: stderrText
171
+ };
172
+ await new Promise((resolve) => setTimeout(resolve, 5));
173
+ }
174
+ throw new Error(`${stage} exceeded ${RUST_COMPILE_TIMEOUT_MS} ms.`);
175
+ } finally {
176
+ await Promise.all([stdout.cancel(), stderr.cancel()]);
177
+ instance.free();
178
+ }
179
+ }
180
+ function requireAllocatorBitcodePath(observation) {
181
+ if (!observation.allocatorBitcodePath) throw new Error("rustc completed without its allocator bitcode module.");
182
+ return observation.allocatorBitcodePath;
183
+ }
184
+ function captureReadable(stream) {
185
+ const reader = stream.getReader();
186
+ const chunks = [];
187
+ let lastUpdate = performance.now();
188
+ (async () => {
189
+ try {
190
+ while (true) {
191
+ const result = await reader.read();
192
+ if (result.done) return;
193
+ const bytes = result.value instanceof Uint8Array ? result.value : new Uint8Array(result.value);
194
+ chunks.push(bytes.slice());
195
+ lastUpdate = performance.now();
196
+ }
197
+ } catch {}
198
+ })();
199
+ return {
200
+ text: () => new TextDecoder().decode(concatenate(chunks)),
201
+ quietFor: (milliseconds) => performance.now() - lastUpdate >= milliseconds,
202
+ cancel: async () => {
203
+ try {
204
+ await reader.cancel();
205
+ } catch {}
206
+ }
207
+ };
208
+ }
209
+ function concatenate(chunks) {
210
+ const output = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.byteLength, 0));
211
+ let offset = 0;
212
+ for (const chunk of chunks) {
213
+ output.set(chunk, offset);
214
+ offset += chunk.byteLength;
215
+ }
216
+ return output;
217
+ }
218
+ async function readValidOutput(work, guestPath, validator) {
219
+ const mountRelativePath = guestPath.startsWith("/work/") ? guestPath.slice(5) : guestPath;
220
+ try {
221
+ const bytes = (await work.readFile(mountRelativePath)).slice();
222
+ return bytes.byteLength > 8 && validator(bytes) ? bytes : void 0;
223
+ } catch {
224
+ return;
225
+ }
226
+ }
227
+ function isRustArchive(bytes) {
228
+ return bytes.byteLength > 8 && new TextDecoder().decode(bytes.subarray(0, 8)) === "!<arch>\n";
229
+ }
230
+ async function readRustAllocatorBitcode(work) {
231
+ try {
232
+ const name = selectRustAllocatorBitcodeName((await work.readDir("/build")).map((entry) => entry.name));
233
+ if (!name) return void 0;
234
+ const bytes = (await work.readFile(`/build/${name}`)).slice();
235
+ return isLlvmBitcode(bytes) ? {
236
+ path: `/work/build/${name}`,
237
+ bytes
238
+ } : void 0;
239
+ } catch (error) {
240
+ if (error instanceof Error && error.message.startsWith("rustc emitted multiple")) throw error;
241
+ return;
242
+ }
243
+ }
244
+ async function loadRustPackage(file, verifiedToolchain) {
245
+ const compressed = await readFile(file);
246
+ if (!verifiedToolchain) verifyDigest(file, compressed, RUST_TOOLCHAIN.packageCompressedSha256);
247
+ const bytes = uint8View(gunzipSync(compressed));
248
+ if (!verifiedToolchain) verifyDigest("decompressed Rust WebC", bytes, RUST_TOOLCHAIN.packageSha256);
249
+ return bytes;
250
+ }
251
+ async function loadRustManifest(file, verifiedToolchain) {
252
+ const bytes = new Uint8Array(await readFile(file));
253
+ if (!verifiedToolchain) verifyDigest(file, bytes, RUST_TOOLCHAIN.manifestSha256);
254
+ return decodeRustToolchainManifest(bytes);
255
+ }
256
+ function requiredToolchainAsset(encoded, assetPath) {
257
+ const file = encoded?.toolchainAssets?.[assetPath];
258
+ if (typeof file !== "string" || !path.isAbsolute(file)) throw new Error(`The Rust compiler stage did not receive absolute asset '${assetPath}'.`);
259
+ return file;
260
+ }
261
+ function verifyDigest(filename, bytes, expected) {
262
+ const actual = createHash("sha256").update(bytes).digest("hex");
263
+ if (actual !== expected) throw new Error(`Pinned Rust toolchain asset '${filename}' has digest ${actual}; expected ${expected}.`);
264
+ }
265
+ function uint8View(bytes) {
266
+ return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
267
+ }
268
+ async function readStdin() {
269
+ const chunks = [];
270
+ for await (const chunk of process.stdin) chunks.push(chunk);
271
+ return Buffer.concat(chunks).toString("utf8");
272
+ }
273
+ function parseRustDiagnostics(output, entry) {
274
+ const diagnostics = [];
275
+ for (const line of output.split(/\r?\n/)) {
276
+ if (!line.startsWith("{")) continue;
277
+ let value;
278
+ try {
279
+ value = JSON.parse(line);
280
+ } catch {
281
+ continue;
282
+ }
283
+ if (value?.$message_type !== "diagnostic" || typeof value.message !== "string") continue;
284
+ const spans = Array.isArray(value.spans) ? value.spans : [];
285
+ const location = spans.find((span) => span?.is_primary) ?? spans[0];
286
+ diagnostics.push({
287
+ severity: value.level === "warning" ? "warning" : value.level === "note" ? "info" : "error",
288
+ message: value.message,
289
+ file: String(location?.file_name ?? entry).replace(/^\/work\//, ""),
290
+ line: Number(location?.line_start ?? 1),
291
+ column: Number(location?.column_start ?? 1),
292
+ endLine: location?.line_end,
293
+ endColumn: location?.column_end,
294
+ source: "rustc",
295
+ code: value.code?.code
296
+ });
297
+ }
298
+ return diagnostics;
299
+ }
300
+ //#endregion
301
+ export {};