wasm-idle 0.4.0 → 0.5.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 (49) hide show
  1. package/README.md +111 -2
  2. package/dist/clang/app.d.ts +4 -0
  3. package/dist/clang/app.js +330 -15
  4. package/dist/clang/index.d.ts +10 -0
  5. package/dist/clang/index.js +284 -25
  6. package/dist/debug/controller.svelte.d.ts +43 -0
  7. package/dist/debug/controller.svelte.js +268 -0
  8. package/dist/debug/editor/index.d.ts +2 -1
  9. package/dist/debug/editor/index.js +1 -1
  10. package/dist/debug/editor/monaco.d.ts +8 -0
  11. package/dist/debug/editor/monaco.js +23 -0
  12. package/dist/debug/expression.d.ts +24 -0
  13. package/dist/debug/expression.js +307 -138
  14. package/dist/debug/index.d.ts +4 -1
  15. package/dist/debug/index.js +2 -1
  16. package/dist/index.d.ts +6 -3
  17. package/dist/index.js +3 -3
  18. package/dist/playground/assetBridge.d.ts +20 -0
  19. package/dist/playground/assetBridge.js +192 -0
  20. package/dist/playground/assets.d.ts +37 -0
  21. package/dist/playground/assets.js +105 -0
  22. package/dist/playground/clang.d.ts +11 -1
  23. package/dist/playground/clang.js +58 -4
  24. package/dist/playground/index.d.ts +5 -5
  25. package/dist/playground/index.js +48 -6
  26. package/dist/playground/java.d.ts +7 -2
  27. package/dist/playground/java.js +31 -5
  28. package/dist/playground/javaStdin.js +235 -2
  29. package/dist/playground/options.d.ts +18 -0
  30. package/dist/playground/options.js +15 -1
  31. package/dist/playground/python.d.ts +7 -1
  32. package/dist/playground/python.js +50 -5
  33. package/dist/playground/rust.d.ts +32 -0
  34. package/dist/playground/rust.js +175 -0
  35. package/dist/playground/sandbox.d.ts +19 -4
  36. package/dist/playground/wasmRustVersion.d.ts +1 -0
  37. package/dist/playground/wasmRustVersion.js +1 -0
  38. package/dist/playground/worker/assets.d.ts +12 -0
  39. package/dist/playground/worker/assets.js +257 -0
  40. package/dist/playground/worker/clang.js +22 -6
  41. package/dist/playground/worker/java.js +15 -35
  42. package/dist/playground/worker/python.js +13 -33
  43. package/dist/playground/worker/rust.d.ts +1 -0
  44. package/dist/playground/worker/rust.js +159 -0
  45. package/dist/terminal/Terminal.svelte +121 -18
  46. package/dist/terminal/Terminal.svelte.d.ts +4 -0
  47. package/dist/terminal/theme.js +2 -2
  48. package/dist/terminal/types.d.ts +4 -0
  49. package/package.json +19 -13
