wasm-idle 1.0.7 → 1.0.9

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 (59) hide show
  1. package/README.md +48 -11
  2. package/dist/playground/applicationAssets.js +18 -0
  3. package/dist/playground/assetBridge.js +7 -0
  4. package/dist/playground/assets.d.ts +70 -0
  5. package/dist/playground/assets.js +120 -0
  6. package/dist/playground/cachedClang.js +43 -5
  7. package/dist/playground/clang.d.ts +5 -0
  8. package/dist/playground/clang.js +96 -0
  9. package/dist/playground/clangAssetIntegrity.d.ts +6 -0
  10. package/dist/playground/clangAssetIntegrity.js +3 -2
  11. package/dist/playground/clangWorkerProtocol.d.ts +12 -1
  12. package/dist/playground/fennel.d.ts +9 -0
  13. package/dist/playground/fennel.js +30 -0
  14. package/dist/playground/fennelBootstrap.d.ts +31 -0
  15. package/dist/playground/fennelBootstrap.js +118 -0
  16. package/dist/playground/grain.d.ts +9 -0
  17. package/dist/playground/grain.js +127 -0
  18. package/dist/playground/hy.d.ts +21 -0
  19. package/dist/playground/hy.js +24 -0
  20. package/dist/playground/index.d.ts +1 -1
  21. package/dist/playground/index.js +49 -0
  22. package/dist/playground/lua.d.ts +19 -0
  23. package/dist/playground/lua.js +64 -39
  24. package/dist/playground/objectivec.d.ts +3 -1
  25. package/dist/playground/objectivec.js +6 -2
  26. package/dist/playground/options.js +1 -1
  27. package/dist/playground/postgresql.d.ts +36 -0
  28. package/dist/playground/postgresql.js +543 -0
  29. package/dist/playground/python.d.ts +5 -0
  30. package/dist/playground/python.js +13 -0
  31. package/dist/playground/rescript.d.ts +5 -0
  32. package/dist/playground/rescript.js +58 -0
  33. package/dist/playground/rescriptPreflight.d.ts +26 -0
  34. package/dist/playground/rescriptPreflight.js +381 -0
  35. package/dist/playground/staticRuntimeModuleVersion.d.ts +1 -1
  36. package/dist/playground/staticRuntimeModuleVersion.js +1 -1
  37. package/dist/playground/staticRuntimePreflightExecute.d.ts +2 -1
  38. package/dist/playground/staticRuntimePreflightExecute.js +9 -0
  39. package/dist/playground/staticRuntimePreflightProtocol.d.ts +1 -1
  40. package/dist/playground/v.d.ts +46 -0
  41. package/dist/playground/v.js +703 -0
  42. package/dist/playground/wasmFennelVersion.d.ts +23 -0
  43. package/dist/playground/wasmFennelVersion.js +16 -0
  44. package/dist/playground/wasmGrainVersion.d.ts +24 -0
  45. package/dist/playground/wasmGrainVersion.js +25 -0
  46. package/dist/playground/wasmHyVersion.d.ts +7 -0
  47. package/dist/playground/wasmHyVersion.js +15 -0
  48. package/dist/playground/wasmReScriptVersion.d.ts +20 -0
  49. package/dist/playground/wasmReScriptVersion.js +20 -0
  50. package/dist/playground/worker/cachedClangCompile.js +37 -4
  51. package/dist/playground/worker/clang.js +35 -7
  52. package/dist/playground/worker/lua.js +48 -11
  53. package/dist/playground/worker/postgresql.d.ts +1 -0
  54. package/dist/playground/worker/postgresql.js +205 -0
  55. package/dist/playground/worker/python.js +106 -9
  56. package/dist/playground/worker/staticRuntimePreflight.js +2 -1
  57. package/dist/playground/worker/v.d.ts +1 -0
  58. package/dist/playground/worker/v.js +106 -0
  59. package/package.json +18 -7
