veryfront 0.1.1113 → 0.1.1115
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/commands/deploy/command.d.ts +3 -0
- package/esm/cli/commands/deploy/command.d.ts.map +1 -1
- package/esm/cli/commands/deploy/command.js +4 -4
- package/esm/cli/commands/up/command.d.ts +3 -0
- package/esm/cli/commands/up/command.d.ts.map +1 -1
- package/esm/cli/commands/up/command.js +4 -2
- package/esm/cli/skills/loader.d.ts +4 -4
- package/esm/cli/skills/loader.d.ts.map +1 -1
- package/esm/cli/skills/loader.js +6 -6
- package/esm/deno.js +1 -1
- package/esm/src/agent/project/agent-runtime.d.ts +1 -1
- package/esm/src/agent/project/agent-runtime.d.ts.map +1 -1
- package/esm/src/agent/project/agent-runtime.js +2 -1
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +4 -8
- package/esm/src/data/server-data-fetcher.d.ts.map +1 -1
- package/esm/src/data/server-data-fetcher.js +5 -1
- package/esm/src/discovery/import-rewriter.d.ts +0 -6
- package/esm/src/discovery/import-rewriter.d.ts.map +1 -1
- package/esm/src/discovery/import-rewriter.js +79 -47
- package/esm/src/html/hydration-script-builder/templates/router.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.js +87 -24
- package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/pipeline.js +26 -8
- package/esm/src/rendering/script-page-handling.js +1 -1
- package/esm/src/routing/api/module-loader/external-import-rewriter.js +1 -1
- package/esm/src/sandbox/lazy-sandbox.d.ts +5 -3
- package/esm/src/sandbox/lazy-sandbox.d.ts.map +1 -1
- package/esm/src/sandbox/lazy-sandbox.js +116 -51
- package/esm/src/sandbox/proxy-routes.d.ts +3 -0
- package/esm/src/sandbox/proxy-routes.d.ts.map +1 -0
- package/esm/src/sandbox/proxy-routes.js +28 -0
- package/esm/src/sandbox/sandbox.d.ts.map +1 -1
- package/esm/src/sandbox/sandbox.js +43 -30
- package/esm/src/server/handlers/request/module/page-data-endpoint-handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/module/page-data-endpoint-handler.js +6 -3
- package/esm/src/transforms/npm-import-rewrites.d.ts +3 -3
- package/esm/src/transforms/npm-import-rewrites.d.ts.map +1 -1
- package/esm/src/transforms/npm-import-rewrites.js +29 -14
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -5
|
@@ -2,6 +2,7 @@ import { REQUEST_ERROR } from "../errors/index.js";
|
|
|
2
2
|
import { getHostEnv } from "../platform/compat/process.js";
|
|
3
3
|
import { logger } from "../utils/index.js";
|
|
4
4
|
import { resolveSandboxApiUrl, resolveSandboxAuthToken } from "./config.js";
|
|
5
|
+
import { readSandboxFileContent, sandboxSessionRoute } from "./proxy-routes.js";
|
|
5
6
|
const DEFAULT_STARTUP_TIMEOUT_MS = 180_000;
|
|
6
7
|
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
7
8
|
const DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
@@ -39,6 +40,9 @@ export function resolveDefaultSandboxRuntimeEndpoint(input) {
|
|
|
39
40
|
}
|
|
40
41
|
return `http://sandbox.veryfront-sandbox-${shortId}.svc.cluster.local`;
|
|
41
42
|
}
|
|
43
|
+
function normalizeDataPlaneBaseUrl(url) {
|
|
44
|
+
return url.trim().replace(/\/+$/, "");
|
|
45
|
+
}
|
|
42
46
|
/** Lazily provisions sandbox sessions and keeps them alive while in use. */
|
|
43
47
|
export class LazySandbox {
|
|
44
48
|
apiUrl;
|
|
@@ -64,7 +68,7 @@ export class LazySandbox {
|
|
|
64
68
|
heartbeatPromise = null;
|
|
65
69
|
heartbeatTimer = null;
|
|
66
70
|
lastHeartbeatAt = 0;
|
|
67
|
-
|
|
71
|
+
activeBackgroundCommands = new Map();
|
|
68
72
|
constructor(options = {}) {
|
|
69
73
|
this.apiUrl = resolveSandboxApiUrl(options);
|
|
70
74
|
this.authToken = resolveSandboxAuthToken(options);
|
|
@@ -141,36 +145,48 @@ export class LazySandbox {
|
|
|
141
145
|
const reader = res.body.getReader();
|
|
142
146
|
const decoder = new TextDecoder();
|
|
143
147
|
let buffer = "";
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
let completed = false;
|
|
149
|
+
try {
|
|
150
|
+
while (true) {
|
|
151
|
+
const { done, value } = await reader.read();
|
|
152
|
+
if (done) {
|
|
153
|
+
completed = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
buffer += decoder.decode(value, { stream: true });
|
|
157
|
+
const lines = buffer.split("\n");
|
|
158
|
+
buffer = lines.pop() ?? "";
|
|
159
|
+
for (const line of lines) {
|
|
160
|
+
if (!line.trim())
|
|
161
|
+
continue;
|
|
162
|
+
yield JSON.parse(line);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
buffer += decoder.decode();
|
|
166
|
+
if (buffer.trim()) {
|
|
167
|
+
yield JSON.parse(buffer);
|
|
155
168
|
}
|
|
156
169
|
}
|
|
157
|
-
|
|
158
|
-
|
|
170
|
+
finally {
|
|
171
|
+
if (!completed) {
|
|
172
|
+
await reader.cancel().catch(() => { });
|
|
173
|
+
}
|
|
174
|
+
reader.releaseLock();
|
|
159
175
|
}
|
|
160
176
|
}
|
|
161
177
|
async readFile(path) {
|
|
162
178
|
await this.touchSession();
|
|
163
|
-
const res = await this.fetchControl(`${this.
|
|
179
|
+
const res = await this.fetchControl(`${this.resolveDataPlaneRoute().baseUrl}/file?path=${encodeURIComponent(path)}`, {
|
|
164
180
|
headers: this.authHeaders(),
|
|
165
181
|
});
|
|
166
182
|
if (!res.ok) {
|
|
167
183
|
throw REQUEST_ERROR.create({ detail: `Read file failed: ${res.status} ${await res.text()}` });
|
|
168
184
|
}
|
|
169
|
-
return await res
|
|
185
|
+
return await readSandboxFileContent(res);
|
|
170
186
|
}
|
|
171
187
|
async writeFiles(files) {
|
|
172
188
|
await this.touchSession();
|
|
173
|
-
const res = await this.fetchControl(`${this.
|
|
189
|
+
const res = await this.fetchControl(`${this.resolveDataPlaneRoute().baseUrl}/files`, {
|
|
174
190
|
method: "POST",
|
|
175
191
|
headers: this.jsonHeaders(),
|
|
176
192
|
body: JSON.stringify({ files }),
|
|
@@ -183,8 +199,9 @@ export class LazySandbox {
|
|
|
183
199
|
}
|
|
184
200
|
async startBackgroundCommand(command, options) {
|
|
185
201
|
await this.touchSession();
|
|
186
|
-
const
|
|
187
|
-
const
|
|
202
|
+
const route = this.resolveDataPlaneRoute();
|
|
203
|
+
const commandsUrl = backgroundCommandsUrl(route);
|
|
204
|
+
const res = await this.fetchControl(commandsUrl, {
|
|
188
205
|
method: "POST",
|
|
189
206
|
headers: this.jsonHeaders(),
|
|
190
207
|
body: JSON.stringify({ command, ...this.resolveExecOptions(options) }),
|
|
@@ -195,12 +212,15 @@ export class LazySandbox {
|
|
|
195
212
|
});
|
|
196
213
|
}
|
|
197
214
|
const backgroundCommand = mapBackgroundCommand(await res.json());
|
|
198
|
-
this.updateTrackedBackgroundCommand(backgroundCommand,
|
|
215
|
+
this.updateTrackedBackgroundCommand(backgroundCommand, {
|
|
216
|
+
commandsUrl,
|
|
217
|
+
routeKind: route.kind,
|
|
218
|
+
});
|
|
199
219
|
return backgroundCommand;
|
|
200
220
|
}
|
|
201
221
|
async getBackgroundCommand(commandId) {
|
|
202
|
-
const
|
|
203
|
-
const res = await this.fetchControl(`${
|
|
222
|
+
const route = await this.resolveBackgroundCommandRoute(commandId);
|
|
223
|
+
const res = await this.fetchControl(`${route.commandsUrl}/${encodeURIComponent(commandId)}`, {
|
|
204
224
|
headers: this.authHeaders(),
|
|
205
225
|
});
|
|
206
226
|
if (!res.ok) {
|
|
@@ -209,12 +229,12 @@ export class LazySandbox {
|
|
|
209
229
|
});
|
|
210
230
|
}
|
|
211
231
|
const backgroundCommand = mapBackgroundCommand(await res.json());
|
|
212
|
-
this.updateTrackedBackgroundCommand(backgroundCommand,
|
|
232
|
+
this.updateTrackedBackgroundCommand(backgroundCommand, route);
|
|
213
233
|
return backgroundCommand;
|
|
214
234
|
}
|
|
215
235
|
async getBackgroundCommandOutput(commandId) {
|
|
216
|
-
const
|
|
217
|
-
const res = await this.fetchControl(`${
|
|
236
|
+
const route = await this.resolveBackgroundCommandRoute(commandId);
|
|
237
|
+
const res = await this.fetchControl(`${route.commandsUrl}/${encodeURIComponent(commandId)}/output`, {
|
|
218
238
|
headers: this.authHeaders(),
|
|
219
239
|
});
|
|
220
240
|
if (!res.ok) {
|
|
@@ -230,12 +250,12 @@ export class LazySandbox {
|
|
|
230
250
|
stdoutTruncated: json.stdout_truncated,
|
|
231
251
|
stderrTruncated: json.stderr_truncated,
|
|
232
252
|
};
|
|
233
|
-
this.updateTrackedBackgroundCommand(output,
|
|
253
|
+
this.updateTrackedBackgroundCommand(output, route);
|
|
234
254
|
return output;
|
|
235
255
|
}
|
|
236
256
|
async listBackgroundCommands() {
|
|
237
257
|
await this.ensure();
|
|
238
|
-
const res = await this.fetchControl(
|
|
258
|
+
const res = await this.fetchControl(backgroundCommandsUrl(this.resolveDataPlaneRoute()), {
|
|
239
259
|
headers: this.authHeaders(),
|
|
240
260
|
});
|
|
241
261
|
if (!res.ok) {
|
|
@@ -248,8 +268,8 @@ export class LazySandbox {
|
|
|
248
268
|
return commands.map((command) => mapBackgroundCommand(command));
|
|
249
269
|
}
|
|
250
270
|
async cancelBackgroundCommand(commandId) {
|
|
251
|
-
const
|
|
252
|
-
const res = await this.fetchControl(`${
|
|
271
|
+
const route = await this.resolveBackgroundCommandRoute(commandId);
|
|
272
|
+
const res = await this.fetchControl(`${route.commandsUrl}/${encodeURIComponent(commandId)}/cancel`, {
|
|
253
273
|
method: "POST",
|
|
254
274
|
headers: this.authHeaders(),
|
|
255
275
|
});
|
|
@@ -259,7 +279,7 @@ export class LazySandbox {
|
|
|
259
279
|
});
|
|
260
280
|
}
|
|
261
281
|
const backgroundCommand = mapBackgroundCommand(await res.json());
|
|
262
|
-
this.updateTrackedBackgroundCommand(backgroundCommand,
|
|
282
|
+
this.updateTrackedBackgroundCommand(backgroundCommand, route);
|
|
263
283
|
return backgroundCommand;
|
|
264
284
|
}
|
|
265
285
|
async heartbeat(force = false) {
|
|
@@ -282,7 +302,7 @@ export class LazySandbox {
|
|
|
282
302
|
});
|
|
283
303
|
if (!res.ok) {
|
|
284
304
|
if (this.sessionId === currentSessionId) {
|
|
285
|
-
if (this.
|
|
305
|
+
if (this.activeBackgroundCommands.size === 0) {
|
|
286
306
|
await this.deleteSession(currentSessionId);
|
|
287
307
|
this.resetSessionState(currentSessionId);
|
|
288
308
|
}
|
|
@@ -402,7 +422,9 @@ export class LazySandbox {
|
|
|
402
422
|
const readySession = session.status === "running"
|
|
403
423
|
? session
|
|
404
424
|
: await this.waitForReadySession(session.id);
|
|
405
|
-
|
|
425
|
+
if (this.shouldUseInternalDataPlane(readySession.endpoint, readySession.id)) {
|
|
426
|
+
await this.waitForRuntimeDataPlaneReady(readySession);
|
|
427
|
+
}
|
|
406
428
|
return readySession.endpoint;
|
|
407
429
|
}
|
|
408
430
|
async attachExistingSession(sessionId) {
|
|
@@ -497,7 +519,7 @@ export class LazySandbox {
|
|
|
497
519
|
heartbeatFailureCount = 0;
|
|
498
520
|
static HEARTBEAT_WARN_AFTER_FAILURES = 3;
|
|
499
521
|
startHeartbeatLoop() {
|
|
500
|
-
if (!this.sessionId || this.heartbeatTimer || this.
|
|
522
|
+
if (!this.sessionId || this.heartbeatTimer || this.hasActiveInternalBackgroundCommand()) {
|
|
501
523
|
return;
|
|
502
524
|
}
|
|
503
525
|
this.heartbeatTimer = setInterval(() => {
|
|
@@ -536,7 +558,7 @@ export class LazySandbox {
|
|
|
536
558
|
resetSessionState(sessionId) {
|
|
537
559
|
if (!sessionId || this.sessionId === sessionId) {
|
|
538
560
|
this.stopHeartbeatLoop();
|
|
539
|
-
this.
|
|
561
|
+
this.activeBackgroundCommands.clear();
|
|
540
562
|
this.endpoint = null;
|
|
541
563
|
this.sessionId = null;
|
|
542
564
|
this.sessionProjectId = null;
|
|
@@ -548,33 +570,47 @@ export class LazySandbox {
|
|
|
548
570
|
const projectReference = options?.projectReference ?? this.resolveProjectId() ?? undefined;
|
|
549
571
|
return projectReference ? { ...options, projectReference } : options;
|
|
550
572
|
}
|
|
551
|
-
async
|
|
552
|
-
const
|
|
553
|
-
if (
|
|
554
|
-
return
|
|
573
|
+
async resolveBackgroundCommandRoute(commandId) {
|
|
574
|
+
const trackedCommand = this.activeBackgroundCommands.get(commandId);
|
|
575
|
+
if (trackedCommand) {
|
|
576
|
+
return trackedCommand;
|
|
555
577
|
}
|
|
556
578
|
await this.ensure();
|
|
557
|
-
|
|
579
|
+
const route = this.resolveDataPlaneRoute();
|
|
580
|
+
return {
|
|
581
|
+
commandsUrl: backgroundCommandsUrl(route),
|
|
582
|
+
routeKind: route.kind,
|
|
583
|
+
};
|
|
558
584
|
}
|
|
559
|
-
updateTrackedBackgroundCommand(backgroundCommand,
|
|
585
|
+
updateTrackedBackgroundCommand(backgroundCommand, command) {
|
|
560
586
|
if (backgroundCommand.status === "running") {
|
|
561
|
-
this.
|
|
562
|
-
|
|
587
|
+
this.activeBackgroundCommands.set(backgroundCommand.id, command);
|
|
588
|
+
if (command.routeKind === "internal") {
|
|
589
|
+
this.stopHeartbeatLoop();
|
|
590
|
+
}
|
|
563
591
|
return;
|
|
564
592
|
}
|
|
565
|
-
if (!this.
|
|
593
|
+
if (!this.activeBackgroundCommands.delete(backgroundCommand.id)) {
|
|
566
594
|
return;
|
|
567
595
|
}
|
|
568
|
-
if (this.
|
|
596
|
+
if (!this.hasActiveInternalBackgroundCommand() && this.endpoint) {
|
|
569
597
|
this.startHeartbeatLoop();
|
|
570
598
|
}
|
|
571
599
|
}
|
|
600
|
+
hasActiveInternalBackgroundCommand() {
|
|
601
|
+
for (const command of this.activeBackgroundCommands.values()) {
|
|
602
|
+
if (command.routeKind === "internal") {
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
572
608
|
async startExec(command, options) {
|
|
573
|
-
const
|
|
609
|
+
const route = this.resolveDataPlaneRoute();
|
|
574
610
|
const body = JSON.stringify({ command, ...this.resolveExecOptions(options) });
|
|
575
611
|
for (let attempt = 1; attempt <= this.execStartMaxAttempts; attempt += 1) {
|
|
576
612
|
try {
|
|
577
|
-
const res = await this.fetchExecStart(
|
|
613
|
+
const res = await this.fetchExecStart(commandStreamUrl(route), {
|
|
578
614
|
method: "POST",
|
|
579
615
|
headers: this.jsonHeaders(),
|
|
580
616
|
body,
|
|
@@ -615,15 +651,38 @@ export class LazySandbox {
|
|
|
615
651
|
}
|
|
616
652
|
this.resetSessionState(sessionId);
|
|
617
653
|
}
|
|
618
|
-
resolveRuntimeEndpoint() {
|
|
619
|
-
const endpoint = this.requireEndpoint();
|
|
620
|
-
const sessionId = this.requireSessionId();
|
|
621
|
-
return this.resolveRuntimeEndpointFor(endpoint, sessionId);
|
|
622
|
-
}
|
|
623
654
|
resolveRuntimeEndpointFor(endpoint, sessionId) {
|
|
624
655
|
return this.resolveRuntimeEndpointOption?.({ endpoint, sessionId }) ??
|
|
625
656
|
resolveDefaultSandboxRuntimeEndpoint({ endpoint });
|
|
626
657
|
}
|
|
658
|
+
shouldUseInternalDataPlane(endpoint, sessionId) {
|
|
659
|
+
if (!this.resolveRuntimeEndpointOption) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
const runtimeEndpoint = this.resolveRuntimeEndpointFor(endpoint, sessionId);
|
|
663
|
+
return normalizeDataPlaneBaseUrl(runtimeEndpoint) !== normalizeDataPlaneBaseUrl(endpoint);
|
|
664
|
+
}
|
|
665
|
+
resolveDataPlaneRoute() {
|
|
666
|
+
const endpoint = this.requireEndpoint();
|
|
667
|
+
const sessionId = this.requireSessionId();
|
|
668
|
+
if (!this.resolveRuntimeEndpointOption) {
|
|
669
|
+
return {
|
|
670
|
+
baseUrl: sandboxSessionRoute(this.apiUrl, sessionId),
|
|
671
|
+
kind: "proxy",
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
const runtimeEndpoint = this.resolveRuntimeEndpointFor(endpoint, sessionId);
|
|
675
|
+
if (normalizeDataPlaneBaseUrl(runtimeEndpoint) !== normalizeDataPlaneBaseUrl(endpoint)) {
|
|
676
|
+
return {
|
|
677
|
+
baseUrl: normalizeDataPlaneBaseUrl(runtimeEndpoint),
|
|
678
|
+
kind: "internal",
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
return {
|
|
682
|
+
baseUrl: sandboxSessionRoute(this.apiUrl, sessionId),
|
|
683
|
+
kind: "proxy",
|
|
684
|
+
};
|
|
685
|
+
}
|
|
627
686
|
requireSessionId() {
|
|
628
687
|
if (!this.sessionId) {
|
|
629
688
|
throw new Error("Sandbox session unavailable");
|
|
@@ -643,6 +702,12 @@ export class LazySandbox {
|
|
|
643
702
|
function isRetryableExecStartStatus(status) {
|
|
644
703
|
return status === 502 || status === 503 || status === 504;
|
|
645
704
|
}
|
|
705
|
+
function commandStreamUrl(route) {
|
|
706
|
+
return `${route.baseUrl}${route.kind === "internal" ? "/exec" : "/commands/stream"}`;
|
|
707
|
+
}
|
|
708
|
+
function backgroundCommandsUrl(route) {
|
|
709
|
+
return `${route.baseUrl}${route.kind === "internal" ? "/exec/commands" : "/commands"}`;
|
|
710
|
+
}
|
|
646
711
|
/**
|
|
647
712
|
* Heuristic: Deno's fetch throws an `Error` with message "fetch failed" (case-
|
|
648
713
|
* insensitive) when the TCP connection is refused or the host is unreachable.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-routes.d.ts","sourceRoot":"","sources":["../../../src/src/sandbox/proxy-routes.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,SAAK,GACR,MAAM,CAGR;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB3E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { REQUEST_ERROR } from "../errors/index.js";
|
|
2
|
+
export function sandboxSessionRoute(apiUrl, sessionId, path = "") {
|
|
3
|
+
const base = `${apiUrl.replace(/\/+$/, "")}/sandbox-sessions/${encodeURIComponent(sessionId)}`;
|
|
4
|
+
return path ? `${base}${path}` : base;
|
|
5
|
+
}
|
|
6
|
+
export async function readSandboxFileContent(res) {
|
|
7
|
+
const contentType = res.headers.get("Content-Type") ?? "";
|
|
8
|
+
if (!contentType.toLowerCase().includes("application/json")) {
|
|
9
|
+
return await res.text();
|
|
10
|
+
}
|
|
11
|
+
let json;
|
|
12
|
+
try {
|
|
13
|
+
json = await res.json();
|
|
14
|
+
}
|
|
15
|
+
catch (cause) {
|
|
16
|
+
throw REQUEST_ERROR.create({
|
|
17
|
+
detail: "Sandbox file response is not valid JSON",
|
|
18
|
+
cause,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const content = json && typeof json === "object"
|
|
22
|
+
? json.content
|
|
23
|
+
: undefined;
|
|
24
|
+
if (typeof content !== "string") {
|
|
25
|
+
throw REQUEST_ERROR.create({ detail: "Sandbox file response missing content" });
|
|
26
|
+
}
|
|
27
|
+
return content;
|
|
28
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../../src/src/sandbox/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../../src/src/sandbox/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { INITIALIZATION_ERROR, REQUEST_ERROR, TIMEOUT_ERROR } from "../errors/index.js";
|
|
10
10
|
import { LazySandbox } from "./lazy-sandbox.js";
|
|
11
11
|
import { resolveSandboxApiUrl, resolveSandboxAuthToken } from "./config.js";
|
|
12
|
+
import { readSandboxFileContent, sandboxSessionRoute } from "./proxy-routes.js";
|
|
12
13
|
export { resolveSandboxApiUrl, resolveSandboxAuthToken } from "./config.js";
|
|
13
14
|
/** Client for isolated ephemeral compute environments with command execution and file I/O. */
|
|
14
15
|
export class Sandbox {
|
|
@@ -138,7 +139,7 @@ export class Sandbox {
|
|
|
138
139
|
}
|
|
139
140
|
/** Execute a bash command with streaming output (NDJSON). */
|
|
140
141
|
async *executeStream(command, options) {
|
|
141
|
-
const res = await fetch(
|
|
142
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, "/commands/stream"), {
|
|
142
143
|
method: "POST",
|
|
143
144
|
headers: {
|
|
144
145
|
Authorization: `Bearer ${this.authToken}`,
|
|
@@ -155,47 +156,59 @@ export class Sandbox {
|
|
|
155
156
|
const reader = res.body.getReader();
|
|
156
157
|
const decoder = new TextDecoder();
|
|
157
158
|
let buffer = "";
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
159
|
+
let completed = false;
|
|
160
|
+
try {
|
|
161
|
+
while (true) {
|
|
162
|
+
const { done, value } = await reader.read();
|
|
163
|
+
if (done) {
|
|
164
|
+
completed = true;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
buffer += decoder.decode(value, { stream: true });
|
|
168
|
+
const lines = buffer.split("\n");
|
|
169
|
+
buffer = lines.pop();
|
|
170
|
+
for (const line of lines) {
|
|
171
|
+
if (line.trim()) {
|
|
172
|
+
try {
|
|
173
|
+
yield JSON.parse(line);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Malformed NDJSON line (e.g. truncated network chunk); skip and
|
|
177
|
+
// continue streaming so already-buffered output is not lost.
|
|
178
|
+
}
|
|
173
179
|
}
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
buffer += decoder.decode();
|
|
183
|
+
if (buffer.trim()) {
|
|
184
|
+
try {
|
|
185
|
+
yield JSON.parse(buffer);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Malformed final chunk; discard rather than surfacing a SyntaxError.
|
|
189
|
+
}
|
|
180
190
|
}
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
if (!completed) {
|
|
194
|
+
await reader.cancel().catch(() => { });
|
|
183
195
|
}
|
|
196
|
+
reader.releaseLock();
|
|
184
197
|
}
|
|
185
198
|
}
|
|
186
199
|
/** Read a file from the sandbox workspace. */
|
|
187
200
|
async readFile(path) {
|
|
188
|
-
const res = await fetch(
|
|
201
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, `/file?path=${encodeURIComponent(path)}`), {
|
|
189
202
|
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
190
203
|
});
|
|
191
204
|
if (!res.ok) {
|
|
192
205
|
throw REQUEST_ERROR.create({ detail: `Read file failed: ${res.status} ${await res.text()}` });
|
|
193
206
|
}
|
|
194
|
-
return res
|
|
207
|
+
return await readSandboxFileContent(res);
|
|
195
208
|
}
|
|
196
209
|
/** Write files to the sandbox workspace. */
|
|
197
210
|
async writeFiles(files) {
|
|
198
|
-
const res = await fetch(
|
|
211
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, "/files"), {
|
|
199
212
|
method: "POST",
|
|
200
213
|
headers: {
|
|
201
214
|
Authorization: `Bearer ${this.authToken}`,
|
|
@@ -211,7 +224,7 @@ export class Sandbox {
|
|
|
211
224
|
}
|
|
212
225
|
/** Start an async background command in the sandbox. */
|
|
213
226
|
async startBackgroundCommand(command, options) {
|
|
214
|
-
const res = await fetch(
|
|
227
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, "/commands"), {
|
|
215
228
|
method: "POST",
|
|
216
229
|
headers: {
|
|
217
230
|
Authorization: `Bearer ${this.authToken}`,
|
|
@@ -228,7 +241,7 @@ export class Sandbox {
|
|
|
228
241
|
}
|
|
229
242
|
/** Get the status of an async background command. */
|
|
230
243
|
async getBackgroundCommand(commandId) {
|
|
231
|
-
const res = await fetch(
|
|
244
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, `/commands/${encodeURIComponent(commandId)}`), {
|
|
232
245
|
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
233
246
|
});
|
|
234
247
|
if (!res.ok) {
|
|
@@ -240,7 +253,7 @@ export class Sandbox {
|
|
|
240
253
|
}
|
|
241
254
|
/** Get the output of an async background command. */
|
|
242
255
|
async getBackgroundCommandOutput(commandId) {
|
|
243
|
-
const res = await fetch(
|
|
256
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, `/commands/${encodeURIComponent(commandId)}/output`), {
|
|
244
257
|
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
245
258
|
});
|
|
246
259
|
if (!res.ok) {
|
|
@@ -259,7 +272,7 @@ export class Sandbox {
|
|
|
259
272
|
}
|
|
260
273
|
/** List all background commands in the sandbox. */
|
|
261
274
|
async listBackgroundCommands() {
|
|
262
|
-
const res = await fetch(
|
|
275
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, "/commands"), {
|
|
263
276
|
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
264
277
|
});
|
|
265
278
|
if (!res.ok) {
|
|
@@ -273,7 +286,7 @@ export class Sandbox {
|
|
|
273
286
|
}
|
|
274
287
|
/** Cancel an async background command. */
|
|
275
288
|
async cancelBackgroundCommand(commandId) {
|
|
276
|
-
const res = await fetch(
|
|
289
|
+
const res = await fetch(sandboxSessionRoute(this.apiUrl, this.sessionId, `/commands/${encodeURIComponent(commandId)}/cancel`), {
|
|
277
290
|
method: "POST",
|
|
278
291
|
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
279
292
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-data-endpoint-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/module/page-data-endpoint-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AA8EhE,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,cAAc,EACnB,qBAAqB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,eAAe,EAC/D,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,aAAa,EAC9C,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAC1C,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"page-data-endpoint-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/module/page-data-endpoint-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AA8EhE,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,cAAc,EACnB,qBAAqB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,eAAe,EAC/D,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,aAAa,EAC9C,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAC1C,OAAO,CAAC,aAAa,CAAC,CAgHxB"}
|
|
@@ -58,9 +58,12 @@ export function handlePageDataEndpoint(req, pathname, ctx, createResponseBuilder
|
|
|
58
58
|
.replace(/\.json$/, "") || "";
|
|
59
59
|
const url = new URL(req.url);
|
|
60
60
|
const renderer = await getRendererForProject(ctx);
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const isSpeculativePrefetch = req.headers.get("x-veryfront-prefetch") === "1";
|
|
62
|
+
// The request reaches server-data hooks, so prefetch work cannot safely
|
|
63
|
+
// populate or join the foreground response cache/singleflight.
|
|
64
|
+
const canUsePageDataCache = isPageDataCacheEnabled() &&
|
|
65
|
+
!requestHasCacheSensitiveState(req) && !isSpeculativePrefetch;
|
|
66
|
+
const cacheKey = canUsePageDataCache ? buildPageDataCacheKey(ctx, slug, url) : null;
|
|
64
67
|
const cachePolicy = cacheKey ? getPageDataCachePolicy(ctx) : null;
|
|
65
68
|
const payload = cacheKey
|
|
66
69
|
? await resolveCachedPageData(cacheKey, () => withTimeoutThrow(renderer.resolvePageData(slug, { request: req, url }), PAGE_DATA_TIMEOUT_MS, `resolvePageData for ${slug}`), cachePolicy)
|
|
@@ -10,15 +10,15 @@ interface RewriteRule {
|
|
|
10
10
|
declare function buildRules(importMap: Record<string, string>): RewriteRule[];
|
|
11
11
|
/**
|
|
12
12
|
* Returns rewrite rules derived from deno.json's import map.
|
|
13
|
-
* Rules are cached
|
|
13
|
+
* Rules are cached per resolved project directory.
|
|
14
14
|
*/
|
|
15
|
-
export declare function getNpmRewriteRules(): RewriteRule[];
|
|
15
|
+
export declare function getNpmRewriteRules(baseDir?: string): RewriteRule[];
|
|
16
16
|
/**
|
|
17
17
|
* Apply npm import rewrites to source code.
|
|
18
18
|
* Rewrites bare specifiers to pinned npm: versions from deno.json.
|
|
19
19
|
* No-op on Node.js where bare specifiers resolve via node_modules.
|
|
20
20
|
*/
|
|
21
|
-
export declare function rewriteNpmImports(source: string): string;
|
|
21
|
+
export declare function rewriteNpmImports(source: string, baseDir?: string): string;
|
|
22
22
|
/** Exported for testing */
|
|
23
23
|
export { buildRules, REWRITABLE_PACKAGES };
|
|
24
24
|
/** @internal Reset cached rules — only for testing */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"npm-import-rewrites.d.ts","sourceRoot":"","sources":["../../../src/src/transforms/npm-import-rewrites.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,QAAA,MAAM,mBAAmB,aAAc,CAAC;AAExC,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD,iBAAS,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,WAAW,EAAE,CA6BpE;
|
|
1
|
+
{"version":3,"file":"npm-import-rewrites.d.ts","sourceRoot":"","sources":["../../../src/src/transforms/npm-import-rewrites.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,QAAA,MAAM,mBAAmB,aAAc,CAAC;AAExC,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD,iBAAS,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,WAAW,EAAE,CA6BpE;AAyBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,MAAc,GAAG,WAAW,EAAE,CASzE;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,MAAc,GAAG,MAAM,CAOjF;AAED,2BAA2B;AAC3B,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;AAE3C,sDAAsD;AACtD,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|