@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.
- package/.github/workflows/bun-test.yml +20 -2
- package/dist/blob-url.js +1 -1
- package/dist/eval/index.d.ts +59 -8
- package/dist/eval/index.js +2 -3
- package/dist/lib/index.d.ts +59 -8
- package/dist/lib/index.js +43 -4
- package/dist/webworker/entrypoint.js +353 -350
- package/dist/worker.d.ts +7 -0
- package/dist/worker.js +42 -2
- package/lib/shared/types.ts +7 -0
- package/lib/worker.ts +47 -1
- package/package.json +9 -7
- package/scripts/validate-test-matrix.js +148 -0
- package/tests/{example1-readme-example.test.tsx → examples/example01-readme-example.test.tsx} +1 -1
- package/tests/{example2-multiple-files.test.tsx → examples/example02-multiple-files.test.tsx} +1 -1
- package/tests/{example3-encoded-url.test.tsx → examples/example03-encoded-url.test.tsx} +1 -1
- package/tests/{example4-root-child-issue.test.tsx → examples/example04-root-child-issue.test.tsx} +1 -1
- package/tests/{example5-event-recording.test.tsx → examples/example05-event-recording.test.tsx} +1 -1
- package/tests/{example7-import-default-and-namespace.test.tsx → examples/example07-import-default-and-namespace.test.tsx} +2 -2
- package/tests/{example8-footprinter-to220.test.tsx → examples/example08-footprinter-to220.test.tsx} +1 -1
- package/tests/{example9-not-defined-component.test.tsx → examples/example09-not-defined-component.test.tsx} +1 -1
- package/tests/{example13-webworker-without-entrypoint.test.tsx → examples/example13-webworker-without-entrypoint.test.tsx} +1 -1
- package/tests/{example16-parts-engine.test.tsx → examples/example16-parts-engine.test.tsx} +1 -1
- package/tests/{example17-parse-tscircuit-config.test.tsx → examples/example17-parse-tscircuit-config.test.tsx} +1 -1
- package/tests/{circuit-event-forwarding.test.tsx → features/circuit-event-forwarding.test.tsx} +1 -1
- package/tests/features/fetch-proxy/fetch-override.test.ts +46 -0
- package/tests/features/fetch-proxy/fetch-proxy-validation.test.ts +95 -0
- package/tests/{kill.test.ts → features/kill.test.ts} +5 -3
- package/tests/{manual-edits.test.tsx → features/manual-edits.test.tsx} +2 -2
- package/tests/fixtures/resourcePaths.ts +3 -0
- package/webworker/entrypoint.ts +7 -2
- package/webworker/fetchProxy.ts +83 -0
- package/webworker/import-snippet.ts +2 -4
- /package/tests/{example6-dynamic-load-blob-url.test.tsx → examples/example06-dynamic-load-blob-url.test.tsx} +0 -0
- /package/tests/{example10-run-tscircuit-code.test.tsx → examples/example10-run-tscircuit-code.test.tsx} +0 -0
- /package/tests/{example11-flexible-import-extensions.test.tsx → examples/example11-flexible-import-extensions.test.tsx} +0 -0
- /package/tests/{example12-import-from-subdirectory.test.tsx → examples/example12-import-from-subdirectory.test.tsx} +0 -0
- /package/tests/{example14-run-tscircuit-module.test.tsx → examples/example14-run-tscircuit-module.test.tsx} +0 -0
- /package/tests/{example15-run-tscircuit-module-with-props.test.tsx → examples/example15-run-tscircuit-module-with-props.test.tsx} +0 -0
- /package/tests/{parent-directory-import.test.tsx → features/parent-directory-import.test.tsx} +0 -0
- /package/tests/{platform-config.test.tsx → features/platform-config.test.tsx} +0 -0
- /package/tests/{prioritize-default-export.test.tsx → features/prioritize-default-export.test.tsx} +0 -0
- /package/tests/{group-wrapper.test.tsx → repros/group-wrapper.test.tsx} +0 -0
- /package/tests/{nine-keyboard-default-export.test.tsx → repros/nine-keyboard-default-export.test.tsx} +0 -0
- /package/tests/{get-imports-from-code.test.tsx → util-fns/get-imports-from-code.test.tsx} +0 -0
- /package/tests/{getPossibleEntrypointComponentPaths.test.ts → util-fns/getPossibleEntrypointComponentPaths.test.ts} +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test"
|
|
2
|
+
import { createCircuitWebWorker } from "lib"
|
|
3
|
+
import { repoFileUrl } from "tests/fixtures/resourcePaths"
|
|
4
|
+
|
|
5
|
+
describe("fetch proxy validation", () => {
|
|
6
|
+
it("should NOT proxy fetch requests when enableFetchProxy is false (default)", async () => {
|
|
7
|
+
const worker = await createCircuitWebWorker({
|
|
8
|
+
webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
|
|
9
|
+
// enableFetchProxy not set, should default to false
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const rawWorker: Worker = (worker as any).__rawWorker
|
|
13
|
+
const messages: any[] = []
|
|
14
|
+
rawWorker.addEventListener("message", (event) => {
|
|
15
|
+
if (event.data?.type === "worker_fetch") messages.push(event.data)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
await worker.execute(`
|
|
19
|
+
// Test that fetch calls are NOT proxied when enableFetchProxy is false
|
|
20
|
+
fetch("https://example.com/test")
|
|
21
|
+
.catch(() => {}); // Ignore errors, we just want to see if it's proxied
|
|
22
|
+
`)
|
|
23
|
+
|
|
24
|
+
await new Promise((r) => setTimeout(r, 100))
|
|
25
|
+
|
|
26
|
+
// Should NOT have received any worker_fetch messages
|
|
27
|
+
expect(messages.length).toBe(0)
|
|
28
|
+
|
|
29
|
+
await worker.kill()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("should proxy fetch requests when enableFetchProxy is true", async () => {
|
|
33
|
+
const worker = await createCircuitWebWorker({
|
|
34
|
+
webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
|
|
35
|
+
enableFetchProxy: true,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const rawWorker: Worker = (worker as any).__rawWorker
|
|
39
|
+
const messages: any[] = []
|
|
40
|
+
rawWorker.addEventListener("message", (event) => {
|
|
41
|
+
if (event.data?.type === "worker_fetch") messages.push(event.data)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
await worker.execute(`
|
|
45
|
+
// Test that fetch calls are proxied when enableFetchProxy is true
|
|
46
|
+
fetch("https://example.com/test")
|
|
47
|
+
.catch(() => {}); // Ignore errors, we just want to see if it's proxied
|
|
48
|
+
`)
|
|
49
|
+
|
|
50
|
+
await new Promise((r) => setTimeout(r, 100))
|
|
51
|
+
|
|
52
|
+
// Should have received a worker_fetch message indicating the proxy is working
|
|
53
|
+
expect(messages.length).toBeGreaterThan(0)
|
|
54
|
+
expect(messages[0].type).toBe("worker_fetch")
|
|
55
|
+
expect(messages[0].input).toBe("https://example.com/test")
|
|
56
|
+
|
|
57
|
+
await worker.kill()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("should handle fetch errors properly through proxy when enabled", async () => {
|
|
61
|
+
// This test verifies that the fetch proxy correctly handles and forwards errors
|
|
62
|
+
const originalFetch = globalThis.fetch
|
|
63
|
+
const fakeFetch = async () => {
|
|
64
|
+
throw new Error("Network error")
|
|
65
|
+
}
|
|
66
|
+
globalThis.fetch = fakeFetch as any
|
|
67
|
+
|
|
68
|
+
const worker = await createCircuitWebWorker({
|
|
69
|
+
webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
|
|
70
|
+
enableFetchProxy: true,
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const rawWorker: Worker = (worker as any).__rawWorker
|
|
74
|
+
const messages: any[] = []
|
|
75
|
+
rawWorker.addEventListener("message", (event) => {
|
|
76
|
+
if (event.data?.type === "fetch_error") messages.push(event.data)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
await worker.execute(`
|
|
80
|
+
fetch("https://example.com/test")
|
|
81
|
+
.catch(e => {
|
|
82
|
+
postMessage({ type: "fetch_error", name: e.name, message: e.message });
|
|
83
|
+
});
|
|
84
|
+
`)
|
|
85
|
+
|
|
86
|
+
await new Promise((r) => setTimeout(r, 100))
|
|
87
|
+
|
|
88
|
+
expect(messages).toEqual([
|
|
89
|
+
{ type: "fetch_error", name: "Error", message: "Network error" },
|
|
90
|
+
])
|
|
91
|
+
|
|
92
|
+
await worker.kill()
|
|
93
|
+
globalThis.fetch = originalFetch
|
|
94
|
+
})
|
|
95
|
+
})
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect } from "bun:test"
|
|
2
|
-
import { createCircuitWebWorker } from "
|
|
2
|
+
import { createCircuitWebWorker } from "lib"
|
|
3
3
|
|
|
4
4
|
describe("kill method", () => {
|
|
5
5
|
it("should immediately terminate the worker", async () => {
|
|
6
6
|
const worker = await createCircuitWebWorker({
|
|
7
|
-
webWorkerUrl: new URL(
|
|
8
|
-
.
|
|
7
|
+
webWorkerUrl: new URL(
|
|
8
|
+
"../../dist/webworker/entrypoint.js",
|
|
9
|
+
import.meta.url,
|
|
10
|
+
).href,
|
|
9
11
|
})
|
|
10
12
|
|
|
11
13
|
// Ensure worker is running
|
|
@@ -59,7 +59,7 @@ const example2 = {
|
|
|
59
59
|
|
|
60
60
|
test("example1: Manual edits in entrypoint.tsx file", async () => {
|
|
61
61
|
const circuitWebWorker = await createCircuitWebWorker({
|
|
62
|
-
webWorkerUrl: new URL("
|
|
62
|
+
webWorkerUrl: new URL("../../webworker/index.ts", import.meta.url),
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
await circuitWebWorker.executeWithFsMap({
|
|
@@ -89,7 +89,7 @@ test("example1: Manual edits in entrypoint.tsx file", async () => {
|
|
|
89
89
|
|
|
90
90
|
test("example2: Manual edits in manual-edits.json file", async () => {
|
|
91
91
|
const circuitWebWorker = await createCircuitWebWorker({
|
|
92
|
-
webWorkerUrl: new URL("
|
|
92
|
+
webWorkerUrl: new URL("../../webworker/index.ts", import.meta.url),
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
await circuitWebWorker.executeWithFsMap({
|
package/webworker/entrypoint.ts
CHANGED
|
@@ -11,11 +11,13 @@ import {
|
|
|
11
11
|
type ExecutionContext,
|
|
12
12
|
} from "./execution-context"
|
|
13
13
|
import { importEvalPath } from "./import-eval-path"
|
|
14
|
-
import { normalizeFsMap } from "
|
|
14
|
+
import { normalizeFsMap } from "lib/runner/normalizeFsMap"
|
|
15
15
|
import type { RootCircuit } from "@tscircuit/core"
|
|
16
16
|
import { setupDefaultEntrypointIfNeeded } from "lib/runner/setupDefaultEntrypointIfNeeded"
|
|
17
|
+
import { setupFetchProxy } from "./fetchProxy"
|
|
17
18
|
|
|
18
19
|
globalThis.React = React
|
|
20
|
+
setupFetchProxy()
|
|
19
21
|
|
|
20
22
|
let executionContext: ExecutionContext | null = null
|
|
21
23
|
|
|
@@ -124,7 +126,10 @@ const webWorkerApi = {
|
|
|
124
126
|
for (const event in eventListeners) {
|
|
125
127
|
for (const listener of eventListeners[event]) {
|
|
126
128
|
const circuit = executionContext.circuit as unknown as {
|
|
127
|
-
removeListener?: (
|
|
129
|
+
removeListener?: (
|
|
130
|
+
event: string,
|
|
131
|
+
listener: (...args: any[]) => void,
|
|
132
|
+
) => void
|
|
128
133
|
}
|
|
129
134
|
if (typeof circuit.removeListener === "function") {
|
|
130
135
|
circuit.removeListener(event, listener)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export const setupFetchProxy = () => {
|
|
2
|
+
const pendingRequests = new Map<
|
|
3
|
+
number,
|
|
4
|
+
{ resolve: (value: Response) => void; reject: (reason: any) => void }
|
|
5
|
+
>()
|
|
6
|
+
let requestCounter = 0
|
|
7
|
+
|
|
8
|
+
function fetchProxy(
|
|
9
|
+
input: RequestInfo | URL,
|
|
10
|
+
init?: RequestInit,
|
|
11
|
+
): Promise<Response> {
|
|
12
|
+
const requestId = ++requestCounter
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
pendingRequests.set(requestId, { resolve, reject })
|
|
15
|
+
let url: string
|
|
16
|
+
let requestInit: any = init ? { ...init } : {}
|
|
17
|
+
|
|
18
|
+
if (typeof input === "string" || input instanceof URL) {
|
|
19
|
+
url = input.toString()
|
|
20
|
+
} else {
|
|
21
|
+
url = input.url
|
|
22
|
+
requestInit = {
|
|
23
|
+
...requestInit,
|
|
24
|
+
method: input.method,
|
|
25
|
+
headers: (() => {
|
|
26
|
+
const obj: Record<string, string> = {}
|
|
27
|
+
input.headers.forEach((value, key) => {
|
|
28
|
+
obj[key] = value
|
|
29
|
+
})
|
|
30
|
+
return obj
|
|
31
|
+
})(),
|
|
32
|
+
body: input.bodyUsed ? undefined : (input as any).body,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (requestInit.headers instanceof Headers) {
|
|
37
|
+
const obj: Record<string, string> = {}
|
|
38
|
+
requestInit.headers.forEach((value: string, key: string) => {
|
|
39
|
+
obj[key] = value
|
|
40
|
+
})
|
|
41
|
+
requestInit.headers = obj
|
|
42
|
+
}
|
|
43
|
+
;(globalThis as any).postMessage({
|
|
44
|
+
type: "worker_fetch",
|
|
45
|
+
requestId,
|
|
46
|
+
input: url,
|
|
47
|
+
init: requestInit,
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function handleMessage(event: MessageEvent) {
|
|
53
|
+
const data = event.data
|
|
54
|
+
if (!data) return
|
|
55
|
+
|
|
56
|
+
if (data.type === "override_global_fetch") {
|
|
57
|
+
;(globalThis as any).fetch = fetchProxy
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (data.type === "worker_fetch_result") {
|
|
62
|
+
const handlers = pendingRequests.get(data.requestId)
|
|
63
|
+
if (!handlers) return
|
|
64
|
+
pendingRequests.delete(data.requestId)
|
|
65
|
+
|
|
66
|
+
if (data.success) {
|
|
67
|
+
const resp = new Response(data.response.body, {
|
|
68
|
+
status: data.response.status,
|
|
69
|
+
statusText: data.response.statusText,
|
|
70
|
+
headers: data.response.headers,
|
|
71
|
+
})
|
|
72
|
+
handlers.resolve(resp)
|
|
73
|
+
} else {
|
|
74
|
+
const err = new Error(data.error.message)
|
|
75
|
+
if (data.error.name) err.name = data.error.name
|
|
76
|
+
if (data.error.stack) err.stack = data.error.stack
|
|
77
|
+
handlers.reject(err)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
globalThis.addEventListener("message", handleMessage)
|
|
83
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { evalCompiledJs } from "./eval-compiled-js"
|
|
2
2
|
import type { ExecutionContext } from "./execution-context"
|
|
3
|
-
import * as Babel from "@babel/standalone"
|
|
4
|
-
import { importLocalFile } from "./import-local-file"
|
|
5
|
-
import { importEvalPath } from "./import-eval-path"
|
|
6
3
|
|
|
7
4
|
export async function importSnippet(
|
|
8
5
|
importName: string,
|
|
@@ -12,7 +9,8 @@ export async function importSnippet(
|
|
|
12
9
|
const { preSuppliedImports } = ctx
|
|
13
10
|
const fullSnippetName = importName.replace("@tsci/", "").replace(".", "/")
|
|
14
11
|
|
|
15
|
-
const { cjs, error } = await
|
|
12
|
+
const { cjs, error } = await globalThis
|
|
13
|
+
.fetch(`${ctx.cjsRegistryUrl}/${fullSnippetName}`)
|
|
16
14
|
.then(async (res) => ({ cjs: await res.text(), error: null }))
|
|
17
15
|
.catch((e) => ({ error: e, cjs: null }))
|
|
18
16
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/tests/{parent-directory-import.test.tsx → features/parent-directory-import.test.tsx}
RENAMED
|
File without changes
|
|
File without changes
|
/package/tests/{prioritize-default-export.test.tsx → features/prioritize-default-export.test.tsx}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|