@@ -0,0 +1,175 @@
1
+ import { resolveRustCompilerUrl } from './assets';
2
+ import { resolveSandboxExecutionArgs } from './options';
3
+ import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
4
+ class Rust {
5
+ output = null;
6
+ worker = null;
7
+ buffer = new SharedArrayBuffer(1024);
8
+ pendingInput = [];
9
+ begin = 0;
10
+ elapse = 0;
11
+ uid = 0;
12
+ exit = true;
13
+ compilerUrl = '';
14
+ assetPath = '';
15
+ activeReject = null;
16
+ oncompilerdiagnostic;
17
+ waitingForInput = false;
18
+ pendingEof = false;
19
+ load(runtimeAssets = '', _code = '', _log = true, _args = [], _options = {}, progress) {
20
+ return new Promise(async (resolve, reject) => {
21
+ this.pendingInput = [];
22
+ this.waitingForInput = false;
23
+ this.pendingEof = false;
24
+ const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
25
+ const nextCompilerUrl = resolveRustCompilerUrl(runtimeAssets, currentUrl);
26
+ const nextAssetPath = typeof runtimeAssets === 'string'
27
+ ? runtimeAssets
28
+ : runtimeAssets?.rootUrl ||
29
+ (typeof window !== 'undefined'
30
+ ? window.location.pathname.replace(/\/$/, '')
31
+ : '');
32
+ if (!nextCompilerUrl) {
33
+ return reject('Rust runtime is not configured. Set PUBLIC_WASM_RUST_COMPILER_URL or runtimeAssets.rust.compilerUrl.');
34
+ }
35
+ const needsWorkerReset = !this.worker || this.compilerUrl !== nextCompilerUrl || this.assetPath !== nextAssetPath;
36
+ this.compilerUrl = nextCompilerUrl;
37
+ this.assetPath = nextAssetPath;
38
+ if (needsWorkerReset && this.worker) {
39
+ this.worker.terminate();
40
+ delete this.worker;
41
+ }
42
+ if (!this.worker) {
43
+ this.worker = new (await import('./worker/rust?worker')).default();
44
+ this.worker.onerror = (event) => {
45
+ const location = event.filename && event.lineno
46
+ ? ` (${event.filename}:${event.lineno}:${event.colno})`
47
+ : '';
48
+ reject(`Rust worker script error: ${event.message || 'unknown error'}${location}`);
49
+ };
50
+ this.worker.onmessageerror = () => {
51
+ reject('Rust worker message deserialization failed');
52
+ };
53
+ this.worker.onmessage = (event) => {
54
+ if (event.data?.load) {
55
+ progress?.set?.(1);
56
+ resolve();
57
+ }
58
+ if (event.data?.error)
59
+ reject(event.data.error);
60
+ };
61
+ this.worker.postMessage({
62
+ load: true,
63
+ compilerUrl: this.compilerUrl,
64
+ path: this.assetPath
65
+ });
66
+ }
67
+ else {
68
+ progress?.set?.(1);
69
+ resolve();
70
+ }
71
+ });
72
+ }
73
+ write(input) {
74
+ this.pendingInput.push(input);
75
+ this.pendingEof = false;
76
+ this.flushPendingInput();
77
+ }
78
+ eof() {
79
+ this.pendingEof = true;
80
+ this.flushPendingInput();
81
+ }
82
+ flushPendingInput() {
83
+ if (!this.waitingForInput)
84
+ return;
85
+ if (flushQueuedStdin(this.pendingInput, this.buffer)) {
86
+ this.waitingForInput = false;
87
+ return;
88
+ }
89
+ if (this.pendingEof) {
90
+ flushBufferedEof(this.buffer);
91
+ this.pendingEof = false;
92
+ this.waitingForInput = false;
93
+ }
94
+ }
95
+ run(code, prepare, _log = true, _prog, args = [], options = {}) {
96
+ this.exit = false;
97
+ return new Promise((resolve, reject) => {
98
+ if (!this.worker)
99
+ return reject('Worker not loaded');
100
+ const { programArgs } = resolveSandboxExecutionArgs('RUST', args, options);
101
+ const targetTriple = options.rustTargetTriple || 'wasm32-wasip1';
102
+ const _uid = ++this.uid;
103
+ this.activeReject = reject;
104
+ const handler = (event) => {
105
+ if (!this.worker)
106
+ return reject('Worker not loaded');
107
+ if (_uid !== this.uid)
108
+ return (this.worker.onmessage = null);
109
+ const { output, results, error, buffer, diagnostic, progress } = event.data;
110
+ if (buffer) {
111
+ this.waitingForInput = true;
112
+ this.flushPendingInput();
113
+ }
114
+ if (progress && typeof progress.percent === 'number') {
115
+ _prog?.set?.(Math.max(0, Math.min(progress.percent / 100, 1)));
116
+ }
117
+ if (output)
118
+ this.output(output);
119
+ if (diagnostic)
120
+ this.oncompilerdiagnostic?.(diagnostic);
121
+ if (results) {
122
+ this.elapse = Date.now() - this.begin;
123
+ this.exit = true;
124
+ this.waitingForInput = false;
125
+ this.pendingEof = false;
126
+ this.activeReject = null;
127
+ resolve(results);
128
+ }
129
+ if (error) {
130
+ this.elapse = Date.now() - this.begin;
131
+ this.exit = true;
132
+ this.waitingForInput = false;
133
+ this.pendingEof = false;
134
+ this.activeReject = null;
135
+ reject(error);
136
+ }
137
+ };
138
+ this.worker.onmessage = handler;
139
+ this.begin = Date.now();
140
+ this.worker.postMessage({
141
+ code,
142
+ prepare,
143
+ buffer: this.buffer,
144
+ args: programArgs,
145
+ targetTriple,
146
+ log: _log
147
+ });
148
+ });
149
+ }
150
+ kill() {
151
+ this.terminate();
152
+ }
153
+ terminate() {
154
+ this.activeReject?.('Process terminated');
155
+ this.activeReject = null;
156
+ this.waitingForInput = false;
157
+ this.pendingEof = false;
158
+ this.uid += 1;
159
+ this.worker?.terminate?.();
160
+ delete this.worker;
161
+ this.exit = true;
162
+ }
163
+ async clear() {
164
+ this.pendingInput = [];
165
+ this.waitingForInput = false;
166
+ this.pendingEof = false;
167
+ if (this.worker)
168
+ this.worker.onmessage = null;
169
+ resetBufferedStdin(this.buffer);
170
+ if (!this.exit) {
171
+ this.terminate();
172
+ }
173
+ }
174
+ }
175
+ export default Rust;
@@ -1,13 +1,15 @@
1
1
  import type { CompilerDiagnostic, DebugCommand, DebugSessionEvent, SandboxExecutionOptions } from './options';
