wasm-idle 1.0.12 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +150 -37
  2. package/dist/playground/applicationAssets.js +2 -0
  3. package/dist/playground/assetBridge.js +106 -31
  4. package/dist/playground/assets.d.ts +2 -2
  5. package/dist/playground/c3.js +22 -0
  6. package/dist/playground/c3Memory.d.ts +19 -0
  7. package/dist/playground/c3Memory.js +117 -0
  8. package/dist/playground/cachedClang.js +143 -34
  9. package/dist/playground/clangAssetIntegrity.js +6 -6
  10. package/dist/playground/clangWorkerProtocol.d.ts +12 -1
  11. package/dist/playground/cobol.d.ts +3 -0
  12. package/dist/playground/cobol.js +10 -1
  13. package/dist/playground/commonlisp.d.ts +8 -0
  14. package/dist/playground/commonlisp.js +33 -0
  15. package/dist/playground/commonlispAssets.d.ts +30 -0
  16. package/dist/playground/commonlispAssets.js +184 -0
  17. package/dist/playground/compiledArtifactCache.d.ts +3 -1
  18. package/dist/playground/compiledArtifactCache.js +31 -5
  19. package/dist/playground/container/ContainerExplorer.svelte +307 -0
  20. package/dist/playground/container/ContainerExplorer.svelte.d.ts +14 -0
  21. package/dist/playground/container/binding.d.ts +26 -0
  22. package/dist/playground/container/binding.js +247 -0
  23. package/dist/playground/container/clang-runtime.d.ts +38 -0
  24. package/dist/playground/container/clang-runtime.js +343 -0
  25. package/dist/playground/container/client.d.ts +15 -0
  26. package/dist/playground/container/client.js +189 -0
  27. package/dist/playground/container/explorer.d.ts +31 -0
  28. package/dist/playground/container/explorer.js +112 -0
  29. package/dist/playground/container/owner.worker.d.ts +1 -0
  30. package/dist/playground/container/owner.worker.js +390 -0
  31. package/dist/playground/container/protocol.d.ts +73 -0
  32. package/dist/playground/container/protocol.js +28 -0
  33. package/dist/playground/container/release.d.ts +31 -0
  34. package/dist/playground/container/release.js +612 -0
  35. package/dist/playground/container/runtime-adapter.d.ts +73 -0
  36. package/dist/playground/container/runtime-adapter.js +474 -0
  37. package/dist/playground/container/shell-control.d.ts +49 -0
  38. package/dist/playground/container/shell-control.js +303 -0
  39. package/dist/playground/container/workspace.d.ts +8 -0
  40. package/dist/playground/container/workspace.js +29 -0
  41. package/dist/playground/d.d.ts +6 -1
  42. package/dist/playground/d.js +83 -5
  43. package/dist/playground/dotnet.js +6 -8
  44. package/dist/playground/fortran.d.ts +3 -0
  45. package/dist/playground/fortran.js +10 -1
  46. package/dist/playground/go.js +14 -3
  47. package/dist/playground/goDebugInstrumentation.js +184 -54
  48. package/dist/playground/index.d.ts +1 -1
  49. package/dist/playground/index.js +14 -0
  50. package/dist/playground/java.js +3 -2
  51. package/dist/playground/javaRuntimeErrors.d.ts +9 -0
  52. package/dist/playground/javaRuntimeErrors.js +60 -0
  53. package/dist/playground/javaRuntimeStdin.d.ts +9 -0
  54. package/dist/playground/javaRuntimeStdin.js +145 -0
  55. package/dist/playground/lean4.d.ts +13 -0
  56. package/dist/playground/lean4.js +50 -0
  57. package/dist/playground/lean4Assets.d.ts +25 -0
  58. package/dist/playground/lean4Assets.js +123 -0
  59. package/dist/playground/lfortran.js +10 -0
  60. package/dist/playground/lfortranAssets.d.ts +2 -2
  61. package/dist/playground/loadingProgress.js +4 -1
  62. package/dist/playground/nim.js +22 -0
  63. package/dist/playground/objectivec.d.ts +3 -0
  64. package/dist/playground/objectivec.js +11 -2
  65. package/dist/playground/options.d.ts +2 -0
  66. package/dist/playground/python.js +8 -0
  67. package/dist/playground/runtimeAssetCache.d.ts +1 -32
  68. package/dist/playground/runtimeAssetCache.js +1 -193
  69. package/dist/playground/runtimeSession.d.ts +2 -2
  70. package/dist/playground/runtimeSession.js +11 -11
  71. package/dist/playground/rust.d.ts +6 -0
  72. package/dist/playground/rust.js +103 -6
  73. package/dist/playground/staticStdinRing.d.ts +2 -1
  74. package/dist/playground/staticStdinRing.js +21 -10
  75. package/dist/playground/staticWorkerRuntime.d.ts +15 -1
  76. package/dist/playground/staticWorkerRuntime.js +119 -17
  77. package/dist/playground/tinygo.d.ts +3 -0
  78. package/dist/playground/tinygo.js +81 -6
  79. package/dist/playground/v.d.ts +3 -0
  80. package/dist/playground/v.js +10 -1
  81. package/dist/playground/wasmAwkVersion.d.ts +13 -13
  82. package/dist/playground/wasmAwkVersion.js +4 -4
  83. package/dist/playground/wasmBqnVersion.d.ts +2 -2
  84. package/dist/playground/wasmBqnVersion.js +2 -2
  85. package/dist/playground/wasmC3Version.d.ts +2 -2
  86. package/dist/playground/wasmC3Version.js +2 -2
  87. package/dist/playground/wasmClojureScriptVersion.d.ts +2 -2
  88. package/dist/playground/wasmClojureScriptVersion.js +2 -2
  89. package/dist/playground/wasmCommonLispVersion.d.ts +32 -0
  90. package/dist/playground/wasmCommonLispVersion.js +33 -0
  91. package/dist/playground/wasmDIntegrity.d.ts +5 -5
  92. package/dist/playground/wasmDIntegrity.js +5 -5
  93. package/dist/playground/wasmDVersion.d.ts +16 -1
  94. package/dist/playground/wasmDVersion.js +16 -1
  95. package/dist/playground/wasmDebugVersion.d.ts +1 -1
  96. package/dist/playground/wasmDebugVersion.js +1 -1
  97. package/dist/playground/wasmForthVersion.d.ts +2 -2
  98. package/dist/playground/wasmForthVersion.js +2 -2
  99. package/dist/playground/wasmGleamVersion.d.ts +2 -2
  100. package/dist/playground/wasmGleamVersion.js +2 -2
  101. package/dist/playground/wasmGrainVersion.d.ts +2 -2
  102. package/dist/playground/wasmGrainVersion.js +2 -2
  103. package/dist/playground/wasmJVersion.d.ts +2 -2
  104. package/dist/playground/wasmJVersion.js +2 -2
  105. package/dist/playground/wasmJanetVersion.js +2 -2
  106. package/dist/playground/wasmJuliaVersion.js +2 -2
  107. package/dist/playground/wasmLean4Version.d.ts +110 -0
  108. package/dist/playground/wasmLean4Version.js +111 -0
  109. package/dist/playground/wasmLfortranVersion.d.ts +2 -2
  110. package/dist/playground/wasmLfortranVersion.js +2 -2
  111. package/dist/playground/wasmNimVersion.d.ts +9 -9
  112. package/dist/playground/wasmNimVersion.js +6 -6
  113. package/dist/playground/wasmOcamlVersion.d.ts +2 -2
  114. package/dist/playground/wasmOcamlVersion.js +1 -1
  115. package/dist/playground/wasmPascalVersion.js +2 -2
  116. package/dist/playground/wasmPerlVersion.js +2 -2
  117. package/dist/playground/wasmPrologVersion.d.ts +2 -2
  118. package/dist/playground/wasmPrologVersion.js +2 -2
  119. package/dist/playground/wasmReScriptVersion.d.ts +2 -2
  120. package/dist/playground/wasmReScriptVersion.js +2 -2
  121. package/dist/playground/wasmRustVersion.d.ts +8 -8
  122. package/dist/playground/wasmRustVersion.js +7 -7
  123. package/dist/playground/wasmTclVersion.d.ts +4 -4
  124. package/dist/playground/wasmTclVersion.js +2 -2
  125. package/dist/playground/wasmTinyGoVersion.d.ts +14 -14
  126. package/dist/playground/wasmTinyGoVersion.js +14 -14
  127. package/dist/playground/wasmTypeScriptVersion.d.ts +5 -5
  128. package/dist/playground/wasmTypeScriptVersion.js +5 -5
  129. package/dist/playground/worker/cachedClangCompile.js +52 -4
  130. package/dist/playground/worker/cachedClangExecute.js +6 -5
  131. package/dist/playground/worker/clang.js +32 -10
  132. package/dist/playground/worker/cobol.js +2 -2
  133. package/dist/playground/worker/d.js +12 -5
  134. package/dist/playground/worker/fortran.js +2 -2
  135. package/dist/playground/worker/go.js +16 -5
  136. package/dist/playground/worker/haskell.js +10 -7
  137. package/dist/playground/worker/java.js +92 -39
  138. package/dist/playground/worker/lua.js +2 -3
  139. package/dist/playground/worker/php.js +15 -9
  140. package/dist/playground/worker/python.js +131 -131
  141. package/dist/playground/worker/pythonDebugPreview.d.ts +2 -0
  142. package/dist/playground/worker/pythonDebugPreview.js +55 -0
  143. package/dist/playground/worker/pythonExecution.d.ts +8 -0
  144. package/dist/playground/worker/pythonExecution.js +183 -0
  145. package/dist/playground/worker/pythonStdio.d.ts +32 -0
  146. package/dist/playground/worker/pythonStdio.js +253 -0
  147. package/dist/playground/worker/pythonWorkspaceFiles.d.ts +6 -0
  148. package/dist/playground/worker/pythonWorkspaceFiles.js +26 -0
  149. package/dist/playground/worker/pythonWorkspaceImports.d.ts +4 -0
  150. package/dist/playground/worker/pythonWorkspaceImports.js +129 -0
  151. package/dist/playground/worker/r.js +13 -6
  152. package/dist/playground/worker/rust.js +34 -2
  153. package/dist/playground/worker/sqlite.js +4 -3
  154. package/dist/playground/worker/tinygo.js +11 -3
  155. package/dist/playground/worker/typescript.js +2 -3
  156. package/dist/playground/worker/v.js +2 -2
  157. package/dist/playground/worker/wat.js +2 -3
  158. package/dist/playground/worker/zig.js +20 -6
  159. package/dist/playground/workerSession.d.ts +1 -28
  160. package/dist/playground/workerSession.js +1 -164
  161. package/package.json +30 -15
