@ox-content/code-play 3.0.0-alpha.1 → 3.0.0-alpha.11

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.
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as escapeHtml, l as mergeConfig, p as resolveLanguage, u as resolveCodePlayOptions } from "./payload.mjs";
1
+ import { a as escapeHtml, d as mergeConfig, f as resolveCodePlayOptions, h as resolveLanguage } from "./payload.mjs";
2
2
  //#region \0rolldown/runtime.js
3
3
  var __defProp = Object.defineProperty;
4
4
  var __exportAll = (all, no_symbols) => {
@@ -336,10 +336,115 @@ function buildJavaScriptSandboxDocument(code, messageId) {
336
336
  })();
337
337
  <\/script></body></html>`;
338
338
  }
339
+ function buildJavaScriptWorkerSource() {
340
+ return `
341
+ (function () {
342
+ function format(args) {
343
+ return Array.prototype.map.call(args, function (value) {
344
+ if (typeof value === "string") return value;
345
+ if (value === undefined) return "undefined";
346
+ if (value === null) return "null";
347
+ try { return JSON.stringify(value); } catch (error) { return String(value); }
348
+ }).join(" ") + "\\n";
349
+ }
350
+ self.onmessage = function (event) {
351
+ var data = event.data || {};
352
+ if (!data.id) return;
353
+ var stdout = [];
354
+ var stderr = [];
355
+ var consoleLike = {
356
+ log: function () { stdout.push(format(arguments)); },
357
+ info: function () { stdout.push(format(arguments)); },
358
+ warn: function () { stderr.push(format(arguments)); },
359
+ error: function () { stderr.push(format(arguments)); }
360
+ };
361
+ try {
362
+ var run = new Function("console", '"use strict";\\n' + String(data.code || ""));
363
+ var value = run(consoleLike);
364
+ self.postMessage({
365
+ id: data.id,
366
+ stdout: stdout,
367
+ stderr: stderr,
368
+ value: value === undefined ? undefined : String(value)
369
+ });
370
+ } catch (error) {
371
+ var message = error && error.message ? String(error.message) : String(error);
372
+ self.postMessage({ id: data.id, stdout: stdout, stderr: stderr, error: message });
373
+ }
374
+ };
375
+ })();
376
+ `;
377
+ }
339
378
  function applySandboxStreams(stdio, message) {
340
379
  for (const text of message.stdout ?? []) stdio.push("stdout", text);
341
380
  for (const text of message.stderr ?? []) stdio.push("stderr", text);
342
381
  }
382
+ const WORKER_UNAVAILABLE_CODE = "ERR_SCRIPT_WORKER_UNAVAILABLE";
383
+ function workerUnavailableError(error) {
384
+ const message = error instanceof Error && error.message ? error.message : "JavaScript worker sandbox is unavailable.";
385
+ return Object.assign(new Error(message), { code: WORKER_UNAVAILABLE_CODE });
386
+ }
387
+ function isSandboxWorkerUnavailable(error) {
388
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === WORKER_UNAVAILABLE_CODE);
389
+ }
390
+ function canUseSandboxWorker() {
391
+ return typeof Worker !== "undefined" && typeof Blob !== "undefined" && typeof URL !== "undefined" && typeof URL.createObjectURL === "function" && typeof URL.revokeObjectURL === "function";
392
+ }
393
+ async function executeInSandboxWorker(code, timeoutMs, stdio, signal) {
394
+ if (!canUseSandboxWorker()) throw workerUnavailableError(/* @__PURE__ */ new Error("JavaScript worker sandbox needs Worker, Blob, and object URLs."));
395
+ if (signal?.aborted) throw abortError();
396
+ const messageId = `ox-code-play-${Math.random().toString(36).slice(2)}`;
397
+ const url = URL.createObjectURL(new Blob([buildJavaScriptWorkerSource()], { type: "text/javascript" }));
398
+ let worker;
399
+ try {
400
+ worker = new Worker(url);
401
+ } catch (error) {
402
+ URL.revokeObjectURL(url);
403
+ throw workerUnavailableError(error);
404
+ }
405
+ return new Promise((resolve, reject) => {
406
+ let settled = false;
407
+ const cleanup = () => {
408
+ if (settled) return;
409
+ settled = true;
410
+ clearTimeout(timer);
411
+ signal?.removeEventListener("abort", onAbort);
412
+ worker.onmessage = null;
413
+ worker.onerror = null;
414
+ worker.terminate();
415
+ URL.revokeObjectURL(url);
416
+ };
417
+ const onAbort = () => {
418
+ cleanup();
419
+ reject(abortError());
420
+ };
421
+ const onMessage = (event) => {
422
+ if (event.data?.id !== messageId) return;
423
+ cleanup();
424
+ applySandboxStreams(stdio, event.data);
425
+ if (event.data.error) {
426
+ reject(new Error(event.data.error));
427
+ return;
428
+ }
429
+ resolve(event.data.value);
430
+ };
431
+ const onError = (event) => {
432
+ cleanup();
433
+ reject(workerUnavailableError(new Error(event.message || "JavaScript worker sandbox failed.")));
434
+ };
435
+ const timer = setTimeout(() => {
436
+ cleanup();
437
+ reject(Object.assign(/* @__PURE__ */ new Error("JavaScript execution timed out."), { code: "ERR_SCRIPT_EXECUTION_TIMEOUT" }));
438
+ }, timeoutMs);
439
+ worker.onmessage = onMessage;
440
+ worker.onerror = onError;
441
+ signal?.addEventListener("abort", onAbort, { once: true });
442
+ worker.postMessage({
443
+ id: messageId,
444
+ code
445
+ });
446
+ });
447
+ }
343
448
  async function executeInSandboxIframe(code, timeoutMs, stdio, signal) {
344
449
  if (typeof document === "undefined" || typeof window === "undefined") throw new Error("JavaScript sandbox iframe needs a document.");
345
450
  if (signal?.aborted) throw abortError();
@@ -391,24 +496,23 @@ async function runJavaScript(request) {
391
496
  const tracker = new PhaseTracker();
392
497
  tracker.start("execute", "Execute");
393
498
  const stdio = new StdioBuffer(tracker.startedAt);
394
- const provenance = { execute: {
395
- host: "local",
396
- runtime: hasNodeVm() ? "node:vm" : "iframe",
397
- sandbox: hasNodeVm() ? "vm" : "srcdoc"
398
- } };
499
+ const runtime = currentJavaScriptRuntime();
500
+ let executedRuntime = runtime;
399
501
  try {
400
- const value = await executeScript(request.code, request.timeoutMs, stdio, request.signal);
502
+ const result = await executeScriptWithRuntime(request.code, request.timeoutMs, stdio, request.signal, runtime);
503
+ executedRuntime = result.runtime;
401
504
  tracker.stop();
402
505
  return {
403
506
  status: "ok",
404
507
  stdio: stdio.snapshot(),
405
508
  diagnostics: [],
406
- provenance,
509
+ provenance: { execute: javascriptRuntimeProvenance(executedRuntime) },
407
510
  timing: tracker.report(),
408
- value: value === void 0 ? void 0 : String(value)
511
+ value: result.value === void 0 ? void 0 : String(result.value)
409
512
  };
410
513
  } catch (error) {
411
514
  if (isAbortError(error) || request.signal?.aborted) throw error;
515
+ executedRuntime = executionRuntimeFromError(error) ?? executedRuntime;
412
516
  tracker.stop();
413
517
  const diagnostic = toDiagnostic(error);
414
518
  stdio.push("stderr", `${diagnostic.message}\n`);
@@ -416,12 +520,30 @@ async function runJavaScript(request) {
416
520
  status: isTimeout(error) ? "timeout" : "error",
417
521
  stdio: stdio.snapshot(),
418
522
  diagnostics: [diagnostic],
419
- provenance,
523
+ provenance: { execute: javascriptRuntimeProvenance(executedRuntime) },
420
524
  timing: tracker.report()
421
525
  };
422
526
  }
423
527
  }
424
- async function executeScript(code, timeoutMs, stdio, signal) {
528
+ async function executeScriptWithRuntime(code, timeoutMs, stdio, signal, runtime = currentJavaScriptRuntime()) {
529
+ try {
530
+ return {
531
+ value: await executeScriptInRuntime(code, timeoutMs, stdio, signal, runtime),
532
+ runtime
533
+ };
534
+ } catch (error) {
535
+ if (runtime === "worker" && isSandboxWorkerUnavailable(error) && typeof document !== "undefined") try {
536
+ return {
537
+ value: await executeScriptInRuntime(code, timeoutMs, stdio, signal, "iframe"),
538
+ runtime: "iframe"
539
+ };
540
+ } catch (fallbackError) {
541
+ throw withExecutionRuntime(fallbackError, "iframe");
542
+ }
543
+ throw withExecutionRuntime(error, runtime);
544
+ }
545
+ }
546
+ async function executeScriptInRuntime(code, timeoutMs, stdio, signal, runtime) {
425
547
  const consoleLike = {
426
548
  log: (...args) => stdio.push("stdout", formatConsoleArgs(args)),
427
549
  info: (...args) => stdio.push("stdout", formatConsoleArgs(args)),
@@ -429,7 +551,7 @@ async function executeScript(code, timeoutMs, stdio, signal) {
429
551
  error: (...args) => stdio.push("stderr", formatConsoleArgs(args))
430
552
  };
431
553
  if (signal?.aborted) throw abortError();
432
- if (javascriptExecuteRuntime(hasNodeVm(), typeof document !== "undefined") === "vm") {
554
+ if (runtime === "vm") {
433
555
  const vm = await import("node:vm");
434
556
  const context = vm.createContext({ console: consoleLike });
435
557
  return vm.runInContext(code, context, {
@@ -437,12 +559,45 @@ async function executeScript(code, timeoutMs, stdio, signal) {
437
559
  displayErrors: true
438
560
  });
439
561
  }
562
+ if (runtime === "worker") return executeInSandboxWorker(code, timeoutMs, stdio, signal);
440
563
  return executeInSandboxIframe(code, timeoutMs, stdio, signal);
441
564
  }
442
- function javascriptExecuteRuntime(hasVm, hasDocument) {
565
+ function currentJavaScriptRuntime() {
566
+ return javascriptExecuteRuntime(hasNodeVm(), canUseSandboxWorker(), typeof document !== "undefined");
567
+ }
568
+ function javascriptExecuteRuntime(hasVm, hasWorker, hasDocument) {
443
569
  if (hasVm) return "vm";
570
+ if (hasWorker) return "worker";
444
571
  if (hasDocument) return "iframe";
445
- throw new Error("JavaScript execute needs node:vm or a document for the sandbox iframe.");
572
+ throw new Error("JavaScript execute needs node:vm, a browser worker sandbox, or a document for the sandbox iframe.");
573
+ }
574
+ function javascriptRuntimeProvenance(runtime) {
575
+ if (runtime === "vm") return {
576
+ host: "local",
577
+ runtime: "node:vm",
578
+ sandbox: "vm"
579
+ };
580
+ if (runtime === "worker") return {
581
+ host: "local",
582
+ runtime: "web-worker",
583
+ sandbox: "worker"
584
+ };
585
+ return {
586
+ host: "local",
587
+ runtime: "iframe",
588
+ sandbox: "srcdoc"
589
+ };
590
+ }
591
+ function withExecutionRuntime(error, runtime) {
592
+ if (error instanceof Error) return Object.assign(error, { executionRuntime: runtime });
593
+ if (isErrorLike(error)) return Object.assign(error, { executionRuntime: runtime });
594
+ return Object.assign(new Error(String(error)), { executionRuntime: runtime });
595
+ }
596
+ function executionRuntimeFromError(error) {
597
+ if (error && typeof error === "object" && "executionRuntime" in error && isJavaScriptExecutionRuntime(error.executionRuntime)) return error.executionRuntime;
598
+ }
599
+ function isJavaScriptExecutionRuntime(value) {
600
+ return value === "vm" || value === "worker" || value === "iframe";
446
601
  }
447
602
  function isTimeout(error) {
448
603
  return Boolean(error && typeof error === "object" && "code" in error && error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT");
@@ -709,9 +864,12 @@ async function runTypeScript(request) {
709
864
  const stdio = new StdioBuffer(tracker.startedAt);
710
865
  tracker.start("compile", "Strip types");
711
866
  const javascript = stripTypeScript(request.code);
867
+ const runtime = currentJavaScriptRuntime();
868
+ let executedRuntime = runtime;
712
869
  tracker.start("execute", "Execute");
713
870
  try {
714
- const value = await executeScript(javascript, request.timeoutMs, stdio, request.signal);
871
+ const result = await executeScriptWithRuntime(javascript, request.timeoutMs, stdio, request.signal, runtime);
872
+ executedRuntime = result.runtime;
715
873
  tracker.stop();
716
874
  return {
717
875
  status: "ok",
@@ -722,14 +880,10 @@ async function runTypeScript(request) {
722
880
  host: "local",
723
881
  runtime: "strip-types"
724
882
  },
725
- execute: {
726
- host: "local",
727
- runtime: hasNodeVm() ? "node:vm" : "iframe",
728
- sandbox: hasNodeVm() ? "vm" : "srcdoc"
729
- }
883
+ execute: javascriptRuntimeProvenance(executedRuntime)
730
884
  },
731
885
  timing: tracker.report(),
732
- value: value === void 0 ? void 0 : String(value)
886
+ value: result.value === void 0 ? void 0 : String(result.value)
733
887
  };
734
888
  } catch (error) {
735
889
  if (isAbortError(error) || request.signal?.aborted) throw error;
@@ -749,11 +903,7 @@ async function runTypeScript(request) {
749
903
  host: "local",
750
904
  runtime: "strip-types"
751
905
  },
752
- execute: {
753
- host: "local",
754
- runtime: hasNodeVm() ? "node:vm" : "iframe",
755
- sandbox: hasNodeVm() ? "vm" : "srcdoc"
756
- }
906
+ execute: javascriptRuntimeProvenance(executedRuntime)
757
907
  },
758
908
  timing: tracker.report()
759
909
  };
@@ -926,9 +1076,12 @@ function errorMessage(error) {
926
1076
  }
927
1077
  function friendlyTransportMessage(error) {
928
1078
  const message = errorMessage(error);
929
- if ((error instanceof TypeError || error instanceof Error && error.name === "TypeError") && /failed to fetch|networkerror|load failed|network request failed/i.test(message)) return "The executor could not be reached from this page (often CORS). Set endpoints to a host that allows browser POST, or use the Vite dev proxy.";
1079
+ if (isOfflineError(error)) return "The executor is offline or unreachable from this page (for example, CORS). Set endpoints to a host that allows browser POST, or use the Vite dev proxy.";
930
1080
  return message;
931
1081
  }
1082
+ function transportFailureStatus(error) {
1083
+ return isOfflineError(error) ? "offline" : "error";
1084
+ }
932
1085
  function errorResult(message, source = "code-play", status = "error") {
933
1086
  return withStdioText({
934
1087
  status,
@@ -942,6 +1095,14 @@ function errorResult(message, source = "code-play", status = "error") {
942
1095
  timing: emptyTiming()
943
1096
  });
944
1097
  }
1098
+ function isOfflineError(error) {
1099
+ const message = errorMessage(error);
1100
+ const name = error && typeof error === "object" && "name" in error ? String(error.name) : void 0;
1101
+ const typeError = error instanceof TypeError || name === "TypeError";
1102
+ if (name === "MissingTransportError") return true;
1103
+ if (typeError && /failed to fetch|networkerror|load failed|network request failed/i.test(message)) return true;
1104
+ return /\boffline\b|no code play transport|network request failed/i.test(message);
1105
+ }
945
1106
  //#endregion
946
1107
  //#region src/session.ts
947
1108
  var CodePlaySession = class {
@@ -961,6 +1122,7 @@ var CodePlaySession = class {
961
1122
  timeoutMs;
962
1123
  transport;
963
1124
  endpoints;
1125
+ project;
964
1126
  loadTypeScript;
965
1127
  listeners = /* @__PURE__ */ new Map();
966
1128
  abort;
@@ -972,6 +1134,7 @@ var CodePlaySession = class {
972
1134
  this.timeoutMs = input.timeoutMs;
973
1135
  this.transport = input.transport;
974
1136
  this.endpoints = input.endpoints;
1137
+ this.project = input.project;
975
1138
  this.loadTypeScript = input.loadTypeScript;
976
1139
  }
977
1140
  on(event, listener) {
@@ -1012,6 +1175,7 @@ var CodePlaySession = class {
1012
1175
  transport: this.transport,
1013
1176
  loadTypeScript: this.loadTypeScript,
1014
1177
  endpoints: this.endpoints,
1178
+ project: this.project,
1015
1179
  signal
1016
1180
  };
1017
1181
  try {
@@ -1019,7 +1183,7 @@ var CodePlaySession = class {
1019
1183
  return this.finish(result);
1020
1184
  } catch (error) {
1021
1185
  if (signal.aborted || isAbortError(error)) return this.finish(errorResult("Run cancelled.", "code-play", "cancelled"));
1022
- return this.finish(errorResult(friendlyTransportMessage(error)));
1186
+ return this.finish(errorResult(friendlyTransportMessage(error), "code-play", transportFailureStatus(error)));
1023
1187
  }
1024
1188
  }
1025
1189
  finish(result) {