@yolk-sdk/sandbox 0.1.0-canary.39 → 0.1.0-canary.41
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/dist/vercel/client.d.mts +12 -12
- package/dist/vercel/client.d.mts.map +1 -1
- package/dist/vercel/client.mjs +25 -21
- package/dist/vercel/client.mjs.map +1 -1
- package/dist/vercel/layer.d.mts.map +1 -1
- package/dist/vercel/layer.mjs +10 -13
- package/dist/vercel/layer.mjs.map +1 -1
- package/package.json +2 -2
- package/src/vercel/client.ts +52 -37
- package/src/vercel/layer.ts +15 -16
package/dist/vercel/client.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SandboxInitialSource, SandboxResources, SandboxSnapshotRetention } from "../model.mjs";
|
|
2
|
-
import { Context, Layer } from "effect";
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
3
|
import { NetworkPolicy } from "@vercel/sandbox";
|
|
4
4
|
|
|
5
5
|
//#region src/vercel/client.d.ts
|
|
@@ -13,14 +13,14 @@ type VercelCommandSignal = 'SIGTERM' | 'SIGKILL';
|
|
|
13
13
|
type VercelFinishedCommand = {
|
|
14
14
|
readonly id: string;
|
|
15
15
|
readonly exitCode: number;
|
|
16
|
-
readonly output:
|
|
16
|
+
readonly output: Effect.Effect<VercelCommandOutput, unknown>;
|
|
17
17
|
};
|
|
18
18
|
type VercelDetachedCommand = {
|
|
19
19
|
readonly id: string;
|
|
20
20
|
readonly exitCode: number | null;
|
|
21
|
-
readonly wait:
|
|
22
|
-
readonly kill: (signal: VercelCommandSignal) =>
|
|
23
|
-
readonly output:
|
|
21
|
+
readonly wait: Effect.Effect<VercelFinishedCommand, unknown>;
|
|
22
|
+
readonly kill: (signal: VercelCommandSignal) => Effect.Effect<void, unknown>;
|
|
23
|
+
readonly output: Effect.Effect<VercelCommandOutput, unknown>;
|
|
24
24
|
};
|
|
25
25
|
type VercelSandboxFile = {
|
|
26
26
|
readonly path: string;
|
|
@@ -50,16 +50,16 @@ type VercelSandboxGetInput = {
|
|
|
50
50
|
};
|
|
51
51
|
type VercelSandboxHandle = {
|
|
52
52
|
readonly name: string;
|
|
53
|
-
readonly writeFiles: (files: ReadonlyArray<VercelSandboxFile>) =>
|
|
54
|
-
readonly runDetachedCommand: (input: VercelRunCommandInput) =>
|
|
55
|
-
readonly getCommand: (id: string) =>
|
|
56
|
-
readonly extendTimeout: (durationMs: number) =>
|
|
57
|
-
readonly delete:
|
|
53
|
+
readonly writeFiles: (files: ReadonlyArray<VercelSandboxFile>) => Effect.Effect<void, unknown>;
|
|
54
|
+
readonly runDetachedCommand: (input: VercelRunCommandInput) => Effect.Effect<VercelDetachedCommand, unknown>;
|
|
55
|
+
readonly getCommand: (id: string) => Effect.Effect<VercelDetachedCommand, unknown>;
|
|
56
|
+
readonly extendTimeout: (durationMs: number) => Effect.Effect<void, unknown>;
|
|
57
|
+
readonly delete: Effect.Effect<void, unknown>;
|
|
58
58
|
readonly domain: (port: number) => string;
|
|
59
59
|
};
|
|
60
60
|
type VercelSandboxClientApi = {
|
|
61
|
-
readonly get: (input: VercelSandboxGetInput) =>
|
|
62
|
-
readonly create: (input: VercelSandboxCreateInput) =>
|
|
61
|
+
readonly get: (input: VercelSandboxGetInput) => Effect.Effect<VercelSandboxHandle | null, unknown>;
|
|
62
|
+
readonly create: (input: VercelSandboxCreateInput) => Effect.Effect<VercelSandboxHandle, unknown>;
|
|
63
63
|
};
|
|
64
64
|
declare const VercelSandboxClient_base: Context.ServiceClass<VercelSandboxClient, "@yolk-sdk/sandbox/vercel/VercelSandboxClient", VercelSandboxClientApi>;
|
|
65
65
|
declare class VercelSandboxClient extends VercelSandboxClient_base {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.mts","names":[],"sources":["../../src/vercel/client.ts"],"mappings":";;;;;KAUY,oBAAA;AAAA,KACA,mBAAA,GAAsB,aAAa;AAAA,KAEnC,mBAAA;EAAA,SACD,MAAA;EAAA,SACA,MAAM;AAAA;AAAA,KAGL,mBAAA;AAAA,KAEA,qBAAA;EAAA,SACD,EAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA,
|
|
1
|
+
{"version":3,"file":"client.d.mts","names":[],"sources":["../../src/vercel/client.ts"],"mappings":";;;;;KAUY,oBAAA;AAAA,KACA,mBAAA,GAAsB,aAAa;AAAA,KAEnC,mBAAA;EAAA,SACD,MAAA;EAAA,SACA,MAAM;AAAA;AAAA,KAGL,mBAAA;AAAA,KAEA,qBAAA;EAAA,SACD,EAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA,EAAQ,MAAA,CAAO,MAAM,CAAC,mBAAA;AAAA;AAAA,KAGrB,qBAAA;EAAA,SACD,EAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA,EAAM,MAAA,CAAO,MAAA,CAAO,qBAAA;EAAA,SACpB,IAAA,GAAO,MAAA,EAAQ,mBAAA,KAAwB,MAAA,CAAO,MAAA;EAAA,SAC9C,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,mBAAA;AAAA;AAAA,KAGrB,iBAAA;EAAA,SACD,IAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;AAAA;AAAA,KAGC,qBAAA;EAAA,SACD,GAAA;EAAA,SACA,IAAA,GAAO,aAAa;EAAA,SACpB,GAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,IAAA;EAAA,SACA,MAAA,EAAQ,oBAAA;EAAA,SACR,KAAA,EAAO,aAAA;EAAA,SACP,SAAA;EAAA,SACA,SAAA,EAAW,gBAAA;EAAA,SACX,OAAA,EAAS,oBAAA;EAAA,SACT,GAAA,GAAM,QAAA,CAAS,MAAA;EAAA,SACf,UAAA;EAAA,SACA,oBAAA;EAAA,SACA,iBAAA,GAAoB,wBAAA;EAAA,SACpB,aAAA,GAAgB,mBAAA;AAAA;AAAA,KAGf,qBAAA;EAAA,SACD,IAAI;AAAA;AAAA,KAGH,mBAAA;EAAA,SACD,IAAA;EAAA,SACA,UAAA,GAAa,KAAA,EAAO,aAAA,CAAc,iBAAA,MAAuB,MAAA,CAAO,MAAA;EAAA,SAChE,kBAAA,GACP,KAAA,EAAO,qBAAA,KACJ,MAAA,CAAO,MAAA,CAAO,qBAAA;EAAA,SACV,UAAA,GAAa,EAAA,aAAe,MAAA,CAAO,MAAA,CAAO,qBAAA;EAAA,SAC1C,aAAA,GAAgB,UAAA,aAAuB,MAAA,CAAO,MAAA;EAAA,SAC9C,MAAA,EAAQ,MAAA,CAAO,MAAA;EAAA,SACf,MAAA,GAAS,IAAA;AAAA;AAAA,KAGR,sBAAA;EAAA,SACD,GAAA,GAAM,KAAA,EAAO,qBAAA,KAA0B,MAAA,CAAO,MAAA,CAAO,mBAAA;EAAA,SACrD,MAAA,GAAS,KAAA,EAAO,wBAAA,KAA6B,MAAA,CAAO,MAAA,CAAO,mBAAA;AAAA;AAAA,cACrE,wBAAA;cAEY,mBAAA,SAA4B,wBAGU;AAAA,cAEtC,2BAAA,GAA+B,KAAc;AAAA,cAoJ7C,uBAAA,EAAuB,KAAA,CAAA,KAAA,CAAA,mBAAA"}
|
package/dist/vercel/client.mjs
CHANGED
|
@@ -1,40 +1,44 @@
|
|
|
1
|
-
import { Context, Layer } from "effect";
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
2
|
import { APIError, Sandbox } from "@vercel/sandbox";
|
|
3
3
|
//#region src/vercel/client.ts
|
|
4
4
|
var VercelSandboxClient = class extends Context.Service()("@yolk-sdk/sandbox/vercel/VercelSandboxClient") {};
|
|
5
5
|
const isVercelMissingSandboxError = (error) => error instanceof APIError && (error.response.status === 404 || error.response.status === 410);
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
})
|
|
6
|
+
const tryVercelPromise = (body) => Effect.tryPromise({
|
|
7
|
+
try: body,
|
|
8
|
+
catch: (error) => error
|
|
9
|
+
});
|
|
10
|
+
const commandOutput = (command) => Effect.all({
|
|
11
|
+
stdout: tryVercelPromise(() => command.stdout()),
|
|
12
|
+
stderr: tryVercelPromise(() => command.stderr())
|
|
13
|
+
});
|
|
10
14
|
const toFinishedCommand = (command) => ({
|
|
11
15
|
id: command.cmdId,
|
|
12
16
|
exitCode: command.exitCode,
|
|
13
|
-
output:
|
|
17
|
+
output: commandOutput(command)
|
|
14
18
|
});
|
|
15
19
|
const toDetachedCommand = (command) => ({
|
|
16
20
|
id: command.cmdId,
|
|
17
21
|
exitCode: command.exitCode,
|
|
18
|
-
wait: () => command.wait().
|
|
19
|
-
kill: (signal) => command.kill(signal),
|
|
20
|
-
output:
|
|
22
|
+
wait: tryVercelPromise(() => command.wait()).pipe(Effect.map(toFinishedCommand)),
|
|
23
|
+
kill: (signal) => tryVercelPromise(() => command.kill(signal)),
|
|
24
|
+
output: commandOutput(command)
|
|
21
25
|
});
|
|
22
26
|
const toHandle = (sandbox) => ({
|
|
23
27
|
name: sandbox.name,
|
|
24
|
-
writeFiles: (files) => sandbox.writeFiles(files.map((file) => ({
|
|
28
|
+
writeFiles: (files) => tryVercelPromise(() => sandbox.writeFiles(files.map((file) => ({
|
|
25
29
|
path: file.path,
|
|
26
30
|
content: file.content,
|
|
27
31
|
...file.mode === void 0 ? {} : { mode: file.mode }
|
|
28
|
-
}))),
|
|
29
|
-
runDetachedCommand: (input) => sandbox.runCommand({
|
|
32
|
+
})))),
|
|
33
|
+
runDetachedCommand: (input) => tryVercelPromise(() => sandbox.runCommand({
|
|
30
34
|
cmd: input.cmd,
|
|
31
35
|
args: input.args === void 0 ? [] : [...input.args],
|
|
32
36
|
...input.cwd === void 0 ? {} : { cwd: input.cwd },
|
|
33
37
|
detached: true
|
|
34
|
-
}).
|
|
35
|
-
getCommand: (id) => sandbox.getCommand(id).
|
|
36
|
-
extendTimeout: (durationMs) => sandbox.extendTimeout(durationMs).
|
|
37
|
-
delete: () => sandbox.delete().
|
|
38
|
+
})).pipe(Effect.map(toDetachedCommand)),
|
|
39
|
+
getCommand: (id) => tryVercelPromise(() => sandbox.getCommand(id)).pipe(Effect.map(toDetachedCommand)),
|
|
40
|
+
extendTimeout: (durationMs) => tryVercelPromise(() => sandbox.extendTimeout(durationMs)).pipe(Effect.asVoid),
|
|
41
|
+
delete: tryVercelPromise(() => sandbox.delete()).pipe(Effect.asVoid),
|
|
38
42
|
domain: (port) => sandbox.domain(port)
|
|
39
43
|
});
|
|
40
44
|
const envObject = (env) => env === void 0 ? void 0 : Object.fromEntries(Object.entries(env));
|
|
@@ -101,11 +105,11 @@ const createSandbox = (input) => {
|
|
|
101
105
|
}
|
|
102
106
|
};
|
|
103
107
|
const VercelSandboxClientLive = Layer.succeed(VercelSandboxClient, VercelSandboxClient.of({
|
|
104
|
-
get: (input) => Sandbox.get({ name: input.name }).
|
|
105
|
-
if (isVercelMissingSandboxError(error)) return null;
|
|
106
|
-
|
|
107
|
-
}),
|
|
108
|
-
create: (input) => createSandbox(input).
|
|
108
|
+
get: (input) => tryVercelPromise(() => Sandbox.get({ name: input.name })).pipe(Effect.map(toHandle), Effect.catch((error) => {
|
|
109
|
+
if (isVercelMissingSandboxError(error)) return Effect.succeed(null);
|
|
110
|
+
return Effect.fail(error);
|
|
111
|
+
})),
|
|
112
|
+
create: (input) => tryVercelPromise(() => createSandbox(input)).pipe(Effect.map(toHandle))
|
|
109
113
|
}));
|
|
110
114
|
//#endregion
|
|
111
115
|
export { VercelSandboxClient, VercelSandboxClientLive, isVercelMissingSandboxError };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":["VercelSdkSandbox"],"sources":["../../src/vercel/client.ts"],"sourcesContent":["import { Context, Layer } from 'effect'\nimport {\n APIError,\n Sandbox as VercelSdkSandbox,\n type Command,\n type CommandFinished,\n type NetworkPolicy\n} from '@vercel/sandbox'\nimport type { SandboxInitialSource, SandboxResources, SandboxSnapshotRetention } from '../model.ts'\n\nexport type VercelSandboxRuntime = 'node22' | 'node24' | 'node26' | 'python3.13'\nexport type VercelNetworkPolicy = NetworkPolicy\n\nexport type VercelCommandOutput = {\n readonly stdout: string\n readonly stderr: string\n}\n\nexport type VercelCommandSignal = 'SIGTERM' | 'SIGKILL'\n\nexport type VercelFinishedCommand = {\n readonly id: string\n readonly exitCode: number\n readonly output: () => Promise<VercelCommandOutput>\n}\n\nexport type VercelDetachedCommand = {\n readonly id: string\n readonly exitCode: number | null\n readonly wait: () => Promise<VercelFinishedCommand>\n readonly kill: (signal: VercelCommandSignal) => Promise<void>\n readonly output: () => Promise<VercelCommandOutput>\n}\n\nexport type VercelSandboxFile = {\n readonly path: string\n readonly content: string\n readonly mode?: number\n}\n\nexport type VercelRunCommandInput = {\n readonly cmd: string\n readonly args?: ReadonlyArray<string>\n readonly cwd?: string\n}\n\nexport type VercelSandboxCreateInput = {\n readonly name: string\n readonly source: SandboxInitialSource\n readonly ports: ReadonlyArray<number>\n readonly timeoutMs: number\n readonly resources: SandboxResources\n readonly runtime: VercelSandboxRuntime\n readonly env?: Readonly<Record<string, string>>\n readonly persistent: boolean\n readonly snapshotExpirationMs?: number\n readonly keepLastSnapshots?: SandboxSnapshotRetention\n readonly networkPolicy?: VercelNetworkPolicy\n}\n\nexport type VercelSandboxGetInput = {\n readonly name: string\n}\n\nexport type VercelSandboxHandle = {\n readonly name: string\n readonly writeFiles: (files: ReadonlyArray<VercelSandboxFile>) => Promise<void>\n readonly runDetachedCommand: (input: VercelRunCommandInput) => Promise<VercelDetachedCommand>\n readonly getCommand: (id: string) => Promise<VercelDetachedCommand>\n readonly extendTimeout: (durationMs: number) => Promise<void>\n readonly delete: () => Promise<void>\n readonly domain: (port: number) => string\n}\n\nexport type VercelSandboxClientApi = {\n readonly get: (input: VercelSandboxGetInput) => Promise<VercelSandboxHandle | null>\n readonly create: (input: VercelSandboxCreateInput) => Promise<VercelSandboxHandle>\n}\n\nexport class VercelSandboxClient extends Context.Service<\n VercelSandboxClient,\n VercelSandboxClientApi\n>()('@yolk-sdk/sandbox/vercel/VercelSandboxClient') {}\n\nexport const isVercelMissingSandboxError = (error: unknown) =>\n error instanceof APIError && (error.response.status === 404 || error.response.status === 410)\n\nconst commandOutput = (command: Command | CommandFinished): Promise<VercelCommandOutput> =>\n Promise.all([command.stdout(), command.stderr()]).then(([stdout, stderr]) => ({ stdout, stderr }))\n\nconst toFinishedCommand = (command: CommandFinished): VercelFinishedCommand => ({\n id: command.cmdId,\n exitCode: command.exitCode,\n output: () => commandOutput(command)\n})\n\nconst toDetachedCommand = (command: Command): VercelDetachedCommand => ({\n id: command.cmdId,\n exitCode: command.exitCode,\n wait: () => command.wait().then(toFinishedCommand),\n kill: signal => command.kill(signal),\n output: () => commandOutput(command)\n})\n\nconst toHandle = (sandbox: VercelSdkSandbox): VercelSandboxHandle => ({\n name: sandbox.name,\n writeFiles: files =>\n sandbox.writeFiles(\n files.map(file => ({\n path: file.path,\n content: file.content,\n ...(file.mode === undefined ? {} : { mode: file.mode })\n }))\n ),\n runDetachedCommand: input =>\n sandbox\n .runCommand({\n cmd: input.cmd,\n args: input.args === undefined ? [] : [...input.args],\n ...(input.cwd === undefined ? {} : { cwd: input.cwd }),\n detached: true\n })\n .then(toDetachedCommand),\n getCommand: id => sandbox.getCommand(id).then(toDetachedCommand),\n extendTimeout: durationMs => sandbox.extendTimeout(durationMs).then(() => undefined),\n delete: () => sandbox.delete().then(() => undefined),\n domain: port => sandbox.domain(port)\n})\n\nconst envObject = (env?: Readonly<Record<string, string>>) =>\n env === undefined ? undefined : Object.fromEntries(Object.entries(env))\n\nconst retentionObject = (retention?: SandboxSnapshotRetention) =>\n retention === undefined\n ? undefined\n : {\n count: retention.count,\n ...(retention.expirationMs === undefined ? {} : { expiration: retention.expirationMs }),\n ...(retention.deleteEvicted === undefined ? {} : { deleteEvicted: retention.deleteEvicted })\n }\n\ntype AnonymousGitSource = {\n readonly type: 'git'\n readonly url: string\n readonly depth?: number\n readonly revision?: string\n}\n\ntype BasicAuthGitSource = AnonymousGitSource & {\n readonly username: string\n readonly password: string\n}\n\nconst commonCreateOptions = (input: VercelSandboxCreateInput) => ({\n name: input.name,\n ports: [...input.ports],\n timeout: input.timeoutMs,\n resources: { vcpus: input.resources.vcpus },\n env: envObject(input.env),\n persistent: input.persistent,\n networkPolicy: input.networkPolicy,\n snapshotExpiration: input.snapshotExpirationMs,\n keepLastSnapshots: retentionObject(input.keepLastSnapshots)\n})\n\nconst gitSource = (\n source: Extract<SandboxInitialSource, { readonly _tag: 'Git' }>\n): AnonymousGitSource | BasicAuthGitSource => {\n if ((source.username === undefined) !== (source.password === undefined)) {\n throw new Error('Vercel git source requires both username and password when using basic auth')\n }\n\n if (source.username !== undefined && source.password !== undefined) {\n return {\n type: 'git',\n url: source.url,\n username: source.username,\n password: source.password,\n ...(source.depth === undefined ? {} : { depth: source.depth }),\n ...(source.revision === undefined ? {} : { revision: source.revision })\n }\n }\n\n return {\n type: 'git',\n url: source.url,\n ...(source.depth === undefined ? {} : { depth: source.depth }),\n ...(source.revision === undefined ? {} : { revision: source.revision })\n }\n}\n\nconst createSandbox = (input: VercelSandboxCreateInput) => {\n const common = commonCreateOptions(input)\n\n switch (input.source._tag) {\n case 'Empty':\n return VercelSdkSandbox.create({\n ...common,\n runtime: input.runtime\n })\n case 'Snapshot':\n return VercelSdkSandbox.create({\n ...common,\n source: { type: 'snapshot', snapshotId: input.source.snapshotId }\n })\n case 'Git':\n return VercelSdkSandbox.create({\n ...common,\n runtime: input.runtime,\n source: gitSource(input.source)\n })\n case 'Tarball':\n return VercelSdkSandbox.create({\n ...common,\n runtime: input.runtime,\n source: { type: 'tarball', url: input.source.url }\n })\n }\n}\n\nexport const VercelSandboxClientLive = Layer.succeed(\n VercelSandboxClient,\n VercelSandboxClient.of({\n get: input =>\n VercelSdkSandbox.get({ name: input.name })\n .then(toHandle)\n .catch(error => {\n if (isVercelMissingSandboxError(error)) {\n return null\n }\n\n throw error\n }),\n create: input => createSandbox(input).then(toHandle)\n })\n)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.mjs","names":["VercelSdkSandbox"],"sources":["../../src/vercel/client.ts"],"sourcesContent":["import { Context, Effect, Layer } from 'effect'\nimport {\n APIError,\n Sandbox as VercelSdkSandbox,\n type Command,\n type CommandFinished,\n type NetworkPolicy\n} from '@vercel/sandbox'\nimport type { SandboxInitialSource, SandboxResources, SandboxSnapshotRetention } from '../model.ts'\n\nexport type VercelSandboxRuntime = 'node22' | 'node24' | 'node26' | 'python3.13'\nexport type VercelNetworkPolicy = NetworkPolicy\n\nexport type VercelCommandOutput = {\n readonly stdout: string\n readonly stderr: string\n}\n\nexport type VercelCommandSignal = 'SIGTERM' | 'SIGKILL'\n\nexport type VercelFinishedCommand = {\n readonly id: string\n readonly exitCode: number\n readonly output: Effect.Effect<VercelCommandOutput, unknown>\n}\n\nexport type VercelDetachedCommand = {\n readonly id: string\n readonly exitCode: number | null\n readonly wait: Effect.Effect<VercelFinishedCommand, unknown>\n readonly kill: (signal: VercelCommandSignal) => Effect.Effect<void, unknown>\n readonly output: Effect.Effect<VercelCommandOutput, unknown>\n}\n\nexport type VercelSandboxFile = {\n readonly path: string\n readonly content: string\n readonly mode?: number\n}\n\nexport type VercelRunCommandInput = {\n readonly cmd: string\n readonly args?: ReadonlyArray<string>\n readonly cwd?: string\n}\n\nexport type VercelSandboxCreateInput = {\n readonly name: string\n readonly source: SandboxInitialSource\n readonly ports: ReadonlyArray<number>\n readonly timeoutMs: number\n readonly resources: SandboxResources\n readonly runtime: VercelSandboxRuntime\n readonly env?: Readonly<Record<string, string>>\n readonly persistent: boolean\n readonly snapshotExpirationMs?: number\n readonly keepLastSnapshots?: SandboxSnapshotRetention\n readonly networkPolicy?: VercelNetworkPolicy\n}\n\nexport type VercelSandboxGetInput = {\n readonly name: string\n}\n\nexport type VercelSandboxHandle = {\n readonly name: string\n readonly writeFiles: (files: ReadonlyArray<VercelSandboxFile>) => Effect.Effect<void, unknown>\n readonly runDetachedCommand: (\n input: VercelRunCommandInput\n ) => Effect.Effect<VercelDetachedCommand, unknown>\n readonly getCommand: (id: string) => Effect.Effect<VercelDetachedCommand, unknown>\n readonly extendTimeout: (durationMs: number) => Effect.Effect<void, unknown>\n readonly delete: Effect.Effect<void, unknown>\n readonly domain: (port: number) => string\n}\n\nexport type VercelSandboxClientApi = {\n readonly get: (input: VercelSandboxGetInput) => Effect.Effect<VercelSandboxHandle | null, unknown>\n readonly create: (input: VercelSandboxCreateInput) => Effect.Effect<VercelSandboxHandle, unknown>\n}\n\nexport class VercelSandboxClient extends Context.Service<\n VercelSandboxClient,\n VercelSandboxClientApi\n>()('@yolk-sdk/sandbox/vercel/VercelSandboxClient') {}\n\nexport const isVercelMissingSandboxError = (error: unknown) =>\n error instanceof APIError && (error.response.status === 404 || error.response.status === 410)\n\nconst tryVercelPromise = <A>(body: () => Promise<A>) =>\n Effect.tryPromise({\n try: body,\n catch: error => error\n })\n\nconst commandOutput = (command: Command | CommandFinished): Effect.Effect<VercelCommandOutput, unknown> =>\n Effect.all({\n stdout: tryVercelPromise(() => command.stdout()),\n stderr: tryVercelPromise(() => command.stderr())\n })\n\nconst toFinishedCommand = (command: CommandFinished): VercelFinishedCommand => ({\n id: command.cmdId,\n exitCode: command.exitCode,\n output: commandOutput(command)\n})\n\nconst toDetachedCommand = (command: Command): VercelDetachedCommand => ({\n id: command.cmdId,\n exitCode: command.exitCode,\n wait: tryVercelPromise(() => command.wait()).pipe(Effect.map(toFinishedCommand)),\n kill: signal => tryVercelPromise(() => command.kill(signal)),\n output: commandOutput(command)\n})\n\nconst toHandle = (sandbox: VercelSdkSandbox): VercelSandboxHandle => ({\n name: sandbox.name,\n writeFiles: files =>\n tryVercelPromise(() =>\n sandbox.writeFiles(\n files.map(file => ({\n path: file.path,\n content: file.content,\n ...(file.mode === undefined ? {} : { mode: file.mode })\n }))\n )\n ),\n runDetachedCommand: input =>\n tryVercelPromise(() =>\n sandbox.runCommand({\n cmd: input.cmd,\n args: input.args === undefined ? [] : [...input.args],\n ...(input.cwd === undefined ? {} : { cwd: input.cwd }),\n detached: true\n })\n ).pipe(Effect.map(toDetachedCommand)),\n getCommand: id => tryVercelPromise(() => sandbox.getCommand(id)).pipe(Effect.map(toDetachedCommand)),\n extendTimeout: durationMs =>\n tryVercelPromise(() => sandbox.extendTimeout(durationMs)).pipe(Effect.asVoid),\n delete: tryVercelPromise(() => sandbox.delete()).pipe(Effect.asVoid),\n domain: port => sandbox.domain(port)\n})\n\nconst envObject = (env?: Readonly<Record<string, string>>) =>\n env === undefined ? undefined : Object.fromEntries(Object.entries(env))\n\nconst retentionObject = (retention?: SandboxSnapshotRetention) =>\n retention === undefined\n ? undefined\n : {\n count: retention.count,\n ...(retention.expirationMs === undefined ? {} : { expiration: retention.expirationMs }),\n ...(retention.deleteEvicted === undefined ? {} : { deleteEvicted: retention.deleteEvicted })\n }\n\ntype AnonymousGitSource = {\n readonly type: 'git'\n readonly url: string\n readonly depth?: number\n readonly revision?: string\n}\n\ntype BasicAuthGitSource = AnonymousGitSource & {\n readonly username: string\n readonly password: string\n}\n\nconst commonCreateOptions = (input: VercelSandboxCreateInput) => ({\n name: input.name,\n ports: [...input.ports],\n timeout: input.timeoutMs,\n resources: { vcpus: input.resources.vcpus },\n env: envObject(input.env),\n persistent: input.persistent,\n networkPolicy: input.networkPolicy,\n snapshotExpiration: input.snapshotExpirationMs,\n keepLastSnapshots: retentionObject(input.keepLastSnapshots)\n})\n\nconst gitSource = (\n source: Extract<SandboxInitialSource, { readonly _tag: 'Git' }>\n): AnonymousGitSource | BasicAuthGitSource => {\n if ((source.username === undefined) !== (source.password === undefined)) {\n throw new Error('Vercel git source requires both username and password when using basic auth')\n }\n\n if (source.username !== undefined && source.password !== undefined) {\n return {\n type: 'git',\n url: source.url,\n username: source.username,\n password: source.password,\n ...(source.depth === undefined ? {} : { depth: source.depth }),\n ...(source.revision === undefined ? {} : { revision: source.revision })\n }\n }\n\n return {\n type: 'git',\n url: source.url,\n ...(source.depth === undefined ? {} : { depth: source.depth }),\n ...(source.revision === undefined ? {} : { revision: source.revision })\n }\n}\n\nconst createSandbox = (input: VercelSandboxCreateInput) => {\n const common = commonCreateOptions(input)\n\n switch (input.source._tag) {\n case 'Empty':\n return VercelSdkSandbox.create({\n ...common,\n runtime: input.runtime\n })\n case 'Snapshot':\n return VercelSdkSandbox.create({\n ...common,\n source: { type: 'snapshot', snapshotId: input.source.snapshotId }\n })\n case 'Git':\n return VercelSdkSandbox.create({\n ...common,\n runtime: input.runtime,\n source: gitSource(input.source)\n })\n case 'Tarball':\n return VercelSdkSandbox.create({\n ...common,\n runtime: input.runtime,\n source: { type: 'tarball', url: input.source.url }\n })\n }\n}\n\nexport const VercelSandboxClientLive = Layer.succeed(\n VercelSandboxClient,\n VercelSandboxClient.of({\n get: input =>\n tryVercelPromise(() => VercelSdkSandbox.get({ name: input.name })).pipe(\n Effect.map(toHandle),\n Effect.catch((error: unknown) => {\n if (isVercelMissingSandboxError(error)) {\n return Effect.succeed(null)\n }\n\n return Effect.fail(error)\n })\n ),\n create: input => tryVercelPromise(() => createSandbox(input)).pipe(Effect.map(toHandle))\n })\n)\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer.d.mts","names":[],"sources":["../../src/vercel/layer.ts"],"mappings":";;;;;;;KAuCY,wBAAA;EAAA,SACD,gBAAA;EAAA,SACA,SAAA,GAAY,gBAAA;EAAA,SACZ,MAAA,GAAS,oBAAA;EAAA,SACT,GAAA,GAAM,QAAA,CAAS,MAAA;EAAA,SACf,KAAA,GAAQ,aAAA;EAAA,SACR,SAAA,GAAY,gBAAA;EAAA,SACZ,OAAA,GAAU,oBAAA;EAAA,SACV,aAAA,GAAgB,mBAAA;EAAA,SAChB,aAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"layer.d.mts","names":[],"sources":["../../src/vercel/layer.ts"],"mappings":";;;;;;;KAuCY,wBAAA;EAAA,SACD,gBAAA;EAAA,SACA,SAAA,GAAY,gBAAA;EAAA,SACZ,MAAA,GAAS,oBAAA;EAAA,SACT,GAAA,GAAM,QAAA,CAAS,MAAA;EAAA,SACf,KAAA,GAAQ,aAAA;EAAA,SACR,SAAA,GAAY,gBAAA;EAAA,SACZ,OAAA,GAAU,oBAAA;EAAA,SACV,aAAA,GAAgB,mBAAA;EAAA,SAChB,aAAA;AAAA;AAAA,cAiLE,gCAAA,GAAoC,MAAA,EAAQ,wBAAA,KAAwB,KAAA,CAAA,KAAA,CAAA,OAAA,SAAA,iBAAA,GAAA,mBAAA;AAAA,cA0MpE,sBAAA,GAA0B,MAAA,EAAQ,wBAAA,KAAwB,KAAA,CAAA,KAAA,CAAA,OAAA,SAAA,iBAAA"}
|
package/dist/vercel/layer.mjs
CHANGED
|
@@ -15,10 +15,7 @@ const providerError = (operation, error) => new SandboxProviderError({
|
|
|
15
15
|
message: `Vercel Sandbox ${operation} failed: ${unknownToMessage(error)}`,
|
|
16
16
|
underlying: error
|
|
17
17
|
});
|
|
18
|
-
const tryProvider = (operation,
|
|
19
|
-
try: body,
|
|
20
|
-
catch: (error) => providerError(operation, error)
|
|
21
|
-
});
|
|
18
|
+
const tryProvider = (operation, effect) => effect.pipe(Effect.mapError((error) => providerError(operation, error)));
|
|
22
19
|
const lifecycleTimeoutMs = (lifecycle) => {
|
|
23
20
|
switch (lifecycle._tag) {
|
|
24
21
|
case "Disposable": return Math.min(lifecycle.idleTtlMs, lifecycle.maxLifetimeMs);
|
|
@@ -54,7 +51,7 @@ const waitForegroundCommand = (command, timeoutMs) => tryProvider("command.wait"
|
|
|
54
51
|
})))), Effect.timeoutOrElse({
|
|
55
52
|
duration: Duration.millis(timeoutMs),
|
|
56
53
|
orElse: () => Effect.gen(function* () {
|
|
57
|
-
yield* tryProvider("command.kill",
|
|
54
|
+
yield* tryProvider("command.kill", command.kill("SIGKILL")).pipe(Effect.catchTag("SandboxProviderError", () => Effect.void));
|
|
58
55
|
const output = yield* commandOutputOrEmpty(command);
|
|
59
56
|
return {
|
|
60
57
|
exitCode: null,
|
|
@@ -64,7 +61,7 @@ const waitForegroundCommand = (command, timeoutMs) => tryProvider("command.wait"
|
|
|
64
61
|
};
|
|
65
62
|
})
|
|
66
63
|
}));
|
|
67
|
-
const probeBackgroundCommand = (handle, command) => Effect.sleep(Duration.millis(backgroundSandboxProbeMs)).pipe(Effect.flatMap(() => tryProvider("command.get",
|
|
64
|
+
const probeBackgroundCommand = (handle, command) => Effect.sleep(Duration.millis(backgroundSandboxProbeMs)).pipe(Effect.flatMap(() => tryProvider("command.get", handle.getCommand(command.id))), Effect.flatMap((current) => {
|
|
68
65
|
if (current.exitCode === null) return Effect.succeed({
|
|
69
66
|
exitCode: null,
|
|
70
67
|
stdout: "",
|
|
@@ -116,9 +113,9 @@ const makeVercelSandboxLayerWithClient = (config) => Layer.effect(Sandbox, Effec
|
|
|
116
113
|
const runtime = config.runtime ?? defaultVercelRuntime;
|
|
117
114
|
const workspaceRoot = config.workspaceRoot ?? "/vercel/sandbox";
|
|
118
115
|
const name = makeVercelSandboxName(config.sandboxSessionId);
|
|
119
|
-
const deleteNamedSandbox = (sandboxName) => tryProvider("get",
|
|
116
|
+
const deleteNamedSandbox = (sandboxName) => tryProvider("get", client.get({ name: sandboxName })).pipe(Effect.flatMap((handle) => handle === null ? Effect.void : tryProvider("delete", handle.delete)));
|
|
120
117
|
const createSandbox = (input) => Effect.gen(function* () {
|
|
121
|
-
const handle = yield* tryProvider("create",
|
|
118
|
+
const handle = yield* tryProvider("create", client.create({
|
|
122
119
|
name,
|
|
123
120
|
source,
|
|
124
121
|
ports,
|
|
@@ -163,7 +160,7 @@ const makeVercelSandboxLayerWithClient = (config) => Layer.effect(Sandbox, Effec
|
|
|
163
160
|
};
|
|
164
161
|
});
|
|
165
162
|
const attachOrCreateSandbox = (input) => Effect.gen(function* () {
|
|
166
|
-
const handle = yield* tryProvider("get",
|
|
163
|
+
const handle = yield* tryProvider("get", client.get({ name }));
|
|
167
164
|
if (handle !== null) return yield* attachExistingSandbox({
|
|
168
165
|
handle,
|
|
169
166
|
nowMs: input.nowMs
|
|
@@ -180,7 +177,7 @@ const makeVercelSandboxLayerWithClient = (config) => Layer.effect(Sandbox, Effec
|
|
|
180
177
|
before: input.state,
|
|
181
178
|
after: touched
|
|
182
179
|
});
|
|
183
|
-
if (deltaMs > 0) yield* tryProvider("extendTimeout",
|
|
180
|
+
if (deltaMs > 0) yield* tryProvider("extendTimeout", input.handle.extendTimeout(deltaMs));
|
|
184
181
|
yield* store.save({
|
|
185
182
|
sandboxSessionId: config.sandboxSessionId,
|
|
186
183
|
state: touched
|
|
@@ -212,7 +209,7 @@ const makeVercelSandboxLayerWithClient = (config) => Layer.effect(Sandbox, Effec
|
|
|
212
209
|
workspaceReset: decision.workspaceReset
|
|
213
210
|
});
|
|
214
211
|
}
|
|
215
|
-
const handle = yield* tryProvider("get",
|
|
212
|
+
const handle = yield* tryProvider("get", client.get({ name }));
|
|
216
213
|
if (handle === null) {
|
|
217
214
|
yield* store.clear(config.sandboxSessionId);
|
|
218
215
|
return yield* createSandbox({
|
|
@@ -239,9 +236,9 @@ const makeVercelSandboxLayerWithClient = (config) => Layer.effect(Sandbox, Effec
|
|
|
239
236
|
command: input.command,
|
|
240
237
|
stdin: input.stdin
|
|
241
238
|
});
|
|
242
|
-
yield* tryProvider("writeFiles",
|
|
239
|
+
yield* tryProvider("writeFiles", active.handle.writeFiles(commandFiles.files));
|
|
243
240
|
const startedAtMs = yield* Clock.currentTimeMillis;
|
|
244
|
-
const command = yield* tryProvider("runCommand",
|
|
241
|
+
const command = yield* tryProvider("runCommand", active.handle.runDetachedCommand({
|
|
245
242
|
cmd: "bash",
|
|
246
243
|
args: [commandFiles.wrapperPath],
|
|
247
244
|
cwd: absoluteSandboxCwd(workspaceRoot, normalizedCwd)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer.mjs","names":["Arr"],"sources":["../../src/vercel/layer.ts"],"sourcesContent":["import { Array as Arr, Clock, Duration, Effect, Layer, Option, Ref, Semaphore } from 'effect'\nimport {\n absoluteSandboxCwd,\n backgroundSandboxProbeMs,\n defaultSandboxPorts,\n defaultSandboxWorkspaceRoot,\n initialSandboxState,\n normalizeWorkspaceCwd,\n sandboxCommandTimeoutMs,\n sandboxLifecycleOrDefault,\n sandboxSourceOrDefault,\n sandboxStateDecision,\n sandboxTimeoutExtendDeltaMs,\n touchSandboxState,\n validateSandboxCommand\n} from '../lifecycle.ts'\nimport { makeVercelSandboxName } from '../name.ts'\nimport {\n SandboxCommandResult,\n type SandboxCommandInput,\n SandboxPreviewUrl,\n SandboxResources,\n type SandboxInitialSource,\n type SandboxLifecycle,\n type SandboxState\n} from '../model.ts'\nimport { Sandbox } from '../service.ts'\nimport { SandboxStateStore } from '../state-store.ts'\nimport { SandboxProviderError, unknownToMessage } from '../errors.ts'\nimport type { SandboxError } from '../errors.ts'\nimport {\n VercelSandboxClient,\n VercelSandboxClientLive,\n type VercelDetachedCommand,\n type VercelNetworkPolicy,\n type VercelSandboxHandle,\n type VercelSandboxRuntime\n} from './client.ts'\n\nexport type VercelSandboxLayerConfig = {\n readonly sandboxSessionId: string\n readonly lifecycle?: SandboxLifecycle\n readonly source?: SandboxInitialSource\n readonly env?: Readonly<Record<string, string>>\n readonly ports?: ReadonlyArray<number>\n readonly resources?: SandboxResources\n readonly runtime?: VercelSandboxRuntime\n readonly networkPolicy?: VercelNetworkPolicy\n readonly workspaceRoot?: string\n}\n\ntype ActiveSandbox = {\n readonly handle: VercelSandboxHandle\n readonly state: SandboxState\n readonly workspaceReset: boolean\n}\n\ntype CommandRunOutput = {\n readonly exitCode: number | null\n readonly stdout: string\n readonly stderr: string\n readonly timedOut: boolean\n readonly backgroundId?: string\n}\n\nconst defaultVercelResources = SandboxResources.make({ vcpus: 2 })\nconst defaultVercelRuntime: VercelSandboxRuntime = 'node24'\n\nconst providerError = (operation: string, error: unknown) =>\n new SandboxProviderError({\n provider: 'vercel',\n operation,\n message: `Vercel Sandbox ${operation} failed: ${unknownToMessage(error)}`,\n underlying: error\n })\n\nconst tryProvider = <A>(operation: string, body: () => Promise<A>) =>\n Effect.tryPromise({\n try: body,\n catch: error => providerError(operation, error)\n })\n\nconst lifecycleTimeoutMs = (lifecycle: SandboxLifecycle) => {\n switch (lifecycle._tag) {\n case 'Disposable':\n return Math.min(lifecycle.idleTtlMs, lifecycle.maxLifetimeMs)\n case 'Persistent':\n return lifecycle.idleTtlMs\n }\n}\n\nconst persistentFlag = (lifecycle: SandboxLifecycle) => lifecycle._tag === 'Persistent'\n\nconst snapshotExpirationMs = (lifecycle: SandboxLifecycle) =>\n lifecycle._tag === 'Persistent' ? lifecycle.snapshotExpirationMs : undefined\n\nconst keepLastSnapshots = (lifecycle: SandboxLifecycle) =>\n lifecycle._tag === 'Persistent' ? lifecycle.keepLastSnapshots : undefined\n\nconst previewUrls = (handle: VercelSandboxHandle, ports: ReadonlyArray<number>) =>\n Effect.forEach(ports, port =>\n Effect.try({\n try: () => handle.domain(port),\n catch: error => error\n }).pipe(\n Effect.match({\n onFailure: () => Option.none<SandboxPreviewUrl>(),\n onSuccess: url => Option.some(SandboxPreviewUrl.make({ port, url }))\n })\n )\n ).pipe(Effect.map(Arr.getSomes))\n\nconst commandOutputOrEmpty = (command: VercelDetachedCommand) =>\n tryProvider('command.output', command.output).pipe(\n Effect.catchTag('SandboxProviderError', error =>\n Effect.succeed({\n stdout: '',\n stderr: error.message\n })\n )\n )\n\nconst finishedCommandOutputOrEmpty = (command: {\n readonly output: () => Promise<{ readonly stdout: string; readonly stderr: string }>\n}) =>\n tryProvider('command.output', command.output).pipe(\n Effect.catchTag('SandboxProviderError', error =>\n Effect.succeed({\n stdout: '',\n stderr: error.message\n })\n )\n )\n\nconst waitForegroundCommand = (\n command: VercelDetachedCommand,\n timeoutMs: number\n): Effect.Effect<CommandRunOutput, SandboxProviderError> =>\n tryProvider('command.wait', command.wait).pipe(\n Effect.flatMap(finished =>\n finishedCommandOutputOrEmpty(finished).pipe(\n Effect.map(output => ({\n exitCode: finished.exitCode,\n stdout: output.stdout,\n stderr: output.stderr,\n timedOut: false\n }))\n )\n ),\n Effect.timeoutOrElse({\n duration: Duration.millis(timeoutMs),\n orElse: () =>\n Effect.gen(function* () {\n yield* tryProvider('command.kill', () => command.kill('SIGKILL')).pipe(\n Effect.catchTag('SandboxProviderError', () => Effect.void)\n )\n const output = yield* commandOutputOrEmpty(command)\n\n return {\n exitCode: null,\n stdout: output.stdout,\n stderr: output.stderr,\n timedOut: true\n }\n })\n })\n )\n\nconst probeBackgroundCommand = (\n handle: VercelSandboxHandle,\n command: VercelDetachedCommand\n): Effect.Effect<CommandRunOutput, SandboxProviderError> =>\n Effect.sleep(Duration.millis(backgroundSandboxProbeMs)).pipe(\n Effect.flatMap(() => tryProvider('command.get', () => handle.getCommand(command.id))),\n Effect.flatMap(current => {\n if (current.exitCode === null) {\n return Effect.succeed({\n exitCode: null,\n stdout: '',\n stderr: '',\n timedOut: false,\n backgroundId: command.id\n })\n }\n\n return commandOutputOrEmpty(current).pipe(\n Effect.map(output => ({\n exitCode: current.exitCode,\n stdout: output.stdout,\n stderr: output.stderr,\n timedOut: false\n }))\n )\n })\n )\n\nconst createCommandFiles = (input: {\n readonly commandId: string\n readonly workspaceRoot: string\n readonly command: string\n readonly stdin?: string\n}) => {\n const commandDir = `${input.workspaceRoot}/.yolk/commands/${input.commandId}`\n const commandPath = `${commandDir}/command.sh`\n const stdinPath = `${commandDir}/stdin.txt`\n const wrapperPath = `${commandDir}/wrapper.sh`\n\n return {\n wrapperPath,\n files: [\n {\n path: commandPath,\n content: `#!/usr/bin/env bash\\n${input.command}\\n`,\n mode: 0o755\n },\n {\n path: stdinPath,\n content: input.stdin ?? ''\n },\n {\n path: wrapperPath,\n content: `#!/usr/bin/env bash\\nbash ${JSON.stringify(commandPath)} < ${JSON.stringify(stdinPath)}\\n`,\n mode: 0o755\n }\n ]\n }\n}\n\nexport const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfig) =>\n Layer.effect(\n Sandbox,\n Effect.gen(function* () {\n const store = yield* SandboxStateStore\n const client = yield* VercelSandboxClient\n const semaphore = yield* Semaphore.make(1)\n const commandCounter = yield* Ref.make(0)\n const lifecycle = sandboxLifecycleOrDefault(config.lifecycle)\n const source = sandboxSourceOrDefault(config.source)\n const ports = config.ports ?? defaultSandboxPorts\n const resources = config.resources ?? defaultVercelResources\n const runtime = config.runtime ?? defaultVercelRuntime\n const workspaceRoot = config.workspaceRoot ?? defaultSandboxWorkspaceRoot\n const name = makeVercelSandboxName(config.sandboxSessionId)\n\n const deleteNamedSandbox = (sandboxName: string) =>\n tryProvider('get', () => client.get({ name: sandboxName })).pipe(\n Effect.flatMap(handle =>\n handle === null ? Effect.void : tryProvider('delete', () => handle.delete())\n )\n )\n\n const createSandbox = (input: { readonly nowMs: number; readonly workspaceReset: boolean }) =>\n Effect.gen(function* () {\n const handle = yield* tryProvider('create', () =>\n client.create({\n name,\n source,\n ports,\n timeoutMs: lifecycleTimeoutMs(lifecycle),\n resources,\n runtime,\n env: config.env,\n persistent: persistentFlag(lifecycle),\n snapshotExpirationMs: snapshotExpirationMs(lifecycle),\n keepLastSnapshots: keepLastSnapshots(lifecycle),\n networkPolicy: config.networkPolicy\n })\n )\n const state = initialSandboxState({ name, nowMs: input.nowMs, lifecycle })\n yield* store.save({ sandboxSessionId: config.sandboxSessionId, state })\n\n return { handle, state, workspaceReset: input.workspaceReset }\n })\n\n const attachExistingSandbox = (input: {\n readonly handle: VercelSandboxHandle\n readonly nowMs: number\n }) =>\n Effect.gen(function* () {\n const state = initialSandboxState({ name, nowMs: input.nowMs, lifecycle })\n yield* store.save({ sandboxSessionId: config.sandboxSessionId, state })\n\n return {\n handle: input.handle,\n state,\n workspaceReset: false\n }\n })\n\n const attachOrCreateSandbox = (input: {\n readonly nowMs: number\n readonly workspaceReset: boolean\n }) =>\n Effect.gen(function* () {\n const handle = yield* tryProvider('get', () => client.get({ name }))\n\n if (handle !== null) {\n return yield* attachExistingSandbox({ handle, nowMs: input.nowMs })\n }\n\n return yield* createSandbox(input)\n })\n\n const touchExistingSandbox = (input: {\n readonly handle: VercelSandboxHandle\n readonly state: SandboxState\n readonly nowMs: number\n readonly workspaceReset: boolean\n }) =>\n Effect.gen(function* () {\n const touched = touchSandboxState({\n state: input.state,\n nowMs: input.nowMs,\n lifecycle\n })\n const deltaMs = sandboxTimeoutExtendDeltaMs({ before: input.state, after: touched })\n\n if (deltaMs > 0) {\n yield* tryProvider('extendTimeout', () => input.handle.extendTimeout(deltaMs))\n }\n\n yield* store.save({ sandboxSessionId: config.sandboxSessionId, state: touched })\n\n return {\n handle: input.handle,\n state: touched,\n workspaceReset: input.workspaceReset\n }\n })\n\n const ensureSandbox = (nowMs: number): Effect.Effect<ActiveSandbox, SandboxError> =>\n Effect.gen(function* () {\n const loaded = yield* store.load(config.sandboxSessionId)\n const decision = sandboxStateDecision({ state: loaded, name, nowMs })\n\n if (decision._tag === 'Create') {\n if (Option.isNone(loaded)) {\n return yield* attachOrCreateSandbox({\n nowMs,\n workspaceReset: decision.workspaceReset\n })\n }\n\n if (Option.isSome(loaded) && decision.workspaceReset) {\n yield* deleteNamedSandbox(loaded.value.name)\n yield* store.clear(config.sandboxSessionId)\n }\n\n return yield* createSandbox({ nowMs, workspaceReset: decision.workspaceReset })\n }\n\n const handle = yield* tryProvider('get', () => client.get({ name }))\n\n if (handle === null) {\n yield* store.clear(config.sandboxSessionId)\n return yield* createSandbox({ nowMs, workspaceReset: true })\n }\n\n return yield* touchExistingSandbox({\n handle,\n state: decision.state,\n nowMs,\n workspaceReset: false\n })\n })\n\n const nextCommandId = Ref.updateAndGet(commandCounter, value => value + 1).pipe(\n Effect.map(value => `command-${value}`)\n )\n\n const runUnlocked = (input: SandboxCommandInput) =>\n Effect.gen(function* () {\n yield* validateSandboxCommand(input.command)\n const normalizedCwd = yield* normalizeWorkspaceCwd(input.cwd)\n const timeoutMs = sandboxCommandTimeoutMs(input.timeoutMs)\n const nowMs = yield* Clock.currentTimeMillis\n const active = yield* ensureSandbox(nowMs)\n const id = yield* nextCommandId\n const commandFiles = createCommandFiles({\n commandId: id,\n workspaceRoot,\n command: input.command,\n stdin: input.stdin\n })\n\n yield* tryProvider('writeFiles', () => active.handle.writeFiles(commandFiles.files))\n\n const startedAtMs = yield* Clock.currentTimeMillis\n const command = yield* tryProvider('runCommand', () =>\n active.handle.runDetachedCommand({\n cmd: 'bash',\n args: [commandFiles.wrapperPath],\n cwd: absoluteSandboxCwd(workspaceRoot, normalizedCwd)\n })\n )\n const output = yield* input.background === true\n ? probeBackgroundCommand(active.handle, command)\n : waitForegroundCommand(command, timeoutMs)\n const endedAtMs = yield* Clock.currentTimeMillis\n const urls = yield* previewUrls(active.handle, ports)\n\n return SandboxCommandResult.make({\n exitCode: output.exitCode,\n stdout: output.stdout,\n stderr: output.stderr,\n durationMs: Math.max(0, endedAtMs - startedAtMs),\n timedOut: output.timedOut,\n workspaceReset: active.workspaceReset,\n ...(output.backgroundId === undefined ? {} : { backgroundId: output.backgroundId }),\n previewUrls: urls,\n state: active.state\n })\n })\n\n return Sandbox.of({\n run: input => semaphore.withPermits(1)(runUnlocked(input)),\n currentState: store.load(config.sandboxSessionId),\n delete: Effect.gen(function* () {\n const loaded = yield* store.load(config.sandboxSessionId)\n if (Option.isSome(loaded)) {\n yield* deleteNamedSandbox(loaded.value.name)\n }\n yield* store.clear(config.sandboxSessionId)\n })\n })\n })\n )\n\nexport const makeVercelSandboxLayer = (config: VercelSandboxLayerConfig) =>\n makeVercelSandboxLayerWithClient(config).pipe(Layer.provide(VercelSandboxClientLive))\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"layer.mjs","names":["Arr"],"sources":["../../src/vercel/layer.ts"],"sourcesContent":["import { Array as Arr, Clock, Duration, Effect, Layer, Option, Ref, Semaphore } from 'effect'\nimport {\n absoluteSandboxCwd,\n backgroundSandboxProbeMs,\n defaultSandboxPorts,\n defaultSandboxWorkspaceRoot,\n initialSandboxState,\n normalizeWorkspaceCwd,\n sandboxCommandTimeoutMs,\n sandboxLifecycleOrDefault,\n sandboxSourceOrDefault,\n sandboxStateDecision,\n sandboxTimeoutExtendDeltaMs,\n touchSandboxState,\n validateSandboxCommand\n} from '../lifecycle.ts'\nimport { makeVercelSandboxName } from '../name.ts'\nimport {\n SandboxCommandResult,\n type SandboxCommandInput,\n SandboxPreviewUrl,\n SandboxResources,\n type SandboxInitialSource,\n type SandboxLifecycle,\n type SandboxState\n} from '../model.ts'\nimport { Sandbox } from '../service.ts'\nimport { SandboxStateStore } from '../state-store.ts'\nimport { SandboxProviderError, unknownToMessage } from '../errors.ts'\nimport type { SandboxError } from '../errors.ts'\nimport {\n VercelSandboxClient,\n VercelSandboxClientLive,\n type VercelDetachedCommand,\n type VercelNetworkPolicy,\n type VercelSandboxHandle,\n type VercelSandboxRuntime\n} from './client.ts'\n\nexport type VercelSandboxLayerConfig = {\n readonly sandboxSessionId: string\n readonly lifecycle?: SandboxLifecycle\n readonly source?: SandboxInitialSource\n readonly env?: Readonly<Record<string, string>>\n readonly ports?: ReadonlyArray<number>\n readonly resources?: SandboxResources\n readonly runtime?: VercelSandboxRuntime\n readonly networkPolicy?: VercelNetworkPolicy\n readonly workspaceRoot?: string\n}\n\ntype ActiveSandbox = {\n readonly handle: VercelSandboxHandle\n readonly state: SandboxState\n readonly workspaceReset: boolean\n}\n\ntype CommandRunOutput = {\n readonly exitCode: number | null\n readonly stdout: string\n readonly stderr: string\n readonly timedOut: boolean\n readonly backgroundId?: string\n}\n\nconst defaultVercelResources = SandboxResources.make({ vcpus: 2 })\nconst defaultVercelRuntime: VercelSandboxRuntime = 'node24'\n\nconst providerError = (operation: string, error: unknown) =>\n new SandboxProviderError({\n provider: 'vercel',\n operation,\n message: `Vercel Sandbox ${operation} failed: ${unknownToMessage(error)}`,\n underlying: error\n })\n\nconst tryProvider = <A>(operation: string, effect: Effect.Effect<A, unknown>) =>\n effect.pipe(Effect.mapError(error => providerError(operation, error)))\n\nconst lifecycleTimeoutMs = (lifecycle: SandboxLifecycle) => {\n switch (lifecycle._tag) {\n case 'Disposable':\n return Math.min(lifecycle.idleTtlMs, lifecycle.maxLifetimeMs)\n case 'Persistent':\n return lifecycle.idleTtlMs\n }\n}\n\nconst persistentFlag = (lifecycle: SandboxLifecycle) => lifecycle._tag === 'Persistent'\n\nconst snapshotExpirationMs = (lifecycle: SandboxLifecycle) =>\n lifecycle._tag === 'Persistent' ? lifecycle.snapshotExpirationMs : undefined\n\nconst keepLastSnapshots = (lifecycle: SandboxLifecycle) =>\n lifecycle._tag === 'Persistent' ? lifecycle.keepLastSnapshots : undefined\n\nconst previewUrls = (handle: VercelSandboxHandle, ports: ReadonlyArray<number>) =>\n Effect.forEach(ports, port =>\n Effect.try({\n try: () => handle.domain(port),\n catch: error => error\n }).pipe(\n Effect.match({\n onFailure: () => Option.none<SandboxPreviewUrl>(),\n onSuccess: url => Option.some(SandboxPreviewUrl.make({ port, url }))\n })\n )\n ).pipe(Effect.map(Arr.getSomes))\n\nconst commandOutputOrEmpty = (command: VercelDetachedCommand) =>\n tryProvider('command.output', command.output).pipe(\n Effect.catchTag('SandboxProviderError', error =>\n Effect.succeed({\n stdout: '',\n stderr: error.message\n })\n )\n )\n\nconst finishedCommandOutputOrEmpty = (command: {\n readonly output: Effect.Effect<{ readonly stdout: string; readonly stderr: string }, unknown>\n}) =>\n tryProvider('command.output', command.output).pipe(\n Effect.catchTag('SandboxProviderError', error =>\n Effect.succeed({\n stdout: '',\n stderr: error.message\n })\n )\n )\n\nconst waitForegroundCommand = (\n command: VercelDetachedCommand,\n timeoutMs: number\n): Effect.Effect<CommandRunOutput, SandboxProviderError> =>\n tryProvider('command.wait', command.wait).pipe(\n Effect.flatMap(finished =>\n finishedCommandOutputOrEmpty(finished).pipe(\n Effect.map(output => ({\n exitCode: finished.exitCode,\n stdout: output.stdout,\n stderr: output.stderr,\n timedOut: false\n }))\n )\n ),\n Effect.timeoutOrElse({\n duration: Duration.millis(timeoutMs),\n orElse: () =>\n Effect.gen(function* () {\n yield* tryProvider('command.kill', command.kill('SIGKILL')).pipe(\n Effect.catchTag('SandboxProviderError', () => Effect.void)\n )\n const output = yield* commandOutputOrEmpty(command)\n\n return {\n exitCode: null,\n stdout: output.stdout,\n stderr: output.stderr,\n timedOut: true\n }\n })\n })\n )\n\nconst probeBackgroundCommand = (\n handle: VercelSandboxHandle,\n command: VercelDetachedCommand\n): Effect.Effect<CommandRunOutput, SandboxProviderError> =>\n Effect.sleep(Duration.millis(backgroundSandboxProbeMs)).pipe(\n Effect.flatMap(() => tryProvider('command.get', handle.getCommand(command.id))),\n Effect.flatMap(current => {\n if (current.exitCode === null) {\n return Effect.succeed({\n exitCode: null,\n stdout: '',\n stderr: '',\n timedOut: false,\n backgroundId: command.id\n })\n }\n\n return commandOutputOrEmpty(current).pipe(\n Effect.map(output => ({\n exitCode: current.exitCode,\n stdout: output.stdout,\n stderr: output.stderr,\n timedOut: false\n }))\n )\n })\n )\n\nconst createCommandFiles = (input: {\n readonly commandId: string\n readonly workspaceRoot: string\n readonly command: string\n readonly stdin?: string\n}) => {\n const commandDir = `${input.workspaceRoot}/.yolk/commands/${input.commandId}`\n const commandPath = `${commandDir}/command.sh`\n const stdinPath = `${commandDir}/stdin.txt`\n const wrapperPath = `${commandDir}/wrapper.sh`\n\n return {\n wrapperPath,\n files: [\n {\n path: commandPath,\n content: `#!/usr/bin/env bash\\n${input.command}\\n`,\n mode: 0o755\n },\n {\n path: stdinPath,\n content: input.stdin ?? ''\n },\n {\n path: wrapperPath,\n content: `#!/usr/bin/env bash\\nbash ${JSON.stringify(commandPath)} < ${JSON.stringify(stdinPath)}\\n`,\n mode: 0o755\n }\n ]\n }\n}\n\nexport const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfig) =>\n Layer.effect(\n Sandbox,\n Effect.gen(function* () {\n const store = yield* SandboxStateStore\n const client = yield* VercelSandboxClient\n const semaphore = yield* Semaphore.make(1)\n const commandCounter = yield* Ref.make(0)\n const lifecycle = sandboxLifecycleOrDefault(config.lifecycle)\n const source = sandboxSourceOrDefault(config.source)\n const ports = config.ports ?? defaultSandboxPorts\n const resources = config.resources ?? defaultVercelResources\n const runtime = config.runtime ?? defaultVercelRuntime\n const workspaceRoot = config.workspaceRoot ?? defaultSandboxWorkspaceRoot\n const name = makeVercelSandboxName(config.sandboxSessionId)\n\n const deleteNamedSandbox = (sandboxName: string) =>\n tryProvider('get', client.get({ name: sandboxName })).pipe(\n Effect.flatMap(handle =>\n handle === null ? Effect.void : tryProvider('delete', handle.delete)\n )\n )\n\n const createSandbox = (input: { readonly nowMs: number; readonly workspaceReset: boolean }) =>\n Effect.gen(function* () {\n const handle = yield* tryProvider(\n 'create',\n client.create({\n name,\n source,\n ports,\n timeoutMs: lifecycleTimeoutMs(lifecycle),\n resources,\n runtime,\n env: config.env,\n persistent: persistentFlag(lifecycle),\n snapshotExpirationMs: snapshotExpirationMs(lifecycle),\n keepLastSnapshots: keepLastSnapshots(lifecycle),\n networkPolicy: config.networkPolicy\n })\n )\n const state = initialSandboxState({ name, nowMs: input.nowMs, lifecycle })\n yield* store.save({ sandboxSessionId: config.sandboxSessionId, state })\n\n return { handle, state, workspaceReset: input.workspaceReset }\n })\n\n const attachExistingSandbox = (input: {\n readonly handle: VercelSandboxHandle\n readonly nowMs: number\n }) =>\n Effect.gen(function* () {\n const state = initialSandboxState({ name, nowMs: input.nowMs, lifecycle })\n yield* store.save({ sandboxSessionId: config.sandboxSessionId, state })\n\n return {\n handle: input.handle,\n state,\n workspaceReset: false\n }\n })\n\n const attachOrCreateSandbox = (input: {\n readonly nowMs: number\n readonly workspaceReset: boolean\n }) =>\n Effect.gen(function* () {\n const handle = yield* tryProvider('get', client.get({ name }))\n\n if (handle !== null) {\n return yield* attachExistingSandbox({ handle, nowMs: input.nowMs })\n }\n\n return yield* createSandbox(input)\n })\n\n const touchExistingSandbox = (input: {\n readonly handle: VercelSandboxHandle\n readonly state: SandboxState\n readonly nowMs: number\n readonly workspaceReset: boolean\n }) =>\n Effect.gen(function* () {\n const touched = touchSandboxState({\n state: input.state,\n nowMs: input.nowMs,\n lifecycle\n })\n const deltaMs = sandboxTimeoutExtendDeltaMs({ before: input.state, after: touched })\n\n if (deltaMs > 0) {\n yield* tryProvider('extendTimeout', input.handle.extendTimeout(deltaMs))\n }\n\n yield* store.save({ sandboxSessionId: config.sandboxSessionId, state: touched })\n\n return {\n handle: input.handle,\n state: touched,\n workspaceReset: input.workspaceReset\n }\n })\n\n const ensureSandbox = (nowMs: number): Effect.Effect<ActiveSandbox, SandboxError> =>\n Effect.gen(function* () {\n const loaded = yield* store.load(config.sandboxSessionId)\n const decision = sandboxStateDecision({ state: loaded, name, nowMs })\n\n if (decision._tag === 'Create') {\n if (Option.isNone(loaded)) {\n return yield* attachOrCreateSandbox({\n nowMs,\n workspaceReset: decision.workspaceReset\n })\n }\n\n if (Option.isSome(loaded) && decision.workspaceReset) {\n yield* deleteNamedSandbox(loaded.value.name)\n yield* store.clear(config.sandboxSessionId)\n }\n\n return yield* createSandbox({ nowMs, workspaceReset: decision.workspaceReset })\n }\n\n const handle = yield* tryProvider('get', client.get({ name }))\n\n if (handle === null) {\n yield* store.clear(config.sandboxSessionId)\n return yield* createSandbox({ nowMs, workspaceReset: true })\n }\n\n return yield* touchExistingSandbox({\n handle,\n state: decision.state,\n nowMs,\n workspaceReset: false\n })\n })\n\n const nextCommandId = Ref.updateAndGet(commandCounter, value => value + 1).pipe(\n Effect.map(value => `command-${value}`)\n )\n\n const runUnlocked = (input: SandboxCommandInput) =>\n Effect.gen(function* () {\n yield* validateSandboxCommand(input.command)\n const normalizedCwd = yield* normalizeWorkspaceCwd(input.cwd)\n const timeoutMs = sandboxCommandTimeoutMs(input.timeoutMs)\n const nowMs = yield* Clock.currentTimeMillis\n const active = yield* ensureSandbox(nowMs)\n const id = yield* nextCommandId\n const commandFiles = createCommandFiles({\n commandId: id,\n workspaceRoot,\n command: input.command,\n stdin: input.stdin\n })\n\n yield* tryProvider('writeFiles', active.handle.writeFiles(commandFiles.files))\n\n const startedAtMs = yield* Clock.currentTimeMillis\n const command = yield* tryProvider(\n 'runCommand',\n active.handle.runDetachedCommand({\n cmd: 'bash',\n args: [commandFiles.wrapperPath],\n cwd: absoluteSandboxCwd(workspaceRoot, normalizedCwd)\n })\n )\n const output = yield* input.background === true\n ? probeBackgroundCommand(active.handle, command)\n : waitForegroundCommand(command, timeoutMs)\n const endedAtMs = yield* Clock.currentTimeMillis\n const urls = yield* previewUrls(active.handle, ports)\n\n return SandboxCommandResult.make({\n exitCode: output.exitCode,\n stdout: output.stdout,\n stderr: output.stderr,\n durationMs: Math.max(0, endedAtMs - startedAtMs),\n timedOut: output.timedOut,\n workspaceReset: active.workspaceReset,\n ...(output.backgroundId === undefined ? {} : { backgroundId: output.backgroundId }),\n previewUrls: urls,\n state: active.state\n })\n })\n\n return Sandbox.of({\n run: input => semaphore.withPermits(1)(runUnlocked(input)),\n currentState: store.load(config.sandboxSessionId),\n delete: Effect.gen(function* () {\n const loaded = yield* store.load(config.sandboxSessionId)\n if (Option.isSome(loaded)) {\n yield* deleteNamedSandbox(loaded.value.name)\n }\n yield* store.clear(config.sandboxSessionId)\n })\n })\n })\n )\n\nexport const makeVercelSandboxLayer = (config: VercelSandboxLayerConfig) =>\n makeVercelSandboxLayerWithClient(config).pipe(Layer.provide(VercelSandboxClientLive))\n"],"mappings":";;;;;;;;;AAiEA,MAAM,yBAAyB,iBAAiB,KAAK,EAAE,OAAO,EAAE,CAAC;AACjE,MAAM,uBAA6C;AAEnD,MAAM,iBAAiB,WAAmB,UACxC,IAAI,qBAAqB;CACvB,UAAU;CACV;CACA,SAAS,kBAAkB,UAAU,WAAW,iBAAiB,KAAK;CACtE,YAAY;AACd,CAAC;AAEH,MAAM,eAAkB,WAAmB,WACzC,OAAO,KAAK,OAAO,UAAS,UAAS,cAAc,WAAW,KAAK,CAAC,CAAC;AAEvE,MAAM,sBAAsB,cAAgC;CAC1D,QAAQ,UAAU,MAAlB;EACE,KAAK,cACH,OAAO,KAAK,IAAI,UAAU,WAAW,UAAU,aAAa;EAC9D,KAAK,cACH,OAAO,UAAU;CACrB;AACF;AAEA,MAAM,kBAAkB,cAAgC,UAAU,SAAS;AAE3E,MAAM,wBAAwB,cAC5B,UAAU,SAAS,eAAe,UAAU,uBAAuB,KAAA;AAErE,MAAM,qBAAqB,cACzB,UAAU,SAAS,eAAe,UAAU,oBAAoB,KAAA;AAElE,MAAM,eAAe,QAA6B,UAChD,OAAO,QAAQ,QAAO,SACpB,OAAO,IAAI;CACT,WAAW,OAAO,OAAO,IAAI;CAC7B,QAAO,UAAS;AAClB,CAAC,EAAE,KACD,OAAO,MAAM;CACX,iBAAiB,OAAO,KAAwB;CAChD,YAAW,QAAO,OAAO,KAAK,kBAAkB,KAAK;EAAE;EAAM;CAAI,CAAC,CAAC;AACrE,CAAC,CACH,CACF,EAAE,KAAK,OAAO,IAAIA,MAAI,QAAQ,CAAC;AAEjC,MAAM,wBAAwB,YAC5B,YAAY,kBAAkB,QAAQ,MAAM,EAAE,KAC5C,OAAO,SAAS,yBAAwB,UACtC,OAAO,QAAQ;CACb,QAAQ;CACR,QAAQ,MAAM;AAChB,CAAC,CACH,CACF;AAEF,MAAM,gCAAgC,YAGpC,YAAY,kBAAkB,QAAQ,MAAM,EAAE,KAC5C,OAAO,SAAS,yBAAwB,UACtC,OAAO,QAAQ;CACb,QAAQ;CACR,QAAQ,MAAM;AAChB,CAAC,CACH,CACF;AAEF,MAAM,yBACJ,SACA,cAEA,YAAY,gBAAgB,QAAQ,IAAI,EAAE,KACxC,OAAO,SAAQ,aACb,6BAA6B,QAAQ,EAAE,KACrC,OAAO,KAAI,YAAW;CACpB,UAAU,SAAS;CACnB,QAAQ,OAAO;CACf,QAAQ,OAAO;CACf,UAAU;AACZ,EAAE,CACJ,CACF,GACA,OAAO,cAAc;CACnB,UAAU,SAAS,OAAO,SAAS;CACnC,cACE,OAAO,IAAI,aAAa;EACpB,OAAO,YAAY,gBAAgB,QAAQ,KAAK,SAAS,CAAC,EAAE,KAC5D,OAAO,SAAS,8BAA8B,OAAO,IAAI,CAC3D;EACA,MAAM,SAAS,OAAO,qBAAqB,OAAO;EAElD,OAAO;GACL,UAAU;GACV,QAAQ,OAAO;GACf,QAAQ,OAAO;GACf,UAAU;EACZ;CACF,CAAC;AACL,CAAC,CACH;AAEF,MAAM,0BACJ,QACA,YAEA,OAAO,MAAM,SAAS,OAAO,wBAAwB,CAAC,EAAE,KACtD,OAAO,cAAc,YAAY,eAAe,OAAO,WAAW,QAAQ,EAAE,CAAC,CAAC,GAC9E,OAAO,SAAQ,YAAW;CACxB,IAAI,QAAQ,aAAa,MACvB,OAAO,OAAO,QAAQ;EACpB,UAAU;EACV,QAAQ;EACR,QAAQ;EACR,UAAU;EACV,cAAc,QAAQ;CACxB,CAAC;CAGH,OAAO,qBAAqB,OAAO,EAAE,KACnC,OAAO,KAAI,YAAW;EACpB,UAAU,QAAQ;EAClB,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,UAAU;CACZ,EAAE,CACJ;AACF,CAAC,CACH;AAEF,MAAM,sBAAsB,UAKtB;CACJ,MAAM,aAAa,GAAG,MAAM,cAAc,kBAAkB,MAAM;CAClE,MAAM,cAAc,GAAG,WAAW;CAClC,MAAM,YAAY,GAAG,WAAW;CAChC,MAAM,cAAc,GAAG,WAAW;CAElC,OAAO;EACL;EACA,OAAO;GACL;IACE,MAAM;IACN,SAAS,wBAAwB,MAAM,QAAQ;IAC/C,MAAM;GACR;GACA;IACE,MAAM;IACN,SAAS,MAAM,SAAS;GAC1B;GACA;IACE,MAAM;IACN,SAAS,6BAA6B,KAAK,UAAU,WAAW,EAAE,KAAK,KAAK,UAAU,SAAS,EAAE;IACjG,MAAM;GACR;EACF;CACF;AACF;AAEA,MAAa,oCAAoC,WAC/C,MAAM,OACJ,SACA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,SAAS,OAAO;CACtB,MAAM,YAAY,OAAO,UAAU,KAAK,CAAC;CACzC,MAAM,iBAAiB,OAAO,IAAI,KAAK,CAAC;CACxC,MAAM,YAAY,0BAA0B,OAAO,SAAS;CAC5D,MAAM,SAAS,uBAAuB,OAAO,MAAM;CACnD,MAAM,QAAQ,OAAO,SAAS;CAC9B,MAAM,YAAY,OAAO,aAAa;CACtC,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,gBAAgB,OAAO,iBAAA;CAC7B,MAAM,OAAO,sBAAsB,OAAO,gBAAgB;CAE1D,MAAM,sBAAsB,gBAC1B,YAAY,OAAO,OAAO,IAAI,EAAE,MAAM,YAAY,CAAC,CAAC,EAAE,KACpD,OAAO,SAAQ,WACb,WAAW,OAAO,OAAO,OAAO,YAAY,UAAU,OAAO,MAAM,CACrE,CACF;CAEF,MAAM,iBAAiB,UACrB,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,YACpB,UACA,OAAO,OAAO;GACZ;GACA;GACA;GACA,WAAW,mBAAmB,SAAS;GACvC;GACA;GACA,KAAK,OAAO;GACZ,YAAY,eAAe,SAAS;GACpC,sBAAsB,qBAAqB,SAAS;GACpD,mBAAmB,kBAAkB,SAAS;GAC9C,eAAe,OAAO;EACxB,CAAC,CACH;EACA,MAAM,QAAQ,oBAAoB;GAAE;GAAM,OAAO,MAAM;GAAO;EAAU,CAAC;EACzE,OAAO,MAAM,KAAK;GAAE,kBAAkB,OAAO;GAAkB;EAAM,CAAC;EAEtE,OAAO;GAAE;GAAQ;GAAO,gBAAgB,MAAM;EAAe;CAC/D,CAAC;CAEH,MAAM,yBAAyB,UAI7B,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,oBAAoB;GAAE;GAAM,OAAO,MAAM;GAAO;EAAU,CAAC;EACzE,OAAO,MAAM,KAAK;GAAE,kBAAkB,OAAO;GAAkB;EAAM,CAAC;EAEtE,OAAO;GACL,QAAQ,MAAM;GACd;GACA,gBAAgB;EAClB;CACF,CAAC;CAEH,MAAM,yBAAyB,UAI7B,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,YAAY,OAAO,OAAO,IAAI,EAAE,KAAK,CAAC,CAAC;EAE7D,IAAI,WAAW,MACb,OAAO,OAAO,sBAAsB;GAAE;GAAQ,OAAO,MAAM;EAAM,CAAC;EAGpE,OAAO,OAAO,cAAc,KAAK;CACnC,CAAC;CAEH,MAAM,wBAAwB,UAM5B,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU,kBAAkB;GAChC,OAAO,MAAM;GACb,OAAO,MAAM;GACb;EACF,CAAC;EACD,MAAM,UAAU,4BAA4B;GAAE,QAAQ,MAAM;GAAO,OAAO;EAAQ,CAAC;EAEnF,IAAI,UAAU,GACZ,OAAO,YAAY,iBAAiB,MAAM,OAAO,cAAc,OAAO,CAAC;EAGzE,OAAO,MAAM,KAAK;GAAE,kBAAkB,OAAO;GAAkB,OAAO;EAAQ,CAAC;EAE/E,OAAO;GACL,QAAQ,MAAM;GACd,OAAO;GACP,gBAAgB,MAAM;EACxB;CACF,CAAC;CAEH,MAAM,iBAAiB,UACrB,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,MAAM,KAAK,OAAO,gBAAgB;EACxD,MAAM,WAAW,qBAAqB;GAAE,OAAO;GAAQ;GAAM;EAAM,CAAC;EAEpE,IAAI,SAAS,SAAS,UAAU;GAC9B,IAAI,OAAO,OAAO,MAAM,GACtB,OAAO,OAAO,sBAAsB;IAClC;IACA,gBAAgB,SAAS;GAC3B,CAAC;GAGH,IAAI,OAAO,OAAO,MAAM,KAAK,SAAS,gBAAgB;IACpD,OAAO,mBAAmB,OAAO,MAAM,IAAI;IAC3C,OAAO,MAAM,MAAM,OAAO,gBAAgB;GAC5C;GAEA,OAAO,OAAO,cAAc;IAAE;IAAO,gBAAgB,SAAS;GAAe,CAAC;EAChF;EAEA,MAAM,SAAS,OAAO,YAAY,OAAO,OAAO,IAAI,EAAE,KAAK,CAAC,CAAC;EAE7D,IAAI,WAAW,MAAM;GACnB,OAAO,MAAM,MAAM,OAAO,gBAAgB;GAC1C,OAAO,OAAO,cAAc;IAAE;IAAO,gBAAgB;GAAK,CAAC;EAC7D;EAEA,OAAO,OAAO,qBAAqB;GACjC;GACA,OAAO,SAAS;GAChB;GACA,gBAAgB;EAClB,CAAC;CACH,CAAC;CAEH,MAAM,gBAAgB,IAAI,aAAa,iBAAgB,UAAS,QAAQ,CAAC,EAAE,KACzE,OAAO,KAAI,UAAS,WAAW,OAAO,CACxC;CAEA,MAAM,eAAe,UACnB,OAAO,IAAI,aAAa;EACtB,OAAO,uBAAuB,MAAM,OAAO;EAC3C,MAAM,gBAAgB,OAAO,sBAAsB,MAAM,GAAG;EAC5D,MAAM,YAAY,wBAAwB,MAAM,SAAS;EAEzD,MAAM,SAAS,OAAO,cAAc,OADf,MAAM,iBACc;EAEzC,MAAM,eAAe,mBAAmB;GACtC,WAAW,OAFK;GAGhB;GACA,SAAS,MAAM;GACf,OAAO,MAAM;EACf,CAAC;EAED,OAAO,YAAY,cAAc,OAAO,OAAO,WAAW,aAAa,KAAK,CAAC;EAE7E,MAAM,cAAc,OAAO,MAAM;EACjC,MAAM,UAAU,OAAO,YACrB,cACA,OAAO,OAAO,mBAAmB;GAC/B,KAAK;GACL,MAAM,CAAC,aAAa,WAAW;GAC/B,KAAK,mBAAmB,eAAe,aAAa;EACtD,CAAC,CACH;EACA,MAAM,SAAS,OAAO,MAAM,eAAe,OACvC,uBAAuB,OAAO,QAAQ,OAAO,IAC7C,sBAAsB,SAAS,SAAS;EAC5C,MAAM,YAAY,OAAO,MAAM;EAC/B,MAAM,OAAO,OAAO,YAAY,OAAO,QAAQ,KAAK;EAEpD,OAAO,qBAAqB,KAAK;GAC/B,UAAU,OAAO;GACjB,QAAQ,OAAO;GACf,QAAQ,OAAO;GACf,YAAY,KAAK,IAAI,GAAG,YAAY,WAAW;GAC/C,UAAU,OAAO;GACjB,gBAAgB,OAAO;GACvB,GAAI,OAAO,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,OAAO,aAAa;GACjF,aAAa;GACb,OAAO,OAAO;EAChB,CAAC;CACH,CAAC;CAEH,OAAO,QAAQ,GAAG;EAChB,MAAK,UAAS,UAAU,YAAY,CAAC,EAAE,YAAY,KAAK,CAAC;EACzD,cAAc,MAAM,KAAK,OAAO,gBAAgB;EAChD,QAAQ,OAAO,IAAI,aAAa;GAC9B,MAAM,SAAS,OAAO,MAAM,KAAK,OAAO,gBAAgB;GACxD,IAAI,OAAO,OAAO,MAAM,GACtB,OAAO,mBAAmB,OAAO,MAAM,IAAI;GAE7C,OAAO,MAAM,MAAM,OAAO,gBAAgB;EAC5C,CAAC;CACH,CAAC;AACH,CAAC,CACH;AAEF,MAAa,0BAA0B,WACrC,iCAAiC,MAAM,EAAE,KAAK,MAAM,QAAQ,uBAAuB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yolk-sdk/sandbox",
|
|
3
|
-
"version": "0.1.0-canary.
|
|
3
|
+
"version": "0.1.0-canary.41",
|
|
4
4
|
"description": "Effect-native sandbox execution plane primitives and Vercel Sandbox adapter for Yolk agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@vercel/sandbox": "2.2.1",
|
|
63
63
|
"effect": "4.0.0-beta.65",
|
|
64
|
-
"@yolk-sdk/agent": "^0.1.0-canary.
|
|
64
|
+
"@yolk-sdk/agent": "^0.1.0-canary.41"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsdown",
|
package/src/vercel/client.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Layer } from 'effect'
|
|
1
|
+
import { Context, Effect, Layer } from 'effect'
|
|
2
2
|
import {
|
|
3
3
|
APIError,
|
|
4
4
|
Sandbox as VercelSdkSandbox,
|
|
@@ -21,15 +21,15 @@ export type VercelCommandSignal = 'SIGTERM' | 'SIGKILL'
|
|
|
21
21
|
export type VercelFinishedCommand = {
|
|
22
22
|
readonly id: string
|
|
23
23
|
readonly exitCode: number
|
|
24
|
-
readonly output:
|
|
24
|
+
readonly output: Effect.Effect<VercelCommandOutput, unknown>
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export type VercelDetachedCommand = {
|
|
28
28
|
readonly id: string
|
|
29
29
|
readonly exitCode: number | null
|
|
30
|
-
readonly wait:
|
|
31
|
-
readonly kill: (signal: VercelCommandSignal) =>
|
|
32
|
-
readonly output:
|
|
30
|
+
readonly wait: Effect.Effect<VercelFinishedCommand, unknown>
|
|
31
|
+
readonly kill: (signal: VercelCommandSignal) => Effect.Effect<void, unknown>
|
|
32
|
+
readonly output: Effect.Effect<VercelCommandOutput, unknown>
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export type VercelSandboxFile = {
|
|
@@ -64,17 +64,19 @@ export type VercelSandboxGetInput = {
|
|
|
64
64
|
|
|
65
65
|
export type VercelSandboxHandle = {
|
|
66
66
|
readonly name: string
|
|
67
|
-
readonly writeFiles: (files: ReadonlyArray<VercelSandboxFile>) =>
|
|
68
|
-
readonly runDetachedCommand: (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
readonly
|
|
67
|
+
readonly writeFiles: (files: ReadonlyArray<VercelSandboxFile>) => Effect.Effect<void, unknown>
|
|
68
|
+
readonly runDetachedCommand: (
|
|
69
|
+
input: VercelRunCommandInput
|
|
70
|
+
) => Effect.Effect<VercelDetachedCommand, unknown>
|
|
71
|
+
readonly getCommand: (id: string) => Effect.Effect<VercelDetachedCommand, unknown>
|
|
72
|
+
readonly extendTimeout: (durationMs: number) => Effect.Effect<void, unknown>
|
|
73
|
+
readonly delete: Effect.Effect<void, unknown>
|
|
72
74
|
readonly domain: (port: number) => string
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
export type VercelSandboxClientApi = {
|
|
76
|
-
readonly get: (input: VercelSandboxGetInput) =>
|
|
77
|
-
readonly create: (input: VercelSandboxCreateInput) =>
|
|
78
|
+
readonly get: (input: VercelSandboxGetInput) => Effect.Effect<VercelSandboxHandle | null, unknown>
|
|
79
|
+
readonly create: (input: VercelSandboxCreateInput) => Effect.Effect<VercelSandboxHandle, unknown>
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
export class VercelSandboxClient extends Context.Service<
|
|
@@ -85,45 +87,57 @@ export class VercelSandboxClient extends Context.Service<
|
|
|
85
87
|
export const isVercelMissingSandboxError = (error: unknown) =>
|
|
86
88
|
error instanceof APIError && (error.response.status === 404 || error.response.status === 410)
|
|
87
89
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
+
const tryVercelPromise = <A>(body: () => Promise<A>) =>
|
|
91
|
+
Effect.tryPromise({
|
|
92
|
+
try: body,
|
|
93
|
+
catch: error => error
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const commandOutput = (command: Command | CommandFinished): Effect.Effect<VercelCommandOutput, unknown> =>
|
|
97
|
+
Effect.all({
|
|
98
|
+
stdout: tryVercelPromise(() => command.stdout()),
|
|
99
|
+
stderr: tryVercelPromise(() => command.stderr())
|
|
100
|
+
})
|
|
90
101
|
|
|
91
102
|
const toFinishedCommand = (command: CommandFinished): VercelFinishedCommand => ({
|
|
92
103
|
id: command.cmdId,
|
|
93
104
|
exitCode: command.exitCode,
|
|
94
|
-
output:
|
|
105
|
+
output: commandOutput(command)
|
|
95
106
|
})
|
|
96
107
|
|
|
97
108
|
const toDetachedCommand = (command: Command): VercelDetachedCommand => ({
|
|
98
109
|
id: command.cmdId,
|
|
99
110
|
exitCode: command.exitCode,
|
|
100
|
-
wait: () => command.wait().
|
|
101
|
-
kill: signal => command.kill(signal),
|
|
102
|
-
output:
|
|
111
|
+
wait: tryVercelPromise(() => command.wait()).pipe(Effect.map(toFinishedCommand)),
|
|
112
|
+
kill: signal => tryVercelPromise(() => command.kill(signal)),
|
|
113
|
+
output: commandOutput(command)
|
|
103
114
|
})
|
|
104
115
|
|
|
105
116
|
const toHandle = (sandbox: VercelSdkSandbox): VercelSandboxHandle => ({
|
|
106
117
|
name: sandbox.name,
|
|
107
118
|
writeFiles: files =>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
tryVercelPromise(() =>
|
|
120
|
+
sandbox.writeFiles(
|
|
121
|
+
files.map(file => ({
|
|
122
|
+
path: file.path,
|
|
123
|
+
content: file.content,
|
|
124
|
+
...(file.mode === undefined ? {} : { mode: file.mode })
|
|
125
|
+
}))
|
|
126
|
+
)
|
|
114
127
|
),
|
|
115
128
|
runDetachedCommand: input =>
|
|
116
|
-
|
|
117
|
-
.runCommand({
|
|
129
|
+
tryVercelPromise(() =>
|
|
130
|
+
sandbox.runCommand({
|
|
118
131
|
cmd: input.cmd,
|
|
119
132
|
args: input.args === undefined ? [] : [...input.args],
|
|
120
133
|
...(input.cwd === undefined ? {} : { cwd: input.cwd }),
|
|
121
134
|
detached: true
|
|
122
135
|
})
|
|
123
|
-
|
|
124
|
-
getCommand: id => sandbox.getCommand(id).
|
|
125
|
-
extendTimeout: durationMs =>
|
|
126
|
-
|
|
136
|
+
).pipe(Effect.map(toDetachedCommand)),
|
|
137
|
+
getCommand: id => tryVercelPromise(() => sandbox.getCommand(id)).pipe(Effect.map(toDetachedCommand)),
|
|
138
|
+
extendTimeout: durationMs =>
|
|
139
|
+
tryVercelPromise(() => sandbox.extendTimeout(durationMs)).pipe(Effect.asVoid),
|
|
140
|
+
delete: tryVercelPromise(() => sandbox.delete()).pipe(Effect.asVoid),
|
|
127
141
|
domain: port => sandbox.domain(port)
|
|
128
142
|
})
|
|
129
143
|
|
|
@@ -222,15 +236,16 @@ export const VercelSandboxClientLive = Layer.succeed(
|
|
|
222
236
|
VercelSandboxClient,
|
|
223
237
|
VercelSandboxClient.of({
|
|
224
238
|
get: input =>
|
|
225
|
-
VercelSdkSandbox.get({ name: input.name })
|
|
226
|
-
.
|
|
227
|
-
.catch(error => {
|
|
239
|
+
tryVercelPromise(() => VercelSdkSandbox.get({ name: input.name })).pipe(
|
|
240
|
+
Effect.map(toHandle),
|
|
241
|
+
Effect.catch((error: unknown) => {
|
|
228
242
|
if (isVercelMissingSandboxError(error)) {
|
|
229
|
-
return null
|
|
243
|
+
return Effect.succeed(null)
|
|
230
244
|
}
|
|
231
245
|
|
|
232
|
-
|
|
233
|
-
})
|
|
234
|
-
|
|
246
|
+
return Effect.fail(error)
|
|
247
|
+
})
|
|
248
|
+
),
|
|
249
|
+
create: input => tryVercelPromise(() => createSandbox(input)).pipe(Effect.map(toHandle))
|
|
235
250
|
})
|
|
236
251
|
)
|
package/src/vercel/layer.ts
CHANGED
|
@@ -74,11 +74,8 @@ const providerError = (operation: string, error: unknown) =>
|
|
|
74
74
|
underlying: error
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
-
const tryProvider = <A>(operation: string,
|
|
78
|
-
Effect.
|
|
79
|
-
try: body,
|
|
80
|
-
catch: error => providerError(operation, error)
|
|
81
|
-
})
|
|
77
|
+
const tryProvider = <A>(operation: string, effect: Effect.Effect<A, unknown>) =>
|
|
78
|
+
effect.pipe(Effect.mapError(error => providerError(operation, error)))
|
|
82
79
|
|
|
83
80
|
const lifecycleTimeoutMs = (lifecycle: SandboxLifecycle) => {
|
|
84
81
|
switch (lifecycle._tag) {
|
|
@@ -121,7 +118,7 @@ const commandOutputOrEmpty = (command: VercelDetachedCommand) =>
|
|
|
121
118
|
)
|
|
122
119
|
|
|
123
120
|
const finishedCommandOutputOrEmpty = (command: {
|
|
124
|
-
readonly output:
|
|
121
|
+
readonly output: Effect.Effect<{ readonly stdout: string; readonly stderr: string }, unknown>
|
|
125
122
|
}) =>
|
|
126
123
|
tryProvider('command.output', command.output).pipe(
|
|
127
124
|
Effect.catchTag('SandboxProviderError', error =>
|
|
@@ -151,7 +148,7 @@ const waitForegroundCommand = (
|
|
|
151
148
|
duration: Duration.millis(timeoutMs),
|
|
152
149
|
orElse: () =>
|
|
153
150
|
Effect.gen(function* () {
|
|
154
|
-
|
|
151
|
+
yield* tryProvider('command.kill', command.kill('SIGKILL')).pipe(
|
|
155
152
|
Effect.catchTag('SandboxProviderError', () => Effect.void)
|
|
156
153
|
)
|
|
157
154
|
const output = yield* commandOutputOrEmpty(command)
|
|
@@ -171,7 +168,7 @@ const probeBackgroundCommand = (
|
|
|
171
168
|
command: VercelDetachedCommand
|
|
172
169
|
): Effect.Effect<CommandRunOutput, SandboxProviderError> =>
|
|
173
170
|
Effect.sleep(Duration.millis(backgroundSandboxProbeMs)).pipe(
|
|
174
|
-
Effect.flatMap(() => tryProvider('command.get',
|
|
171
|
+
Effect.flatMap(() => tryProvider('command.get', handle.getCommand(command.id))),
|
|
175
172
|
Effect.flatMap(current => {
|
|
176
173
|
if (current.exitCode === null) {
|
|
177
174
|
return Effect.succeed({
|
|
@@ -243,15 +240,16 @@ export const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfi
|
|
|
243
240
|
const name = makeVercelSandboxName(config.sandboxSessionId)
|
|
244
241
|
|
|
245
242
|
const deleteNamedSandbox = (sandboxName: string) =>
|
|
246
|
-
tryProvider('get',
|
|
243
|
+
tryProvider('get', client.get({ name: sandboxName })).pipe(
|
|
247
244
|
Effect.flatMap(handle =>
|
|
248
|
-
handle === null ? Effect.void : tryProvider('delete',
|
|
245
|
+
handle === null ? Effect.void : tryProvider('delete', handle.delete)
|
|
249
246
|
)
|
|
250
247
|
)
|
|
251
248
|
|
|
252
249
|
const createSandbox = (input: { readonly nowMs: number; readonly workspaceReset: boolean }) =>
|
|
253
250
|
Effect.gen(function* () {
|
|
254
|
-
const handle = yield* tryProvider(
|
|
251
|
+
const handle = yield* tryProvider(
|
|
252
|
+
'create',
|
|
255
253
|
client.create({
|
|
256
254
|
name,
|
|
257
255
|
source,
|
|
@@ -292,7 +290,7 @@ export const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfi
|
|
|
292
290
|
readonly workspaceReset: boolean
|
|
293
291
|
}) =>
|
|
294
292
|
Effect.gen(function* () {
|
|
295
|
-
const handle = yield* tryProvider('get',
|
|
293
|
+
const handle = yield* tryProvider('get', client.get({ name }))
|
|
296
294
|
|
|
297
295
|
if (handle !== null) {
|
|
298
296
|
return yield* attachExistingSandbox({ handle, nowMs: input.nowMs })
|
|
@@ -316,7 +314,7 @@ export const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfi
|
|
|
316
314
|
const deltaMs = sandboxTimeoutExtendDeltaMs({ before: input.state, after: touched })
|
|
317
315
|
|
|
318
316
|
if (deltaMs > 0) {
|
|
319
|
-
yield* tryProvider('extendTimeout',
|
|
317
|
+
yield* tryProvider('extendTimeout', input.handle.extendTimeout(deltaMs))
|
|
320
318
|
}
|
|
321
319
|
|
|
322
320
|
yield* store.save({ sandboxSessionId: config.sandboxSessionId, state: touched })
|
|
@@ -349,7 +347,7 @@ export const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfi
|
|
|
349
347
|
return yield* createSandbox({ nowMs, workspaceReset: decision.workspaceReset })
|
|
350
348
|
}
|
|
351
349
|
|
|
352
|
-
const handle = yield* tryProvider('get',
|
|
350
|
+
const handle = yield* tryProvider('get', client.get({ name }))
|
|
353
351
|
|
|
354
352
|
if (handle === null) {
|
|
355
353
|
yield* store.clear(config.sandboxSessionId)
|
|
@@ -383,10 +381,11 @@ export const makeVercelSandboxLayerWithClient = (config: VercelSandboxLayerConfi
|
|
|
383
381
|
stdin: input.stdin
|
|
384
382
|
})
|
|
385
383
|
|
|
386
|
-
yield* tryProvider('writeFiles',
|
|
384
|
+
yield* tryProvider('writeFiles', active.handle.writeFiles(commandFiles.files))
|
|
387
385
|
|
|
388
386
|
const startedAtMs = yield* Clock.currentTimeMillis
|
|
389
|
-
const command = yield* tryProvider(
|
|
387
|
+
const command = yield* tryProvider(
|
|
388
|
+
'runCommand',
|
|
390
389
|
active.handle.runDetachedCommand({
|
|
391
390
|
cmd: 'bash',
|
|
392
391
|
args: [commandFiles.wrapperPath],
|