@@ -1,8 +1,11 @@
1
- import { resolveExecutionLimits, resolveRuntimeAssetCacheOptions } from '@wasm-idle/core';
1
+ import { resolveExecutionLimits, resolveRuntimeAssetCacheOptions, OutputLimitError } from '@wasm-idle/core';
2
2
  import { resolveRuntimeAssetConfig } from './assets';
3
3
  import { WorkerAssetBridge } from './assetBridge';
4
4
  import { shouldStreamBundledClang } from './clangStreamingPolicy';
5
5
  import { CompiledArtifactCache, clangCompileKey } from './compiledArtifactCache';
6
+ import { CLANG_STDIN_DATA, CLANG_STDIN_EOF, CLANG_STDIN_HEADER_BYTES } from './clangWorkerProtocol';
7
+ const MAX_BUFFERED_INPUT_BYTES = 128 * 1024;
8
+ const MAX_HEADER_BUILD_TIMEOUT_MS = 30_000;
6
9
  const workers = {
7
10
  async compile() {
8
11
  const { default: CompileWorker } = await import('./worker/cachedClangCompile?worker');
@@ -20,6 +23,7 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
20
23
  let runtimeBaseUrl = '';
21
24
  let assetConfig;
22
25
  let maxAssetBytes = 0;
26
+ let maxWasmMemoryBytes = 0;
23
27
  let languageSysroots = false;
24
28
  let activeWorker;
25
29
  let cancelWorker;
@@ -30,47 +34,97 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
30
34
  let inputBuffer;
31
35
  let inputRequested = false;
32
36
  let pendingEof = false;
37
+ let loadedMaxInputBytes = MAX_BUFFERED_INPUT_BYTES;
38
+ let maxBufferedInputBytes = loadedMaxInputBytes;
39
+ let pendingInputBytes = 0;
40
+ let loadedHeaderTimeoutMs = MAX_HEADER_BUILD_TIMEOUT_MS;
41
+ let headerTimeoutMs = loadedHeaderTimeoutMs;
42
+ let loadedMaxWorkers = 1;
43
+ let maxWorkers = loadedMaxWorkers;
33
44
  const pendingInput = [];
34
45
  const encoder = new TextEncoder();
35
- // Built in the background by the compile worker after a <bits/stdc++.h> source; it outlives
36
- // runs and cancellations and is discarded only with the sandbox.
46
+ // Header builds survive ordinary cancellation, within their own deadline and Worker budget.
37
47
  let precompiledHeader;
38
48
  let headerWorker;
49
+ function disposeWorker(worker, bridge) {
50
+ worker.onmessage = null;
51
+ worker.onerror = null;
52
+ worker.onmessageerror = null;
53
+ try {
54
+ bridge?.dispose();
55
+ }
56
+ catch {
57
+ // Cleanup must preserve the primary result and still attempt Worker termination.
58
+ }
59
+ try {
60
+ worker.terminate();
61
+ }
62
+ catch {
63
+ // Preserve the primary result even if a custom Worker fails to terminate.
64
+ }
65
+ }
39
66
  function adoptHeaderWorker(worker, bridge) {
40
67
  headerWorker?.dispose();
68
+ let settled = false;
69
+ let timeout;
41
70
  const dispose = () => {
71
+ if (settled)
72
+ return;
73
+ settled = true;
74
+ clearTimeout(timeout);
42
75
  if (headerWorker?.worker === worker)
43
76
  headerWorker = undefined;
44
- bridge?.dispose();
45
- worker.onmessage = null;
46
- worker.onerror = null;
47
- worker.onmessageerror = null;
48
- worker.terminate();
77
+ disposeWorker(worker, bridge);
49
78
  };
50
79
  headerWorker = { worker, dispose };
80
+ timeout = setTimeout(dispose, headerTimeoutMs);
51
81
  worker.onerror = dispose;
52
82
  worker.onmessageerror = dispose;
53
83
  worker.onmessage = (event) => {
54
- if (bridge?.handleMessage(event))
55
- return;
56
- if (event.data?.type !== 'precompiled-header')
84
+ if (settled || disposed || headerWorker?.worker !== worker)
57
85
  return;
58
- if (event.data.header)
59
- precompiledHeader = event.data.header;
60
- dispose();
86
+ try {
87
+ if (bridge?.handleMessage(event))
88
+ return;
89
+ if (event.data?.type === 'error' && event.data.code === 'output-limit') {
90
+ dispose();
91
+ return;
92
+ }
93
+ if (event.data?.type !== 'precompiled-header')
94
+ return;
95
+ if (event.data.header)
96
+ precompiledHeader = event.data.header;
97
+ dispose();
98
+ }
99
+ catch {
100
+ dispose();
101
+ }
61
102
  };
62
103
  }
63
104
  function resetInput() {
64
105
  pendingInput.length = 0;
106
+ pendingInputBytes = 0;
65
107
  pendingEof = false;
66
108
  inputRequested = false;
67
109
  inputBuffer = undefined;
110
+ maxBufferedInputBytes = loadedMaxInputBytes;
111
+ }
112
+ function bufferedInputBytes() {
113
+ const control = inputBuffer && new Int32Array(inputBuffer, 0, 2);
114
+ // DATA remains owned by the consumer until it requests its next chunk.
115
+ const publishedBytes = control && Atomics.load(control, 0) === CLANG_STDIN_DATA ? Atomics.load(control, 1) : 0;
116
+ return pendingInputBytes + publishedBytes;
117
+ }
118
+ function assertInputCapacity(actual, limit = maxBufferedInputBytes) {
119
+ if (actual > limit) {
120
+ throw new RangeError(`C/C++ stdin buffered bytes exceed ${limit}`);
121
+ }
68
122
  }
69
123
  function flushInput() {
70
124
  if (!inputRequested || !inputBuffer)
71
125
  return;
72
126
  const control = new Int32Array(inputBuffer, 0, 2);
73
- const payload = new Uint8Array(inputBuffer, 8);
127
+ const payload = new Uint8Array(inputBuffer, CLANG_STDIN_HEADER_BYTES);
74
128
  const next = pendingInput[0];
75
129
  if (next) {
76
130
  const length = Math.min(next.byteLength, payload.byteLength);
@@ -78,13 +132,14 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
78
132
  if (length === next.byteLength)
79
133
  pendingInput.shift();
80
134
  else
81
- pendingInput[0] = next.subarray(length);
135
+ pendingInput[0] = next.slice(length);
136
+ pendingInputBytes -= length;
82
137
  Atomics.store(control, 1, length);
83
- Atomics.store(control, 0, 1);
138
+ Atomics.store(control, 0, CLANG_STDIN_DATA);
84
139
  }
85
140
  else if (pendingEof) {
86
141
  Atomics.store(control, 1, 0);
87
- Atomics.store(control, 0, 2);
142
+ Atomics.store(control, 0, CLANG_STDIN_EOF);
88
143
  }
89
144
  else
90
145
  return;
@@ -98,9 +153,12 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
98
153
  resetInput();
99
154
  }
100
155
  async function workerOperation(factory, message, token, progress, compileLimit = 0, signal, executionAssetConfig = assetConfig) {
156
+ // The background compiler and the next foreground Worker share one budget.
157
+ if (headerWorker && maxWorkers < 2)
158
+ headerWorker.dispose();
101
159
  const worker = await factory();
102
160
  if (token !== generation || signal?.aborted) {
103
- worker.terminate();
161
+ disposeWorker(worker);
104
162
  throw signal?.reason ?? new Error('Process terminated');
105
163
  }
106
164
  return new Promise((resolve, reject) => {
@@ -110,7 +168,7 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
110
168
  bridge = new WorkerAssetBridge(worker, 'clang', executionAssetConfig, progress, compileLimit, languageSysroots, runtimeCache);
111
169
  }
112
170
  catch (error) {
113
- worker.terminate();
171
+ disposeWorker(worker);
114
172
  reject(error);
115
173
  return;
116
174
  }
@@ -124,15 +182,10 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
124
182
  activeWorker = undefined;
125
183
  cancelWorker = undefined;
126
184
  signal?.removeEventListener('abort', abort);
127
- worker.onmessage = null;
128
- worker.onerror = null;
129
- worker.onmessageerror = null;
130
185
  if (keepForHeader)
131
186
  adoptHeaderWorker(worker, bridge);
132
- else {
133
- bridge?.dispose();
134
- worker.terminate();
135
- }
187
+ else
188
+ disposeWorker(worker, bridge);
136
189
  if (error)
137
190
  reject(error);
138
191
  else
@@ -170,6 +223,17 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
170
223
  flushInput();
171
224
  }
172
225
  else if (data.type === 'compiled' || data.type === 'error') {
226
+ if (data.type === 'error' && data.code === 'output-limit') {
227
+ finish(new OutputLimitError(data.error, {
228
+ limit: data.limit,
229
+ actual: data.actual,
230
+ phase: 'compile'
231
+ }));
232
+ return;
233
+ }
234
+ for (const diagnostic of data.diagnostics ?? []) {
235
+ legacy.oncompilerdiagnostic?.({ ...diagnostic });
236
+ }
173
237
  if (data.stdout)
174
238
  legacy.output?.(data.stdout);
175
239
  if (data.stderr)
@@ -178,7 +242,10 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
178
242
  if (data.type === 'error')
179
243
  finish(new Error(data.error), undefined, keepForHeader);
180
244
  else
181
- finish(undefined, data.artifact, keepForHeader);
245
+ finish(undefined, {
246
+ artifact: data.artifact,
247
+ diagnostics: data.diagnostics ?? []
248
+ }, keepForHeader);
182
249
  }
183
250
  else if (data.type === 'done') {
184
251
  if (data.exitCode !== 0 && data.exitCode !== null)
@@ -222,6 +289,11 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
222
289
  return legacy.load(assets, code, log, args, options, progress);
223
290
  runtimeBaseUrl = assetConfig.baseUrl;
224
291
  maxAssetBytes = resolveExecutionLimits(options.limits).maxAssetBytes;
292
+ maxWasmMemoryBytes = resolveExecutionLimits(options.limits).maxWasmMemoryBytes;
293
+ loadedMaxInputBytes = Math.min(MAX_BUFFERED_INPUT_BYTES, resolveExecutionLimits(options.limits).maxWorkspaceBytes);
294
+ maxBufferedInputBytes = loadedMaxInputBytes;
295
+ loadedHeaderTimeoutMs = Math.min(MAX_HEADER_BUILD_TIMEOUT_MS, resolveExecutionLimits(options.limits).compileTimeoutMs);
296
+ loadedMaxWorkers = resolveExecutionLimits(options.limits).maxWorkers;
225
297
  languageSysroots = config?.clang?.bundledLanguageSysroots === true;
226
298
  },
227
299
  async run(code, prepare, log = true, progress, args = [], options = {}) {
@@ -246,10 +318,13 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
246
318
  };
247
319
  options.signal?.throwIfAborted();
248
320
  const token = ++generation;
321
+ headerTimeoutMs = Math.min(loadedHeaderTimeoutMs, resolveExecutionLimits(options.limits).compileTimeoutMs);
322
+ maxWorkers = Math.min(loadedMaxWorkers, resolveExecutionLimits(options.limits).maxWorkers);
249
323
  // Reactive UI arrays/records are Proxies and cannot cross postMessage.
250
324
  // Snapshot known fields before awaiting compilation, so the cache key,
251
325
  // compiler and executor also observe the same input values.
252
326
  const request = {
327
+ maxWasmMemoryBytes: Math.min(maxWasmMemoryBytes, resolveExecutionLimits(options.limits).maxWasmMemoryBytes),
253
328
  code,
254
329
  language,
255
330
  activePath: options.activePath,
@@ -268,16 +343,37 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
268
343
  ? undefined
269
344
  : Object.fromEntries(Object.entries(options.env));
270
345
  const stdin = options.stdin;
346
+ const inputLimit = Math.min(loadedMaxInputBytes, resolveExecutionLimits(options.limits).maxWorkspaceBytes);
347
+ if (!prepare && typeof stdin === 'string') {
348
+ // A string stdin is a complete input stream and replaces any queued writes.
349
+ // Check UTF-16 length first to avoid encoding an arbitrarily large write.
350
+ assertInputCapacity(stdin.length, inputLimit);
351
+ assertInputCapacity(encoder.encode(stdin).byteLength, inputLimit);
352
+ resetInput();
353
+ pendingEof = true;
354
+ }
355
+ else {
356
+ assertInputCapacity(bufferedInputBytes(), inputLimit);
357
+ }
271
358
  const limit = Math.min(maxAssetBytes, resolveExecutionLimits(options.limits).maxAssetBytes);
272
359
  const key = clangCompileKey(runtimeBaseUrl, limit, request, languageSysroots);
273
360
  let artifact = cache.get(key);
361
+ // Per-run backpressure starts only after admission and ends with this run.
362
+ maxBufferedInputBytes = inputLimit;
274
363
  running = true;
275
364
  try {
276
- if (!artifact) {
277
- artifact = await workerOperation(() => factories.compile(), {
365
+ if (artifact) {
366
+ for (const diagnostic of cache.getDiagnostics(key))
367
+ legacy.oncompilerdiagnostic?.(diagnostic);
368
+ if (token !== generation)
369
+ throw new Error('Process terminated');
370
+ }
371
+ else {
372
+ const compiled = await workerOperation(() => factories.compile(), {
278
373
  request,
279
374
  runtimeBaseUrl,
280
375
  maxAssetBytes: limit,
376
+ maxOutputBytes: resolveExecutionLimits(options.limits).maxOutputBytes,
281
377
  languageSysroots,
282
378
  log,
283
379
  persistentCache: executionAssetConfig.persistentCache,
@@ -293,14 +389,16 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
293
389
  }, token, progress, limit, options.signal, executionAssetConfig);
294
390
  if (token !== generation)
295
391
  throw new Error('Process terminated');
296
- cache.set(key, artifact);
392
+ artifact = compiled.artifact;
393
+ cache.set(key, artifact, compiled.diagnostics);
297
394
  }
298
395
  progress?.set?.(1);
299
396
  if (prepare)
300
397
  return true;
301
- inputBuffer = new SharedArrayBuffer(65536 + 8);
398
+ inputBuffer = new SharedArrayBuffer(Math.min(65536, maxBufferedInputBytes) + CLANG_STDIN_HEADER_BYTES);
302
399
  return await workerOperation(() => factories.execute(), {
303
400
  artifact,
401
+ maxWasmMemoryBytes: request.maxWasmMemoryBytes,
304
402
  code,
305
403
  activePath: request.activePath,
306
404
  workspaceFiles: request.workspaceFiles,
@@ -313,16 +411,27 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
313
411
  finally {
314
412
  if (token === generation) {
315
413
  running = false;
414
+ maxBufferedInputBytes = loadedMaxInputBytes;
316
415
  if (!prepare)
317
416
  resetInput();
318
417
  }
319
418
  }
320
419
  },
321
420
  write(input) {
421
+ if (disposed)
422
+ throw new Error('C/C++ sandbox was disposed');
322
423
  if (!cached)
323
424
  return legacy.write?.(input);
324
- if (input)
325
- pendingInput.push(encoder.encode(input));
425
+ if (pendingEof)
426
+ throw new Error('C/C++ stdin is closed');
427
+ if (input) {
428
+ const buffered = bufferedInputBytes();
429
+ assertInputCapacity(buffered + input.length);
430
+ const bytes = encoder.encode(input);
431
+ assertInputCapacity(buffered + bytes.byteLength);
432
+ pendingInput.push(bytes);
433
+ pendingInputBytes += bytes.byteLength;
434
+ }
326
435
  flushInput();
327
436
  },
328
437
  eof() {
@@ -7,10 +7,10 @@ export const BUNDLED_CLANG_ASSET_INTEGRITY = Object.freeze({
7
7
  'runtime-manifest.v1.json': integrityEntry(967, '0b854bc6b41924420cfcc840509ecbe03af3c63ca3edd4940897917e32c8d8ad'),
8
8
  'libc-printscan-long-double.a.gz': integrityEntry(52_723, 'b3f11e17e40fb13371a97244fdde00d5bd951ad8e20dfdf88a069167d6be628b', 111_062, '33e04007d3547095068391b42189d1ac5398dd04e9da3118dfa644ffea7f4148'),
9
9
  'bin/memfs.wasm.gz': integrityEntry(16_111, 'a3e43451bc15ae69a7f113009e2ee82ab4db711625c1782cd45d0d3c4d38175a', 38_071, '5b741e03dd3502bcfd80e4e5055232b5d633604e1461752efed0189f93407dc3'),
10
- 'bin/clang.wasm.gz': integrityEntry(13_121_917, '8dc032057fbeb41e4a9986dfc54b2336c17532033dee172eb0095eba9c5fbe75', 35_658_969, 'd92ef06cdd3fea88acf384db15a6f2a344790c05bcba8e9f13f5b75b36ad4a99'),
11
- 'bin/lld.wasm.gz': integrityEntry(6_417_339, '495813efde8f354c38483749cdface7a7d9e23c8411da45a6f5f80030159eb11', 16_171_013, '34d39bc410c098e7e09933b61cc8e28699447af9a28abf4544d71b6e9cad1f9d'),
12
- 'bin/sysroot.tar.gz': integrityEntry(5_059_493, 'c0ef46e903492383a3c7069bfd4aed0e764e8df988f92bb81eb96bea50bf2c00', 19_312_640, 'e122f1acec0642d62d8976101c542aaa5346460df6eae5a3f8efb594ff32f5ae'),
13
- 'bin/c-sysroot.tar.gz': integrityEntry(1_216_797, 'fb3e1cdacac3eceddcfe2e57cbbf78e593ec2a298f01acb61c06e4b9d24fbbee', 3_736_064, '720c620e459025e918747768b9f5f1aef7b48c6df1b34c1a31fb2e5b1b7a213e'),
14
- 'bin/cpp-addon.tar.gz': integrityEntry(3_840_608, '47e9946c5aaeb3b35a1d42d6a80eae8987c596f4f858b207e492c00d8680af9e', 15_572_992, '7d61b724d377dc4e5670725055fb2884ebc8153d697e05093992004d5859310d'),
15
- 'language-sysroots.v1.json': integrityEntry(175_348, 'd69acbdb636009dc5b2243f13f1580264f64a34362f0af67c9cd661388b565d0')
10
+ 'bin/clang.wasm.gz': integrityEntry(13_124_999, 'cc7b6b229af392f439a1ca89dbb8d5e016792264a0a6ee59608ff24e269be982', 35_597_829, 'fe7c40c2369d4a1b91d87cd2a38b1a5be11cd7f381373b7888be0b5f209e2d5b'),
11
+ 'bin/lld.wasm.gz': integrityEntry(6_421_841, '798ce825f3e3cf9a695b6a049f157ba28d38731a3dc5e699ccdf23d69d3a5c20', 16_136_490, '77949fed32d5481979b8ebe6081009e3ec69c7219cb355e3f388a316746ea9b7'),
12
+ 'bin/sysroot.tar.gz': integrityEntry(6_780_412, '6188b500fa7af2dceadcbd6dcf2619b6935fa94c224c1c2078426666ebea1d50', 35_594_240, 'fb6d8a8786ec395009d44f62ff24a5bf09ff8672340b7dae9f48e28cf1569cba'),
13
+ 'bin/c-sysroot.tar.gz': integrityEntry(2_006_388, 'da7a29250b2fe2d928fa8818069ff67e1dcb26c529bbf01f40bbeb251535ecaa', 12_213_760, '517b32208f4e556b22eb5ac775411c39fb75239dfaf81f206e6052e168425b62'),
14
+ 'bin/cpp-addon.tar.gz': integrityEntry(4_776_509, '6e243c219561b1f5aad64db4a9ff8bbeb85a97b5e3b5df3ed71d8340d35a8cd7', 23_382_528, 'feaf2aa538623ec8c543ccb49e9a833d2a1aa6dee7a9ad502c277deba24ef642'),
15
+ 'language-sysroots.v1.json': integrityEntry(426_858, '08f6c2c87b4bebc9599193334e1d0ed322ebb38cbdd2bbb83d2b8c3a4cb61263')
16
16
  });
@@ -1,9 +1,11 @@
1
1
  import type { BrowserClangArtifact, BrowserClangCompileProgress, BrowserClangCompileRequest, BrowserClangPrecompiledHeader, BrowserClangWorkspaceFile } from '@wasm-idle/llvm-core/clang';
2
+ import type { CompilerDiagnostic } from '@wasm-idle/llvm-core/clang';
2
3
  import type { WorkerRuntimeAssetConfig } from './worker/assets';
3
4
  export type ClangCompileWorkerRequest = {
4
5
  request: Omit<BrowserClangCompileRequest, 'onProgress'>;
5
6
  runtimeBaseUrl: string;
6
7
  maxAssetBytes?: number;
8
+ maxOutputBytes?: number;
7
9
  languageSysroots?: boolean;
8
10
  log?: boolean;
9
11
  assets: WorkerRuntimeAssetConfig;
@@ -23,18 +25,27 @@ export type ClangCompileWorkerResponse = {
23
25
  artifact: BrowserClangArtifact;
24
26
  stdout: string;
25
27
  stderr: string;
28
+ diagnostics?: CompilerDiagnostic[];
26
29
  precompiledHeader?: 'building';
27
- } | {
30
+ } | ({
28
31
  type: 'error';
29
32
  error: string;
30
33
  stdout: string;
31
34
  stderr: string;
35
+ diagnostics?: CompilerDiagnostic[];
32
36
  precompiledHeader?: 'building';
37
+ } & ({
38
+ code?: undefined;
33
39
  } | {
40
+ code: 'output-limit';
41
+ limit: number;
42
+ actual: number;
43
+ })) | {
34
44
  type: 'precompiled-header';
35
45
  header?: BrowserClangPrecompiledHeader;
36
46
  };
37
47
  export type ClangExecuteWorkerRequest = {
48
+ maxWasmMemoryBytes?: number;
38
49
  artifact: BrowserClangArtifact;
39
50
  programArgs?: string[];
40
51
  env?: Record<string, string>;
@@ -1,4 +1,5 @@
1
1
  import { WorkerAssetBridge } from './assetBridge';
2
+ import type { RuntimeAssetCache } from './runtimeAssetCache';
2
3
  import { type PlaygroundRuntimeAssets } from './assets';
3
4
  import type { SandboxExecutionOptions } from './options';
4
5
  import type { Sandbox, SandboxProgress } from './sandbox';
@@ -18,10 +19,12 @@ declare class Cobol implements Sandbox {
18
19
  assetBridge: WorkerAssetBridge | null;
19
20
  activeCobolBaseUrl: string;
20
21
  private activeOperation;
22
+ private runtimeAssetCache?;
21
23
  private disposed;
22
24
  private disposePromise;
23
25
  private readonly disposeCancellation;
24
26
  private readonly workerSession;
27
+ setRuntimeAssetCache(cache: RuntimeAssetCache): void;
25
28
  private beginOperation;
26
29
  private isOperationActive;
27
30
  private releaseOperation;
@@ -26,6 +26,7 @@ class Cobol {
26
26
  assetBridge = null;
27
27
  activeCobolBaseUrl = '';
28
28
  activeOperation = null;
29
+ runtimeAssetCache;
29
30
  disposed = false;
30
31
  disposePromise = null;
31
32
  disposeCancellation = new CancelledError('COBOL sandbox disposed', {
@@ -53,6 +54,14 @@ class Cobol {
53
54
  this.pendingEof = false;
54
55
  }
55
56
  });
57
+ setRuntimeAssetCache(cache) {
58
+ if (this.runtimeAssetCache === cache)
59
+ return;
60
+ if (this.disposed || this.worker || this.activeOperation) {
61
+ throw new RuntimeConfigurationError('Cannot replace an active COBOL compiler cache');
62
+ }
63
+ this.runtimeAssetCache = cache;
64
+ }
56
65
  beginOperation(phase) {
57
66
  if (this.disposed) {
58
67
  throw new RuntimeConfigurationError('COBOL sandbox is disposed', {
@@ -303,7 +312,7 @@ class Cobol {
303
312
  }
304
313
  let assetBridge;
305
314
  try {
306
- assetBridge = new WorkerAssetBridge(worker, 'clang', clangAssets, progress, limits.maxAssetBytes);
315
+ assetBridge = new WorkerAssetBridge(worker, 'clang', clangAssets, progress, limits.maxAssetBytes, false, this.runtimeAssetCache);
307
316
  }
308
317
  catch (error) {
309
318
  try {
@@ -0,0 +1,8 @@
1
+ import { StaticWorkerRuntimeSandbox } from './staticWorkerRuntime';
2
+ /** Real upstream ECL (Embeddable Common-Lisp) built to Wasm by the wasm-llvm producer. */
3
+ export default class CommonLisp extends StaticWorkerRuntimeSandbox {
4
+ readonly evidence: {
5
+ current: unknown;
6
+ };
7
+ constructor();
8
+ }
@@ -0,0 +1,33 @@
1
+ import { StaticWorkerRuntimeSandbox } from './staticWorkerRuntime';
2
+ import { preflightCommonLispRuntimeAssets, resolveCommonLispRuntimeAssetConfig } from './commonlispAssets';
3
+ /** Real upstream ECL (Embeddable Common-Lisp) built to Wasm by the wasm-llvm producer. */
4
+ export default class CommonLisp extends StaticWorkerRuntimeSandbox {
5
+ evidence;
6
+ constructor() {
7
+ const evidence = { current: undefined };
8
+ super({
9
+ displayName: 'Common Lisp',
10
+ languageId: 'COMMONLISP',
11
+ defaultActivePath: 'main.lisp',
12
+ workerLifetime: { mode: 'per-run' },
13
+ runtimePreflightDelivery: 'transfer-owned',
14
+ inlineVerifiedWorker: true,
15
+ requireExactWorkerResponseUrl: true,
16
+ moduleWorker: true,
17
+ includeExecutionLimits: true,
18
+ onEvidence(value) {
19
+ evidence.current = value;
20
+ },
21
+ stdin: {
22
+ mode: 'streaming',
23
+ sourceHintPattern: /\(\s*(?:read|read-line|read-char|read-byte|peek-char)\b|\*standard-input\*/i
24
+ },
25
+ resolveRuntimeAssets: resolveCommonLispRuntimeAssetConfig,
26
+ async preflightRuntimeAssets(urls, context) {
27
+ evidence.current = undefined;
28
+ return context.createOwnedDelivery(await preflightCommonLispRuntimeAssets(urls.baseUrl, context));
29
+ }
30
+ });
31
+ this.evidence = evidence;
32
+ }
33
+ }
@@ -0,0 +1,30 @@
1
+ import { type ExecutionLimits, type RuntimeAssetCacheOptions } from '@wasm-idle/core';
2
+ import type { PlaygroundRuntimeAssets } from './assets';
3
+ export declare const COMMONLISP_INITIAL_MEMORY_BYTES: number;
4
+ /** ecl.wasm is delivered as the producer's pinned gzip bytes; `.bin` keeps hosts from adding
5
+ * Content-Encoding, so the browser never transparently decodes it before verification. */
6
+ export declare const COMMONLISP_WASM_STORAGE_PATH = "ecl.wasm.gz.bin";
7
+ export declare const COMMONLISP_RUNTIME_MANIFEST: import("@wasm-idle/core").RuntimeRegistryManifest;
8
+ export declare function resolveCommonLispRuntimeAssetConfig(assets: string | PlaygroundRuntimeAssets, currentUrl: string): {
9
+ baseUrl: string;
10
+ workerUrl: string;
11
+ manifestFingerprint: "56f1eb7cf6470619cb3393e99d5c8ad1841a001ab758f388c006ca1d801ba071";
12
+ workerReceipt: {
13
+ readonly bytes: 12104;
14
+ readonly sha256: "d179242c40cdce862ff45bb35f736eaf8e79b97bdc06754576406ad4de698b7d";
15
+ };
16
+ };
17
+ export declare function preflightCommonLispRuntimeAssets(baseUrl: string, options: {
18
+ limits: ExecutionLimits;
19
+ persistentCache?: RuntimeAssetCacheOptions;
20
+ signal?: AbortSignal;
21
+ reportProgress?: (value: number, stage: string) => void;
22
+ fetch?: typeof globalThis.fetch;
23
+ }): Promise<Readonly<{
24
+ fingerprint: "56f1eb7cf6470619cb3393e99d5c8ad1841a001ab758f388c006ca1d801ba071";
25
+ 'producer-receipt.json': Uint8Array<ArrayBufferLike>;
26
+ 'ecl.mjs': Uint8Array<ArrayBufferLike>;
27
+ 'ecl.wasm': Uint8Array<ArrayBuffer>;
28
+ }>>;
29
+ /** Decode the verified gzip delivery into an exactly sized buffer and verify the logical receipt. */
30
+ export declare function decompressCommonLispWasm(compressed: Uint8Array, signal?: AbortSignal): Promise<Uint8Array<ArrayBuffer>>;