@tscircuit/eval 0.0.287 → 0.0.289

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 (46) hide show
  1. package/.github/workflows/bun-test.yml +20 -2
  2. package/dist/blob-url.js +1 -1
  3. package/dist/eval/index.d.ts +59 -8
  4. package/dist/eval/index.js +2 -3
  5. package/dist/lib/index.d.ts +59 -8
  6. package/dist/lib/index.js +43 -4
  7. package/dist/webworker/entrypoint.js +353 -350
  8. package/dist/worker.d.ts +7 -0
  9. package/dist/worker.js +42 -2
  10. package/lib/shared/types.ts +7 -0
  11. package/lib/worker.ts +47 -1
  12. package/package.json +9 -7
  13. package/scripts/validate-test-matrix.js +148 -0
  14. package/tests/{example1-readme-example.test.tsx → examples/example01-readme-example.test.tsx} +1 -1
  15. package/tests/{example2-multiple-files.test.tsx → examples/example02-multiple-files.test.tsx} +1 -1
  16. package/tests/{example3-encoded-url.test.tsx → examples/example03-encoded-url.test.tsx} +1 -1
  17. package/tests/{example4-root-child-issue.test.tsx → examples/example04-root-child-issue.test.tsx} +1 -1
  18. package/tests/{example5-event-recording.test.tsx → examples/example05-event-recording.test.tsx} +1 -1
  19. package/tests/{example7-import-default-and-namespace.test.tsx → examples/example07-import-default-and-namespace.test.tsx} +2 -2
  20. package/tests/{example8-footprinter-to220.test.tsx → examples/example08-footprinter-to220.test.tsx} +1 -1
  21. package/tests/{example9-not-defined-component.test.tsx → examples/example09-not-defined-component.test.tsx} +1 -1
  22. package/tests/{example13-webworker-without-entrypoint.test.tsx → examples/example13-webworker-without-entrypoint.test.tsx} +1 -1
  23. package/tests/{example16-parts-engine.test.tsx → examples/example16-parts-engine.test.tsx} +1 -1
  24. package/tests/{example17-parse-tscircuit-config.test.tsx → examples/example17-parse-tscircuit-config.test.tsx} +1 -1
  25. package/tests/{circuit-event-forwarding.test.tsx → features/circuit-event-forwarding.test.tsx} +1 -1
  26. package/tests/features/fetch-proxy/fetch-override.test.ts +46 -0
  27. package/tests/features/fetch-proxy/fetch-proxy-validation.test.ts +95 -0
  28. package/tests/{kill.test.ts → features/kill.test.ts} +5 -3
  29. package/tests/{manual-edits.test.tsx → features/manual-edits.test.tsx} +2 -2
  30. package/tests/fixtures/resourcePaths.ts +3 -0
  31. package/webworker/entrypoint.ts +7 -2
  32. package/webworker/fetchProxy.ts +83 -0
  33. package/webworker/import-snippet.ts +2 -4
  34. /package/tests/{example6-dynamic-load-blob-url.test.tsx → examples/example06-dynamic-load-blob-url.test.tsx} +0 -0
  35. /package/tests/{example10-run-tscircuit-code.test.tsx → examples/example10-run-tscircuit-code.test.tsx} +0 -0
  36. /package/tests/{example11-flexible-import-extensions.test.tsx → examples/example11-flexible-import-extensions.test.tsx} +0 -0
  37. /package/tests/{example12-import-from-subdirectory.test.tsx → examples/example12-import-from-subdirectory.test.tsx} +0 -0
  38. /package/tests/{example14-run-tscircuit-module.test.tsx → examples/example14-run-tscircuit-module.test.tsx} +0 -0
  39. /package/tests/{example15-run-tscircuit-module-with-props.test.tsx → examples/example15-run-tscircuit-module-with-props.test.tsx} +0 -0
  40. /package/tests/{parent-directory-import.test.tsx → features/parent-directory-import.test.tsx} +0 -0
  41. /package/tests/{platform-config.test.tsx → features/platform-config.test.tsx} +0 -0
  42. /package/tests/{prioritize-default-export.test.tsx → features/prioritize-default-export.test.tsx} +0 -0
  43. /package/tests/{group-wrapper.test.tsx → repros/group-wrapper.test.tsx} +0 -0
  44. /package/tests/{nine-keyboard-default-export.test.tsx → repros/nine-keyboard-default-export.test.tsx} +0 -0
  45. /package/tests/{get-imports-from-code.test.tsx → util-fns/get-imports-from-code.test.tsx} +0 -0
  46. /package/tests/{getPossibleEntrypointComponentPaths.test.ts → util-fns/getPossibleEntrypointComponentPaths.test.ts} +0 -0
package/dist/worker.d.ts CHANGED
@@ -17,6 +17,13 @@ interface WebWorkerConfiguration extends CircuitRunnerConfiguration {
17
17
  */
18
18
  webWorkerUrl?: URL | string;
19
19
  webWorkerBlobUrl?: URL | string;
20
+ /**
21
+ * Enable fetch proxy to route worker fetch requests through parent thread.
22
+ * Useful when running in restricted environments (like ChatGPT) where
23
+ * worker fetch requests are blocked.
24
+ * Default: false
25
+ */
26
+ enableFetchProxy?: boolean;
20
27
  }
21
28
  type CircuitWebWorker = {
22
29
  execute: (code: string) => Promise<void>;
package/dist/worker.js CHANGED
@@ -47,7 +47,7 @@ var createCircuitWebWorker = async (configuration) => {
47
47
  let workerBlobUrl = configuration.webWorkerBlobUrl ?? configuration.webWorkerUrl;
48
48
  if (!workerBlobUrl) {
49
49
  const cdnUrl = `https://cdn.jsdelivr.net/npm/@tscircuit/eval@${configuration.evalVersion ?? "latest"}/dist/webworker/entrypoint.js`;
50
- const workerBlob = await fetch(cdnUrl).then((res) => res.blob());
50
+ const workerBlob = await globalThis.fetch(cdnUrl).then((res) => res.blob());
51
51
  workerBlobUrl = URL.createObjectURL(workerBlob);
52
52
  }
53
53
  const rawWorker = new Worker(workerBlobUrl, { type: "module" });
@@ -66,11 +66,50 @@ var createCircuitWebWorker = async (configuration) => {
66
66
  console.log("[Worker] Message in worker", event);
67
67
  };
68
68
  rawWorker.addEventListener("message", earlyMessageHandler);
69
+ rawWorker.addEventListener("message", async (event) => {
70
+ const data = event.data;
71
+ if (data?.type !== "worker_fetch") return;
72
+ try {
73
+ const response = await globalThis.fetch(data.input, data.init);
74
+ const body = await response.text();
75
+ rawWorker.postMessage({
76
+ type: "worker_fetch_result",
77
+ requestId: data.requestId,
78
+ success: true,
79
+ response: {
80
+ body,
81
+ status: response.status,
82
+ statusText: response.statusText,
83
+ headers: (() => {
84
+ const obj = {};
85
+ response.headers.forEach((value, key) => {
86
+ obj[key] = value;
87
+ });
88
+ return obj;
89
+ })()
90
+ }
91
+ });
92
+ } catch (err) {
93
+ rawWorker.postMessage({
94
+ type: "worker_fetch_result",
95
+ requestId: data.requestId,
96
+ success: false,
97
+ error: {
98
+ name: err.name,
99
+ message: err.message,
100
+ stack: err.stack
101
+ }
102
+ });
103
+ }
104
+ });
69
105
  if (workerInitError) {
70
106
  throw workerInitError;
71
107
  }
72
108
  const comlinkWorker = Comlink.wrap(rawWorker);
73
109
  rawWorker.removeEventListener("message", earlyMessageHandler);
110
+ if (configuration.enableFetchProxy) {
111
+ rawWorker.postMessage({ type: "override_global_fetch" });
112
+ }
74
113
  if (configuration.snippetsApiBaseUrl) {
75
114
  await comlinkWorker.setSnippetsApiBaseUrl(configuration.snippetsApiBaseUrl);
76
115
  }
@@ -110,6 +149,7 @@ var createCircuitWebWorker = async (configuration) => {
110
149
  }
111
150
  }
112
151
  };
