@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,2564 @@
1
+ import { A as PYTHON_PACKAGE_ASSET_PATH, B as TYPESCRIPT_VERSION, C as JAVA_COMPILE_CLASSLIB_ASSET_PATH, H as toolchainPackageIdentities, M as QUICKJS_PACKAGE, R as RUST_VERSION, T as JAVA_RUNTIME_CLASSLIB_ASSET_PATH, V as toolchainContentIdentity, a as CLANG_PACKAGE_ASSET_PATH, i as CLANG_LIBCXX_PCH_MANIFEST_SHA256, k as PYTHON_PACKAGE, n as CLANG_CC1_PINS_SHA256, o as CLANG_PACKAGE_SHA256, r as CLANG_LIBCXX_PCH_MANIFEST_ASSET_PATH, s as CLANG_VERSION, t as CLANG_CC1_PINS_ASSET_PATH, v as GO_VERSION, y as JAVA_COMPILER_ASSET_PATH, z as TYPESCRIPT_ASSET_PATH } from "./chunks/toolchains-C6KuA1yM.js";
2
+ import { f as MountedOutputStabilityObserver, n as RUST_TOOLCHAIN, t as RUST_COMPILE_TIMEOUT_MS } from "./chunks/rust-toolchain-CJ3sMxPE.js";
3
+ import { _ as pythonDependencyFiles, g as npmDependencyFiles, h as goDependencyInput, i as GO_TOOLCHAIN, m as cppDependencyInput, n as GO_COMPILE_TIMEOUT_MS, p as assertProjectDependencyEcosystem, v as rustDependencyInput } from "./chunks/go-toolchain-Dbt-lp2L.js";
4
+ import { n as javaMainClass, t as JAVA_COMPILE_TIMEOUT_MS } from "./chunks/java-toolchain-DajoRCHu.js";
5
+ import { t as PYTHON_COMPILE_TIMEOUT_MS } from "./chunks/python-toolchain-Dx834o2A.js";
6
+ import { constants, writeFileSync } from "node:fs";
7
+ import { deserialize, serialize } from "node:v8";
8
+ import { access, lstat, mkdtemp, open, readFile, rm, writeFile } from "node:fs/promises";
9
+ import { spawn } from "node:child_process";
10
+ import { createHash } from "node:crypto";
11
+ import os from "node:os";
12
+ import path from "node:path";
13
+ import { gunzipSync } from "node:zlib";
14
+ import { Runtime, init } from "@wasmer/sdk/node";
15
+ import { assertCompilerCacheKey, assertValidProject, toolchainAssetSource, toolchainCacheIdentity, toolchainProfileSource, validateServerToolchainSources } from "@wasm-oj/core";
16
+ import { WASM_OJ_CONTRACT_VERSION, WASM_OJ_SCHEMAS, assertLanguageIdentifier, isBuiltinLanguage } from "@wasm-oj/contracts";
17
+ import { Directory as Directory$1, Wasmer as Wasmer$1 } from "@wasmer/sdk";
18
+ import { fileURLToPath } from "node:url";
19
+ //#region src/core/project-files.ts
20
+ var PROJECT_SOURCE_LIMITS = Object.freeze({
21
+ files: 256,
22
+ bytesPerFile: 4194304,
23
+ totalBytes: 16777216
24
+ });
25
+ var UTF8_ENCODER = new TextEncoder();
26
+ /** Locale-independent ordering used anywhere file order can affect build output. */
27
+ function compareCanonicalPaths(left, right) {
28
+ return left < right ? -1 : left > right ? 1 : 0;
29
+ }
30
+ function assertSafeRelativePath(path, label = "Project path") {
31
+ if (typeof path !== "string" || !path || path !== path.trim() || path.length > 4096) throw new Error(`${label} must be a non-empty, trimmed string of at most 4096 characters.`);
32
+ if (path.startsWith("/") || path.includes("\\") || path.includes("\0") || path.split("/").some((segment) => !segment || segment === "." || segment === "..")) throw new Error(`${label} '${path}' must be a normalized relative path that cannot escape the project.`);
33
+ }
34
+ /**
35
+ * Validates a project file set and returns a fresh, locale-independently sorted
36
+ * array. Build hosts must use this order for filesystem creation and argv.
37
+ */
38
+ function canonicalProjectFiles(files) {
39
+ if (!Array.isArray(files) || files.length === 0) throw new Error("A project must contain at least one source file.");
40
+ if (files.length > PROJECT_SOURCE_LIMITS.files) throw new Error(`A project cannot contain more than ${PROJECT_SOURCE_LIMITS.files} source files.`);
41
+ const seen = /* @__PURE__ */ new Set();
42
+ let totalBytes = 0;
43
+ return files.map((file, index) => {
44
+ if (!file || typeof file !== "object") throw new Error(`Project file ${index} is invalid.`);
45
+ assertSafeRelativePath(file.path, `Project file ${index} path`);
46
+ assertLanguageIdentifier(file.language);
47
+ if (typeof file.content !== "string") throw new Error(`Project file '${file.path}' content must be a string.`);
48
+ if (file.content.length > PROJECT_SOURCE_LIMITS.bytesPerFile) throw new Error(`Project file '${file.path}' exceeds the ${PROJECT_SOURCE_LIMITS.bytesPerFile} byte source limit.`);
49
+ const contentBytes = UTF8_ENCODER.encode(file.content).byteLength;
50
+ if (contentBytes > PROJECT_SOURCE_LIMITS.bytesPerFile) throw new Error(`Project file '${file.path}' exceeds the ${PROJECT_SOURCE_LIMITS.bytesPerFile} byte source limit.`);
51
+ totalBytes += contentBytes;
52
+ if (totalBytes > PROJECT_SOURCE_LIMITS.totalBytes) throw new Error(`Project sources exceed the ${PROJECT_SOURCE_LIMITS.totalBytes} byte total limit.`);
53
+ if (seen.has(file.path)) throw new Error(`Duplicate project path '${file.path}'.`);
54
+ seen.add(file.path);
55
+ return {
56
+ path: file.path,
57
+ language: file.language,
58
+ content: file.content
59
+ };
60
+ }).sort((left, right) => compareCanonicalPaths(left.path, right.path));
61
+ }
62
+ function canonicalFileEntries(files) {
63
+ if (!files || typeof files !== "object" || Array.isArray(files)) throw new Error("Runtime bundle files must be a record.");
64
+ return Object.entries(files).map(([path, contents]) => {
65
+ assertSafeRelativePath(path, "Runtime bundle path");
66
+ return [path, contents];
67
+ }).sort(([left], [right]) => compareCanonicalPaths(left, right));
68
+ }
69
+ function canonicalFileRecord(files) {
70
+ return Object.fromEntries(canonicalFileEntries(files));
71
+ }
72
+ //#endregion
73
+ //#region src/core/sha256.ts
74
+ async function sha256Hex(value) {
75
+ const source = typeof value === "string" ? new TextEncoder().encode(value) : value;
76
+ const bytes = new Uint8Array(source.byteLength);
77
+ bytes.set(source);
78
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
79
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
80
+ }
81
+ //#endregion
82
+ //#region src/core/dependencies.ts
83
+ var MIB = 1048576;
84
+ /** Contract-level admission limits shared by dependency hosts and compilers. */
85
+ var DEPENDENCY_RESOLUTION_LIMITS = Object.freeze({
86
+ requirements: 128,
87
+ sourceFiles: 128,
88
+ sourceTextBytes: 8 * MIB,
89
+ hosts: 32,
90
+ roots: 512,
91
+ packages: 512,
92
+ referencesPerPackage: 512,
93
+ concurrency: 16,
94
+ metadataBytes: 8 * MIB,
95
+ packageBytes: 256 * MIB,
96
+ totalDownloadBytes: 512 * MIB,
97
+ archiveFiles: 16384,
98
+ unpackedBytes: 512 * MIB
99
+ });
100
+ Object.freeze({
101
+ packages: DEPENDENCY_RESOLUTION_LIMITS.packages,
102
+ filesPerPackage: DEPENDENCY_RESOLUTION_LIMITS.archiveFiles,
103
+ bytesPerFile: 64 * MIB,
104
+ totalBytes: DEPENDENCY_RESOLUTION_LIMITS.unpackedBytes
105
+ });
106
+ //#endregion
107
+ //#region src/compiler/clang-pins.ts
108
+ var decoder$3 = new TextDecoder();
109
+ async function decodeClangPins(bytes) {
110
+ const digest = await sha256Hex(bytes);
111
+ if (digest !== "66c4604dccd3f89d8e1472bf4432367d7396cce4a01279b1a1db445f229dba72") throw new Error(`The pinned cc1 manifest drifted from its contract: expected ${CLANG_CC1_PINS_SHA256}, received ${digest}. Regenerate it with scripts/pin-clang-cc1-argv.mjs and update CLANG_CC1_PINS_SHA256.`);
112
+ const parsed = JSON.parse(decoder$3.decode(bytes));
113
+ if (parsed.schema !== WASM_OJ_SCHEMAS.clangPins) throw new Error(`Unsupported cc1 pin schema '${parsed.schema}'.`);
114
+ for (const key of [
115
+ "input",
116
+ "output",
117
+ "mainFileName",
118
+ "objects"
119
+ ]) if (typeof parsed.placeholders?.[key] !== "string") throw new Error(`The cc1 pin manifest is missing the '${key}' placeholder.`);
120
+ if (!parsed.command || !parsed.linkerCommand) throw new Error("The cc1 pin manifest is missing a compiler or linker command.");
121
+ if (!parsed.source || !/^[a-f0-9]{64}$/.test(parsed.sourceSha256)) throw new Error("The cc1 pin manifest is missing its source toolchain identity.");
122
+ for (const [key, config] of Object.entries(parsed.configs)) if (!Array.isArray(config.cc1) || !Array.isArray(config.link) || config.cc1[0] !== "-cc1") throw new Error(`The cc1 pin manifest entry '${key}' is malformed.`);
123
+ return parsed;
124
+ }
125
+ function instantiateClangCc1(template, placeholders, source, objectPath) {
126
+ const basename = source.slice(source.lastIndexOf("/") + 1);
127
+ const inputPath = source.startsWith("/") ? source : `/project/${source}`;
128
+ return template.map((token) => {
129
+ if (token === placeholders.input) return inputPath;
130
+ if (token === placeholders.output) return objectPath;
131
+ if (token === placeholders.mainFileName) return basename;
132
+ return token;
133
+ });
134
+ }
135
+ function instantiateClangPch(template, placeholders, header, outputPath) {
136
+ return instantiateClangCc1(template.map((token) => token === "-emit-obj" ? "-emit-pch" : token === "c++" ? "c++-header" : token), placeholders, header, outputPath);
137
+ }
138
+ function instantiateClangLink(template, placeholders, objectPaths, outputPath) {
139
+ const argv = [];
140
+ for (const token of template) if (token === placeholders.objects) argv.push(...objectPaths);
141
+ else if (token === placeholders.output) argv.push(outputPath);
142
+ else argv.push(token);
143
+ return argv;
144
+ }
145
+ //#endregion
146
+ //#region src/compiler/incremental-build-graph.ts
147
+ var BUILD_NODE_KINDS = Object.freeze([
148
+ "source",
149
+ "header",
150
+ "package",
151
+ "pch",
152
+ "object",
153
+ "link-result"
154
+ ]);
155
+ /**
156
+ * Content-addressed source → header/package → PCH/object → link-result graph.
157
+ *
158
+ * Logical manifests remember which inputs a tool actually observed. Reuse
159
+ * rehashes every input and derives the structural node key again; no timestamp
160
+ * or host path participates in identity.
161
+ */
162
+ var IncrementalBuildGraph = class {
163
+ limitBytes;
164
+ logical = /* @__PURE__ */ new Map();
165
+ nodes = /* @__PURE__ */ new Map();
166
+ blobs = /* @__PURE__ */ new Map();
167
+ storedBytes = 0;
168
+ generation = 0;
169
+ constructor(limitBytes) {
170
+ if (!Number.isSafeInteger(limitBytes) || limitBytes <= 0) throw new RangeError("Incremental build graph limit must be a positive safe integer.");
171
+ this.limitBytes = limitBytes;
172
+ }
173
+ async lookup(logicalKey, availableInputs) {
174
+ const manifest = this.logical.get(logicalKey);
175
+ if (!manifest) return void 0;
176
+ const inputs = [];
177
+ for (const dependency of manifest.dependencies) {
178
+ const input = availableInputs.get(dependency.identity);
179
+ if (!input || input.kind !== dependency.kind) return void 0;
180
+ inputs.push(input);
181
+ }
182
+ return this.lookupExact(manifest.kind, logicalKey, inputs);
183
+ }
184
+ async lookupExact(kind, logicalKey, inputs) {
185
+ const key = await structuralKey(kind, logicalKey, (await this.internInputs(inputs)).map((item) => item.key));
186
+ const node = this.nodes.get(key);
187
+ if (!node) return void 0;
188
+ const blob = this.blobs.get(node.digest);
189
+ if (!blob) return void 0;
190
+ this.blobs.delete(node.digest);
191
+ this.blobs.set(node.digest, blob);
192
+ return blob.slice();
193
+ }
194
+ async store(kind, logicalKey, inputs, output) {
195
+ if (output.byteLength > this.limitBytes) return false;
196
+ const canonicalInputs = canonicalizeInputs(inputs);
197
+ const dependencies = await this.internInputs(canonicalInputs);
198
+ const key = await structuralKey(kind, logicalKey, dependencies.map((item) => item.key));
199
+ const bytes = output.slice();
200
+ const digest = await sha256Hex(bytes);
201
+ const previousManifest = this.logical.get(logicalKey);
202
+ const previousNode = previousManifest ? this.nodes.get(previousManifest.nodeKey) : void 0;
203
+ let changed = false;
204
+ if (previousNode && (previousNode.key !== key || previousNode.digest !== digest)) {
205
+ this.logical.delete(logicalKey);
206
+ this.nodes.delete(previousNode.key);
207
+ if (![...this.logical.values()].some((manifest) => this.nodes.get(manifest.nodeKey)?.digest === previousNode.digest)) {
208
+ const removed = this.blobs.get(previousNode.digest);
209
+ if (removed) {
210
+ this.blobs.delete(previousNode.digest);
211
+ this.storedBytes -= removed.byteLength;
212
+ }
213
+ }
214
+ changed = true;
215
+ }
216
+ changed = this.ensureCapacity(bytes.byteLength, digest) || changed;
217
+ if (!this.blobs.has(digest)) {
218
+ this.blobs.set(digest, bytes);
219
+ this.storedBytes += bytes.byteLength;
220
+ changed = true;
221
+ }
222
+ const nextNode = {
223
+ key,
224
+ kind,
225
+ identity: logicalKey,
226
+ digest,
227
+ dependencies: dependencies.map((item) => item.key),
228
+ byteLength: bytes.byteLength
229
+ };
230
+ const nextManifest = {
231
+ kind,
232
+ dependencies: canonicalInputs.map(({ kind: inputKind, identity }) => ({
233
+ kind: inputKind,
234
+ identity
235
+ })),
236
+ nodeKey: key
237
+ };
238
+ const currentNode = this.nodes.get(key);
239
+ const currentManifest = this.logical.get(logicalKey);
240
+ if (!sameNode(currentNode, nextNode) || !sameLogicalManifest(currentManifest, nextManifest)) changed = true;
241
+ this.nodes.set(key, nextNode);
242
+ this.logical.set(logicalKey, nextManifest);
243
+ if (changed) this.generation += 1;
244
+ return true;
245
+ }
246
+ exportState() {
247
+ const entries = [];
248
+ const referencedDigests = /* @__PURE__ */ new Set();
249
+ for (const [logicalKey, manifest] of this.logical) {
250
+ const node = this.nodes.get(manifest.nodeKey);
251
+ if (!node) continue;
252
+ const output = this.blobs.get(node.digest);
253
+ if (!output) continue;
254
+ const inputs = node.dependencies.map((key) => {
255
+ const dependency = this.nodes.get(key);
256
+ if (!dependency) throw new Error(`Build graph dependency '${key}' is missing.`);
257
+ return {
258
+ kind: dependency.kind,
259
+ identity: dependency.identity,
260
+ digest: dependency.digest
261
+ };
262
+ });
263
+ entries.push({
264
+ kind: manifest.kind,
265
+ logicalKey,
266
+ inputs,
267
+ outputDigest: node.digest,
268
+ outputByteLength: output.byteLength
269
+ });
270
+ referencedDigests.add(node.digest);
271
+ }
272
+ return {
273
+ manifest: {
274
+ schema: WASM_OJ_SCHEMAS.incrementalBuildGraph,
275
+ version: 2,
276
+ generation: this.generation,
277
+ entries: entries.sort((left, right) => compareText(left.logicalKey, right.logicalKey))
278
+ },
279
+ blobs: [...referencedDigests].sort().map((digest) => ({
280
+ digest,
281
+ bytes: this.blobs.get(digest)
282
+ }))
283
+ };
284
+ }
285
+ async restoreState(state) {
286
+ if (!state || typeof state !== "object" || Array.isArray(state) || Object.keys(state).sort().join(",") !== "blobs,manifest") throw new Error("Incremental build graph state does not use the active WASM-OJ contract.");
287
+ const { manifest } = state;
288
+ if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || Object.keys(manifest).sort().join(",") !== "entries,generation,schema,version" || manifest.schema !== WASM_OJ_SCHEMAS.incrementalBuildGraph || manifest.version !== 2 || !Number.isSafeInteger(manifest.generation) || manifest.generation < 0 || !Array.isArray(manifest.entries) || !Array.isArray(state.blobs)) throw new Error("Incremental build graph manifest does not use the active WASM-OJ contract.");
289
+ const blobs = /* @__PURE__ */ new Map();
290
+ let totalBytes = 0;
291
+ let previousDigest = "";
292
+ for (const candidate of state.blobs) {
293
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) throw new Error("Incremental build graph state contains a malformed blob.");
294
+ const blob = candidate;
295
+ if (Object.keys(blob).sort().join(",") !== "bytes,digest" || typeof blob.digest !== "string" || !/^[0-9a-f]{64}$/.test(blob.digest) || blob.digest <= previousDigest || !(blob.bytes instanceof Uint8Array) || await sha256Hex(blob.bytes) !== blob.digest) throw new Error("Incremental build graph state contains an invalid content-addressed blob.");
296
+ previousDigest = blob.digest;
297
+ totalBytes += blob.bytes.byteLength;
298
+ if (!Number.isSafeInteger(totalBytes) || totalBytes > this.limitBytes) throw new Error("Incremental build graph state exceeds its storage limit.");
299
+ blobs.set(blob.digest, blob.bytes);
300
+ }
301
+ const logicalKeys = /* @__PURE__ */ new Set();
302
+ const verified = [];
303
+ const referencedDigests = /* @__PURE__ */ new Set();
304
+ let previousLogicalKey = "";
305
+ for (const candidate of manifest.entries) {
306
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) throw new Error("Incremental build graph manifest contains a malformed entry.");
307
+ const entry = candidate;
308
+ if (Object.keys(entry).sort().join(",") !== "inputs,kind,logicalKey,outputByteLength,outputDigest") throw new Error("Incremental build graph manifest entry has an invalid shape.");
309
+ if (entry.kind !== "pch" && entry.kind !== "object" && entry.kind !== "link-result") throw new Error("Incremental build graph manifest entry has an invalid node kind.");
310
+ if (typeof entry.logicalKey !== "string" || !entry.logicalKey || entry.logicalKey !== entry.logicalKey.trim() || entry.logicalKey.length > 16384 || previousLogicalKey !== "" && compareText(previousLogicalKey, entry.logicalKey) >= 0) throw new Error("Incremental build graph manifest has an invalid or non-canonical logical key.");
311
+ previousLogicalKey = entry.logicalKey;
312
+ if (logicalKeys.has(entry.logicalKey)) throw new Error(`Incremental build graph manifest repeats '${entry.logicalKey}'.`);
313
+ logicalKeys.add(entry.logicalKey);
314
+ if (typeof entry.outputDigest !== "string" || !/^[0-9a-f]{64}$/.test(entry.outputDigest) || !Number.isSafeInteger(entry.outputByteLength) || entry.outputByteLength < 0) throw new Error(`Incremental build graph output '${entry.logicalKey}' has invalid metadata.`);
315
+ const output = blobs.get(entry.outputDigest);
316
+ if (!output || output.byteLength !== entry.outputByteLength) throw new Error(`Incremental build graph output '${entry.logicalKey}' is missing or has the wrong size.`);
317
+ referencedDigests.add(entry.outputDigest);
318
+ if (!Array.isArray(entry.inputs)) throw new Error(`Incremental build graph entry '${entry.logicalKey}' inputs must be an array.`);
319
+ const inputs = entry.inputs.map((input) => {
320
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error(`Incremental build graph entry '${entry.logicalKey}' has a malformed input.`);
321
+ const record = input;
322
+ if (Object.keys(record).sort().join(",") !== "digest,identity,kind" || !BUILD_NODE_KINDS.slice(0, 5).includes(record.kind) || typeof record.identity !== "string" || typeof record.digest !== "string") throw new Error(`Incremental build graph entry '${entry.logicalKey}' has an invalid input.`);
323
+ return {
324
+ kind: record.kind,
325
+ identity: record.identity,
326
+ digest: record.digest
327
+ };
328
+ });
329
+ if (canonicalizeInputs(inputs).some((input, index) => input.identity !== inputs[index]?.identity)) throw new Error(`Incremental build graph entry '${entry.logicalKey}' inputs are not canonical.`);
330
+ verified.push({
331
+ kind: entry.kind,
332
+ logicalKey: entry.logicalKey,
333
+ inputs,
334
+ output
335
+ });
336
+ }
337
+ if (referencedDigests.size !== blobs.size) throw new Error("Incremental build graph state contains an unreferenced content-addressed blob.");
338
+ this.clear();
339
+ for (const entry of verified) if (!await this.store(entry.kind, entry.logicalKey, entry.inputs, entry.output)) throw new Error(`Incremental build graph entry '${entry.logicalKey}' exceeds its storage limit.`);
340
+ this.generation = manifest.generation;
341
+ }
342
+ snapshot() {
343
+ return {
344
+ schema: WASM_OJ_SCHEMAS.incrementalBuildGraph,
345
+ nodes: [...this.nodes.values()].map((node) => ({
346
+ ...node,
347
+ dependencies: [...node.dependencies]
348
+ })).sort((left, right) => compareText(left.key, right.key)),
349
+ storedBytes: this.storedBytes
350
+ };
351
+ }
352
+ clear() {
353
+ const changed = this.logical.size > 0 || this.nodes.size > 0 || this.blobs.size > 0;
354
+ this.logical.clear();
355
+ this.nodes.clear();
356
+ this.blobs.clear();
357
+ this.storedBytes = 0;
358
+ if (changed) this.generation += 1;
359
+ }
360
+ async internInputs(inputs) {
361
+ return Promise.all(canonicalizeInputs(inputs).map(async (input) => {
362
+ const digest = await inputDigest(input);
363
+ const key = await sha256Hex(JSON.stringify({
364
+ schema: WASM_OJ_SCHEMAS.incrementalBuildGraph,
365
+ kind: input.kind,
366
+ identity: input.identity,
367
+ digest
368
+ }));
369
+ const node = {
370
+ key,
371
+ kind: input.kind,
372
+ identity: input.identity,
373
+ digest,
374
+ dependencies: [],
375
+ byteLength: input.bytes?.byteLength ?? 0
376
+ };
377
+ this.nodes.set(key, node);
378
+ return node;
379
+ }));
380
+ }
381
+ ensureCapacity(incomingBytes, incomingDigest) {
382
+ if (this.blobs.has(incomingDigest)) return false;
383
+ let changed = false;
384
+ while (this.storedBytes + incomingBytes > this.limitBytes && this.blobs.size > 0) {
385
+ const oldestDigest = this.blobs.keys().next().value;
386
+ const oldest = this.blobs.get(oldestDigest);
387
+ this.blobs.delete(oldestDigest);
388
+ this.storedBytes -= oldest.byteLength;
389
+ changed = true;
390
+ for (const [key, node] of this.nodes) {
391
+ if (node.digest !== oldestDigest || node.dependencies.length === 0) continue;
392
+ this.nodes.delete(key);
393
+ for (const [logicalKey, manifest] of this.logical) if (manifest.nodeKey === key) this.logical.delete(logicalKey);
394
+ }
395
+ }
396
+ return changed;
397
+ }
398
+ };
399
+ function sameNode(left, right) {
400
+ return left?.key === right.key && left.kind === right.kind && left.identity === right.identity && left.digest === right.digest && left.byteLength === right.byteLength && left.dependencies.length === right.dependencies.length && left.dependencies.every((dependency, index) => dependency === right.dependencies[index]);
401
+ }
402
+ function sameLogicalManifest(left, right) {
403
+ return left?.kind === right.kind && left.nodeKey === right.nodeKey && left.dependencies.length === right.dependencies.length && left.dependencies.every((dependency, index) => dependency.kind === right.dependencies[index]?.kind && dependency.identity === right.dependencies[index]?.identity);
404
+ }
405
+ function canonicalizeInputs(inputs) {
406
+ const byIdentity = /* @__PURE__ */ new Map();
407
+ for (const input of inputs) {
408
+ if (!input.identity || input.identity !== input.identity.trim() || input.identity.length > 16384) throw new Error("Build graph input identities must be non-empty, trimmed strings.");
409
+ if (byIdentity.has(input.identity)) throw new Error(`Duplicate build graph input '${input.identity}'.`);
410
+ if (input.bytes === void 0 === (input.digest === void 0)) throw new Error(`Build graph input '${input.identity}' must provide exactly one of bytes or digest.`);
411
+ byIdentity.set(input.identity, input);
412
+ }
413
+ return [...byIdentity.values()].sort((left, right) => compareText(left.identity, right.identity));
414
+ }
415
+ function compareText(left, right) {
416
+ return left < right ? -1 : left > right ? 1 : 0;
417
+ }
418
+ async function inputDigest(input) {
419
+ if (input.bytes) return sha256Hex(input.bytes);
420
+ if (!/^[0-9a-f]{64}$/.test(input.digest)) throw new Error(`Build graph input '${input.identity}' has an invalid digest.`);
421
+ return input.digest;
422
+ }
423
+ function structuralKey(kind, logicalKey, dependencies) {
424
+ return sha256Hex(JSON.stringify({
425
+ schema: WASM_OJ_SCHEMAS.incrementalBuildGraph,
426
+ kind,
427
+ logicalKey,
428
+ dependencies
429
+ }));
430
+ }
431
+ //#endregion
432
+ //#region src/compiler/clang-object-cache.ts
433
+ var decoder$2 = new TextDecoder();
434
+ /**
435
+ * Content-addressed direct-mode cache for Clang translation units.
436
+ *
437
+ * Unit identity includes the frozen argv manifest and source digest. Every
438
+ * project dependency from Clang's dependency file is rehashed before reuse.
439
+ * System headers are covered by the pinned toolchain identity.
440
+ */
441
+ var ClangObjectCache = class {
442
+ graph;
443
+ constructor(limitBytes) {
444
+ this.graph = new IncrementalBuildGraph(limitBytes);
445
+ }
446
+ async unitManifestKey(pins, configKey, source, sourceBytes) {
447
+ const config = pins.configs[configKey];
448
+ if (!config) throw new Error(`Unknown pinned Clang configuration '${configKey}'.`);
449
+ return sha256Hex(JSON.stringify({
450
+ schema: WASM_OJ_SCHEMAS.objectCache,
451
+ pinsSha256: CLANG_CC1_PINS_SHA256,
452
+ sourceToolchainSha256: pins.sourceSha256,
453
+ packageSha256: CLANG_PACKAGE_SHA256,
454
+ version: pins.version,
455
+ config: configKey,
456
+ cc1Argv: config.cc1,
457
+ unit: source,
458
+ source: await sha256Hex(sourceBytes)
459
+ }));
460
+ }
461
+ async lookup(manifestKey, projectFiles, additionalInputs = []) {
462
+ return this.graph.lookup(manifestKey, availableInputs(projectFiles, additionalInputs));
463
+ }
464
+ async store(manifestKey, dependencyPaths, projectFiles, object, additionalInputs = []) {
465
+ const normalized = normalizeProjectDependencies(dependencyPaths, projectFiles);
466
+ if (!normalized) return false;
467
+ return this.graph.store("object", manifestKey, [...graphInputs(normalized, projectFiles), ...additionalInputs], object);
468
+ }
469
+ async lookupPch(manifestKey, projectFiles) {
470
+ return this.graph.lookup(manifestKey, availableInputs(projectFiles));
471
+ }
472
+ async storePch(manifestKey, dependencyPaths, projectFiles, pch) {
473
+ const normalized = normalizeProjectDependencies(dependencyPaths, projectFiles);
474
+ if (!normalized) return false;
475
+ return this.graph.store("pch", manifestKey, graphInputs(normalized, projectFiles), pch);
476
+ }
477
+ lookupLink(manifestKey, objects) {
478
+ return this.graph.lookupExact("link-result", manifestKey, withToolchain(objects));
479
+ }
480
+ storeLink(manifestKey, objects, wasm) {
481
+ return this.graph.store("link-result", manifestKey, withToolchain(objects), wasm);
482
+ }
483
+ snapshot() {
484
+ return this.graph.snapshot();
485
+ }
486
+ exportState() {
487
+ return this.graph.exportState();
488
+ }
489
+ restoreState(state) {
490
+ return this.graph.restoreState(state);
491
+ }
492
+ clear() {
493
+ this.graph.clear();
494
+ }
495
+ };
496
+ function parseClangDependencyFile(bytes) {
497
+ const joined = decoder$2.decode(bytes).replace(/\\\r?\n/g, " ");
498
+ const colon = joined.indexOf(":");
499
+ if (colon < 0) return [];
500
+ const deps = [];
501
+ const pattern = /(?:\\.|[^\s\\])+/g;
502
+ const remainder = joined.slice(colon + 1);
503
+ for (let match = pattern.exec(remainder); match; match = pattern.exec(remainder)) deps.push(match[0].replace(/\\(.)/g, "$1"));
504
+ return deps;
505
+ }
506
+ function normalizeProjectDependencies(dependencyPaths, projectFiles) {
507
+ const normalized = /* @__PURE__ */ new Set();
508
+ for (const raw of dependencyPaths) {
509
+ if (raw.startsWith("/usr/") || raw.startsWith("/sysroot/") || raw.startsWith("/lib/")) continue;
510
+ const path = raw.startsWith("/project/") ? raw.slice(9) : raw.replace(/^\.\//, "");
511
+ if (!path || path.startsWith("/") || path.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) return;
512
+ if (!projectFiles.has(path)) return void 0;
513
+ normalized.add(path);
514
+ }
515
+ if (normalized.size === 0) return void 0;
516
+ return [...normalized].sort();
517
+ }
518
+ function fileKind(path) {
519
+ return /\.(?:c|cc|cpp|cxx)$/i.test(path) ? "source" : "header";
520
+ }
521
+ function graphInputs(paths, projectFiles) {
522
+ return withToolchain(paths.map((path) => ({
523
+ kind: fileKind(path),
524
+ identity: path,
525
+ bytes: projectFiles.get(path)
526
+ })));
527
+ }
528
+ function withToolchain(inputs) {
529
+ return [...inputs, {
530
+ kind: "package",
531
+ identity: `cpp:clang@${CLANG_PACKAGE_SHA256}`,
532
+ digest: CLANG_PACKAGE_SHA256
533
+ }];
534
+ }
535
+ function availableInputs(projectFiles, additionalInputs = []) {
536
+ const inputs = new Map([...projectFiles].map(([path, bytes]) => [path, {
537
+ kind: fileKind(path),
538
+ identity: path,
539
+ bytes
540
+ }]));
541
+ inputs.set(`cpp:clang@${CLANG_PACKAGE_SHA256}`, {
542
+ kind: "package",
543
+ identity: `cpp:clang@${CLANG_PACKAGE_SHA256}`,
544
+ digest: CLANG_PACKAGE_SHA256
545
+ });
546
+ for (const input of additionalInputs) inputs.set(input.identity, input);
547
+ return inputs;
548
+ }
549
+ //#endregion
550
+ //#region src/core/resources.ts
551
+ /** The weighted meter defined by the active WASM-OJ contract. */
552
+ var WEIGHTED_METER_MODEL = "weighted";
553
+ Math.floor(Number.MAX_SAFE_INTEGER / 1e6);
554
+ Object.freeze({
555
+ instructionBudget: 1e10,
556
+ logicalTimeLimitMs: 6e4,
557
+ memoryLimitBytes: 268435456,
558
+ outputLimitBytes: 4194304,
559
+ filesystemWriteLimitBytes: 67108864,
560
+ filesystemEntryLimit: 4096,
561
+ wallTimeLimitMs: 6e4
562
+ });
563
+ new TextEncoder();
564
+ Object.freeze({
565
+ runtimeCoreWasmSha256: "92500f3a2e65fe6979e893179d8000e12d66822c160eeb779b0d4fe0a6b55603",
566
+ runtimeSourceRootSha256: "3ef42cb2c70e7013e4a6f9d4d7457a7071101795fbd3753efcd20c1ac338ebd5",
567
+ wasmerNativeVersion: "7.2.1",
568
+ wasmerSdkVersion: "0.10.0",
569
+ wasmerSdkWasmSha256: "49a6646209f5ab5e7c737eac33407d87d9a9959ac83e5ecaaab9261b2323589e",
570
+ wasmerWasixVersion: "0.702.1"
571
+ });
572
+ /**
573
+ * SHA-256 of `runtimeIdentityBytes()`.
574
+ * Release verification independently checks the component bytes before this
575
+ * identity is admitted into a calibrated release.
576
+ */
577
+ var WASM_OJ_RUNTIME_IDENTITY_SHA256 = "24c0bcff9820fbfd1fd4db1c57e2a866b83041409dd22b5b725688739bd3e223";
578
+ //#endregion
579
+ //#region src/core/cost-profile.ts
580
+ function coordinates(language, target, optimization) {
581
+ assertLanguageIdentifier(language);
582
+ return [
583
+ "wasm-oj-cost",
584
+ `contract-${WASM_OJ_CONTRACT_VERSION}`,
585
+ encodeURIComponent(language),
586
+ target,
587
+ optimization
588
+ ];
589
+ }
590
+ /** Stable identity for one calibrated compiler/runtime overhead profile. */
591
+ function costProfileId(language, target, optimization, downstreamToolchainContent) {
592
+ const content = isBuiltinLanguage(language) ? toolchainContentIdentity(language) : downstreamToolchainContent;
593
+ if (!content || !/^[A-Za-z0-9._-]+$/.test(content)) throw new Error(isBuiltinLanguage(language) ? `WASM-OJ toolchain content identity is invalid for '${language}'.` : `Downstream language '${language}' requires an explicit content identity using letters, digits, '.', '_' or '-'.`);
594
+ return [
595
+ ...coordinates(language, target, optimization),
596
+ `content-${content}`,
597
+ `runtime-${WASM_OJ_RUNTIME_IDENTITY_SHA256}`,
598
+ WEIGHTED_METER_MODEL
599
+ ].join(":");
600
+ }
601
+ //#endregion
602
+ //#region src/core/diagnostics.ts
603
+ function severity(value) {
604
+ if (value === "warning") return "warning";
605
+ if (value === "note" || value === "info") return "info";
606
+ return "error";
607
+ }
608
+ function projectPath(path) {
609
+ return path.replace(/^file:\/\//, "").replace(/^\/?(?:workspace|project|work)\//, "").replace(/^\.\//, "");
610
+ }
611
+ function parseClangDiagnostics(output) {
612
+ const diagnostics = [];
613
+ const pattern = /^(.*?):(\d+):(\d+):\s+(fatal error|error|warning|note):\s+(.+?)(?:\s+\[([^\]]+)\])?$/gm;
614
+ let match;
615
+ while ((match = pattern.exec(output)) !== null) diagnostics.push({
616
+ file: projectPath(match[1]),
617
+ line: Number(match[2]),
618
+ column: Number(match[3]),
619
+ severity: severity(match[4].replace("fatal ", "")),
620
+ message: match[5],
621
+ source: "clang",
622
+ code: match[6]
623
+ });
624
+ return diagnostics;
625
+ }
626
+ function parsePythonDiagnostics(output) {
627
+ const diagnostics = [];
628
+ const lines = output.split(/\r?\n/);
629
+ for (let index = 0; index < lines.length; index += 1) {
630
+ const location = lines[index].match(/^\s*File "([^"]+)", line (\d+)/);
631
+ if (!location) continue;
632
+ let column = 1;
633
+ let message = "Python compilation failed";
634
+ const caret = (lines[index + 2] ?? "").indexOf("^");
635
+ if (caret >= 0) column = caret + 1;
636
+ for (let cursor = index + 1; cursor < Math.min(lines.length, index + 6); cursor += 1) {
637
+ const error = lines[cursor].match(/^([A-Za-z]+(?:Error|Exception)):\s*(.+)$/);
638
+ if (error) {
639
+ message = `${error[1]}: ${error[2]}`;
640
+ break;
641
+ }
642
+ }
643
+ diagnostics.push({
644
+ file: projectPath(location[1]),
645
+ line: Number(location[2]),
646
+ column,
647
+ severity: "error",
648
+ message,
649
+ source: "python"
650
+ });
651
+ }
652
+ return diagnostics;
653
+ }
654
+ function parseTypeScriptDiagnostics(output) {
655
+ const diagnostics = [];
656
+ const pattern = /^(.*?)\((\d+),(\d+)\):\s+(error|warning|message)\s+TS(\d+):\s+(.+)$/gm;
657
+ let match;
658
+ while ((match = pattern.exec(output)) !== null) diagnostics.push({
659
+ severity: severity(match[4]),
660
+ message: match[6],
661
+ file: projectPath(match[1]),
662
+ line: Number(match[2]),
663
+ column: Number(match[3]),
664
+ source: "typescript",
665
+ code: `TS${match[5]}`
666
+ });
667
+ return diagnostics;
668
+ }
669
+ function parseRustDiagnostics(output) {
670
+ const diagnostics = [];
671
+ for (const line of output.split(/\r?\n/)) {
672
+ if (!line.startsWith("{")) continue;
673
+ let value;
674
+ try {
675
+ value = JSON.parse(line);
676
+ } catch {
677
+ continue;
678
+ }
679
+ if (!value || typeof value !== "object") continue;
680
+ const record = value;
681
+ if (record.$message_type !== "diagnostic" || typeof record.message !== "string") continue;
682
+ const spans = Array.isArray(record.spans) ? record.spans : [];
683
+ const location = spans.find((candidate) => candidate && typeof candidate === "object" && candidate.is_primary === true) ?? spans.find((candidate) => candidate && typeof candidate === "object");
684
+ const code = record.code && typeof record.code === "object" ? record.code.code : void 0;
685
+ diagnostics.push({
686
+ severity: severity(typeof record.level === "string" ? record.level : "error"),
687
+ message: record.message,
688
+ file: projectPath(typeof location?.file_name === "string" ? location.file_name : "main.rs"),
689
+ line: typeof location?.line_start === "number" ? location.line_start : 1,
690
+ column: typeof location?.column_start === "number" ? location.column_start : 1,
691
+ endLine: typeof location?.line_end === "number" ? location.line_end : void 0,
692
+ endColumn: typeof location?.column_end === "number" ? location.column_end : void 0,
693
+ source: "rustc",
694
+ code: typeof code === "string" ? code : void 0
695
+ });
696
+ }
697
+ return diagnostics;
698
+ }
699
+ function parseGoDiagnostics(output) {
700
+ const diagnostics = [];
701
+ const pattern = /^(.*?\.go):(\d+)(?::(\d+))?:\s*(.+)$/gm;
702
+ let match;
703
+ while ((match = pattern.exec(output)) !== null) diagnostics.push({
704
+ severity: "error",
705
+ message: match[4],
706
+ file: projectPath(match[1]),
707
+ line: Number(match[2]),
708
+ column: Number(match[3] ?? 1),
709
+ source: "go"
710
+ });
711
+ return diagnostics;
712
+ }
713
+ function ensureFailureDiagnostic(diagnostics, summary) {
714
+ if (diagnostics.length > 0) return diagnostics;
715
+ return [{
716
+ severity: "error",
717
+ file: projectPath(summary.file),
718
+ line: 1,
719
+ column: 1,
720
+ source: summary.source,
721
+ message: summary.message
722
+ }];
723
+ }
724
+ //#endregion
725
+ //#region src/compiler/libcxx-pch.ts
726
+ var WASM_OJ_LIBCXX_PCH_HEADER = `#pragma once
727
+ #include <algorithm>
728
+ #include <array>
729
+ #include <bitset>
730
+ #include <cassert>
731
+ #include <cctype>
732
+ #include <cerrno>
733
+ #include <cfloat>
734
+ #include <charconv>
735
+ #include <chrono>
736
+ #include <climits>
737
+ #include <cmath>
738
+ #include <compare>
739
+ #include <concepts>
740
+ #include <cstddef>
741
+ #include <cstdint>
742
+ #include <cstdio>
743
+ #include <cstdlib>
744
+ #include <cstring>
745
+ #include <deque>
746
+ #include <exception>
747
+ #include <functional>
748
+ #include <iomanip>
749
+ #include <ios>
750
+ #include <iostream>
751
+ #include <iterator>
752
+ #include <limits>
753
+ #include <map>
754
+ #include <memory>
755
+ #include <numeric>
756
+ #include <optional>
757
+ #include <queue>
758
+ #include <random>
759
+ #include <ranges>
760
+ #include <set>
761
+ #include <span>
762
+ #include <sstream>
763
+ #include <stack>
764
+ #include <string>
765
+ #include <string_view>
766
+ #include <tuple>
767
+ #include <type_traits>
768
+ #include <unordered_map>
769
+ #include <unordered_set>
770
+ #include <utility>
771
+ #include <variant>
772
+ #include <vector>
773
+ `;
774
+ var decoder$1 = new TextDecoder();
775
+ async function decodeLibcxxPchManifest(bytes) {
776
+ const digest = await sha256Hex(bytes);
777
+ if (digest !== "d126c99e951a7302d4ea2b66da4ed64d3d74e9d319d562518867c8d8c97a06b8") throw new Error(`Pinned libc++ PCH manifest digest mismatch: expected ${CLANG_LIBCXX_PCH_MANIFEST_SHA256}, received ${digest}.`);
778
+ let value;
779
+ try {
780
+ value = JSON.parse(decoder$1.decode(bytes));
781
+ } catch (error) {
782
+ throw new Error("Pinned libc++ PCH manifest is not valid JSON.", { cause: error });
783
+ }
784
+ if (!isRecord(value) || value.schema !== WASM_OJ_SCHEMAS.clangLibcxxPch || value.version !== "22.0.0-git20542-10" || value.clangPackageSha256 !== "21ded33b9c6d4e1aaad5528c940bdaf6c3e84be77ea8f522f018ca7289a2a224" || value.clangPinsSha256 !== "66c4604dccd3f89d8e1472bf4432367d7396cce4a01279b1a1db445f229dba72" || value.header !== WASM_OJ_LIBCXX_PCH_HEADER || !isRecord(value.profiles)) throw new Error("Pinned libc++ PCH manifest is not admitted by the active Clang toolchain contract.");
785
+ if (value.headerSha256 !== await sha256Hex(WASM_OJ_LIBCXX_PCH_HEADER)) throw new Error("Pinned libc++ PCH header digest does not match its canonical source.");
786
+ const manifestProfiles = value.profiles;
787
+ const profiles = Object.fromEntries(await Promise.all(["cpp-debug", "cpp-release"].map(async (profile) => {
788
+ const asset = manifestProfiles[profile];
789
+ if (!isRecord(asset) || typeof asset.path !== "string" || !asset.path.endsWith(`.${profile}.pch.gz.bin`) || !isBytes(asset.byteLength) || !isBytes(asset.compressedByteLength) || !isSha256(asset.sha256) || !isSha256(asset.compressedSha256)) throw new Error(`Pinned libc++ PCH profile '${profile}' is malformed.`);
790
+ return [profile, {
791
+ path: asset.path,
792
+ byteLength: asset.byteLength,
793
+ sha256: asset.sha256,
794
+ compressedByteLength: asset.compressedByteLength,
795
+ compressedSha256: asset.compressedSha256
796
+ }];
797
+ })));
798
+ if (Object.keys(manifestProfiles).sort().join(",") !== "cpp-debug,cpp-release") throw new Error("Pinned libc++ PCH manifest has an unexpected profile set.");
799
+ return {
800
+ schema: WASM_OJ_SCHEMAS.clangLibcxxPch,
801
+ version: CLANG_VERSION,
802
+ clangPackageSha256: CLANG_PACKAGE_SHA256,
803
+ clangPinsSha256: CLANG_CC1_PINS_SHA256,
804
+ header: WASM_OJ_LIBCXX_PCH_HEADER,
805
+ headerSha256: value.headerSha256,
806
+ profiles
807
+ };
808
+ }
809
+ function isToolchainLibcxxPchHeader(contents) {
810
+ return contents === WASM_OJ_LIBCXX_PCH_HEADER;
811
+ }
812
+ function isRecord(value) {
813
+ return typeof value === "object" && value !== null && !Array.isArray(value);
814
+ }
815
+ function isSha256(value) {
816
+ return typeof value === "string" && /^[0-9a-f]{64}$/.test(value);
817
+ }
818
+ function isBytes(value) {
819
+ return Number.isSafeInteger(value) && value > 0;
820
+ }
821
+ Object.freeze({
822
+ randomSeed: 1592594996,
823
+ realtimeEpochMs: Date.UTC(2e3, 0, 1),
824
+ clockStepNs: 1e6
825
+ });
826
+ //#endregion
827
+ //#region src/runtime/determinism.ts
828
+ var DETERMINISTIC_NATIVE_SOURCE_PATH = ".wasm-oj/determinism.c";
829
+ var PYTHON_RUNNER_PATH = ".wasm-oj/deterministic_runner.py";
830
+ var DETERMINISTIC_NATIVE_RUNTIME = String.raw`
831
+ #include <stddef.h>
832
+ #include <stdint.h>
833
+ #include <stdlib.h>
834
+
835
+ #ifdef __cplusplus
836
+ extern "C" {
837
+ #endif
838
+
839
+ static uint32_t wasm_oj_random_state;
840
+ static int wasm_oj_initialized;
841
+
842
+ static uint64_t wasm_oj_parse_u64(const char *value) {
843
+ if (!value || !*value) abort();
844
+ uint64_t result = 0;
845
+ for (const unsigned char *cursor = (const unsigned char *)value; *cursor; ++cursor) {
846
+ if (*cursor < '0' || *cursor > '9') abort();
847
+ uint64_t digit = (uint64_t)(*cursor - '0');
848
+ if (result > (UINT64_MAX - digit) / 10) abort();
849
+ result = result * 10 + digit;
850
+ }
851
+ return result;
852
+ }
853
+
854
+ static void wasm_oj_initialize(void) {
855
+ if (wasm_oj_initialized) return;
856
+ uint64_t seed = wasm_oj_parse_u64(getenv("WASM_OJ_RANDOM_SEED"));
857
+ wasm_oj_random_state = (uint32_t)seed;
858
+ wasm_oj_initialized = 1;
859
+ }
860
+
861
+ static uint32_t wasm_oj_next_u32(void) {
862
+ wasm_oj_random_state += 0x9e3779b9u;
863
+ uint32_t value = wasm_oj_random_state;
864
+ value ^= value >> 16;
865
+ value *= 0x21f0aaadu;
866
+ value ^= value >> 15;
867
+ value *= 0x735a2d97u;
868
+ value ^= value >> 15;
869
+ return value;
870
+ }
871
+
872
+ uint32_t __imported_wasi_snapshot_preview1_random_get(uint8_t *buffer, size_t length) {
873
+ wasm_oj_initialize();
874
+ uint32_t word = 0;
875
+ for (size_t index = 0; index < length; ++index) {
876
+ if ((index & 3u) == 0) word = wasm_oj_next_u32();
877
+ buffer[index] = (uint8_t)(word >> ((index & 3u) * 8u));
878
+ }
879
+ return 0;
880
+ }
881
+
882
+ #ifdef __cplusplus
883
+ }
884
+ #endif
885
+ `;
886
+ var PYTHON_DETERMINISTIC_RUNNER = String.raw`
887
+ import os as _os
888
+ import runpy as _runpy
889
+ import sys as _sys
890
+
891
+ _random_state = None
892
+
893
+ def _random_seed():
894
+ global _random_state
895
+ if _random_state is None:
896
+ _random_state = int(_os.environ["WASM_OJ_RANDOM_SEED"]) & 0xffffffff
897
+ return _random_state
898
+
899
+ def _next_u32():
900
+ global _random_state
901
+ _random_seed()
902
+ _random_state = (_random_state + 0x9e3779b9) & 0xffffffff
903
+ value = _random_state
904
+ value ^= value >> 16
905
+ value = (value * 0x21f0aaad) & 0xffffffff
906
+ value ^= value >> 15
907
+ value = (value * 0x735a2d97) & 0xffffffff
908
+ value ^= value >> 15
909
+ return value & 0xffffffff
910
+
911
+ def _urandom(length):
912
+ if not isinstance(length, int) or length < 0:
913
+ raise ValueError("negative argument not allowed")
914
+ output = bytearray(length)
915
+ word = 0
916
+ for index in range(length):
917
+ if index % 4 == 0:
918
+ word = _next_u32()
919
+ output[index] = (word >> ((index % 4) * 8)) & 0xff
920
+ return bytes(output)
921
+
922
+ _os.urandom = _urandom
923
+ if hasattr(_os, "getrandom"):
924
+ _os.getrandom = lambda size, flags=0: _urandom(size)
925
+
926
+ _entry = _sys.argv[1]
927
+ _sys.argv = [_entry, *_sys.argv[2:]]
928
+ _runpy.run_path(_entry, run_name="__main__")
929
+ `;
930
+ //#endregion
931
+ //#region src/compiler/sdk-direct-clang.ts
932
+ var loadedToolchain;
933
+ var loadedLibcxxPchManifest;
934
+ var loadedLibcxxPch = /* @__PURE__ */ new Map();
935
+ var objectCache = new ClangObjectCache(67108864);
936
+ var encoder$2 = new TextEncoder();
937
+ var decoder = new TextDecoder();
938
+ var STAGE_OUTPUT_TIMEOUT_MS = 55e3;
939
+ /**
940
+ * Browser compiler that drives the pinned cc1 and wasm-ld jobs through
941
+ * the official SDK threadpool while keeping every command and project volume
942
+ * isolated. No Clang driver or guest subprocess is involved.
943
+ */
944
+ async function buildClangWithSdkDirect(project, cacheKey, requestId, host) {
945
+ if (project.config.target !== "wasip1" && project.config.target !== "wasix") throw new Error("The output-ready Clang compiler accepts only wasip1 or wasix targets.");
946
+ if (project.config.language !== "c" && project.config.language !== "cpp") throw new Error("The output-ready Clang compiler accepts only C and C++ projects.");
947
+ const started = performance.now();
948
+ host.progress(requestId, "loading-toolchain", "Loading pinned Clang 22 toolchain", .15);
949
+ const { pins, compiler, linker } = await ensureToolchain(requestId, host);
950
+ const configKey = `${project.config.language}-${project.config.optimization}`;
951
+ const config = pins.configs[configKey];
952
+ if (!config) throw new Error(`The pinned Clang manifest has no '${configKey}' configuration.`);
953
+ host.trace(requestId, "filesystemPrepare", "start");
954
+ const projectFiles = new Map(project.files.map((file) => [file.path, encoder$2.encode(file.content)]));
955
+ const dependencies = cppDependencyInput(project);
956
+ for (const [path, bytes] of dependencies.files) projectFiles.set(path, bytes);
957
+ projectFiles.set(DETERMINISTIC_NATIVE_SOURCE_PATH, encoder$2.encode(DETERMINISTIC_NATIVE_RUNTIME));
958
+ const directory = new Directory$1(Object.fromEntries([...projectFiles].map(([path, bytes]) => [`/${path}`, bytes])));
959
+ try {
960
+ await ensureDirectory(directory, "/build");
961
+ await ensureDirectory(directory, "/.wasm-oj");
962
+ host.trace(requestId, "filesystemPrepare", "end");
963
+ const isCpp = project.config.language === "cpp";
964
+ const extensions = isCpp ? /\.(?:cc|cpp|cxx)$/ : /\.c$/;
965
+ const sources = project.files.filter((file) => extensions.test(file.path)).map((file) => file.path);
966
+ if (!sources.includes(project.config.entry)) sources.unshift(project.config.entry);
967
+ const units = [
968
+ ...sources,
969
+ ...dependencies.sources,
970
+ DETERMINISTIC_NATIVE_SOURCE_PATH
971
+ ];
972
+ let stdout = "";
973
+ let stderr = "";
974
+ const objectPaths = [];
975
+ const objectInputs = [];
976
+ let objectCacheHits = 0;
977
+ let objectCacheStores = 0;
978
+ let pchHits = 0;
979
+ let pchMisses = 0;
980
+ let pchStores = 0;
981
+ let linkHits = 0;
982
+ let linkMisses = 0;
983
+ let linkStores = 0;
984
+ const structuredDiagnostics = [];
985
+ const pchHeader = isCpp ? findPrecompiledHeader(project) : void 0;
986
+ const pchPath = "/project/build/wasm-oj.pch";
987
+ let pchInput;
988
+ let admittedPch = false;
989
+ if (pchHeader) {
990
+ const headerBytes = projectFiles.get(pchHeader);
991
+ let pch;
992
+ if (isToolchainLibcxxPchHeader(decoder.decode(headerBytes))) {
993
+ admittedPch = true;
994
+ const reservedHeader = "wasm-oj.libcxx.hpp";
995
+ if (projectFiles.has(reservedHeader)) throw new Error(`C++ projects using WASM-OJ's admitted libc++ PCH may not define reserved path '${reservedHeader}'.`);
996
+ projectFiles.set(reservedHeader, headerBytes);
997
+ await directory.writeFile(`/${reservedHeader}`, headerBytes);
998
+ pch = await loadLibcxxPch(configKey, requestId, host);
999
+ pchHits += 1;
1000
+ await directory.writeFile(pchPath.slice(8), pch);
1001
+ } else {
1002
+ const baseKey = await objectCache.unitManifestKey(pins, configKey, pchHeader, headerBytes);
1003
+ const pchManifestKey = await sha256Hex(JSON.stringify({
1004
+ baseKey,
1005
+ mode: "c++-header"
1006
+ }));
1007
+ const cached = await objectCache.lookupPch(pchManifestKey, projectFiles);
1008
+ if (cached) {
1009
+ pch = cached;
1010
+ pchHits += 1;
1011
+ await directory.writeFile(pchPath.slice(8), pch);
1012
+ } else {
1013
+ pchMisses += 1;
1014
+ const dependencyPath = "/project/build/wasm-oj.pch.d";
1015
+ const args = instantiateClangPch(config.cc1, pins.placeholders, pchHeader, pchPath);
1016
+ args.splice(args.length - 1, 0, ...dependencies.includeDirectories.flatMap((directory) => ["-I", directory]));
1017
+ args.push("-dependency-file", dependencyPath, "-MT", pchPath);
1018
+ const output = await runPchStage(compiler, args, directory, host, requestId, pchPath, dependencyPath);
1019
+ structuredDiagnostics.push(...output.diagnostics);
1020
+ stdout += output.stdout;
1021
+ stderr += output.stderr;
1022
+ if (!output.pch || !output.dependency) return failedBuild(project, stdout, stderr, 1, "clang", structuredDiagnostics);
1023
+ pch = output.pch;
1024
+ if (await objectCache.storePch(pchManifestKey, parseClangDependencyFile(output.dependency), projectFiles, pch)) pchStores += 1;
1025
+ }
1026
+ }
1027
+ pchInput = {
1028
+ kind: "pch",
1029
+ identity: `pch:${pchHeader}`,
1030
+ digest: await sha256Hex(pch)
1031
+ };
1032
+ }
1033
+ host.progress(requestId, "compiling", `Compiling ${units.length} translation units with SDK-direct cc1`, .35);
1034
+ host.trace(requestId, "commandStart", "start");
1035
+ host.trace(requestId, "commandStart", "end");
1036
+ host.trace(requestId, "commandWait", "start");
1037
+ host.trace(requestId, "projectCompile", "start");
1038
+ for (const [index, source] of units.entries()) {
1039
+ if (source === ".wasm-oj/determinism.c") {
1040
+ host.trace(requestId, "projectCompile", "end");
1041
+ host.trace(requestId, "runtimeShimCompile", "start");
1042
+ }
1043
+ const objectPath = `/project/build/${String(index).padStart(4, "0")}.o`;
1044
+ const dependencyPath = `/project/build/${String(index).padStart(4, "0")}.d`;
1045
+ const sourceBytes = projectFiles.get(source);
1046
+ if (!sourceBytes) throw new Error(`SDK-direct Clang is missing source bytes for '${source}'.`);
1047
+ const baseManifestKey = await objectCache.unitManifestKey(pins, configKey, source, sourceBytes);
1048
+ const unitPchInput = source !== ".wasm-oj/determinism.c" ? pchInput : void 0;
1049
+ const manifestKey = unitPchInput ? await sha256Hex(JSON.stringify({
1050
+ baseManifestKey,
1051
+ pch: unitPchInput.digest
1052
+ })) : baseManifestKey;
1053
+ const additionalInputs = unitPchInput ? [unitPchInput] : [];
1054
+ const cached = await objectCache.lookup(manifestKey, projectFiles, additionalInputs);
1055
+ if (cached) {
1056
+ await directory.writeFile(objectPath.slice(8), cached);
1057
+ objectCacheHits += 1;
1058
+ objectPaths.push(objectPath);
1059
+ objectInputs.push({
1060
+ kind: "object",
1061
+ identity: source,
1062
+ bytes: cached
1063
+ });
1064
+ continue;
1065
+ }
1066
+ const args = instantiateClangCc1(config.cc1, pins.placeholders, source, objectPath);
1067
+ args.splice(args.length - 1, 0, ...dependencies.includeDirectories.flatMap((directory) => ["-I", directory]));
1068
+ if (unitPchInput) args.splice(args.length - 1, 0, "-include-pch", pchPath, ...admittedPch ? ["-fno-validate-pch"] : []);
1069
+ args.push("-dependency-file", dependencyPath, "-MT", objectPath);
1070
+ const output = await runClangStage(compiler, args, directory, host, requestId, source === ".wasm-oj/determinism.c" ? "runtimeShimSpawn" : "projectSpawn", source === ".wasm-oj/determinism.c" ? "runtimeShimWait" : "projectWait", source === ".wasm-oj/determinism.c" ? "runtimeShimOutputReady" : "projectOutputReady", objectPath, dependencyPath);
1071
+ structuredDiagnostics.push(...output.diagnostics);
1072
+ stdout += output.stdout;
1073
+ stderr += output.stderr;
1074
+ if (!output.object || !output.dependency) {
1075
+ host.trace(requestId, source === ".wasm-oj/determinism.c" ? "runtimeShimCompile" : "projectCompile", "end");
1076
+ host.trace(requestId, "commandWait", "end");
1077
+ return failedBuild(project, stdout, stderr, 1, "clang", structuredDiagnostics);
1078
+ }
1079
+ if (output.diagnostics.length === 0 && await objectCache.store(manifestKey, parseClangDependencyFile(output.dependency), projectFiles, output.object, additionalInputs)) objectCacheStores += 1;
1080
+ objectPaths.push(objectPath);
1081
+ objectInputs.push({
1082
+ kind: "object",
1083
+ identity: source,
1084
+ bytes: output.object
1085
+ });
1086
+ }
1087
+ host.trace(requestId, "runtimeShimCompile", "end");
1088
+ host.progress(requestId, "linking", "Linking SDK-direct Clang objects", .8);
1089
+ host.trace(requestId, "link", "start");
1090
+ const outputPath = "/project/build/app.wasm";
1091
+ const linkArguments = instantiateClangLink(config.link, pins.placeholders, objectPaths, outputPath);
1092
+ const linkManifestKey = await sha256Hex(JSON.stringify({
1093
+ pins: pins.sourceSha256,
1094
+ package: CLANG_PACKAGE_SHA256,
1095
+ target: project.config.target,
1096
+ arguments: config.link
1097
+ }));
1098
+ let bytes = await objectCache.lookupLink(linkManifestKey, objectInputs);
1099
+ let linkedStdout = "";
1100
+ let linkedStderr = "";
1101
+ if (bytes) linkHits += 1;
1102
+ else {
1103
+ linkMisses += 1;
1104
+ const linked = await runLinkStage(linker, linkArguments, directory, host, requestId, "linkSpawn", "linkWait", "linkOutputReady", outputPath);
1105
+ linkedStdout = linked.stdout;
1106
+ linkedStderr = linked.stderr;
1107
+ bytes = linked.value;
1108
+ if (bytes && await objectCache.storeLink(linkManifestKey, objectInputs, bytes)) linkStores += 1;
1109
+ }
1110
+ host.trace(requestId, "link", "end");
1111
+ host.trace(requestId, "commandWait", "end");
1112
+ stdout += linkedStdout;
1113
+ stderr += linkedStderr;
1114
+ if (!bytes) return failedBuild(project, stdout, stderr, 1, "wasm-ld", structuredDiagnostics);
1115
+ host.progress(requestId, "linking", "Reading linked WebAssembly module", .95);
1116
+ host.trace(requestId, "artifactReadback", "start");
1117
+ host.trace(requestId, "artifactReadback", "end");
1118
+ return {
1119
+ success: true,
1120
+ diagnostics: structuredDiagnostics,
1121
+ artifact: {
1122
+ kind: "wasm",
1123
+ wasmOjContract: WASM_OJ_CONTRACT_VERSION,
1124
+ id: crypto.randomUUID(),
1125
+ projectId: project.id,
1126
+ cacheKey,
1127
+ name: `${project.name}.wasm`,
1128
+ language: project.config.language,
1129
+ target: project.config.target,
1130
+ optimization: project.config.optimization,
1131
+ createdAt: Date.now(),
1132
+ durationMs: performance.now() - started,
1133
+ size: bytes.byteLength,
1134
+ toolchains: toolchainPackageIdentities(project.config.language),
1135
+ costProfile: costProfileId(project.config.language, project.config.target, project.config.optimization),
1136
+ ...project.dependencies === void 0 ? {} : { dependencyLockSha256: project.dependencies.lockSha256 },
1137
+ bytes
1138
+ },
1139
+ stdout,
1140
+ stderr,
1141
+ cacheHit: false,
1142
+ buildGraph: {
1143
+ hits: {
1144
+ pch: pchHits,
1145
+ object: objectCacheHits,
1146
+ "link-result": linkHits
1147
+ },
1148
+ misses: {
1149
+ pch: pchMisses,
1150
+ object: units.length - objectCacheHits,
1151
+ "link-result": linkMisses
1152
+ },
1153
+ stores: {
1154
+ pch: pchStores,
1155
+ object: objectCacheStores,
1156
+ "link-result": linkStores
1157
+ }
1158
+ }
1159
+ };
1160
+ } finally {
1161
+ directory.free();
1162
+ }
1163
+ }
1164
+ async function clearSdkDirectClangCaches() {
1165
+ await disposeSdkDirectClangToolchain();
1166
+ loadedLibcxxPchManifest = void 0;
1167
+ loadedLibcxxPch.clear();
1168
+ objectCache.clear();
1169
+ }
1170
+ /** Release all SDK resources tied to one Runtime while preserving object-cache bytes. */
1171
+ async function disposeSdkDirectClangToolchain() {
1172
+ const pending = loadedToolchain;
1173
+ loadedToolchain = void 0;
1174
+ if (!pending) return;
1175
+ const { pkg, compiler, linker } = await pending;
1176
+ compiler.free();
1177
+ linker.free();
1178
+ pkg.free();
1179
+ }
1180
+ async function ensureToolchain(requestId, host) {
1181
+ if (loadedToolchain) {
1182
+ for (const operation of [
1183
+ "toolchainFetch",
1184
+ "toolchainDecode",
1185
+ "toolchainLoad"
1186
+ ]) {
1187
+ host.trace(requestId, operation, "start");
1188
+ host.trace(requestId, operation, "end");
1189
+ }
1190
+ return loadedToolchain;
1191
+ }
1192
+ loadedToolchain = (async () => {
1193
+ host.trace(requestId, "toolchainFetch", "start");
1194
+ const [packageBytes, pinsBytes] = await Promise.all([host.loadToolchainAsset(CLANG_PACKAGE_ASSET_PATH), host.loadToolchainFile(CLANG_CC1_PINS_ASSET_PATH)]);
1195
+ host.trace(requestId, "toolchainFetch", "end");
1196
+ host.trace(requestId, "toolchainDecode", "start");
1197
+ const pins = await decodeClangPins(pinsBytes);
1198
+ const packageSha256 = await sha256Hex(packageBytes);
1199
+ if (packageSha256 !== "21ded33b9c6d4e1aaad5528c940bdaf6c3e84be77ea8f522f018ca7289a2a224") throw new Error(`Pinned Clang package digest mismatch: received ${packageSha256}.`);
1200
+ host.trace(requestId, "toolchainDecode", "end");
1201
+ host.trace(requestId, "toolchainLoad", "start");
1202
+ const pkg = await Wasmer$1.fromFile(packageBytes, host.runtime);
1203
+ const compiler = requireCommand(pkg, pins.command);
1204
+ const linker = requireCommand(pkg, pins.linkerCommand);
1205
+ host.trace(requestId, "toolchainLoad", "end");
1206
+ return {
1207
+ pkg,
1208
+ pins,
1209
+ compiler,
1210
+ linker
1211
+ };
1212
+ })();
1213
+ try {
1214
+ return await loadedToolchain;
1215
+ } catch (error) {
1216
+ loadedToolchain = void 0;
1217
+ throw error;
1218
+ }
1219
+ }
1220
+ function requireCommand(pkg, name) {
1221
+ const selected = pkg.commands[name];
1222
+ if (!selected) throw new Error(`The SDK-direct Clang package does not expose '${name}'.`);
1223
+ return selected;
1224
+ }
1225
+ async function loadLibcxxPch(profile, requestId, host) {
1226
+ loadedLibcxxPchManifest ??= host.loadToolchainFile(CLANG_LIBCXX_PCH_MANIFEST_ASSET_PATH).then(decodeLibcxxPchManifest);
1227
+ let pending = loadedLibcxxPch.get(profile);
1228
+ if (!pending) {
1229
+ pending = loadedLibcxxPchManifest.then(async (manifest) => {
1230
+ const asset = manifest.profiles[profile];
1231
+ host.progress(requestId, "loading-toolchain", `Loading admitted libc++ PCH (${profile})`, .25);
1232
+ const bytes = await host.loadToolchainAsset(`/toolchains/${asset.path}`);
1233
+ if (bytes.byteLength !== asset.byteLength || await sha256Hex(bytes) !== asset.sha256) throw new Error(`Pinned libc++ PCH '${profile}' failed decompressed integrity verification.`);
1234
+ return bytes;
1235
+ });
1236
+ loadedLibcxxPch.set(profile, pending);
1237
+ }
1238
+ try {
1239
+ return await pending;
1240
+ } catch (error) {
1241
+ loadedLibcxxPch.delete(profile);
1242
+ throw error;
1243
+ }
1244
+ }
1245
+ function findPrecompiledHeader(project) {
1246
+ const headers = project.files.map((file) => file.path).filter((path) => path.split("/").at(-1) === "wasm-oj.pch.hpp");
1247
+ if (headers.length > 1) throw new Error(`C++ projects may contain at most one wasm-oj.pch.hpp; received ${headers.join(", ")}.`);
1248
+ return headers[0];
1249
+ }
1250
+ function runPchStage(command, args, directory, host, requestId, outputPath, dependencyPath) {
1251
+ const stability = new MountedOutputStabilityObserver();
1252
+ return runUntilOutputReady(command, args, directory, host, requestId, "projectSpawn", "projectWait", "projectOutputReady", async (capturedStderr) => {
1253
+ const [snapshot, dependency] = await Promise.all([readOptionalFile(directory, outputPath), readOptionalFile(directory, dependencyPath)]);
1254
+ const pch = stability.observe(snapshot?.byteLength ? snapshot : void 0, performance.now());
1255
+ if (pch && dependency?.byteLength && decoder.decode(dependency).endsWith("\n")) return {
1256
+ pch,
1257
+ dependency
1258
+ };
1259
+ return /\d+ errors? generated\.\s*$/.test(capturedStderr) ? {} : void 0;
1260
+ }).then((observed) => ({
1261
+ ...observed.value,
1262
+ diagnostics: parseClangDiagnostics(`${observed.stderr}\n${observed.stdout}`),
1263
+ stdout: observed.stdout,
1264
+ stderr: observed.stderr
1265
+ }));
1266
+ }
1267
+ function runClangStage(command, args, directory, host, requestId, spawnOperation, waitOperation, outputReadyOperation, outputPath, dependencyPath) {
1268
+ return runUntilOutputReady(command, args, directory, host, requestId, spawnOperation, waitOperation, outputReadyOperation, async (capturedStderr) => {
1269
+ const [object, dependency] = await Promise.all([readValidWasmFile(directory, outputPath), readOptionalFile(directory, dependencyPath)]);
1270
+ if (object && dependency?.byteLength && decoder.decode(dependency).endsWith("\n")) return {
1271
+ object,
1272
+ dependency
1273
+ };
1274
+ return /\d+ errors? generated\.\s*$/.test(capturedStderr) ? {} : void 0;
1275
+ }).then((observed) => ({
1276
+ ...observed.value,
1277
+ diagnostics: parseClangDiagnostics(`${observed.stderr}\n${observed.stdout}`),
1278
+ stdout: observed.stdout,
1279
+ stderr: observed.stderr
1280
+ }));
1281
+ }
1282
+ function runLinkStage(command, args, directory, host, requestId, spawnOperation, waitOperation, outputReadyOperation, outputPath) {
1283
+ return runUntilOutputReady(command, args, directory, host, requestId, spawnOperation, waitOperation, outputReadyOperation, async (capturedStderr) => {
1284
+ const output = await readValidWasmFile(directory, outputPath);
1285
+ if (output) return output;
1286
+ return /(?:wasm-ld|lld): error:/i.test(capturedStderr) ? null : void 0;
1287
+ }).then((observed) => ({
1288
+ ...observed,
1289
+ value: observed.value ?? void 0
1290
+ }));
1291
+ }
1292
+ async function runUntilOutputReady(command, args, directory, host, requestId, spawnOperation, waitOperation, outputReadyOperation, probe) {
1293
+ host.trace(requestId, spawnOperation, "start");
1294
+ const instance = await command.run({
1295
+ args,
1296
+ cwd: "/project",
1297
+ env: {
1298
+ PATH: "/bin",
1299
+ SOURCE_DATE_EPOCH: "946684800",
1300
+ TZ: "UTC",
1301
+ LC_ALL: "C"
1302
+ },
1303
+ mount: { "/project": directory }
1304
+ });
1305
+ host.trace(requestId, spawnOperation, "end");
1306
+ host.trace(requestId, waitOperation, "start");
1307
+ host.trace(requestId, outputReadyOperation, "start");
1308
+ const stdoutCapture = captureReadable(instance.stdout);
1309
+ const stderrCapture = captureReadable(instance.stderr);
1310
+ const deadline = performance.now() + STAGE_OUTPUT_TIMEOUT_MS;
1311
+ try {
1312
+ while (performance.now() < deadline) {
1313
+ const result = await probe(stderrCapture.text());
1314
+ if (result !== void 0) {
1315
+ await new Promise((resolve) => setTimeout(resolve, 0));
1316
+ return {
1317
+ value: result,
1318
+ stdout: stdoutCapture.text(),
1319
+ stderr: stderrCapture.text()
1320
+ };
1321
+ }
1322
+ await new Promise((resolve) => setTimeout(resolve, 5));
1323
+ }
1324
+ throw new Error(`Compiler stage did not produce a complete output within ${STAGE_OUTPUT_TIMEOUT_MS} ms.`);
1325
+ } finally {
1326
+ host.trace(requestId, outputReadyOperation, "end");
1327
+ host.trace(requestId, waitOperation, "end");
1328
+ await Promise.all([stdoutCapture.cancel(), stderrCapture.cancel()]);
1329
+ instance.free();
1330
+ }
1331
+ }
1332
+ function captureReadable(stream) {
1333
+ const reader = stream.getReader();
1334
+ const chunks = [];
1335
+ (async () => {
1336
+ try {
1337
+ while (true) {
1338
+ const result = await reader.read();
1339
+ if (result.done) return;
1340
+ const bytes = result.value instanceof Uint8Array ? result.value : new Uint8Array(result.value);
1341
+ chunks.push(bytes.slice());
1342
+ }
1343
+ } catch {}
1344
+ })();
1345
+ return {
1346
+ text: () => decoder.decode(concatenate(chunks)),
1347
+ cancel: async () => {
1348
+ try {
1349
+ await reader.cancel();
1350
+ } catch {}
1351
+ }
1352
+ };
1353
+ }
1354
+ function concatenate(chunks) {
1355
+ const output = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.byteLength, 0));
1356
+ let offset = 0;
1357
+ for (const chunk of chunks) {
1358
+ output.set(chunk, offset);
1359
+ offset += chunk.byteLength;
1360
+ }
1361
+ return output;
1362
+ }
1363
+ async function readValidWasmFile(directory, guestPath) {
1364
+ const bytes = await readOptionalFile(directory, guestPath);
1365
+ if (!bytes || bytes.byteLength <= 8) return void 0;
1366
+ const copy = new Uint8Array(bytes.byteLength);
1367
+ copy.set(bytes);
1368
+ return WebAssembly.validate(copy.buffer) ? copy : void 0;
1369
+ }
1370
+ async function ensureDirectory(directory, path) {
1371
+ try {
1372
+ await directory.createDir(path);
1373
+ } catch (error) {
1374
+ if (!String(error).toLowerCase().includes("exist")) throw error;
1375
+ }
1376
+ }
1377
+ async function readOptionalFile(directory, guestPath) {
1378
+ const mountRelativePath = guestPath.startsWith("/project/") ? guestPath.slice(8) : guestPath;
1379
+ try {
1380
+ return await directory.readFile(mountRelativePath);
1381
+ } catch {
1382
+ return;
1383
+ }
1384
+ }
1385
+ function failedBuild(project, stdout, stderr, code, source, providedDiagnostics) {
1386
+ return {
1387
+ success: false,
1388
+ diagnostics: ensureFailureDiagnostic(providedDiagnostics ?? parseClangDiagnostics(`${stderr}\n${stdout}`), {
1389
+ file: project.config.entry,
1390
+ source,
1391
+ message: stderr.trim() || `${source} exited with code ${code}.`
1392
+ }),
1393
+ stdout,
1394
+ stderr,
1395
+ cacheHit: false
1396
+ };
1397
+ }
1398
+ new TextEncoder();
1399
+ Object.freeze({
1400
+ python: "python",
1401
+ javascript: "qjs",
1402
+ typescript: "qjs"
1403
+ });
1404
+ function requiredTrimmedString(value, label, maximum = 16384) {
1405
+ if (typeof value !== "string" || !value || value !== value.trim() || value.length > maximum) throw new Error(`${label} must be a non-empty, trimmed string of at most ${maximum} characters.`);
1406
+ }
1407
+ function serializeRuntimeBundleManifest(data) {
1408
+ return JSON.stringify({
1409
+ schema: WASM_OJ_SCHEMAS.runtimeBundle,
1410
+ version: WASM_OJ_CONTRACT_VERSION,
1411
+ name: data.name,
1412
+ target: data.target,
1413
+ language: data.language,
1414
+ runtime: {
1415
+ package: data.runtimePackage,
1416
+ command: data.command
1417
+ },
1418
+ execution: {
1419
+ deterministic: true,
1420
+ contractVersion: WASM_OJ_CONTRACT_VERSION
1421
+ },
1422
+ entry: data.entry,
1423
+ files: [...data.files]
1424
+ }, null, 2);
1425
+ }
1426
+ /** Canonical WASM-OJ manifest constructor for built-in and downstream runtime bundles. */
1427
+ function createRuntimeBundleManifest(project, runtimePackage, command, entry) {
1428
+ requiredTrimmedString(project.name, "Project name");
1429
+ requiredTrimmedString(runtimePackage, "Runtime package");
1430
+ requiredTrimmedString(command, "Runtime command", 128);
1431
+ assertLanguageIdentifier(project.config.language);
1432
+ assertSafeRelativePath(entry, "Runtime bundle entry");
1433
+ return serializeRuntimeBundleManifest({
1434
+ name: project.name,
1435
+ target: project.config.target,
1436
+ language: project.config.language,
1437
+ runtimePackage,
1438
+ command,
1439
+ entry,
1440
+ files: canonicalProjectFiles(project.files).map((file) => file.path)
1441
+ });
1442
+ }
1443
+ /** Produces a new record whose insertion order is canonical and path-safe. */
1444
+ function canonicalRuntimeBundleFiles(files) {
1445
+ return canonicalFileRecord(files);
1446
+ }
1447
+ //#endregion
1448
+ //#region src/core/quickjs-runtime.ts
1449
+ var QUICKJS_STD_MODULE_DECLARATION = String.raw`
1450
+ declare module "std" {
1451
+ const std: {
1452
+ err: { puts(value: string): void };
1453
+ in: { readAsString(): string };
1454
+ out: { puts(value: string): void };
1455
+ };
1456
+ export = std;
1457
+ }
1458
+ `;
1459
+ //#endregion
1460
+ //#region src/compiler/language-driver.ts
1461
+ /** Internal registry for WASM-OJ's built-in compiler pipelines. */
1462
+ var LanguageDriverRegistry = class {
1463
+ drivers = /* @__PURE__ */ new Map();
1464
+ ids = /* @__PURE__ */ new Set();
1465
+ register(driver) {
1466
+ if (!driver || typeof driver !== "object") throw new TypeError("Language drivers must be objects.");
1467
+ if (typeof driver.id !== "string" || !driver.id || driver.id !== driver.id.trim() || driver.id.length > 128) throw new Error("Language driver IDs must be non-empty, trimmed, and at most 128 characters.");
1468
+ if (this.ids.has(driver.id)) throw new Error(`Language driver '${driver.id}' is already registered.`);
1469
+ if (!Array.isArray(driver.languages) || driver.languages.length === 0) throw new Error(`Language driver '${driver.id}' has no languages.`);
1470
+ if (typeof driver.build !== "function") throw new TypeError(`Language driver '${driver.id}' must implement build().`);
1471
+ const languages = /* @__PURE__ */ new Set();
1472
+ for (const language of driver.languages) {
1473
+ if (typeof language !== "string") throw new TypeError("Language identifiers must be strings.");
1474
+ assertLanguageIdentifier(language);
1475
+ if (languages.has(language)) throw new Error(`Language '${language}' is duplicated in driver '${driver.id}'.`);
1476
+ languages.add(language);
1477
+ const existing = this.drivers.get(language);
1478
+ if (existing) throw new Error(`Language '${language}' is already owned by driver '${existing.id}'.`);
1479
+ }
1480
+ for (const language of languages) this.drivers.set(language, driver);
1481
+ this.ids.add(driver.id);
1482
+ }
1483
+ driver(language) {
1484
+ const driver = this.drivers.get(language);
1485
+ if (!driver) throw new Error(`No language driver is registered for '${language}'.`);
1486
+ return driver;
1487
+ }
1488
+ languages() {
1489
+ return [...this.drivers.keys()];
1490
+ }
1491
+ };
1492
+ //#endregion
1493
+ //#region src/compiler/wasmer-engine.ts
1494
+ var encoder = new TextEncoder();
1495
+ var typescriptCompilerBytes;
1496
+ var host;
1497
+ function configureWasmerCompilerHost(nextHost) {
1498
+ host = nextHost;
1499
+ }
1500
+ function progress(requestId, phase, label, value) {
1501
+ requireHost().progress(requestId, phase, label, value);
1502
+ }
1503
+ function requireHost() {
1504
+ if (!host) throw new Error("Wasmer compiler host is not configured.");
1505
+ return host;
1506
+ }
1507
+ function requireRuntime() {
1508
+ return requireHost().getRuntime();
1509
+ }
1510
+ async function getTypeScriptCompiler() {
1511
+ typescriptCompilerBytes ??= requireHost().loadToolchainAsset(TYPESCRIPT_ASSET_PATH);
1512
+ try {
1513
+ return Wasmer$1.fromWasm(await typescriptCompilerBytes, requireRuntime());
1514
+ } catch (error) {
1515
+ typescriptCompilerBytes = void 0;
1516
+ throw error;
1517
+ }
1518
+ }
1519
+ function createArtifactBase(project, cacheKey, started, size, toolchains, contentIdentity) {
1520
+ return {
1521
+ wasmOjContract: WASM_OJ_CONTRACT_VERSION,
1522
+ id: crypto.randomUUID(),
1523
+ projectId: project.id,
1524
+ cacheKey,
1525
+ name: `${project.name}.${project.config.target === "wasip1" ? "wasm" : "wasix.wasm"}`,
1526
+ language: project.config.language,
1527
+ target: project.config.target,
1528
+ optimization: project.config.optimization,
1529
+ createdAt: Date.now(),
1530
+ durationMs: performance.now() - started,
1531
+ size,
1532
+ toolchains,
1533
+ costProfile: costProfileId(project.config.language, project.config.target, project.config.optimization, contentIdentity),
1534
+ ...project.dependencies === void 0 ? {} : { dependencyLockSha256: project.dependencies.lockSha256 }
1535
+ };
1536
+ }
1537
+ async function buildRust(project, cacheKey, requestId) {
1538
+ const started = performance.now();
1539
+ progress(requestId, "compiling", `Compiling with rustc ${RUST_VERSION}`, .2);
1540
+ const dependencies = rustDependencyInput(project);
1541
+ const compiled = await requireHost().compileRust({
1542
+ entry: project.config.entry,
1543
+ files: [...project.files, ...dependencies.files],
1544
+ optimization: project.config.optimization,
1545
+ dependencies: dependencies.crates,
1546
+ rootExterns: dependencies.roots
1547
+ });
1548
+ if (!compiled.success || !compiled.wasm) return {
1549
+ success: false,
1550
+ diagnostics: ensureFailureDiagnostic(compiled.diagnostics, {
1551
+ file: project.config.entry,
1552
+ source: "rustc",
1553
+ message: compiled.stderr.trim() || "rustc failed without a diagnostic."
1554
+ }),
1555
+ stdout: compiled.stdout,
1556
+ stderr: compiled.stderr,
1557
+ cacheHit: false
1558
+ };
1559
+ const bytes = compiled.wasm;
1560
+ const artifact = {
1561
+ kind: "wasm",
1562
+ ...createArtifactBase(project, cacheKey, started, bytes.byteLength, toolchainPackageIdentities("rust")),
1563
+ bytes
1564
+ };
1565
+ return {
1566
+ success: true,
1567
+ diagnostics: compiled.diagnostics,
1568
+ artifact,
1569
+ stdout: compiled.stdout,
1570
+ stderr: compiled.stderr,
1571
+ cacheHit: false
1572
+ };
1573
+ }
1574
+ function sumFileSize(files) {
1575
+ return Object.values(files).reduce((total, file) => total + (typeof file === "string" ? encoder.encode(file).byteLength : file.byteLength), 0);
1576
+ }
1577
+ async function buildPython(project, cacheKey, requestId) {
1578
+ const started = performance.now();
1579
+ const dependencies = pythonDependencyFiles(project);
1580
+ const compilerFiles = [...project.files, ...dependencies.sourceFiles];
1581
+ const pythonFiles = compilerFiles.filter((file) => file.path.endsWith(".py"));
1582
+ progress(requestId, "compiling", `Byte-compiling ${pythonFiles.length} Python file${pythonFiles.length === 1 ? "" : "s"}`, .55);
1583
+ const frontend = await requireHost().compilePython({ files: compilerFiles });
1584
+ if (!frontend.success) return {
1585
+ success: false,
1586
+ diagnostics: ensureFailureDiagnostic(frontend.diagnostics, {
1587
+ file: project.config.entry,
1588
+ source: "python",
1589
+ message: frontend.stderr.trim() || "Python byte-compilation failed without a diagnostic."
1590
+ }),
1591
+ stdout: frontend.stdout,
1592
+ stderr: frontend.stderr,
1593
+ cacheHit: false
1594
+ };
1595
+ const files = Object.fromEntries(project.files.map((file) => [file.path, file.content]));
1596
+ Object.assign(files, dependencies.artifactFiles);
1597
+ files[PYTHON_RUNNER_PATH] = PYTHON_DETERMINISTIC_RUNNER;
1598
+ for (const file of pythonFiles) {
1599
+ const compiledPath = `build/${file.path.replace(/\.py$/, ".pyc")}`;
1600
+ const bytecode = frontend.bytecode[compiledPath];
1601
+ if (!bytecode) throw new Error(`Python stage omitted '${compiledPath}'.`);
1602
+ files[compiledPath] = bytecode;
1603
+ }
1604
+ const entry = `build/${project.config.entry.replace(/\.py$/, ".pyc")}`;
1605
+ const manifest = createRuntimeBundleManifest(project, PYTHON_PACKAGE, "python", entry);
1606
+ files["wasm-oj.manifest.json"] = manifest;
1607
+ const bundleFiles = canonicalRuntimeBundleFiles(files);
1608
+ const artifact = {
1609
+ kind: "runtime-bundle",
1610
+ ...createArtifactBase(project, cacheKey, started, sumFileSize(bundleFiles), toolchainPackageIdentities("python")),
1611
+ name: `${project.name}.python-${project.config.target}.json`,
1612
+ runtimePackage: PYTHON_PACKAGE,
1613
+ command: "python",
1614
+ entry,
1615
+ files: bundleFiles,
1616
+ manifest
1617
+ };
1618
+ return {
1619
+ success: true,
1620
+ diagnostics: frontend.diagnostics,
1621
+ artifact,
1622
+ stdout: frontend.stdout,
1623
+ stderr: frontend.stderr,
1624
+ cacheHit: false
1625
+ };
1626
+ }
1627
+ async function buildGo(project, cacheKey, requestId) {
1628
+ const started = performance.now();
1629
+ progress(requestId, "compiling", `Compiling with Go ${GO_VERSION}`, .3);
1630
+ const dependencies = goDependencyInput(project);
1631
+ const compiled = await requireHost().compileGo({
1632
+ entry: project.config.entry,
1633
+ files: project.files,
1634
+ dependencyFiles: dependencies.files,
1635
+ optimization: project.config.optimization,
1636
+ dependencies: dependencies.packages
1637
+ });
1638
+ if (!compiled.success || !compiled.wasm) return {
1639
+ success: false,
1640
+ diagnostics: ensureFailureDiagnostic(compiled.diagnostics, {
1641
+ file: project.config.entry,
1642
+ source: "go",
1643
+ message: compiled.stderr.trim() || "Go compilation failed without a diagnostic."
1644
+ }),
1645
+ stdout: compiled.stdout,
1646
+ stderr: compiled.stderr,
1647
+ cacheHit: false
1648
+ };
1649
+ const artifact = {
1650
+ kind: "wasm",
1651
+ ...createArtifactBase(project, cacheKey, started, compiled.wasm.byteLength, toolchainPackageIdentities("go")),
1652
+ bytes: compiled.wasm
1653
+ };
1654
+ return {
1655
+ success: true,
1656
+ diagnostics: compiled.diagnostics,
1657
+ artifact,
1658
+ stdout: compiled.stdout,
1659
+ stderr: compiled.stderr,
1660
+ cacheHit: false
1661
+ };
1662
+ }
1663
+ async function buildJava(project, cacheKey, requestId) {
1664
+ const started = performance.now();
1665
+ const entry = project.files.find((file) => file.path === project.config.entry);
1666
+ if (!entry || !entry.path.endsWith(".java")) return {
1667
+ success: false,
1668
+ diagnostics: [{
1669
+ severity: "error",
1670
+ message: "The Java entry must be a .java source file.",
1671
+ file: project.config.entry,
1672
+ line: 1,
1673
+ column: 1,
1674
+ source: "project"
1675
+ }],
1676
+ stdout: "",
1677
+ stderr: "",
1678
+ cacheHit: false
1679
+ };
1680
+ progress(requestId, "compiling", `Compiling Java ${javaMainClass(entry.path, entry.content)}`, .3);
1681
+ const compiled = await requireHost().compileJava({
1682
+ entry: project.config.entry,
1683
+ files: project.files,
1684
+ optimization: project.config.optimization
1685
+ });
1686
+ if (!compiled.success || !compiled.wasm) return {
1687
+ success: false,
1688
+ diagnostics: ensureFailureDiagnostic(compiled.diagnostics, {
1689
+ file: project.config.entry,
1690
+ source: "java",
1691
+ message: compiled.stderr.trim() || "Java compilation failed without a diagnostic."
1692
+ }),
1693
+ stdout: compiled.stdout,
1694
+ stderr: compiled.stderr,
1695
+ cacheHit: false
1696
+ };
1697
+ const artifact = {
1698
+ kind: "wasm",
1699
+ ...createArtifactBase(project, cacheKey, started, compiled.wasm.byteLength, toolchainPackageIdentities("java"), toolchainContentIdentity("java")),
1700
+ bytes: compiled.wasm
1701
+ };
1702
+ return {
1703
+ success: true,
1704
+ diagnostics: compiled.diagnostics,
1705
+ artifact,
1706
+ stdout: compiled.stdout,
1707
+ stderr: compiled.stderr,
1708
+ cacheHit: false
1709
+ };
1710
+ }
1711
+ function emittedScriptPath(path) {
1712
+ if (path.endsWith(".ts")) return path.slice(0, -3) + ".js";
1713
+ return path;
1714
+ }
1715
+ function scriptSourceFiles(project) {
1716
+ const extension = project.config.language === "typescript" ? ".ts" : ".js";
1717
+ return project.files.filter((file) => file.path.endsWith(extension));
1718
+ }
1719
+ function emittedSourceFiles(project) {
1720
+ return scriptSourceFiles(project).filter((file) => !file.path.endsWith(".d.ts"));
1721
+ }
1722
+ async function transpileScriptProject(project, requestId) {
1723
+ const scriptFiles = scriptSourceFiles(project);
1724
+ const emittedFiles = emittedSourceFiles(project);
1725
+ const dependencyFiles = npmDependencyFiles(project);
1726
+ progress(requestId, "loading-toolchain", `Loading TypeScript ${TYPESCRIPT_VERSION}/WASI`);
1727
+ const entrypoint = (await getTypeScriptCompiler()).entrypoint;
1728
+ if (!entrypoint) throw new Error("The TypeScript/WASI compiler has no executable entrypoint.");
1729
+ const outputPaths = emittedFiles.map((file) => emittedScriptPath(file.path));
1730
+ const declarationPath = "/project/.wasm-oj/quickjs.d.ts";
1731
+ const output = await (await entrypoint.run({ stdin: JSON.stringify({
1732
+ files: {
1733
+ ...Object.fromEntries(project.files.map((file) => [`/project/${file.path}`, file.content])),
1734
+ ...Object.fromEntries(Object.entries(dependencyFiles).filter(([, contents]) => typeof contents === "string").map(([path, contents]) => [`/project/${path}`, contents])),
1735
+ [declarationPath]: QUICKJS_STD_MODULE_DECLARATION
1736
+ },
1737
+ javascript: project.config.language === "javascript",
1738
+ sources: [
1739
+ declarationPath,
1740
+ ...scriptFiles.map((file) => `/project/${file.path}`),
1741
+ ...Object.entries(dependencyFiles).filter(([path, contents]) => path.endsWith(".d.ts") && typeof contents === "string").map(([path]) => `/project/${path}`)
1742
+ ],
1743
+ outputs: outputPaths.map((path) => `/project/build/${path}`)
1744
+ }) })).wait();
1745
+ let response;
1746
+ if (output.ok) try {
1747
+ response = JSON.parse(output.stdout);
1748
+ } catch {
1749
+ response = void 0;
1750
+ }
1751
+ const files = {};
1752
+ if (response) for (const outputPath of outputPaths) {
1753
+ const contents = response.files[`/project/build/${outputPath}`];
1754
+ if (contents !== void 0) files[outputPath] = contents;
1755
+ }
1756
+ Object.assign(files, dependencyFiles);
1757
+ return {
1758
+ files,
1759
+ output,
1760
+ response
1761
+ };
1762
+ }
1763
+ async function buildScript(project, cacheKey, requestId) {
1764
+ const started = performance.now();
1765
+ if (!emittedSourceFiles(project).some((file) => file.path === project.config.entry)) return {
1766
+ success: false,
1767
+ diagnostics: [{
1768
+ severity: "error",
1769
+ message: `The ${project.config.language === "typescript" ? ".ts" : ".js"} entry file is not a supported executable source.`,
1770
+ file: project.config.entry,
1771
+ line: 1,
1772
+ column: 1,
1773
+ source: "project"
1774
+ }],
1775
+ stdout: "",
1776
+ stderr: "",
1777
+ cacheHit: false
1778
+ };
1779
+ progress(requestId, "compiling", `Compiling ${project.config.language === "typescript" ? "TypeScript" : "JavaScript"} with TypeScript/WASI`, .5);
1780
+ const { files, output, response } = await transpileScriptProject(project, requestId);
1781
+ const diagnostics = parseTypeScriptDiagnostics(response?.diagnostics ?? "");
1782
+ const emittedOutputsPresent = emittedSourceFiles(project).every((file) => Object.hasOwn(files, emittedScriptPath(file.path)));
1783
+ if (!output.ok || !response || response.status !== 0 || !emittedOutputsPresent || diagnostics.some((diagnostic) => diagnostic.severity === "error")) return {
1784
+ success: false,
1785
+ diagnostics: ensureFailureDiagnostic(diagnostics, {
1786
+ file: project.config.entry,
1787
+ source: "typescript",
1788
+ message: output.stderr.trim() || response?.diagnostics.trim() || `TypeScript 7.0.2 did not return every compiled output.`
1789
+ }),
1790
+ stdout: "",
1791
+ stderr: output.stderr,
1792
+ cacheHit: false
1793
+ };
1794
+ const entry = emittedScriptPath(project.config.entry);
1795
+ const manifest = createRuntimeBundleManifest(project, QUICKJS_PACKAGE, "qjs", entry);
1796
+ files["wasm-oj.manifest.json"] = manifest;
1797
+ const bundleFiles = canonicalRuntimeBundleFiles(files);
1798
+ return {
1799
+ success: true,
1800
+ diagnostics,
1801
+ artifact: {
1802
+ kind: "runtime-bundle",
1803
+ ...createArtifactBase(project, cacheKey, started, sumFileSize(bundleFiles), toolchainPackageIdentities(project.config.language)),
1804
+ name: `${project.name}.${project.config.language === "typescript" ? "typescript" : "javascript"}-${project.config.target}.json`,
1805
+ runtimePackage: QUICKJS_PACKAGE,
1806
+ command: "qjs",
1807
+ entry,
1808
+ files: bundleFiles,
1809
+ manifest
1810
+ },
1811
+ stdout: "",
1812
+ stderr: output.stderr,
1813
+ cacheHit: false
1814
+ };
1815
+ }
1816
+ async function buildProject(project, cacheKey, requestId) {
1817
+ const canonicalProject = {
1818
+ ...project,
1819
+ files: canonicalProjectFiles(project.files)
1820
+ };
1821
+ assertProjectDependencyEcosystem(canonicalProject);
1822
+ progress(requestId, "checking", "Validating project configuration", .05);
1823
+ if (!canonicalProject.files.some((file) => file.path === canonicalProject.config.entry)) return {
1824
+ success: false,
1825
+ diagnostics: [{
1826
+ severity: "error",
1827
+ message: "Configured entry file does not exist.",
1828
+ file: canonicalProject.config.entry,
1829
+ line: 1,
1830
+ column: 1,
1831
+ source: "project"
1832
+ }],
1833
+ stdout: "",
1834
+ stderr: "",
1835
+ cacheHit: false
1836
+ };
1837
+ if (canonicalProject.config.language === "c" || canonicalProject.config.language === "cpp") {
1838
+ const activeHost = requireHost();
1839
+ return buildClangWithSdkDirect(canonicalProject, cacheKey, requestId, {
1840
+ runtime: activeHost.getRuntime(),
1841
+ loadToolchainAsset: activeHost.loadToolchainAsset,
1842
+ loadToolchainFile: activeHost.loadToolchainFile,
1843
+ progress: activeHost.progress,
1844
+ trace: activeHost.trace
1845
+ });
1846
+ }
1847
+ return languageDrivers.driver(canonicalProject.config.language).build({
1848
+ project: canonicalProject,
1849
+ cacheKey,
1850
+ requestId
1851
+ });
1852
+ }
1853
+ var languageDrivers = new LanguageDriverRegistry();
1854
+ languageDrivers.register({
1855
+ id: "rustc",
1856
+ languages: ["rust"],
1857
+ build: ({ project, cacheKey, requestId }) => buildRust(project, cacheKey, requestId)
1858
+ });
1859
+ languageDrivers.register({
1860
+ id: "cpython",
1861
+ languages: ["python"],
1862
+ build: ({ project, cacheKey, requestId }) => buildPython(project, cacheKey, requestId)
1863
+ });
1864
+ languageDrivers.register({
1865
+ id: "typescript",
1866
+ languages: ["javascript", "typescript"],
1867
+ build: ({ project, cacheKey, requestId }) => buildScript(project, cacheKey, requestId)
1868
+ });
1869
+ languageDrivers.register({
1870
+ id: "go",
1871
+ languages: ["go"],
1872
+ build: ({ project, cacheKey, requestId }) => buildGo(project, cacheKey, requestId)
1873
+ });
1874
+ languageDrivers.register({
1875
+ id: "teavm-java",
1876
+ languages: ["java"],
1877
+ build: ({ project, cacheKey, requestId }) => buildJava(project, cacheKey, requestId)
1878
+ });
1879
+ function clearCompilerHostCaches() {
1880
+ typescriptCompilerBytes = void 0;
1881
+ }
1882
+ //#endregion
1883
+ //#region src/server/wasmer-runtime.ts
1884
+ var initialization;
1885
+ async function initializeServerWasmerSdk() {
1886
+ initialization ??= init({ log: "error" }).then(() => void 0);
1887
+ try {
1888
+ await initialization;
1889
+ } catch (error) {
1890
+ initialization = void 0;
1891
+ throw error;
1892
+ }
1893
+ }
1894
+ //#endregion
1895
+ //#region src/server/bounded-transport.ts
1896
+ /** Collects a child-process channel without permitting unbounded host memory growth. */
1897
+ var BoundedByteCollector = class {
1898
+ chunks = [];
1899
+ label;
1900
+ maximumBytes;
1901
+ onLimitExceeded;
1902
+ totalBytes = 0;
1903
+ limitError;
1904
+ constructor(label, maximumBytes, onLimitExceeded) {
1905
+ if (!Number.isSafeInteger(maximumBytes) || maximumBytes <= 0) throw new TypeError("A bounded transport limit must be a positive safe integer.");
1906
+ this.label = label;
1907
+ this.maximumBytes = maximumBytes;
1908
+ this.onLimitExceeded = onLimitExceeded;
1909
+ }
1910
+ append(chunk) {
1911
+ if (this.limitError) return;
1912
+ this.totalBytes += chunk.byteLength;
1913
+ if (this.totalBytes > this.maximumBytes) {
1914
+ this.limitError = /* @__PURE__ */ new Error(`${this.label} exceeded the ${this.maximumBytes} byte transport boundary.`);
1915
+ this.chunks.length = 0;
1916
+ this.onLimitExceeded(this.limitError);
1917
+ return;
1918
+ }
1919
+ this.chunks.push(Buffer.from(chunk));
1920
+ }
1921
+ bytes() {
1922
+ if (this.limitError) throw this.limitError;
1923
+ return Buffer.concat(this.chunks, this.totalBytes);
1924
+ }
1925
+ text() {
1926
+ return this.bytes().toString();
1927
+ }
1928
+ };
1929
+ /** Reads a private one-shot response through a stable descriptor and enforces a hard byte cap. */
1930
+ async function readBoundedRegularFile(filename, maximumBytes) {
1931
+ if (!Number.isSafeInteger(maximumBytes) || maximumBytes <= 0) throw new TypeError("A bounded file limit must be a positive safe integer.");
1932
+ const pathStatus = await lstat(filename);
1933
+ if (!pathStatus.isFile()) throw new Error(`Transport response '${filename}' must be a regular file.`);
1934
+ if (pathStatus.size > maximumBytes) throw new Error(`Transport response '${filename}' exceeds the ${maximumBytes} byte boundary.`);
1935
+ const handle = await open(filename, "r");
1936
+ try {
1937
+ const descriptorStatus = await handle.stat();
1938
+ if (!descriptorStatus.isFile() || descriptorStatus.dev !== pathStatus.dev || descriptorStatus.ino !== pathStatus.ino) throw new Error(`Transport response '${filename}' changed before it could be read.`);
1939
+ const chunks = [];
1940
+ let totalBytes = 0;
1941
+ while (true) {
1942
+ const chunk = Buffer.allocUnsafe(Math.min(65536, maximumBytes - totalBytes + 1));
1943
+ const { bytesRead } = await handle.read(chunk, 0, chunk.byteLength, null);
1944
+ if (bytesRead === 0) break;
1945
+ totalBytes += bytesRead;
1946
+ if (totalBytes > maximumBytes) throw new Error(`Transport response '${filename}' exceeds the ${maximumBytes} byte boundary.`);
1947
+ chunks.push(chunk.subarray(0, bytesRead));
1948
+ }
1949
+ return Buffer.concat(chunks, totalBytes);
1950
+ } finally {
1951
+ await handle.close();
1952
+ }
1953
+ }
1954
+ //#endregion
1955
+ //#region src/compiler/build-timeout-policy.ts
1956
+ var CLANG_BUILD_CONTROL_TIMEOUT_MS = 6e4;
1957
+ var DEFAULT_BUILD_CONTROL_TIMEOUT_MS = 12e4;
1958
+ var GO_BUILD_CONTROL_TIMEOUT_MS = GO_COMPILE_TIMEOUT_MS + 1e4;
1959
+ var RUST_BUILD_CONTROL_TIMEOUT_MS = RUST_COMPILE_TIMEOUT_MS + 1e4;
1960
+ /**
1961
+ * Hard host deadline for one complete compiler request. The server child and
1962
+ * browser Worker must use the same policy because an SDK call can block the
1963
+ * JavaScript event loop and therefore cannot enforce its own timer.
1964
+ */
1965
+ function buildControlTimeoutMs(language) {
1966
+ if (language === "java") return 19e4;
1967
+ if (!isBuiltinLanguage(language)) throw new Error(`The built-in WASM-OJ compiler does not support language '${language}'.`);
1968
+ if (language === "c" || language === "cpp") return CLANG_BUILD_CONTROL_TIMEOUT_MS;
1969
+ if (language === "rust") return RUST_BUILD_CONTROL_TIMEOUT_MS;
1970
+ if (language === "go") return GO_BUILD_CONTROL_TIMEOUT_MS;
1971
+ return DEFAULT_BUILD_CONTROL_TIMEOUT_MS;
1972
+ }
1973
+ //#endregion
1974
+ //#region src/server/toolchain-sources.ts
1975
+ function snapshotServerToolchainSources(sources) {
1976
+ validateServerToolchainSources(sources);
1977
+ return Object.freeze(sources.map((source) => Object.freeze({
1978
+ kind: "server",
1979
+ descriptor: freezeDescriptor(source.descriptor),
1980
+ directory: new URL(source.directory.href)
1981
+ })));
1982
+ }
1983
+ function serializeServerToolchainSources(sources) {
1984
+ return Object.freeze(sources.map((source) => Object.freeze({
1985
+ kind: "server",
1986
+ descriptor: source.descriptor,
1987
+ directory: source.directory.href
1988
+ })));
1989
+ }
1990
+ function deserializeServerToolchainSources(sources) {
1991
+ if (!Array.isArray(sources)) throw new Error("The isolated server stage did not receive toolchain sources.");
1992
+ return snapshotServerToolchainSources(sources.map((source) => {
1993
+ if (typeof source !== "object" || source === null || Array.isArray(source) || source.kind !== "server" || typeof source.directory !== "string") throw new Error("The isolated server stage received an invalid toolchain source.");
1994
+ return {
1995
+ kind: "server",
1996
+ descriptor: source.descriptor,
1997
+ directory: new URL(source.directory)
1998
+ };
1999
+ }));
2000
+ }
2001
+ function serverToolchainAssetFile(sources, assetPath) {
2002
+ const { source, asset } = toolchainAssetSource(sources, assetPath);
2003
+ const filename = path.basename(asset.path);
2004
+ const file = fileURLToPath(new URL(filename, source.directory));
2005
+ const directory = fileURLToPath(source.directory);
2006
+ const relative = path.relative(directory, file);
2007
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Toolchain asset escapes its package directory: '${assetPath}'.`);
2008
+ return file;
2009
+ }
2010
+ function serverToolchainAssetFiles(sources, assetPaths) {
2011
+ return Object.freeze(Object.fromEntries(assetPaths.map((assetPath) => [assetPath, serverToolchainAssetFile(sources, assetPath)])));
2012
+ }
2013
+ function serverToolchainDirectories(sources) {
2014
+ return Object.freeze([...new Set(sources.map((source) => fileURLToPath(source.directory)))]);
2015
+ }
2016
+ function assertServerToolchainProfile(sources, language, target, optimization) {
2017
+ toolchainProfileSource(sources, language, target, optimization);
2018
+ }
2019
+ function freezeDescriptor(descriptor) {
2020
+ return Object.freeze({
2021
+ ...descriptor,
2022
+ languages: Object.freeze([...descriptor.languages]),
2023
+ profiles: Object.freeze(descriptor.profiles.map((profile) => Object.freeze({ ...profile }))),
2024
+ assets: Object.freeze(descriptor.assets.map((asset) => Object.freeze({ ...asset })))
2025
+ });
2026
+ }
2027
+ //#endregion
2028
+ //#region src/server/verified-distribution.ts
2029
+ var verifiedDistributions = /* @__PURE__ */ new WeakSet();
2030
+ function assertVerifiedToolchainDistribution(token, toolchains) {
2031
+ if (!verifiedDistributions.has(token)) throw new Error("WASM-OJ verified-distribution token is not process-authentic.");
2032
+ const actual = serverToolchainAssetFiles(toolchains, toolchains.flatMap((source) => source.descriptor.assets.map((asset) => asset.path)));
2033
+ if (!sameRecord(token.toolchainAssetFiles, actual)) throw new Error("WASM-OJ verified-distribution token does not authorize these toolchain sources.");
2034
+ }
2035
+ function sameRecord(expected, actual) {
2036
+ const expectedEntries = Object.entries(expected).sort(([left], [right]) => left.localeCompare(right));
2037
+ const actualEntries = Object.entries(actual).sort(([left], [right]) => left.localeCompare(right));
2038
+ return expectedEntries.length === actualEntries.length && expectedEntries.every(([key, value], index) => {
2039
+ const candidate = actualEntries[index];
2040
+ return candidate?.[0] === key && candidate[1] === value;
2041
+ });
2042
+ }
2043
+ //#endregion
2044
+ //#region src/server/stage-scripts.ts
2045
+ var SERVER_STAGE_SCRIPTS = Object.freeze([
2046
+ "server-build-stage.mjs",
2047
+ "server-runner-stage.mjs",
2048
+ "python-stage.mjs",
2049
+ "rustc-stage.mjs",
2050
+ "go-stage.mjs",
2051
+ "java-stage.mjs"
2052
+ ]);
2053
+ var SERVER_STAGE_SCRIPT_SET = new Set(SERVER_STAGE_SCRIPTS);
2054
+ /** Resolve the one package-owned directory that contains every isolated server stage. */
2055
+ function resolveServerStageDirectory(moduleUrl = import.meta.url) {
2056
+ const modulePath = fileURLToPath(moduleUrl);
2057
+ const moduleDirectory = path.dirname(modulePath);
2058
+ const moduleFilename = path.basename(modulePath);
2059
+ if (moduleFilename === "stage-scripts.ts" && path.basename(moduleDirectory) === "server" && path.basename(path.dirname(moduleDirectory)) === "src") return moduleDirectory;
2060
+ if ((moduleFilename === "index.js" || moduleFilename === "server-build-stage.mjs") && path.basename(moduleDirectory) === "dist") return moduleDirectory;
2061
+ throw new Error(`Unsupported @wasm-oj/server module layout '${modulePath}'.`);
2062
+ }
2063
+ /** Resolve only a declared stage below an already-established package stage root. */
2064
+ function serverStageScript(stageDirectory, scriptName) {
2065
+ if (!path.isAbsolute(stageDirectory)) throw new Error("The @wasm-oj/server stage directory must be absolute.");
2066
+ if (!SERVER_STAGE_SCRIPT_SET.has(scriptName)) throw new Error(`Unknown isolated server stage '${scriptName}'.`);
2067
+ return path.join(stageDirectory, scriptName);
2068
+ }
2069
+ //#endregion
2070
+ //#region src/server/server-compiler.ts
2071
+ var IN_PROCESS_STAGE = Symbol("wasm-oj-in-process-server-compiler");
2072
+ var SERVER_STAGE_LOG_LIMIT_BYTES = 1048576;
2073
+ var SERVER_STAGE_PROGRESS_LINE_LIMIT_BYTES = 1048576;
2074
+ var SERVER_BUILD_RESPONSE_LIMIT_BYTES = 268435456;
2075
+ var SERVER_BUILD_REQUEST_LIMIT_BYTES$1 = 805306368;
2076
+ var SERVER_COMPILER_STAGE_RESPONSE_LIMIT_BYTES = 268435456;
2077
+ /**
2078
+ * Node/server compiler host using the exact language drivers and Wasmer
2079
+ * packages used by the browser Worker.
2080
+ */
2081
+ var ServerCompiler = class {
2082
+ progressListeners = /* @__PURE__ */ new Set();
2083
+ compilerExecutable;
2084
+ toolchains;
2085
+ initialization;
2086
+ generation = 0;
2087
+ disposed = false;
2088
+ inProcess;
2089
+ verifiedToolchain;
2090
+ stageDirectory;
2091
+ activeChildren = /* @__PURE__ */ new Set();
2092
+ activeOperation;
2093
+ constructor(options, stage) {
2094
+ this.compilerExecutable = path.resolve(options.compilerExecutable);
2095
+ this.toolchains = snapshotServerToolchainSources(options.toolchains);
2096
+ if (options.verifiedDistribution) assertVerifiedToolchainDistribution(options.verifiedDistribution, this.toolchains);
2097
+ if (options.verifiedToolchain === true && stage !== IN_PROCESS_STAGE) throw new Error("Verified toolchain inheritance is reserved for the isolated compiler stage.");
2098
+ this.verifiedToolchain = options.verifiedDistribution !== void 0 || options.verifiedToolchain === true;
2099
+ this.inProcess = stage === IN_PROCESS_STAGE;
2100
+ if (stage === IN_PROCESS_STAGE) {
2101
+ const inheritedStageDirectory = options.stageDirectory;
2102
+ if (typeof inheritedStageDirectory !== "string" || !path.isAbsolute(inheritedStageDirectory)) throw new Error("The inherited @wasm-oj/server stage directory must be absolute.");
2103
+ this.stageDirectory = inheritedStageDirectory;
2104
+ } else this.stageDirectory = resolveServerStageDirectory();
2105
+ }
2106
+ cacheIdentity(project) {
2107
+ this.assertActive();
2108
+ assertServerToolchainProfile(this.toolchains, project.config.language, project.config.target, project.config.optimization);
2109
+ return JSON.stringify(toolchainCacheIdentity(project.config.language));
2110
+ }
2111
+ async ready() {
2112
+ this.assertActive();
2113
+ const generation = this.generation;
2114
+ let initialization = this.initialization;
2115
+ if (!initialization) {
2116
+ initialization = this.initialize();
2117
+ this.initialization = initialization;
2118
+ initialization.catch(() => {
2119
+ if (this.initialization === initialization) this.initialization = void 0;
2120
+ });
2121
+ }
2122
+ await initialization;
2123
+ this.assertActive();
2124
+ if (generation !== this.generation) throw new Error("Server compiler initialization was superseded.");
2125
+ }
2126
+ async build(project, cacheKey) {
2127
+ assertValidProject(project);
2128
+ assertCompilerCacheKey(cacheKey);
2129
+ const operation = this.beginOperation("build");
2130
+ try {
2131
+ await this.ready();
2132
+ this.assertCurrent(operation, "Server compilation was cancelled before initialization completed.");
2133
+ if (!this.inProcess) return await this.buildIsolated(project, cacheKey, operation);
2134
+ const runtime = new Runtime({ registry: null });
2135
+ configureWasmerCompilerHost({
2136
+ getRuntime: () => runtime,
2137
+ loadToolchainAsset: (assetPath) => this.loadToolchainAsset(assetPath),
2138
+ loadToolchainFile: (assetPath) => this.loadToolchainFile(assetPath),
2139
+ compileRust: (request) => this.compileRust(request),
2140
+ compilePython: (request) => this.compilePython(request),
2141
+ compileGo: (request) => this.compileGo(request),
2142
+ compileJava: (request) => this.compileJava(request),
2143
+ progress: (_requestId, phase, label, value) => {
2144
+ if (!this.isCurrent(operation)) return;
2145
+ const progress = {
2146
+ phase,
2147
+ label,
2148
+ progress: value
2149
+ };
2150
+ for (const listener of this.progressListeners) listener(progress);
2151
+ },
2152
+ trace: () => void 0
2153
+ });
2154
+ try {
2155
+ const result = await buildProject(project, cacheKey, crypto.randomUUID());
2156
+ this.assertCurrent(operation, "Server compilation was cancelled.");
2157
+ return result;
2158
+ } finally {
2159
+ await clearSdkDirectClangCaches();
2160
+ runtime.free();
2161
+ }
2162
+ } finally {
2163
+ this.endOperation(operation);
2164
+ }
2165
+ }
2166
+ onProgress(listener) {
2167
+ this.assertActive();
2168
+ this.progressListeners.add(listener);
2169
+ return () => this.progressListeners.delete(listener);
2170
+ }
2171
+ async clearToolchainCache() {
2172
+ const operation = this.beginOperation("cache-clear");
2173
+ try {
2174
+ await this.ready();
2175
+ this.assertCurrent(operation, "Server compiler cache clearing was superseded.");
2176
+ if (this.inProcess) {
2177
+ clearCompilerHostCaches();
2178
+ await clearSdkDirectClangCaches();
2179
+ this.assertCurrent(operation, "Server compiler cache clearing was superseded.");
2180
+ }
2181
+ } finally {
2182
+ this.endOperation(operation);
2183
+ }
2184
+ }
2185
+ cancel() {
2186
+ if (this.disposed) return;
2187
+ if (this.activeOperation?.kind === "cache-clear") return;
2188
+ this.generation += 1;
2189
+ if (this.activeOperation) {
2190
+ this.activeOperation.superseded = true;
2191
+ this.activeOperation = void 0;
2192
+ }
2193
+ this.terminateChildren();
2194
+ }
2195
+ restart() {
2196
+ this.assertActive();
2197
+ if (this.activeOperation?.kind === "cache-clear") throw new Error("Cannot restart ServerCompiler while clearing its cache.");
2198
+ this.cancel();
2199
+ if (this.inProcess) clearCompilerHostCaches();
2200
+ }
2201
+ dispose() {
2202
+ if (this.disposed) return;
2203
+ this.disposed = true;
2204
+ this.generation += 1;
2205
+ if (this.activeOperation) {
2206
+ this.activeOperation.superseded = true;
2207
+ this.activeOperation = void 0;
2208
+ }
2209
+ this.terminateChildren();
2210
+ this.progressListeners.clear();
2211
+ }
2212
+ async initialize() {
2213
+ await Promise.all([
2214
+ access(this.compilerExecutable, constants.X_OK),
2215
+ ...serverToolchainDirectories(this.toolchains).map((directory) => access(directory, constants.R_OK)),
2216
+ this.inProcess ? initializeServerWasmerSdk() : Promise.resolve()
2217
+ ]);
2218
+ }
2219
+ async buildIsolated(project, cacheKey, operation) {
2220
+ const transportDirectory = await mkdtemp(path.join(os.tmpdir(), "wasm-oj-build-response-"));
2221
+ const responsePath = path.join(transportDirectory, "response.v8");
2222
+ const requestPath = path.join(transportDirectory, "request.v8");
2223
+ const timeoutMs = buildControlTimeoutMs(project.config.language);
2224
+ try {
2225
+ this.assertCurrent(operation, "Server compilation was cancelled before its isolated stage started.");
2226
+ const encodedRequest = serialize({
2227
+ compilerExecutable: this.compilerExecutable,
2228
+ stageDirectory: this.stageDirectory,
2229
+ toolchains: serializeServerToolchainSources(this.toolchains),
2230
+ verifiedToolchain: this.verifiedToolchain,
2231
+ project,
2232
+ cacheKey
2233
+ });
2234
+ if (encodedRequest.byteLength > SERVER_BUILD_REQUEST_LIMIT_BYTES$1) throw new Error(`Server compiler request exceeds ${SERVER_BUILD_REQUEST_LIMIT_BYTES$1} bytes.`);
2235
+ await writeFile(requestPath, encodedRequest, {
2236
+ flag: "wx",
2237
+ mode: 384
2238
+ });
2239
+ return await new Promise((resolve, reject) => {
2240
+ const script = serverStageScript(this.stageDirectory, "server-build-stage.mjs");
2241
+ const child = spawn(process.execPath, [
2242
+ "--experimental-strip-types",
2243
+ "--disable-warning=ExperimentalWarning",
2244
+ script
2245
+ ], {
2246
+ stdio: [
2247
+ "pipe",
2248
+ "pipe",
2249
+ "pipe",
2250
+ "pipe"
2251
+ ],
2252
+ env: {
2253
+ ...process.env,
2254
+ WASM_OJ_BUILD_REQUEST: requestPath,
2255
+ WASM_OJ_BUILD_RESPONSE: responsePath
2256
+ }
2257
+ });
2258
+ this.activeChildren.add(child);
2259
+ let progressBuffer = "";
2260
+ let timedOut = false;
2261
+ let transportError;
2262
+ const failTransport = (error) => {
2263
+ transportError ??= error;
2264
+ child.kill("SIGKILL");
2265
+ };
2266
+ const stdout = new BoundedByteCollector("Isolated server compiler stdout", SERVER_STAGE_LOG_LIMIT_BYTES, failTransport);
2267
+ const stderr = new BoundedByteCollector("Isolated server compiler stderr", SERVER_STAGE_LOG_LIMIT_BYTES, failTransport);
2268
+ child.stdout.on("data", (chunk) => stdout.append(chunk));
2269
+ child.stderr.on("data", (chunk) => stderr.append(chunk));
2270
+ child.on("error", (error) => {
2271
+ transportError = error;
2272
+ });
2273
+ child.stdin.on("error", (error) => {
2274
+ transportError ??= error;
2275
+ });
2276
+ const progressStream = child.stdio[3];
2277
+ if (!progressStream || typeof progressStream === "number") {
2278
+ child.kill("SIGKILL");
2279
+ this.activeChildren.delete(child);
2280
+ reject(/* @__PURE__ */ new Error("The isolated server compiler did not expose its progress channel."));
2281
+ return;
2282
+ }
2283
+ progressStream.on("data", (chunk) => {
2284
+ if (Buffer.byteLength(progressBuffer, "utf8") + chunk.byteLength > SERVER_STAGE_PROGRESS_LINE_LIMIT_BYTES) {
2285
+ failTransport(/* @__PURE__ */ new Error(`Isolated server compiler progress exceeded the ${SERVER_STAGE_PROGRESS_LINE_LIMIT_BYTES} byte line boundary.`));
2286
+ return;
2287
+ }
2288
+ progressBuffer += chunk.toString();
2289
+ const lines = progressBuffer.split("\n");
2290
+ progressBuffer = lines.pop() ?? "";
2291
+ for (const line of lines) {
2292
+ if (!line) continue;
2293
+ try {
2294
+ const progress = JSON.parse(line);
2295
+ if (this.isCurrent(operation)) for (const listener of this.progressListeners) listener(progress);
2296
+ } catch {}
2297
+ }
2298
+ });
2299
+ const timer = setTimeout(() => {
2300
+ timedOut = true;
2301
+ child.kill("SIGKILL");
2302
+ }, timeoutMs);
2303
+ child.on("close", async () => {
2304
+ clearTimeout(timer);
2305
+ this.activeChildren.delete(child);
2306
+ try {
2307
+ this.assertCurrent(operation, "Server compilation was cancelled.");
2308
+ if (timedOut) throw new Error(`Server compilation exceeded ${timeoutMs} ms.`);
2309
+ if (transportError) throw transportError;
2310
+ let encodedResponse;
2311
+ try {
2312
+ encodedResponse = await readBoundedRegularFile(responsePath, SERVER_BUILD_RESPONSE_LIMIT_BYTES);
2313
+ } catch (error) {
2314
+ const stageError = stderr.text().trim() || stdout.text().trim();
2315
+ if (stageError) throw new Error(stageError, { cause: error });
2316
+ throw error;
2317
+ }
2318
+ const response = deserialize(encodedResponse);
2319
+ if (!response.ok || !response.result) throw new Error(response.error || stderr.text() || stdout.text() || "The isolated server compiler failed.");
2320
+ resolve(response.result);
2321
+ } catch (error) {
2322
+ reject(error);
2323
+ }
2324
+ });
2325
+ child.stdin.end();
2326
+ });
2327
+ } finally {
2328
+ await rm(transportDirectory, {
2329
+ recursive: true,
2330
+ force: true
2331
+ });
2332
+ }
2333
+ }
2334
+ async compileRust(request) {
2335
+ const result = await this.runCompilerStage("rustc-stage.mjs", { request }, RUST_COMPILE_TIMEOUT_MS, [RUST_TOOLCHAIN.packageAsset, RUST_TOOLCHAIN.manifestAsset]);
2336
+ return {
2337
+ ...result,
2338
+ diagnostics: parseRustDiagnostics(result.stderr),
2339
+ wasm: result.wasmBase64 ? new Uint8Array(Buffer.from(result.wasmBase64, "base64")) : void 0
2340
+ };
2341
+ }
2342
+ async compilePython(request) {
2343
+ const result = await this.runCompilerStage("python-stage.mjs", { request }, PYTHON_COMPILE_TIMEOUT_MS, [PYTHON_PACKAGE_ASSET_PATH]);
2344
+ return {
2345
+ ...result,
2346
+ bytecode: Object.fromEntries(Object.entries(result.bytecodeBase64).map(([path, base64]) => [path, new Uint8Array(Buffer.from(base64, "base64"))])),
2347
+ diagnostics: parsePythonDiagnostics(`${result.stderr}\n${result.stdout}`)
2348
+ };
2349
+ }
2350
+ async compileGo(request) {
2351
+ const result = await this.runCompilerStage("go-stage.mjs", {
2352
+ compilerExecutable: this.compilerExecutable,
2353
+ compileBatchSchema: WASM_OJ_SCHEMAS.compileBatch,
2354
+ request
2355
+ }, GO_COMPILE_TIMEOUT_MS, [
2356
+ GO_TOOLCHAIN.packageAsset,
2357
+ GO_TOOLCHAIN.manifestAsset,
2358
+ GO_TOOLCHAIN.standardLibraryAsset
2359
+ ]);
2360
+ return {
2361
+ ...result,
2362
+ diagnostics: parseGoDiagnostics(result.stderr),
2363
+ wasm: result.wasmBase64 ? new Uint8Array(Buffer.from(result.wasmBase64, "base64")) : void 0
2364
+ };
2365
+ }
2366
+ async compileJava(request) {
2367
+ const result = await this.runCompilerStage("java-stage.mjs", { request }, JAVA_COMPILE_TIMEOUT_MS, [
2368
+ JAVA_COMPILER_ASSET_PATH,
2369
+ JAVA_COMPILE_CLASSLIB_ASSET_PATH,
2370
+ JAVA_RUNTIME_CLASSLIB_ASSET_PATH
2371
+ ]);
2372
+ return {
2373
+ ...result,
2374
+ wasm: result.wasmBase64 ? new Uint8Array(Buffer.from(result.wasmBase64, "base64")) : void 0
2375
+ };
2376
+ }
2377
+ runCompilerStage(scriptName, input, timeoutMs, assetPaths) {
2378
+ const operation = this.activeOperation;
2379
+ if (!operation || operation.kind !== "build") return Promise.reject(/* @__PURE__ */ new Error("Server compilation was cancelled before its compiler stage started."));
2380
+ this.assertCurrent(operation, "Server compilation was cancelled before its compiler stage started.");
2381
+ return new Promise((resolve, reject) => {
2382
+ const script = serverStageScript(this.stageDirectory, scriptName);
2383
+ const child = spawn(process.execPath, [
2384
+ "--experimental-strip-types",
2385
+ "--disable-warning=ExperimentalWarning",
2386
+ script
2387
+ ], { stdio: [
2388
+ "pipe",
2389
+ "pipe",
2390
+ "pipe",
2391
+ "pipe"
2392
+ ] });
2393
+ this.activeChildren.add(child);
2394
+ let transportError;
2395
+ let timedOut = false;
2396
+ const failTransport = (error) => {
2397
+ transportError ??= error;
2398
+ child.kill("SIGKILL");
2399
+ };
2400
+ const stdout = new BoundedByteCollector(`Isolated compiler stage '${scriptName}' stdout`, SERVER_STAGE_LOG_LIMIT_BYTES, failTransport);
2401
+ const stderr = new BoundedByteCollector(`Isolated compiler stage '${scriptName}' stderr`, SERVER_STAGE_LOG_LIMIT_BYTES, failTransport);
2402
+ const responseBytes = new BoundedByteCollector(`Isolated compiler stage '${scriptName}' response`, SERVER_COMPILER_STAGE_RESPONSE_LIMIT_BYTES, failTransport);
2403
+ child.stdout.on("data", (chunk) => stdout.append(chunk));
2404
+ child.stderr.on("data", (chunk) => stderr.append(chunk));
2405
+ child.on("error", (error) => {
2406
+ transportError = error;
2407
+ });
2408
+ child.stdin.on("error", (error) => {
2409
+ transportError ??= error;
2410
+ });
2411
+ const responseStream = child.stdio[3];
2412
+ if (!responseStream || typeof responseStream === "number") {
2413
+ child.kill("SIGKILL");
2414
+ this.activeChildren.delete(child);
2415
+ reject(/* @__PURE__ */ new Error(`The isolated compiler stage '${scriptName}' did not expose its response channel.`));
2416
+ return;
2417
+ }
2418
+ responseStream.on("data", (chunk) => responseBytes.append(chunk));
2419
+ const timer = setTimeout(() => {
2420
+ timedOut = true;
2421
+ child.kill("SIGKILL");
2422
+ }, timeoutMs + 5e3);
2423
+ child.on("close", () => {
2424
+ clearTimeout(timer);
2425
+ this.activeChildren.delete(child);
2426
+ try {
2427
+ if (transportError) throw transportError;
2428
+ if (timedOut) throw new Error(`The isolated compiler stage '${scriptName}' exceeded ${timeoutMs + 5e3} ms.`);
2429
+ const response = JSON.parse(responseBytes.text());
2430
+ if (!response.ok || !response.result) throw new Error(response.error || stderr.text() || stdout.text() || `The isolated compiler stage '${scriptName}' failed.`);
2431
+ resolve(response.result);
2432
+ } catch (error) {
2433
+ reject(error);
2434
+ }
2435
+ });
2436
+ child.stdin.end(JSON.stringify({
2437
+ toolchainAssets: serverToolchainAssetFiles(this.toolchains, assetPaths),
2438
+ verifiedToolchain: this.verifiedToolchain,
2439
+ ...input
2440
+ }));
2441
+ });
2442
+ }
2443
+ async loadToolchainAsset(assetPath) {
2444
+ const resolved = serverToolchainAssetFile(this.toolchains, assetPath);
2445
+ const compressed = await readFile(resolved);
2446
+ if (!this.verifiedToolchain) this.verifyToolchainAsset(assetPath, compressed);
2447
+ return uint8View(gunzipSync(compressed));
2448
+ }
2449
+ async loadToolchainFile(assetPath) {
2450
+ const resolved = serverToolchainAssetFile(this.toolchains, assetPath);
2451
+ const bytes = await readFile(resolved);
2452
+ if (!this.verifiedToolchain) this.verifyToolchainAsset(assetPath, bytes);
2453
+ return new Uint8Array(bytes);
2454
+ }
2455
+ verifyToolchainAsset(assetPath, bytes) {
2456
+ const expected = toolchainAssetSource(this.toolchains, assetPath).asset.sha256;
2457
+ const actual = createHash("sha256").update(bytes).digest("hex");
2458
+ if (actual !== expected) throw new Error(`Pinned toolchain asset '${assetPath}' has digest ${actual}; expected ${expected}.`);
2459
+ }
2460
+ beginOperation(kind) {
2461
+ this.assertActive();
2462
+ if (this.activeOperation) throw new Error("ServerCompiler accepts one active operation at a time.");
2463
+ const operation = {
2464
+ kind,
2465
+ generation: this.generation,
2466
+ superseded: false
2467
+ };
2468
+ this.activeOperation = operation;
2469
+ return operation;
2470
+ }
2471
+ endOperation(operation) {
2472
+ if (this.activeOperation === operation) this.activeOperation = void 0;
2473
+ }
2474
+ assertCurrent(operation, message) {
2475
+ this.assertActive();
2476
+ if (!this.isCurrent(operation)) throw new Error(message);
2477
+ }
2478
+ isCurrent(operation) {
2479
+ return !this.disposed && !operation.superseded && operation.generation === this.generation;
2480
+ }
2481
+ terminateChildren() {
2482
+ for (const child of this.activeChildren) {
2483
+ if (this.inProcess) {
2484
+ child.kill("SIGKILL");
2485
+ continue;
2486
+ }
2487
+ child.kill("SIGTERM");
2488
+ setTimeout(() => {
2489
+ if (this.activeChildren.has(child)) child.kill("SIGKILL");
2490
+ }, 1e3).unref();
2491
+ }
2492
+ }
2493
+ assertActive() {
2494
+ if (this.disposed) throw new Error("ServerCompiler is disposed.");
2495
+ }
2496
+ };
2497
+ function uint8View(bytes) {
2498
+ return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
2499
+ }
2500
+ /** @internal Entry point used only by the isolated Node compiler process. */
2501
+ async function buildServerProjectInProcess(options, project, cacheKey, onProgress) {
2502
+ const compiler = new ServerCompiler(options, IN_PROCESS_STAGE);
2503
+ const removeProgress = compiler.onProgress(onProgress);
2504
+ const terminate = () => compiler.dispose();
2505
+ process.once("SIGTERM", terminate);
2506
+ try {
2507
+ return await compiler.build(project, cacheKey);
2508
+ } finally {
2509
+ process.off("SIGTERM", terminate);
2510
+ removeProgress();
2511
+ compiler.dispose();
2512
+ }
2513
+ }
2514
+ //#endregion
2515
+ //#region src/server/process-keepalive.mjs
2516
+ /**
2517
+ * Keep Node alive while a promise is backed only by a foreign async runtime.
2518
+ * Top-level await does not itself create a referenced libuv handle, so Node can
2519
+ * otherwise exit with code 13 while a Wasmer SDK operation is still pending.
2520
+ */
2521
+ async function withProcessKeepalive(promise) {
2522
+ const keepalive = setInterval(() => void 0, 6e4);
2523
+ try {
2524
+ return await promise;
2525
+ } finally {
2526
+ clearInterval(keepalive);
2527
+ }
2528
+ }
2529
+ //#endregion
2530
+ //#region src/server/server-build-stage.mjs
2531
+ var SERVER_BUILD_REQUEST_LIMIT_BYTES = 805306368;
2532
+ try {
2533
+ const responsePath = requiredResponsePath();
2534
+ const encoded = deserialize(await readBoundedRegularFile(requiredRequestPath(), SERVER_BUILD_REQUEST_LIMIT_BYTES));
2535
+ const result = await withProcessKeepalive(buildServerProjectInProcess({
2536
+ compilerExecutable: encoded.compilerExecutable,
2537
+ stageDirectory: encoded.stageDirectory,
2538
+ toolchains: deserializeServerToolchainSources(encoded.toolchains),
2539
+ verifiedToolchain: encoded.verifiedToolchain === true
2540
+ }, encoded.project, encoded.cacheKey, (progress) => writeFileSync(3, `${JSON.stringify(progress)}\n`)));
2541
+ writeFileSync(responsePath, serialize({
2542
+ ok: true,
2543
+ result
2544
+ }), { flag: "wx" });
2545
+ setTimeout(() => process.exit(0), 10);
2546
+ } catch (error) {
2547
+ writeFileSync(requiredResponsePath(), serialize({
2548
+ ok: false,
2549
+ error: error instanceof Error ? error.message : String(error)
2550
+ }), { flag: "wx" });
2551
+ setTimeout(() => process.exit(1), 10);
2552
+ }
2553
+ function requiredResponsePath() {
2554
+ const value = process.env.WASM_OJ_BUILD_RESPONSE;
2555
+ if (!value) throw new Error("WASM_OJ_BUILD_RESPONSE is required.");
2556
+ return value;
2557
+ }
2558
+ function requiredRequestPath() {
2559
+ const value = process.env.WASM_OJ_BUILD_REQUEST;
2560
+ if (!value) throw new Error("WASM_OJ_BUILD_REQUEST is required.");
2561
+ return value;
2562
+ }
2563
+ //#endregion
2564
+ export {};