@@ -0,0 +1,703 @@
1
+ import { WorkerAssetBridge } from './assetBridge';
2
+ import { resolveVBaseUrl, resolveRuntimeAssetConfig } from './assets';
3
+ import { BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
4
+ import { resolveSandboxExecutionArgs } from './options';
5
+ import { createWasmIdleSharedBuffer } from './sharedBuffer';
6
+ import { WorkerSession } from './workerSession';
7
+ import { reportWorkerInputReady } from './workerProgress';
8
+ import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
9
+ const OUTPUT_ENCODER = new TextEncoder();
10
+ const abortReason = (signal, phase) => signal.reason !== undefined
11
+ ? signal.reason
12
+ : new DOMException(phase === 'startup' ? 'V runtime startup aborted' : 'V execution aborted', 'AbortError');
13
+ class VLang {
14
+ language = 'V';
15
+ output;
16
+ worker = null;
17
+ buffer = createWasmIdleSharedBuffer(4096);
18
+ pendingInput = [];
19
+ begin = 0;
20
+ elapse = 0;
21
+ uid = 0;
22
+ log = true;
23
+ waitingForInput = false;
24
+ pendingEof = false;
25
+ exit = true;
26
+ assetBridge = null;
27
+ activeVBaseUrl = '';
28
+ activeOperation = null;
29
+ disposed = false;
30
+ disposePromise = null;
31
+ disposeCancellation = new CancelledError('V sandbox disposed', {
32
+ phase: 'dispose',
33
+ runtimeId: 'V',
34
+ recoverable: false
35
+ });
36
+ workerSession = new WorkerSession({
37
+ label: 'V',
38
+ onDispose: (worker) => {
39
+ if (this.worker === worker) {
40
+ const assetBridge = this.assetBridge;
41
+ delete this.worker;
42
+ this.assetBridge = null;
43
+ this.activeVBaseUrl = '';
44
+ try {
45
+ assetBridge?.dispose();
46
+ }
47
+ catch {
48
+ // Asset cleanup must not replace the worker operation result.
49
+ }
50
+ }
51
+ this.exit = true;
52
+ this.waitingForInput = false;
53
+ this.pendingEof = false;
54
+ }
55
+ });
56
+ beginOperation(phase) {
57
+ if (this.disposed) {
58
+ throw new RuntimeConfigurationError('V sandbox is disposed', {
59
+ phase: 'dispose',
60
+ runtimeId: 'V'
61
+ });
62
+ }
63
+ if (this.activeOperation) {
64
+ throw new BusyError('V runtime already has an active operation', {
65
+ runtimeId: 'V',
66
+ phase: this.activeOperation.phase
67
+ });
68
+ }
69
+ const operation = {
70
+ token: Symbol(phase),
71
+ phase,
72
+ cancelled: false,
73
+ cleanedUp: false,
74
+ cleanups: [],
75
+ explicitStdin: false
76
+ };
77
+ this.activeOperation = operation;
78
+ return operation;
79
+ }
80
+ isOperationActive(operation) {
81
+ return this.activeOperation?.token === operation.token && !operation.cancelled;
82
+ }
83
+ releaseOperation(operation) {
84
+ if (this.activeOperation?.token !== operation.token)
85
+ return false;
86
+ this.activeOperation = null;
87
+ return true;
88
+ }
89
+ cleanupOperation(operation) {
90
+ if (operation.cleanedUp)
91
+ return;
92
+ operation.cleanedUp = true;
93
+ const cleanups = operation.cleanups.splice(0);
94
+ for (const cleanup of cleanups) {
95
+ try {
96
+ cleanup();
97
+ }
98
+ catch {
99
+ // Caller-owned lifecycle cleanup must not replace the operation result.
100
+ }
101
+ }
102
+ }
103
+ releaseBeforeSession(operation, reason) {
104
+ const outcome = operation.cancelled ? operation.cancellationReason : reason;
105
+ this.releaseOperation(operation);
106
+ this.cleanupOperation(operation);
107
+ return outcome;
108
+ }
109
+ bindPreSessionAbort(operation, signal) {
110
+ if (!signal || !this.isOperationActive(operation))
111
+ return () => undefined;
112
+ let registered = false;
113
+ let unbound = false;
114
+ const unbind = () => {
115
+ if (unbound)
116
+ return;
117
+ unbound = true;
118
+ if (registered)
119
+ signal.removeEventListener('abort', onAbort);
120
+ };
121
+ const onAbort = () => {
122
+ if (!this.isOperationActive(operation))
123
+ return;
124
+ let reason;
125
+ try {
126
+ reason = abortReason(signal, operation.phase);
127
+ }
128
+ catch (error) {
129
+ reason = error;
130
+ }
131
+ operation.cancelled = true;
132
+ operation.cancellationReason = reason;
133
+ this.releaseOperation(operation);
134
+ this.cleanupOperation(operation);
135
+ };
136
+ operation.cleanups.push(unbind);
137
+ try {
138
+ registered = true;
139
+ signal.addEventListener('abort', onAbort, { once: true });
140
+ if (signal.aborted)
141
+ onAbort();
142
+ }
143
+ catch (error) {
144
+ if (this.isOperationActive(operation)) {
145
+ operation.cancelled = true;
146
+ operation.cancellationReason = error;
147
+ this.releaseOperation(operation);
148
+ this.cleanupOperation(operation);
149
+ }
150
+ }
151
+ return unbind;
152
+ }
153
+ bindAbortSignal(operation, signal) {
154
+ if (!signal || !this.isOperationActive(operation))
155
+ return;
156
+ let registered = false;
157
+ const onAbort = () => {
158
+ if (!this.isOperationActive(operation))
159
+ return;
160
+ let reason;
161
+ try {
162
+ reason = abortReason(signal, operation.phase);
163
+ }
164
+ catch (error) {
165
+ reason = error;
166
+ }
167
+ this.cancelOperation(operation, reason);
168
+ };
169
+ operation.cleanups.push(() => {
170
+ if (!registered)
171
+ return;
172
+ try {
173
+ signal.removeEventListener('abort', onAbort);
174
+ }
175
+ catch {
176
+ // Listener cleanup must not replace the operation result.
177
+ }
178
+ });
179
+ try {
180
+ registered = true;
181
+ signal.addEventListener('abort', onAbort, { once: true });
182
+ if (signal.aborted)
183
+ onAbort();
184
+ }
185
+ catch (error) {
186
+ this.cancelOperation(operation, error);
187
+ }
188
+ }
189
+ bindOperationTimeout(operation, timeoutMs) {
190
+ if (!this.isOperationActive(operation))
191
+ return;
192
+ let timeout;
193
+ operation.cleanups.push(() => {
194
+ if (timeout !== undefined)
195
+ clearTimeout(timeout);
196
+ });
197
+ try {
198
+ timeout = setTimeout(() => {
199
+ if (!this.isOperationActive(operation))
200
+ return;
201
+ const label = operation.phase === 'startup' ? 'startup' : 'execution';
202
+ this.cancelOperation(operation, new TimeoutError(`V ${label} timed out after ${timeoutMs} ms`, {
203
+ phase: operation.phase,
204
+ runtimeId: 'V',
205
+ timeoutMs
206
+ }));
207
+ }, timeoutMs);
208
+ if (operation.cleanedUp)
209
+ clearTimeout(timeout);
210
+ }
211
+ catch (error) {
212
+ this.cancelOperation(operation, error);
213
+ }
214
+ }
215
+ resetExplicitStdinState() {
216
+ this.pendingInput = [];
217
+ this.pendingEof = false;
218
+ this.waitingForInput = false;
219
+ try {
220
+ resetBufferedStdin(this.buffer);
221
+ }
222
+ catch {
223
+ // Explicit stdin never consumes the shared terminal buffer.
224
+ }
225
+ }
226
+ finishExplicitStdin(operation) {
227
+ if (!operation.explicitStdin)
228
+ return;
229
+ operation.explicitStdin = false;
230
+ this.resetExplicitStdinState();
231
+ }
232
+ load(runtimeAssets = '', code = '', log = true, args = [], options = {}, progress) {
233
+ let operation;
234
+ try {
235
+ operation = this.beginOperation('startup');
236
+ }
237
+ catch (error) {
238
+ return Promise.reject(error);
239
+ }
240
+ let signal;
241
+ let limits;
242
+ let unbindPreSessionAbort = () => undefined;
243
+ try {
244
+ signal = options.signal;
245
+ unbindPreSessionAbort = this.bindPreSessionAbort(operation, signal);
246
+ if (!this.isOperationActive(operation) || signal?.aborted) {
247
+ return Promise.reject(this.releaseBeforeSession(operation, 'V runtime startup cancelled'));
248
+ }
249
+ limits = resolveExecutionLimits(options.limits);
250
+ if (!this.isOperationActive(operation) || signal?.aborted) {
251
+ return Promise.reject(this.releaseBeforeSession(operation, 'V runtime startup cancelled'));
252
+ }
253
+ unbindPreSessionAbort();
254
+ }
255
+ catch (error) {
256
+ return Promise.reject(this.releaseBeforeSession(operation, error));
257
+ }
258
+ if (!this.isOperationActive(operation)) {
259
+ return Promise.reject(this.releaseBeforeSession(operation, 'V runtime startup cancelled'));
260
+ }
261
+ const loading = this.workerSession.load(async (resolve, reject) => {
262
+ const resolveOperation = () => {
263
+ if (!this.releaseOperation(operation))
264
+ return;
265
+ resolve();
266
+ this.cleanupOperation(operation);
267
+ };
268
+ const rejectOperation = (reason) => {
269
+ if (!this.releaseOperation(operation))
270
+ return;
271
+ reject(reason);
272
+ this.cleanupOperation(operation);
273
+ };
274
+ try {
275
+ if (!this.isOperationActive(operation))
276
+ return;
277
+ this.pendingInput = [];
278
+ this.waitingForInput = false;
279
+ this.pendingEof = false;
280
+ const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
281
+ const clangAssets = resolveRuntimeAssetConfig('clang', runtimeAssets, currentUrl);
282
+ if (!this.isOperationActive(operation))
283
+ return;
284
+ const vBaseUrl = resolveVBaseUrl(runtimeAssets, currentUrl);
285
+ if (!this.isOperationActive(operation))
286
+ return;
287
+ const needsWorkerReset = !this.worker ||
288
+ !this.assetBridge ||
289
+ !this.assetBridge.matches(clangAssets, limits.maxAssetBytes) ||
290
+ this.activeVBaseUrl !== vBaseUrl;
291
+ if (needsWorkerReset && this.worker) {
292
+ this.workerSession.reset();
293
+ }
294
+ if (!this.worker) {
295
+ const WorkerConstructor = (await import('./worker/v?worker'))
296
+ .default;
297
+ if (!this.isOperationActive(operation))
298
+ return;
299
+ const worker = new WorkerConstructor();
300
+ if (!this.isOperationActive(operation)) {
301
+ worker.terminate();
302
+ return;
303
+ }
304
+ let assetBridge;
305
+ try {
306
+ assetBridge = new WorkerAssetBridge(worker, 'clang', clangAssets, progress, limits.maxAssetBytes);
307
+ }
308
+ catch (error) {
309
+ try {
310
+ worker.terminate();
311
+ }
312
+ catch {
313
+ // Worker cleanup must not replace the progress callback error.
314
+ }
315
+ throw error;
316
+ }
317
+ if (!this.isOperationActive(operation)) {
318
+ try {
319
+ assetBridge.dispose();
320
+ }
321
+ catch {
322
+ // Stale asset cleanup is best effort.
323
+ }
324
+ try {
325
+ worker.terminate();
326
+ }
327
+ catch {
328
+ // The unattached worker is already detached.
329
+ }
330
+ return;
331
+ }
332
+ this.worker = worker;
333
+ this.assetBridge = assetBridge;
334
+ this.workerSession.attach(worker);
335
+ let handler;
336
+ const ownsWorker = () => this.worker === worker &&
337
+ this.assetBridge === assetBridge &&
338
+ worker.onmessage === handler;
339
+ const ownsLoad = () => this.isOperationActive(operation) && ownsWorker();
340
+ handler = (event) => {
341
+ if (!ownsWorker())
342
+ return;
343
+ try {
344
+ if (assetBridge.handleMessage(event))
345
+ return;
346
+ if (!ownsLoad())
347
+ return;
348
+ if (event.data?.progress != null) {
349
+ progress?.set?.(event.data.progress);
350
+ if (!ownsLoad())
351
+ return;
352
+ }
353
+ if (event.data?.load) {
354
+ this.log = log;
355
+ this.activeVBaseUrl = vBaseUrl;
356
+ resolveOperation();
357
+ return;
358
+ }
359
+ if (event.data?.error !== undefined)
360
+ rejectOperation(event.data.error);
361
+ }
362
+ catch (error) {
363
+ rejectOperation(error);
364
+ }
365
+ };
366
+ worker.onmessage = handler;
367
+ worker.postMessage({
368
+ load: true,
369
+ log,
370
+ code,
371
+ args,
372
+ clangAssets: {
373
+ baseUrl: clangAssets.baseUrl,
374
+ maxAssetBytes: limits.maxAssetBytes,
375
+ useAssetBridge: clangAssets.useAssetBridge
376
+ },
377
+ vBaseUrl,
378
+ maxAssetBytes: limits.maxAssetBytes
379
+ });
380
+ }
381
+ else {
382
+ const worker = this.worker;
383
+ const assetBridge = this.assetBridge;
384
+ if (!assetBridge) {
385
+ return rejectOperation('V asset bridge is not loaded');
386
+ }
387
+ assetBridge.rebind(worker, clangAssets, progress, limits.maxAssetBytes);
388
+ if (!this.isOperationActive(operation) ||
389
+ this.worker !== worker ||
390
+ this.assetBridge !== assetBridge) {
391
+ return;
392
+ }
393
+ worker.postMessage({ log });
394
+ this.log = log;
395
+ this.activeVBaseUrl = vBaseUrl;
396
+ resolveOperation();
397
+ }
398
+ }
399
+ catch (error) {
400
+ rejectOperation(error);
401
+ }
402
+ });
403
+ const timeoutMs = Math.min(2_147_483_647, limits.assetTimeoutMs + limits.startupTimeoutMs);
404
+ this.bindOperationTimeout(operation, timeoutMs);
405
+ this.bindAbortSignal(operation, signal);
406
+ return loading.finally(() => {
407
+ this.releaseOperation(operation);
408
+ this.cleanupOperation(operation);
409
+ });
410
+ }
411
+ write(input) {
412
+ if (this.disposed)
413
+ return;
414
+ this.pendingInput.push(input);
415
+ this.pendingEof = false;
416
+ this.flushPendingInput();
417
+ }
418
+ eof() {
419
+ if (this.disposed)
420
+ return;
421
+ this.pendingEof = true;
422
+ this.flushPendingInput();
423
+ }
424
+ flushPendingInput() {
425
+ if (!this.waitingForInput)
426
+ return;
427
+ if (flushQueuedStdin(this.pendingInput, this.buffer)) {
428
+ this.waitingForInput = false;
429
+ return;
430
+ }
431
+ if (this.pendingEof) {
432
+ flushBufferedEof(this.buffer);
433
+ this.pendingEof = false;
434
+ this.waitingForInput = false;
435
+ }
436
+ }
437
+ async run(code, prepare, log = this.log, prog, args = [], options = {}) {
438
+ let activeOperation;
439
+ try {
440
+ activeOperation = this.beginOperation('execute');
441
+ }
442
+ catch (error) {
443
+ return Promise.reject(error);
444
+ }
445
+ let signal;
446
+ let unbindPreSessionAbort = () => undefined;
447
+ let worker;
448
+ let assetBridge;
449
+ let compileArgs;
450
+ let programArgs;
451
+ let limits;
452
+ let workspace;
453
+ let stdin;
454
+ try {
455
+ const debug = options.debug;
456
+ if (!this.isOperationActive(activeOperation)) {
457
+ return Promise.reject(this.releaseBeforeSession(activeOperation, 'V execution cancelled'));
458
+ }
459
+ if (debug) {
460
+ return Promise.reject(this.releaseBeforeSession(activeOperation, 'V debugging is not supported yet.'));
461
+ }
462
+ signal = options.signal;
463
+ unbindPreSessionAbort = this.bindPreSessionAbort(activeOperation, signal);
464
+ if (!this.isOperationActive(activeOperation) || signal?.aborted) {
465
+ return Promise.reject(this.releaseBeforeSession(activeOperation, 'V execution cancelled'));
466
+ }
467
+ const currentWorker = this.worker;
468
+ worker = currentWorker;
469
+ if (!worker)
470
+ throw 'Worker not loaded';
471
+ const currentAssetBridge = this.assetBridge;
472
+ assetBridge = currentAssetBridge;
473
+ if (!assetBridge)
474
+ throw 'V asset bridge is not loaded';
475
+ ({ compileArgs, programArgs } = resolveSandboxExecutionArgs(this.language, args, options));
476
+ limits = resolveExecutionLimits(options.limits);
477
+ const workspaceFiles = options.workspaceFiles ?? [];
478
+ const activePath = options.activePath ?? 'main.v';
479
+ const workspaceLimits = options.workspaceLimits;
480
+ workspace = validateExecutionWorkspace(code, workspaceFiles, activePath, {
481
+ ...workspaceLimits,
482
+ maxFileBytes: Math.min(workspaceLimits?.maxFileBytes ?? DEFAULT_WORKSPACE_LIMITS.maxFileBytes, limits.maxWorkspaceBytes),
483
+ maxTotalBytes: Math.min(workspaceLimits?.maxTotalBytes ?? DEFAULT_WORKSPACE_LIMITS.maxTotalBytes, limits.maxWorkspaceBytes)
484
+ });
485
+ stdin = options.stdin;
486
+ if (!this.isOperationActive(activeOperation) || signal?.aborted) {
487
+ return Promise.reject(this.releaseBeforeSession(activeOperation, 'V execution cancelled'));
488
+ }
489
+ unbindPreSessionAbort();
490
+ }
491
+ catch (error) {
492
+ return Promise.reject(this.releaseBeforeSession(activeOperation, error));
493
+ }
494
+ if (!this.isOperationActive(activeOperation)) {
495
+ return Promise.reject(this.releaseBeforeSession(activeOperation, 'V execution cancelled'));
496
+ }
497
+ const hasExplicitStdin = stdin !== undefined;
498
+ if (hasExplicitStdin) {
499
+ activeOperation.explicitStdin = true;
500
+ this.resetExplicitStdinState();
501
+ }
502
+ this.exit = false;
503
+ try {
504
+ return await new Promise((resolve, reject) => {
505
+ let outputBytes = 0;
506
+ const workerOperation = this.workerSession.beginRun(worker, reject);
507
+ const timeoutMs = Math.min(2_147_483_647, limits.compileTimeoutMs + limits.runTimeoutMs);
508
+ this.bindOperationTimeout(activeOperation, timeoutMs);
509
+ this.bindAbortSignal(activeOperation, signal);
510
+ if (!this.isOperationActive(activeOperation))
511
+ return;
512
+ const runUid = ++this.uid;
513
+ let handler;
514
+ const ownsWorker = () => this.worker === worker &&
515
+ this.assetBridge === assetBridge &&
516
+ worker.onmessage === handler;
517
+ const ownsRun = () => this.isOperationActive(activeOperation) && ownsWorker() && runUid === this.uid;
518
+ const claimRun = () => {
519
+ if (!ownsRun())
520
+ return false;
521
+ this.finishExplicitStdin(activeOperation);
522
+ this.workerSession.complete(workerOperation);
523
+ this.releaseOperation(activeOperation);
524
+ this.cleanupOperation(activeOperation);
525
+ this.elapse = Date.now() - this.begin;
526
+ this.exit = true;
527
+ this.waitingForInput = false;
528
+ this.pendingEof = false;
529
+ return true;
530
+ };
531
+ const failRun = (error, disposeWorker = false) => {
532
+ if (!ownsRun())
533
+ return;
534
+ if (disposeWorker) {
535
+ this.cancelOperation(activeOperation, error);
536
+ return;
537
+ }
538
+ if (!claimRun())
539
+ return;
540
+ reject(error);
541
+ };
542
+ handler = (event) => {
543
+ if (!ownsWorker())
544
+ return;
545
+ try {
546
+ if (assetBridge.handleMessage(event))
547
+ return;
548
+ if (!ownsRun())
549
+ return;
550
+ const { output, results, log: workerLog, error, buffer, progress } = event.data;
551
+ if (buffer && !hasExplicitStdin) {
552
+ this.waitingForInput = true;
553
+ if (!prepare) {
554
+ reportWorkerInputReady(prog, 'V runtime ready for input');
555
+ if (!ownsRun())
556
+ return;
557
+ }
558
+ this.flushPendingInput();
559
+ if (!ownsRun())
560
+ return;
561
+ }
562
+ if (output) {
563
+ const actual = outputBytes + OUTPUT_ENCODER.encode(String(output)).byteLength;
564
+ if (actual > limits.maxOutputBytes) {
565
+ failRun(new OutputLimitError(`V output exceeded ${limits.maxOutputBytes} bytes`, {
566
+ actual,
567
+ limit: limits.maxOutputBytes,
568
+ phase: 'execute',
569
+ runtimeId: 'V'
570
+ }), true);
571
+ return;
572
+ }
573
+ outputBytes = actual;
574
+ this.output?.(output);
575
+ if (!ownsRun())
576
+ return;
577
+ }
578
+ if (results !== undefined) {
579
+ if (!claimRun())
580
+ return;
581
+ resolve(results);
582
+ return;
583
+ }
584
+ if (workerLog) {
585
+ console.log(workerLog);
586
+ if (!ownsRun())
587
+ return;
588
+ }
589
+ if (error !== undefined) {
590
+ failRun(error);
591
+ return;
592
+ }
593
+ if (progress != null) {
594
+ prog?.set?.(progress);
595
+ if (!ownsRun())
596
+ return;
597
+ }
598
+ }
599
+ catch (error) {
600
+ failRun(error, true);
601
+ }
602
+ };
603
+ worker.onmessage = handler;
604
+ if (!ownsRun())
605
+ return;
606
+ this.begin = Date.now();
607
+ try {
608
+ worker.postMessage({
609
+ code,
610
+ prepare,
611
+ buffer: this.buffer,
612
+ stdin,
613
+ log,
614
+ compileArgs,
615
+ programArgs,
616
+ activePath: workspace.activePath,
617
+ workspaceFiles: workspace.workspaceFiles
618
+ });
619
+ }
620
+ catch (error) {
621
+ failRun(error);
622
+ }
623
+ });
624
+ }
625
+ finally {
626
+ if (this.releaseOperation(activeOperation)) {
627
+ this.finishExplicitStdin(activeOperation);
628
+ this.exit = true;
629
+ }
630
+ this.cleanupOperation(activeOperation);
631
+ }
632
+ }
633
+ cancelOperation(operation, reason) {
634
+ if (!this.isOperationActive(operation))
635
+ return;
636
+ this.finishExplicitStdin(operation);
637
+ operation.cancelled = true;
638
+ operation.cancellationReason = reason;
639
+ this.activeOperation = null;
640
+ this.waitingForInput = false;
641
+ this.pendingEof = false;
642
+ this.uid += 1;
643
+ this.workerSession.terminate(reason);
644
+ this.exit = true;
645
+ this.cleanupOperation(operation);
646
+ }
647
+ kill() {
648
+ this.terminate();
649
+ }
650
+ terminate(reason = 'Process terminated') {
651
+ if (this.disposed)
652
+ return;
653
+ const operation = this.activeOperation;
654
+ if (operation) {
655
+ this.cancelOperation(operation, reason);
656
+ return;
657
+ }
658
+ this.waitingForInput = false;
659
+ this.pendingEof = false;
660
+ this.uid += 1;
661
+ this.workerSession.terminate(reason);
662
+ this.exit = true;
663
+ }
664
+ async clear() {
665
+ if (this.disposed)
666
+ return;
667
+ this.terminate();
668
+ this.pendingInput = [];
669
+ this.waitingForInput = false;
670
+ this.pendingEof = false;
671
+ resetBufferedStdin(this.buffer);
672
+ await new Promise((resolve) => setTimeout(resolve, 200));
673
+ }
674
+ dispose() {
675
+ if (this.disposePromise)
676
+ return this.disposePromise;
677
+ this.disposed = true;
678
+ this.disposePromise = Promise.resolve();
679
+ const activeOperation = this.activeOperation;
680
+ const assetBridge = this.assetBridge;
681
+ delete this.worker;
682
+ this.assetBridge = null;
683
+ this.activeVBaseUrl = '';
684
+ this.output = undefined;
685
+ this.resetExplicitStdinState();
686
+ try {
687
+ assetBridge?.dispose();
688
+ }
689
+ catch {
690
+ // Asset cleanup is best effort after host state becomes unreachable.
691
+ }
692
+ if (activeOperation) {
693
+ this.cancelOperation(activeOperation, this.disposeCancellation);
694
+ }
695
+ else {
696
+ this.uid += 1;
697
+ this.workerSession.terminate(this.disposeCancellation);
698
+ this.exit = true;
699
+ }
700
+ return this.disposePromise;
701
+ }
702
+ }
703
+ export default VLang;