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.
Files changed (42) hide show
  1. package/esm/cli/commands/deploy/command.d.ts +3 -0
  2. package/esm/cli/commands/deploy/command.d.ts.map +1 -1
  3. package/esm/cli/commands/deploy/command.js +4 -4
  4. package/esm/cli/commands/up/command.d.ts +3 -0
  5. package/esm/cli/commands/up/command.d.ts.map +1 -1
  6. package/esm/cli/commands/up/command.js +4 -2
  7. package/esm/cli/skills/loader.d.ts +4 -4
  8. package/esm/cli/skills/loader.d.ts.map +1 -1
  9. package/esm/cli/skills/loader.js +6 -6
  10. package/esm/deno.js +1 -1
  11. package/esm/src/agent/project/agent-runtime.d.ts +1 -1
  12. package/esm/src/agent/project/agent-runtime.d.ts.map +1 -1
  13. package/esm/src/agent/project/agent-runtime.js +2 -1
  14. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  15. package/esm/src/agent/runtime/index.js +4 -8
  16. package/esm/src/data/server-data-fetcher.d.ts.map +1 -1
  17. package/esm/src/data/server-data-fetcher.js +5 -1
  18. package/esm/src/discovery/import-rewriter.d.ts +0 -6
  19. package/esm/src/discovery/import-rewriter.d.ts.map +1 -1
  20. package/esm/src/discovery/import-rewriter.js +79 -47
  21. package/esm/src/html/hydration-script-builder/templates/router.d.ts.map +1 -1
  22. package/esm/src/html/hydration-script-builder/templates/router.js +87 -24
  23. package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
  24. package/esm/src/rendering/orchestrator/pipeline.js +26 -8
  25. package/esm/src/rendering/script-page-handling.js +1 -1
  26. package/esm/src/routing/api/module-loader/external-import-rewriter.js +1 -1
  27. package/esm/src/sandbox/lazy-sandbox.d.ts +5 -3
  28. package/esm/src/sandbox/lazy-sandbox.d.ts.map +1 -1
  29. package/esm/src/sandbox/lazy-sandbox.js +116 -51
  30. package/esm/src/sandbox/proxy-routes.d.ts +3 -0
  31. package/esm/src/sandbox/proxy-routes.d.ts.map +1 -0
  32. package/esm/src/sandbox/proxy-routes.js +28 -0
  33. package/esm/src/sandbox/sandbox.d.ts.map +1 -1
  34. package/esm/src/sandbox/sandbox.js +43 -30
  35. package/esm/src/server/handlers/request/module/page-data-endpoint-handler.d.ts.map +1 -1
  36. package/esm/src/server/handlers/request/module/page-data-endpoint-handler.js +6 -3
  37. package/esm/src/transforms/npm-import-rewrites.d.ts +3 -3
  38. package/esm/src/transforms/npm-import-rewrites.d.ts.map +1 -1
  39. package/esm/src/transforms/npm-import-rewrites.js +29 -14
  40. package/esm/src/utils/version-constant.d.ts +1 -1
  41. package/esm/src/utils/version-constant.js +1 -1
  42. 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
