@alchemy.run/archil 0.0.0 → 2.0.0-beta.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +57 -4
  3. package/lib/AWS/S3Disk.d.ts +68 -0
  4. package/lib/AWS/S3Disk.d.ts.map +1 -0
  5. package/lib/AWS/S3Disk.js +100 -0
  6. package/lib/AWS/S3Disk.js.map +1 -0
  7. package/lib/AWS/index.d.ts +2 -0
  8. package/lib/AWS/index.d.ts.map +1 -0
  9. package/lib/AWS/index.js +2 -0
  10. package/lib/AWS/index.js.map +1 -0
  11. package/lib/ApiToken.d.ts +63 -0
  12. package/lib/ApiToken.d.ts.map +1 -0
  13. package/lib/ApiToken.js +121 -0
  14. package/lib/ApiToken.js.map +1 -0
  15. package/lib/ArchilBindings.d.ts +65 -0
  16. package/lib/ArchilBindings.d.ts.map +1 -0
  17. package/lib/ArchilBindings.js +128 -0
  18. package/lib/ArchilBindings.js.map +1 -0
  19. package/lib/AuthProvider.d.ts +40 -0
  20. package/lib/AuthProvider.d.ts.map +1 -0
  21. package/lib/AuthProvider.js +87 -0
  22. package/lib/AuthProvider.js.map +1 -0
  23. package/lib/Bootstrap.d.ts +8 -0
  24. package/lib/Bootstrap.d.ts.map +1 -0
  25. package/lib/Bootstrap.js +27 -0
  26. package/lib/Bootstrap.js.map +1 -0
  27. package/lib/Branch.d.ts +101 -0
  28. package/lib/Branch.d.ts.map +1 -0
  29. package/lib/Branch.js +117 -0
  30. package/lib/Branch.js.map +1 -0
  31. package/lib/BranchDisk.d.ts +42 -0
  32. package/lib/BranchDisk.d.ts.map +1 -0
  33. package/lib/BranchDisk.js +14 -0
  34. package/lib/BranchDisk.js.map +1 -0
  35. package/lib/Checkpoint.d.ts +78 -0
  36. package/lib/Checkpoint.d.ts.map +1 -0
  37. package/lib/Checkpoint.js +95 -0
  38. package/lib/Checkpoint.js.map +1 -0
  39. package/lib/Clients.d.ts +369 -0
  40. package/lib/Clients.d.ts.map +1 -0
  41. package/lib/Clients.js +334 -0
  42. package/lib/Clients.js.map +1 -0
  43. package/lib/ConnectSandbox.d.ts +69 -0
  44. package/lib/ConnectSandbox.d.ts.map +1 -0
  45. package/lib/ConnectSandbox.js +21 -0
  46. package/lib/ConnectSandbox.js.map +1 -0
  47. package/lib/Contributions.d.ts +7 -0
  48. package/lib/Contributions.d.ts.map +1 -0
  49. package/lib/Contributions.js +6 -0
  50. package/lib/Contributions.js.map +1 -0
  51. package/lib/CreateDisk.d.ts +90 -0
  52. package/lib/CreateDisk.d.ts.map +1 -0
  53. package/lib/CreateDisk.js +47 -0
  54. package/lib/CreateDisk.js.map +1 -0
  55. package/lib/CreateImage.d.ts +42 -0
  56. package/lib/CreateImage.d.ts.map +1 -0
  57. package/lib/CreateImage.js +19 -0
  58. package/lib/CreateImage.js.map +1 -0
  59. package/lib/CreateSandbox.d.ts +104 -0
  60. package/lib/CreateSandbox.d.ts.map +1 -0
  61. package/lib/CreateSandbox.js +98 -0
  62. package/lib/CreateSandbox.js.map +1 -0
  63. package/lib/Credentials.d.ts +44 -0
  64. package/lib/Credentials.d.ts.map +1 -0
  65. package/lib/Credentials.js +57 -0
  66. package/lib/Credentials.js.map +1 -0
  67. package/lib/Disk.d.ts +283 -0
  68. package/lib/Disk.d.ts.map +1 -0
  69. package/lib/Disk.js +294 -0
  70. package/lib/Disk.js.map +1 -0
  71. package/lib/DiskObjectsHttp.d.ts +20 -0
  72. package/lib/DiskObjectsHttp.d.ts.map +1 -0
  73. package/lib/DiskObjectsHttp.js +51 -0
  74. package/lib/DiskObjectsHttp.js.map +1 -0
  75. package/lib/DiskUser.d.ts +189 -0
  76. package/lib/DiskUser.d.ts.map +1 -0
  77. package/lib/DiskUser.js +243 -0
  78. package/lib/DiskUser.js.map +1 -0
  79. package/lib/ExecDisk.d.ts +57 -0
  80. package/lib/ExecDisk.d.ts.map +1 -0
  81. package/lib/ExecDisk.js +3 -0
  82. package/lib/ExecDisk.js.map +1 -0
  83. package/lib/ExecDiskHttp.d.ts +5 -0
  84. package/lib/ExecDiskHttp.d.ts.map +1 -0
  85. package/lib/ExecDiskHttp.js +18 -0
  86. package/lib/ExecDiskHttp.js.map +1 -0
  87. package/lib/ExecDisks.d.ts +54 -0
  88. package/lib/ExecDisks.d.ts.map +1 -0
  89. package/lib/ExecDisks.js +37 -0
  90. package/lib/ExecDisks.js.map +1 -0
  91. package/lib/Image.d.ts +188 -0
  92. package/lib/Image.d.ts.map +1 -0
  93. package/lib/Image.js +191 -0
  94. package/lib/Image.js.map +1 -0
  95. package/lib/InferEnv.d.ts +26 -0
  96. package/lib/InferEnv.d.ts.map +1 -0
  97. package/lib/InferEnv.js +1 -0
  98. package/lib/InferEnv.js.map +1 -0
  99. package/lib/MountDisk.d.ts +190 -0
  100. package/lib/MountDisk.d.ts.map +1 -0
  101. package/lib/MountDisk.js +227 -0
  102. package/lib/MountDisk.js.map +1 -0
  103. package/lib/Providers.d.ts +25 -0
  104. package/lib/Providers.d.ts.map +1 -0
  105. package/lib/Providers.js +48 -0
  106. package/lib/Providers.js.map +1 -0
  107. package/lib/ReadDisk.d.ts +55 -0
  108. package/lib/ReadDisk.d.ts.map +1 -0
  109. package/lib/ReadDisk.js +3 -0
  110. package/lib/ReadDisk.js.map +1 -0
  111. package/lib/ReadWriteDisk.d.ts +26 -0
  112. package/lib/ReadWriteDisk.d.ts.map +1 -0
  113. package/lib/ReadWriteDisk.js +3 -0
  114. package/lib/ReadWriteDisk.js.map +1 -0
  115. package/lib/Sandbox.d.ts +507 -0
  116. package/lib/Sandbox.d.ts.map +1 -0
  117. package/lib/Sandbox.js +729 -0
  118. package/lib/Sandbox.js.map +1 -0
  119. package/lib/SandboxOptions.d.ts +185 -0
  120. package/lib/SandboxOptions.d.ts.map +1 -0
  121. package/lib/SandboxOptions.js +102 -0
  122. package/lib/SandboxOptions.js.map +1 -0
  123. package/lib/SandboxPortToken.d.ts +64 -0
  124. package/lib/SandboxPortToken.d.ts.map +1 -0
  125. package/lib/SandboxPortToken.js +77 -0
  126. package/lib/SandboxPortToken.js.map +1 -0
  127. package/lib/WriteDisk.d.ts +37 -0
  128. package/lib/WriteDisk.d.ts.map +1 -0
  129. package/lib/WriteDisk.js +3 -0
  130. package/lib/WriteDisk.js.map +1 -0
  131. package/lib/index.d.ts +29 -0
  132. package/lib/index.d.ts.map +1 -0
  133. package/lib/index.js +28 -0
  134. package/lib/index.js.map +1 -0
  135. package/lib/internal/DeployerKey.d.ts +21 -0
  136. package/lib/internal/DeployerKey.d.ts.map +1 -0
  137. package/lib/internal/DeployerKey.js +34 -0
  138. package/lib/internal/DeployerKey.js.map +1 -0
  139. package/lib/internal/archil.d.ts +87 -0
  140. package/lib/internal/archil.d.ts.map +1 -0
  141. package/lib/internal/archil.js +154 -0
  142. package/lib/internal/archil.js.map +1 -0
  143. package/lib/internal/hosted.d.ts +90 -0
  144. package/lib/internal/hosted.d.ts.map +1 -0
  145. package/lib/internal/hosted.js +291 -0
  146. package/lib/internal/hosted.js.map +1 -0
  147. package/package.json +79 -3
  148. package/src/AWS/S3Disk.ts +125 -0
  149. package/src/AWS/index.ts +1 -0
  150. package/src/ApiToken.ts +168 -0
  151. package/src/ArchilBindings.ts +179 -0
  152. package/src/AuthProvider.ts +122 -0
  153. package/src/Bootstrap.ts +54 -0
  154. package/src/Branch.ts +199 -0
  155. package/src/BranchDisk.ts +57 -0
  156. package/src/Checkpoint.ts +145 -0
  157. package/src/Clients.ts +954 -0
  158. package/src/ConnectSandbox.ts +91 -0
  159. package/src/Contributions.ts +9 -0
  160. package/src/CreateDisk.ts +165 -0
  161. package/src/CreateImage.ts +73 -0
  162. package/src/CreateSandbox.ts +258 -0
  163. package/src/Credentials.ts +101 -0
  164. package/src/Disk.ts +468 -0
  165. package/src/DiskObjectsHttp.ts +64 -0
  166. package/src/DiskUser.ts +369 -0
  167. package/src/ExecDisk.ts +62 -0
  168. package/src/ExecDiskHttp.ts +25 -0
  169. package/src/ExecDisks.ts +100 -0
  170. package/src/Image.ts +316 -0
  171. package/src/InferEnv.ts +27 -0
  172. package/src/MountDisk.ts +466 -0
  173. package/src/Providers.ts +75 -0
  174. package/src/ReadDisk.ts +61 -0
  175. package/src/ReadWriteDisk.ts +31 -0
  176. package/src/Sandbox.ts +1064 -0
  177. package/src/SandboxOptions.ts +230 -0
  178. package/src/SandboxPortToken.ts +125 -0
  179. package/src/WriteDisk.ts +42 -0
  180. package/src/globals.d.ts +2 -0
  181. package/src/index.ts +59 -0
  182. package/src/internal/DeployerKey.ts +63 -0
  183. package/src/internal/archil.ts +273 -0
  184. package/src/internal/hosted.ts +402 -0