152
+ wrapper.__rawWorker = rawWorker;
113
153
  globalThis.TSCIRCUIT_GLOBAL_CIRCUIT_WORKER = wrapper;
114
154
  return wrapper;
115
155
  };
@@ -117,4 +157,4 @@ export {
117
157
  createCircuitWebWorker,
118
158
  getImportsFromCode
119
159
  };
120
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vbGliL3dvcmtlci50cyIsICIuLi9saWIvdXRpbHMvZ2V0LWltcG9ydHMtZnJvbS1jb2RlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQgKiBhcyBDb21saW5rIGZyb20gXCJjb21saW5rXCJcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzL2luZGV4XCJcbmltcG9ydCB0eXBlIHtcbiAgSW50ZXJuYWxXZWJXb3JrZXJBcGksXG4gIFdlYldvcmtlckNvbmZpZ3VyYXRpb24sXG4gIENpcmN1aXRXZWJXb3JrZXIsXG59IGZyb20gXCIuL3NoYXJlZC90eXBlc1wiXG5pbXBvcnQgdHlwZSB7IFJvb3RDaXJjdWl0RXZlbnROYW1lIH0gZnJvbSBcIkB0c2NpcmN1aXQvY29yZVwiXG5cbmV4cG9ydCB0eXBlIHsgQ2lyY3VpdFdlYldvcmtlciwgV2ViV29ya2VyQ29uZmlndXJhdGlvbiB9XG5cbmRlY2xhcmUgZ2xvYmFsIHtcbiAgaW50ZXJmYWNlIFdpbmRvdyB7XG4gICAgVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUjogQ2lyY3VpdFdlYldvcmtlciB8IHVuZGVmaW5lZFxuICB9XG4gIHZhciBUU0NJUkNVSVRfR0xPQkFMX0NJUkNVSVRfV09SS0VSOiBDaXJjdWl0V2ViV29ya2VyIHwgdW5kZWZpbmVkXG59XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVDaXJjdWl0V2ViV29ya2VyID0gYXN5bmMgKFxuICBjb25maWd1cmF0aW9uOiBQYXJ0aWFsPFdlYldvcmtlckNvbmZpZ3VyYXRpb24+LFxuKTogUHJvbWlzZTxDaXJjdWl0V2ViV29ya2VyPiA9PiB7XG4gIC8vIEtpbGwgZXhpc3RpbmcgZ2xvYmFsIHdvcmtlciBpbnN0YW5jZSBpZiBwcmVzZW50XG4gIGNvbnN0IGV4aXN0aW5nV29ya2VyID0gZ2xvYmFsVGhpcy5UU0NJUkNVSVRfR0xPQkFMX0NJUkNVSVRfV09SS0VSXG4gIGlmIChleGlzdGluZ1dvcmtlciAmJiB0eXBlb2YgZXhpc3RpbmdXb3JrZXIua2lsbCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgaWYgKGNvbmZpZ3VyYXRpb24udmVyYm9zZSkge1xuICAgICAgY29uc29sZS5sb2coXCJbV29ya2VyXSBLaWxsaW5nIHByZXZpb3VzIGdsb2JhbCB3b3JrZXIgaW5zdGFuY2UuLi5cIilcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGV4aXN0aW5nV29ya2VyLmtpbGwoKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChjb25maWd1cmF0aW9uLnZlcmJvc2UpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIFwiW1dvcmtlcl0gRXJyb3Iga2lsbGluZyBwcmV2aW91cyBnbG9iYWwgd29ya2VyIGluc3RhbmNlOlwiLFxuICAgICAgICAgIGUsXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIC8vIEVuc3VyZSB0aGUga2V5IGlzIGNsZWFyZWQgZXZlbiBpZiBraWxsIHRocm93cyBhbiBlcnJvclxuICAgICAgaWYgKGdsb2JhbFRoaXMuVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUiA9PT0gZXhpc3RpbmdXb3JrZXIpIHtcbiAgICAgICAgZ2xvYmFsVGhpcy5UU0NJUkNVSVRfR0xPQkFMX0NJUkNVSVRfV09SS0VSID0gdW5kZWZpbmVkXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaWYgKGNvbmZpZ3VyYXRpb24udmVyYm9zZSkge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgXCJbV29ya2VyXSBDcmVhdGluZyBjaXJjdWl0IHdlYiB3b3JrZXIgd2l0aCBjb25maWc6XCIsXG4gICAgICBjb25maWd1cmF0aW9uLFxuICAgIClcbiAgfVxuXG4gIGxldCB3b3JrZXJCbG9iVXJsID1cbiAgICBjb25maWd1cmF0aW9uLndlYldvcmtlckJsb2JVcmwgPz8gY29uZmlndXJhdGlvbi53ZWJXb3JrZXJVcmxcblxuICBpZiAoIXdvcmtlckJsb2JVcmwpIHtcbiAgICBjb25zdCBjZG5VcmwgPSBgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AdHNjaXJjdWl0L2V2YWxAJHtjb25maWd1cmF0aW9uLmV2YWxWZXJzaW9uID8/IFwibGF0ZXN0XCJ9L2Rpc3Qvd2Vid29ya2VyL2VudHJ5cG9pbnQuanNgXG5cbiAgICBjb25zdCB3b3JrZXJCbG9iID0gYXdhaXQgZmV0Y2goY2RuVXJsKS50aGVuKChyZXMpID0+IHJlcy5ibG9iKCkpXG4gICAgd29ya2VyQmxvYlVybCA9IFVSTC5jcmVhdGVPYmplY3RVUkwod29ya2VyQmxvYilcbiAgfVxuXG4gIGNvbnN0IHJhd1dvcmtlciA9IG5ldyBXb3JrZXIod29ya2VyQmxvYlVybCwgeyB0eXBlOiBcIm1vZHVsZVwiIH0pXG4gIGxldCB3b3JrZXJJbml0RXJyb3I6IGFueVxuICByYXdXb3JrZXIuYWRkRXZlbnRMaXN0ZW5lcihcImVycm9yXCIsIChldmVudCkgPT4ge1xuICAgIGNvbnNvbGUuZXJyb3IoXCJbV29ya2VyXSBFcnJvciBpbiB3b3JrZXJcIiwgZXZlbnQpXG4gICAgd29ya2VySW5pdEVycm9yID0gZXZlbnRcbiAgfSlcbiAgcmF3V29ya2VyLmFkZEV2ZW50TGlzdGVuZXIoXCJ1bmhhbmRsZWRyZWplY3Rpb25cIiwgKGV2ZW50KSA9PiB7XG4gICAgY29uc29sZS5lcnJvcihcIltXb3JrZXJdIFVuaGFuZGxlZCByZWplY3Rpb24gaW4gd29ya2VyXCIsIGV2ZW50KVxuICB9KVxuICByYXdXb3JrZXIuYWRkRXZlbnRMaXN0ZW5lcihcIm1lc3NhZ2VlcnJvclwiLCAoZXZlbnQpID0+IHtcbiAgICBjb25zb2xlLmVycm9yKFwiW1dvcmtlcl0gTWVzc2FnZSBlcnJvciBpbiB3b3JrZXJcIiwgZXZlbnQpXG4gIH0pXG4gIGNvbnN0IGVhcmx5TWVzc2FnZUhhbmRsZXIgPSAoZXZlbnQ6IE1lc3NhZ2VFdmVudCkgPT4ge1xuICAgIGNvbnNvbGUubG9nKFwiW1dvcmtlcl0gTWVzc2FnZSBpbiB3b3JrZXJcIiwgZXZlbnQpXG4gIH1cbiAgcmF3V29ya2VyLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIGVhcmx5TWVzc2FnZUhhbmRsZXIpXG5cbiAgaWYgKHdvcmtlckluaXRFcnJvcikge1xuICAgIHRocm93IHdvcmtlckluaXRFcnJvclxuICB9XG5cbiAgY29uc3QgY29tbGlua1dvcmtlciA9IENvbWxpbmsud3JhcDxJbnRlcm5hbFdlYldvcmtlckFwaT4ocmF3V29ya2VyKVxuXG4gIHJhd1dvcmtlci5yZW1vdmVFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBlYXJseU1lc3NhZ2VIYW5kbGVyKVxuXG4gIGlmIChjb25maWd1cmF0aW9uLnNuaXBwZXRzQXBpQmFzZVVybCkge1xuICAgIGF3YWl0IGNvbWxpbmtXb3JrZXIuc2V0U25pcHBldHNBcGlCYXNlVXJsKGNvbmZpZ3VyYXRpb24uc25pcHBldHNBcGlCYXNlVXJsKVxuICB9XG4gIGlmIChjb25maWd1cmF0aW9uLnBsYXRmb3JtKSB7XG4gICAgYXdhaXQgY29tbGlua1dvcmtlci5zZXRQbGF0Zm9ybUNvbmZpZyhjb25maWd1cmF0aW9uLnBsYXRmb3JtKVxuICB9XG5cbiAgbGV0IGlzVGVybWluYXRlZCA9IGZhbHNlXG5cbiAgLy8gQ3JlYXRlIGEgd3JhcHBlciB0aGF0IGhhbmRsZXMgZXZlbnRzIGRpcmVjdGx5IHRocm91Z2ggY2lyY3VpdCBpbnN0YW5jZVxuICBjb25zdCB3cmFwcGVyOiBDaXJjdWl0V2ViV29ya2VyID0ge1xuICAgIGNsZWFyRXZlbnRMaXN0ZW5lcnM6IGNvbWxpbmtXb3JrZXIuY2xlYXJFdmVudExpc3RlbmVycy5iaW5kKGNvbWxpbmtXb3JrZXIpLFxuICAgIHZlcnNpb246IGNvbWxpbmtXb3JrZXIudmVyc2lvbi5iaW5kKGNvbWxpbmtXb3JrZXIpLFxuICAgIGV4ZWN1dGU6IGFzeW5jICguLi5hcmdzKSA9PiB7XG4gICAgICBpZiAoaXNUZXJtaW5hdGVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNpcmN1aXRXZWJXb3JrZXIgd2FzIHRlcm1pbmF0ZWQsIGNhbid0IGV4ZWN1dGVcIilcbiAgICAgIH1cbiAgICAgIHJldHVybiBjb21saW5rV29ya2VyLmV4ZWN1dGUuYmluZChjb21saW5rV29ya2VyKSguLi5hcmdzKVxuICAgIH0sXG4gICAgZXhlY3V0ZVdpdGhGc01hcDogYXN5bmMgKC4uLmFyZ3MpID0+IHtcbiAgICAgIGlmIChpc1Rlcm1pbmF0ZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIFwiQ2lyY3VpdFdlYldvcmtlciB3YXMgdGVybWluYXRlZCwgY2FuJ3QgZXhlY3V0ZVdpdGhGc01hcFwiLFxuICAgICAgICApXG4gICAgICB9XG4gICAgICByZXR1cm4gY29tbGlua1dvcmtlci5leGVjdXRlV2l0aEZzTWFwLmJpbmQoY29tbGlua1dvcmtlcikoLi4uYXJncylcbiAgICB9LFxuICAgIHJlbmRlclVudGlsU2V0dGxlZDogY29tbGlua1dvcmtlci5yZW5kZXJVbnRpbFNldHRsZWQuYmluZChjb21saW5rV29ya2VyKSxcbiAgICBnZXRDaXJjdWl0SnNvbjogY29tbGlua1dvcmtlci5nZXRDaXJjdWl0SnNvbi5iaW5kKGNvbWxpbmtXb3JrZXIpLFxuICAgIG9uOiAoZXZlbnQ6IHN0cmluZywgY2FsbGJhY2s6ICguLi5hcmdzOiBhbnlbXSkgPT4gdm9pZCkgPT4ge1xuICAgICAgY29uc3QgcHJveGllZENhbGxiYWNrID0gQ29tbGluay5wcm94eShjYWxsYmFjaylcbiAgICAgIGNvbWxpbmtXb3JrZXIub24oZXZlbnQgYXMgUm9vdENpcmN1aXRFdmVudE5hbWUsIHByb3hpZWRDYWxsYmFjaylcbiAgICB9LFxuICAgIGtpbGw6IGFzeW5jICgpID0+IHtcbiAgICAgIGNvbWxpbmtXb3JrZXJbQ29tbGluay5yZWxlYXNlUHJveHldKClcbiAgICAgIHJhd1dvcmtlci50ZXJtaW5hdGUoKVxuICAgICAgaXNUZXJtaW5hdGVkID0gdHJ1ZVxuICAgICAgaWYgKGdsb2JhbFRoaXMuVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUiA9PT0gd3JhcHBlcikge1xuICAgICAgICBnbG9iYWxUaGlzLlRTQ0lSQ1VJVF9HTE9CQUxfQ0lSQ1VJVF9XT1JLRVIgPSB1bmRlZmluZWRcbiAgICAgIH1cbiAgICB9LFxuICB9XG4gIGdsb2JhbFRoaXMuVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUiA9IHdyYXBwZXJcbiAgcmV0dXJuIHdyYXBwZXJcbn1cbiIsICJleHBvcnQgY29uc3QgZ2V0SW1wb3J0c0Zyb21Db2RlID0gKGNvZGU6IHN0cmluZyk6IHN0cmluZ1tdID0+IHtcbiAgLy8gTWF0Y2ggYmFzaWMgaW1wb3J0IHBhdHRlcm5zIGluY2x1ZGluZyBjb21iaW5lZCBkZWZhdWx0IGFuZCBuYW1lc3BhY2UgaW1wb3J0c1xuICBjb25zdCBpbXBvcnRSZWdleCA9XG4gICAgL15cXHMqaW1wb3J0XFxzKyg/Oig/OltcXHdcXHNdKyxcXHMqKT8oPzpcXCpcXHMrYXNcXHMrW1xcd1xcc10rfFxce1tcXHNcXHcsXStcXH18XFx3KylcXHMrZnJvbVxccyspP1snXCJdKC4rPylbJ1wiXS9nbVxuICBjb25zdCBpbXBvcnRzOiBzdHJpbmdbXSA9IFtdXG4gIGxldCBtYXRjaDogUmVnRXhwRXhlY0FycmF5IHwgbnVsbFxuXG4gIC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9Bc3NpZ25JbkV4cHJlc3Npb25zOiA8ZXhwbGFuYXRpb24+XG4gIHdoaWxlICgobWF0Y2ggPSBpbXBvcnRSZWdleC5leGVjKGNvZGUpKSAhPT0gbnVsbCkge1xuICAgIGltcG9ydHMucHVzaChtYXRjaFsxXSlcbiAgfVxuXG4gIC8vIE1hdGNoIHJlLWV4cG9ydHNcbiAgY29uc3QgcmVFeHBvcnRSZWdleCA9XG4gICAgL15cXHMqZXhwb3J0XFxzKyg/OlxcKnwoPzpcXHtbXFxzXFx3LF0rXFx9KSlcXHMrZnJvbVxccytbJ1wiXSguKz8pWydcIl0vZ21cbiAgbGV0IHJlRXhwb3J0TWF0Y2g6IFJlZ0V4cEV4ZWNBcnJheSB8IG51bGxcbiAgLy8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub0Fzc2lnbkluRXhwcmVzc2lvbnM6IDxleHBsYW5hdGlvbj5cbiAgd2hpbGUgKChyZUV4cG9ydE1hdGNoID0gcmVFeHBvcnRSZWdleC5leGVjKGNvZGUpKSAhPT0gbnVsbCkge1xuICAgIGltcG9ydHMucHVzaChyZUV4cG9ydE1hdGNoWzFdKVxuICB9XG5cbiAgcmV0dXJuIGltcG9ydHNcbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBQSxZQUFZLGFBQWE7OztBQ0FsQixJQUFNLHFCQUFxQixDQUFDLFNBQTJCO0FBRTVELFFBQU0sY0FDSjtBQUNGLFFBQU0sVUFBb0IsQ0FBQztBQUMzQixNQUFJO0FBR0osVUFBUSxRQUFRLFlBQVksS0FBSyxJQUFJLE9BQU8sTUFBTTtBQUNoRCxZQUFRLEtBQUssTUFBTSxDQUFDLENBQUM7QUFBQSxFQUN2QjtBQUdBLFFBQU0sZ0JBQ0o7QUFDRixNQUFJO0FBRUosVUFBUSxnQkFBZ0IsY0FBYyxLQUFLLElBQUksT0FBTyxNQUFNO0FBQzFELFlBQVEsS0FBSyxjQUFjLENBQUMsQ0FBQztBQUFBLEVBQy9CO0FBRUEsU0FBTztBQUNUOzs7QURKTyxJQUFNLHlCQUF5QixPQUNwQyxrQkFDOEI7QUFFOUIsUUFBTSxpQkFBaUIsV0FBVztBQUNsQyxNQUFJLGtCQUFrQixPQUFPLGVBQWUsU0FBUyxZQUFZO0FBQy9ELFFBQUksY0FBYyxTQUFTO0FBQ3pCLGNBQVEsSUFBSSxxREFBcUQ7QUFBQSxJQUNuRTtBQUNBLFFBQUk7QUFDRixZQUFNLGVBQWUsS0FBSztBQUFBLElBQzVCLFNBQVMsR0FBRztBQUNWLFVBQUksY0FBYyxTQUFTO0FBQ3pCLGdCQUFRO0FBQUEsVUFDTjtBQUFBLFVBQ0E7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUVBLFVBQUksV0FBVyxvQ0FBb0MsZ0JBQWdCO0FBQ2pFLG1CQUFXLGtDQUFrQztBQUFBLE1BQy9DO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFFQSxNQUFJLGNBQWMsU0FBUztBQUN6QixZQUFRO0FBQUEsTUFDTjtBQUFBLE1B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
160
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vbGliL3dvcmtlci50cyIsICIuLi9saWIvdXRpbHMvZ2V0LWltcG9ydHMtZnJvbS1jb2RlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQgKiBhcyBDb21saW5rIGZyb20gXCJjb21saW5rXCJcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzL2luZGV4XCJcbmltcG9ydCB0eXBlIHtcbiAgSW50ZXJuYWxXZWJXb3JrZXJBcGksXG4gIFdlYldvcmtlckNvbmZpZ3VyYXRpb24sXG4gIENpcmN1aXRXZWJXb3JrZXIsXG59IGZyb20gXCIuL3NoYXJlZC90eXBlc1wiXG5pbXBvcnQgdHlwZSB7IFJvb3RDaXJjdWl0RXZlbnROYW1lIH0gZnJvbSBcIkB0c2NpcmN1aXQvY29yZVwiXG5cbmV4cG9ydCB0eXBlIHsgQ2lyY3VpdFdlYldvcmtlciwgV2ViV29ya2VyQ29uZmlndXJhdGlvbiB9XG5cbmRlY2xhcmUgZ2xvYmFsIHtcbiAgaW50ZXJmYWNlIFdpbmRvdyB7XG4gICAgVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUjogQ2lyY3VpdFdlYldvcmtlciB8IHVuZGVmaW5lZFxuICB9XG4gIHZhciBUU0NJUkNVSVRfR0xPQkFMX0NJUkNVSVRfV09SS0VSOiBDaXJjdWl0V2ViV29ya2VyIHwgdW5kZWZpbmVkXG59XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVDaXJjdWl0V2ViV29ya2VyID0gYXN5bmMgKFxuICBjb25maWd1cmF0aW9uOiBQYXJ0aWFsPFdlYldvcmtlckNvbmZpZ3VyYXRpb24+LFxuKTogUHJvbWlzZTxDaXJjdWl0V2ViV29ya2VyPiA9PiB7XG4gIC8vIEtpbGwgZXhpc3RpbmcgZ2xvYmFsIHdvcmtlciBpbnN0YW5jZSBpZiBwcmVzZW50XG4gIGNvbnN0IGV4aXN0aW5nV29ya2VyID0gZ2xvYmFsVGhpcy5UU0NJUkNVSVRfR0xPQkFMX0NJUkNVSVRfV09SS0VSXG4gIGlmIChleGlzdGluZ1dvcmtlciAmJiB0eXBlb2YgZXhpc3RpbmdXb3JrZXIua2lsbCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgaWYgKGNvbmZpZ3VyYXRpb24udmVyYm9zZSkge1xuICAgICAgY29uc29sZS5sb2coXCJbV29ya2VyXSBLaWxsaW5nIHByZXZpb3VzIGdsb2JhbCB3b3JrZXIgaW5zdGFuY2UuLi5cIilcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGV4aXN0aW5nV29ya2VyLmtpbGwoKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChjb25maWd1cmF0aW9uLnZlcmJvc2UpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIFwiW1dvcmtlcl0gRXJyb3Iga2lsbGluZyBwcmV2aW91cyBnbG9iYWwgd29ya2VyIGluc3RhbmNlOlwiLFxuICAgICAgICAgIGUsXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIC8vIEVuc3VyZSB0aGUga2V5IGlzIGNsZWFyZWQgZXZlbiBpZiBraWxsIHRocm93cyBhbiBlcnJvclxuICAgICAgaWYgKGdsb2JhbFRoaXMuVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUiA9PT0gZXhpc3RpbmdXb3JrZXIpIHtcbiAgICAgICAgZ2xvYmFsVGhpcy5UU0NJUkNVSVRfR0xPQkFMX0NJUkNVSVRfV09SS0VSID0gdW5kZWZpbmVkXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaWYgKGNvbmZpZ3VyYXRpb24udmVyYm9zZSkge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgXCJbV29ya2VyXSBDcmVhdGluZyBjaXJjdWl0IHdlYiB3b3JrZXIgd2l0aCBjb25maWc6XCIsXG4gICAgICBjb25maWd1cmF0aW9uLFxuICAgIClcbiAgfVxuXG4gIGxldCB3b3JrZXJCbG9iVXJsID1cbiAgICBjb25maWd1cmF0aW9uLndlYldvcmtlckJsb2JVcmwgPz8gY29uZmlndXJhdGlvbi53ZWJXb3JrZXJVcmxcblxuICBpZiAoIXdvcmtlckJsb2JVcmwpIHtcbiAgICBjb25zdCBjZG5VcmwgPSBgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AdHNjaXJjdWl0L2V2YWxAJHtjb25maWd1cmF0aW9uLmV2YWxWZXJzaW9uID8/IFwibGF0ZXN0XCJ9L2Rpc3Qvd2Vid29ya2VyL2VudHJ5cG9pbnQuanNgXG5cbiAgICBjb25zdCB3b3JrZXJCbG9iID0gYXdhaXQgZ2xvYmFsVGhpcy5mZXRjaChjZG5VcmwpLnRoZW4oKHJlcykgPT4gcmVzLmJsb2IoKSlcbiAgICB3b3JrZXJCbG9iVXJsID0gVVJMLmNyZWF0ZU9iamVjdFVSTCh3b3JrZXJCbG9iKVxuICB9XG5cbiAgY29uc3QgcmF3V29ya2VyID0gbmV3IFdvcmtlcih3b3JrZXJCbG9iVXJsLCB7IHR5cGU6IFwibW9kdWxlXCIgfSlcbiAgbGV0IHdvcmtlckluaXRFcnJvcjogYW55XG4gIHJhd1dvcmtlci5hZGRFdmVudExpc3RlbmVyKFwiZXJyb3JcIiwgKGV2ZW50KSA9PiB7XG4gICAgY29uc29sZS5lcnJvcihcIltXb3JrZXJdIEVycm9yIGluIHdvcmtlclwiLCBldmVudClcbiAgICB3b3JrZXJJbml0RXJyb3IgPSBldmVudFxuICB9KVxuICByYXdXb3JrZXIuYWRkRXZlbnRMaXN0ZW5lcihcInVuaGFuZGxlZHJlamVjdGlvblwiLCAoZXZlbnQpID0+IHtcbiAgICBjb25zb2xlLmVycm9yKFwiW1dvcmtlcl0gVW5oYW5kbGVkIHJlamVjdGlvbiBpbiB3b3JrZXJcIiwgZXZlbnQpXG4gIH0pXG4gIHJhd1dvcmtlci5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZWVycm9yXCIsIChldmVudCkgPT4ge1xuICAgIGNvbnNvbGUuZXJyb3IoXCJbV29ya2VyXSBNZXNzYWdlIGVycm9yIGluIHdvcmtlclwiLCBldmVudClcbiAgfSlcbiAgY29uc3QgZWFybHlNZXNzYWdlSGFuZGxlciA9IChldmVudDogTWVzc2FnZUV2ZW50KSA9PiB7XG4gICAgY29uc29sZS5sb2coXCJbV29ya2VyXSBNZXNzYWdlIGluIHdvcmtlclwiLCBldmVudClcbiAgfVxuICByYXdXb3JrZXIuYWRkRXZlbnRMaXN0ZW5lcihcIm1lc3NhZ2VcIiwgZWFybHlNZXNzYWdlSGFuZGxlcilcblxuICAvLyBIYW5kbGUgZmV0Y2ggcmVxdWVzdHMgZnJvbSB0aGUgd29ya2VyXG4gIHJhd1dvcmtlci5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBhc3luYyAoZXZlbnQ6IE1lc3NhZ2VFdmVudCkgPT4ge1xuICAgIGNvbnN0IGRhdGEgPSBldmVudC5kYXRhXG4gICAgaWYgKGRhdGE/LnR5cGUgIT09IFwid29ya2VyX2ZldGNoXCIpIHJldHVyblxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZ2xvYmFsVGhpcy5mZXRjaChkYXRhLmlucHV0LCBkYXRhLmluaXQpXG4gICAgICBjb25zdCBib2R5ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpXG4gICAgICByYXdXb3JrZXIucG9zdE1lc3NhZ2Uoe1xuICAgICAgICB0eXBlOiBcIndvcmtlcl9mZXRjaF9yZXN1bHRcIixcbiAgICAgICAgcmVxdWVzdElkOiBkYXRhLnJlcXVlc3RJZCxcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgcmVzcG9uc2U6IHtcbiAgICAgICAgICBib2R5LFxuICAgICAgICAgIHN0YXR1czogcmVzcG9uc2Uuc3RhdHVzLFxuICAgICAgICAgIHN0YXR1c1RleHQ6IHJlc3BvbnNlLnN0YXR1c1RleHQsXG4gICAgICAgICAgaGVhZGVyczogKCgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG9iajogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9XG4gICAgICAgICAgICByZXNwb25zZS5oZWFkZXJzLmZvckVhY2goKHZhbHVlLCBrZXkpID0+IHtcbiAgICAgICAgICAgICAgb2JqW2tleV0gPSB2YWx1ZVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVybiBvYmpcbiAgICAgICAgICB9KSgpLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgcmF3V29ya2VyLnBvc3RNZXNzYWdlKHtcbiAgICAgICAgdHlwZTogXCJ3b3JrZXJfZmV0Y2hfcmVzdWx0XCIsXG4gICAgICAgIHJlcXVlc3RJZDogZGF0YS5yZXF1ZXN0SWQsXG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBlcnJvcjoge1xuICAgICAgICAgIG5hbWU6IGVyci5uYW1lLFxuICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgIHN0YWNrOiBlcnIuc3RhY2ssXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgIH1cbiAgfSlcblxuICBpZiAod29ya2VySW5pdEVycm9yKSB7XG4gICAgdGhyb3cgd29ya2VySW5pdEVycm9yXG4gIH1cblxuICBjb25zdCBjb21saW5rV29ya2VyID0gQ29tbGluay53cmFwPEludGVybmFsV2ViV29ya2VyQXBpPihyYXdXb3JrZXIpXG5cbiAgcmF3V29ya2VyLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIGVhcmx5TWVzc2FnZUhhbmRsZXIpXG5cbiAgLy8gQ29uZGl0aW9uYWxseSBvdmVycmlkZSBnbG9iYWwgZmV0Y2ggaW5zaWRlIHRoZSB3b3JrZXIgdG8gcm91dGUgdGhyb3VnaCB0aGUgcGFyZW50XG4gIC8vIE9ubHkgZW5hYmxlIHdoZW4gZXhwbGljaXRseSByZXF1ZXN0ZWQgdmlhIGNvbmZpZ3VyYXRpb25cbiAgaWYgKGNvbmZpZ3VyYXRpb24uZW5hYmxlRmV0Y2hQcm94eSkge1xuICAgIHJhd1dvcmtlci5wb3N0TWVzc2FnZSh7IHR5cGU6IFwib3ZlcnJpZGVfZ2xvYmFsX2ZldGNoXCIgfSlcbiAgfVxuXG4gIGlmIChjb25maWd1cmF0aW9uLnNuaXBwZXRzQXBpQmFzZVVybCkge1xuICAgIGF3YWl0IGNvbWxpbmtXb3JrZXIuc2V0U25pcHBldHNBcGlCYXNlVXJsKGNvbmZpZ3VyYXRpb24uc25pcHBldHNBcGlCYXNlVXJsKVxuICB9XG4gIGlmIChjb25maWd1cmF0aW9uLnBsYXRmb3JtKSB7XG4gICAgYXdhaXQgY29tbGlua1dvcmtlci5zZXRQbGF0Zm9ybUNvbmZpZyhjb25maWd1cmF0aW9uLnBsYXRmb3JtKVxuICB9XG5cbiAgbGV0IGlzVGVybWluYXRlZCA9IGZhbHNlXG5cbiAgLy8gQ3JlYXRlIGEgd3JhcHBlciB0aGF0IGhhbmRsZXMgZXZlbnRzIGRpcmVjdGx5IHRocm91Z2ggY2lyY3VpdCBpbnN0YW5jZVxuICBjb25zdCB3cmFwcGVyOiBDaXJjdWl0V2ViV29ya2VyID0ge1xuICAgIGNsZWFyRXZlbnRMaXN0ZW5lcnM6IGNvbWxpbmtXb3JrZXIuY2xlYXJFdmVudExpc3RlbmVycy5iaW5kKGNvbWxpbmtXb3JrZXIpLFxuICAgIHZlcnNpb246IGNvbWxpbmtXb3JrZXIudmVyc2lvbi5iaW5kKGNvbWxpbmtXb3JrZXIpLFxuICAgIGV4ZWN1dGU6IGFzeW5jICguLi5hcmdzKSA9PiB7XG4gICAgICBpZiAoaXNUZXJtaW5hdGVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNpcmN1aXRXZWJXb3JrZXIgd2FzIHRlcm1pbmF0ZWQsIGNhbid0IGV4ZWN1dGVcIilcbiAgICAgIH1cbiAgICAgIHJldHVybiBjb21saW5rV29ya2VyLmV4ZWN1dGUuYmluZChjb21saW5rV29ya2VyKSguLi5hcmdzKVxuICAgIH0sXG4gICAgZXhlY3V0ZVdpdGhGc01hcDogYXN5bmMgKC4uLmFyZ3MpID0+IHtcbiAgICAgIGlmIChpc1Rlcm1pbmF0ZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIFwiQ2lyY3VpdFdlYldvcmtlciB3YXMgdGVybWluYXRlZCwgY2FuJ3QgZXhlY3V0ZVdpdGhGc01hcFwiLFxuICAgICAgICApXG4gICAgICB9XG4gICAgICByZXR1cm4gY29tbGlua1dvcmtlci5leGVjdXRlV2l0aEZzTWFwLmJpbmQoY29tbGlua1dvcmtlcikoLi4uYXJncylcbiAgICB9LFxuICAgIHJlbmRlclVudGlsU2V0dGxlZDogY29tbGlua1dvcmtlci5yZW5kZXJVbnRpbFNldHRsZWQuYmluZChjb21saW5rV29ya2VyKSxcbiAgICBnZXRDaXJjdWl0SnNvbjogY29tbGlua1dvcmtlci5nZXRDaXJjdWl0SnNvbi5iaW5kKGNvbWxpbmtXb3JrZXIpLFxuICAgIG9uOiAoZXZlbnQ6IHN0cmluZywgY2FsbGJhY2s6ICguLi5hcmdzOiBhbnlbXSkgPT4gdm9pZCkgPT4ge1xuICAgICAgY29uc3QgcHJveGllZENhbGxiYWNrID0gQ29tbGluay5wcm94eShjYWxsYmFjaylcbiAgICAgIGNvbWxpbmtXb3JrZXIub24oZXZlbnQgYXMgUm9vdENpcmN1aXRFdmVudE5hbWUsIHByb3hpZWRDYWxsYmFjaylcbiAgICB9LFxuICAgIGtpbGw6IGFzeW5jICgpID0+IHtcbiAgICAgIGNvbWxpbmtXb3JrZXJbQ29tbGluay5yZWxlYXNlUHJveHldKClcbiAgICAgIHJhd1dvcmtlci50ZXJtaW5hdGUoKVxuICAgICAgaXNUZXJtaW5hdGVkID0gdHJ1ZVxuICAgICAgaWYgKGdsb2JhbFRoaXMuVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUiA9PT0gd3JhcHBlcikge1xuICAgICAgICBnbG9iYWxUaGlzLlRTQ0lSQ1VJVF9HTE9CQUxfQ0lSQ1VJVF9XT1JLRVIgPSB1bmRlZmluZWRcbiAgICAgIH1cbiAgICB9LFxuICB9XG4gIDsod3JhcHBlciBhcyBhbnkpLl9fcmF3V29ya2VyID0gcmF3V29ya2VyXG4gIGdsb2JhbFRoaXMuVFNDSVJDVUlUX0dMT0JBTF9DSVJDVUlUX1dPUktFUiA9IHdyYXBwZXJcbiAgcmV0dXJuIHdyYXBwZXJcbn1cbiIsICJleHBvcnQgY29uc3QgZ2V0SW1wb3J0c0Zyb21Db2RlID0gKGNvZGU6IHN0cmluZyk6IHN0cmluZ1tdID0+IHtcbiAgLy8gTWF0Y2ggYmFzaWMgaW1wb3J0IHBhdHRlcm5zIGluY2x1ZGluZyBjb21iaW5lZCBkZWZhdWx0IGFuZCBuYW1lc3BhY2UgaW1wb3J0c1xuICBjb25zdCBpbXBvcnRSZWdleCA9XG4gICAgL15cXHMqaW1wb3J0XFxzKyg/Oig/OltcXHdcXHNdKyxcXHMqKT8oPzpcXCpcXHMrYXNcXHMrW1xcd1xcc10rfFxce1tcXHNcXHcsXStcXH18XFx3KylcXHMrZnJvbVxccyspP1snXCJdKC4rPylbJ1wiXS9nbVxuICBjb25zdCBpbXBvcnRzOiBzdHJpbmdbXSA9IFtdXG4gIGxldCBtYXRjaDogUmVnRXhwRXhlY0FycmF5IHwgbnVsbFxuXG4gIC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9Bc3NpZ25JbkV4cHJlc3Npb25zOiA8ZXhwbGFuYXRpb24+XG4gIHdoaWxlICgobWF0Y2ggPSBpbXBvcnRSZWdleC5leGVjKGNvZGUpKSAhPT0gbnVsbCkge1xuICAgIGltcG9ydHMucHVzaChtYXRjaFsxXSlcbiAgfVxuXG4gIC8vIE1hdGNoIHJlLWV4cG9ydHNcbiAgY29uc3QgcmVFeHBvcnRSZWdleCA9XG4gICAgL15cXHMqZXhwb3J0XFxzKyg/OlxcKnwoPzpcXHtbXFxzXFx3LF0rXFx9KSlcXHMrZnJvbVxccytbJ1wiXSguKz8pWydcIl0vZ21cbiAgbGV0IHJlRXhwb3J0TWF0Y2g6IFJlZ0V4cEV4ZWNBcnJheSB8IG51bGxcbiAgLy8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub0Fzc2lnbkluRXhwcmVzc2lvbnM6IDxleHBsYW5hdGlvbj5cbiAgd2hpbGUgKChyZUV4cG9ydE1hdGNoID0gcmVFeHBvcnRSZWdleC5leGVjKGNvZGUpKSAhPT0gbnVsbCkge1xuICAgIGltcG9ydHMucHVzaChyZUV4cG9ydE1hdGNoWzFdKVxuICB9XG5cbiAgcmV0dXJuIGltcG9ydHNcbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBQSxZQUFZLGFBQWE7OztBQ0FsQixJQUFNLHFCQUFxQixDQUFDLFNBQTJCO0FBRTVELFFBQU0sY0FDSjtBQUNGLFFBQU0sVUFBb0IsQ0FBQztBQUMzQixNQUFJO0FBR0osVUFBUSxRQUFRLFlBQVksS0FBSyxJQUFJLE9BQU8sTUFBTTtBQUNoRCxZQUFRLEtBQUssTUFBTSxDQUFD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
@@ -16,6 +16,13 @@ export interface WebWorkerConfiguration extends CircuitRunnerConfiguration {
16
16
  */
17
17
  webWorkerUrl?: URL | string
18
18
  webWorkerBlobUrl?: URL | string
19
+ /**
20
+ * Enable fetch proxy to route worker fetch requests through parent thread.
21
+ * Useful when running in restricted environments (like ChatGPT) where
22
+ * worker fetch requests are blocked.
23
+ * Default: false
24
+ */
25
+ enableFetchProxy?: boolean
19
26
  }