- activeBackgroundCommandEndpoints = new Map();
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
- while (true) {
145
- const { done, value } = await reader.read();
146
- if (done)
147
- break;
148
- buffer += decoder.decode(value, { stream: true });
149
- const lines = buffer.split("\n");
150
- buffer = lines.pop() ?? "";
151
- for (const line of lines) {
152
- if (!line.trim())
153
- continue;
154
- yield JSON.parse(line);
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
- if (buffer.trim()) {
158
- yield JSON.parse(buffer);
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.requireEndpoint()}/file?path=${encodeURIComponent(path)}`, {
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.text();
185
+ return await readSandboxFileContent(res);
170
186
  }
171
187
  async writeFiles(files) {
172
188
  await this.touchSession();
173
- const res = await this.fetchControl(`${this.requireEndpoint()}/files`, {
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 endpoint = this.resolveRuntimeEndpoint();
187
- const res = await this.fetchControl(`${endpoint}/exec/commands`, {
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, endpoint);
215
+ this.updateTrackedBackgroundCommand(backgroundCommand, {
216
+ commandsUrl,
217
+ routeKind: route.kind,
218
+ });
199
219
  return backgroundCommand;
200
220
  }
201
221
  async getBackgroundCommand(commandId) {
202
- const endpoint = await this.resolveBackgroundCommandEndpoint(commandId);
203
- const res = await this.fetchControl(`${endpoint}/exec/commands/${encodeURIComponent(commandId)}`, {
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, endpoint);
232
+ this.updateTrackedBackgroundCommand(backgroundCommand, route);
213
233
  return backgroundCommand;
214
234
  }
215
235
  async getBackgroundCommandOutput(commandId) {
216
- const endpoint = await this.resolveBackgroundCommandEndpoint(commandId);
217
- const res = await this.fetchControl(`${endpoint}/exec/commands/${encodeURIComponent(commandId)}/output`, {
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, endpoint);
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(`${this.requireEndpoint()}/exec/commands`, {
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 endpoint = await this.resolveBackgroundCommandEndpoint(commandId);
252
- const res = await this.fetchControl(`${endpoint}/exec/commands/${encodeURIComponent(commandId)}/cancel`, {
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, endpoint);
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.activeBackgroundCommandEndpoints.size === 0) {
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
- await this.waitForRuntimeDataPlaneReady(readySession);
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.activeBackgroundCommandEndpoints.size > 0) {
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.activeBackgroundCommandEndpoints.clear();
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 resolveBackgroundCommandEndpoint(commandId) {
552
- const trackedEndpoint = this.activeBackgroundCommandEndpoints.get(commandId);
553
- if (trackedEndpoint) {
554
- return trackedEndpoint;
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
- return this.resolveRuntimeEndpoint();
579
+ const route = this.resolveDataPlaneRoute();
580
+ return {
581
+ commandsUrl: backgroundCommandsUrl(route),
582
+ routeKind: route.kind,
583
+ };
558
584
  }
559
- updateTrackedBackgroundCommand(backgroundCommand, endpoint) {
585
+ updateTrackedBackgroundCommand(backgroundCommand, command) {
560
586
  if (backgroundCommand.status === "running") {
561
- this.activeBackgroundCommandEndpoints.set(backgroundCommand.id, endpoint);
562
- this.stopHeartbeatLoop();
587
+ this.activeBackgroundCommands.set(backgroundCommand.id, command);
588
+ if (command.routeKind === "internal") {
589
+ this.stopHeartbeatLoop();
590
+ }
563
591
  return;
564
592
  }
565
- if (!this.activeBackgroundCommandEndpoints.delete(backgroundCommand.id)) {
593
+ if (!this.activeBackgroundCommands.delete(backgroundCommand.id)) {
566
594
  return;
567
595
  }
568
- if (this.activeBackgroundCommandEndpoints.size === 0 && this.endpoint) {
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 endpoint = this.resolveRuntimeEndpoint();
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(`${endpoint}/exec`, {
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,3 @@
1
+ export declare function sandboxSessionRoute(apiUrl: string, sessionId: string, path?: string): string;
2
+ export declare function readSandboxFileContent(res: Response): Promise<string>;
3
+ //# sourceMappingURL=proxy-routes.d.ts.map
@@ -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":"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"}
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(`${this.endpoint}/exec`, {
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
- while (true) {
159
- const { done, value } = await reader.read();
160
- if (done)
161
- break;
162
- buffer += decoder.decode(value, { stream: true });
163
- const lines = buffer.split("\n");
164
- buffer = lines.pop();
165
- for (const line of lines) {
166
- if (line.trim()) {
167
- try {
168
- yield JSON.parse(line);
169
- }
170
- catch {
171
- // Malformed NDJSON line (e.g. truncated network chunk); skip and
172
- // continue streaming so already-buffered output is not lost.
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
- if (buffer.trim()) {
178
- try {
179
- yield JSON.parse(buffer);
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
- catch {
182
- // Malformed final chunk; discard rather than surfacing a SyntaxError.
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(`${this.endpoint}/file?path=${encodeURIComponent(path)}`, {
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.text();
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(`${this.endpoint}/files`, {
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(`${this.endpoint}/exec/commands`, {
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(`${this.endpoint}/exec/commands/${encodeURIComponent(commandId)}`, {
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(`${this.endpoint}/exec/commands/${encodeURIComponent(commandId)}/output`, {
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(`${this.endpoint}/exec/commands`, {
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(`${this.endpoint}/exec/commands/${encodeURIComponent(commandId)}/cancel`, {
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,CA6GxB"}
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 cacheKey = !isPageDataCacheEnabled() || requestHasCacheSensitiveState(req)
62
- ? null
63
- : buildPageDataCacheKey(ctx, slug, url);
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 after first call.
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;AAcD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,EAAE,CAKlD;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED,2BAA2B;AAC3B,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;AAE3C,sDAAsD;AACtD,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
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"}