veryfront 0.1.1113 → 0.1.1114
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/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/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/sandbox/lazy-sandbox.d.ts +4 -3
- package/esm/src/sandbox/lazy-sandbox.d.ts.map +1 -1
- package/esm/src/sandbox/lazy-sandbox.js +99 -50
- 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/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -5
package/esm/deno.js
CHANGED
|
@@ -15,7 +15,7 @@ export type ProjectAgentRuntimeAgentIdCandidates = {
|
|
|
15
15
|
/** Input payload for discover project agent runtime. */
|
|
16
16
|
export type DiscoverProjectAgentRuntimeInput = {
|
|
17
17
|
projectDir: string;
|
|
18
|
-
adapter
|
|
18
|
+
adapter?: RuntimeAdapter;
|
|
19
19
|
config?: VeryfrontConfig | null;
|
|
20
20
|
fsAdapter?: FileSystemAdapter;
|
|
21
21
|
cacheKey?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-runtime.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/project/agent-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAKhE,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-runtime.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/project/agent-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAKhE,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAKzE,OAAO,KAAK,EACV,8BAA8B,EAE/B,MAAM,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,aAAa,CAAC;AACtD,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,qCAAqC,CAAC;AAO7C,kEAAkE;AAClE,MAAM,MAAM,8BAA8B,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1E,yEAAyE;AACzE,MAAM,MAAM,oCAAoC,GAAG;IACjD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,gCAAgC,GAAG;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yFAAyF;IACzF,uBAAuB,CAAC,EAAE,+BAA+B,CAAC;CAC3D,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,4BAA4B,GAAG,eAAe,GAAG;IAC3D,uBAAuB,EAAE,+BAA+B,CAAC;CAC1D,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,OAAO,EAAE,IAAI,CAAC,4BAA4B,EAAE,yBAAyB,CAAC,EACtE,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAEH;AA8CD,8CAA8C;AAC9C,wBAAgB,kCAAkC,IAAI,IAAI,CAMzD;AAED,6CAA6C;AAC7C,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,gCAAgC,GACtC,OAAO,CAAC,4BAA4B,CAAC,CA+BvC;AAED,4DAA4D;AAC5D,wBAAgB,uCAAuC,CACrD,YAAY,EAAE,KAAK,EACnB,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAOT;AAED,kDAAkD;AAClD,wBAAsB,qCAAqC,CACzD,YAAY,EAAE,KAAK,GAClB,OAAO,CAAC,8BAA8B,CAAC,CA+BzC;AAED,wDAAwD;AACxD,wBAAgB,uCAAuC,CACrD,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,GAAG,IAAI,GAAG,SAAS,GAClE,oCAAoC,CAgBtC;AAED,iEAAiE;AACjE,wBAAgB,4CAA4C,CAC1D,KAAK,EAAE,oCAAoC,GAC1C,MAAM,CAKR;AAED,sDAAsD;AACtD,wBAAgB,uCAAuC,CAAC,KAAK,EAAE;IAC7D,UAAU,EAAE,oCAAoC,CAAC;IACjD,MAAM,EAAE,8BAA8B,CAAC;CACxC,GAAG,MAAM,GAAG,IAAI,CAiBhB"}
|
|
@@ -3,6 +3,7 @@ import { clearTrackedAgents } from "../../discovery/discovery-utils.js";
|
|
|
3
3
|
import { createProjectDiscoveryConfig } from "../../discovery/project-discovery-config.js";
|
|
4
4
|
import { clearTranspileCache } from "../../discovery/transpiler.js";
|
|
5
5
|
import { getConfig } from "../../config/index.js";
|
|
6
|
+
import { getLocalAdapter } from "../../platform/adapters/registry.js";
|
|
6
7
|
import { clearMCPRegistry } from "../../mcp/index.js";
|
|
7
8
|
import { workflowRegistry } from "../../workflow/registry.js";
|
|
8
9
|
import { agentRegistry } from "../composition/index.js";
|
|
@@ -60,7 +61,7 @@ export async function discoverProjectAgentRuntime(input) {
|
|
|
60
61
|
return await runWithEffectiveSourceIntegrationPolicy(input.sourceIntegrationPolicy, async () => {
|
|
61
62
|
clearProjectAgentRuntimeRegistries();
|
|
62
63
|
const config = input.config ??
|
|
63
|
-
await getConfig(input.projectDir, input.adapter, input.cacheKey ? { cacheKey: input.cacheKey } : undefined);
|
|
64
|
+
await getConfig(input.projectDir, input.adapter ?? await getLocalAdapter(), input.cacheKey ? { cacheKey: input.cacheKey } : undefined);
|
|
64
65
|
const discoveryOptions = createProjectDiscoveryConfig({
|
|
65
66
|
projectDir: input.projectDir,
|
|
66
67
|
config,
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Import Rewriter
|
|
3
|
-
*
|
|
4
|
-
* Transforms import statements for different runtime environments
|
|
5
|
-
* (Deno, Node.js) and handles veryfront package resolution.
|
|
6
|
-
*/
|
|
7
1
|
import { createFileSystem } from "../platform/compat/fs.js";
|
|
8
2
|
export declare const DISCOVERY_GLOBAL_VERYFRONT_MODULES: readonly ["veryfront/agent", "veryfront/tool", "veryfront/platform", "veryfront/prompt", "veryfront/resource", "veryfront/embedding", "veryfront/knowledge", "veryfront/workflow", "veryfront/eval", "veryfront/metrics", "veryfront/schemas", "veryfront/integrations", "veryfront/chat/uploads"];
|
|
9
3
|
interface DenoRewriteOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/import-rewriter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/import-rewriter.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,eAAO,MAAM,kCAAkC,oSAerC,CAAC;AAEX,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;CAClD;AAwHD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CA2BR;AAqFD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAyRjB"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Transforms import statements for different runtime environments
|
|
5
5
|
* (Deno, Node.js) and handles veryfront package resolution.
|
|
6
6
|
*/
|
|
7
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
7
8
|
import { isDenoCompiled } from "../platform/compat/runtime.js";
|
|
8
9
|
import * as pathHelper from "../platform/compat/path/index.js";
|
|
9
10
|
import { LRUCache } from "../utils/lru-wrapper.js";
|
|
@@ -93,6 +94,12 @@ function isUnprefixedNpmSpecifier(specifier) {
|
|
|
93
94
|
// `import type` / `export type` lines reference types only; they get erased
|
|
94
95
|
// by TypeScript and must not trigger filesystem resolution.
|
|
95
96
|
const TYPE_ONLY_STATIC_RE = /(?:^|[\s;{}])(?:import|export)\s+type\b/;
|
|
97
|
+
function isNotFoundError(error) {
|
|
98
|
+
const DenoNotFound = dntShim.dntGlobalThis.Deno?.errors?.NotFound;
|
|
99
|
+
if (DenoNotFound && error instanceof DenoNotFound)
|
|
100
|
+
return true;
|
|
101
|
+
return error?.code === "ENOENT";
|
|
102
|
+
}
|
|
96
103
|
function rewriteBareNpmImportsForDeno(code) {
|
|
97
104
|
return code
|
|
98
105
|
// `import x from "spec"`, `export { x } from "spec"`, `export * from "spec"`.
|
|
@@ -229,6 +236,7 @@ export async function rewriteDiscoveryImports(code, projectDir, fs, fileDir) {
|
|
|
229
236
|
let transformed = code;
|
|
230
237
|
try {
|
|
231
238
|
const { pathToFileURL } = await import("node:url");
|
|
239
|
+
const projectRoot = pathHelper.resolve(projectDir);
|
|
232
240
|
// Handle relative imports
|
|
233
241
|
transformed = transformed.replace(/from\s+["'](\.\.\/[^"']+)["']/g, (_match, relativePath) => `from "${pathToFileURL(pathHelper.resolve(fileDir, relativePath)).href}"`);
|
|
234
242
|
// Resolve a bare specifier (optionally with subpath) to a file:// URL,
|
|
@@ -238,14 +246,14 @@ export async function rewriteDiscoveryImports(code, projectDir, fs, fileDir) {
|
|
|
238
246
|
// so a subsequent `npm install` of the missing dep is picked up
|
|
239
247
|
// without a process restart.
|
|
240
248
|
const resolvePackageToFileUrl = async (specifier) => {
|
|
241
|
-
const cacheKey = `${
|
|
249
|
+
const cacheKey = `${projectRoot}::${specifier}`;
|
|
242
250
|
const cached = resolvedSpecifierCache.get(cacheKey);
|
|
243
251
|
if (cached !== undefined)
|
|
244
252
|
return cached;
|
|
245
253
|
const { name: packageName, subpath } = splitPackageSubpath(specifier);
|
|
246
|
-
let searchDir =
|
|
254
|
+
let searchDir = projectRoot;
|
|
247
255
|
for (let i = 0; i < 10; i++) {
|
|
248
|
-
const packagePath = pathHelper.
|
|
256
|
+
const packagePath = pathHelper.resolve(searchDir, "node_modules", packageName);
|
|
249
257
|
const packageJsonPath = pathHelper.join(packagePath, "package.json");
|
|
250
258
|
try {
|
|
251
259
|
const pkgJson = JSON.parse(await fs.readTextFile(packageJsonPath));
|
|
@@ -357,40 +365,53 @@ export async function rewriteDiscoveryImports(code, projectDir, fs, fileDir) {
|
|
|
357
365
|
.replace(new RegExp(`from\\s*["']${escapedSpecifier}["']`, "g"), `from "${resolvedUrl}"`)
|
|
358
366
|
.replace(new RegExp(`import\\s*\\(\\s*["']${escapedSpecifier}["']\\s*\\)`, "g"), `import("${resolvedUrl}")`);
|
|
359
367
|
};
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
368
|
+
const findVeryfrontExportSource = async () => {
|
|
369
|
+
const nodePackagePath = pathHelper.resolve(projectRoot, "node_modules", "veryfront");
|
|
370
|
+
const vfPackageJsonPath = pathHelper.join(nodePackagePath, "package.json");
|
|
371
|
+
let hasNodePackagePath = false;
|
|
372
|
+
try {
|
|
373
|
+
await fs.stat(nodePackagePath);
|
|
374
|
+
hasNodePackagePath = true;
|
|
375
|
+
}
|
|
376
|
+
catch (error) {
|
|
377
|
+
if (!isNotFoundError(error)) {
|
|
378
|
+
return { kind: "present", packagePath: nodePackagePath, exportsMap: undefined };
|
|
379
|
+
}
|
|
380
|
+
/* expected: veryfront directory absent, fallback to deno.json search */
|
|
381
|
+
}
|
|
382
|
+
if (hasNodePackagePath) {
|
|
383
|
+
try {
|
|
384
|
+
const packageJsonText = await fs.readTextFile(vfPackageJsonPath);
|
|
385
|
+
const pkgJson = JSON.parse(packageJsonText);
|
|
386
|
+
return { kind: "present", packagePath: nodePackagePath, exportsMap: pkgJson.exports };
|
|
387
|
+
}
|
|
388
|
+
catch (_) {
|
|
389
|
+
return { kind: "present", packagePath: nodePackagePath, exportsMap: undefined };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Search for deno.json in parent directories.
|
|
393
|
+
let searchDir = projectRoot;
|
|
372
394
|
for (let i = 0; i < 5; i++) {
|
|
373
395
|
try {
|
|
374
396
|
const denoJsonPath = pathHelper.join(searchDir, "deno.json");
|
|
375
397
|
const denoJson = JSON.parse(await fs.readTextFile(denoJsonPath));
|
|
376
|
-
if (denoJson.name === "veryfront" && denoJson
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
398
|
+
if (denoJson.name === "veryfront" && "exports" in denoJson) {
|
|
399
|
+
return {
|
|
400
|
+
kind: "present",
|
|
401
|
+
packagePath: pathHelper.resolve(searchDir),
|
|
402
|
+
exportsMap: denoJson.exports,
|
|
403
|
+
};
|
|
380
404
|
}
|
|
381
405
|
}
|
|
382
406
|
catch (_) {
|
|
383
407
|
/* expected: deno.json not found at this level */
|
|
384
408
|
}
|
|
385
|
-
|
|
409
|
+
const parent = pathHelper.dirname(searchDir);
|
|
410
|
+
if (parent === searchDir)
|
|
411
|
+
break;
|
|
412
|
+
searchDir = parent;
|
|
386
413
|
}
|
|
387
|
-
|
|
388
|
-
const getExportPath = (entry) => {
|
|
389
|
-
if (!entry)
|
|
390
|
-
return null;
|
|
391
|
-
if (typeof entry === "string")
|
|
392
|
-
return entry;
|
|
393
|
-
return entry.import ?? null;
|
|
414
|
+
return { kind: "absent" };
|
|
394
415
|
};
|
|
395
416
|
const veryfrontSpecifiers = new Set();
|
|
396
417
|
for (const match of transformed.matchAll(/from\s+["'](veryfront(?:\/[^"']+)?)["']/g)) {
|
|
@@ -403,29 +424,40 @@ export async function rewriteDiscoveryImports(code, projectDir, fs, fileDir) {
|
|
|
403
424
|
if (specifier)
|
|
404
425
|
veryfrontSpecifiers.add(specifier);
|
|
405
426
|
}
|
|
427
|
+
const veryfrontExportSource = await findVeryfrontExportSource();
|
|
428
|
+
const resolveVeryfrontExportToFileUrl = (specifier) => {
|
|
429
|
+
if (veryfrontExportSource.kind === "absent")
|
|
430
|
+
return { kind: "rejected" };
|
|
431
|
+
const subpath = specifier === "veryfront" ? "." : "./" + specifier.replace("veryfront/", "");
|
|
432
|
+
const exportPath = resolveExportPath(veryfrontExportSource.exportsMap, subpath);
|
|
433
|
+
if (!exportPath)
|
|
434
|
+
return { kind: "rejected" };
|
|
435
|
+
const packagePath = veryfrontExportSource.packagePath;
|
|
436
|
+
const resolvedPath = pathHelper.resolve(packagePath, exportPath);
|
|
437
|
+
const packagePathPrefix = packagePath.endsWith(pathHelper.SEPARATOR)
|
|
438
|
+
? packagePath
|
|
439
|
+
: packagePath + pathHelper.SEPARATOR;
|
|
440
|
+
if (resolvedPath !== packagePath && !resolvedPath.startsWith(packagePathPrefix)) {
|
|
441
|
+
return { kind: "rejected" };
|
|
442
|
+
}
|
|
443
|
+
return { kind: "resolved", url: pathToFileURL(resolvedPath).href };
|
|
444
|
+
};
|
|
406
445
|
for (const specifier of veryfrontSpecifiers) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
446
|
+
if (veryfrontExportSource.kind === "absent")
|
|
447
|
+
continue;
|
|
448
|
+
const result = resolveVeryfrontExportToFileUrl(specifier);
|
|
449
|
+
if (result.kind === "resolved") {
|
|
450
|
+
transformed = rewriteResolvedSpecifierImports(transformed, specifier, result.url);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (veryfrontExportSource.kind === "absent") {
|
|
454
|
+
for (const specifier of veryfrontSpecifiers) {
|
|
455
|
+
const resolvedUrl = resolveRuntimeSpecifierToFileUrl(specifier);
|
|
456
|
+
if (resolvedUrl) {
|
|
457
|
+
transformed = rewriteResolvedSpecifierImports(transformed, specifier, resolvedUrl);
|
|
458
|
+
}
|
|
410
459
|
}
|
|
411
460
|
}
|
|
412
|
-
// Rewrite veryfront subpath imports
|
|
413
|
-
transformed = transformed.replace(/from\s+["'](veryfront\/[^"']+)["']/g, (match, fullSpecifier) => {
|
|
414
|
-
const subpath = "./" + fullSpecifier.replace("veryfront/", "");
|
|
415
|
-
const exportPath = getExportPath(exportsMap[subpath]);
|
|
416
|
-
if (!exportPath)
|
|
417
|
-
return match;
|
|
418
|
-
const resolvedPath = pathHelper.join(vfPackagePath, exportPath);
|
|
419
|
-
return `from "${pathToFileURL(resolvedPath).href}"`;
|
|
420
|
-
});
|
|
421
|
-
// Rewrite bare veryfront import
|
|
422
|
-
transformed = transformed.replace(/from\s+["']veryfront["']/g, () => {
|
|
423
|
-
const exportPath = getExportPath(exportsMap["."]);
|
|
424
|
-
if (!exportPath)
|
|
425
|
-
return 'from "veryfront"';
|
|
426
|
-
const resolvedPath = pathHelper.join(vfPackagePath, exportPath);
|
|
427
|
-
return `from "${pathToFileURL(resolvedPath).href}"`;
|
|
428
|
-
});
|
|
429
461
|
}
|
|
430
462
|
catch (_) {
|
|
431
463
|
/* expected: Node.js URL module unavailable in non-Node runtime */
|
|
@@ -53,7 +53,7 @@ export declare class LazySandbox {
|
|
|
53
53
|
private heartbeatPromise;
|
|
54
54
|
private heartbeatTimer;
|
|
55
55
|
private lastHeartbeatAt;
|
|
56
|
-
private readonly
|
|
56
|
+
private readonly activeBackgroundCommands;
|
|
57
57
|
constructor(options?: LazySandboxOptions);
|
|
58
58
|
ensure(): Promise<void>;
|
|
59
59
|
executeCommand(command: string, options?: ExecOptions): Promise<ExecResult>;
|
|
@@ -90,15 +90,16 @@ export declare class LazySandbox {
|
|
|
90
90
|
private resolveProjectId;
|
|
91
91
|
private resetSessionState;
|
|
92
92
|
private resolveExecOptions;
|
|
93
|
-
private
|
|
93
|
+
private resolveBackgroundCommandRoute;
|
|
94
94
|
private updateTrackedBackgroundCommand;
|
|
95
|
+
private hasActiveInternalBackgroundCommand;
|
|
95
96
|
private startExec;
|
|
96
97
|
private fetchExecStart;
|
|
97
98
|
private fetchControl;
|
|
98
99
|
private waitForExecStartRetry;
|
|
99
100
|
private reprovisionAfterExecStartFailure;
|
|
100
|
-
private resolveRuntimeEndpoint;
|
|
101
101
|
private resolveRuntimeEndpointFor;
|
|
102
|
+
private resolveDataPlaneRoute;
|
|
102
103
|
private requireSessionId;
|
|
103
104
|
private authHeaders;
|
|
104
105
|
private jsonHeaders;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-sandbox.d.ts","sourceRoot":"","sources":["../../../src/src/sandbox/lazy-sandbox.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lazy-sandbox.d.ts","sourceRoot":"","sources":["../../../src/src/sandbox/lazy-sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
}
|
|
@@ -497,7 +517,7 @@ export class LazySandbox {
|
|
|
497
517
|
heartbeatFailureCount = 0;
|
|
498
518
|
static HEARTBEAT_WARN_AFTER_FAILURES = 3;
|
|
499
519
|
startHeartbeatLoop() {
|
|
500
|
-
if (!this.sessionId || this.heartbeatTimer || this.
|
|
520
|
+
if (!this.sessionId || this.heartbeatTimer || this.hasActiveInternalBackgroundCommand()) {
|
|
501
521
|
return;
|
|
502
522
|
}
|
|
503
523
|
this.heartbeatTimer = setInterval(() => {
|
|
@@ -536,7 +556,7 @@ export class LazySandbox {
|
|
|
536
556
|
resetSessionState(sessionId) {
|
|
537
557
|
if (!sessionId || this.sessionId === sessionId) {
|
|
538
558
|
this.stopHeartbeatLoop();
|
|
539
|
-
this.
|
|
559
|
+
this.activeBackgroundCommands.clear();
|
|
540
560
|
this.endpoint = null;
|
|
541
561
|
this.sessionId = null;
|
|
542
562
|
this.sessionProjectId = null;
|
|
@@ -548,33 +568,47 @@ export class LazySandbox {
|
|
|
548
568
|
const projectReference = options?.projectReference ?? this.resolveProjectId() ?? undefined;
|
|
549
569
|
return projectReference ? { ...options, projectReference } : options;
|
|
550
570
|
}
|
|
551
|
-
async
|
|
552
|
-
const
|
|
553
|
-
if (
|
|
554
|
-
return
|
|
571
|
+
async resolveBackgroundCommandRoute(commandId) {
|
|
572
|
+
const trackedCommand = this.activeBackgroundCommands.get(commandId);
|
|
573
|
+
if (trackedCommand) {
|
|
574
|
+
return trackedCommand;
|
|
555
575
|
}
|
|
556
576
|
await this.ensure();
|
|
557
|
-
|
|
577
|
+
const route = this.resolveDataPlaneRoute();
|
|
578
|
+
return {
|
|
579
|
+
commandsUrl: backgroundCommandsUrl(route),
|
|
580
|
+
routeKind: route.kind,
|
|
581
|
+
};
|
|
558
582
|
}
|
|
559
|
-
updateTrackedBackgroundCommand(backgroundCommand,
|
|
583
|
+
updateTrackedBackgroundCommand(backgroundCommand, command) {
|
|
560
584
|
if (backgroundCommand.status === "running") {
|
|
561
|
-
this.
|
|
562
|
-
|
|
585
|
+
this.activeBackgroundCommands.set(backgroundCommand.id, command);
|
|
586
|
+
if (command.routeKind === "internal") {
|
|
587
|
+
this.stopHeartbeatLoop();
|
|
588
|
+
}
|
|
563
589
|
return;
|
|
564
590
|
}
|
|
565
|
-
if (!this.
|
|
591
|
+
if (!this.activeBackgroundCommands.delete(backgroundCommand.id)) {
|
|
566
592
|
return;
|
|
567
593
|
}
|
|
568
|
-
if (this.
|
|
594
|
+
if (!this.hasActiveInternalBackgroundCommand() && this.endpoint) {
|
|
569
595
|
this.startHeartbeatLoop();
|
|
570
596
|
}
|
|
571
597
|
}
|
|
598
|
+
hasActiveInternalBackgroundCommand() {
|
|
599
|
+
for (const command of this.activeBackgroundCommands.values()) {
|
|
600
|
+
if (command.routeKind === "internal") {
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
572
606
|
async startExec(command, options) {
|
|
573
|
-
const
|
|
607
|
+
const route = this.resolveDataPlaneRoute();
|
|
574
608
|
const body = JSON.stringify({ command, ...this.resolveExecOptions(options) });
|
|
575
609
|
for (let attempt = 1; attempt <= this.execStartMaxAttempts; attempt += 1) {
|
|
576
610
|
try {
|
|
577
|
-
const res = await this.fetchExecStart(
|
|
611
|
+
const res = await this.fetchExecStart(commandStreamUrl(route), {
|
|
578
612
|
method: "POST",
|
|
579
613
|
headers: this.jsonHeaders(),
|
|
580
614
|
body,
|
|
@@ -615,15 +649,24 @@ export class LazySandbox {
|
|
|
615
649
|
}
|
|
616
650
|
this.resetSessionState(sessionId);
|
|
617
651
|
}
|
|
618
|
-
resolveRuntimeEndpoint() {
|
|
619
|
-
const endpoint = this.requireEndpoint();
|
|
620
|
-
const sessionId = this.requireSessionId();
|
|
621
|
-
return this.resolveRuntimeEndpointFor(endpoint, sessionId);
|
|
622
|
-
}
|
|
623
652
|
resolveRuntimeEndpointFor(endpoint, sessionId) {
|
|
624
653
|
return this.resolveRuntimeEndpointOption?.({ endpoint, sessionId }) ??
|
|
625
654
|
resolveDefaultSandboxRuntimeEndpoint({ endpoint });
|
|
626
655
|
}
|
|
656
|
+
resolveDataPlaneRoute() {
|
|
657
|
+
const endpoint = this.requireEndpoint();
|
|
658
|
+
const sessionId = this.requireSessionId();
|
|
659
|
+
const runtimeEndpoint = this.resolveRuntimeEndpointFor(endpoint, sessionId);
|
|
660
|
+
const normalizedEndpoint = normalizeDataPlaneBaseUrl(endpoint);
|
|
661
|
+
const normalizedRuntimeEndpoint = normalizeDataPlaneBaseUrl(runtimeEndpoint);
|
|
662
|
+
if (normalizedRuntimeEndpoint !== normalizedEndpoint) {
|
|
663
|
+
return { baseUrl: normalizedRuntimeEndpoint, kind: "internal" };
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
baseUrl: sandboxSessionRoute(this.apiUrl, sessionId),
|
|
667
|
+
kind: "proxy",
|
|
668
|
+
};
|
|
669
|
+
}
|
|
627
670
|
requireSessionId() {
|
|
628
671
|
if (!this.sessionId) {
|
|
629
672
|
throw new Error("Sandbox session unavailable");
|
|
@@ -643,6 +686,12 @@ export class LazySandbox {
|
|
|
643
686
|
function isRetryableExecStartStatus(status) {
|
|
644
687
|
return status === 502 || status === 503 || status === 504;
|
|
645
688
|
}
|
|
689
|
+
function commandStreamUrl(route) {
|
|
690
|
+
return `${route.baseUrl}${route.kind === "internal" ? "/exec" : "/commands/stream"}`;
|
|
691
|
+
}
|
|
692
|
+
function backgroundCommandsUrl(route) {
|
|
693
|
+
return `${route.baseUrl}${route.kind === "internal" ? "/exec/commands" : "/commands"}`;
|
|
694
|
+
}
|
|
646
695
|
/**
|
|
647
696
|
* Heuristic: Deno's fetch throws an `Error` with message "fetch failed" (case-
|
|
648
697
|
* 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
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1114",
|
|
4
4
|
"description": "The simplest way to build AI-powered apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -332,10 +332,10 @@
|
|
|
332
332
|
"@types/react": "19.2.14",
|
|
333
333
|
"@types/react-dom": "19.2.3",
|
|
334
334
|
"ws": "8.21.0",
|
|
335
|
-
"@veryfront/ext-bundler-esbuild": "0.1.
|
|
336
|
-
"@veryfront/ext-content-mdx": "0.1.
|
|
337
|
-
"@veryfront/ext-css-tailwind": "0.1.
|
|
338
|
-
"@veryfront/ext-parser-babel": "0.1.
|
|
335
|
+
"@veryfront/ext-bundler-esbuild": "0.1.1114",
|
|
336
|
+
"@veryfront/ext-content-mdx": "0.1.1114",
|
|
337
|
+
"@veryfront/ext-css-tailwind": "0.1.1114",
|
|
338
|
+
"@veryfront/ext-parser-babel": "0.1.1114"
|
|
339
339
|
},
|
|
340
340
|
"devDependencies": {
|
|
341
341
|
"@types/node": "20.9.0"
|