20
27
 
21
28
  /**
package/lib/worker.ts CHANGED
@@ -54,7 +54,7 @@ export const createCircuitWebWorker = async (
54
54
  if (!workerBlobUrl) {
55
55
  const cdnUrl = `https://cdn.jsdelivr.net/npm/@tscircuit/eval@${configuration.evalVersion ?? "latest"}/dist/webworker/entrypoint.js`
56
56
 
57
- const workerBlob = await fetch(cdnUrl).then((res) => res.blob())
57
+ const workerBlob = await globalThis.fetch(cdnUrl).then((res) => res.blob())
58
58
  workerBlobUrl = URL.createObjectURL(workerBlob)
59
59
  }
60
60
 
@@ -75,6 +75,45 @@ export const createCircuitWebWorker = async (
75
75
  }
76
76
  rawWorker.addEventListener("message", earlyMessageHandler)
77
77
 
78
+ // Handle fetch requests from the worker
79
+ rawWorker.addEventListener("message", async (event: MessageEvent) => {
80
+ const data = event.data
81
+ if (data?.type !== "worker_fetch") return
82
+
83
+ try {
84
+ const response = await globalThis.fetch(data.input, data.init)
85
+ const body = await response.text()
86
+ rawWorker.postMessage({
87
+ type: "worker_fetch_result",
88
+ requestId: data.requestId,
89
+ success: true,
90
+ response: {
91
+ body,
92
+ status: response.status,
93
+ statusText: response.statusText,
94
+ headers: (() => {
95
+ const obj: Record<string, string> = {}
96
+ response.headers.forEach((value, key) => {
97
+ obj[key] = value
98
+ })
99
+ return obj
100
+ })(),
101
+ },
102
+ })
103
+ } catch (err: any) {
104
+ rawWorker.postMessage({
105
+ type: "worker_fetch_result",
106
+ requestId: data.requestId,
107
+ success: false,
108
+ error: {
109
+ name: err.name,
110
+ message: err.message,
111
+ stack: err.stack,
112
+ },
113
+ })
114
+ }
115
+ })
116
+
78
117
  if (workerInitError) {
79
118
  throw workerInitError
80
119
  }
@@ -83,6 +122,12 @@ export const createCircuitWebWorker = async (
83
122
 
84
123
  rawWorker.removeEventListener("message", earlyMessageHandler)
85
124
 
125
+ // Conditionally override global fetch inside the worker to route through the parent
126
+ // Only enable when explicitly requested via configuration
127
+ if (configuration.enableFetchProxy) {
128
+ rawWorker.postMessage({ type: "override_global_fetch" })
129
+ }
130
+
86
131
  if (configuration.snippetsApiBaseUrl) {
87
132
  await comlinkWorker.setSnippetsApiBaseUrl(configuration.snippetsApiBaseUrl)
88
133
  }
@@ -125,6 +170,7 @@ export const createCircuitWebWorker = async (
125
170
  }
126
171
  },
127
172
  }
173
+ ;(wrapper as any).__rawWorker = rawWorker
128
174
  globalThis.TSCIRCUIT_GLOBAL_CIRCUIT_WORKER = wrapper
129
175
  return wrapper
130
176
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/eval",
3
3
  "main": "dist/lib/index.js",
4
- "version": "0.0.287",
4
+ "version": "0.0.289",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "bun run build:lib && bun run build:webworker && bun run build:blob-url && bun run build:runner && bun run build:worker-wrapper",
@@ -16,6 +16,7 @@
16
16
  "format:check": "biome format .",
17
17
  "test:playwright": "playwright test",
18
18
  "test": "bun test tests",
19
+ "test:validate-matrix": "bun run scripts/validate-test-matrix.js",
19
20
  "copy-core-versions": "bun run scripts/copy-core-versions.ts && bun install --ignore-scripts"
20
21
  },
21
22
  "exports": {
@@ -53,20 +54,20 @@
53
54
  "@biomejs/biome": "^1.8.3",
54
55
  "@playwright/test": "^1.50.1",
55
56
  "@tscircuit/capacity-autorouter": "^0.0.100",
56
- "@tscircuit/checks": "^0.0.68",
57
+ "@tscircuit/checks": "^0.0.71",
57
58
  "@tscircuit/circuit-json-flex": "^0.0.3",
58
59
  "@tscircuit/circuit-json-util": "^0.0.65",
59
- "@tscircuit/core": "^0.0.631",
60
+ "@tscircuit/core": "^0.0.641",
60
61
  "@tscircuit/footprinter": "^0.0.208",
61
62
  "@tscircuit/import-snippet": "^0.0.4",
62
63
  "@tscircuit/infgrid-ijump-astar": "^0.0.33",
63
64
  "@tscircuit/layout": "^0.0.28",
64
65
  "@tscircuit/log-soup": "^1.0.2",
65
- "@tscircuit/matchpack": "^0.0.4",
66
+ "@tscircuit/matchpack": "^0.0.9",
66
67
  "@tscircuit/math-utils": "^0.0.18",
67
68
  "@tscircuit/miniflex": "^0.0.4",
68
69
  "@tscircuit/parts-engine": "^0.0.8",
69
- "@tscircuit/props": "^0.0.286",
70
+ "@tscircuit/props": "^0.0.287",
70
71
  "@tscircuit/schematic-autolayout": "^0.0.6",
71
72
  "@tscircuit/schematic-corpus": "^0.0.110",
72
73
  "@tscircuit/schematic-match-adapt": "^0.0.16",
@@ -81,7 +82,7 @@
81
82
  "bun-match-svg": "0.0.12",
82
83
  "calculate-elbow": "^0.0.9",
83
84
  "chokidar-cli": "^3.0.0",
84
- "circuit-json": "^0.0.228",
85
+ "circuit-json": "^0.0.232",
85
86
  "circuit-json-to-bpc": "^0.0.13",
86
87
  "circuit-json-to-connectivity-map": "^0.0.22",
87
88
  "circuit-json-to-simple-3d": "^0.0.6",
@@ -99,7 +100,8 @@
99
100
  "react-dom": "^19.1.0",
100
101
  "schematic-symbols": "^0.0.180",
101
102
  "ts-expect": "^1.3.0",
102
- "tsup": "^8.2.4"
103
+ "tsup": "^8.2.4",
104
+ "minicssgrid": "^0.0.8"
103
105
  },
104
106
  "peerDependencies": {
105
107
  "typescript": "^5.0.0",
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readdirSync, statSync, readFileSync } from "fs"
4
+ import { join } from "path"
5
+ import { fileURLToPath } from "url"
6
+ import { dirname } from "path"
7
+
8
+ const __filename = fileURLToPath(import.meta.url)
9
+ const __dirname = dirname(__filename)
10
+
11
+ const testsDir = join(__dirname, "..", "tests")
12
+ const workflowFile = join(
13
+ __dirname,
14
+ "..",
15
+ ".github",
16
+ "workflows",
17
+ "bun-test.yml",
18
+ )
19
+
20
+ // Get all directories in tests/ that contain test files
21
+ function getTestDirectories() {
22
+ const entries = readdirSync(testsDir)
23
+ const testDirs = []
24
+
25
+ for (const entry of entries) {
26
+ const fullPath = join(testsDir, entry)
27
+
28
+ // Skip non-directories
29
+ if (!statSync(fullPath).isDirectory()) continue
30
+
31
+ // Skip hidden directories like .claude
32
+ if (entry.startsWith(".")) continue
33
+
34
+ // Check if directory contains test files
35
+ if (hasTestFiles(fullPath)) {
36
+ testDirs.push(entry)
37
+ }
38
+ }
39
+
40
+ return testDirs.sort()
41
+ }
42
+
43
+ // Check if a directory contains test files (recursively)
44
+ function hasTestFiles(dirPath) {
45
+ try {
46
+ const entries = readdirSync(dirPath)
47
+
48
+ for (const entry of entries) {
49
+ const fullPath = join(dirPath, entry)
50
+ const stat = statSync(fullPath)
51
+
52
+ if (
53
+ stat.isFile() &&
54
+ (entry.endsWith(".test.ts") || entry.endsWith(".test.tsx"))
55
+ ) {
56
+ return true
57
+ }
58
+
59
+ if (stat.isDirectory() && hasTestFiles(fullPath)) {
60
+ return true
61
+ }
62
+ }
63
+
64
+ return false
65
+ } catch (error) {
66
+ console.warn(`Warning: Could not read directory ${dirPath}`)
67
+ return false
68
+ }
69
+ }
70
+
71
+ // Extract test directories from workflow file
72
+ function getWorkflowTestDirectories() {
73
+ const workflowContent = readFileSync(workflowFile, "utf8")
74
+
75
+ // Look for the matrix test-dir configuration
76
+ const matrixMatch = workflowContent.match(/test-dir:\s*\[(.*?)\]/s)
77
+
78
+ if (!matrixMatch) {
79
+ throw new Error(
80
+ "Could not find test-dir matrix configuration in workflow file",
81
+ )
82
+ }
83
+
84
+ const matrixContent = matrixMatch[1]
85
+ const dirs = matrixContent
86
+ .split(",")
87
+ .map((dir) => dir.trim().replace(/['"]/g, ""))
88
+ .filter((dir) => dir.length > 0)
89
+ .sort()
90
+
91
+ return dirs
92
+ }
93
+
94
+ function main() {
95
+ console.log("🔍 Validating test matrix configuration...")
96
+
97
+ const actualTestDirs = getTestDirectories()
98
+ const workflowTestDirs = getWorkflowTestDirectories()
99
+
100
+ console.log(
101
+ `Found ${actualTestDirs.length} test directories:`,
102
+ actualTestDirs,
103
+ )
104
+ console.log(
105
+ `Workflow covers ${workflowTestDirs.length} directories:`,
106
+ workflowTestDirs,
107
+ )
108
+
109
+ const missing = actualTestDirs.filter(
110
+ (dir) => !workflowTestDirs.includes(dir),
111
+ )
112
+ const extra = workflowTestDirs.filter((dir) => !actualTestDirs.includes(dir))
113
+
114
+ if (missing.length > 0) {
115
+ console.error(
116
+ "❌ ERROR: The following test directories are NOT covered by the workflow matrix:",
117
+ )
118
+ for (const dir of missing) {
119
+ console.error(` - ${dir}`)
120
+ }
121
+ console.error(
122
+ "\nPlease add these directories to the test-dir matrix in .github/workflows/bun-test.yml",
123
+ )
124
+ }
125
+
126
+ if (extra.length > 0) {
127
+ console.warn(
128
+ "⚠️ WARNING: The following directories in the workflow matrix do not contain test files:",
129
+ )
130
+ for (const dir of extra) {
131
+ console.warn(` - ${dir}`)
132
+ }
133
+ console.warn(
134
+ "\nConsider removing these from the test-dir matrix in .github/workflows/bun-test.yml",
135
+ )
136
+ }
137
+
138
+ if (missing.length === 0 && extra.length === 0) {
139
+ console.log(
140
+ "✅ All test directories are properly covered by the workflow matrix!",
141
+ )
142
+ process.exit(0)
143
+ } else {
144
+ process.exit(1)
145
+ }
146
+ }
147
+
148
+ main()
@@ -3,7 +3,7 @@ import { expect, test } from "bun:test"
3
3
 
4
4
  test("example1-readme-example", async () => {
5
5
  const circuitWebWorker = await createCircuitWebWorker({
6
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
6
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
7
7
  })
8
8
 
9
9
  await circuitWebWorker.executeWithFsMap({
@@ -3,7 +3,7 @@ import { expect, test } from "bun:test"
3
3
 
4
4
  test("virtual filesystem with components", async () => {
5
5
  const circuitWebWorker = await createCircuitWebWorker({
6
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
6
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
7
7
  })
8
8
 
9
9
  await circuitWebWorker.executeWithFsMap({
@@ -1,7 +1,7 @@
1
1
  import { createCircuitWebWorker } from "lib"
2
2
  import { expect, test } from "bun:test"
3
3
  // @ts-ignore
4
- import blobUrl from "dist/blob-url"
4
+ import blobUrl from "../../dist/blob-url"
5
5
 
6
6
  test("example3-encoded-worker-url", async () => {
7
7
  const circuitWebWorker = await createCircuitWebWorker({
@@ -15,7 +15,7 @@ test(
15
15
  "example4-root-child-issue",
16
16
  async () => {
17
17
  const circuitWebWorker = await createCircuitWebWorker({
18
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
18
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
19
19
  })
20
20
 
21
21
  await circuitWebWorker.executeWithFsMap({
@@ -4,7 +4,7 @@ import { createCircuitWebWorker } from "lib/index"
4
4
  // Skipped for flakiness, re-enable when flakiness is solved
5
5
  test.skip("example5-event-recording", async () => {
6
6
  const circuitWebWorker = await createCircuitWebWorker({
7
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
7
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
8
8
  })
9
9
 
10
10
  let eventCount = 0
@@ -3,7 +3,7 @@ import { expect, test } from "bun:test"
3
3
 
4
4
  test("namespace import syntax", async () => {
5
5
  const circuitWebWorker = await createCircuitWebWorker({
6
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
6
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
7
7
  })
8
8
 
9
9
  await circuitWebWorker.executeWithFsMap({
@@ -39,7 +39,7 @@ test("namespace import syntax", async () => {
39
39
 
40
40
  test("combined default and namespace import with fallback", async () => {
41
41
  const circuitWebWorker = await createCircuitWebWorker({
42
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
42
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
43
43
  })
44
44
 
45
45
  await circuitWebWorker.executeWithFsMap({
@@ -3,7 +3,7 @@ import { expect, test } from "bun:test"
3
3
 
4
4
  test("example8-footprinter-to220", async () => {
5
5
  const circuitWebWorker = await createCircuitWebWorker({
6
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
6
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
7
7
  })
8
8
 
9
9
  await circuitWebWorker.execute(`
@@ -3,7 +3,7 @@ import { expect, test } from "bun:test"
3
3
 
4
4
  test("example9-not-defined-component", async () => {
5
5
  const circuitWebWorker = await createCircuitWebWorker({
6
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
6
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
7
7
  })
8
8
 
9
9
  expect(async () => {
@@ -4,7 +4,7 @@ import type { SourceSimpleResistor } from "circuit-json"
4
4
 
5
5
  test("example13-webworker-without-entrypoint", async () => {
6
6
  const circuitWebWorker = await createCircuitWebWorker({
7
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
7
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
8
8
  })
9
9
 
10
10
  try {
@@ -4,7 +4,7 @@ import type { SourceComponentBase } from "circuit-json"
4
4
 
5
5
  test("example16-jlc-parts-engine with entrypoint", async () => {
6
6
  const circuitWebWorker = await createCircuitWebWorker({
7
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
7
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
8
8
  verbose: true,
9
9
  })
10
10
 
@@ -3,7 +3,7 @@ import { expect, test } from "bun:test"
3
3
 
4
4
  test("parse tscircuit.config.js with mainEntrypoint", async () => {
5
5
  const circuitWebWorker = await createCircuitWebWorker({
6
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
6
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
7
7
  })
8
8
 
9
9
  await circuitWebWorker.executeWithFsMap({
@@ -6,7 +6,7 @@ test("circuit-web-worker-events", async () => {
6
6
  const capturedEvents: string[] = []
7
7
 
8
8
  const circuitWebWorker = await createCircuitWebWorker({
9
- webWorkerUrl: new URL("../webworker/entrypoint.ts", import.meta.url),
9
+ webWorkerUrl: new URL("../../webworker/entrypoint.ts", import.meta.url),
10
10
  })
11
11
 
12
12
  await circuitWebWorker.execute(`
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect } from "bun:test"
2
+ import { createCircuitWebWorker } from "lib"
3
+ import { repoFileUrl } from "tests/fixtures/resourcePaths"
4
+
5
+ describe("fetch override", () => {
6
+ it("allows worker to fetch via parent and propagates errors", async () => {
7
+ const originalFetch = globalThis.fetch
8
+ const fakeFetch = async (input: RequestInfo, init?: RequestInit) => {
9
+ if (typeof input === "string" && input.includes("cjs.tscircuit.com")) {
10
+ return new Response("module.exports = { default: 123 };", {
11
+ status: 200,
12
+ })
13
+ }
14
+ throw new Error("fake fail")
15
+ }
16
+ globalThis.fetch = fakeFetch as any
17
+
18
+ const worker = await createCircuitWebWorker({
19
+ webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
20
+ enableFetchProxy: true,
21
+ })
22
+
23
+ const rawWorker: Worker = (worker as any).__rawWorker
24
+ const messages: any[] = []
25
+ rawWorker.addEventListener("message", (event) => {
26
+ if (event.data?.type === "fetch_error") messages.push(event.data)
27
+ })
28
+
29
+ await worker.execute(`
30
+ import val from "@tsci/test.snippet";
31
+ if (val !== 123) { throw new Error("snippet failed"); }
32
+ fetch("https://fail.test").catch(e => {
33
+ postMessage({ type: "fetch_error", name: e.name, message: e.message });
34
+ });
35
+ `)
36
+
37
+ await new Promise((r) => setTimeout(r, 10))
38
+
39
+ expect(messages).toEqual([
40
+ { type: "fetch_error", name: "Error", message: "fake fail" },
41
+ ])
42
+
43
+ await worker.kill()
44
+ globalThis.fetch = originalFetch
45
+ })
46
+ })