@yolk-sdk/sandbox 0.1.0-canary.78 → 0.1.0-canary.80
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/README.md +8 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/lifecycle.d.mts +5 -3
- package/dist/lifecycle.d.mts.map +1 -1
- package/dist/lifecycle.mjs +13 -3
- package/dist/lifecycle.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/lifecycle.ts +35 -4
package/README.md
CHANGED
|
@@ -70,6 +70,14 @@ const lifecycle = DisposableSandboxLifecycle.make({
|
|
|
70
70
|
})
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## Workspace paths
|
|
74
|
+
|
|
75
|
+
`normalizeWorkspaceCwd(rawCwd)` returns an Effect with a `NormalizedWorkspaceCwd` branded string
|
|
76
|
+
(exported from `@yolk-sdk/sandbox`). Raw `Sandbox.run({ cwd })` inputs stay strings. The normalizer
|
|
77
|
+
trims raw outer whitespace, resolves dot segments, and rejects absolute/NUL/escaping paths.
|
|
78
|
+
Whitespace belonging to remaining directory names is preserved. The brand records lexical path
|
|
79
|
+
validation, not filesystem or symlink confinement.
|
|
80
|
+
|
|
73
81
|
## Initial source model
|
|
74
82
|
|
|
75
83
|
`SandboxInitialSource` is a tagged union:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SandboxConfigError, SandboxError, SandboxExpiredError, SandboxInputError, SandboxInputErrorCause, SandboxProviderError, SandboxStateError, SandboxStateStoreError } from "./errors.mjs";
|
|
2
2
|
import { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxBasicAuth, GitSandboxInitialSource, PersistentSandboxLifecycle, SandboxCommandInput, SandboxCommandResult, SandboxInitialSource, SandboxLifecycle, SandboxPreviewUrl, SandboxResources, SandboxSnapshotRetention, SandboxState, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState } from "./model.mjs";
|
|
3
3
|
import { Sandbox, SandboxApi } from "./service.mjs";
|
|
4
|
-
import { backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand } from "./lifecycle.mjs";
|
|
4
|
+
import { NormalizedWorkspaceCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand } from "./lifecycle.mjs";
|
|
5
5
|
import { makeVercelSandboxName } from "./name.mjs";
|
|
6
6
|
import { SandboxStateStore, SandboxStateStoreApi } from "./state-store.mjs";
|
|
7
|
-
export { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxBasicAuth, GitSandboxInitialSource, PersistentSandboxLifecycle, Sandbox, type SandboxApi, SandboxCommandInput, SandboxCommandResult, SandboxConfigError, type SandboxError, SandboxExpiredError, SandboxInitialSource, SandboxInputError, SandboxInputErrorCause, SandboxLifecycle, SandboxPreviewUrl, SandboxProviderError, SandboxResources, SandboxSnapshotRetention, SandboxState, SandboxStateError, SandboxStateStore, type SandboxStateStoreApi, SandboxStateStoreError, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, makeVercelSandboxName, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
7
|
+
export { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxBasicAuth, GitSandboxInitialSource, NormalizedWorkspaceCwd, PersistentSandboxLifecycle, Sandbox, type SandboxApi, SandboxCommandInput, SandboxCommandResult, SandboxConfigError, type SandboxError, SandboxExpiredError, SandboxInitialSource, SandboxInputError, SandboxInputErrorCause, SandboxLifecycle, SandboxPreviewUrl, SandboxProviderError, SandboxResources, SandboxSnapshotRetention, SandboxState, SandboxStateError, SandboxStateStore, type SandboxStateStoreApi, SandboxStateStoreError, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, makeVercelSandboxName, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SandboxConfigError, SandboxExpiredError, SandboxInputError, SandboxInputErrorCause, SandboxProviderError, SandboxStateError, SandboxStateStoreError } from "./errors.mjs";
|
|
2
2
|
import { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxBasicAuth, GitSandboxInitialSource, PersistentSandboxLifecycle, SandboxCommandInput, SandboxCommandResult, SandboxInitialSource, SandboxLifecycle, SandboxPreviewUrl, SandboxResources, SandboxSnapshotRetention, SandboxState, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState } from "./model.mjs";
|
|
3
|
-
import { backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand } from "./lifecycle.mjs";
|
|
3
|
+
import { NormalizedWorkspaceCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand } from "./lifecycle.mjs";
|
|
4
4
|
import { Sandbox } from "./service.mjs";
|
|
5
5
|
import { makeVercelSandboxName } from "./name.mjs";
|
|
6
6
|
import { SandboxStateStore } from "./state-store.mjs";
|
|
7
|
-
export { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxBasicAuth, GitSandboxInitialSource, PersistentSandboxLifecycle, Sandbox, SandboxCommandInput, SandboxCommandResult, SandboxConfigError, SandboxExpiredError, SandboxInitialSource, SandboxInputError, SandboxInputErrorCause, SandboxLifecycle, SandboxPreviewUrl, SandboxProviderError, SandboxResources, SandboxSnapshotRetention, SandboxState, SandboxStateError, SandboxStateStore, SandboxStateStoreError, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, makeVercelSandboxName, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
7
|
+
export { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxBasicAuth, GitSandboxInitialSource, NormalizedWorkspaceCwd, PersistentSandboxLifecycle, Sandbox, SandboxCommandInput, SandboxCommandResult, SandboxConfigError, SandboxExpiredError, SandboxInitialSource, SandboxInputError, SandboxInputErrorCause, SandboxLifecycle, SandboxPreviewUrl, SandboxProviderError, SandboxResources, SandboxSnapshotRetention, SandboxState, SandboxStateError, SandboxStateStore, SandboxStateStoreError, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, makeVercelSandboxName, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
package/dist/lifecycle.d.mts
CHANGED
|
@@ -12,6 +12,8 @@ declare const backgroundSandboxProbeMs = 2000;
|
|
|
12
12
|
declare const sandboxToolOutputLimit = 50000;
|
|
13
13
|
declare const defaultSandboxPorts: ReadonlyArray<number>;
|
|
14
14
|
declare const defaultSandboxWorkspaceRoot = "/vercel/sandbox";
|
|
15
|
+
declare const NormalizedWorkspaceCwd: Schema.brand<Schema.String, "NormalizedWorkspaceCwd">;
|
|
16
|
+
type NormalizedWorkspaceCwd = typeof NormalizedWorkspaceCwd.Type;
|
|
15
17
|
declare const defaultSandboxLifecycle: DisposableSandboxLifecycle;
|
|
16
18
|
declare const defaultSandboxInitialSource: EmptySandboxInitialSource;
|
|
17
19
|
type SandboxRecreateReason = 'idle_expired' | 'max_expired' | 'name_mismatch';
|
|
@@ -27,8 +29,8 @@ declare const sandboxLifecycleOrDefault: (lifecycle?: SandboxLifecycle) => Sandb
|
|
|
27
29
|
declare const sandboxSourceOrDefault: (source?: SandboxInitialSource) => SandboxInitialSource;
|
|
28
30
|
declare const sandboxCommandTimeoutMs: (timeoutMs?: number) => number;
|
|
29
31
|
declare const validateSandboxCommand: (command: string) => Effect.Effect<never, SandboxInputError, never> | Effect.Effect<string, never, never>;
|
|
30
|
-
declare const normalizeWorkspaceCwd: (cwd?: string | null) => Effect.Effect<
|
|
31
|
-
declare const absoluteSandboxCwd: (workspaceRoot: string, normalizedCwd:
|
|
32
|
+
declare const normalizeWorkspaceCwd: (cwd?: string | null) => Effect.Effect<NormalizedWorkspaceCwd, SandboxInputError>;
|
|
33
|
+
declare const absoluteSandboxCwd: (workspaceRoot: string, normalizedCwd: NormalizedWorkspaceCwd) => string;
|
|
32
34
|
declare const initialSandboxState: (input: {
|
|
33
35
|
readonly name: string;
|
|
34
36
|
readonly nowMs: number;
|
|
@@ -50,5 +52,5 @@ declare const sandboxStateDecision: (input: {
|
|
|
50
52
|
readonly lifecycle: SandboxLifecycle;
|
|
51
53
|
}) => SandboxStateDecision;
|
|
52
54
|
//#endregion
|
|
53
|
-
export { SandboxRecreateReason, SandboxStateDecision, absoluteSandboxCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, initialSandboxState, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
55
|
+
export { NormalizedWorkspaceCwd, SandboxRecreateReason, SandboxStateDecision, absoluteSandboxCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, initialSandboxState, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
54
56
|
//# sourceMappingURL=lifecycle.d.mts.map
|
package/dist/lifecycle.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.mts","names":[],"sources":["../src/lifecycle.ts"],"mappings":";;;;;;cAYa,uBAAA;AAAA,cAEA,2BAAA;AAAA,cAEA,8BAAA;AAAA,cAEA,0BAAA;AAAA,cAEA,wBAAA;AAAA,cAEA,sBAAA;AAAA,cAEA,mBAAA,EAAqB,aAAa;AAAA,cAElC,2BAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.mts","names":[],"sources":["../src/lifecycle.ts"],"mappings":";;;;;;cAYa,uBAAA;AAAA,cAEA,2BAAA;AAAA,cAEA,8BAAA;AAAA,cAEA,0BAAA;AAAA,cAEA,wBAAA;AAAA,cAEA,sBAAA;AAAA,cAEA,mBAAA,EAAqB,aAAa;AAAA,cAElC,2BAAA;AAAA,cAcA,sBAAA,EAAsB,MAAA,CAAA,KAAA,CAAA,MAAA,CAAA,MAAA;AAAA,KAOvB,sBAAA,UAAgC,sBAAA,CAAuB,IAAI;AAAA,cAE1D,uBAAA,EAAuB,0BAGlC;AAAA,cAEW,2BAAA,EAA2B,yBAAqC;AAAA,KAEjE,qBAAA;AAAA,cAMN,qBAAA,EAAqB,MAAA,CAAA,YAAA;EAAA;;;KAKf,oBAAA;EAAA,SAEG,IAAA;EAAA,SACA,KAAA,EAAO,YAAA;AAAA,WAEX,qBAAA,CAAsB,IAAI;AAAA,cAUxB,yBAAA,GAA6B,SAAA,GAAY,gBAAA,KAAmB,gBACnC;AAAA,cAEzB,sBAAA,GAA0B,MAAA,GAAS,oBAAA,KAAuB,oBAChC;AAAA,cAE1B,uBAAA,GAA2B,SAAkB;AAAA,cAG7C,sBAAA,GAA0B,OAAA,aAAe,MAAA,CAAA,MAAA,QAAA,iBAAA,WAAA,MAAA,CAAA,MAAA;AAAA,cAazC,qBAAA,GACX,GAAA,qBACC,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,iBAAA;AAAA,cAsD5B,kBAAA,GAAsB,aAAA,UAAuB,aAAA,EAAe,sBAAsB;AAAA,cAGlF,mBAAA,GAAuB,KAAA;EAAA,SACzB,IAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;AAAA,MACrB,kBAsBE;AAAA,cAEU,iBAAA,GAAqB,KAAA;EAAA,SACvB,KAAA,EAAO,YAAA;EAAA,SACP,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;AAAA,MACrB,kBAAA;AAAA,cAoBY,2BAAA,GAA+B,KAAA;EAAA,SACjC,MAAA,EAAQ,YAAA;EAAA,SACR,KAAA,EAAO,YAAY;AAAA;AAAA,cAGjB,oBAAA,GAAwB,KAAA;EAAA,SAC1B,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA,SACrB,IAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;AAAA,MAClB,oBAAA"}
|
package/dist/lifecycle.mjs
CHANGED
|
@@ -16,6 +16,13 @@ const defaultSandboxPorts = [
|
|
|
16
16
|
8e3
|
|
17
17
|
];
|
|
18
18
|
const defaultSandboxWorkspaceRoot = "/vercel/sandbox";
|
|
19
|
+
const isNormalizedWorkspaceCwd = (value) => {
|
|
20
|
+
if (value.length === 0 || value.includes("\0")) return false;
|
|
21
|
+
if (value === ".") return true;
|
|
22
|
+
if (value.startsWith("/") || value.endsWith("/") || value.includes("//")) return false;
|
|
23
|
+
return value.split("/").every((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
24
|
+
};
|
|
25
|
+
const NormalizedWorkspaceCwd = Schema.String.pipe(Schema.check(Schema.makeFilter(isNormalizedWorkspaceCwd, { identifier: "NormalizedWorkspaceCwd" })), Schema.brand("NormalizedWorkspaceCwd"));
|
|
19
26
|
const defaultSandboxLifecycle = DisposableSandboxLifecycle.make({
|
|
20
27
|
idleTtlMs: defaultSandboxIdleTtlMs,
|
|
21
28
|
maxLifetimeMs: defaultSandboxMaxLifetimeMs
|
|
@@ -46,7 +53,7 @@ const validateSandboxCommand = (command) => {
|
|
|
46
53
|
return Effect.succeed(command);
|
|
47
54
|
};
|
|
48
55
|
const normalizeWorkspaceCwd = (cwd) => {
|
|
49
|
-
if (cwd === void 0 || cwd === null || cwd.trim().length === 0) return Effect.succeed(".");
|
|
56
|
+
if (cwd === void 0 || cwd === null || cwd.trim().length === 0) return Effect.succeed(NormalizedWorkspaceCwd.make("."));
|
|
50
57
|
const trimmed = cwd.trim();
|
|
51
58
|
if (trimmed.startsWith("/") || trimmed.includes("\0")) return Effect.fail(new SandboxInputError({
|
|
52
59
|
cause: "invalid_cwd",
|
|
@@ -64,7 +71,10 @@ const normalizeWorkspaceCwd = (cwd) => {
|
|
|
64
71
|
}
|
|
65
72
|
parts.push(segment);
|
|
66
73
|
}
|
|
67
|
-
return
|
|
74
|
+
return Schema.decodeUnknownEffect(NormalizedWorkspaceCwd)(parts.length === 0 ? "." : parts.join("/")).pipe(Effect.mapError(() => new SandboxInputError({
|
|
75
|
+
cause: "invalid_cwd",
|
|
76
|
+
message: "cwd must be workspace-relative"
|
|
77
|
+
})));
|
|
68
78
|
};
|
|
69
79
|
const absoluteSandboxCwd = (workspaceRoot, normalizedCwd) => normalizedCwd === "." ? workspaceRoot : `${workspaceRoot}/${normalizedCwd}`;
|
|
70
80
|
const initialSandboxState = (input) => Match.value(input.lifecycle).pipe(Match.withReturnType(), Match.tag("Disposable", (lifecycle) => VercelSandboxState.make({
|
|
@@ -109,6 +119,6 @@ const sandboxStateDecision = (input) => {
|
|
|
109
119
|
return existingSandboxStateDecision(state);
|
|
110
120
|
};
|
|
111
121
|
//#endregion
|
|
112
|
-
export { absoluteSandboxCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, initialSandboxState, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
122
|
+
export { NormalizedWorkspaceCwd, absoluteSandboxCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, initialSandboxState, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
113
123
|
|
|
114
124
|
//# sourceMappingURL=lifecycle.mjs.map
|
package/dist/lifecycle.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.mjs","names":[],"sources":["../src/lifecycle.ts"],"sourcesContent":["import { Effect, Match, Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { SandboxInputError } from './errors.ts'\nimport {\n DisposableSandboxLifecycle,\n EmptySandboxInitialSource,\n type SandboxInitialSource,\n type SandboxLifecycle,\n type SandboxState,\n VercelSandboxState\n} from './model.ts'\n\nexport const defaultSandboxIdleTtlMs = 30 * 60_000\n\nexport const defaultSandboxMaxLifetimeMs = 45 * 60_000\n\nexport const defaultSandboxCommandTimeoutMs = 120_000\n\nexport const maxSandboxCommandTimeoutMs = 600_000\n\nexport const backgroundSandboxProbeMs = 2_000\n\nexport const sandboxToolOutputLimit = 50_000\n\nexport const defaultSandboxPorts: ReadonlyArray<number> = [3000, 5173, 4321, 8000]\n\nexport const defaultSandboxWorkspaceRoot = '/vercel/sandbox'\n\nexport const defaultSandboxLifecycle = DisposableSandboxLifecycle.make({\n idleTtlMs: defaultSandboxIdleTtlMs,\n maxLifetimeMs: defaultSandboxMaxLifetimeMs\n})\n\nexport const defaultSandboxInitialSource = EmptySandboxInitialSource.make({})\n\nexport type SandboxRecreateReason = 'idle_expired' | 'max_expired' | 'name_mismatch'\n\nconst SandboxUseExistingDecision = Schema.TaggedStruct('UseExisting', {\n state: Schema.Unknown\n})\n\nconst SandboxCreateDecision = Schema.TaggedStruct('Create', {\n workspaceReset: Schema.Boolean,\n reason: Schema.optionalKey(Schema.Literals(['idle_expired', 'max_expired', 'name_mismatch']))\n})\n\nexport type SandboxStateDecision =\n | {\n readonly _tag: 'UseExisting'\n readonly state: SandboxState\n }\n | typeof SandboxCreateDecision.Type\n\nconst existingSandboxStateDecision = (state: SandboxState): SandboxStateDecision => ({\n ...SandboxUseExistingDecision.make({ state }),\n state\n})\n\nconst positiveOr = (value: number | undefined, fallback: number) =>\n value === undefined || !Number.isFinite(value) || value <= 0 ? fallback : Math.floor(value)\n\nexport const sandboxLifecycleOrDefault = (lifecycle?: SandboxLifecycle): SandboxLifecycle =>\n lifecycle ?? defaultSandboxLifecycle\n\nexport const sandboxSourceOrDefault = (source?: SandboxInitialSource): SandboxInitialSource =>\n source ?? defaultSandboxInitialSource\n\nexport const sandboxCommandTimeoutMs = (timeoutMs?: number) =>\n Math.min(maxSandboxCommandTimeoutMs, positiveOr(timeoutMs, defaultSandboxCommandTimeoutMs))\n\nexport const validateSandboxCommand = (command: string) => {\n if (command.trim().length === 0) {\n return Effect.fail(\n new SandboxInputError({\n cause: 'empty_command',\n message: 'Sandbox command must not be empty'\n })\n )\n }\n\n return Effect.succeed(command)\n}\n\nexport const normalizeWorkspaceCwd = (\n cwd?: string | null\n): Effect.Effect<string, SandboxInputError> => {\n if (cwd === undefined || cwd === null || cwd.trim().length === 0) {\n return Effect.succeed('.')\n }\n\n const trimmed = cwd.trim()\n\n if (trimmed.startsWith('/') || trimmed.includes('\\0')) {\n return Effect.fail(\n new SandboxInputError({\n cause: 'invalid_cwd',\n message: 'cwd must be workspace-relative'\n })\n )\n }\n\n const parts: Array<string> = []\n\n for (const segment of trimmed.split('/')) {\n if (segment.length === 0 || segment === '.') {\n continue\n }\n\n if (segment === '..') {\n const previous = parts.pop()\n\n if (previous === undefined) {\n return Effect.fail(\n new SandboxInputError({\n cause: 'invalid_cwd',\n message: 'cwd must not escape the workspace'\n })\n )\n }\n\n continue\n }\n\n parts.push(segment)\n }\n\n return Effect.succeed(parts.length === 0 ? '.' : parts.join('/'))\n}\n\nexport const absoluteSandboxCwd = (workspaceRoot: string, normalizedCwd: string) =>\n normalizedCwd === '.' ? workspaceRoot : `${workspaceRoot}/${normalizedCwd}`\n\nexport const initialSandboxState = (input: {\n readonly name: string\n readonly nowMs: number\n readonly lifecycle: SandboxLifecycle\n}) =>\n Match.value(input.lifecycle).pipe(\n Match.withReturnType<SandboxState>(),\n Match.tag('Disposable', lifecycle =>\n VercelSandboxState.make({\n name: input.name,\n createdAtMs: input.nowMs,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: input.nowMs + lifecycle.idleTtlMs,\n maxExpiresAtMs: input.nowMs + lifecycle.maxLifetimeMs\n })\n ),\n Match.tag('Persistent', lifecycle =>\n VercelSandboxState.make({\n name: input.name,\n createdAtMs: input.nowMs,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: input.nowMs + lifecycle.idleTtlMs,\n maxExpiresAtMs: Number.MAX_SAFE_INTEGER\n })\n ),\n Match.exhaustive\n )\n\nexport const touchSandboxState = (input: {\n readonly state: SandboxState\n readonly nowMs: number\n readonly lifecycle: SandboxLifecycle\n}) =>\n Match.value(input.lifecycle).pipe(\n Match.withReturnType<SandboxState>(),\n Match.tag('Disposable', lifecycle =>\n VercelSandboxState.make({\n ...input.state,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: Math.min(input.nowMs + lifecycle.idleTtlMs, input.state.maxExpiresAtMs)\n })\n ),\n Match.tag('Persistent', lifecycle =>\n VercelSandboxState.make({\n ...input.state,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: input.nowMs + lifecycle.idleTtlMs\n })\n ),\n Match.exhaustive\n )\n\nexport const sandboxTimeoutExtendDeltaMs = (input: {\n readonly before: SandboxState\n readonly after: SandboxState\n}) => Math.max(0, input.after.expiresAtMs - input.before.expiresAtMs)\n\nexport const sandboxStateDecision = (input: {\n readonly state: Option.Option<SandboxState>\n readonly name: string\n readonly nowMs: number\n readonly lifecycle: SandboxLifecycle\n}): SandboxStateDecision => {\n if (Option.isNone(input.state)) {\n return SandboxCreateDecision.make({ workspaceReset: false })\n }\n\n const state = input.state.value\n\n if (state.name !== input.name) {\n return SandboxCreateDecision.make({ workspaceReset: true, reason: 'name_mismatch' })\n }\n\n if (Predicate.isTagged(input.lifecycle, 'Persistent')) {\n return existingSandboxStateDecision(state)\n }\n\n if (input.nowMs >= state.maxExpiresAtMs) {\n return SandboxCreateDecision.make({ workspaceReset: true, reason: 'max_expired' })\n }\n\n if (input.nowMs >= state.expiresAtMs) {\n return SandboxCreateDecision.make({ workspaceReset: true, reason: 'idle_expired' })\n }\n\n return existingSandboxStateDecision(state)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecycle.mjs","names":[],"sources":["../src/lifecycle.ts"],"sourcesContent":["import { Effect, Match, Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { SandboxInputError } from './errors.ts'\nimport {\n DisposableSandboxLifecycle,\n EmptySandboxInitialSource,\n type SandboxInitialSource,\n type SandboxLifecycle,\n type SandboxState,\n VercelSandboxState\n} from './model.ts'\n\nexport const defaultSandboxIdleTtlMs = 30 * 60_000\n\nexport const defaultSandboxMaxLifetimeMs = 45 * 60_000\n\nexport const defaultSandboxCommandTimeoutMs = 120_000\n\nexport const maxSandboxCommandTimeoutMs = 600_000\n\nexport const backgroundSandboxProbeMs = 2_000\n\nexport const sandboxToolOutputLimit = 50_000\n\nexport const defaultSandboxPorts: ReadonlyArray<number> = [3000, 5173, 4321, 8000]\n\nexport const defaultSandboxWorkspaceRoot = '/vercel/sandbox'\n\nconst isNormalizedWorkspaceCwd = (value: string): boolean => {\n if (value.length === 0 || value.includes('\\0')) return false\n\n if (value === '.') return true\n\n // Segment whitespace is a valid filename: removing './' or a trailing '/.'\n // can expose it even though the raw input was trimmed before normalization.\n if (value.startsWith('/') || value.endsWith('/') || value.includes('//')) return false\n\n return value.split('/').every(segment => segment !== '' && segment !== '.' && segment !== '..')\n}\n\nexport const NormalizedWorkspaceCwd = Schema.String.pipe(\n Schema.check(\n Schema.makeFilter(isNormalizedWorkspaceCwd, { identifier: 'NormalizedWorkspaceCwd' })\n ),\n Schema.brand('NormalizedWorkspaceCwd')\n)\n\nexport type NormalizedWorkspaceCwd = typeof NormalizedWorkspaceCwd.Type\n\nexport const defaultSandboxLifecycle = DisposableSandboxLifecycle.make({\n idleTtlMs: defaultSandboxIdleTtlMs,\n maxLifetimeMs: defaultSandboxMaxLifetimeMs\n})\n\nexport const defaultSandboxInitialSource = EmptySandboxInitialSource.make({})\n\nexport type SandboxRecreateReason = 'idle_expired' | 'max_expired' | 'name_mismatch'\n\nconst SandboxUseExistingDecision = Schema.TaggedStruct('UseExisting', {\n state: Schema.Unknown\n})\n\nconst SandboxCreateDecision = Schema.TaggedStruct('Create', {\n workspaceReset: Schema.Boolean,\n reason: Schema.optionalKey(Schema.Literals(['idle_expired', 'max_expired', 'name_mismatch']))\n})\n\nexport type SandboxStateDecision =\n | {\n readonly _tag: 'UseExisting'\n readonly state: SandboxState\n }\n | typeof SandboxCreateDecision.Type\n\nconst existingSandboxStateDecision = (state: SandboxState): SandboxStateDecision => ({\n ...SandboxUseExistingDecision.make({ state }),\n state\n})\n\nconst positiveOr = (value: number | undefined, fallback: number) =>\n value === undefined || !Number.isFinite(value) || value <= 0 ? fallback : Math.floor(value)\n\nexport const sandboxLifecycleOrDefault = (lifecycle?: SandboxLifecycle): SandboxLifecycle =>\n lifecycle ?? defaultSandboxLifecycle\n\nexport const sandboxSourceOrDefault = (source?: SandboxInitialSource): SandboxInitialSource =>\n source ?? defaultSandboxInitialSource\n\nexport const sandboxCommandTimeoutMs = (timeoutMs?: number) =>\n Math.min(maxSandboxCommandTimeoutMs, positiveOr(timeoutMs, defaultSandboxCommandTimeoutMs))\n\nexport const validateSandboxCommand = (command: string) => {\n if (command.trim().length === 0) {\n return Effect.fail(\n new SandboxInputError({\n cause: 'empty_command',\n message: 'Sandbox command must not be empty'\n })\n )\n }\n\n return Effect.succeed(command)\n}\n\nexport const normalizeWorkspaceCwd = (\n cwd?: string | null\n): Effect.Effect<NormalizedWorkspaceCwd, SandboxInputError> => {\n if (cwd === undefined || cwd === null || cwd.trim().length === 0) {\n return Effect.succeed(NormalizedWorkspaceCwd.make('.'))\n }\n\n const trimmed = cwd.trim()\n\n if (trimmed.startsWith('/') || trimmed.includes('\\0')) {\n return Effect.fail(\n new SandboxInputError({\n cause: 'invalid_cwd',\n message: 'cwd must be workspace-relative'\n })\n )\n }\n\n const parts: Array<string> = []\n\n for (const segment of trimmed.split('/')) {\n if (segment.length === 0 || segment === '.') {\n continue\n }\n\n if (segment === '..') {\n const previous = parts.pop()\n\n if (previous === undefined) {\n return Effect.fail(\n new SandboxInputError({\n cause: 'invalid_cwd',\n message: 'cwd must not escape the workspace'\n })\n )\n }\n\n continue\n }\n\n parts.push(segment)\n }\n\n return Schema.decodeUnknownEffect(NormalizedWorkspaceCwd)(\n parts.length === 0 ? '.' : parts.join('/')\n ).pipe(\n Effect.mapError(\n () =>\n new SandboxInputError({\n cause: 'invalid_cwd',\n message: 'cwd must be workspace-relative'\n })\n )\n )\n}\n\nexport const absoluteSandboxCwd = (workspaceRoot: string, normalizedCwd: NormalizedWorkspaceCwd) =>\n normalizedCwd === '.' ? workspaceRoot : `${workspaceRoot}/${normalizedCwd}`\n\nexport const initialSandboxState = (input: {\n readonly name: string\n readonly nowMs: number\n readonly lifecycle: SandboxLifecycle\n}) =>\n Match.value(input.lifecycle).pipe(\n Match.withReturnType<SandboxState>(),\n Match.tag('Disposable', lifecycle =>\n VercelSandboxState.make({\n name: input.name,\n createdAtMs: input.nowMs,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: input.nowMs + lifecycle.idleTtlMs,\n maxExpiresAtMs: input.nowMs + lifecycle.maxLifetimeMs\n })\n ),\n Match.tag('Persistent', lifecycle =>\n VercelSandboxState.make({\n name: input.name,\n createdAtMs: input.nowMs,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: input.nowMs + lifecycle.idleTtlMs,\n maxExpiresAtMs: Number.MAX_SAFE_INTEGER\n })\n ),\n Match.exhaustive\n )\n\nexport const touchSandboxState = (input: {\n readonly state: SandboxState\n readonly nowMs: number\n readonly lifecycle: SandboxLifecycle\n}) =>\n Match.value(input.lifecycle).pipe(\n Match.withReturnType<SandboxState>(),\n Match.tag('Disposable', lifecycle =>\n VercelSandboxState.make({\n ...input.state,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: Math.min(input.nowMs + lifecycle.idleTtlMs, input.state.maxExpiresAtMs)\n })\n ),\n Match.tag('Persistent', lifecycle =>\n VercelSandboxState.make({\n ...input.state,\n lastUsedAtMs: input.nowMs,\n expiresAtMs: input.nowMs + lifecycle.idleTtlMs\n })\n ),\n Match.exhaustive\n )\n\nexport const sandboxTimeoutExtendDeltaMs = (input: {\n readonly before: SandboxState\n readonly after: SandboxState\n}) => Math.max(0, input.after.expiresAtMs - input.before.expiresAtMs)\n\nexport const sandboxStateDecision = (input: {\n readonly state: Option.Option<SandboxState>\n readonly name: string\n readonly nowMs: number\n readonly lifecycle: SandboxLifecycle\n}): SandboxStateDecision => {\n if (Option.isNone(input.state)) {\n return SandboxCreateDecision.make({ workspaceReset: false })\n }\n\n const state = input.state.value\n\n if (state.name !== input.name) {\n return SandboxCreateDecision.make({ workspaceReset: true, reason: 'name_mismatch' })\n }\n\n if (Predicate.isTagged(input.lifecycle, 'Persistent')) {\n return existingSandboxStateDecision(state)\n }\n\n if (input.nowMs >= state.maxExpiresAtMs) {\n return SandboxCreateDecision.make({ workspaceReset: true, reason: 'max_expired' })\n }\n\n if (input.nowMs >= state.expiresAtMs) {\n return SandboxCreateDecision.make({ workspaceReset: true, reason: 'idle_expired' })\n }\n\n return existingSandboxStateDecision(state)\n}\n"],"mappings":"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"}
|
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.80",
|
|
4
4
|
"description": "Effect-native sandbox execution contracts, an agent tool, testing fakes, and a Vercel Sandbox adapter.",
|
|
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-rc.115",
|
|
64
|
-
"@yolk-sdk/agent": "^0.1.0-canary.
|
|
64
|
+
"@yolk-sdk/agent": "^0.1.0-canary.80"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsdown",
|
package/src/index.ts
CHANGED
package/src/lifecycle.ts
CHANGED
|
@@ -26,6 +26,27 @@ export const defaultSandboxPorts: ReadonlyArray<number> = [3000, 5173, 4321, 800
|
|
|
26
26
|
|
|
27
27
|
export const defaultSandboxWorkspaceRoot = '/vercel/sandbox'
|
|
28
28
|
|
|
29
|
+
const isNormalizedWorkspaceCwd = (value: string): boolean => {
|
|
30
|
+
if (value.length === 0 || value.includes('\0')) return false
|
|
31
|
+
|
|
32
|
+
if (value === '.') return true
|
|
33
|
+
|
|
34
|
+
// Segment whitespace is a valid filename: removing './' or a trailing '/.'
|
|
35
|
+
// can expose it even though the raw input was trimmed before normalization.
|
|
36
|
+
if (value.startsWith('/') || value.endsWith('/') || value.includes('//')) return false
|
|
37
|
+
|
|
38
|
+
return value.split('/').every(segment => segment !== '' && segment !== '.' && segment !== '..')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const NormalizedWorkspaceCwd = Schema.String.pipe(
|
|
42
|
+
Schema.check(
|
|
43
|
+
Schema.makeFilter(isNormalizedWorkspaceCwd, { identifier: 'NormalizedWorkspaceCwd' })
|
|
44
|
+
),
|
|
45
|
+
Schema.brand('NormalizedWorkspaceCwd')
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
export type NormalizedWorkspaceCwd = typeof NormalizedWorkspaceCwd.Type
|
|
49
|
+
|
|
29
50
|
export const defaultSandboxLifecycle = DisposableSandboxLifecycle.make({
|
|
30
51
|
idleTtlMs: defaultSandboxIdleTtlMs,
|
|
31
52
|
maxLifetimeMs: defaultSandboxMaxLifetimeMs
|
|
@@ -83,9 +104,9 @@ export const validateSandboxCommand = (command: string) => {
|
|
|
83
104
|
|
|
84
105
|
export const normalizeWorkspaceCwd = (
|
|
85
106
|
cwd?: string | null
|
|
86
|
-
): Effect.Effect<
|
|
107
|
+
): Effect.Effect<NormalizedWorkspaceCwd, SandboxInputError> => {
|
|
87
108
|
if (cwd === undefined || cwd === null || cwd.trim().length === 0) {
|
|
88
|
-
return Effect.succeed('.')
|
|
109
|
+
return Effect.succeed(NormalizedWorkspaceCwd.make('.'))
|
|
89
110
|
}
|
|
90
111
|
|
|
91
112
|
const trimmed = cwd.trim()
|
|
@@ -124,10 +145,20 @@ export const normalizeWorkspaceCwd = (
|
|
|
124
145
|
parts.push(segment)
|
|
125
146
|
}
|
|
126
147
|
|
|
127
|
-
return
|
|
148
|
+
return Schema.decodeUnknownEffect(NormalizedWorkspaceCwd)(
|
|
149
|
+
parts.length === 0 ? '.' : parts.join('/')
|
|
150
|
+
).pipe(
|
|
151
|
+
Effect.mapError(
|
|
152
|
+
() =>
|
|
153
|
+
new SandboxInputError({
|
|
154
|
+
cause: 'invalid_cwd',
|
|
155
|
+
message: 'cwd must be workspace-relative'
|
|
156
|
+
})
|
|
157
|
+
)
|
|
158
|
+
)
|
|
128
159
|
}
|
|
129
160
|
|
|
130
|
-
export const absoluteSandboxCwd = (workspaceRoot: string, normalizedCwd:
|
|
161
|
+
export const absoluteSandboxCwd = (workspaceRoot: string, normalizedCwd: NormalizedWorkspaceCwd) =>
|
|
131
162
|
normalizedCwd === '.' ? workspaceRoot : `${workspaceRoot}/${normalizedCwd}`
|
|
132
163
|
|
|
133
164
|
export const initialSandboxState = (input: {
|