@@ -0,0 +1,507 @@
1
+ import * as archil from "@distilled.cloud/archil";
2
+ import { type MountCapability } from "alchemy/Mount";
3
+ import { Platform, type Main, type PlatformProps } from "alchemy/Platform";
4
+ import * as Provider from "alchemy/Provider";
5
+ import type { LookupMethod, Resource } from "alchemy/Resource";
6
+ import { type HostRuntimeContext, type ServerHost } from "alchemy/Runtime/Process";
7
+ import { Stack } from "alchemy/Stack";
8
+ import * as Effect from "effect/Effect";
9
+ import type * as Redacted from "effect/Redacted";
10
+ import { type ImagePush } from "./Image.ts";
11
+ import { type ProgramBuildOptions, type ProgramExtraFile } from "./internal/hosted.ts";
12
+ import type { Providers } from "./Providers.ts";
13
+ import { MountDiskUnresolved, type DiskMount, type DiskMountOptions, type SandboxEgress, type SandboxEndpoint } from "./SandboxOptions.ts";
14
+ declare const SandboxSetupFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
15
+ readonly _tag: "Archil.SandboxSetupFailed";
16
+ } & Readonly<A>;
17
+ /** A disk a binding mounts into a program sandbox (`MountDisk` inside one). */
18
+ /** A sandbox's `run` command exited non-zero. */
19
+ export declare class SandboxSetupFailed extends SandboxSetupFailed_base<{
20
+ readonly sandbox: string;
21
+ readonly command: string;
22
+ readonly exitCode: number;
23
+ readonly stderr: string;
24
+ }> {
25
+ get message(): string;
26
+ }
27
+ export interface SandboxMountBinding extends DiskMountOptions {
28
+ readonly diskId: string;
29
+ }
30
+ /**
31
+ * What bindings attach to a sandbox: its program's environment, disks it
32
+ * mounts natively (`SandboxMountBinding`), and filesystem clients other
33
+ * mount bindings install into its image (`MountCapability`, from
34
+ * `alchemy/Mount`).
35
+ */
36
+ export interface SandboxBinding {
37
+ env?: Record<string, any>;
38
+ mounts?: ReadonlyArray<SandboxMountBinding | MountCapability>;
39
+ }
40
+ export interface SandboxProps extends PlatformProps {
41
+ /**
42
+ * Sandbox name, unique within your account: lowercase letters, digits
43
+ * and `-`, at most 63 characters. If omitted, a unique name is generated
44
+ * from the stack, stage, and logical ID. Changing it replaces the sandbox.
45
+ */
46
+ name?: string;
47
+ /**
48
+ * Image id from an {@link Image} (e.g. `image.imageId`), for a private
49
+ * image or a pinned digest. Exclusive with `baseImage`. Changing it
50
+ * replaces the sandbox.
51
+ */
52
+ image?: string;
53
+ /**
54
+ * Public OCI image reference with a `linux/amd64` manifest. Exclusive
55
+ * with `image`. Changing it replaces the sandbox.
56
+ * @default "node:24-bookworm"
57
+ */
58
+ baseImage?: string;
59
+ /** vCPUs, 1–32. Changing it replaces the sandbox. @default 1 */
60
+ vcpuCount?: number;
61
+ /** Memory in MiB, 256–65536. Changing it replaces the sandbox. @default 2048 */
62
+ memSizeMiB?: number;
63
+ /**
64
+ * TCP ports to serve publicly. Updated in place. When set, it is the
65
+ * whole list (plus the program's `port`): ports not in it are unexposed.
66
+ */
67
+ ports?: number[];
68
+ /**
69
+ * Let services inside the sandbox publish their own ingress.
70
+ * Changing it replaces the sandbox. @default false
71
+ */
72
+ enableServiceIngress?: boolean;
73
+ /**
74
+ * Environment variables. With `main`, they are the program's environment
75
+ * and a change restarts it. Without `main`, every process in the sandbox
76
+ * gets them, and a change replaces the sandbox.
77
+ */
78
+ env?: Record<string, string | Redacted.Redacted<string>>;
79
+ /** Outbound network policy. Updated in place. */
80
+ network?: {
81
+ egress?: SandboxEgress;
82
+ };
83
+ /**
84
+ * Disks to mount: a declared `Archil.Disk` (or the Effect that declares
85
+ * it) at a `path`. Updated in place: the sandbox stops, then starts with
86
+ * the new mounts, keeping its root filesystem.
87
+ */
88
+ mounts?: DiskMount[];
89
+ /**
90
+ * Seconds a powered-on session may run before the sandbox pauses
91
+ * (at most 24 hours). Changing it replaces the sandbox.
92
+ */
93
+ maxTtlSeconds?: number;
94
+ /**
95
+ * Seconds without a process connection before the sandbox pauses.
96
+ * `0` disables idle expiry. Updated in place.
97
+ */
98
+ idleTtlSeconds?: number;
99
+ /** Concurrent processes allowed. Changing it replaces the sandbox. */
100
+ maxConcurrentExecs?: number;
101
+ /**
102
+ * Shell commands run in the sandbox, in order, once it is created: clone
103
+ * a repository, install packages, warm a cache. A non-zero exit fails the
104
+ * deploy with `SandboxSetupFailed`. Changing them replaces the sandbox,
105
+ * so it starts again from its image and runs the new commands. Fork the
106
+ * result at run time with `Archil.CreateSandbox(sandbox)`.
107
+ */
108
+ run?: string[];
109
+ /**
110
+ * A program to run in the sandbox. In the Effect form, `import.meta.url`
111
+ * (the file is both the bundle entry and the program). In the async form,
112
+ * a path to a module whose default export has `fetch(request, env)`.
113
+ * A code change uploads it and restarts the program in place.
114
+ */
115
+ main?: string;
116
+ /** Named export to load from `main`. @default "default" */
117
+ handler?: string;
118
+ /**
119
+ * TCP port the program listens on, passed to it as `PORT`. Alchemy
120
+ * exposes it publicly and returns its URL as `url`.
121
+ * @default 3000
122
+ */
123
+ port?: number;
124
+ /**
125
+ * Bundler options for `main` (rolldown `input` / `output`), and
126
+ * `install`: packages to `npm install` next to the program instead of
127
+ * bundling them.
128
+ */
129
+ build?: ProgramBuildOptions;
130
+ /**
131
+ * Host files or directories uploaded with the program, e.g. a site's
132
+ * built assets. With `extraFiles`, an async `main` is treated as a
133
+ * complete Node program and uploaded as built instead of bundled.
134
+ * Their content is part of `code.hash`, so a change redeploys.
135
+ */
136
+ extraFiles?: ReadonlyArray<ProgramExtraFile>;
137
+ /**
138
+ * Where Alchemy pushes the sandbox's derived image, for Archil to pull.
139
+ * Only needed when a binding installs a filesystem client (an
140
+ * `alchemy/Mount` capability) into the program's image: Alchemy builds
141
+ * the base image plus those install lines with your local Docker.
142
+ */
143
+ push?: ImagePush;
144
+ }
145
+ export interface SandboxAttributes {
146
+ /** Sandbox id. */
147
+ sandboxId: string;
148
+ /** Sandbox name. */
149
+ name: string;
150
+ /** Lifecycle state when last observed, e.g. `running` or `paused`. */
151
+ status: string;
152
+ /** The image reference the sandbox boots. */
153
+ baseImage: string;
154
+ /** Digest of the booted image. */
155
+ imageDigest: string | undefined;
156
+ vcpuCount: number;
157
+ memSizeMiB: number;
158
+ /** Public hostnames of the exposed ports. */
159
+ endpoints: SandboxEndpoint[];
160
+ /** `https://` URL of the program's port, or of the first exposed port. */
161
+ url: string | undefined;
162
+ /** The port the program listens on, when the sandbox runs one. */
163
+ port: number | undefined;
164
+ /** Content hash of the deployed program, when the sandbox runs one. */
165
+ code: {
166
+ hash: string;
167
+ } | undefined;
168
+ /**
169
+ * The image Alchemy built for the sandbox (its base plus the install
170
+ * lines its bindings contribute), when it needed one.
171
+ */
172
+ derivedImage: {
173
+ imageId: string;
174
+ hash: string;
175
+ } | undefined;
176
+ /** Hash of the `run` commands the sandbox was set up with. */
177
+ setupHash: string | undefined;
178
+ }
179
+ export type Sandbox = Resource<"Archil.Sandbox", SandboxProps, SandboxAttributes, SandboxBinding, Providers, SandboxLookup>;
180
+ /**
181
+ * Props for {@link Sandbox.lookup}: find a sandbox this stack
182
+ * doesn't manage by its name.
183
+ */
184
+ export interface SandboxLookup {
185
+ /** Sandbox name. */
186
+ name: string;
187
+ }
188
+ export type SandboxShape = Main<ServerHost>;
189
+ /**
190
+ * An Archil sandbox: a Firecracker microVM with disks mounted, public
191
+ * ports, and an outbound network policy that can inject credentials at the
192
+ * boundary. It pauses when idle and resumes on the next connection,
193
+ * keeping its memory.
194
+ *
195
+ * Declare one as a box (a dev box or a preview environment that outlives
196
+ * deploys), or give it a `main` and it runs your program: Alchemy bundles
197
+ * it, uploads it, and registers it with Archil's service manager, which
198
+ * restarts it when it crashes and starts it whenever the sandbox boots. Its
199
+ * port gets a public `https://` URL, and a request to a stopped sandbox
200
+ * starts it again, typically in a few seconds. A code change uploads the
201
+ * program and restarts it in place.
202
+ *
203
+ * Short-lived sandboxes for one user or task are created at run time with
204
+ * {@link CreateSandbox}; act on a declared one with {@link ConnectSandbox}.
205
+ *
206
+ * :::caution
207
+ * Changing the image, size, timeouts, or the `env` of a sandbox without
208
+ * `main` replaces the sandbox, and a new one starts with an empty root
209
+ * filesystem. Keep data on a mounted disk. `mounts`, `ports`, `network`
210
+ * and the program update in place.
211
+ * :::
212
+ *
213
+ * :::caution
214
+ * An exposed port is public: anyone with the URL can call it. Check
215
+ * requests yourself, or hand clients an `Archil.SandboxPortToken`.
216
+ * :::
217
+ * @see https://docs.archil.com/compute/sandboxes/introduction
218
+ *
219
+ * ### Creating a Sandbox
220
+ * **Example:** A dev box with a disk mounted
221
+ * ```typescript
222
+ * export const Workspace = Archil.Disk("Workspace", {});
223
+ * export const DevBox = Archil.Sandbox("DevBox", {
224
+ * baseImage: "node:24-bookworm",
225
+ * vcpuCount: 2,
226
+ * memSizeMiB: 4096,
227
+ * mounts: [{ disk: Workspace, path: "/workspace" }],
228
+ * ports: [3000],
229
+ * idleTtlSeconds: 600,
230
+ * });
231
+ * ```
232
+ *
233
+ * **Example:** A bigger sandbox that never pauses while idle
234
+ * ```typescript
235
+ * export const Box = Archil.Sandbox("Box", {
236
+ * vcpuCount: 4,
237
+ * memSizeMiB: 8192,
238
+ * idleTtlSeconds: 0,
239
+ * });
240
+ * ```
241
+ *
242
+ * **Example:** Boot a private image
243
+ * ```typescript
244
+ * export const AgentImage = Archil.Image("AgentImage", {
245
+ * image: "ghcr.io/acme/agent:1",
246
+ * registry: { server: "ghcr.io", username: "acme", password: Config.Redacted("GHCR_TOKEN") },
247
+ * });
248
+ * export const Agent = Effect.gen(function* () {
249
+ * const image = yield* AgentImage;
250
+ * return yield* Archil.Sandbox("Agent", { image: image.imageId });
251
+ * });
252
+ * ```
253
+ *
254
+ * ### Setting Up at Deploy and Forking at Run Time
255
+ * **Example:** Clone a repository once, then fork the sandbox per task
256
+ * ```typescript
257
+ * export const Golden = Archil.Sandbox("Golden", {
258
+ * run: ["git clone --depth 1 https://github.com/sindresorhus/is /work/is"],
259
+ * });
260
+ *
261
+ * // in a Worker or program:
262
+ * const sandboxes = yield* Archil.CreateSandbox(Golden);
263
+ * const task = yield* sandboxes.create({ name: "task-1" });
264
+ * const result = yield* task.exec("git log -1", { cwd: "/work/is" });
265
+ * ```
266
+ *
267
+ * ### Running a Program
268
+ * **Example:** An Effect program that reads a mounted disk
269
+ * ```typescript
270
+ * // src/Api.ts
271
+ * import * as Archil from "@alchemy.run/archil";
272
+ * import * as Effect from "effect/Effect";
273
+ * import * as FileSystem from "effect/FileSystem";
274
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
275
+ *
276
+ * export const Dataset = Archil.Disk("Dataset", {});
277
+ *
278
+ * export default class Api extends Archil.Sandbox<Api>()(
279
+ * "Api",
280
+ * { main: import.meta.url, port: 3000 },
281
+ * Effect.gen(function* () {
282
+ * const dataset = yield* Archil.MountDisk(Dataset, { path: "/data", mode: "read-only" });
283
+ * const fs = yield* FileSystem.FileSystem;
284
+ * return {
285
+ * fetch: Effect.gen(function* () {
286
+ * return yield* HttpServerResponse.json(yield* fs.readDirectory(dataset.path));
287
+ * }).pipe(Effect.orDie),
288
+ * };
289
+ * }).pipe(Effect.provide(Archil.MountDiskLive)),
290
+ * ) {}
291
+ * ```
292
+ *
293
+ * **Example:** A plain async handler with typed `env`
294
+ * ```typescript
295
+ * // src/infra.ts
296
+ * export const Hello = Archil.Sandbox("Hello", {
297
+ * main: "./src/hello.ts",
298
+ * env: { GREETING: "hello" },
299
+ * });
300
+ * export type HelloEnv = Archil.InferEnv<typeof Hello>;
301
+ * ```
302
+ *
303
+ * ```typescript
304
+ * // src/hello.ts
305
+ * import type { HelloEnv } from "./infra.ts";
306
+ *
307
+ * export default {
308
+ * async fetch(request: Request, env: HelloEnv) {
309
+ * return new Response(`${env.GREETING} from ${new URL(request.url).pathname}`);
310
+ * },
311
+ * };
312
+ * ```
313
+ *
314
+ * **Example:** Secrets in the program's environment
315
+ * ```typescript
316
+ * export const Billing = Archil.Sandbox("Billing", {
317
+ * main: "./src/billing.ts",
318
+ * env: { STRIPE_KEY: Config.Redacted("STRIPE_KEY") },
319
+ * });
320
+ * ```
321
+ *
322
+ * ### Mounting Disks
323
+ * Archil sandboxes mount disks natively. Each entry names the disk and a
324
+ * `path`, with Archil's own options: `mode` (`exclusive`, `conditional`
325
+ * or `read-only`), `subdirectory`, and `queueMs`.
326
+ *
327
+ * **Example:** Mount two disks, one read-only
328
+ * ```typescript
329
+ * export const Box = Archil.Sandbox("Box", {
330
+ * mounts: [
331
+ * { disk: Workspace, path: "/workspace" },
332
+ * { disk: Dataset, path: "/data", mode: "read-only" },
333
+ * ],
334
+ * });
335
+ * ```
336
+ *
337
+ * **Example:** Mount from the program with `MountDisk`
338
+ * ```typescript
339
+ * const uploads = yield* Archil.MountDisk(Uploads, { path: "/uploads", mode: "conditional" });
340
+ * // runtime: the disk is already mounted at uploads.path
341
+ * yield* fs.writeFileString(`${uploads.path}/${id}.txt`, body);
342
+ * ```
343
+ *
344
+ * ### Mount Clients From Other Bindings
345
+ * A binding that installs a filesystem client (an `alchemy/Mount`
346
+ * capability) into a program's image makes Alchemy build one: the
347
+ * sandbox's base plus the client's install lines, built with your local
348
+ * Docker and pushed to `push.repository` for Archil to pull. A different
349
+ * set of clients replaces the sandbox.
350
+ *
351
+ * **Example:** Give a program sandbox a repository for its derived image
352
+ * ```typescript
353
+ * export default class Indexer extends Archil.Sandbox<Indexer>()(
354
+ * "Indexer",
355
+ * {
356
+ * main: import.meta.url,
357
+ * push: {
358
+ * repository: "ghcr.io/acme/indexer",
359
+ * credentials: { server: "ghcr.io", username: "acme-bot", password: Alchemy.Secret("GHCR_TOKEN") },
360
+ * },
361
+ * },
362
+ * Effect.gen(function* () {
363
+ * const media = yield* Cloud.MountBucket(Media, { path: "/media" }); // installs a FUSE client
364
+ * return { fetch: Effect.succeed(HttpServerResponse.text(media.path)) };
365
+ * }),
366
+ * ) {}
367
+ * ```
368
+ *
369
+ * ### Packaging
370
+ * Alchemy bundles `main` with rolldown into one Node program. Packages
371
+ * that can't be bundled (native modules, or ones that read their own files
372
+ * at run time) go in `build.install` and are installed next to it with
373
+ * `npm install`.
374
+ *
375
+ * **Example:** Install a native package
376
+ * ```typescript
377
+ * export const Thumbs = Archil.Sandbox("Thumbs", {
378
+ * main: "./src/thumbs.ts",
379
+ * build: { install: ["sharp"] },
380
+ * });
381
+ * ```
382
+ *
383
+ * **Example:** Upload static files next to the program
384
+ * ```typescript
385
+ * export const Site = Archil.Sandbox("Site", {
386
+ * main: "./dist/server.mjs",
387
+ * extraFiles: [{ source: "./dist/client", destination: "client" }],
388
+ * });
389
+ * ```
390
+ *
391
+ * ### Ports
392
+ * **Example:** Serve a port and hand out a token for it
393
+ * ```typescript
394
+ * export const Preview = Archil.Sandbox("Preview", { ports: [8080] });
395
+ * export const PreviewToken = Effect.gen(function* () {
396
+ * const preview = yield* Preview;
397
+ * return yield* Archil.SandboxPortToken("PreviewToken", {
398
+ * sandbox: preview.sandboxId,
399
+ * port: 8080,
400
+ * ttl: "24h",
401
+ * });
402
+ * });
403
+ * ```
404
+ *
405
+ * ### Network Policy
406
+ * **Example:** Deny by default, inject a token for one API
407
+ * ```typescript
408
+ * export const Agent = Archil.Sandbox("Agent", {
409
+ * network: {
410
+ * egress: {
411
+ * default: "deny",
412
+ * allow: [
413
+ * "registry.npmjs.org",
414
+ * { target: "api.github.com", headers: { Authorization: Alchemy.Secret("GITHUB_AUTH") } },
415
+ * ],
416
+ * },
417
+ * },
418
+ * });
419
+ * ```
420
+ *
421
+ * **Example:** Forward an API's requests to a Worker gateway that adds the key
422
+ * ```typescript
423
+ * const gateway = yield* MyGateway;
424
+ * const sandbox = yield* Archil.Sandbox("MySandbox", {
425
+ * network: {
426
+ * egress: {
427
+ * default: "deny",
428
+ * allow: [
429
+ * {
430
+ * target: "api.example.com",
431
+ * // proves to the gateway that the request came through this policy
432
+ * headers: { "X-Gateway-Token": Config.Redacted("GATEWAY_TOKEN") },
433
+ * forwardUrl: gateway.url.as<string>(),
434
+ * },
435
+ * ],
436
+ * },
437
+ * },
438
+ * });
439
+ * ```
440
+ *
441
+ * ### Using a Sandbox at Run Time
442
+ * **Example:** Run a command and fork a preview from a Worker
443
+ * ```typescript
444
+ * const preview = yield* Archil.ConnectSandbox(Preview);
445
+ * const result = yield* preview.exec("pnpm build", { cwd: "/workspace" });
446
+ * const fork = yield* preview.fork({ name: "pr-42" });
447
+ * ```
448
+ *
449
+ * ### Looking up an existing sandbox
450
+ * `Sandbox.lookup` references a sandbox Alchemy doesn't manage (created in
451
+ * the Archil console or by another stack). It is read during plan/deploy,
452
+ * never created, updated or deleted.
453
+ * Its program fields are `undefined`: they come from the deploy that started
454
+ * the sandbox's program.
455
+ *
456
+ * **Example:** Reference an existing sandbox
457
+ * ```typescript
458
+ * const box = Archil.Sandbox.lookup({ name: "research" });
459
+ * ```
460
+ *
461
+ * @resource
462
+ * @product Sandbox
463
+ */
464
+ export declare const Sandbox: Platform<Sandbox, ServerHost, SandboxShape, HostRuntimeContext> & LookupMethod<Sandbox>;
465
+ /**
466
+ * Map a sandbox and its exposed ports to attributes. Archil lists port
467
+ * hostnames separately; sandbox responses don't carry them. `program` is
468
+ * the port and code of the program the sandbox runs, if any.
469
+ */
470
+ export declare const toSandboxAttributes: (sandbox: archil.Sandbox, ports: ReadonlyArray<{
471
+ port: number;
472
+ hostname: string;
473
+ }>, program?: {
474
+ readonly port: number;
475
+ readonly code: {
476
+ hash: string;
477
+ };
478
+ }, derivedImage?: {
479
+ readonly imageId: string;
480
+ readonly hash: string;
481
+ }) => SandboxAttributes;
482
+ /** Read a sandbox's exposed ports and map it to attributes. */
483
+ export declare const observeSandbox: (sandbox: archil.Sandbox, program?: {
484
+ readonly port: number;
485
+ readonly code: {
486
+ hash: string;
487
+ };
488
+ } | undefined, derivedImage?: {
489
+ readonly imageId: string;
490
+ readonly hash: string;
491
+ } | undefined) => Effect.Effect<SandboxAttributes, archil.ArchilParseError | archil.BadGateway | import("@distilled.cloud/core/errors").BadRequest | archil.ConfigError | import("@distilled.cloud/core/errors").Conflict | import("@distilled.cloud/core/errors").Forbidden | archil.GatewayTimeout | import("effect/http/HttpClientError").HttpClientError | archil.InternalServerError | import("@distilled.cloud/core/protocol-http").InvalidInput | archil.Locked | import("@distilled.cloud/core/sdk-error").SdkError | archil.ServiceUnavailable | archil.TooManyRequests | archil.Unauthorized | archil.UnknownArchilError | archil.UnprocessableEntity, archil.ArchilOpContext>;
492
+ /** The create request for sandbox props, with mounts already on the wire. */
493
+ export declare const toCreateSandboxRequest: (name: string | undefined, props: Omit<SandboxProps, "name" | "mounts">, mounts: ReadonlyArray<archil.SandboxMount> | undefined) => archil.CreateSandboxRequest;
494
+ /**
495
+ * Delete a sandbox and wait until it is gone. Archil only deletes stopped,
496
+ * exited or failed sandboxes, so a live one is stopped first. Deleting a
497
+ * missing sandbox succeeds.
498
+ */
499
+ export declare const deleteSandbox: (sid: string) => Effect.Effect<void, import("./index.ts").ArchilFailed | import("./index.ts").ArchilNotReady | archil.ArchilParseError | archil.BadGateway | import("@distilled.cloud/core/errors").BadRequest | archil.BadRequest | archil.ConfigError | import("@distilled.cloud/core/errors").Conflict | import("@distilled.cloud/core/errors").Forbidden | archil.GatewayTimeout | import("effect/http/HttpClientError").HttpClientError | archil.InternalServerError | import("@distilled.cloud/core/protocol-http").InvalidInput | archil.Locked | archil.SandboxHasForks | archil.SandboxNotDeletable | archil.SandboxStopConflict | import("@distilled.cloud/core/sdk-error").SdkError | archil.ServiceUnavailable | archil.TooManyRequests | archil.Unauthorized | archil.UnknownArchilError | archil.UnprocessableEntity, archil.ArchilOpContext>;
500
+ /**
501
+ * Wire mounts for a list of entries whose disks resolved to attributes or
502
+ * handles. Fails when a disk has no id yet.
503
+ */
504
+ export declare const toSandboxMounts: (owner: string, mounts: readonly DiskMount[]) => Effect.Effect<archil.SandboxMount[], MountDiskUnresolved | import("./SandboxOptions.ts").MountOptionUnsupported, never>;
505
+ export declare const SandboxProvider: () => import("effect/Layer").Layer<Provider.Provider<Sandbox>, never, import("effect/process/ChildProcessSpawner").ChildProcessSpawner | import("@alchemy.run/docker/Docker").Docker | import("effect/FileSystem").FileSystem | import("effect/Path").Path | Stack | import("alchemy").Stage | archil.ArchilOpContext>;
506
+ export {};
507
+ //# sourceMappingURL=Sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sandbox.d.ts","sources":["../src/Sandbox.ts"],"names":[],"mappings":"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"}