@codeworksh/plugin 0.0.1-canary.10.1.g65d5c167
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/LICENSE +21 -0
- package/README.md +111 -0
- package/error-ClDISWlT.d.mts +11 -0
- package/event-9PbbjnHJ.d.mts +895 -0
- package/event.d.mts +2 -0
- package/event.mjs +125 -0
- package/event.mjs.map +1 -0
- package/filesystem-Cp-KapCE.d.mts +142 -0
- package/ids-CHjmAdTc.d.mts +43 -0
- package/ids.d.mts +2 -0
- package/ids.mjs +48 -0
- package/ids.mjs.map +1 -0
- package/index.d.mts +3 -0
- package/index.mjs +3 -0
- package/io-BYs7hbiY.d.mts +497 -0
- package/location-D4hAfuXF.d.mts +61 -0
- package/location.d.mts +2 -0
- package/location.mjs +48 -0
- package/location.mjs.map +1 -0
- package/package.json +169 -0
- package/plugin/prompt.d.mts +2 -0
- package/plugin/prompt.mjs +7 -0
- package/plugin/prompt.mjs.map +1 -0
- package/plugin/tool.d.mts +2 -0
- package/plugin/tool.mjs +29 -0
- package/plugin/tool.mjs.map +1 -0
- package/plugin-DHCdfzdO.d.mts +140 -0
- package/plugin-lorpq7Oi.mjs +41 -0
- package/plugin-lorpq7Oi.mjs.map +1 -0
- package/plugin.d.mts +4 -0
- package/plugin.mjs +4 -0
- package/posix.d.mts +6 -0
- package/posix.mjs +8 -0
- package/posix.mjs.map +1 -0
- package/project-CLGsIFD-.d.mts +21 -0
- package/project.d.mts +2 -0
- package/project.mjs +22 -0
- package/project.mjs.map +1 -0
- package/prompt-BcpagjGh.d.mts +10 -0
- package/repo.d.mts +42 -0
- package/repo.mjs +46 -0
- package/repo.mjs.map +1 -0
- package/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/sandbox/driver.d.mts +2 -0
- package/sandbox/driver.mjs +63 -0
- package/sandbox/driver.mjs.map +1 -0
- package/sandbox/errors.d.mts +2 -0
- package/sandbox/errors.mjs +160 -0
- package/sandbox/errors.mjs.map +1 -0
- package/sandbox/filesystem.d.mts +2 -0
- package/sandbox/filesystem.mjs +142 -0
- package/sandbox/filesystem.mjs.map +1 -0
- package/sandbox/instance.d.mts +2 -0
- package/sandbox/instance.mjs +144 -0
- package/sandbox/instance.mjs.map +1 -0
- package/sandbox/io.d.mts +2 -0
- package/sandbox/io.mjs +127 -0
- package/sandbox/io.mjs.map +1 -0
- package/sandbox/resource.d.mts +28 -0
- package/sandbox/resource.mjs +29 -0
- package/sandbox/resource.mjs.map +1 -0
- package/sandbox/shell.d.mts +2 -0
- package/sandbox/shell.mjs +93 -0
- package/sandbox/shell.mjs.map +1 -0
- package/sandbox.d.mts +19 -0
- package/sandbox.mjs +49 -0
- package/sandbox.mjs.map +1 -0
- package/schema.d.mts +93 -0
- package/schema.mjs +107 -0
- package/schema.mjs.map +1 -0
- package/settings-C6RxGd-M.d.mts +557 -0
- package/settings.d.mts +2 -0
- package/settings.mjs +132 -0
- package/settings.mjs.map +1 -0
- package/shell-CZ6Y4lNU.d.mts +109 -0
- package/space-CR-9UxdT.d.mts +25 -0
- package/space.d.mts +2 -0
- package/space.mjs +33 -0
- package/space.mjs.map +1 -0
- package/tool/error.d.mts +2 -0
- package/tool/error.mjs +11 -0
- package/tool/error.mjs.map +1 -0
- package/tool/progress.d.mts +2 -0
- package/tool/progress.mjs +11 -0
- package/tool/progress.mjs.map +1 -0
- package/tool-BoVqkYvL.d.mts +287 -0
- package/tool-DuYBgiJf.d.mts +142 -0
- package/tool.d.mts +2 -0
- package/tool.mjs +71 -0
- package/tool.mjs.map +1 -0
package/sandbox/io.mjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { ID } from "./instance.mjs";
|
|
3
|
+
import { posix } from "../posix.mjs";
|
|
4
|
+
import { Service, withCwd } from "./filesystem.mjs";
|
|
5
|
+
import { Shell as Shell$1, withCwd as withCwd$1 } from "./shell.mjs";
|
|
6
|
+
import { Context, Effect, Layer } from "effect";
|
|
7
|
+
//#region src/sandbox/io.ts
|
|
8
|
+
var io_exports = /* @__PURE__ */ __exportAll({
|
|
9
|
+
Current: () => Current,
|
|
10
|
+
FileSystem: () => FileSystem,
|
|
11
|
+
SandboxIO: () => io_exports,
|
|
12
|
+
Shell: () => Shell,
|
|
13
|
+
host: () => host,
|
|
14
|
+
hostLayer: () => hostLayer,
|
|
15
|
+
identityLayer: () => identityLayer,
|
|
16
|
+
mount: () => mount,
|
|
17
|
+
remote: () => remote,
|
|
18
|
+
resolveMountCwd: () => resolveMountCwd,
|
|
19
|
+
virtual: () => virtual
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* `SandboxIO` is a **mount**: a filesystem, a shell, and the identity and
|
|
23
|
+
* working directory they act on.
|
|
24
|
+
*
|
|
25
|
+
* It is the whole vocabulary a consumer needs. Project, Git, Copy, Location, and
|
|
26
|
+
* every tool ask for `SandboxIO.FileSystem`, `SandboxIO.Shell`, and
|
|
27
|
+
* `SandboxIO.Current` — never for a driver, an address, or a provider SDK — so
|
|
28
|
+
* a host directory, an in-memory VFS, and a remote microVM are interchangeable
|
|
29
|
+
* behind one contract.
|
|
30
|
+
*
|
|
31
|
+
* The mount neither creates nor destroys infrastructure. `SandboxInstance` is
|
|
32
|
+
* the durable namespace it acts on — a device, which exists whether or not
|
|
33
|
+
* anything has it mounted — and `Sandbox.Controller` is the only path that
|
|
34
|
+
* creates, stops, or destroys one.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* The filesystem tag. Re-exported here so consumers import one namespace —
|
|
38
|
+
* Project, Git, Copy, and the runner ask for `SandboxIO.FileSystem`, never for
|
|
39
|
+
* the module that happens to define it. Code *inside* `sandbox/` keeps importing
|
|
40
|
+
* the tag directly, since `io.ts` is built on top of it.
|
|
41
|
+
*/
|
|
42
|
+
const FileSystem = Service;
|
|
43
|
+
/** The shell tag. Re-exported here so consumers import one namespace. */
|
|
44
|
+
const Shell = Shell$1;
|
|
45
|
+
/** Identity and working directory of the current mount. */
|
|
46
|
+
var Current = class extends Context.Service()("@codeworksh/plugin/sandbox/io/Current") {};
|
|
47
|
+
/**
|
|
48
|
+
* Resolve a mount's cwd without consulting ambient process state.
|
|
49
|
+
*
|
|
50
|
+
* The default is supplied by the namespace adapter:
|
|
51
|
+
* provider metadata remotely, `/` for a virtual filesystem, and `process.cwd()` for the host adapter.
|
|
52
|
+
* An explicit absolute cwd replaces it; a relative cwd is resolved inside it. The
|
|
53
|
+
* result is therefore always the one concrete absolute path `Current` requires.
|
|
54
|
+
*
|
|
55
|
+
* A non-absolute default throws rather than failing typed. It is the one
|
|
56
|
+
* defect-level guard in this module, and deliberately so:
|
|
57
|
+
* Adapters reading a value from a provider call this inside their own error channel,
|
|
58
|
+
* where the throw becomes their typed failure (see `EnvDaytona.mountCwd`).
|
|
59
|
+
*/
|
|
60
|
+
const resolveMountCwd = (defaultCwd, cwd) => {
|
|
61
|
+
if (!posix.isAbsolute(defaultCwd)) throw new TypeError(`Sandbox default cwd must be absolute: ${defaultCwd}`);
|
|
62
|
+
if (cwd === void 0) return posix.resolve(defaultCwd);
|
|
63
|
+
return posix.isAbsolute(cwd) ? posix.resolve(cwd) : posix.resolve(defaultCwd, cwd);
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Bind a cwd-neutral transport to one mount.
|
|
67
|
+
*
|
|
68
|
+
* The transport underneath is shared between
|
|
69
|
+
* mounts and stays rooted at the namespace root, and everything directory-shaped
|
|
70
|
+
* happens here, once per mount. Two mounts of one namespace at different working
|
|
71
|
+
* directories therefore coexist without seeing or moving each other's.
|
|
72
|
+
*
|
|
73
|
+
* It consumes the same two tags it provides — the transport is supplied by the
|
|
74
|
+
* layer this is composed over, not by itself.
|
|
75
|
+
*/
|
|
76
|
+
const mount = (identity) => Layer.mergeAll(Layer.succeed(Current, identity), Layer.effect(Service, Effect.map(Service, (fs) => withCwd(fs, identity.cwd))), Layer.effect(Shell$1, Effect.map(Shell$1, (shell) => withCwd$1(shell, identity.cwd))));
|
|
77
|
+
/**
|
|
78
|
+
* Just the identity tag, with no filesystem or shell beneath it. For consumers
|
|
79
|
+
* assembled from stubs — a test that runs `Project` over a fake filesystem still
|
|
80
|
+
* needs to know which namespace it is in.
|
|
81
|
+
*/
|
|
82
|
+
const identityLayer = (identity) => Layer.succeed(Current, identity);
|
|
83
|
+
/** The host identity alone. See {@link identityLayer}. */
|
|
84
|
+
const hostLayer = (cwd) => identityLayer(host(cwd));
|
|
85
|
+
/**
|
|
86
|
+
* The host, rooted at `cwd`. Always `SandboxInstance.ID.local`: the working
|
|
87
|
+
* directory selects where relative paths resolve, it does not make a second host
|
|
88
|
+
* namespace — two mounts rooted at different directories still agree on absolute
|
|
89
|
+
* paths.
|
|
90
|
+
*
|
|
91
|
+
* The host coordinate is explicit so a caller cannot accidentally substitute ambient process
|
|
92
|
+
* state for the application or session directory it owns.
|
|
93
|
+
*/
|
|
94
|
+
const host = (cwd) => ({
|
|
95
|
+
id: ID.local,
|
|
96
|
+
driver: "local",
|
|
97
|
+
kind: "local",
|
|
98
|
+
cwd: resolveMountCwd(cwd)
|
|
99
|
+
});
|
|
100
|
+
/**
|
|
101
|
+
* A VFS-backed namespace. The id is minted per call unless one is named, because
|
|
102
|
+
* building one of these builds a fresh VFS: N unnamed calls are N distinct
|
|
103
|
+
* namespaces, none of which outlives the process. A file-backed store is the
|
|
104
|
+
* exception — its file is the state, so whoever knows the file supplies the id
|
|
105
|
+
* it was registered under.
|
|
106
|
+
*/
|
|
107
|
+
const virtual = (input) => ({
|
|
108
|
+
id: input.id ?? ID.create(),
|
|
109
|
+
driver: input.driver,
|
|
110
|
+
kind: "virtual",
|
|
111
|
+
cwd: resolveMountCwd(input.defaultCwd ?? "/", input.cwd)
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* A provider-hosted namespace. The id is always supplied: a remote resource's
|
|
115
|
+
* durable identity is minted and recorded by whoever provisioned it, never
|
|
116
|
+
* derived here from the provider's own locator.
|
|
117
|
+
*/
|
|
118
|
+
const remote = (input) => ({
|
|
119
|
+
id: input.id,
|
|
120
|
+
driver: input.driver,
|
|
121
|
+
kind: "remote",
|
|
122
|
+
cwd: resolveMountCwd(input.defaultCwd, input.cwd)
|
|
123
|
+
});
|
|
124
|
+
//#endregion
|
|
125
|
+
export { Current, FileSystem, io_exports as SandboxIO, Shell, host, hostLayer, identityLayer, mount, remote, resolveMountCwd, virtual };
|
|
126
|
+
|
|
127
|
+
//# sourceMappingURL=io.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.mjs","names":["SandboxFileSystem.Service","ShellTag","EffectLayer","SandboxFileSystem.withCwd","shellWithCwd"],"sources":["../../../src/sandbox/io.ts"],"sourcesContent":["import { Context, Effect, Layer as EffectLayer } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport type { SandboxDriver } from \"./driver.ts\";\nimport { SandboxFileSystem } from \"./filesystem.ts\";\nimport { SandboxInstance } from \"./instance.ts\";\nimport { type ISandboxExe, Shell as ShellTag, withCwd as shellWithCwd } from \"./shell.ts\";\n\n/**\n * `SandboxIO` is a **mount**: a filesystem, a shell, and the identity and\n * working directory they act on.\n *\n * It is the whole vocabulary a consumer needs. Project, Git, Copy, Location, and\n * every tool ask for `SandboxIO.FileSystem`, `SandboxIO.Shell`, and\n * `SandboxIO.Current` — never for a driver, an address, or a provider SDK — so\n * a host directory, an in-memory VFS, and a remote microVM are interchangeable\n * behind one contract.\n *\n * The mount neither creates nor destroys infrastructure. `SandboxInstance` is\n * the durable namespace it acts on — a device, which exists whether or not\n * anything has it mounted — and `Sandbox.Controller` is the only path that\n * creates, stops, or destroys one.\n */\n\n/**\n * The filesystem tag. Re-exported here so consumers import one namespace —\n * Project, Git, Copy, and the runner ask for `SandboxIO.FileSystem`, never for\n * the module that happens to define it. Code *inside* `sandbox/` keeps importing\n * the tag directly, since `io.ts` is built on top of it.\n */\nexport const FileSystem = SandboxFileSystem.Service;\nexport type FileSystem = SandboxFileSystem.Service;\n\n/** The shell tag. Re-exported here so consumers import one namespace. */\nexport const Shell = ShellTag;\nexport type Shell = ShellTag;\n\n/**\n * What a mount sees: immutable identity, plus the working directory resolved for\n * *this* mount.\n *\n * Nothing mutable belongs here. `status`, `usage`, and reference counts all\n * change while a mount is open, so a mount-time snapshot of them would be wrong\n * by construction — runtime code that needs live management state asks the\n * control plane. The driver's own resource locator is likewise absent: consumers\n * never parse a Vercel name or a Daytona id.\n */\nexport interface Identity {\n\treadonly id: SandboxInstance.ID;\n\treadonly driver: SandboxDriver.Name;\n\treadonly kind: SandboxInstance.Kind;\n\t/** Absolute, and always a path in *this* namespace. */\n\treadonly cwd: string;\n}\n\n/** Identity and working directory of the current mount. */\nexport class Current extends Context.Service<Current, Identity>()(\"@codeworksh/plugin/sandbox/io/Current\") {}\n\n/** Everything a mount provides. */\nexport type Provides = Current | SandboxFileSystem.Service | ShellTag;\n\n/** A built mount. */\nexport type Layer<E = never, RIn = never> = EffectLayer.Layer<Provides, E, RIn>;\n\n/**\n * Resolve a mount's cwd without consulting ambient process state.\n *\n * The default is supplied by the namespace adapter:\n * provider metadata remotely, `/` for a virtual filesystem, and `process.cwd()` for the host adapter.\n * An explicit absolute cwd replaces it; a relative cwd is resolved inside it. The\n * result is therefore always the one concrete absolute path `Current` requires.\n *\n * A non-absolute default throws rather than failing typed. It is the one\n * defect-level guard in this module, and deliberately so:\n * Adapters reading a value from a provider call this inside their own error channel,\n * where the throw becomes their typed failure (see `EnvDaytona.mountCwd`).\n */\nexport const resolveMountCwd = (defaultCwd: string, cwd?: string): string => {\n\tif (!posix.isAbsolute(defaultCwd)) {\n\t\tthrow new TypeError(`Sandbox default cwd must be absolute: ${defaultCwd}`);\n\t}\n\t// `resolve`, not `normalize`: normalize keeps a trailing slash, and `cwd` is\n\t// persisted — `space.location` and its id hash would read\n\t// `/workspace/` and `/workspace` as two directories and keep a row for each.\n\t//\n\t// A provider-reported default (`getWorkDir()`) or a config value is free to\n\t// carry one, so it is stripped here rather than at every reader.\n\tif (cwd === undefined) return posix.resolve(defaultCwd);\n\treturn posix.isAbsolute(cwd) ? posix.resolve(cwd) : posix.resolve(defaultCwd, cwd);\n};\n\n/**\n * Bind a cwd-neutral transport to one mount.\n *\n * The transport underneath is shared between\n * mounts and stays rooted at the namespace root, and everything directory-shaped\n * happens here, once per mount. Two mounts of one namespace at different working\n * directories therefore coexist without seeing or moving each other's.\n *\n * It consumes the same two tags it provides — the transport is supplied by the\n * layer this is composed over, not by itself.\n */\nexport const mount = (identity: Identity): EffectLayer.Layer<Provides, never, SandboxFileSystem.Service | ShellTag> =>\n\tEffectLayer.mergeAll(\n\t\tEffectLayer.succeed(Current, identity),\n\t\tEffectLayer.effect(\n\t\t\tSandboxFileSystem.Service,\n\t\t\tEffect.map(SandboxFileSystem.Service, (fs) => SandboxFileSystem.withCwd(fs, identity.cwd)),\n\t\t),\n\t\tEffectLayer.effect(\n\t\t\tShellTag,\n\t\t\tEffect.map(ShellTag, (shell: ISandboxExe) => shellWithCwd(shell, identity.cwd)),\n\t\t),\n\t);\n\n/**\n * Just the identity tag, with no filesystem or shell beneath it. For consumers\n * assembled from stubs — a test that runs `Project` over a fake filesystem still\n * needs to know which namespace it is in.\n */\nexport const identityLayer = (identity: Identity) => EffectLayer.succeed(Current, identity);\n\n/** The host identity alone. See {@link identityLayer}. */\nexport const hostLayer = (cwd: string) => identityLayer(host(cwd));\n\n/**\n * The host, rooted at `cwd`. Always `SandboxInstance.ID.local`: the working\n * directory selects where relative paths resolve, it does not make a second host\n * namespace — two mounts rooted at different directories still agree on absolute\n * paths.\n *\n * The host coordinate is explicit so a caller cannot accidentally substitute ambient process\n * state for the application or session directory it owns.\n */\nexport const host = (cwd: string): Identity => ({\n\tid: SandboxInstance.ID.local,\n\tdriver: \"local\" as SandboxDriver.Name,\n\tkind: \"local\",\n\tcwd: resolveMountCwd(cwd),\n});\n\n/**\n * A VFS-backed namespace. The id is minted per call unless one is named, because\n * building one of these builds a fresh VFS: N unnamed calls are N distinct\n * namespaces, none of which outlives the process. A file-backed store is the\n * exception — its file is the state, so whoever knows the file supplies the id\n * it was registered under.\n */\nexport const virtual = (input: {\n\treadonly driver: string;\n\treadonly id?: SandboxInstance.ID;\n\treadonly defaultCwd?: string;\n\treadonly cwd?: string;\n}): Identity => ({\n\tid: input.id ?? SandboxInstance.ID.create(),\n\tdriver: input.driver as SandboxDriver.Name,\n\tkind: \"virtual\",\n\tcwd: resolveMountCwd(input.defaultCwd ?? \"/\", input.cwd),\n});\n\n/**\n * A provider-hosted namespace. The id is always supplied: a remote resource's\n * durable identity is minted and recorded by whoever provisioned it, never\n * derived here from the provider's own locator.\n */\nexport const remote = (input: {\n\treadonly driver: string;\n\treadonly id: SandboxInstance.ID;\n\t/** Namespace-intrinsic default supplied or discovered by the driver. */\n\treadonly defaultCwd: string;\n\treadonly cwd?: string;\n}): Identity => ({\n\tid: input.id,\n\tdriver: input.driver as SandboxDriver.Name,\n\tkind: \"remote\",\n\tcwd: resolveMountCwd(input.defaultCwd, input.cwd),\n});\n\nexport * as SandboxIO from \"./io.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,aAAaA;;AAI1B,MAAa,QAAQC;;AAsBrB,IAAa,UAAb,cAA6B,QAAQ,QAA2B,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;AAqB5G,MAAa,mBAAmB,YAAoB,QAAyB;CAC5E,IAAI,CAAC,MAAM,WAAW,UAAU,GAC/B,MAAM,IAAI,UAAU,yCAAyC,YAAY;CAQ1E,IAAI,QAAQ,KAAA,GAAW,OAAO,MAAM,QAAQ,UAAU;CACtD,OAAO,MAAM,WAAW,GAAG,IAAI,MAAM,QAAQ,GAAG,IAAI,MAAM,QAAQ,YAAY,GAAG;AAClF;;;;;;;;;;;;AAaA,MAAa,SAAS,aACrBC,MAAY,SACXA,MAAY,QAAQ,SAAS,QAAQ,GACrCA,MAAY,OACXF,SACA,OAAO,IAAIA,UAA4B,OAAOG,QAA0B,IAAI,SAAS,GAAG,CAAC,CAC1F,GACAD,MAAY,OACXD,SACA,OAAO,IAAIA,UAAW,UAAuBG,UAAa,OAAO,SAAS,GAAG,CAAC,CAC/E,CACD;;;;;;AAOD,MAAa,iBAAiB,aAAuBF,MAAY,QAAQ,SAAS,QAAQ;;AAG1F,MAAa,aAAa,QAAgB,cAAc,KAAK,GAAG,CAAC;;;;;;;;;;AAWjE,MAAa,QAAQ,SAA2B;CAC/C,IAAA,GAAuB;CACvB,QAAQ;CACR,MAAM;CACN,KAAK,gBAAgB,GAAG;AACzB;;;;;;;;AASA,MAAa,WAAW,WAKP;CAChB,IAAI,MAAM,MAAA,GAAyB,OAAO;CAC1C,QAAQ,MAAM;CACd,MAAM;CACN,KAAK,gBAAgB,MAAM,cAAc,KAAK,MAAM,GAAG;AACxD;;;;;;AAOA,MAAa,UAAU,WAMN;CAChB,IAAI,MAAM;CACV,QAAQ,MAAM;CACd,MAAM;CACN,KAAK,gBAAgB,MAAM,YAAY,MAAM,GAAG;AACjD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
declare namespace resource_d_exports {
|
|
3
|
+
export { resource_d_exports as SandboxResource, Service };
|
|
4
|
+
}
|
|
5
|
+
declare const Service_base: Context.ServiceClass<Service, "@codeworksh/plugin/sandbox/resource/Service", {
|
|
6
|
+
readonly providerResourceId: string;
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* The driver's own locator for the attached resource — a Vercel sandbox name, a
|
|
10
|
+
* Daytona sandbox id.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately *not* on `SandboxIO.Current`: consumers never parse one,
|
|
13
|
+
* and keeps it separate from the application id precisely so a driver's format can
|
|
14
|
+
* change without touching identity.
|
|
15
|
+
*
|
|
16
|
+
* It exists for the control plane, which records it as `provider_resource_id`,
|
|
17
|
+
* and for tests that reattach to the same resource.
|
|
18
|
+
*
|
|
19
|
+
* One tag for every driver rather than one per driver. A mount has exactly one
|
|
20
|
+
* driver, so there is nothing to disambiguate, and the control plane has to read
|
|
21
|
+
* the locator without knowing which driver produced it — keeps the
|
|
22
|
+
* driver name open, so anything keyed on a closed `"vercel" | "daytona"` set is
|
|
23
|
+
* a bug waiting for the third driver.
|
|
24
|
+
*/
|
|
25
|
+
export declare class Service extends Service_base {}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { resource_d_exports as SandboxResource };
|
|
28
|
+
//# sourceMappingURL=resource.d.mts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Context } from "effect";
|
|
3
|
+
//#region src/sandbox/resource.ts
|
|
4
|
+
var resource_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
SandboxResource: () => resource_exports,
|
|
6
|
+
Service: () => Service
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* The driver's own locator for the attached resource — a Vercel sandbox name, a
|
|
10
|
+
* Daytona sandbox id.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately *not* on `SandboxIO.Current`: consumers never parse one,
|
|
13
|
+
* and keeps it separate from the application id precisely so a driver's format can
|
|
14
|
+
* change without touching identity.
|
|
15
|
+
*
|
|
16
|
+
* It exists for the control plane, which records it as `provider_resource_id`,
|
|
17
|
+
* and for tests that reattach to the same resource.
|
|
18
|
+
*
|
|
19
|
+
* One tag for every driver rather than one per driver. A mount has exactly one
|
|
20
|
+
* driver, so there is nothing to disambiguate, and the control plane has to read
|
|
21
|
+
* the locator without knowing which driver produced it — keeps the
|
|
22
|
+
* driver name open, so anything keyed on a closed `"vercel" | "daytona"` set is
|
|
23
|
+
* a bug waiting for the third driver.
|
|
24
|
+
*/
|
|
25
|
+
var Service = class extends Context.Service()("@codeworksh/plugin/sandbox/resource/Service") {};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { resource_exports as SandboxResource, Service };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=resource.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.mjs","names":[],"sources":["../../../src/sandbox/resource.ts"],"sourcesContent":["import { Context } from \"effect\";\n\n/**\n * The driver's own locator for the attached resource — a Vercel sandbox name, a\n * Daytona sandbox id.\n *\n * Deliberately *not* on `SandboxIO.Current`: consumers never parse one,\n * and keeps it separate from the application id precisely so a driver's format can\n * change without touching identity.\n *\n * It exists for the control plane, which records it as `provider_resource_id`,\n * and for tests that reattach to the same resource.\n *\n * One tag for every driver rather than one per driver. A mount has exactly one\n * driver, so there is nothing to disambiguate, and the control plane has to read\n * the locator without knowing which driver produced it — keeps the\n * driver name open, so anything keyed on a closed `\"vercel\" | \"daytona\"` set is\n * a bug waiting for the third driver.\n */\nexport class Service extends Context.Service<Service, { readonly providerResourceId: string }>()(\n\t\"@codeworksh/plugin/sandbox/resource/Service\",\n) {}\n\nexport * as SandboxResource from \"./resource.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAmBA,IAAa,UAAb,cAA6B,QAAQ,QAA0D,CAAC,CAC/F,6CACD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as ShellError, c as perMount, d as resolveCwd, f as withCwd, i as Shell, l as quote, n as ExecResult, o as ShellOptions, r as ISandboxExe, s as fromExec, t as ExecChunk, u as quoteArgv } from "../shell-CZ6Y4lNU.mjs";
|
|
2
|
+
export { ExecChunk, ExecResult, ISandboxExe, Shell, ShellError, ShellOptions, fromExec, perMount, quote, quoteArgv, resolveCwd, withCwd };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { posix } from "../posix.mjs";
|
|
2
|
+
import { Context, Schema } from "effect";
|
|
3
|
+
//#region src/sandbox/shell.ts
|
|
4
|
+
/**
|
|
5
|
+
* The pluggable execution contract. Local sandboxes usually get a Shell through
|
|
6
|
+
* just-bash over the local `Local.Vfs`; remote sandboxes provide their own
|
|
7
|
+
* native Shell. Either way the rest of the harness depends only on this service
|
|
8
|
+
* tag.
|
|
9
|
+
*/
|
|
10
|
+
var ShellError = class extends Schema.TaggedError()("ShellError", {
|
|
11
|
+
command: Schema.String,
|
|
12
|
+
cause: Schema.optional(Schema.Defect())
|
|
13
|
+
}) {};
|
|
14
|
+
/**
|
|
15
|
+
* Mount-local shell factories are attached out-of-band so the public Shell
|
|
16
|
+
* contract stays about command execution only.
|
|
17
|
+
*
|
|
18
|
+
* Most transports are safely shared and need only the cwd wrapper below.
|
|
19
|
+
* Stateful in-process interpreters use this hook to construct one interpreter
|
|
20
|
+
* per mount while retaining the underlying filesystem transport. This tag must
|
|
21
|
+
* remain on the outermost wrapper consumed by {@link withCwd}; wrapper helpers
|
|
22
|
+
* such as {@link fromExec} must propagate it when they return a new object.
|
|
23
|
+
*/
|
|
24
|
+
const mountFactories = /* @__PURE__ */ new WeakMap();
|
|
25
|
+
const perMount = (transport, make) => {
|
|
26
|
+
mountFactories.set(transport, make);
|
|
27
|
+
return transport;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* POSIX single-quote escaping: wrap in `'…'` and rewrite each embedded quote as
|
|
31
|
+
* `'\''`. Everything inside single quotes is literal to the shell, so this is
|
|
32
|
+
* safe for arbitrary bytes.
|
|
33
|
+
*/
|
|
34
|
+
const quote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
35
|
+
/** Render an argument vector as one shell-safe command string. */
|
|
36
|
+
const quoteArgv = (argv) => argv.map(quote).join(" ");
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a per-command cwd against the sandbox cwd. Passing a relative cwd
|
|
39
|
+
* straight to a host or remote process API would otherwise resolve it against
|
|
40
|
+
* that API's own default, which need not be the filesystem's configured cwd.
|
|
41
|
+
*/
|
|
42
|
+
const resolveCwd = (base, cwd) => {
|
|
43
|
+
if (cwd === void 0 || posix.isAbsolute(cwd) || base === void 0) return cwd ?? base;
|
|
44
|
+
return posix.resolve(base, cwd);
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Complete a string-only backend: `execArgv` quotes the vector and runs it
|
|
48
|
+
* through `exec`. Backends that spawn a real argument vector (Vercel) implement
|
|
49
|
+
* `execArgv` themselves instead, so the args never meet a shell parser at all.
|
|
50
|
+
*
|
|
51
|
+
* `cwd` rides the options rather than a `cd <dir> && …` prefix. Every backend
|
|
52
|
+
* we wrap takes a working directory natively, and the prefix form cannot tell a
|
|
53
|
+
* failed `cd` from a failed command — both arrive as one exit code.
|
|
54
|
+
*/
|
|
55
|
+
const fromExec = (backend) => {
|
|
56
|
+
const wrapped = {
|
|
57
|
+
...backend,
|
|
58
|
+
execArgv: (argv, options) => backend.exec(quoteArgv(argv), options)
|
|
59
|
+
};
|
|
60
|
+
const mountFactory = mountFactories.get(backend);
|
|
61
|
+
return mountFactory === void 0 ? wrapped : perMount(wrapped, (cwd) => fromExec(mountFactory(cwd)));
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Bind a cwd-neutral backend to one mount's working directory.
|
|
65
|
+
*
|
|
66
|
+
* The transport is shared between mounts and must stay rooted at the namespace
|
|
67
|
+
* root, so the directory cannot live inside it: two mounts at different
|
|
68
|
+
* directories would otherwise see each other's. This wrapper is per mount, and
|
|
69
|
+
* an operation-level `cwd` still wins — resolved against the mount's, so a
|
|
70
|
+
* relative one means what it reads like.
|
|
71
|
+
*/
|
|
72
|
+
const withCwd = (backend, cwd) => {
|
|
73
|
+
const mounted = mountFactories.get(backend)?.(cwd) ?? backend;
|
|
74
|
+
const at = (options) => {
|
|
75
|
+
const resolvedCwd = resolveCwd(cwd, options?.cwd);
|
|
76
|
+
return {
|
|
77
|
+
...options,
|
|
78
|
+
...resolvedCwd === void 0 ? {} : { cwd: resolvedCwd }
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
const stream = mounted.stream;
|
|
82
|
+
return {
|
|
83
|
+
exec: (command, options) => mounted.exec(command, at(options)),
|
|
84
|
+
execArgv: (argv, options) => mounted.execArgv(argv, at(options)),
|
|
85
|
+
...stream === void 0 ? {} : { stream: (command, options) => stream(command, at(options)) }
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
/** Execution service — the live {@link ISandboxExe} for the active sandbox. */
|
|
89
|
+
var Shell = class extends Context.Service()("@codeworksh/plugin/sandbox/shell") {};
|
|
90
|
+
//#endregion
|
|
91
|
+
export { Shell, ShellError, fromExec, perMount, quote, quoteArgv, resolveCwd, withCwd };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=shell.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.mjs","names":["path"],"sources":["../../../src/sandbox/shell.ts"],"sourcesContent":["import { Context, type Effect, Schema, type Stream } from \"effect\";\nimport { posix as path } from \"../posix.ts\";\n\n/**\n * The pluggable execution contract. Local sandboxes usually get a Shell through\n * just-bash over the local `Local.Vfs`; remote sandboxes provide their own\n * native Shell. Either way the rest of the harness depends only on this service\n * tag.\n */\n\nexport class ShellError extends Schema.TaggedError<ShellError>()(\"ShellError\", {\n\tcommand: Schema.String,\n\tcause: Schema.optional(Schema.Defect()),\n}) {}\n\nexport interface ExecResult {\n\treadonly stdout: string;\n\treadonly stderr: string;\n\treadonly exitCode: number;\n}\n\n/**\n * One options shape for every entry point. `cwd` is the operation-level\n * override: it wins over the mount's working directory, and a relative value\n * resolves against it. Neither mutates shared state, so concurrent commands in\n * one mount can run in different directories.\n */\nexport interface ShellOptions {\n\treadonly env?: Record<string, string>;\n\treadonly cwd?: string;\n}\n\n/**\n * A streamed chunk of command output, terminated by a single `exit` carrying the\n * exit code. (A backend-level mirror of the tool layer's event; kept here so\n * `sandbox/` does not depend on `tool/`.)\n */\nexport type ExecChunk =\n\t| { readonly _tag: \"stdout\"; readonly bytes: Uint8Array }\n\t| { readonly _tag: \"stderr\"; readonly bytes: Uint8Array }\n\t| { readonly _tag: \"exit\"; readonly exitCode: number };\n\n/**\n * The command-execution capability a sandbox exposes. For an in-process\n * backend this is just-bash; for a remote backend it is the sandbox's own\n * shell. The {@link Shell} service tag carries this interface.\n */\nexport interface ISandboxExe {\n\treadonly exec: (command: string, options?: ShellOptions) => Effect.Effect<ExecResult, ShellError>;\n\t/**\n\t * Run a program with an explicit argument vector, bypassing shell word\n\t * splitting. Callers that build commands from untrusted values — branch\n\t * names, file paths — must use this instead of interpolating into\n\t * {@link exec}, where a space or `$(…)` would change what runs.\n\t *\n\t * Backends whose transport only accepts a string quote the vector with\n\t * {@link quote}; backends that spawn directly pass it through untouched.\n\t */\n\treadonly execArgv: (argv: ReadonlyArray<string>, options?: ShellOptions) => Effect.Effect<ExecResult, ShellError>;\n\t/**\n\t * Optional streaming output: stdout/stderr chunks then a terminal `exit`.\n\t * Backends that can stream (e.g. Vercel) implement it; `ToolShell.fromSandboxShell`\n\t * bridges it to `ToolShell.stream` so the bash tool streams over them too.\n\t */\n\treadonly stream?: (command: string, options?: ShellOptions) => Stream.Stream<ExecChunk, ShellError>;\n}\n\ntype MountFactory = (cwd: string) => ISandboxExe;\n\n/**\n * Mount-local shell factories are attached out-of-band so the public Shell\n * contract stays about command execution only.\n *\n * Most transports are safely shared and need only the cwd wrapper below.\n * Stateful in-process interpreters use this hook to construct one interpreter\n * per mount while retaining the underlying filesystem transport. This tag must\n * remain on the outermost wrapper consumed by {@link withCwd}; wrapper helpers\n * such as {@link fromExec} must propagate it when they return a new object.\n */\nconst mountFactories = new WeakMap<object, MountFactory>();\n\nexport const perMount = (transport: ISandboxExe, make: MountFactory): ISandboxExe => {\n\tmountFactories.set(transport, make);\n\treturn transport;\n};\n\n/**\n * POSIX single-quote escaping: wrap in `'…'` and rewrite each embedded quote as\n * `'\\''`. Everything inside single quotes is literal to the shell, so this is\n * safe for arbitrary bytes.\n */\nexport const quote = (value: string) => `'${value.replace(/'/g, `'\\\\''`)}'`;\n\n/** Render an argument vector as one shell-safe command string. */\nexport const quoteArgv = (argv: ReadonlyArray<string>) => argv.map(quote).join(\" \");\n\n/**\n * Resolve a per-command cwd against the sandbox cwd. Passing a relative cwd\n * straight to a host or remote process API would otherwise resolve it against\n * that API's own default, which need not be the filesystem's configured cwd.\n */\nexport const resolveCwd = (base: string | undefined, cwd: string | undefined) => {\n\tif (cwd === undefined || path.isAbsolute(cwd) || base === undefined) return cwd ?? base;\n\treturn path.resolve(base, cwd);\n};\n\n/**\n * Complete a string-only backend: `execArgv` quotes the vector and runs it\n * through `exec`. Backends that spawn a real argument vector (Vercel) implement\n * `execArgv` themselves instead, so the args never meet a shell parser at all.\n *\n * `cwd` rides the options rather than a `cd <dir> && …` prefix. Every backend\n * we wrap takes a working directory natively, and the prefix form cannot tell a\n * failed `cd` from a failed command — both arrive as one exit code.\n */\nexport const fromExec = (backend: Omit<ISandboxExe, \"execArgv\">): ISandboxExe => {\n\tconst wrapped: ISandboxExe = {\n\t\t...backend,\n\t\texecArgv: (argv, options) => backend.exec(quoteArgv(argv), options),\n\t};\n\tconst mountFactory = mountFactories.get(backend);\n\treturn mountFactory === undefined ? wrapped : perMount(wrapped, (cwd) => fromExec(mountFactory(cwd)));\n};\n\n/**\n * Bind a cwd-neutral backend to one mount's working directory.\n *\n * The transport is shared between mounts and must stay rooted at the namespace\n * root, so the directory cannot live inside it: two mounts at different\n * directories would otherwise see each other's. This wrapper is per mount, and\n * an operation-level `cwd` still wins — resolved against the mount's, so a\n * relative one means what it reads like.\n */\nexport const withCwd = (backend: ISandboxExe, cwd: string): ISandboxExe => {\n\tconst mounted = mountFactories.get(backend)?.(cwd) ?? backend;\n\tconst at = (options?: ShellOptions): ShellOptions => {\n\t\tconst resolvedCwd = resolveCwd(cwd, options?.cwd);\n\t\treturn { ...options, ...(resolvedCwd === undefined ? {} : { cwd: resolvedCwd }) };\n\t};\n\tconst stream = mounted.stream;\n\treturn {\n\t\texec: (command, options) => mounted.exec(command, at(options)),\n\t\texecArgv: (argv, options) => mounted.execArgv(argv, at(options)),\n\t\t...(stream === undefined ? {} : { stream: (command, options) => stream(command, at(options)) }),\n\t};\n};\n\n/** Execution service — the live {@link ISandboxExe} for the active sandbox. */\nexport class Shell extends Context.Service<Shell, ISandboxExe>()(\"@codeworksh/plugin/sandbox/shell\") {}\n"],"mappings":";;;;;;;;;AAUA,IAAa,aAAb,cAAgC,OAAO,YAAwB,CAAC,CAAC,cAAc;CAC9E,SAAS,OAAO;CAChB,OAAO,OAAO,SAAS,OAAO,OAAO,CAAC;AACvC,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;AAkEJ,MAAM,iCAAiB,IAAI,QAA8B;AAEzD,MAAa,YAAY,WAAwB,SAAoC;CACpF,eAAe,IAAI,WAAW,IAAI;CAClC,OAAO;AACR;;;;;;AAOA,MAAa,SAAS,UAAkB,IAAI,MAAM,QAAQ,MAAM,OAAO,EAAE;;AAGzE,MAAa,aAAa,SAAgC,KAAK,IAAI,KAAK,CAAC,CAAC,KAAK,GAAG;;;;;;AAOlF,MAAa,cAAc,MAA0B,QAA4B;CAChF,IAAI,QAAQ,KAAA,KAAaA,MAAK,WAAW,GAAG,KAAK,SAAS,KAAA,GAAW,OAAO,OAAO;CACnF,OAAOA,MAAK,QAAQ,MAAM,GAAG;AAC9B;;;;;;;;;;AAWA,MAAa,YAAY,YAAwD;CAChF,MAAM,UAAuB;EAC5B,GAAG;EACH,WAAW,MAAM,YAAY,QAAQ,KAAK,UAAU,IAAI,GAAG,OAAO;CACnE;CACA,MAAM,eAAe,eAAe,IAAI,OAAO;CAC/C,OAAO,iBAAiB,KAAA,IAAY,UAAU,SAAS,UAAU,QAAQ,SAAS,aAAa,GAAG,CAAC,CAAC;AACrG;;;;;;;;;;AAWA,MAAa,WAAW,SAAsB,QAA6B;CAC1E,MAAM,UAAU,eAAe,IAAI,OAAO,CAAC,GAAG,GAAG,KAAK;CACtD,MAAM,MAAM,YAAyC;EACpD,MAAM,cAAc,WAAW,KAAK,SAAS,GAAG;EAChD,OAAO;GAAE,GAAG;GAAS,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK,YAAY;EAAG;CACjF;CACA,MAAM,SAAS,QAAQ;CACvB,OAAO;EACN,OAAO,SAAS,YAAY,QAAQ,KAAK,SAAS,GAAG,OAAO,CAAC;EAC7D,WAAW,MAAM,YAAY,QAAQ,SAAS,MAAM,GAAG,OAAO,CAAC;EAC/D,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,SAAS,YAAY,OAAO,SAAS,GAAG,OAAO,CAAC,EAAE;CAC9F;AACD;;AAGA,IAAa,QAAb,cAA2B,QAAQ,QAA4B,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC"}
|
package/sandbox.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { A as apiVersion, C as Observed, D as RuntimeConfigBase, E as Registration, I as Redactor, M as driver, O as RuntimeInput, S as Name, _ as Capabilities, a as Provides, at as providerError, b as Module, ct as sanitizeError, g as ApiVersion, h as AbsolutePath, i as Layer, it as makeRedactor, j as defineModule, n as FileSystem, o as Shell, ot as providerErrorCause, q as SandboxProviderError, r as Identity, st as providerErrorIsNotFound, t as Current, v as Definition, vt as instance_d_exports, w as Provisioned, x as ModuleDefinition, y as Driver } from "./io-BYs7hbiY.mjs";
|
|
2
|
+
import { c as filesystem_d_exports } from "./filesystem-Cp-KapCE.mjs";
|
|
3
|
+
import { a as ShellError, i as Shell$1, l as quote, n as ExecResult, o as ShellOptions, r as ISandboxExe, s as fromExec, t as ExecChunk, u as quoteArgv } from "./shell-CZ6Y4lNU.mjs";
|
|
4
|
+
import { SandboxResource as resource_d_exports } from "./sandbox/resource.mjs";
|
|
5
|
+
declare namespace driver_d_exports {
|
|
6
|
+
export { AbsolutePath, ApiVersion, Capabilities, Definition, Driver, Module, ModuleDefinition, Name, Observed, Provisioned, Registration, RuntimeConfigBase as RuntimeConfig, RuntimeConfigBase, RuntimeInput, driver_d_exports as SandboxDriver, apiVersion, driver, defineModule as module };
|
|
7
|
+
}
|
|
8
|
+
declare namespace io_d_exports {
|
|
9
|
+
export { Current, FileSystem, Identity, Layer, Provides, io_d_exports as SandboxIO, Shell };
|
|
10
|
+
}
|
|
11
|
+
declare namespace provider_d_exports {
|
|
12
|
+
export { Redactor, SandboxProviderError, makeRedactor, providerError, providerErrorCause, providerErrorIsNotFound, sanitizeError };
|
|
13
|
+
}
|
|
14
|
+
declare namespace shell_d_exports {
|
|
15
|
+
export { ExecChunk, ExecResult, ISandboxExe, Shell$1 as Shell, ShellError, ShellOptions, fromExec, quote, quoteArgv };
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { driver_d_exports as SandboxDriver, filesystem_d_exports as SandboxFileSystem, io_d_exports as SandboxIO, instance_d_exports as SandboxInstance, provider_d_exports as SandboxProvider, resource_d_exports as SandboxResource, shell_d_exports as SandboxShell };
|
|
19
|
+
//# sourceMappingURL=sandbox.d.mts.map
|
package/sandbox.mjs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { SandboxInstance as instance_exports } from "./sandbox/instance.mjs";
|
|
3
|
+
import { SandboxFileSystem as filesystem_exports } from "./sandbox/filesystem.mjs";
|
|
4
|
+
import { Shell, ShellError, fromExec, quote, quoteArgv } from "./sandbox/shell.mjs";
|
|
5
|
+
import { Current, FileSystem, Shell as Shell$1 } from "./sandbox/io.mjs";
|
|
6
|
+
import { AbsolutePath, Name, RuntimeConfigBase, driver, module as defineModule } from "./sandbox/driver.mjs";
|
|
7
|
+
import { SandboxProviderError, makeRedactor, providerError, providerErrorCause, providerErrorIsNotFound, sanitizeError } from "./sandbox/errors.mjs";
|
|
8
|
+
import { SandboxResource as resource_exports } from "./sandbox/resource.mjs";
|
|
9
|
+
//#region src/sandbox/public/driver.ts
|
|
10
|
+
var driver_exports = /* @__PURE__ */ __exportAll({
|
|
11
|
+
AbsolutePath: () => AbsolutePath,
|
|
12
|
+
Name: () => Name,
|
|
13
|
+
RuntimeConfigBase: () => RuntimeConfigBase,
|
|
14
|
+
SandboxDriver: () => driver_exports,
|
|
15
|
+
apiVersion: () => 1,
|
|
16
|
+
driver: () => driver,
|
|
17
|
+
module: () => defineModule
|
|
18
|
+
});
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/sandbox/public/io.ts
|
|
21
|
+
var io_exports = /* @__PURE__ */ __exportAll({
|
|
22
|
+
Current: () => Current,
|
|
23
|
+
FileSystem: () => FileSystem,
|
|
24
|
+
SandboxIO: () => io_exports,
|
|
25
|
+
Shell: () => Shell$1
|
|
26
|
+
});
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/sandbox/provider.ts
|
|
29
|
+
var provider_exports = /* @__PURE__ */ __exportAll({
|
|
30
|
+
SandboxProviderError: () => SandboxProviderError,
|
|
31
|
+
makeRedactor: () => makeRedactor,
|
|
32
|
+
providerError: () => providerError,
|
|
33
|
+
providerErrorCause: () => providerErrorCause,
|
|
34
|
+
providerErrorIsNotFound: () => providerErrorIsNotFound,
|
|
35
|
+
sanitizeError: () => sanitizeError
|
|
36
|
+
});
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/sandbox/public/shell.ts
|
|
39
|
+
var shell_exports = /* @__PURE__ */ __exportAll({
|
|
40
|
+
Shell: () => Shell,
|
|
41
|
+
ShellError: () => ShellError,
|
|
42
|
+
fromExec: () => fromExec,
|
|
43
|
+
quote: () => quote,
|
|
44
|
+
quoteArgv: () => quoteArgv
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
export { driver_exports as SandboxDriver, filesystem_exports as SandboxFileSystem, io_exports as SandboxIO, instance_exports as SandboxInstance, provider_exports as SandboxProvider, resource_exports as SandboxResource, shell_exports as SandboxShell };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=sandbox.mjs.map
|
package/sandbox.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.mjs","names":[],"sources":["../../src/sandbox/public/driver.ts","../../src/sandbox/public/io.ts","../../src/sandbox/provider.ts","../../src/sandbox/public/shell.ts"],"sourcesContent":["export { AbsolutePath, apiVersion, driver, module, Name, RuntimeConfigBase } from \"../driver.ts\";\nexport type {\n\tApiVersion,\n\tCapabilities,\n\tDefinition,\n\tDriver,\n\tModule,\n\tModuleDefinition,\n\tObserved,\n\tProvisioned,\n\tRegistration,\n\tRuntimeConfigBase as RuntimeConfig,\n\tRuntimeInput,\n} from \"../driver.ts\";\n\nexport * as SandboxDriver from \"./driver.ts\";\n","export { Current, FileSystem, Shell } from \"../io.ts\";\nexport type { Identity, Layer, Provides } from \"../io.ts\";\n\nexport * as SandboxIO from \"./io.ts\";\n","export {\n\tmakeRedactor,\n\tproviderError,\n\tproviderErrorCause,\n\tproviderErrorIsNotFound,\n\tSandboxProviderError,\n\tsanitizeError,\n} from \"./errors.ts\";\nexport type { Redactor } from \"./errors.ts\";\n","export { fromExec, quote, quoteArgv, Shell, ShellError } from \"../shell.ts\";\nexport type { ExecChunk, ExecResult, ISandboxExe, ShellOptions } from \"../shell.ts\";\n"],"mappings":""}
|
package/schema.d.mts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Message, Model } from "@codeworksh/aikit";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
//#region src/schema.d.ts
|
|
4
|
+
/** Validate an aikit message without coercing or rewriting durable data. */
|
|
5
|
+
export declare const validateAikitMessage: (value: unknown, label: string) => Message.Message;
|
|
6
|
+
export declare const validateAikitUserMessage: (value: unknown, label: string) => Message.UserMessage;
|
|
7
|
+
export declare const validateAikitAssistantMessage: (value: unknown, label: string) => Message.AssistantMessage;
|
|
8
|
+
export declare const validateAikitToolCallTerminalPart: (value: unknown, label: string) => Message.ToolCallTerminalPart;
|
|
9
|
+
export declare const validateAikitModelInfo: (value: unknown, label: string) => Model.Info;
|
|
10
|
+
export declare const isAikitModelInfo: (value: unknown) => value is Model.Info;
|
|
11
|
+
export declare const isAikitAssistantMessage: (value: unknown) => value is Message.AssistantMessage;
|
|
12
|
+
export declare const isAikitToolCallTerminalPart: (value: unknown) => value is Message.ToolCallTerminalPart;
|
|
13
|
+
/**
|
|
14
|
+
* Integer greater than zero.
|
|
15
|
+
*/
|
|
16
|
+
export declare const PositiveInt: Schema.Int;
|
|
17
|
+
/**
|
|
18
|
+
* Integer greater than or equal to zero.
|
|
19
|
+
*/
|
|
20
|
+
export declare const NonNegativeInt: Schema.Int;
|
|
21
|
+
/**
|
|
22
|
+
* Cost greater than or equal with finite value
|
|
23
|
+
*/
|
|
24
|
+
export declare const NonNegativeCost: Schema.Finite;
|
|
25
|
+
/**
|
|
26
|
+
* Absolute POSIX file path (e.g., `/home/user/projects/myapp/src/main.ts`).
|
|
27
|
+
*/
|
|
28
|
+
export declare const AbsolutePath: Schema.brand<Schema.String, "AbsolutePath">;
|
|
29
|
+
export type AbsolutePath = Schema.Schema.Type<typeof AbsolutePath>;
|
|
30
|
+
/**
|
|
31
|
+
* Optional public JSON field that can hold explicit `undefined` on the type
|
|
32
|
+
* side but encodes it as an omitted key, matching legacy `JSON.stringify`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const optional: <S extends Schema.Top>(schema: S) => Schema.decodeTo<Schema.optional<Schema.toType<S>>, Schema.optionalKey<S>, never, never>;
|
|
35
|
+
/**
|
|
36
|
+
* Strip `readonly` from a nested type. Stand-in for `effect`'s `Types.DeepMutable`
|
|
37
|
+
* until `effect:core/x228my` ("Types.DeepMutable widens unknown to `{}`") lands.
|
|
38
|
+
*
|
|
39
|
+
* The upstream version falls through `unknown` into `{ -readonly [K in keyof T]: ... }`
|
|
40
|
+
* where `keyof unknown = never`, so `unknown` collapses to `{}`. This local
|
|
41
|
+
* version gates the object branch on `extends object` (which `unknown` does
|
|
42
|
+
* not) so `unknown` passes through untouched.
|
|
43
|
+
*
|
|
44
|
+
* Primitive bailout matches upstream — without it, branded strings like
|
|
45
|
+
* `string & Brand<"SessionID">` fall into the object branch and get their
|
|
46
|
+
* prototype methods walked.
|
|
47
|
+
*
|
|
48
|
+
* Tuple branch preserves readonly tuples (e.g. `ConfigPlugin.Spec`'s
|
|
49
|
+
* `readonly [string, Options]`); the general array branch would otherwise
|
|
50
|
+
* widen them to unbounded arrays.
|
|
51
|
+
*/
|
|
52
|
+
export type DeepMutable<T> = T extends string | number | boolean | bigint | symbol | Function ? T : T extends readonly [unknown, ...unknown[]] ? { -readonly [K in keyof T]: DeepMutable<T[K]>; } : T extends readonly (infer U)[] ? DeepMutable<U>[] : T extends object ? { -readonly [K in keyof T]: DeepMutable<T[K]>; } : T;
|
|
53
|
+
/**
|
|
54
|
+
* Attach static methods to a schema object. Designed to be used with `.pipe()`:
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* export const Foo = fooSchema.pipe(
|
|
58
|
+
* withStatics((schema) => ({
|
|
59
|
+
* zero: schema.make(0),
|
|
60
|
+
* from: Schema.decodeUnknownOption(schema),
|
|
61
|
+
* }))
|
|
62
|
+
* )
|
|
63
|
+
*/
|
|
64
|
+
export declare const withStatics: <S extends object, M extends Record<string, unknown>>(methods: (schema: S) => M) => (schema: S) => S & M;
|
|
65
|
+
/**
|
|
66
|
+
* Nominal wrapper for scalar types. The class itself is a valid schema —
|
|
67
|
+
* pass it directly to `Schema.decode`, `Schema.decodeEffect`, etc.
|
|
68
|
+
*
|
|
69
|
+
* Overrides `~type.make` on the derived `Schema.Opaque` so `Schema.Schema.Type`
|
|
70
|
+
* of a field using this newtype resolves to `Self` rather than the underlying
|
|
71
|
+
* branded phantom. Without that override, passing a class instance to code
|
|
72
|
+
* typed against `Schema.Schema.Type<FieldSchema>` would require a cast even
|
|
73
|
+
* though the values are structurally equivalent at runtime.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* class QuestionID extends Newtype<QuestionID>()("QuestionID", Schema.String) {
|
|
77
|
+
* static make(id: string): QuestionID {
|
|
78
|
+
* return this.make(id)
|
|
79
|
+
* }
|
|
80
|
+
* }
|
|
81
|
+
*
|
|
82
|
+
* Schema.decodeEffect(QuestionID)(input)
|
|
83
|
+
*/
|
|
84
|
+
export declare function Newtype<Self>(): <const Tag extends string, S extends Schema.Top>(tag: Tag, schema: S) => (abstract new (_: never) => {
|
|
85
|
+
readonly _newtype: Tag;
|
|
86
|
+
}) & {
|
|
87
|
+
readonly make: (value: Schema.Schema.Type<S>) => Self;
|
|
88
|
+
} & Omit<Schema.Opaque<Self, S, {}>, "make" | "~type.make"> & {
|
|
89
|
+
readonly "~type.make": Self;
|
|
90
|
+
};
|
|
91
|
+
export declare const DateTimeUtcFromMillis: Schema.decodeTo<Schema.DateTimeUtc, Schema.Finite, never, never>;
|
|
92
|
+
//#endregion
|
|
93
|
+
//# sourceMappingURL=schema.d.mts.map
|
package/schema.mjs
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Message, Model } from "@codeworksh/aikit";
|
|
2
|
+
import { DateTime, Option, Schema, SchemaGetter } from "effect";
|
|
3
|
+
import TypeBoxSchema from "typebox/schema";
|
|
4
|
+
//#region src/schema.ts
|
|
5
|
+
const aikitValidators = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
const aikitValidatorFor = (schema) => {
|
|
7
|
+
const cached = aikitValidators.get(schema);
|
|
8
|
+
if (cached !== void 0) return cached;
|
|
9
|
+
const compiled = TypeBoxSchema.Compile(schema);
|
|
10
|
+
aikitValidators.set(schema, compiled);
|
|
11
|
+
return compiled;
|
|
12
|
+
};
|
|
13
|
+
const aikitErrorPath = (error) => {
|
|
14
|
+
if (error.instancePath) return error.instancePath.substring(1);
|
|
15
|
+
const required = error.params?.requiredProperties;
|
|
16
|
+
return Array.isArray(required) ? required.join(", ") : "root";
|
|
17
|
+
};
|
|
18
|
+
const validateAikitSchema = (schema, value, label) => {
|
|
19
|
+
const validator = aikitValidatorFor(schema);
|
|
20
|
+
if (validator.Check(value)) return value;
|
|
21
|
+
const [, issues] = validator.Errors(value);
|
|
22
|
+
const details = issues.map((issue) => ` - ${aikitErrorPath(issue)}: ${issue.message}`).join("\n") || "unknown error";
|
|
23
|
+
throw new Error(`validation failed for ${label}\n${details}`);
|
|
24
|
+
};
|
|
25
|
+
/** Validate an aikit message without coercing or rewriting durable data. */
|
|
26
|
+
const validateAikitMessage = (value, label) => validateAikitSchema(Message.MessageSchema, value, label);
|
|
27
|
+
const validateAikitUserMessage = (value, label) => validateAikitSchema(Message.UserMessageSchema, value, label);
|
|
28
|
+
const validateAikitAssistantMessage = (value, label) => validateAikitSchema(Message.AssistantMessageSchema, value, label);
|
|
29
|
+
const validateAikitToolCallTerminalPart = (value, label) => validateAikitSchema(Message.ToolCallTerminalPartSchema, value, label);
|
|
30
|
+
const validateAikitModelInfo = (value, label) => validateAikitSchema(Model.Info, value, label);
|
|
31
|
+
const isAikitModelInfo = (value) => aikitValidatorFor(Model.Info).Check(value);
|
|
32
|
+
const isAikitAssistantMessage = (value) => aikitValidatorFor(Message.AssistantMessageSchema).Check(value);
|
|
33
|
+
const isAikitToolCallTerminalPart = (value) => aikitValidatorFor(Message.ToolCallTerminalPartSchema).Check(value);
|
|
34
|
+
/**
|
|
35
|
+
* Integer greater than zero.
|
|
36
|
+
*/
|
|
37
|
+
const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0));
|
|
38
|
+
/**
|
|
39
|
+
* Integer greater than or equal to zero.
|
|
40
|
+
*/
|
|
41
|
+
const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
42
|
+
/**
|
|
43
|
+
* Cost greater than or equal with finite value
|
|
44
|
+
*/
|
|
45
|
+
const NonNegativeCost = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0));
|
|
46
|
+
/**
|
|
47
|
+
* Absolute POSIX file path (e.g., `/home/user/projects/myapp/src/main.ts`).
|
|
48
|
+
*/
|
|
49
|
+
const AbsolutePath = Schema.String.check(Schema.isPattern(/^\//)).pipe(Schema.brand("AbsolutePath"));
|
|
50
|
+
/**
|
|
51
|
+
* Optional public JSON field that can hold explicit `undefined` on the type
|
|
52
|
+
* side but encodes it as an omitted key, matching legacy `JSON.stringify`.
|
|
53
|
+
*/
|
|
54
|
+
const optional = (schema) => Schema.optionalKey(schema).pipe(Schema.decodeTo(Schema.optional(Schema.toType(schema)), {
|
|
55
|
+
decode: SchemaGetter.passthrough({ strict: false }),
|
|
56
|
+
encode: SchemaGetter.transformOptional(Option.filter((value) => value !== void 0))
|
|
57
|
+
}));
|
|
58
|
+
/**
|
|
59
|
+
* Attach static methods to a schema object. Designed to be used with `.pipe()`:
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* export const Foo = fooSchema.pipe(
|
|
63
|
+
* withStatics((schema) => ({
|
|
64
|
+
* zero: schema.make(0),
|
|
65
|
+
* from: Schema.decodeUnknownOption(schema),
|
|
66
|
+
* }))
|
|
67
|
+
* )
|
|
68
|
+
*/
|
|
69
|
+
const withStatics = (methods) => (schema) => Object.assign(schema, methods(schema));
|
|
70
|
+
/**
|
|
71
|
+
* Nominal wrapper for scalar types. The class itself is a valid schema —
|
|
72
|
+
* pass it directly to `Schema.decode`, `Schema.decodeEffect`, etc.
|
|
73
|
+
*
|
|
74
|
+
* Overrides `~type.make` on the derived `Schema.Opaque` so `Schema.Schema.Type`
|
|
75
|
+
* of a field using this newtype resolves to `Self` rather than the underlying
|
|
76
|
+
* branded phantom. Without that override, passing a class instance to code
|
|
77
|
+
* typed against `Schema.Schema.Type<FieldSchema>` would require a cast even
|
|
78
|
+
* though the values are structurally equivalent at runtime.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* class QuestionID extends Newtype<QuestionID>()("QuestionID", Schema.String) {
|
|
82
|
+
* static make(id: string): QuestionID {
|
|
83
|
+
* return this.make(id)
|
|
84
|
+
* }
|
|
85
|
+
* }
|
|
86
|
+
*
|
|
87
|
+
* Schema.decodeEffect(QuestionID)(input)
|
|
88
|
+
*/
|
|
89
|
+
function Newtype() {
|
|
90
|
+
return (tag, schema) => {
|
|
91
|
+
class Base {
|
|
92
|
+
static make(value) {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
Object.setPrototypeOf(Base, schema);
|
|
97
|
+
return Base;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const DateTimeUtcFromMillis = Schema.Finite.pipe(Schema.decodeTo(Schema.DateTimeUtc, {
|
|
101
|
+
decode: SchemaGetter.transform((value) => DateTime.makeUnsafe(value)),
|
|
102
|
+
encode: SchemaGetter.transform((value) => DateTime.toEpochMillis(value))
|
|
103
|
+
}));
|
|
104
|
+
//#endregion
|
|
105
|
+
export { AbsolutePath, DateTimeUtcFromMillis, Newtype, NonNegativeCost, NonNegativeInt, PositiveInt, isAikitAssistantMessage, isAikitModelInfo, isAikitToolCallTerminalPart, optional, validateAikitAssistantMessage, validateAikitMessage, validateAikitModelInfo, validateAikitToolCallTerminalPart, validateAikitUserMessage, withStatics };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=schema.mjs.map
|
package/schema.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":[],"sources":["../../src/schema.ts"],"sourcesContent":["import { Message, Model } from \"@codeworksh/aikit\";\nimport { DateTime, Option, Schema, SchemaGetter } from \"effect\";\nimport type { Static, TSchema } from \"typebox\";\nimport TypeBoxSchema from \"typebox/schema\";\n\nconst aikitValidators = new WeakMap<TSchema, ReturnType<typeof TypeBoxSchema.Compile>>();\n\nconst aikitValidatorFor = <T extends TSchema>(schema: T): ReturnType<typeof TypeBoxSchema.Compile<T>> => {\n\tconst cached = aikitValidators.get(schema) as ReturnType<typeof TypeBoxSchema.Compile<T>> | undefined;\n\tif (cached !== undefined) return cached;\n\tconst compiled = TypeBoxSchema.Compile(schema);\n\taikitValidators.set(schema, compiled);\n\treturn compiled;\n};\n\nconst aikitErrorPath = (error: {\n\treadonly instancePath?: string;\n\treadonly params?: Record<string, unknown>;\n}): string => {\n\tif (error.instancePath) return error.instancePath.substring(1);\n\tconst required = error.params?.requiredProperties;\n\treturn Array.isArray(required) ? required.join(\", \") : \"root\";\n};\n\nconst validateAikitSchema = <T extends TSchema>(schema: T, value: unknown, label: string): Static<T> => {\n\tconst validator = aikitValidatorFor(schema);\n\tif (validator.Check(value)) return value;\n\n\tconst [, issues] = validator.Errors(value);\n\tconst details = issues.map((issue) => ` - ${aikitErrorPath(issue)}: ${issue.message}`).join(\"\\n\") || \"unknown error\";\n\tthrow new Error(`validation failed for ${label}\\n${details}`);\n};\n\n/** Validate an aikit message without coercing or rewriting durable data. */\nexport const validateAikitMessage = (value: unknown, label: string): Message.Message =>\n\tvalidateAikitSchema(Message.MessageSchema, value, label);\n\nexport const validateAikitUserMessage = (value: unknown, label: string): Message.UserMessage =>\n\tvalidateAikitSchema(Message.UserMessageSchema, value, label);\n\nexport const validateAikitAssistantMessage = (value: unknown, label: string): Message.AssistantMessage =>\n\tvalidateAikitSchema(Message.AssistantMessageSchema, value, label);\n\nexport const validateAikitToolCallTerminalPart = (value: unknown, label: string): Message.ToolCallTerminalPart =>\n\tvalidateAikitSchema(Message.ToolCallTerminalPartSchema, value, label);\n\nexport const validateAikitModelInfo = (value: unknown, label: string): Model.Info =>\n\tvalidateAikitSchema(Model.Info, value, label);\n\nexport const isAikitModelInfo = (value: unknown): value is Model.Info => aikitValidatorFor(Model.Info).Check(value);\n\nexport const isAikitAssistantMessage = (value: unknown): value is Message.AssistantMessage =>\n\taikitValidatorFor(Message.AssistantMessageSchema).Check(value);\n\nexport const isAikitToolCallTerminalPart = (value: unknown): value is Message.ToolCallTerminalPart =>\n\taikitValidatorFor(Message.ToolCallTerminalPartSchema).Check(value);\n\n/**\n * Integer greater than zero.\n */\nexport const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0));\n\n/**\n * Integer greater than or equal to zero.\n */\nexport const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));\n\n/**\n * Cost greater than or equal with finite value\n */\nexport const NonNegativeCost = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0));\n\n/**\n * Absolute POSIX file path (e.g., `/home/user/projects/myapp/src/main.ts`).\n */\nexport const AbsolutePath = Schema.String.check(Schema.isPattern(/^\\//)).pipe(Schema.brand(\"AbsolutePath\"));\nexport type AbsolutePath = Schema.Schema.Type<typeof AbsolutePath>;\n\n/**\n * Optional public JSON field that can hold explicit `undefined` on the type\n * side but encodes it as an omitted key, matching legacy `JSON.stringify`.\n */\nexport const optional = <S extends Schema.Top>(schema: S) =>\n\tSchema.optionalKey(schema).pipe(\n\t\tSchema.decodeTo(Schema.optional(Schema.toType(schema)), {\n\t\t\tdecode: SchemaGetter.passthrough({ strict: false }),\n\t\t\tencode: SchemaGetter.transformOptional(Option.filter((value) => value !== undefined)),\n\t\t}),\n\t);\n\n/**\n * Strip `readonly` from a nested type. Stand-in for `effect`'s `Types.DeepMutable`\n * until `effect:core/x228my` (\"Types.DeepMutable widens unknown to `{}`\") lands.\n *\n * The upstream version falls through `unknown` into `{ -readonly [K in keyof T]: ... }`\n * where `keyof unknown = never`, so `unknown` collapses to `{}`. This local\n * version gates the object branch on `extends object` (which `unknown` does\n * not) so `unknown` passes through untouched.\n *\n * Primitive bailout matches upstream — without it, branded strings like\n * `string & Brand<\"SessionID\">` fall into the object branch and get their\n * prototype methods walked.\n *\n * Tuple branch preserves readonly tuples (e.g. `ConfigPlugin.Spec`'s\n * `readonly [string, Options]`); the general array branch would otherwise\n * widen them to unbounded arrays.\n */\nexport type DeepMutable<T> = T extends string | number | boolean | bigint | symbol | Function\n\t? T\n\t: T extends readonly [unknown, ...unknown[]]\n\t\t? { -readonly [K in keyof T]: DeepMutable<T[K]> }\n\t\t: T extends readonly (infer U)[]\n\t\t\t? DeepMutable<U>[]\n\t\t\t: T extends object\n\t\t\t\t? { -readonly [K in keyof T]: DeepMutable<T[K]> }\n\t\t\t\t: T;\n\n/**\n * Attach static methods to a schema object. Designed to be used with `.pipe()`:\n *\n * @example\n * export const Foo = fooSchema.pipe(\n * withStatics((schema) => ({\n * zero: schema.make(0),\n * from: Schema.decodeUnknownOption(schema),\n * }))\n * )\n */\nexport const withStatics =\n\t<S extends object, M extends Record<string, unknown>>(methods: (schema: S) => M) =>\n\t(schema: S): S & M =>\n\t\tObject.assign(schema, methods(schema));\n\n/**\n * Nominal wrapper for scalar types. The class itself is a valid schema —\n * pass it directly to `Schema.decode`, `Schema.decodeEffect`, etc.\n *\n * Overrides `~type.make` on the derived `Schema.Opaque` so `Schema.Schema.Type`\n * of a field using this newtype resolves to `Self` rather than the underlying\n * branded phantom. Without that override, passing a class instance to code\n * typed against `Schema.Schema.Type<FieldSchema>` would require a cast even\n * though the values are structurally equivalent at runtime.\n *\n * @example\n * class QuestionID extends Newtype<QuestionID>()(\"QuestionID\", Schema.String) {\n * static make(id: string): QuestionID {\n * return this.make(id)\n * }\n * }\n *\n * Schema.decodeEffect(QuestionID)(input)\n */\nexport function Newtype<Self>() {\n\treturn <const Tag extends string, S extends Schema.Top>(tag: Tag, schema: S) => {\n\t\tabstract class Base {\n\t\t\tdeclare readonly _newtype: Tag;\n\n\t\t\tstatic make(value: Schema.Schema.Type<S>): Self {\n\t\t\t\treturn value as unknown as Self;\n\t\t\t}\n\t\t}\n\n\t\tObject.setPrototypeOf(Base, schema);\n\n\t\treturn Base as unknown as (abstract new (_: never) => { readonly _newtype: Tag }) & {\n\t\t\treadonly make: (value: Schema.Schema.Type<S>) => Self;\n\t\t} & Omit<Schema.Opaque<Self, S, {}>, \"make\" | \"~type.make\"> & {\n\t\t\t\treadonly \"~type.make\": Self;\n\t\t\t};\n\t};\n}\n\nexport const DateTimeUtcFromMillis = Schema.Finite.pipe(\n\tSchema.decodeTo(Schema.DateTimeUtc, {\n\t\tdecode: SchemaGetter.transform((value) => DateTime.makeUnsafe(value)),\n\t\tencode: SchemaGetter.transform((value) => DateTime.toEpochMillis(value)),\n\t}),\n);\n"],"mappings":";;;;AAKA,MAAM,kCAAkB,IAAI,QAA2D;AAEvF,MAAM,qBAAwC,WAA2D;CACxG,MAAM,SAAS,gBAAgB,IAAI,MAAM;CACzC,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,MAAM,WAAW,cAAc,QAAQ,MAAM;CAC7C,gBAAgB,IAAI,QAAQ,QAAQ;CACpC,OAAO;AACR;AAEA,MAAM,kBAAkB,UAGV;CACb,IAAI,MAAM,cAAc,OAAO,MAAM,aAAa,UAAU,CAAC;CAC7D,MAAM,WAAW,MAAM,QAAQ;CAC/B,OAAO,MAAM,QAAQ,QAAQ,IAAI,SAAS,KAAK,IAAI,IAAI;AACxD;AAEA,MAAM,uBAA0C,QAAW,OAAgB,UAA6B;CACvG,MAAM,YAAY,kBAAkB,MAAM;CAC1C,IAAI,UAAU,MAAM,KAAK,GAAG,OAAO;CAEnC,MAAM,GAAG,UAAU,UAAU,OAAO,KAAK;CACzC,MAAM,UAAU,OAAO,KAAK,UAAU,MAAM,eAAe,KAAK,EAAE,IAAI,MAAM,SAAS,CAAC,CAAC,KAAK,IAAI,KAAK;CACrG,MAAM,IAAI,MAAM,yBAAyB,MAAM,IAAI,SAAS;AAC7D;;AAGA,MAAa,wBAAwB,OAAgB,UACpD,oBAAoB,QAAQ,eAAe,OAAO,KAAK;AAExD,MAAa,4BAA4B,OAAgB,UACxD,oBAAoB,QAAQ,mBAAmB,OAAO,KAAK;AAE5D,MAAa,iCAAiC,OAAgB,UAC7D,oBAAoB,QAAQ,wBAAwB,OAAO,KAAK;AAEjE,MAAa,qCAAqC,OAAgB,UACjE,oBAAoB,QAAQ,4BAA4B,OAAO,KAAK;AAErE,MAAa,0BAA0B,OAAgB,UACtD,oBAAoB,MAAM,MAAM,OAAO,KAAK;AAE7C,MAAa,oBAAoB,UAAwC,kBAAkB,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK;AAElH,MAAa,2BAA2B,UACvC,kBAAkB,QAAQ,sBAAsB,CAAC,CAAC,MAAM,KAAK;AAE9D,MAAa,+BAA+B,UAC3C,kBAAkB,QAAQ,0BAA0B,CAAC,CAAC,MAAM,KAAK;;;;AAKlE,MAAa,cAAc,OAAO,IAAI,MAAM,OAAO,cAAc,CAAC,CAAC;;;;AAKnE,MAAa,iBAAiB,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;;;;AAK/E,MAAa,kBAAkB,OAAO,OAAO,MAAM,OAAO,uBAAuB,CAAC,CAAC;;;;AAKnF,MAAa,eAAe,OAAO,OAAO,MAAM,OAAO,UAAU,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM,cAAc,CAAC;;;;;AAO1G,MAAa,YAAkC,WAC9C,OAAO,YAAY,MAAM,CAAC,CAAC,KAC1B,OAAO,SAAS,OAAO,SAAS,OAAO,OAAO,MAAM,CAAC,GAAG;CACvD,QAAQ,aAAa,YAAY,EAAE,QAAQ,MAAM,CAAC;CAClD,QAAQ,aAAa,kBAAkB,OAAO,QAAQ,UAAU,UAAU,KAAA,CAAS,CAAC;AACrF,CAAC,CACF;;;;;;;;;;;;AAwCD,MAAa,eAC0C,aACrD,WACA,OAAO,OAAO,QAAQ,QAAQ,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;AAqBvC,SAAgB,UAAgB;CAC/B,QAAwD,KAAU,WAAc;EAC/E,MAAe,KAAK;GAGnB,OAAO,KAAK,OAAoC;IAC/C,OAAO;GACR;EACD;EAEA,OAAO,eAAe,MAAM,MAAM;EAElC,OAAO;CAKR;AACD;AAEA,MAAa,wBAAwB,OAAO,OAAO,KAClD,OAAO,SAAS,OAAO,aAAa;CACnC,QAAQ,aAAa,WAAW,UAAU,SAAS,WAAW,KAAK,CAAC;CACpE,QAAQ,aAAa,WAAW,UAAU,SAAS,cAAc,KAAK,CAAC;AACxE,CAAC,CACF"}
|