2
+ import type { PlaygroundRuntimeAssets } from './assets';
2
3
  import type { Writable } from 'svelte/store';
3
- type ProgressLike = Writable<number> | {
4
+ export type SandboxRuntimeAssets = string | PlaygroundRuntimeAssets;
5
+ export type SandboxProgress = Writable<number> | {
4
6
  set?: (value: number) => void;
5
7
  };
6
8
  export interface Sandbox {
7
9
  constructor: any;
8
10
  eof: () => void;
9
- load: (path: string, code?: string, log?: boolean, args?: string[], options?: SandboxExecutionOptions) => Promise<void>;
10
- run: (code: string, prepare: boolean, log?: boolean, prog?: ProgressLike, args?: string[], options?: SandboxExecutionOptions) => Promise<boolean | string>;
11
+ load: (runtimeAssets?: SandboxRuntimeAssets, code?: string, log?: boolean, args?: string[], options?: SandboxExecutionOptions, progress?: SandboxProgress) => Promise<void>;
12
+ run: (code: string, prepare: boolean, log?: boolean, prog?: SandboxProgress, args?: string[], options?: SandboxExecutionOptions) => Promise<boolean | string>;
11
13
  terminate: () => void;
12
14
  clear: () => Promise<void>;
13
15
  kill?: () => void;
@@ -16,6 +18,7 @@ export interface Sandbox {
16
18
  ondebug?: (event: DebugSessionEvent) => void;
17
19
  oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
18
20
  debugCommand?: (command: DebugCommand) => void;
21
+ setBreakpoints?: (lines: number[]) => void;
19
22
  debugEvaluate?: (expression: string) => Promise<string>;
20
23
  image?: (data: {
21
24
  mime: string;
@@ -24,4 +27,16 @@ export interface Sandbox {
24
27
  }) => void;
25
28
  elapse?: number;
26
29
  }
27
- export {};
30
+ export interface BoundSandbox extends Omit<Sandbox, 'load'> {
31
+ load: (code?: string, log?: boolean, args?: string[], options?: SandboxExecutionOptions, progress?: SandboxProgress) => Promise<void>;
32
+ runtimeAssets: SandboxRuntimeAssets;
33
+ }
34
+ export interface PlaygroundTerminalProps {
35
+ playground: PlaygroundBinding;
36
+ runtimeAssets: SandboxRuntimeAssets;
37
+ }
38
+ export interface PlaygroundBinding {
39
+ runtimeAssets: SandboxRuntimeAssets;
40
+ terminalProps: PlaygroundTerminalProps;
41
+ load: (language: string) => Promise<BoundSandbox>;
42
+ }
@@ -0,0 +1 @@
1
+ export declare const WASM_RUST_ASSET_VERSION = "2d36c8a3cd2cbbfd";
@@ -0,0 +1 @@
1
+ export const WASM_RUST_ASSET_VERSION = "2d36c8a3cd2cbbfd";
@@ -0,0 +1,12 @@
1
+ export interface WorkerRuntimeAssetConfig {
2
+ baseUrl: string;
3
+ useAssetBridge: boolean;
4
+ }
5
+ interface LoadedWorkerAsset {
6
+ bytes: Uint8Array;
7
+ mimeType?: string;
8
+ }
9
+ export declare function configureWorkerRuntimeAssets(config: WorkerRuntimeAssetConfig | null): void;
10
+ export declare function handleWorkerAssetMessage(data: any): boolean;
11
+ export declare function loadWorkerRuntimeAsset(asset: string): Promise<LoadedWorkerAsset>;
12
+ export {};
@@ -0,0 +1,257 @@
1
+ const decoder = new TextDecoder();
2
+ const originalFetch = globalThis.fetch.bind(globalThis);
3
+ const NativeXMLHttpRequest = globalThis.XMLHttpRequest;
4
+ let activeConfig = null;
5
+ let interceptorsInstalled = false;
6
+ let nextAssetRequestId = 0;
7
+ const pendingAssetRequests = new Map();
8
+ const responseBuffer = (bytes) => {
9
+ const buffer = bytes.buffer;
10
+ return bytes.byteOffset === 0 && bytes.byteLength === buffer.byteLength
11
+ ? buffer
12
+ : buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
13
+ };
14
+ const trackedAssetUrl = (input) => {
15
+ if (!activeConfig)
16
+ return null;
17
+ if (typeof input === 'string')
18
+ return new URL(input, activeConfig.baseUrl).href;
19
+ if (input instanceof URL)
20
+ return input.href;
21
+ return input.url;
22
+ };
23
+ const trackedAssetName = (url) => {
24
+ if (!activeConfig || !url.startsWith(activeConfig.baseUrl))
25
+ return null;
26
+ return url.slice(activeConfig.baseUrl.length);
27
+ };
28
+ const isTrackedAssetUrl = (url) => trackedAssetName(url) !== null;
29
+ const loadAssetFromBridge = async (asset) => {
30
+ const id = ++nextAssetRequestId;
31
+ return await new Promise((resolve, reject) => {
32
+ pendingAssetRequests.set(id, { resolve, reject });
33
+ self.postMessage({
34
+ assetRequest: {
35
+ id,
36
+ asset
37
+ }
38
+ });
39
+ });
40
+ };
41
+ const loadAssetFromUrl = async (url, asset) => {
42
+ const response = await originalFetch(url);
43
+ if (!response.ok)
44
+ throw new Error(`Failed to load ${asset}: ${response.status}`);
45
+ const total = Number(response.headers.get('content-length') || 0) || undefined;
46
+ const mimeType = response.headers.get('content-type') || undefined;
47
+ if (!response.body) {
48
+ const bytes = new Uint8Array(await response.arrayBuffer());
49
+ self.postMessage({
50
+ assetProgress: {
51
+ asset,
52
+ loaded: bytes.byteLength,
53
+ total: total ?? bytes.byteLength
54
+ }
55
+ });
56
+ return { bytes, mimeType };
57
+ }
58
+ const reader = response.body.getReader();
59
+ let receivedLength = 0;
60
+ const chunks = [];
61
+ while (true) {
62
+ const { done, value } = await reader.read();
63
+ if (done)
64
+ break;
65
+ if (!value)
66
+ continue;
67
+ const chunk = Uint8Array.from(value);
68
+ chunks.push(chunk);
69
+ receivedLength += chunk.byteLength;
70
+ self.postMessage({
71
+ assetProgress: {
72
+ asset,
73
+ loaded: receivedLength,
74
+ total
75
+ }
76
+ });
77
+ }
78
+ const bytes = new Uint8Array(receivedLength);
79
+ let position = 0;
80
+ for (const chunk of chunks) {
81
+ bytes.set(chunk, position);
82
+ position += chunk.byteLength;
83
+ }
84
+ self.postMessage({
85
+ assetProgress: {
86
+ asset,
87
+ loaded: receivedLength,
88
+ total: total ?? receivedLength
89
+ }
90
+ });
91
+ return { bytes, mimeType };
92
+ };
93
+ async function loadTrackedAsset(url) {
94
+ const asset = trackedAssetName(url);
95
+ if (!asset || !activeConfig)
96
+ throw new Error('Untracked runtime asset request');
97
+ return activeConfig.useAssetBridge
98
+ ? await loadAssetFromBridge(asset)
99
+ : await loadAssetFromUrl(url, asset);
100
+ }
101
+ function createTrackedResponse(asset) {
102
+ return new Response(responseBuffer(asset.bytes), {
103
+ status: 200,
104
+ headers: asset.mimeType ? { 'Content-Type': asset.mimeType } : undefined
105
+ });
106
+ }
107
+ function installTrackedFetch() {
108
+ if (typeof NativeXMLHttpRequest === 'undefined')
109
+ return;
110
+ class RuntimeAssetXMLHttpRequest {
111
+ responseType = '';
112
+ response = null;
113
+ responseText = '';
114
+ readyState = 0;
115
+ status = 0;
116
+ statusText = '';
117
+ timeout = 0;
118
+ withCredentials = false;
119
+ onload = null;
120
+ onerror = null;
121
+ onprogress = null;
122
+ onreadystatechange = null;
123
+ native = null;
124
+ url = '';
125
+ open(method, url) {
126
+ const resolvedUrl = trackedAssetUrl(url);
127
+ if (!resolvedUrl || !isTrackedAssetUrl(resolvedUrl)) {
128
+ const nativeUrl = resolvedUrl || (url instanceof URL ? url.href : String(url));
129
+ this.native = new NativeXMLHttpRequest();
130
+ this.native.responseType = this.responseType;
131
+ this.native.timeout = this.timeout;
132
+ this.native.withCredentials = this.withCredentials;
133
+ this.native.onload = (event) => {
134
+ this.response = this.native?.response;
135
+ this.responseText = this.native?.responseText || '';
136
+ this.readyState = this.native?.readyState || 0;
137
+ this.status = this.native?.status || 0;
138
+ this.statusText = this.native?.statusText || '';
139
+ this.onreadystatechange?.call(this, event);
140
+ this.onload?.call(this, event);
141
+ };
142
+ this.native.onerror = (event) => {
143
+ this.readyState = this.native?.readyState || 4;
144
+ this.status = this.native?.status || 0;
145
+ this.statusText = this.native?.statusText || '';
146
+ this.onreadystatechange?.call(this, event);
147
+ this.onerror?.call(this, event);
148
+ };
149
+ this.native.onprogress = (event) => {
150
+ this.onprogress?.call(this, event);
151
+ };
152
+ this.native.onreadystatechange = (event) => {
153
+ this.readyState = this.native?.readyState || 0;
154
+ this.onreadystatechange?.call(this, event);
155
+ };
156
+ this.native.open(method, nativeUrl);
157
+ return;
158
+ }
159
+ this.url = resolvedUrl;
160
+ this.readyState = 1;
161
+ this.onreadystatechange?.call(this, new ProgressEvent('readystatechange'));
162
+ }
163
+ setRequestHeader(name, value) {
164
+ this.native?.setRequestHeader(name, value);
165
+ }
166
+ async send(body) {
167
+ if (this.native) {
168
+ this.native.send(body);
169
+ return;
170
+ }
171
+ try {
172
+ const loaded = await loadTrackedAsset(this.url);
173
+ const buffer = responseBuffer(loaded.bytes);
174
+ this.status = 200;
175
+ this.statusText = 'OK';
176
+ this.readyState = 4;
177
+ if (this.responseType === 'arraybuffer') {
178
+ this.response = buffer;
179
+ }
180
+ else if (this.responseType === 'blob') {
181
+ this.response = new Blob([buffer], {
182
+ type: loaded.mimeType || 'application/octet-stream'
183
+ });
184
+ }
185
+ else {
186
+ const text = decoder.decode(loaded.bytes);
187
+ this.responseText = text;
188
+ this.response = text;
189
+ }
190
+ const progressEvent = new ProgressEvent('progress', {
191
+ lengthComputable: true,
192
+ loaded: loaded.bytes.byteLength,
193
+ total: loaded.bytes.byteLength
194
+ });
195
+ this.onprogress?.call(this, progressEvent);
196
+ this.onreadystatechange?.call(this, new ProgressEvent('readystatechange'));
197
+ this.onload?.call(this, new ProgressEvent('load'));
198
+ }
199
+ catch (error) {
200
+ this.readyState = 4;
201
+ this.status = 0;
202
+ this.statusText = error instanceof Error ? error.message : String(error);
203
+ this.onreadystatechange?.call(this, new ProgressEvent('readystatechange'));
204
+ this.onerror?.call(this, new ProgressEvent('error'));
205
+ }
206
+ }
207
+ abort() {
208
+ this.native?.abort();
209
+ }
210
+ getAllResponseHeaders() {
211
+ return this.native?.getAllResponseHeaders() || '';
212
+ }
213
+ getResponseHeader(name) {
214
+ return this.native?.getResponseHeader(name) || null;
215
+ }
216
+ }
217
+ globalThis.XMLHttpRequest = RuntimeAssetXMLHttpRequest;
218
+ }
219
+ function installRuntimeAssetInterceptors() {
220
+ if (interceptorsInstalled)
221
+ return;
222
+ interceptorsInstalled = true;
223
+ globalThis.fetch = (async (input, init) => {
224
+ const resolvedUrl = trackedAssetUrl(input);
225
+ if (!resolvedUrl || !isTrackedAssetUrl(resolvedUrl))
226
+ return originalFetch(input, init);
227
+ return createTrackedResponse(await loadTrackedAsset(resolvedUrl));
228
+ });
229
+ installTrackedFetch();
230
+ }
231
+ export function configureWorkerRuntimeAssets(config) {
232
+ activeConfig = config;
233
+ installRuntimeAssetInterceptors();
234
+ }
235
+ export function handleWorkerAssetMessage(data) {
236
+ const response = data?.assetResponse;
237
+ if (!response)
238
+ return false;
239
+ const pending = pendingAssetRequests.get(response.id);
240
+ if (!pending)
241
+ return true;
242
+ pendingAssetRequests.delete(response.id);
243
+ if (!response.ok) {
244
+ pending.reject(new Error(response.error || 'Runtime asset request failed'));
245
+ return true;
246
+ }
247
+ pending.resolve({
248
+ bytes: new Uint8Array(response.bytes),
249
+ mimeType: response.mimeType || undefined
250
+ });
251
+ return true;
252
+ }
253
+ export async function loadWorkerRuntimeAsset(asset) {
254
+ if (!activeConfig)
255
+ throw new Error('Runtime asset config unavailable');
256
+ return await loadTrackedAsset(new URL(asset, activeConfig.baseUrl).href);
257
+ }
@@ -4,7 +4,7 @@ self.document = {
4
4
  return [];
5
5
  }
6
6
  };
7
- let stdinBufferClang, debugBufferClang, interruptBufferClang, clang;
7
+ let stdinBufferClang, debugBufferClang, watchBufferClang, watchResultBufferClang, interruptBufferClang, clang;
8
8
  async function loadClang(path, log) {
9
9
  const { default: Clang } = await import('../../clang');
10
10
  clang = new Clang({
@@ -17,7 +17,7 @@ async function loadClang(path, log) {
17
17
  });
18
18
  }
19
19
  self.onmessage = async (event) => {
20
- const { code, buffer, debugBuffer, load, interrupt, log, path, prepare, args, debug, breakpoints, pauseOnEntry } = event.data;
20
+ const { code, buffer, debugBuffer, watchBuffer, watchResultBuffer, load, interrupt, log, path, prepare, language, compileArgs, programArgs, cppVersion, cVersion, debug, breakpoints, pauseOnEntry } = event.data;
21
21
  if (load) {
22
22
  await loadClang(path, log);
23
23
  postMessage({ load: true });
@@ -25,15 +25,23 @@ self.onmessage = async (event) => {
25
25
  else if (prepare) {
26
26
  stdinBufferClang = new Int32Array(buffer);
27
27
  debugBufferClang = new Int32Array(debugBuffer);
28
+ watchBufferClang = new Int32Array(watchBuffer);
29
+ watchResultBufferClang = new Int32Array(watchResultBuffer);
28
30
  interruptBufferClang = new Uint8Array(interrupt);
29
31
  try {
30
32
  await clang.compileLink(code, {
31
- args,
33
+ language,
34
+ compileArgs,
35
+ programArgs,
36
+ cppVersion,
37
+ cVersion,
32
38
  debug,
33
39
  breakpoints,
34
40
  pauseOnEntry,
35
41
  debugBuffer: debugBufferClang,
36
- interruptBuffer: interruptBufferClang
42
+ interruptBuffer: interruptBufferClang,
43
+ watchBuffer: watchBufferClang,
44
+ watchResultBuffer: watchResultBufferClang
37
45
  });
38
46
  self.postMessage({ results: true });
39
47
  }
@@ -45,15 +53,23 @@ self.onmessage = async (event) => {
45
53
  clang.log = log;
46
54
  stdinBufferClang = new Int32Array(buffer);
47
55
  debugBufferClang = new Int32Array(debugBuffer);
56
+ watchBufferClang = new Int32Array(watchBuffer);
57
+ watchResultBufferClang = new Int32Array(watchResultBuffer);
48
58
  interruptBufferClang = new Uint8Array(interrupt);
49
59
  try {
50
60
  await clang.compileLinkRun(code, {
51
- args,
61
+ language,
62
+ compileArgs,
63
+ programArgs,
64
+ cppVersion,
65
+ cVersion,
52
66
  debug,
53
67
  breakpoints,
54
68
  pauseOnEntry,
55
69
  debugBuffer: debugBufferClang,
56
- interruptBuffer: interruptBufferClang
70
+ interruptBuffer: interruptBufferClang,
71
+ watchBuffer: watchBufferClang,
72
+ watchResultBuffer: watchResultBufferClang
57
73
  });
58
74
  self.postMessage({ results: true });
59
75
  }
@@ -1,6 +1,6 @@
1
1
  import { prepareJavaStdinInjection } from '../javaStdin';
2
2
  import { waitForBufferedStdin } from '../stdinBuffer';
3
- import { resolveTeaVmAssetUrl } from '../teavmConfig';
3
+ import { configureWorkerRuntimeAssets, handleWorkerAssetMessage, loadWorkerRuntimeAsset } from './assets';
4
4
  let compilerLib = null;
5
5
  let compiler = null;
6
6
  let runtimeLoad = null;
@@ -15,18 +15,8 @@ let compiledStdin = '';
15
15
  let compiledMainClass = '';
16
16
  let compiledWasm = null;
17
17
  let currentSourcePath = '';
18
- const isGzip = (bytes) => bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b;
19
- const maybeDecompressWasm = async (bytes) => {
20
- if (!isGzip(bytes))
21
- return bytes;
22
- if (typeof DecompressionStream === 'undefined') {
23
- throw new Error('Generated WebAssembly is gzip-compressed, but DecompressionStream is unavailable');
24
- }
25
- const stream = new Blob([Uint8Array.from(bytes)])
26
- .stream()
27
- .pipeThrough(new DecompressionStream('gzip'));
28
- return new Uint8Array(await new Response(stream).arrayBuffer());
29
- };
18
+ const decoder = new TextDecoder();
19
+ const toInt8Array = (bytes) => new Int8Array(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
30
20
  const flushStdout = () => {
31
21
  if (!stdoutBuffer)
32
22
  return;
@@ -50,41 +40,31 @@ const pushStderr = (charCode) => {
50
40
  flushStderr();
51
41
  };
52
42
  self.addEventListener('message', async (event) => {
53
- const { load, baseUrl, buffer, code, prepare, args = [], stdin = '' } = event.data;
43
+ if (handleWorkerAssetMessage(event.data))
44
+ return;
45
+ const { load, assets, buffer, code, prepare, args = [], stdin = '' } = event.data;
54
46
  try {
55
47
  if (load) {
48
+ const runtimeAssets = assets;
49
+ configureWorkerRuntimeAssets(runtimeAssets || null);
50
+ const baseUrl = runtimeAssets?.baseUrl || '';
56
51
  if (!compiler || loadedBaseUrl !== baseUrl) {
57
52
  loadedBaseUrl = baseUrl;
58
- const runtimeSource = await fetch(resolveTeaVmAssetUrl(baseUrl, 'compiler.wasm-runtime.js')).then((response) => {
59
- if (!response.ok)
60
- throw new Error(`Failed to load TeaVM compiler runtime: ${response.status}`);
61
- return response.text();
62
- });
53
+ const runtimeSource = decoder.decode((await loadWorkerRuntimeAsset('compiler.wasm-runtime.js')).bytes);
63
54
  const runtimeUrl = URL.createObjectURL(new Blob([runtimeSource], { type: 'text/javascript;charset=utf-8' }));
64
55
  const runtimeModule = await import(/* @vite-ignore */ runtimeUrl);
56
+ URL.revokeObjectURL(runtimeUrl);
65
57
  const runtimeLoadFn = runtimeModule.load;
66
58
  runtimeLoad = runtimeLoadFn;
67
- const compilerWasm = await fetch(resolveTeaVmAssetUrl(baseUrl, 'compiler.wasm')).then(async (response) => {
68
- if (!response.ok)
69
- throw new Error(`Failed to load TeaVM compiler wasm: ${response.status}`);
70
- return await maybeDecompressWasm(new Uint8Array(await response.arrayBuffer()));
71
- });
59
+ const compilerWasm = (await loadWorkerRuntimeAsset('compiler.wasm')).bytes;
72
60
  const compilerModule = await runtimeLoadFn(compilerWasm, {
73
61
  stackDeobfuscator: { enabled: false }
74
62
  });
75
63
  compilerLib = compilerModule.exports;
76
64
  compiler = compilerLib.createCompiler();
77
65
  const [sdk, runtimeClasslib] = await Promise.all([
78
- fetch(resolveTeaVmAssetUrl(baseUrl, 'compile-classlib-teavm.bin')).then(async (response) => {
79
- if (!response.ok)
80
- throw new Error(`Failed to load TeaVM SDK: ${response.status}`);
81
- return new Int8Array(await response.arrayBuffer());
82
- }),
83
- fetch(resolveTeaVmAssetUrl(baseUrl, 'runtime-classlib-teavm.bin')).then(async (response) => {
84
- if (!response.ok)
85
- throw new Error(`Failed to load TeaVM runtime classlib: ${response.status}`);
86
- return new Int8Array(await response.arrayBuffer());
87
- })
66
+ loadWorkerRuntimeAsset('compile-classlib-teavm.bin').then(({ bytes }) => toInt8Array(bytes)),
67
+ loadWorkerRuntimeAsset('runtime-classlib-teavm.bin').then(({ bytes }) => toInt8Array(bytes))
88
68
  ]);
89
69
  compiler.setSdk(sdk);
90
70
  compiler.setTeaVMClasslib(runtimeClasslib);
@@ -185,7 +165,7 @@ self.addEventListener('message', async (event) => {
185
165
  compiledCode = code;
186
166
  compiledStdin = stdinInjection.stdinCacheKey;
187
167
  compiledMainClass = mainClass;
188
- compiledWasm = await maybeDecompressWasm(new Uint8Array(compiler.getWebAssemblyOutputFile('app.wasm')));
168
+ compiledWasm = new Uint8Array(compiler.getWebAssemblyOutputFile('app.wasm'));
189
169
  }
190
170
  if (prepare) {
191
171
  self.postMessage({ results: true });