veryfront 0.1.755 → 0.1.756
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/esm/cli/auth/callback-server.d.ts +4 -1
- package/esm/cli/auth/callback-server.d.ts.map +1 -1
- package/esm/cli/auth/callback-server.js +52 -13
- package/esm/cli/auth/index.d.ts +1 -1
- package/esm/cli/auth/index.d.ts.map +1 -1
- package/esm/cli/auth/index.js +1 -1
- package/esm/cli/auth/login.d.ts +2 -0
- package/esm/cli/auth/login.d.ts.map +1 -1
- package/esm/cli/auth/login.js +18 -6
- package/esm/cli/commands/demo/demo.d.ts.map +1 -1
- package/esm/cli/commands/demo/demo.js +6 -7
- package/esm/deno.js +1 -1
- package/esm/src/agent/runtime/index.d.ts +3 -96
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +21 -341
- package/esm/src/agent/runtime/model-capabilities.d.ts +3 -0
- package/esm/src/agent/runtime/model-capabilities.d.ts.map +1 -0
- package/esm/src/agent/runtime/model-capabilities.js +18 -0
- package/esm/src/agent/runtime/runtime-tool-config.d.ts +14 -0
- package/esm/src/agent/runtime/runtime-tool-config.d.ts.map +1 -0
- package/esm/src/agent/runtime/runtime-tool-config.js +37 -0
- package/esm/src/agent/runtime/skill-policy-enforcement.d.ts +16 -0
- package/esm/src/agent/runtime/skill-policy-enforcement.d.ts.map +1 -0
- package/esm/src/agent/runtime/skill-policy-enforcement.js +55 -0
- package/esm/src/agent/runtime/tool-result-continuation.d.ts +34 -0
- package/esm/src/agent/runtime/tool-result-continuation.d.ts.map +1 -0
- package/esm/src/agent/runtime/tool-result-continuation.js +194 -0
- package/esm/src/agent/schemas/agent.schema.d.ts +7 -0
- package/esm/src/agent/schemas/agent.schema.d.ts.map +1 -1
- package/esm/src/agent/schemas/agent.schema.js +9 -3
- package/esm/src/agent/schemas/index.d.ts +1 -1
- package/esm/src/agent/schemas/index.d.ts.map +1 -1
- package/esm/src/agent/schemas/index.js +1 -1
- package/esm/src/modules/server/module-server.d.ts.map +1 -1
- package/esm/src/modules/server/module-server.js +31 -9
- package/esm/src/modules/server/rate-limiter.d.ts +3 -2
- package/esm/src/modules/server/rate-limiter.d.ts.map +1 -1
- package/esm/src/platform/adapters/base.d.ts +24 -3
- package/esm/src/platform/adapters/base.d.ts.map +1 -1
- package/esm/src/platform/adapters/base.js +15 -1
- package/esm/src/platform/adapters/runtime/bun/websocket-adapter.d.ts +2 -0
- package/esm/src/platform/adapters/runtime/bun/websocket-adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/bun/websocket-adapter.js +33 -1
- package/esm/src/platform/adapters/runtime/node/websocket-adapter.d.ts +1 -1
- package/esm/src/platform/adapters/runtime/node/websocket-adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/node/websocket-adapter.js +3 -10
- package/esm/src/proxy/handler.d.ts.map +1 -1
- package/esm/src/proxy/handler.js +25 -116
- package/esm/src/proxy/local-project-resolver.d.ts +18 -0
- package/esm/src/proxy/local-project-resolver.d.ts.map +1 -0
- package/esm/src/proxy/local-project-resolver.js +63 -0
- package/esm/src/proxy/proxy-token-resolution.d.ts +37 -0
- package/esm/src/proxy/proxy-token-resolution.d.ts.map +1 -0
- package/esm/src/proxy/proxy-token-resolution.js +51 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts +10 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +23 -158
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts +20 -0
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.js +80 -0
- package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.d.ts +59 -0
- package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.js +97 -0
- package/esm/src/routing/api/handler.d.ts +2 -1
- package/esm/src/routing/api/handler.d.ts.map +1 -1
- package/esm/src/routing/api/handler.js +2 -1
- package/esm/src/routing/api/route-executor.d.ts +3 -0
- package/esm/src/routing/api/route-executor.d.ts.map +1 -1
- package/esm/src/routing/api/route-executor.js +28 -0
- package/esm/src/runtime/runtime-bridge.js +2 -2
- package/esm/src/security/http/base-handler.d.ts +3 -2
- package/esm/src/security/http/base-handler.d.ts.map +1 -1
- package/esm/src/security/http/base-handler.js +1 -1
- package/esm/src/security/sandbox/project-worker.d.ts +1 -0
- package/esm/src/security/sandbox/project-worker.d.ts.map +1 -1
- package/esm/src/security/sandbox/project-worker.js +17 -1
- package/esm/src/security/sandbox/worker-egress-guard.d.ts +15 -0
- package/esm/src/security/sandbox/worker-egress-guard.d.ts.map +1 -0
- package/esm/src/security/sandbox/worker-egress-guard.js +201 -0
- package/esm/src/security/sandbox/worker-permissions.d.ts +6 -2
- package/esm/src/security/sandbox/worker-permissions.d.ts.map +1 -1
- package/esm/src/security/sandbox/worker-permissions.js +34 -3
- package/esm/src/security/sandbox/worker-pool.d.ts +1 -1
- package/esm/src/security/sandbox/worker-pool.d.ts.map +1 -1
- package/esm/src/security/sandbox/worker-pool.js +35 -9
- package/esm/src/server/handlers/preview/hmr-client-manager.d.ts +3 -2
- package/esm/src/server/handlers/preview/hmr-client-manager.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.js +4 -1
- package/esm/src/server/handlers/request/api/api-handler-wrapper.js +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.d.ts +32 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.d.ts.map +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.js +27 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.js +23 -3
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +15 -15
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker network egress guard.
|
|
3
|
+
*
|
|
4
|
+
* Project workers need outbound network access for public API calls, but user
|
|
5
|
+
* code must not reach host-internal networks or cloud metadata endpoints.
|
|
6
|
+
*
|
|
7
|
+
* @module security/sandbox/worker-egress-guard
|
|
8
|
+
*/
|
|
9
|
+
import * as dntShim from "../../../_dnt.shims.js";
|
|
10
|
+
export const WORKER_INTERNAL_EGRESS_OVERRIDE_ENV = "VERYFRONT_WORKER_ALLOW_INTERNAL_EGRESS";
|
|
11
|
+
export class WorkerEgressBlockedError extends Error {
|
|
12
|
+
name = "WorkerEgressBlockedError";
|
|
13
|
+
}
|
|
14
|
+
const guardInstalled = Symbol.for("veryfront.workerEgressGuardInstalled");
|
|
15
|
+
const guardedFetch = Symbol.for("veryfront.workerEgressGuard.fetch");
|
|
16
|
+
const guardedConnect = Symbol.for("veryfront.workerEgressGuard.connect");
|
|
17
|
+
const guardedConnectTls = Symbol.for("veryfront.workerEgressGuard.connectTls");
|
|
18
|
+
function isObject(value) {
|
|
19
|
+
return typeof value === "object" && value !== null;
|
|
20
|
+
}
|
|
21
|
+
export function isInternalEgressOverrideEnabled(value) {
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return false;
|
|
24
|
+
switch (value.trim().toLowerCase()) {
|
|
25
|
+
case "1":
|
|
26
|
+
case "true":
|
|
27
|
+
case "yes":
|
|
28
|
+
case "on":
|
|
29
|
+
return true;
|
|
30
|
+
default:
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function stripIpv6Brackets(value) {
|
|
35
|
+
return value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
36
|
+
}
|
|
37
|
+
function stripIpv6Zone(value) {
|
|
38
|
+
const zoneIndex = value.indexOf("%");
|
|
39
|
+
return zoneIndex === -1 ? value : value.slice(0, zoneIndex);
|
|
40
|
+
}
|
|
41
|
+
function parseIpv4(value) {
|
|
42
|
+
const parts = value.split(".");
|
|
43
|
+
if (parts.length !== 4)
|
|
44
|
+
return null;
|
|
45
|
+
const octets = [];
|
|
46
|
+
for (const part of parts) {
|
|
47
|
+
if (!/^\d{1,3}$/.test(part))
|
|
48
|
+
return null;
|
|
49
|
+
const octet = Number(part);
|
|
50
|
+
if (!Number.isInteger(octet) || octet < 0 || octet > 255)
|
|
51
|
+
return null;
|
|
52
|
+
octets.push(octet);
|
|
53
|
+
}
|
|
54
|
+
return octets;
|
|
55
|
+
}
|
|
56
|
+
function isPrivateIpv4(octets) {
|
|
57
|
+
const [a = -1, b = -1] = octets;
|
|
58
|
+
return (a === 10 ||
|
|
59
|
+
a === 127 ||
|
|
60
|
+
(a === 169 && b === 254) ||
|
|
61
|
+
(a === 172 && b >= 16 && b <= 31) ||
|
|
62
|
+
(a === 192 && b === 168) ||
|
|
63
|
+
a === 0);
|
|
64
|
+
}
|
|
65
|
+
function isInternalIpv6(value) {
|
|
66
|
+
const normalized = stripIpv6Zone(stripIpv6Brackets(value)).toLowerCase();
|
|
67
|
+
if (normalized === "::" || normalized === "::1")
|
|
68
|
+
return true;
|
|
69
|
+
const mappedIpv4 = normalized.match(/(?:::ffff:)(\d{1,3}(?:\.\d{1,3}){3})$/);
|
|
70
|
+
if (mappedIpv4?.[1]) {
|
|
71
|
+
const octets = parseIpv4(mappedIpv4[1]);
|
|
72
|
+
return octets !== null && isPrivateIpv4(octets);
|
|
73
|
+
}
|
|
74
|
+
const firstHextetText = normalized.split(":", 1)[0] ?? "";
|
|
75
|
+
if (!/^[0-9a-f]{1,4}$/.test(firstHextetText))
|
|
76
|
+
return false;
|
|
77
|
+
const firstHextet = Number.parseInt(firstHextetText, 16);
|
|
78
|
+
// fe80::/10 link-local, fc00::/7 unique local.
|
|
79
|
+
return (firstHextet & 0xffc0) === 0xfe80 || (firstHextet & 0xfe00) === 0xfc00;
|
|
80
|
+
}
|
|
81
|
+
export function isInternalEgressIp(address) {
|
|
82
|
+
const host = stripIpv6Zone(stripIpv6Brackets(address.trim().toLowerCase()));
|
|
83
|
+
const ipv4 = parseIpv4(host);
|
|
84
|
+
if (ipv4)
|
|
85
|
+
return isPrivateIpv4(ipv4);
|
|
86
|
+
return host.includes(":") && isInternalIpv6(host);
|
|
87
|
+
}
|
|
88
|
+
function isIpLiteral(address) {
|
|
89
|
+
const host = stripIpv6Zone(stripIpv6Brackets(address.trim().toLowerCase()));
|
|
90
|
+
return parseIpv4(host) !== null || host.includes(":");
|
|
91
|
+
}
|
|
92
|
+
function isLocalhostName(hostname) {
|
|
93
|
+
const normalized = hostname.trim().toLowerCase();
|
|
94
|
+
return normalized === "localhost" || normalized.endsWith(".localhost");
|
|
95
|
+
}
|
|
96
|
+
async function defaultResolveHost(hostname) {
|
|
97
|
+
const results = [];
|
|
98
|
+
const resolver = dntShim.Deno.resolveDns;
|
|
99
|
+
for (const recordType of ["A", "AAAA"]) {
|
|
100
|
+
try {
|
|
101
|
+
results.push(...await resolver(hostname, recordType));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// A host may legitimately have only one address family.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return results;
|
|
108
|
+
}
|
|
109
|
+
function getUrlHostname(input) {
|
|
110
|
+
const url = input instanceof URL
|
|
111
|
+
? input
|
|
112
|
+
: input instanceof Request
|
|
113
|
+
? new URL(input.url)
|
|
114
|
+
: new URL(String(input));
|
|
115
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" && url.protocol !== "ws:" &&
|
|
116
|
+
url.protocol !== "wss:") {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return stripIpv6Brackets(url.hostname);
|
|
120
|
+
}
|
|
121
|
+
export async function assertWorkerEgressAllowed(target, options = {}) {
|
|
122
|
+
if (options.allowInternalEgress)
|
|
123
|
+
return;
|
|
124
|
+
const hostname = getUrlHostname(target);
|
|
125
|
+
if (!hostname)
|
|
126
|
+
return;
|
|
127
|
+
await assertWorkerHostEgressAllowed(hostname, options);
|
|
128
|
+
}
|
|
129
|
+
export async function assertWorkerHostEgressAllowed(hostname, options = {}) {
|
|
130
|
+
if (options.allowInternalEgress)
|
|
131
|
+
return;
|
|
132
|
+
const host = stripIpv6Brackets(hostname.trim().toLowerCase());
|
|
133
|
+
if (isLocalhostName(host) || isInternalEgressIp(host)) {
|
|
134
|
+
throw new WorkerEgressBlockedError(`Worker network egress blocked for internal host: ${hostname}`);
|
|
135
|
+
}
|
|
136
|
+
if (isIpLiteral(host))
|
|
137
|
+
return;
|
|
138
|
+
const resolveHost = options.resolveHost ?? defaultResolveHost;
|
|
139
|
+
const addresses = await resolveHost(host);
|
|
140
|
+
if (addresses.length === 0) {
|
|
141
|
+
throw new WorkerEgressBlockedError(`Worker network egress blocked: unable to resolve host ${hostname}`);
|
|
142
|
+
}
|
|
143
|
+
for (const address of addresses) {
|
|
144
|
+
if (isInternalEgressIp(address)) {
|
|
145
|
+
throw new WorkerEgressBlockedError(`Worker network egress blocked for host ${hostname} resolved to internal address ${address}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function getConnectHostname(options) {
|
|
150
|
+
if (!isObject(options))
|
|
151
|
+
return null;
|
|
152
|
+
const hostname = options.hostname;
|
|
153
|
+
return typeof hostname === "string" ? hostname : null;
|
|
154
|
+
}
|
|
155
|
+
function getAllowInternalEgress() {
|
|
156
|
+
try {
|
|
157
|
+
return isInternalEgressOverrideEnabled(dntShim.Deno.env.get(WORKER_INTERNAL_EGRESS_OVERRIDE_ENV));
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export function installWorkerEgressGuard(options = {}) {
|
|
164
|
+
const globalRecord = dntShim.dntGlobalThis;
|
|
165
|
+
if (globalRecord[guardInstalled])
|
|
166
|
+
return;
|
|
167
|
+
const baseOptions = {
|
|
168
|
+
...options,
|
|
169
|
+
allowInternalEgress: options.allowInternalEgress ?? getAllowInternalEgress(),
|
|
170
|
+
};
|
|
171
|
+
const originalFetch = globalThis.fetch.bind(dntShim.dntGlobalThis);
|
|
172
|
+
const fetchWrapper = async (input, init) => {
|
|
173
|
+
await assertWorkerEgressAllowed(input, baseOptions);
|
|
174
|
+
return await originalFetch(input, init);
|
|
175
|
+
};
|
|
176
|
+
Object.defineProperty(fetchWrapper, guardedFetch, { value: true });
|
|
177
|
+
globalThis.fetch = fetchWrapper;
|
|
178
|
+
if (typeof dntShim.Deno.connect === "function") {
|
|
179
|
+
const originalConnect = dntShim.Deno.connect.bind(dntShim.Deno);
|
|
180
|
+
const connectWrapper = async (options) => {
|
|
181
|
+
const hostname = getConnectHostname(options);
|
|
182
|
+
if (hostname)
|
|
183
|
+
await assertWorkerHostEgressAllowed(hostname, baseOptions);
|
|
184
|
+
return await originalConnect(options);
|
|
185
|
+
};
|
|
186
|
+
Object.defineProperty(connectWrapper, guardedConnect, { value: true });
|
|
187
|
+
dntShim.Deno.connect = connectWrapper;
|
|
188
|
+
}
|
|
189
|
+
if (typeof dntShim.Deno.connectTls === "function") {
|
|
190
|
+
const originalConnectTls = dntShim.Deno.connectTls.bind(dntShim.Deno);
|
|
191
|
+
const connectTlsWrapper = async (options) => {
|
|
192
|
+
const hostname = getConnectHostname(options);
|
|
193
|
+
if (hostname)
|
|
194
|
+
await assertWorkerHostEgressAllowed(hostname, baseOptions);
|
|
195
|
+
return await originalConnectTls(options);
|
|
196
|
+
};
|
|
197
|
+
Object.defineProperty(connectTlsWrapper, guardedConnectTls, { value: true });
|
|
198
|
+
dntShim.Deno.connectTls = connectTlsWrapper;
|
|
199
|
+
}
|
|
200
|
+
globalRecord[guardInstalled] = true;
|
|
201
|
+
}
|
|
@@ -6,7 +6,7 @@ export interface WorkerPermissions {
|
|
|
6
6
|
read: string[] | boolean;
|
|
7
7
|
write: boolean;
|
|
8
8
|
net: boolean;
|
|
9
|
-
env: boolean;
|
|
9
|
+
env: string[] | boolean;
|
|
10
10
|
run: boolean;
|
|
11
11
|
ffi: boolean;
|
|
12
12
|
sys: boolean;
|
|
@@ -16,14 +16,18 @@ interface WorkerPermissionOptions {
|
|
|
16
16
|
isCompiledBinary?: boolean;
|
|
17
17
|
/** Override for tests that need deterministic compiled-binary support paths. */
|
|
18
18
|
compiledReadPaths?: string[];
|
|
19
|
+
/** Project-configured env keys that route code may read inside the worker. */
|
|
20
|
+
projectEnvKeys?: Iterable<string | undefined>;
|
|
19
21
|
}
|
|
22
|
+
export declare const FRAMEWORK_WORKER_ENV_ALLOWLIST: readonly ["NODE_ENV", "DENO_ENV", "VERYFRONT_ENV", "LOG_LEVEL", "LOG_FORMAT", "NO_COLOR", "FORCE_COLOR", "CI", "VERYFRONT_WORKER_ALLOW_INTERNAL_EGRESS"];
|
|
23
|
+
export declare function buildWorkerEnvAllowlist(projectEnvKeys?: Iterable<string | undefined>): string[];
|
|
20
24
|
/**
|
|
21
25
|
* Build scoped permissions for a project worker.
|
|
22
26
|
*
|
|
23
27
|
* - read: restricted to the project temp dir (transformed modules) and cache dirs
|
|
24
28
|
* - write: denied (workers produce output via postMessage, not filesystem)
|
|
25
29
|
* - net: allowed (data fetchers and API routes may call external APIs)
|
|
26
|
-
* - env:
|
|
30
|
+
* - env: restricted to framework keys and the project's configured env keys
|
|
27
31
|
* - run: denied (no subprocess spawning from user code)
|
|
28
32
|
* - ffi: denied (no native code from user code)
|
|
29
33
|
* - sys: denied (no system info access from user code)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-permissions.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-permissions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker-permissions.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-permissions.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd;AAED,UAAU,uBAAuB;IAC/B,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,8EAA8E;IAC9E,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC/C;AAED,eAAO,MAAM,8BAA8B,0JAUjC,CAAC;AAoCX,wBAAgB,uBAAuB,CACrC,cAAc,GAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAM,GAChD,MAAM,EAAE,CAKV;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,GAAE,uBAA4B,GACpC,iBAAiB,CA4BnB"}
|
|
@@ -10,6 +10,18 @@ import * as dntShim from "../../../_dnt.shims.js";
|
|
|
10
10
|
import { getFrameworkRootFromMeta } from "../../platform/compat/vfs-paths.js";
|
|
11
11
|
import { getHostEnv } from "../../platform/compat/process.js";
|
|
12
12
|
import { getCacheBaseDir, getHttpBundleCacheDir, getMdxEsmCacheDir, } from "../../utils/cache-dir.js";
|
|
13
|
+
import { WORKER_INTERNAL_EGRESS_OVERRIDE_ENV } from "./worker-egress-guard.js";
|
|
14
|
+
export const FRAMEWORK_WORKER_ENV_ALLOWLIST = [
|
|
15
|
+
"NODE_ENV",
|
|
16
|
+
"DENO_ENV",
|
|
17
|
+
"VERYFRONT_ENV",
|
|
18
|
+
"LOG_LEVEL",
|
|
19
|
+
"LOG_FORMAT",
|
|
20
|
+
"NO_COLOR",
|
|
21
|
+
"FORCE_COLOR",
|
|
22
|
+
"CI",
|
|
23
|
+
WORKER_INTERNAL_EGRESS_OVERRIDE_ENV,
|
|
24
|
+
];
|
|
13
25
|
// Cache compiled binary check — Deno.execPath() is a syscall that never changes at runtime
|
|
14
26
|
const _isCompiledBinary = (() => {
|
|
15
27
|
try {
|
|
@@ -35,6 +47,24 @@ function normalizeReadPaths(paths) {
|
|
|
35
47
|
}
|
|
36
48
|
return [...unique];
|
|
37
49
|
}
|
|
50
|
+
function normalizeEnvKeys(keys) {
|
|
51
|
+
const unique = new Set();
|
|
52
|
+
for (const key of keys) {
|
|
53
|
+
if (!key)
|
|
54
|
+
continue;
|
|
55
|
+
const trimmed = key.trim();
|
|
56
|
+
if (!trimmed)
|
|
57
|
+
continue;
|
|
58
|
+
unique.add(trimmed);
|
|
59
|
+
}
|
|
60
|
+
return [...unique];
|
|
61
|
+
}
|
|
62
|
+
export function buildWorkerEnvAllowlist(projectEnvKeys = []) {
|
|
63
|
+
return normalizeEnvKeys([
|
|
64
|
+
...FRAMEWORK_WORKER_ENV_ALLOWLIST,
|
|
65
|
+
...projectEnvKeys,
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
38
68
|
function getDefaultCompiledReadPaths() {
|
|
39
69
|
return normalizeReadPaths([
|
|
40
70
|
getFrameworkRootFromMeta(globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url),
|
|
@@ -50,7 +80,7 @@ function getDefaultCompiledReadPaths() {
|
|
|
50
80
|
* - read: restricted to the project temp dir (transformed modules) and cache dirs
|
|
51
81
|
* - write: denied (workers produce output via postMessage, not filesystem)
|
|
52
82
|
* - net: allowed (data fetchers and API routes may call external APIs)
|
|
53
|
-
* - env:
|
|
83
|
+
* - env: restricted to framework keys and the project's configured env keys
|
|
54
84
|
* - run: denied (no subprocess spawning from user code)
|
|
55
85
|
* - ffi: denied (no native code from user code)
|
|
56
86
|
* - sys: denied (no system info access from user code)
|
|
@@ -58,6 +88,7 @@ function getDefaultCompiledReadPaths() {
|
|
|
58
88
|
export function buildWorkerPermissions(readPaths, options = {}) {
|
|
59
89
|
const isCompiledBinary = options.isCompiledBinary ?? _isCompiledBinary;
|
|
60
90
|
const normalizedReadPaths = normalizeReadPaths(readPaths);
|
|
91
|
+
const env = buildWorkerEnvAllowlist(options.projectEnvKeys);
|
|
61
92
|
if (isCompiledBinary) {
|
|
62
93
|
const compiledReadPaths = options.compiledReadPaths ?? getDefaultCompiledReadPaths();
|
|
63
94
|
const scopedReadPaths = normalizeReadPaths([...normalizedReadPaths, ...compiledReadPaths]);
|
|
@@ -65,7 +96,7 @@ export function buildWorkerPermissions(readPaths, options = {}) {
|
|
|
65
96
|
read: scopedReadPaths.length > 0 ? scopedReadPaths : false,
|
|
66
97
|
write: false,
|
|
67
98
|
net: true,
|
|
68
|
-
env
|
|
99
|
+
env,
|
|
69
100
|
run: false,
|
|
70
101
|
ffi: false,
|
|
71
102
|
sys: false,
|
|
@@ -75,7 +106,7 @@ export function buildWorkerPermissions(readPaths, options = {}) {
|
|
|
75
106
|
read: normalizedReadPaths.length > 0 ? normalizedReadPaths : false,
|
|
76
107
|
write: false,
|
|
77
108
|
net: true,
|
|
78
|
-
env
|
|
109
|
+
env,
|
|
79
110
|
run: false,
|
|
80
111
|
ffi: false,
|
|
81
112
|
sys: false,
|
|
@@ -10,7 +10,7 @@ export declare class WorkerPool {
|
|
|
10
10
|
/**
|
|
11
11
|
* Get or create a worker for the given project.
|
|
12
12
|
*/
|
|
13
|
-
getOrCreateWorker(projectId: string, readPaths: string[]): ProjectWorker;
|
|
13
|
+
getOrCreateWorker(projectId: string, readPaths: string[], projectEnvKeys?: Iterable<string | undefined>): ProjectWorker;
|
|
14
14
|
/**
|
|
15
15
|
* Execute a request in a project worker. Convenience method that
|
|
16
16
|
* combines getOrCreateWorker + execute.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-pool.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-pool.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA4BzF,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,MAAM,CAAmB;IAEjC,OAAO,CAAC,eAAe,CAAqD;IAC5E,OAAO,CAAC,mBAAmB,CAAqD;gBAEpE,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM;IAMlD;;OAEG;IACH,iBAAiB,CACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,EACnB,cAAc,GAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAM,GAChD,aAAa;IAmDhB;;;OAGG;IACH,OAAO,CACL,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,cAAc,CAAC;IAkE1B;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAUpC;;OAEG;IACH,QAAQ,IAAI;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE,MAAM,CAAC;YACf,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,OAAO,CAAC;YACpB,MAAM,EAAE,MAAM,CAAC;YACf,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ;IA4BD;;OAEG;IACH,UAAU,IAAI;QACZ,uCAAuC;QACvC,cAAc,EAAE,MAAM,CAAC;QACvB,oDAAoD;QACpD,kBAAkB,EAAE,MAAM,CAAC;QAC3B,kDAAkD;QAClD,sBAAsB,EAAE,MAAM,CAAC;QAC/B,qDAAqD;QACrD,WAAW,EAAE,MAAM,CAAC;QACpB,kEAAkE;QAClE,cAAc,EAAE,MAAM,CAAC;KACxB;IAoBD;;OAEG;IACH,QAAQ,IAAI,IAAI;IAgBhB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,aAAa;YA4BP,WAAW;IAmBzB;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;CA8BjC;AAqBD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAGlD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAG/C;AAKD,wBAAgB,aAAa,IAAI,UAAU,CAiB1C;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,IAAI,IAAI,CAO1C"}
|
|
@@ -13,9 +13,24 @@ import { getEnvBoolean, getEnvNumber, unrefTimer } from "../../platform/compat/p
|
|
|
13
13
|
import { withSpan } from "../../observability/tracing/otlp-setup.js";
|
|
14
14
|
import { SECURITY_VIOLATION } from "../../errors/index.js";
|
|
15
15
|
import { ProjectWorker } from "./project-worker.js";
|
|
16
|
-
import { buildWorkerPermissions } from "./worker-permissions.js";
|
|
16
|
+
import { buildWorkerEnvAllowlist, buildWorkerPermissions } from "./worker-permissions.js";
|
|
17
17
|
import { DEFAULT_WORKER_POOL_CONFIG } from "./worker-types.js";
|
|
18
18
|
const logger = serverLogger.component("worker-pool");
|
|
19
|
+
function extractProjectEnvKeys(request) {
|
|
20
|
+
if (!("projectEnv" in request) || !request.projectEnv)
|
|
21
|
+
return [];
|
|
22
|
+
return Object.keys(request.projectEnv);
|
|
23
|
+
}
|
|
24
|
+
function normalizeProjectEnvKeys(keys) {
|
|
25
|
+
const frameworkEnvKeyCount = buildWorkerEnvAllowlist([]).length;
|
|
26
|
+
return buildWorkerEnvAllowlist(keys).slice(frameworkEnvKeyCount);
|
|
27
|
+
}
|
|
28
|
+
function sameEnvKeySet(left, right) {
|
|
29
|
+
if (left.length !== right.length)
|
|
30
|
+
return false;
|
|
31
|
+
const rightSet = new Set(right);
|
|
32
|
+
return left.every((key) => rightSet.has(key));
|
|
33
|
+
}
|
|
19
34
|
export class WorkerPool {
|
|
20
35
|
pool = new Map();
|
|
21
36
|
recycling = new Set();
|
|
@@ -30,20 +45,29 @@ export class WorkerPool {
|
|
|
30
45
|
/**
|
|
31
46
|
* Get or create a worker for the given project.
|
|
32
47
|
*/
|
|
33
|
-
getOrCreateWorker(projectId, readPaths) {
|
|
48
|
+
getOrCreateWorker(projectId, readPaths, projectEnvKeys = []) {
|
|
49
|
+
const normalizedProjectEnvKeys = normalizeProjectEnvKeys(projectEnvKeys);
|
|
34
50
|
const existing = this.pool.get(projectId);
|
|
35
51
|
if (existing && existing.worker.status !== "crashed" && existing.worker.status !== "terminated") {
|
|
36
|
-
existing.
|
|
37
|
-
|
|
52
|
+
if (!sameEnvKeySet(existing.projectEnvKeys, normalizedProjectEnvKeys)) {
|
|
53
|
+
existing.worker.terminate();
|
|
54
|
+
this.pool.delete(projectId);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
existing.lastAccessedAt = Date.now();
|
|
58
|
+
return existing.worker;
|
|
59
|
+
}
|
|
38
60
|
}
|
|
39
61
|
// If an existing entry is crashed/terminated, clean it up
|
|
40
|
-
if (existing) {
|
|
62
|
+
if (existing && this.pool.has(projectId)) {
|
|
41
63
|
existing.worker.terminate();
|
|
42
64
|
this.pool.delete(projectId);
|
|
43
65
|
}
|
|
44
66
|
// Evict LRU if at capacity
|
|
45
67
|
this.evictIfNeeded();
|
|
46
|
-
const permissions = buildWorkerPermissions(readPaths
|
|
68
|
+
const permissions = buildWorkerPermissions(readPaths, {
|
|
69
|
+
projectEnvKeys: normalizedProjectEnvKeys,
|
|
70
|
+
});
|
|
47
71
|
const worker = new ProjectWorker({
|
|
48
72
|
projectId,
|
|
49
73
|
permissions,
|
|
@@ -55,6 +79,7 @@ export class WorkerPool {
|
|
|
55
79
|
worker,
|
|
56
80
|
lastAccessedAt: now,
|
|
57
81
|
createdAt: now,
|
|
82
|
+
projectEnvKeys: normalizedProjectEnvKeys,
|
|
58
83
|
});
|
|
59
84
|
logger.debug("Worker created", {
|
|
60
85
|
projectId,
|
|
@@ -78,7 +103,8 @@ export class WorkerPool {
|
|
|
78
103
|
}
|
|
79
104
|
}
|
|
80
105
|
return withSpan("workerPool.execute", async () => {
|
|
81
|
-
const
|
|
106
|
+
const projectEnvKeys = extractProjectEnvKeys(request);
|
|
107
|
+
const worker = this.getOrCreateWorker(projectId, readPaths, projectEnvKeys);
|
|
82
108
|
// Check if worker should be recycled (request count or age)
|
|
83
109
|
const entry = this.pool.get(projectId);
|
|
84
110
|
const shouldRecycle = worker.requestCount >= this.config.maxRequestsPerWorker ||
|
|
@@ -100,11 +126,11 @@ export class WorkerPool {
|
|
|
100
126
|
const result = worker.execute(request);
|
|
101
127
|
void result.then(() => {
|
|
102
128
|
this.evictWorker(projectId);
|
|
103
|
-
this.getOrCreateWorker(projectId, readPaths);
|
|
129
|
+
this.getOrCreateWorker(projectId, readPaths, projectEnvKeys);
|
|
104
130
|
this.recycling.delete(projectId);
|
|
105
131
|
}, () => {
|
|
106
132
|
this.evictWorker(projectId);
|
|
107
|
-
this.getOrCreateWorker(projectId, readPaths);
|
|
133
|
+
this.getOrCreateWorker(projectId, readPaths, projectEnvKeys);
|
|
108
134
|
this.recycling.delete(projectId);
|
|
109
135
|
});
|
|
110
136
|
return result;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { WebSocketConnection } from "../../../platform/adapters/base.js";
|
|
1
2
|
/** Client metadata for observability */
|
|
2
3
|
export interface HMRClientInfo {
|
|
3
4
|
id: string;
|
|
4
|
-
socket:
|
|
5
|
+
socket: WebSocketConnection;
|
|
5
6
|
connectedAt: number;
|
|
6
7
|
projectSlug?: string;
|
|
7
8
|
userAgent?: string;
|
|
@@ -24,7 +25,7 @@ export declare function getClientDetails(): HMRClientDetail[];
|
|
|
24
25
|
* Get all open WebSocket connections, optionally filtered by projectSlug.
|
|
25
26
|
* This replaces the old exported `clientSockets` Set that drifted out of sync.
|
|
26
27
|
*/
|
|
27
|
-
export declare function getOpenSockets(projectSlug?: string):
|
|
28
|
+
export declare function getOpenSockets(projectSlug?: string): WebSocketConnection[];
|
|
28
29
|
export declare function clearAll(): void;
|
|
29
30
|
export {};
|
|
30
31
|
//# sourceMappingURL=hmr-client-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr-client-manager.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr-client-manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hmr-client-manager.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr-client-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAI9E,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,mBAAmB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,yEAAyE;AACzE,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AASD,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAEnD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYnD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAErE;AAED,wBAAgB,gBAAgB,IAAI,eAAe,EAAE,CASpD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAQ1E;AAED,wBAAgB,QAAQ,IAAI,IAAI,CAS/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAuBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAuBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAS7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IAsCnB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA4IvE;;;;;OAKG;YACW,wBAAwB;IAuCtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,+BAA+B,IAAI,MAAM,IAAI;IAWpD,MAAM,CAAC,QAAQ,IAAI,IAAI;CAaxB"}
|
|
@@ -18,6 +18,9 @@ import { getHostEnv } from "../../../platform/compat/process.js";
|
|
|
18
18
|
const logger = serverLogger.component("hmr-handler");
|
|
19
19
|
// Priority between auth (0) and high (100)
|
|
20
20
|
const PRIORITY_HMR = HandlerPriority.EARLY;
|
|
21
|
+
function getMessageEventData(event) {
|
|
22
|
+
return "data" in event ? event.data : undefined;
|
|
23
|
+
}
|
|
21
24
|
export class HMRHandler extends BaseHandler {
|
|
22
25
|
static rateLimiter = new RateLimiter(HMR_MAX_MESSAGES_PER_MINUTE);
|
|
23
26
|
static reloadUnsubscribe = null;
|
|
@@ -149,7 +152,7 @@ export class HMRHandler extends BaseHandler {
|
|
|
149
152
|
socket.addEventListener("message", (event) => {
|
|
150
153
|
handleHmrClientMessage({
|
|
151
154
|
socket,
|
|
152
|
-
data: event
|
|
155
|
+
data: getMessageEventData(event),
|
|
153
156
|
rateLimiter: HMRHandler.rateLimiter,
|
|
154
157
|
onActivity: () => {
|
|
155
158
|
const client = getClient(clientId);
|
|
@@ -55,7 +55,7 @@ export class ApiHandlerWrapper extends BaseHandler {
|
|
|
55
55
|
// Must run within runWithContext so VFS and registry scope are correct.
|
|
56
56
|
await ensureProjectDiscovery(ctx);
|
|
57
57
|
const api = await getApiHandler(ctx);
|
|
58
|
-
const apiRes = await api.handle(req);
|
|
58
|
+
const apiRes = await api.handle(req, ctx);
|
|
59
59
|
if (!apiRes) {
|
|
60
60
|
this.logDebug("[API-Wrapper] API handler returned null, continuing to next handler", { pathname }, ctx);
|
|
61
61
|
return this.continue();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unresolved module HTTP fallback phase for the MDX ESM module fetcher.
|
|
3
|
+
*
|
|
4
|
+
* @module transforms/mdx/esm-module-loader/module-fetcher/http-fallback
|
|
5
|
+
*/
|
|
6
|
+
import type { RuntimeAdapter } from "../../../../platform/adapters/base.js";
|
|
7
|
+
import type { Logger } from "../../../../utils/logger/logger.js";
|
|
8
|
+
import { fetchModuleViaHTTP } from "./http-fetcher.js";
|
|
9
|
+
import { cacheModule } from "./module-cache.js";
|
|
10
|
+
type FetchModuleViaHttpFn = typeof fetchModuleViaHTTP;
|
|
11
|
+
type CacheLocalModuleFn = typeof cacheModule;
|
|
12
|
+
export interface ResolveUnresolvedModuleViaHttpFallbackInput {
|
|
13
|
+
normalizedPath: string;
|
|
14
|
+
parentModulePath?: string;
|
|
15
|
+
adapter: RuntimeAdapter;
|
|
16
|
+
fetchAndCacheModule: (path: string, parent?: string) => Promise<string | null>;
|
|
17
|
+
log: Logger;
|
|
18
|
+
projectSlug: string;
|
|
19
|
+
isLocalProject?: boolean;
|
|
20
|
+
strictMissingModules?: boolean;
|
|
21
|
+
esmCacheDir: string;
|
|
22
|
+
pathCache: Map<string, string>;
|
|
23
|
+
reactVersion?: string;
|
|
24
|
+
fetchViaHttp?: FetchModuleViaHttpFn;
|
|
25
|
+
cacheLocalModule?: CacheLocalModuleFn;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve an unresolved filesystem module through the local HTTP fallback.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveUnresolvedModuleViaHttpFallback(input: ResolveUnresolvedModuleViaHttpFallbackInput): Promise<string | null>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=http-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-fallback.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,KAAK,oBAAoB,GAAG,OAAO,kBAAkB,CAAC;AACtD,KAAK,kBAAkB,GAAG,OAAO,WAAW,CAAC;AAE7C,MAAM,WAAW,2CAA2C;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,cAAc,CAAC;IACxB,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;CACvC;AAED;;GAEG;AACH,wBAAsB,sCAAsC,CAC1D,KAAK,EAAE,2CAA2C,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unresolved module HTTP fallback phase for the MDX ESM module fetcher.
|
|
3
|
+
*
|
|
4
|
+
* @module transforms/mdx/esm-module-loader/module-fetcher/http-fallback
|
|
5
|
+
*/
|
|
6
|
+
import { buildMissingModuleError } from "../missing-module.js";
|
|
7
|
+
import { fetchModuleViaHTTP } from "./http-fetcher.js";
|
|
8
|
+
import { cacheModule } from "./module-cache.js";
|
|
9
|
+
/**
|
|
10
|
+
* Resolve an unresolved filesystem module through the local HTTP fallback.
|
|
11
|
+
*/
|
|
12
|
+
export async function resolveUnresolvedModuleViaHttpFallback(input) {
|
|
13
|
+
const fetchViaHttp = input.fetchViaHttp ?? fetchModuleViaHTTP;
|
|
14
|
+
const cacheLocalModule = input.cacheLocalModule ?? cacheModule;
|
|
15
|
+
const moduleCode = await fetchViaHttp(input.normalizedPath, input.adapter, input.fetchAndCacheModule, input.log, input.projectSlug, input.isLocalProject);
|
|
16
|
+
if (moduleCode) {
|
|
17
|
+
return await cacheLocalModule(input.normalizedPath, moduleCode, input.esmCacheDir, input.pathCache, input.log, input.reactVersion);
|
|
18
|
+
}
|
|
19
|
+
if (input.strictMissingModules ?? true) {
|
|
20
|
+
throw buildMissingModuleError({
|
|
21
|
+
modulePath: input.normalizedPath,
|
|
22
|
+
importer: input.parentModulePath,
|
|
23
|
+
projectSlug: input.projectSlug,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2CH;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgB5D;AAwCD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0D7F"}
|
|
@@ -5,23 +5,43 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { dirname, join, resolve } from "../../../../platform/compat/path/index.js";
|
|
7
7
|
import { FRAMEWORK_ROOT } from "../constants.js";
|
|
8
|
-
import {
|
|
8
|
+
import { DEFAULT_REACT_VERSION, veryfrontStrategy, } from "../../../import-rewriter/index.js";
|
|
9
9
|
import { getLocalFs } from "../cache/index.js";
|
|
10
10
|
import { findStaticImportFromSpans, findStaticSideEffectImportSpans, replaceSourceSpans, } from "../utils/source-spans.js";
|
|
11
|
+
const MODULE_FETCHER_VERYFRONT_CONTEXT = {
|
|
12
|
+
filePath: "",
|
|
13
|
+
projectDir: "",
|
|
14
|
+
projectId: "",
|
|
15
|
+
target: "ssr",
|
|
16
|
+
dev: false,
|
|
17
|
+
reactVersion: DEFAULT_REACT_VERSION,
|
|
18
|
+
};
|
|
19
|
+
function rewriteVeryfrontModuleSpecifier(specifier) {
|
|
20
|
+
const result = veryfrontStrategy.rewrite({
|
|
21
|
+
specifier,
|
|
22
|
+
isDynamic: false,
|
|
23
|
+
start: 0,
|
|
24
|
+
end: specifier.length,
|
|
25
|
+
statementStart: 0,
|
|
26
|
+
statementEnd: 0,
|
|
27
|
+
raw: {},
|
|
28
|
+
}, MODULE_FETCHER_VERYFRONT_CONTEXT);
|
|
29
|
+
return result.specifier;
|
|
30
|
+
}
|
|
11
31
|
/**
|
|
12
32
|
* Rewrite veryfront/* imports to /_vf_modules/_veryfront/ paths for MDX module loading.
|
|
13
33
|
* Uses deno.json exports/imports as the source of truth and appends ?ssr=true.
|
|
14
34
|
*/
|
|
15
35
|
export function rewriteVeryfrontImports(code) {
|
|
16
36
|
const replacements = findStaticImportFromSpans(code, (specifier) => specifier.startsWith("veryfront/") ? specifier : null).flatMap(({ original, path, start, end }) => {
|
|
17
|
-
const mapped =
|
|
37
|
+
const mapped = rewriteVeryfrontModuleSpecifier(path);
|
|
18
38
|
if (!mapped)
|
|
19
39
|
return [];
|
|
20
40
|
return [{
|
|
21
41
|
start,
|
|
22
42
|
end,
|
|
23
43
|
expected: original,
|
|
24
|
-
replacement: `from "${mapped}
|
|
44
|
+
replacement: `from "${mapped}"`,
|
|
25
45
|
}];
|
|
26
46
|
});
|
|
27
47
|
return replaceSourceSpans(code, replacements);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAcxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAS9B;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAOtD;AAED;;GAEG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,SAAS,EAAE,MAAM;CAI9B;AAcD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,oBAAoB,EAC7B,gBAAgB,CAAC,EAAE,MAAM,EACzB,OAAO,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwFxB;AA8ID;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;IACR,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GACA,oBAAoB,CAUtB"}
|