@effect-uai/microsandbox 0.11.0 → 0.12.1

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.
@@ -2,8 +2,6 @@ import { BoundSecret, CommonCreateRequest, Sandbox, SandboxHostnameAllowlist, Sa
2
2
  import * as SandboxError from "@effect-uai/core/SandboxError";
3
3
  import * as Memory from "@effect-uai/core/Memory";
4
4
  import { Context, Duration, Effect, Layer, Scope } from "effect";
5
-
6
- //#region src/MicrosandboxSandbox.d.ts
7
5
  declare namespace MicrosandboxSandbox_d_exports {
8
6
  export { MicrosandboxBoundSecret, MicrosandboxConfig, MicrosandboxCreateRequest, MicrosandboxSandbox, MicrosandboxSandboxService, layer };
9
7
  }
@@ -37,7 +35,8 @@ type MicrosandboxCreateRequest = Omit<CommonCreateRequest, "secrets"> & {
37
35
  readonly detached?: boolean;
38
36
  };
39
37
  type MicrosandboxConfig = {
40
- /** Default OCI image to use when no `image` is supplied on create. */readonly defaultImage?: string;
38
+ /** Default OCI image to use when no `image` is supplied on create. */
39
+ readonly defaultImage?: string;
41
40
  };
42
41
  /**
43
42
  * Microsandbox-narrowed service. `create` accepts the narrowed
@@ -1 +1 @@
1
- {"version":3,"file":"MicrosandboxSandbox.d.mts","names":[],"sources":["../src/MicrosandboxSandbox.ts"],"mappings":";;;;;;;;;KAoEY,uBAAA,GAA0B,IAAA,CAAK,WAAA;AAAA,KAE/B,yBAAA,GAA4B,IAAA,CAAK,mBAAA;EAAA,SAClC,OAAA,GAAU,aAAA,CAAc,uBAAA;EAAA,SACxB,IAAA;EAAA,SACA,IAAA;;;;;;WAMA,MAAA,GAAS,MAAA,CAAO,KAAA;EAAA,SAChB,OAAA;EAAA,SACA,IAAA;EAAA,SACA,WAAA,GAAc,QAAA,CAAS,KAAA;EAAA,SACvB,WAAA,GAAc,QAAA,CAAS,KAAA;EAfoB;AAEtD;;;;EAFsD,SAqB3C,OAAA;IAAA,SAA+B,OAAA;EAAA;EAVtB;;;;EAAA,SAeT,QAAA;AAAA;AAAA,KAGC,kBAAA;EA1BD,+EA4BA,YAAA;AAAA;;;;;;KAQC,0BAAA,GAA6B,IAAA,CAAK,cAAA;EAAA,SACnC,MAAA,GACP,OAAA,EAAS,yBAAA,KACN,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,YAAA,CAAa,YAAA,EAAc,KAAA,CAAM,KAAA;AAAA;AAAA,cACtE,wBAAA;cAEY,mBAAA,SAA4B,wBAAA;AAAA,cA2uB5B,KAAA,GAAS,MAAA,GAAQ,kBAAA,KAAuB,KAAA,CAAA,KAAA,CAAA,mBAAA,GAAA,OAAA,GAAA,wBAAA,GAAA,sBAAA,GAAA,gBAAA,GAAA,cAAA"}
1
+ {"version":3,"file":"MicrosandboxSandbox.d.mts","names":[],"sources":["../src/MicrosandboxSandbox.ts"],"mappings":";;;;;;;KAoEY,0BAA0B,KAAK;KAE/B,4BAA4B,KAAK;WAClC,UAAU,cAAc;WACxB;WACA;;;;;;WAMA,SAAS,OAAO;WAChB;WACA;WACA,cAAc,SAAS;WACvB,cAAc,SAAS;;;;;;WAMvB;aAA+B;;;;;;WAK/B;;KAGC;;WAED;;;;;;;KAQC,6BAA6B,KAAK;WACnC,SACP,SAAS,8BACN,OAAO,OAAO,iBAAiB,aAAa,cAAc,MAAM;;;cAG1D,4BAA4B;cAkvB5B,QAAK,SAAY,uBAAkB,MAAA,MAAA,sBAAA,UAAA,2BAAA,yBAAA,mBAAA"}
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { ExecEvent, Sandbox, SandboxHostnameAllowlist, SandboxId, SandboxSecretInjection, SandboxSnapshots, SandboxVolumes, SnapshotId, VolumeId } from "@effect-uai/core/Sandbox";
3
3
  import * as SandboxError from "@effect-uai/core/SandboxError";
4
4
  import * as Memory from "@effect-uai/core/Memory";
@@ -93,7 +93,7 @@ const buildPolicy = (hosts, cidrs) => {
93
93
  const networkStep = (policy) => Match.value(policy).pipe(Match.tag("Open", () => noop), Match.tag("Blocked", () => (b) => b.disableNetwork()), Match.tag("Allowlist", ({ hosts, cidrs }) => (b) => b.network((n) => n.policyFromBuilder(buildPolicy(hosts ?? [], cidrs ?? [])))), Match.exhaustive);
94
94
  const secretStep = (secret) => (b) => b.secret((sb) => Array.reduce(secret.hosts, sb.env(secret.name).value(Redacted.value(secret.value)), (acc, host) => acc.allowHost(host)).injectHeaders(true));
95
95
  const volumeStep = (vol) => (b) => b.volume(vol.mountPath, (m) => vol.readonly ? m.named(vol.id).readonly() : m.named(vol.id));
96
- const replaceStep = (replace) => replace === true ? (b) => b.replace() : typeof replace === "object" ? (b) => b.replaceWithGrace(replace.graceMs) : noop;
96
+ const replaceStep = (replace) => replace === true ? (b) => b.replace() : typeof replace === "object" ? (b) => b.replaceWithTimeout(replace.graceMs) : noop;
97
97
  const argv = (cmd) => typeof cmd === "string" ? Effect.succeed({
98
98
  cmd,
99
99
  args: []
@@ -233,7 +233,7 @@ const buildService = (config) => {
233
233
  const steps = [
234
234
  yield* resolveImageStep(request.image),
235
235
  when(request.cpus, (n) => (b) => b.cpus(n)),
236
- when(request.memory, (m) => (b) => b.memory(Math.ceil(Memory.toBytes(m) / (1024 * 1024)))),
236
+ when(request.memory, (m) => (b) => b.memory(Math.ceil(Memory.toBytes(m) / 1048576))),
237
237
  when(request.workdir, (p) => (b) => b.workdir(p)),
238
238
  when(request.user, (u) => (b) => b.user(u)),
239
239
  when(request.maxDuration, (d) => (b) => b.maxDuration(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(d)) / 1e3))),
@@ -247,7 +247,7 @@ const buildService = (config) => {
247
247
  ];
248
248
  const built = Array.reduce(steps, Sandbox$1.builder(name), (b, step) => step(b));
249
249
  return yield* Effect.tryPromise({
250
- try: () => request.detached ? built.createDetached() : built.create(),
250
+ try: () => (request.detached ? built.detached(true) : built).create(),
251
251
  catch: mapCreateError
252
252
  });
253
253
  });
@@ -263,16 +263,26 @@ const buildService = (config) => {
263
263
  const token = yield* randomToken;
264
264
  const name = SandboxId(request.name ?? `eff-uai-${token}`);
265
265
  const detached = request.detached === true;
266
- return adaptInstance(yield* Effect.acquireRelease(acquireSandbox(request, name), () => detached ? Effect.void : Effect.ignore(destroyById(name))));
266
+ const msb = yield* Effect.acquireRelease(acquireSandbox(request, name), () => detached ? Effect.void : Effect.ignore(destroyById(name)));
267
+ return adaptInstance(msb);
267
268
  }),
268
269
  attach: (id) => Effect.acquireRelease(acquireAttached(id), () => Effect.void).pipe(Effect.map(adaptInstance)),
269
- list: Effect.tryPromise({
270
- try: () => Sandbox$1.list(),
271
- catch: mapCreateError
272
- }).pipe(Effect.map(Array.map((h) => ({
273
- id: SandboxId(h.name),
274
- name: h.name
275
- })))),
270
+ list: Effect.gen(function* () {
271
+ const refs = [];
272
+ let cursor;
273
+ while (true) {
274
+ const page = yield* Effect.tryPromise({
275
+ try: () => cursor === void 0 ? Sandbox$1.list() : Sandbox$1.listWith((l) => l.cursor(cursor)),
276
+ catch: mapCreateError
277
+ });
278
+ refs.push(...Array.map(page.sandboxes, (h) => ({
279
+ id: SandboxId(h.name),
280
+ name: h.name
281
+ })));
282
+ if (page.nextCursor === void 0) return refs;
283
+ cursor = page.nextCursor;
284
+ }
285
+ }),
276
286
  destroy: destroyById,
277
287
  snapshots: {
278
288
  create: (from, name) => Effect.gen(function* () {
@@ -307,7 +317,7 @@ const buildService = (config) => {
307
317
  volumes: {
308
318
  create: (name, options) => {
309
319
  const builder = Volume.builder(name);
310
- const sized = options?.quotaBytes === void 0 ? builder : builder.quota(Math.ceil(options.quotaBytes / (1024 * 1024)));
320
+ const sized = options?.quotaBytes === void 0 ? builder : builder.quota(Math.ceil(options.quotaBytes / 1048576));
311
321
  return Effect.tryPromise({
312
322
  try: () => sized.create(),
313
323
  catch: mapCreateError
@@ -1 +1 @@
1
- {"version":3,"file":"MicrosandboxSandbox.mjs","names":["MsbSandbox","Arr","CoreExecEvent","MsbSnapshot","MsbVolume","CoreSandbox"],"sources":["../src/MicrosandboxSandbox.ts"],"sourcesContent":["import {\n ExecEvent as CoreExecEvent,\n Sandbox as CoreSandbox,\n SandboxHostnameAllowlist,\n SandboxSecretInjection,\n SandboxSnapshots,\n SandboxVolumes,\n type BoundSecret,\n type CommonCreateRequest,\n type CommonExecRequest,\n type ExecResult,\n type ImageRef,\n type NetworkPolicy,\n type CommonSpawnRequest,\n type ProcessHandle,\n SandboxId,\n type SandboxInstance,\n type SandboxRef,\n type SandboxService,\n SnapshotId,\n VolumeId,\n} from \"@effect-uai/core/Sandbox\"\nimport * as SandboxError from \"@effect-uai/core/SandboxError\"\nimport * as Memory from \"@effect-uai/core/Memory\"\nimport {\n Array as Arr,\n Clock,\n Context,\n Duration,\n Effect,\n Filter,\n Layer,\n Match,\n Option,\n Random,\n Record,\n Redacted,\n Result,\n Schedule,\n Scope,\n Stream,\n} from \"effect\"\nimport {\n type ExecHandle as MsbExecHandle,\n ExecTimeoutError,\n NetworkPolicyBuilder,\n Sandbox as MsbSandbox,\n SandboxNotFoundError,\n SandboxStillRunningError,\n Snapshot as MsbSnapshot,\n Volume as MsbVolume,\n type ExecEvent as MsbExecEvent,\n type SandboxBuilder as MsbSandboxBuilder,\n} from \"microsandbox\"\n\nconst PROVIDER = \"microsandbox\"\n\n// ---------------------------------------------------------------------------\n// Provider-narrowed request types.\n//\n// Microsandbox's secret-injection wire only supports the default\n// `Authorization: Bearer <value>` header convention — there's no\n// per-secret custom header. We omit `header` on the typed surface\n// (row B / type-level narrowing); calls via the generic `Sandbox.create`\n// surface that set `header` are rejected at runtime (row D\n// `SandboxUnsupported`) — see the upcast adapter in `layer`.\n// ---------------------------------------------------------------------------\n\nexport type MicrosandboxBoundSecret = Omit<BoundSecret, \"header\">\n\nexport type MicrosandboxCreateRequest = Omit<CommonCreateRequest, \"secrets\"> & {\n readonly secrets?: ReadonlyArray<MicrosandboxBoundSecret>\n readonly name?: string\n readonly cpus?: number\n /**\n * Memory size. Accepts a byte count, a {@link Memory.Memory}, or a\n * human string like `\"1 GiB\"` / `\"512 MiB\"`. Rounded up to whole\n * MiB at the SDK boundary (microsandbox's builder takes MiB).\n */\n readonly memory?: Memory.Input\n readonly workdir?: string\n readonly user?: string\n readonly maxDuration?: Duration.Input\n readonly idleTimeout?: Duration.Input\n /**\n * Stop any existing sandbox with the same name before creating.\n * `true` = `SIGTERM` with the SDK default grace; `{ graceMs }` =\n * explicit grace before `SIGKILL`.\n */\n readonly replace?: boolean | { readonly graceMs: number }\n /**\n * Detach so the sandbox outlives the calling scope. The scope\n * finalizer skips destroy; clean up via {@link Sandbox.destroy}.\n */\n readonly detached?: boolean\n}\n\nexport type MicrosandboxConfig = {\n /** Default OCI image to use when no `image` is supplied on create. */\n readonly defaultImage?: string\n}\n\n/**\n * Microsandbox-narrowed service. `create` accepts the narrowed\n * {@link MicrosandboxCreateRequest}; every other method is identical\n * to the generic {@link SandboxService}.\n */\nexport type MicrosandboxSandboxService = Omit<SandboxService, \"create\"> & {\n readonly create: (\n request: MicrosandboxCreateRequest,\n ) => Effect.Effect<SandboxInstance, SandboxError.SandboxError, Scope.Scope>\n}\n\nexport class MicrosandboxSandbox extends Context.Service<\n MicrosandboxSandbox,\n MicrosandboxSandboxService\n>()(\"@betalyra/effect-uai/providers/microsandbox/MicrosandboxSandbox\") {}\n\n// ---------------------------------------------------------------------------\n// Effect-native primitives\n// ---------------------------------------------------------------------------\n\n/** Random base-36 token, ~8 chars. Stand-in for `Math.random` IDs. */\nconst randomToken = Random.next.pipe(Effect.map((r) => r.toString(36).slice(2, 10)))\n\n// ---------------------------------------------------------------------------\n// Error mapping\n// ---------------------------------------------------------------------------\n\nconst reasonOf = (e: unknown) => (e instanceof Error ? { reason: e.message } : {})\n\nconst mapCreateError = (e: unknown): SandboxError.SandboxError =>\n e instanceof SandboxStillRunningError\n ? new SandboxError.SandboxAlreadyExists({\n provider: PROVIDER,\n id: e.message,\n })\n : e instanceof SandboxNotFoundError\n ? new SandboxError.SandboxNotFound({ provider: PROVIDER, id: e.message })\n : new SandboxError.SandboxCreateFailed({\n provider: PROVIDER,\n raw: e,\n ...reasonOf(e),\n })\n\nconst mapExecError = (e: unknown): SandboxError.SandboxError =>\n e instanceof ExecTimeoutError\n ? new SandboxError.SandboxTimeout({\n provider: PROVIDER,\n operation: \"exec\",\n raw: e,\n })\n : new SandboxError.SandboxExecFailed({\n provider: PROVIDER,\n raw: e,\n ...reasonOf(e),\n })\n\nconst mapFsError = (e: unknown): SandboxError.SandboxError =>\n new SandboxError.SandboxExecFailed({\n provider: PROVIDER,\n raw: e,\n ...reasonOf(e),\n })\n\nconst mapLookupError =\n (id: string) =>\n (e: unknown): SandboxError.SandboxError =>\n e instanceof SandboxNotFoundError\n ? new SandboxError.SandboxNotFound({ provider: PROVIDER, id })\n : mapCreateError(e)\n\n// ---------------------------------------------------------------------------\n// Stopping & post-kill DB sync.\n//\n// Empirically (spike + SDK 0.4.6):\n// - `handle.connect()` + `live.stopAndWait()` resolves in 0ms on a\n// non-owning connection — the VM keeps running. Useless.\n// - `handle.kill()` signals the runtime to terminate, but the DB row's\n// `status` field only flips to \"stopped\" ~200ms later. Operations\n// that re-read DB status (`MsbSandbox.remove`, `handle.snapshot`)\n// reject during that window with a \"still running\" error.\n//\n// Rather than a fixed sleep (which over- and under-shoots), we kill\n// then retry the next operation on the transient race with exponential\n// backoff. Typical recovery: 1–3 retries (~50–350ms). Budget is 5\n// attempts ≈ 50+100+200+400+800 = 1.55s — plenty of margin for a\n// loaded host.\n// ---------------------------------------------------------------------------\n\nconst settleSchedule = Schedule.exponential(\"50 millis\")\nconst SETTLE_RETRIES = 5\n\n/**\n * Microsandbox's post-kill DB sync window surfaces as \"still running\"\n * either via `SandboxStillRunningError` (mapped to `SandboxAlreadyExists`\n * by {@link mapCreateError}) or, for `handle.snapshot`, a generic\n * `MicrosandboxError` whose message contains \"is not stopped\" /\n * \"still running\" (mapped to `SandboxCreateFailed`).\n */\nconst isPostKillRace = (e: SandboxError.SandboxError) =>\n e._tag === \"SandboxAlreadyExists\" ||\n (e._tag === \"SandboxCreateFailed\" &&\n typeof e.reason === \"string\" &&\n /still running|is not stopped/i.test(e.reason))\n\nconst retryOnSettle = <A, R>(\n effect: Effect.Effect<A, SandboxError.SandboxError, R>,\n): Effect.Effect<A, SandboxError.SandboxError, R> =>\n Effect.retry(effect, {\n schedule: settleSchedule,\n times: SETTLE_RETRIES,\n while: isPostKillRace,\n })\n\n/** Force-kill a running sandbox. No-op if absent or already stopped. */\nconst killRunning = (id: string) =>\n Effect.tryPromise({\n try: () => MsbSandbox.get(id),\n catch: mapLookupError(id),\n }).pipe(\n Effect.flatMap((handle) =>\n handle.status === \"running\"\n ? Effect.tryPromise({\n try: () => handle.kill(),\n catch: mapLookupError(id),\n })\n : Effect.void,\n ),\n Effect.catchTag(\"SandboxNotFound\", () => Effect.void),\n )\n\n/** Stop + remove. Idempotent — `SandboxNotFound` is treated as success. */\nconst destroyById = (id: SandboxId) =>\n killRunning(id).pipe(\n Effect.andThen(\n retryOnSettle(\n Effect.tryPromise({\n try: () => MsbSandbox.remove(id),\n catch: mapLookupError(id),\n }),\n ),\n ),\n Effect.catchTag(\"SandboxNotFound\", () => Effect.void),\n )\n\n// ---------------------------------------------------------------------------\n// Builder pipeline — a `Step` is a pure builder→builder transformation.\n// The create flow folds an array of Steps through the initial builder.\n// ---------------------------------------------------------------------------\n\ntype Step = (b: MsbSandboxBuilder) => MsbSandboxBuilder\n\nconst noop: Step = (b) => b\n\nconst when = <A>(value: A | undefined, step: (a: A) => Step): Step =>\n value === undefined ? noop : step(value)\n\n// ---------------------------------------------------------------------------\n// ImageRef → Step. Snapshots / registry honored; Default falls through\n// to the layer's `defaultImage`; Dockerfile is unsupported.\n// ---------------------------------------------------------------------------\n\nconst imageStep =\n (defaultImage: string | undefined) =>\n (image: ImageRef | undefined): Effect.Effect<Step, SandboxError.SandboxError> => {\n const fromDefault: Effect.Effect<Step, SandboxError.SandboxError> =\n defaultImage === undefined\n ? Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"image\",\n reason:\n \"microsandbox requires an image — pass `image` on the request or set `defaultImage` on the layer config\",\n }),\n )\n : Effect.succeed((b) => b.image(defaultImage))\n\n if (image === undefined) return fromDefault\n\n return Match.value(image).pipe(\n Match.tag(\"Default\", () => fromDefault),\n Match.tag(\n \"Registry\",\n ({ ref }): Effect.Effect<Step, SandboxError.SandboxError> =>\n Effect.succeed((b) => b.image(ref)),\n ),\n Match.tag(\n \"Snapshot\",\n ({ id }): Effect.Effect<Step, SandboxError.SandboxError> =>\n Effect.succeed((b) => b.fromSnapshot(id)),\n ),\n Match.tag(\n \"Dockerfile\",\n (): Effect.Effect<Step, SandboxError.SandboxError> =>\n Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"image\",\n reason: \"microsandbox accepts OCI registry refs or snapshots, not Dockerfiles\",\n }),\n ),\n ),\n Match.exhaustive,\n )\n }\n\n// ---------------------------------------------------------------------------\n// NetworkPolicy → Step. CIDRs and hostnames both honored.\n// ---------------------------------------------------------------------------\n\nconst buildPolicy = (hosts: ReadonlyArray<string>, cidrs: ReadonlyArray<string>) => {\n const withHosts = Arr.reduce(hosts, new NetworkPolicyBuilder().defaultDeny(), (pb, host) =>\n pb.rule((rb) => rb.egress().allowDomain(host)),\n )\n return Arr.reduce(cidrs, withHosts, (pb, cidr) =>\n pb.rule((rb) => rb.egress().allow((d) => d.cidr(cidr))),\n )\n}\n\nconst networkStep = (policy: NetworkPolicy): Step =>\n Match.value(policy).pipe(\n Match.tag(\"Open\", (): Step => noop),\n Match.tag(\"Blocked\", (): Step => (b) => b.disableNetwork()),\n Match.tag(\n \"Allowlist\",\n ({ hosts, cidrs }): Step =>\n (b) =>\n b.network((n) => n.policyFromBuilder(buildPolicy(hosts ?? [], cidrs ?? []))),\n ),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// Secret / volume / replace Steps. Each item folds into its own Step;\n// the create pipeline reduces them through the builder.\n// ---------------------------------------------------------------------------\n\nconst secretStep =\n (secret: {\n readonly name: string\n readonly value: Redacted.Redacted<string>\n readonly hosts: ReadonlyArray<string>\n }): Step =>\n (b) =>\n b.secret((sb) =>\n Arr.reduce(\n secret.hosts,\n sb.env(secret.name).value(Redacted.value(secret.value)),\n (acc, host) => acc.allowHost(host),\n ).injectHeaders(true),\n )\n\nconst volumeStep =\n (vol: { readonly id: VolumeId; readonly mountPath: string; readonly readonly?: boolean }): Step =>\n (b) =>\n b.volume(vol.mountPath, (m) => (vol.readonly ? m.named(vol.id).readonly() : m.named(vol.id)))\n\nconst replaceStep = (replace: MicrosandboxCreateRequest[\"replace\"]): Step =>\n replace === true\n ? (b) => b.replace()\n : typeof replace === \"object\"\n ? (b) => b.replaceWithGrace(replace.graceMs)\n : noop\n\n// ---------------------------------------------------------------------------\n// argv splitter — string is run via shell semantics by the SDK, array\n// is direct argv. Empty argv is a typed error.\n// ---------------------------------------------------------------------------\n\nconst argv = (\n cmd: CommonExecRequest[\"cmd\"],\n): Effect.Effect<\n { readonly cmd: string; readonly args: ReadonlyArray<string> },\n SandboxError.SandboxError\n> =>\n typeof cmd === \"string\"\n ? Effect.succeed({ cmd, args: [] as ReadonlyArray<string> })\n : Option.match(Arr.head(cmd), {\n onNone: () =>\n Effect.fail(\n new SandboxError.SandboxInvalidRequest({\n provider: PROVIDER,\n param: \"cmd\",\n reason: \"argv array must be non-empty\",\n }),\n ),\n onSome: (head) => Effect.succeed({ cmd: head, args: Arr.drop(cmd, 1) }),\n })\n\n// ---------------------------------------------------------------------------\n// CommonExecRequest → ExecOptionsBuilder configurator.\n// ---------------------------------------------------------------------------\n\ntype ExecConfigure = Parameters<MsbSandbox[\"execWith\"]>[1]\n\nconst toBuffer = (input: Uint8Array | string) =>\n typeof input === \"string\" ? Buffer.from(input, \"utf-8\") : Buffer.from(input)\n\n/**\n * `string` / `Uint8Array` stdin uses one-shot `stdinBytes`; a Stream\n * uses `stdinPipe` and gets fed via `feedStdin` once the handle is open.\n */\nconst stdinIsStream = (\n stdin: CommonSpawnRequest[\"stdin\"],\n): stdin is Stream.Stream<Uint8Array, never, never> =>\n stdin !== undefined && typeof stdin !== \"string\" && !(stdin instanceof Uint8Array)\n\nconst execConfigure =\n (args: ReadonlyArray<string>, request: CommonSpawnRequest): ExecConfigure =>\n (b) => {\n const withArgs = args.length === 0 ? b : b.args([...args])\n const withCwd = request.cwd === undefined ? withArgs : withArgs.cwd(request.cwd)\n const withEnv =\n request.env === undefined\n ? withCwd\n : Record.reduce(request.env, withCwd, (acc, v, k) => acc.env(k, v))\n const withTimeout =\n request.timeout === undefined\n ? withEnv\n : withEnv.timeout(Duration.toMillis(Duration.fromInputUnsafe(request.timeout)))\n if (request.stdin === undefined) return withTimeout\n if (stdinIsStream(request.stdin)) return withTimeout.stdinPipe()\n return withTimeout.stdinBytes(toBuffer(request.stdin))\n }\n\n// ---------------------------------------------------------------------------\n// Stream stdin → SDK `ExecSink`. Takes the writer once, pumps each\n// chunk via `sink.write(Buffer)`, closes on stream completion. Errors\n// from the SDK side (sink already taken / closed / process exited\n// mid-stream) are mapped through {@link mapExecError}. Caller forks\n// this against a `Scope` so the pump dies with the spawn.\n// ---------------------------------------------------------------------------\n\nconst feedStreamStdin = (\n handle: MsbExecHandle,\n stream: Stream.Stream<Uint8Array, never, never>,\n): Effect.Effect<void, SandboxError.SandboxError> =>\n Effect.tryPromise({\n try: () => handle.takeStdin(),\n catch: mapExecError,\n }).pipe(\n Effect.flatMap((sink) =>\n sink === null\n ? Effect.fail(\n new SandboxError.SandboxInvalidRequest({\n provider: PROVIDER,\n param: \"stdin\",\n reason: \"stdin sink already taken — the SDK exposes it once per spawn\",\n }),\n )\n : Stream.runForEach(stream, (chunk) =>\n Effect.tryPromise({\n try: () => sink.write(Buffer.from(chunk)),\n catch: mapExecError,\n }),\n ).pipe(\n Effect.andThen(\n Effect.tryPromise({\n try: () => sink.close(),\n catch: mapExecError,\n }),\n ),\n ),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// MsbExecEvent → Option<CoreExecEvent>. `started` carries the pid but\n// downstream observers don't need it — drop via `Option.none()`.\n// Duration is precomputed by the caller (Clock-based).\n// ---------------------------------------------------------------------------\n\nconst execEventFromMsb = (event: MsbExecEvent, durationMs: number): Option.Option<CoreExecEvent> =>\n Match.value(event).pipe(\n Match.discriminators(\"kind\")({\n started: () => Option.none<CoreExecEvent>(),\n stdout: ({ data }) => Option.some(CoreExecEvent.Stdout({ chunk: data })),\n stderr: ({ data }) => Option.some(CoreExecEvent.Stderr({ chunk: data })),\n exited: ({ code }) => Option.some(CoreExecEvent.Complete({ exitCode: code, durationMs })),\n }),\n Match.exhaustive,\n )\n\nconst someEvent = Filter.fromPredicateOption((o: Option.Option<CoreExecEvent>) => o)\n\nconst eventStream = (handle: AsyncIterable<MsbExecEvent>, startedAt: number) =>\n Stream.fromAsyncIterable(handle, mapExecError).pipe(\n Stream.mapEffect((event) =>\n Effect.map(Clock.currentTimeMillis, (now) => execEventFromMsb(event, now - startedAt)),\n ),\n Stream.filterMap(someEvent),\n )\n\n// ---------------------------------------------------------------------------\n// Live SandboxInstance adapter.\n// ---------------------------------------------------------------------------\n\nconst adaptInstance = (msb: MsbSandbox): SandboxInstance => {\n const id = SandboxId(msb.name)\n\n const openExecStream = (request: CommonSpawnRequest) =>\n Effect.gen(function* () {\n const { cmd, args } = yield* argv(request.cmd)\n const startedAt = yield* Clock.currentTimeMillis\n // `asyncDispose` alone drops the relay connection but does NOT\n // terminate the guest process — sleep / dev servers / watchers\n // happily keep running. Explicitly kill first; both calls are\n // safe to invoke on an already-exited handle.\n const handle = yield* Effect.acquireRelease(\n Effect.tryPromise({\n try: () => msb.execStreamWith(cmd, execConfigure(args, request)),\n catch: mapExecError,\n }),\n (h) =>\n Effect.tryPromise({\n try: () => h.kill(),\n catch: () => undefined,\n }).pipe(Effect.ignore, Effect.andThen(Effect.promise(() => h[Symbol.asyncDispose]()))),\n )\n // Stream stdin: fork a fiber that drains the user's stream into\n // the SDK's `ExecSink`, closing on completion. Scoped to the\n // caller's scope so it dies if the spawn is interrupted.\n if (stdinIsStream(request.stdin)) {\n yield* Effect.forkScoped(feedStreamStdin(handle, request.stdin))\n }\n return { handle, startedAt }\n })\n\n return {\n id,\n\n exec: (request) =>\n Effect.gen(function* () {\n const { cmd, args } = yield* argv(request.cmd)\n const startedAt = yield* Clock.currentTimeMillis\n const output = yield* Effect.tryPromise({\n try: () => msb.execWith(cmd, execConfigure(args, request)),\n catch: mapExecError,\n })\n const completedAt = yield* Clock.currentTimeMillis\n return {\n exitCode: output.code,\n stdout: output.stdout(),\n stderr: output.stderr(),\n durationMs: completedAt - startedAt,\n } satisfies ExecResult\n }),\n\n execStream: (request) =>\n Stream.unwrap(\n Effect.map(openExecStream(request), ({ handle, startedAt }) =>\n eventStream(handle, startedAt),\n ),\n ),\n\n spawn: (request) =>\n Effect.map(\n openExecStream(request),\n ({ handle, startedAt }): ProcessHandle => ({\n // Microsandbox surfaces pid via the \"started\" event; the\n // handle exposes no sync getter. Surface 0 until it does.\n pid: 0,\n events: eventStream(handle, startedAt),\n kill: Effect.tryPromise({\n try: () => handle.kill(),\n catch: mapExecError,\n }),\n exit: Effect.tryPromise({\n try: () => handle.wait(),\n catch: mapExecError,\n }).pipe(Effect.map((status) => ({ exitCode: status.code }))),\n }),\n ),\n\n files: {\n read: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().read(path),\n catch: mapFsError,\n }),\n write: (path, contents) =>\n Effect.tryPromise({\n try: () => msb.fs().write(path, contents),\n catch: mapFsError,\n }),\n remove: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().remove(path),\n catch: mapFsError,\n }),\n mkdir: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().mkdir(path),\n catch: mapFsError,\n }),\n list: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().list(path),\n catch: mapFsError,\n }).pipe(Effect.map(Arr.map((e) => ({ path: e.path, kind: e.kind })))),\n exists: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().exists(path),\n catch: mapFsError,\n }),\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Service factory\n// ---------------------------------------------------------------------------\n\nconst buildService = (config: MicrosandboxConfig): MicrosandboxSandboxService => {\n const resolveImageStep = imageStep(config.defaultImage)\n\n const acquireSandbox = (request: MicrosandboxCreateRequest, name: string) =>\n Effect.gen(function* () {\n const img = yield* resolveImageStep(request.image)\n\n const steps: ReadonlyArray<Step> = [\n img,\n when(request.cpus, (n) => (b) => b.cpus(n)),\n when(request.memory, (m) => (b) => b.memory(Math.ceil(Memory.toBytes(m) / (1024 * 1024)))),\n when(request.workdir, (p) => (b) => b.workdir(p)),\n when(request.user, (u) => (b) => b.user(u)),\n when(\n request.maxDuration,\n (d) => (b) =>\n b.maxDuration(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(d)) / 1000)),\n ),\n when(\n request.idleTimeout,\n (d) => (b) =>\n b.idleTimeout(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(d)) / 1000)),\n ),\n when(\n request.timeout,\n (t) => (b) =>\n b.maxDuration(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(t)) / 1000)),\n ),\n when(request.env, (env) => (b) => b.envs(env)),\n when(request.network, networkStep),\n ...Arr.map(request.secrets ?? [], secretStep),\n ...Arr.map(request.volumes ?? [], volumeStep),\n replaceStep(request.replace),\n ]\n\n const built = Arr.reduce(steps, MsbSandbox.builder(name), (b, step) => step(b))\n return yield* Effect.tryPromise({\n try: () => (request.detached ? built.createDetached() : built.create()),\n catch: mapCreateError,\n })\n })\n\n // Attach picks the right resume path: `connect()` for an already-\n // running (e.g. detached) sandbox, `startDetached()` for a stopped\n // one. Plain `MsbSandbox.start(id)` rejects on running sandboxes,\n // which breaks the detached-survives-scope-close flow.\n const acquireAttached = (id: SandboxId) =>\n Effect.tryPromise({\n try: () => MsbSandbox.get(id),\n catch: mapLookupError(id),\n }).pipe(\n Effect.flatMap((handle) =>\n Effect.tryPromise({\n try: handle.status === \"running\" ? () => handle.connect() : () => handle.startDetached(),\n catch: mapLookupError(id),\n }),\n ),\n )\n\n return {\n create: (request) =>\n Effect.gen(function* () {\n const token = yield* randomToken\n const name = SandboxId(request.name ?? `eff-uai-${token}`)\n const detached = request.detached === true\n // Detached sandboxes outlive the scope — finalizer skips\n // teardown and the user calls `destroy(id)` explicitly.\n const msb = yield* Effect.acquireRelease(acquireSandbox(request, name), () =>\n detached ? Effect.void : Effect.ignore(destroyById(name)),\n )\n return adaptInstance(msb)\n }),\n\n attach: (id) =>\n Effect.acquireRelease(\n acquireAttached(id),\n // Detach on scope close — do NOT stop.\n () => Effect.void,\n ).pipe(Effect.map(adaptInstance)),\n\n list: Effect.tryPromise({\n try: () => MsbSandbox.list(),\n catch: mapCreateError,\n }).pipe(Effect.map(Arr.map((h): SandboxRef => ({ id: SandboxId(h.name), name: h.name })))),\n\n destroy: destroyById,\n\n snapshots: {\n // Microsandbox requires the source sandbox to be stopped before\n // snapshotting. We must also flush root-FS writes BEFORE stop:\n // SDK 0.4.6's stop path races the guest poweroff and `fs().write`\n // data sitting in page cache never reaches the upper.ext4. Fix\n // landed upstream as microsandbox#746 but isn't released — we\n // call `sync` via exec first. Drop this `flush` step once the\n // SDK is bumped past the fix.\n //\n // `SandboxHandle.snapshot(name)` registers the artifact in the\n // DB index (visible to `Snapshot.list` / `msb snapshot list` /\n // `fromSnapshot(name)`); `Snapshot.builder` skips that, so we\n // go through the handle. The handle's `inner.status` is read at\n // fetch time, so we re-`get` AFTER the stop has settled.\n create: (from, name) =>\n Effect.gen(function* () {\n const token = yield* randomToken\n const snapName = name ?? `eff-uai-snap-${token}`\n yield* Effect.ignore(from.exec({ cmd: [\"sync\"] }))\n yield* killRunning(from.id)\n // Re-`get` per attempt: `SandboxHandle.status` is snapshotted\n // at fetch time, so a stale handle would keep failing even\n // after the DB lands the \"stopped\" status.\n yield* retryOnSettle(\n Effect.tryPromise({\n try: () => MsbSandbox.get(from.id),\n catch: mapLookupError(from.id),\n }).pipe(\n Effect.flatMap((handle) =>\n Effect.tryPromise({\n try: () => handle.snapshot(snapName),\n catch: mapCreateError,\n }),\n ),\n ),\n )\n return SnapshotId(snapName)\n }),\n destroy: (sid) =>\n Effect.tryPromise({\n try: () => MsbSnapshot.get(sid),\n catch: mapLookupError(sid),\n }).pipe(\n Effect.flatMap((h) =>\n Effect.tryPromise({\n try: () => h.remove(),\n catch: mapLookupError(sid),\n }),\n ),\n ),\n list: Effect.tryPromise({\n try: () => MsbSnapshot.list(),\n catch: mapCreateError,\n }).pipe(\n Effect.map(\n Arr.filterMap((h) =>\n h.name === null\n ? Result.failVoid\n : Result.succeed({ id: SnapshotId(h.name), name: h.name }),\n ),\n ),\n ),\n },\n\n volumes: {\n create: (name, options) => {\n const builder = MsbVolume.builder(name)\n const sized =\n options?.quotaBytes === undefined\n ? builder\n : builder.quota(Math.ceil(options.quotaBytes / (1024 * 1024)))\n return Effect.tryPromise({\n try: () => sized.create(),\n catch: mapCreateError,\n }).pipe(Effect.map((vol) => VolumeId(vol.name)))\n },\n destroy: (vid) =>\n Effect.tryPromise({\n try: () => MsbVolume.remove(vid),\n catch: mapLookupError(vid),\n }),\n list: Effect.tryPromise({\n try: () => MsbVolume.list(),\n catch: mapCreateError,\n }).pipe(Effect.map(Arr.map((h) => ({ id: VolumeId(h.name), name: h.name })))),\n },\n\n ports: {\n // Defensive stub. The Layer doesn't ship `SandboxPortExposure`,\n // so the free helper `Sandbox.exposePort` is a compile error\n // against this provider. This stub only fires if a caller\n // bypassed the marker and reached into `s.ports.expose` directly.\n expose: () =>\n Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"ports.expose\",\n reason:\n \"microsandbox forwards guest ports to host ports at create time via the per-provider request; runtime port exposure is not supported\",\n }),\n ),\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Layer\n// ---------------------------------------------------------------------------\n\n/**\n * Layer that registers the Microsandbox adapter against the `Sandbox`\n * tag, with the capability markers Microsandbox actually supports.\n *\n * Shipped:\n * - {@link SandboxHostnameAllowlist} — `allowDomain` rules at the\n * policy layer (TLS-edge inspection / DNS filtering).\n * - {@link SandboxSecretInjection} — `.secret(...)` placeholder\n * substitution; the real value never enters the guest.\n * - {@link SandboxSnapshots} — `Snapshot.builder(sourceSandbox)`.\n * - {@link SandboxVolumes} — `Volume.builder(name)`.\n *\n * NOT shipped (calling those helpers fails at compile time):\n * - `SandboxPauseResume` — microsandbox's `stop()` + `Sandbox.start(name)`\n * resumes a previously stopped sandbox from disk, but RAM/process\n * state is lost. That's different semantics from E2B-style\n * memory-preserving pause/resume which `SandboxPauseResume` is\n * meant to denote.\n * - `SandboxCustomImage` — accepts OCI registry refs only.\n * - `SandboxPortExposure` — ports are forwarded at create time via the\n * per-provider request; runtime `exposePort` is unavailable.\n * - `SandboxKernelSession`, `SandboxPty` — no Jupyter/REPL/PTY.\n */\n// Row-D guard: reject `BoundSecret.header` when callers route through\n// the generic `Sandbox.create` surface (the typed `MicrosandboxSandbox`\n// surface omits the field at the type level — row B). Microsandbox's\n// secret API doesn't accept arbitrary headers; silently dropping would\n// produce wrong outbound auth, so we fail loudly.\nconst rejectCustomHeader = (\n secrets: CommonCreateRequest[\"secrets\"],\n): Effect.Effect<void, SandboxError.SandboxError> =>\n secrets === undefined || !secrets.some((s) => s.header !== undefined)\n ? Effect.void\n : Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"BoundSecret.header\",\n reason:\n \"microsandbox always injects secrets as `Authorization: Bearer <value>` — custom headers aren't supported. Use the narrowed `MicrosandboxSandbox.create` surface, which omits this field.\",\n }),\n )\n\nconst upcastService = (s: MicrosandboxSandboxService): SandboxService => ({\n ...s,\n create: (request) =>\n rejectCustomHeader(request.secrets).pipe(\n Effect.andThen(s.create(request as MicrosandboxCreateRequest)),\n ),\n})\n\nexport const layer = (config: MicrosandboxConfig = {}) => {\n const service = buildService(config)\n return Layer.mergeAll(\n Layer.succeed(MicrosandboxSandbox, service),\n Layer.succeed(CoreSandbox, upcastService(service)),\n Layer.succeed(SandboxHostnameAllowlist, undefined),\n Layer.succeed(SandboxSecretInjection, undefined),\n Layer.succeed(SandboxSnapshots, undefined),\n Layer.succeed(SandboxVolumes, undefined),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MicrosandboxSandbox.mjs","names":["MsbSandbox","Arr","CoreExecEvent","MsbSnapshot","MsbVolume","CoreSandbox"],"sources":["../src/MicrosandboxSandbox.ts"],"sourcesContent":["import {\n ExecEvent as CoreExecEvent,\n Sandbox as CoreSandbox,\n SandboxHostnameAllowlist,\n SandboxSecretInjection,\n SandboxSnapshots,\n SandboxVolumes,\n type BoundSecret,\n type CommonCreateRequest,\n type CommonExecRequest,\n type ExecResult,\n type ImageRef,\n type NetworkPolicy,\n type CommonSpawnRequest,\n type ProcessHandle,\n SandboxId,\n type SandboxInstance,\n type SandboxRef,\n type SandboxService,\n SnapshotId,\n VolumeId,\n} from \"@effect-uai/core/Sandbox\"\nimport * as SandboxError from \"@effect-uai/core/SandboxError\"\nimport * as Memory from \"@effect-uai/core/Memory\"\nimport {\n Array as Arr,\n Clock,\n Context,\n Duration,\n Effect,\n Filter,\n Layer,\n Match,\n Option,\n Random,\n Record,\n Redacted,\n Result,\n Schedule,\n Scope,\n Stream,\n} from \"effect\"\nimport {\n type ExecHandle as MsbExecHandle,\n ExecTimeoutError,\n NetworkPolicyBuilder,\n Sandbox as MsbSandbox,\n SandboxNotFoundError,\n SandboxStillRunningError,\n Snapshot as MsbSnapshot,\n Volume as MsbVolume,\n type ExecEvent as MsbExecEvent,\n type SandboxBuilder as MsbSandboxBuilder,\n} from \"microsandbox\"\n\nconst PROVIDER = \"microsandbox\"\n\n// ---------------------------------------------------------------------------\n// Provider-narrowed request types.\n//\n// Microsandbox's secret-injection wire only supports the default\n// `Authorization: Bearer <value>` header convention — there's no\n// per-secret custom header. We omit `header` on the typed surface\n// (row B / type-level narrowing); calls via the generic `Sandbox.create`\n// surface that set `header` are rejected at runtime (row D\n// `SandboxUnsupported`) — see the upcast adapter in `layer`.\n// ---------------------------------------------------------------------------\n\nexport type MicrosandboxBoundSecret = Omit<BoundSecret, \"header\">\n\nexport type MicrosandboxCreateRequest = Omit<CommonCreateRequest, \"secrets\"> & {\n readonly secrets?: ReadonlyArray<MicrosandboxBoundSecret>\n readonly name?: string\n readonly cpus?: number\n /**\n * Memory size. Accepts a byte count, a {@link Memory.Memory}, or a\n * human string like `\"1 GiB\"` / `\"512 MiB\"`. Rounded up to whole\n * MiB at the SDK boundary (microsandbox's builder takes MiB).\n */\n readonly memory?: Memory.Input\n readonly workdir?: string\n readonly user?: string\n readonly maxDuration?: Duration.Input\n readonly idleTimeout?: Duration.Input\n /**\n * Stop any existing sandbox with the same name before creating.\n * `true` = `SIGTERM` with the SDK default grace; `{ graceMs }` =\n * explicit grace before `SIGKILL`.\n */\n readonly replace?: boolean | { readonly graceMs: number }\n /**\n * Detach so the sandbox outlives the calling scope. The scope\n * finalizer skips destroy; clean up via {@link Sandbox.destroy}.\n */\n readonly detached?: boolean\n}\n\nexport type MicrosandboxConfig = {\n /** Default OCI image to use when no `image` is supplied on create. */\n readonly defaultImage?: string\n}\n\n/**\n * Microsandbox-narrowed service. `create` accepts the narrowed\n * {@link MicrosandboxCreateRequest}; every other method is identical\n * to the generic {@link SandboxService}.\n */\nexport type MicrosandboxSandboxService = Omit<SandboxService, \"create\"> & {\n readonly create: (\n request: MicrosandboxCreateRequest,\n ) => Effect.Effect<SandboxInstance, SandboxError.SandboxError, Scope.Scope>\n}\n\nexport class MicrosandboxSandbox extends Context.Service<\n MicrosandboxSandbox,\n MicrosandboxSandboxService\n>()(\"@betalyra/effect-uai/providers/microsandbox/MicrosandboxSandbox\") {}\n\n// ---------------------------------------------------------------------------\n// Effect-native primitives\n// ---------------------------------------------------------------------------\n\n/** Random base-36 token, ~8 chars. Stand-in for `Math.random` IDs. */\nconst randomToken = Random.next.pipe(Effect.map((r) => r.toString(36).slice(2, 10)))\n\n// ---------------------------------------------------------------------------\n// Error mapping\n// ---------------------------------------------------------------------------\n\nconst reasonOf = (e: unknown) => (e instanceof Error ? { reason: e.message } : {})\n\nconst mapCreateError = (e: unknown): SandboxError.SandboxError =>\n e instanceof SandboxStillRunningError\n ? new SandboxError.SandboxAlreadyExists({\n provider: PROVIDER,\n id: e.message,\n })\n : e instanceof SandboxNotFoundError\n ? new SandboxError.SandboxNotFound({ provider: PROVIDER, id: e.message })\n : new SandboxError.SandboxCreateFailed({\n provider: PROVIDER,\n raw: e,\n ...reasonOf(e),\n })\n\nconst mapExecError = (e: unknown): SandboxError.SandboxError =>\n e instanceof ExecTimeoutError\n ? new SandboxError.SandboxTimeout({\n provider: PROVIDER,\n operation: \"exec\",\n raw: e,\n })\n : new SandboxError.SandboxExecFailed({\n provider: PROVIDER,\n raw: e,\n ...reasonOf(e),\n })\n\nconst mapFsError = (e: unknown): SandboxError.SandboxError =>\n new SandboxError.SandboxExecFailed({\n provider: PROVIDER,\n raw: e,\n ...reasonOf(e),\n })\n\nconst mapLookupError =\n (id: string) =>\n (e: unknown): SandboxError.SandboxError =>\n e instanceof SandboxNotFoundError\n ? new SandboxError.SandboxNotFound({ provider: PROVIDER, id })\n : mapCreateError(e)\n\n// ---------------------------------------------------------------------------\n// Stopping & post-kill DB sync.\n//\n// Empirically (spike + SDK 0.4.6; not re-verified on 0.6.x):\n// - `handle.connect()` + `live.stopAndWait()` resolves in 0ms on a\n// non-owning connection — the VM keeps running. Useless.\n// - `handle.kill()` signals the runtime to terminate, but the DB row's\n// `status` field only flips to \"stopped\" ~200ms later. Operations\n// that re-read DB status (`MsbSandbox.remove`, `handle.snapshot`)\n// reject during that window with a \"still running\" error.\n//\n// Rather than a fixed sleep (which over- and under-shoots), we kill\n// then retry the next operation on the transient race with exponential\n// backoff. Typical recovery: 1–3 retries (~50–350ms). Budget is 5\n// attempts ≈ 50+100+200+400+800 = 1.55s — plenty of margin for a\n// loaded host.\n// ---------------------------------------------------------------------------\n\nconst settleSchedule = Schedule.exponential(\"50 millis\")\nconst SETTLE_RETRIES = 5\n\n/**\n * Microsandbox's post-kill DB sync window surfaces as \"still running\"\n * either via `SandboxStillRunningError` (mapped to `SandboxAlreadyExists`\n * by {@link mapCreateError}) or, for `handle.snapshot`, a generic\n * `MicrosandboxError` whose message contains \"is not stopped\" /\n * \"still running\" (mapped to `SandboxCreateFailed`).\n */\nconst isPostKillRace = (e: SandboxError.SandboxError) =>\n e._tag === \"SandboxAlreadyExists\" ||\n (e._tag === \"SandboxCreateFailed\" &&\n typeof e.reason === \"string\" &&\n /still running|is not stopped/i.test(e.reason))\n\nconst retryOnSettle = <A, R>(\n effect: Effect.Effect<A, SandboxError.SandboxError, R>,\n): Effect.Effect<A, SandboxError.SandboxError, R> =>\n Effect.retry(effect, {\n schedule: settleSchedule,\n times: SETTLE_RETRIES,\n while: isPostKillRace,\n })\n\n/** Force-kill a running sandbox. No-op if absent or already stopped. */\nconst killRunning = (id: string) =>\n Effect.tryPromise({\n try: () => MsbSandbox.get(id),\n catch: mapLookupError(id),\n }).pipe(\n Effect.flatMap((handle) =>\n handle.status === \"running\"\n ? Effect.tryPromise({\n try: () => handle.kill(),\n catch: mapLookupError(id),\n })\n : Effect.void,\n ),\n Effect.catchTag(\"SandboxNotFound\", () => Effect.void),\n )\n\n/** Stop + remove. Idempotent — `SandboxNotFound` is treated as success. */\nconst destroyById = (id: SandboxId) =>\n killRunning(id).pipe(\n Effect.andThen(\n retryOnSettle(\n Effect.tryPromise({\n try: () => MsbSandbox.remove(id),\n catch: mapLookupError(id),\n }),\n ),\n ),\n Effect.catchTag(\"SandboxNotFound\", () => Effect.void),\n )\n\n// ---------------------------------------------------------------------------\n// Builder pipeline — a `Step` is a pure builder→builder transformation.\n// The create flow folds an array of Steps through the initial builder.\n// ---------------------------------------------------------------------------\n\ntype Step = (b: MsbSandboxBuilder) => MsbSandboxBuilder\n\nconst noop: Step = (b) => b\n\nconst when = <A>(value: A | undefined, step: (a: A) => Step): Step =>\n value === undefined ? noop : step(value)\n\n// ---------------------------------------------------------------------------\n// ImageRef → Step. Snapshots / registry honored; Default falls through\n// to the layer's `defaultImage`; Dockerfile is unsupported.\n// ---------------------------------------------------------------------------\n\nconst imageStep =\n (defaultImage: string | undefined) =>\n (image: ImageRef | undefined): Effect.Effect<Step, SandboxError.SandboxError> => {\n const fromDefault: Effect.Effect<Step, SandboxError.SandboxError> =\n defaultImage === undefined\n ? Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"image\",\n reason:\n \"microsandbox requires an image — pass `image` on the request or set `defaultImage` on the layer config\",\n }),\n )\n : Effect.succeed((b) => b.image(defaultImage))\n\n if (image === undefined) return fromDefault\n\n return Match.value(image).pipe(\n Match.tag(\"Default\", () => fromDefault),\n Match.tag(\"Registry\", ({ ref }): Effect.Effect<Step, SandboxError.SandboxError> =>\n Effect.succeed((b) => b.image(ref)),\n ),\n Match.tag(\"Snapshot\", ({ id }): Effect.Effect<Step, SandboxError.SandboxError> =>\n Effect.succeed((b) => b.fromSnapshot(id)),\n ),\n Match.tag(\"Dockerfile\", (): Effect.Effect<Step, SandboxError.SandboxError> =>\n Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"image\",\n reason: \"microsandbox accepts OCI registry refs or snapshots, not Dockerfiles\",\n }),\n ),\n ),\n Match.exhaustive,\n )\n }\n\n// ---------------------------------------------------------------------------\n// NetworkPolicy → Step. CIDRs and hostnames both honored.\n// ---------------------------------------------------------------------------\n\nconst buildPolicy = (hosts: ReadonlyArray<string>, cidrs: ReadonlyArray<string>) => {\n const withHosts = Arr.reduce(hosts, new NetworkPolicyBuilder().defaultDeny(), (pb, host) =>\n pb.rule((rb) => rb.egress().allowDomain(host)),\n )\n return Arr.reduce(cidrs, withHosts, (pb, cidr) =>\n pb.rule((rb) => rb.egress().allow((d) => d.cidr(cidr))),\n )\n}\n\nconst networkStep = (policy: NetworkPolicy): Step =>\n Match.value(policy).pipe(\n Match.tag(\"Open\", (): Step => noop),\n Match.tag(\"Blocked\", (): Step => (b) => b.disableNetwork()),\n Match.tag(\n \"Allowlist\",\n ({ hosts, cidrs }): Step =>\n (b) =>\n b.network((n) => n.policyFromBuilder(buildPolicy(hosts ?? [], cidrs ?? []))),\n ),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// Secret / volume / replace Steps. Each item folds into its own Step;\n// the create pipeline reduces them through the builder.\n// ---------------------------------------------------------------------------\n\nconst secretStep =\n (secret: {\n readonly name: string\n readonly value: Redacted.Redacted<string>\n readonly hosts: ReadonlyArray<string>\n }): Step =>\n (b) =>\n b.secret((sb) =>\n Arr.reduce(\n secret.hosts,\n sb.env(secret.name).value(Redacted.value(secret.value)),\n (acc, host) => acc.allowHost(host),\n ).injectHeaders(true),\n )\n\nconst volumeStep =\n (vol: { readonly id: VolumeId; readonly mountPath: string; readonly readonly?: boolean }): Step =>\n (b) =>\n b.volume(vol.mountPath, (m) => (vol.readonly ? m.named(vol.id).readonly() : m.named(vol.id)))\n\nconst replaceStep = (replace: MicrosandboxCreateRequest[\"replace\"]): Step =>\n replace === true\n ? (b) => b.replace()\n : typeof replace === \"object\"\n ? (b) => b.replaceWithTimeout(replace.graceMs)\n : noop\n\n// ---------------------------------------------------------------------------\n// argv splitter — string is run via shell semantics by the SDK, array\n// is direct argv. Empty argv is a typed error.\n// ---------------------------------------------------------------------------\n\nconst argv = (\n cmd: CommonExecRequest[\"cmd\"],\n): Effect.Effect<\n { readonly cmd: string; readonly args: ReadonlyArray<string> },\n SandboxError.SandboxError\n> =>\n typeof cmd === \"string\"\n ? Effect.succeed({ cmd, args: [] as ReadonlyArray<string> })\n : Option.match(Arr.head(cmd), {\n onNone: () =>\n Effect.fail(\n new SandboxError.SandboxInvalidRequest({\n provider: PROVIDER,\n param: \"cmd\",\n reason: \"argv array must be non-empty\",\n }),\n ),\n onSome: (head) => Effect.succeed({ cmd: head, args: Arr.drop(cmd, 1) }),\n })\n\n// ---------------------------------------------------------------------------\n// CommonExecRequest → ExecOptionsBuilder configurator.\n// ---------------------------------------------------------------------------\n\ntype ExecConfigure = Parameters<MsbSandbox[\"execWith\"]>[1]\n\nconst toBuffer = (input: Uint8Array | string) =>\n typeof input === \"string\" ? Buffer.from(input, \"utf-8\") : Buffer.from(input)\n\n/**\n * `string` / `Uint8Array` stdin uses one-shot `stdinBytes`; a Stream\n * uses `stdinPipe` and gets fed via `feedStdin` once the handle is open.\n */\nconst stdinIsStream = (\n stdin: CommonSpawnRequest[\"stdin\"],\n): stdin is Stream.Stream<Uint8Array, never, never> =>\n stdin !== undefined && typeof stdin !== \"string\" && !(stdin instanceof Uint8Array)\n\nconst execConfigure =\n (args: ReadonlyArray<string>, request: CommonSpawnRequest): ExecConfigure =>\n (b) => {\n const withArgs = args.length === 0 ? b : b.args([...args])\n const withCwd = request.cwd === undefined ? withArgs : withArgs.cwd(request.cwd)\n const withEnv =\n request.env === undefined\n ? withCwd\n : Record.reduce(request.env, withCwd, (acc, v, k) => acc.env(k, v))\n const withTimeout =\n request.timeout === undefined\n ? withEnv\n : withEnv.timeout(Duration.toMillis(Duration.fromInputUnsafe(request.timeout)))\n if (request.stdin === undefined) return withTimeout\n if (stdinIsStream(request.stdin)) return withTimeout.stdinPipe()\n return withTimeout.stdinBytes(toBuffer(request.stdin))\n }\n\n// ---------------------------------------------------------------------------\n// Stream stdin → SDK `ExecSink`. Takes the writer once, pumps each\n// chunk via `sink.write(Buffer)`, closes on stream completion. Errors\n// from the SDK side (sink already taken / closed / process exited\n// mid-stream) are mapped through {@link mapExecError}. Caller forks\n// this against a `Scope` so the pump dies with the spawn.\n// ---------------------------------------------------------------------------\n\nconst feedStreamStdin = (\n handle: MsbExecHandle,\n stream: Stream.Stream<Uint8Array, never, never>,\n): Effect.Effect<void, SandboxError.SandboxError> =>\n Effect.tryPromise({\n try: () => handle.takeStdin(),\n catch: mapExecError,\n }).pipe(\n Effect.flatMap((sink) =>\n sink === null\n ? Effect.fail(\n new SandboxError.SandboxInvalidRequest({\n provider: PROVIDER,\n param: \"stdin\",\n reason: \"stdin sink already taken — the SDK exposes it once per spawn\",\n }),\n )\n : Stream.runForEach(stream, (chunk) =>\n Effect.tryPromise({\n try: () => sink.write(Buffer.from(chunk)),\n catch: mapExecError,\n }),\n ).pipe(\n Effect.andThen(\n Effect.tryPromise({\n try: () => sink.close(),\n catch: mapExecError,\n }),\n ),\n ),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// MsbExecEvent → Option<CoreExecEvent>. `started` carries the pid but\n// downstream observers don't need it — drop via `Option.none()`.\n// Duration is precomputed by the caller (Clock-based).\n// ---------------------------------------------------------------------------\n\nconst execEventFromMsb = (event: MsbExecEvent, durationMs: number): Option.Option<CoreExecEvent> =>\n Match.value(event).pipe(\n Match.discriminators(\"kind\")({\n started: () => Option.none<CoreExecEvent>(),\n stdout: ({ data }) => Option.some(CoreExecEvent.Stdout({ chunk: data })),\n stderr: ({ data }) => Option.some(CoreExecEvent.Stderr({ chunk: data })),\n exited: ({ code }) => Option.some(CoreExecEvent.Complete({ exitCode: code, durationMs })),\n }),\n Match.exhaustive,\n )\n\nconst someEvent = Filter.fromPredicateOption((o: Option.Option<CoreExecEvent>) => o)\n\nconst eventStream = (handle: AsyncIterable<MsbExecEvent>, startedAt: number) =>\n Stream.fromAsyncIterable(handle, mapExecError).pipe(\n Stream.mapEffect((event) =>\n Effect.map(Clock.currentTimeMillis, (now) => execEventFromMsb(event, now - startedAt)),\n ),\n Stream.filterMap(someEvent),\n )\n\n// ---------------------------------------------------------------------------\n// Live SandboxInstance adapter.\n// ---------------------------------------------------------------------------\n\nconst adaptInstance = (msb: MsbSandbox): SandboxInstance => {\n const id = SandboxId(msb.name)\n\n const openExecStream = (request: CommonSpawnRequest) =>\n Effect.gen(function* () {\n const { cmd, args } = yield* argv(request.cmd)\n const startedAt = yield* Clock.currentTimeMillis\n // `asyncDispose` alone drops the relay connection but does NOT\n // terminate the guest process — sleep / dev servers / watchers\n // happily keep running. Explicitly kill first; both calls are\n // safe to invoke on an already-exited handle.\n const handle = yield* Effect.acquireRelease(\n Effect.tryPromise({\n try: () => msb.execStreamWith(cmd, execConfigure(args, request)),\n catch: mapExecError,\n }),\n (h) =>\n Effect.tryPromise({\n try: () => h.kill(),\n catch: () => undefined,\n }).pipe(Effect.ignore, Effect.andThen(Effect.promise(() => h[Symbol.asyncDispose]()))),\n )\n // Stream stdin: fork a fiber that drains the user's stream into\n // the SDK's `ExecSink`, closing on completion. Scoped to the\n // caller's scope so it dies if the spawn is interrupted.\n if (stdinIsStream(request.stdin)) {\n yield* Effect.forkScoped(feedStreamStdin(handle, request.stdin))\n }\n return { handle, startedAt }\n })\n\n return {\n id,\n\n exec: (request) =>\n Effect.gen(function* () {\n const { cmd, args } = yield* argv(request.cmd)\n const startedAt = yield* Clock.currentTimeMillis\n const output = yield* Effect.tryPromise({\n try: () => msb.execWith(cmd, execConfigure(args, request)),\n catch: mapExecError,\n })\n const completedAt = yield* Clock.currentTimeMillis\n return {\n exitCode: output.code,\n stdout: output.stdout(),\n stderr: output.stderr(),\n durationMs: completedAt - startedAt,\n } satisfies ExecResult\n }),\n\n execStream: (request) =>\n Stream.unwrap(\n Effect.map(openExecStream(request), ({ handle, startedAt }) =>\n eventStream(handle, startedAt),\n ),\n ),\n\n spawn: (request) =>\n Effect.map(openExecStream(request), ({ handle, startedAt }): ProcessHandle => ({\n // Microsandbox surfaces pid via the \"started\" event; the\n // handle exposes no sync getter. Surface 0 until it does.\n pid: 0,\n events: eventStream(handle, startedAt),\n kill: Effect.tryPromise({\n try: () => handle.kill(),\n catch: mapExecError,\n }),\n exit: Effect.tryPromise({\n try: () => handle.wait(),\n catch: mapExecError,\n }).pipe(Effect.map((status) => ({ exitCode: status.code }))),\n })),\n\n files: {\n read: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().read(path),\n catch: mapFsError,\n }),\n write: (path, contents) =>\n Effect.tryPromise({\n try: () => msb.fs().write(path, contents),\n catch: mapFsError,\n }),\n remove: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().remove(path),\n catch: mapFsError,\n }),\n mkdir: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().mkdir(path),\n catch: mapFsError,\n }),\n list: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().list(path),\n catch: mapFsError,\n }).pipe(Effect.map(Arr.map((e) => ({ path: e.path, kind: e.kind })))),\n exists: (path) =>\n Effect.tryPromise({\n try: () => msb.fs().exists(path),\n catch: mapFsError,\n }),\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Service factory\n// ---------------------------------------------------------------------------\n\nconst buildService = (config: MicrosandboxConfig): MicrosandboxSandboxService => {\n const resolveImageStep = imageStep(config.defaultImage)\n\n const acquireSandbox = (request: MicrosandboxCreateRequest, name: string) =>\n Effect.gen(function* () {\n const img = yield* resolveImageStep(request.image)\n\n const steps: ReadonlyArray<Step> = [\n img,\n when(request.cpus, (n) => (b) => b.cpus(n)),\n when(request.memory, (m) => (b) => b.memory(Math.ceil(Memory.toBytes(m) / (1024 * 1024)))),\n when(request.workdir, (p) => (b) => b.workdir(p)),\n when(request.user, (u) => (b) => b.user(u)),\n when(\n request.maxDuration,\n (d) => (b) =>\n b.maxDuration(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(d)) / 1000)),\n ),\n when(\n request.idleTimeout,\n (d) => (b) =>\n b.idleTimeout(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(d)) / 1000)),\n ),\n when(\n request.timeout,\n (t) => (b) =>\n b.maxDuration(Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(t)) / 1000)),\n ),\n when(request.env, (env) => (b) => b.envs(env)),\n when(request.network, networkStep),\n ...Arr.map(request.secrets ?? [], secretStep),\n ...Arr.map(request.volumes ?? [], volumeStep),\n replaceStep(request.replace),\n ]\n\n const built = Arr.reduce(steps, MsbSandbox.builder(name), (b, step) => step(b))\n return yield* Effect.tryPromise({\n try: () => (request.detached ? built.detached(true) : built).create(),\n catch: mapCreateError,\n })\n })\n\n // Attach picks the right resume path: `connect()` for an already-\n // running (e.g. detached) sandbox, `startDetached()` for a stopped\n // one. Plain `MsbSandbox.start(id)` rejects on running sandboxes,\n // which breaks the detached-survives-scope-close flow.\n const acquireAttached = (id: SandboxId) =>\n Effect.tryPromise({\n try: () => MsbSandbox.get(id),\n catch: mapLookupError(id),\n }).pipe(\n Effect.flatMap((handle) =>\n Effect.tryPromise({\n try: handle.status === \"running\" ? () => handle.connect() : () => handle.startDetached(),\n catch: mapLookupError(id),\n }),\n ),\n )\n\n return {\n create: (request) =>\n Effect.gen(function* () {\n const token = yield* randomToken\n const name = SandboxId(request.name ?? `eff-uai-${token}`)\n const detached = request.detached === true\n // Detached sandboxes outlive the scope — finalizer skips\n // teardown and the user calls `destroy(id)` explicitly.\n const msb = yield* Effect.acquireRelease(acquireSandbox(request, name), () =>\n detached ? Effect.void : Effect.ignore(destroyById(name)),\n )\n return adaptInstance(msb)\n }),\n\n attach: (id) =>\n Effect.acquireRelease(\n acquireAttached(id),\n // Detach on scope close — do NOT stop.\n () => Effect.void,\n ).pipe(Effect.map(adaptInstance)),\n\n // `list()` is paginated from 0.6 on; walk the cursor so the\n // service contract stays \"every visible sandbox\".\n list: Effect.gen(function* () {\n const refs: Array<SandboxRef> = []\n let cursor: string | undefined\n while (true) {\n const page = yield* Effect.tryPromise({\n try: () =>\n cursor === undefined\n ? MsbSandbox.list()\n : MsbSandbox.listWith((l) => l.cursor(cursor as string)),\n catch: mapCreateError,\n })\n refs.push(\n ...Arr.map(page.sandboxes, (h): SandboxRef => ({ id: SandboxId(h.name), name: h.name })),\n )\n if (page.nextCursor === undefined) return refs\n cursor = page.nextCursor\n }\n }),\n\n destroy: destroyById,\n\n snapshots: {\n // Microsandbox requires the source sandbox to be stopped before\n // snapshotting. We must also flush root-FS writes BEFORE stop:\n // SDK 0.4.6's stop path races the guest poweroff and `fs().write`\n // data sitting in page cache never reaches the upper.ext4, so we\n // call `sync` via exec first. The upstream fix (microsandbox#746)\n // should be in 0.6.x; drop this `flush` step once a live snapshot\n // run confirms it.\n //\n // `SandboxHandle.snapshot(name)` registers the artifact in the\n // DB index (visible to `Snapshot.list` / `msb snapshot list` /\n // `fromSnapshot(name)`); `Snapshot.builder` skips that, so we\n // go through the handle. The handle's `inner.status` is read at\n // fetch time, so we re-`get` AFTER the stop has settled.\n create: (from, name) =>\n Effect.gen(function* () {\n const token = yield* randomToken\n const snapName = name ?? `eff-uai-snap-${token}`\n yield* Effect.ignore(from.exec({ cmd: [\"sync\"] }))\n yield* killRunning(from.id)\n // Re-`get` per attempt: `SandboxHandle.status` is snapshotted\n // at fetch time, so a stale handle would keep failing even\n // after the DB lands the \"stopped\" status.\n yield* retryOnSettle(\n Effect.tryPromise({\n try: () => MsbSandbox.get(from.id),\n catch: mapLookupError(from.id),\n }).pipe(\n Effect.flatMap((handle) =>\n Effect.tryPromise({\n try: () => handle.snapshot(snapName),\n catch: mapCreateError,\n }),\n ),\n ),\n )\n return SnapshotId(snapName)\n }),\n destroy: (sid) =>\n Effect.tryPromise({\n try: () => MsbSnapshot.get(sid),\n catch: mapLookupError(sid),\n }).pipe(\n Effect.flatMap((h) =>\n Effect.tryPromise({\n try: () => h.remove(),\n catch: mapLookupError(sid),\n }),\n ),\n ),\n list: Effect.tryPromise({\n try: () => MsbSnapshot.list(),\n catch: mapCreateError,\n }).pipe(\n Effect.map(\n Arr.filterMap((h) =>\n h.name === null\n ? Result.failVoid\n : Result.succeed({ id: SnapshotId(h.name), name: h.name }),\n ),\n ),\n ),\n },\n\n volumes: {\n create: (name, options) => {\n const builder = MsbVolume.builder(name)\n const sized =\n options?.quotaBytes === undefined\n ? builder\n : builder.quota(Math.ceil(options.quotaBytes / (1024 * 1024)))\n return Effect.tryPromise({\n try: () => sized.create(),\n catch: mapCreateError,\n }).pipe(Effect.map((vol) => VolumeId(vol.name)))\n },\n destroy: (vid) =>\n Effect.tryPromise({\n try: () => MsbVolume.remove(vid),\n catch: mapLookupError(vid),\n }),\n list: Effect.tryPromise({\n try: () => MsbVolume.list(),\n catch: mapCreateError,\n }).pipe(Effect.map(Arr.map((h) => ({ id: VolumeId(h.name), name: h.name })))),\n },\n\n ports: {\n // Defensive stub. The Layer doesn't ship `SandboxPortExposure`,\n // so the free helper `Sandbox.exposePort` is a compile error\n // against this provider. This stub only fires if a caller\n // bypassed the marker and reached into `s.ports.expose` directly.\n expose: () =>\n Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"ports.expose\",\n reason:\n \"microsandbox forwards guest ports to host ports at create time via the per-provider request; runtime port exposure is not supported\",\n }),\n ),\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Layer\n// ---------------------------------------------------------------------------\n\n/**\n * Layer that registers the Microsandbox adapter against the `Sandbox`\n * tag, with the capability markers Microsandbox actually supports.\n *\n * Shipped:\n * - {@link SandboxHostnameAllowlist} — `allowDomain` rules at the\n * policy layer (TLS-edge inspection / DNS filtering).\n * - {@link SandboxSecretInjection} — `.secret(...)` placeholder\n * substitution; the real value never enters the guest.\n * - {@link SandboxSnapshots} — `Snapshot.builder(sourceSandbox)`.\n * - {@link SandboxVolumes} — `Volume.builder(name)`.\n *\n * NOT shipped (calling those helpers fails at compile time):\n * - `SandboxPauseResume` — microsandbox's `stop()` + `Sandbox.start(name)`\n * resumes a previously stopped sandbox from disk, but RAM/process\n * state is lost. That's different semantics from E2B-style\n * memory-preserving pause/resume which `SandboxPauseResume` is\n * meant to denote.\n * - `SandboxCustomImage` — accepts OCI registry refs only.\n * - `SandboxPortExposure` — ports are forwarded at create time via the\n * per-provider request; runtime `exposePort` is unavailable.\n * - `SandboxKernelSession`, `SandboxPty` — no Jupyter/REPL/PTY.\n */\n// Row-D guard: reject `BoundSecret.header` when callers route through\n// the generic `Sandbox.create` surface (the typed `MicrosandboxSandbox`\n// surface omits the field at the type level — row B). Microsandbox's\n// secret API doesn't accept arbitrary headers; silently dropping would\n// produce wrong outbound auth, so we fail loudly.\nconst rejectCustomHeader = (\n secrets: CommonCreateRequest[\"secrets\"],\n): Effect.Effect<void, SandboxError.SandboxError> =>\n secrets === undefined || !secrets.some((s) => s.header !== undefined)\n ? Effect.void\n : Effect.fail(\n new SandboxError.SandboxUnsupported({\n provider: PROVIDER,\n capability: \"BoundSecret.header\",\n reason:\n \"microsandbox always injects secrets as `Authorization: Bearer <value>` — custom headers aren't supported. Use the narrowed `MicrosandboxSandbox.create` surface, which omits this field.\",\n }),\n )\n\nconst upcastService = (s: MicrosandboxSandboxService): SandboxService => ({\n ...s,\n create: (request) =>\n rejectCustomHeader(request.secrets).pipe(\n Effect.andThen(s.create(request as MicrosandboxCreateRequest)),\n ),\n})\n\nexport const layer = (config: MicrosandboxConfig = {}) => {\n const service = buildService(config)\n return Layer.mergeAll(\n Layer.succeed(MicrosandboxSandbox, service),\n Layer.succeed(CoreSandbox, upcastService(service)),\n Layer.succeed(SandboxHostnameAllowlist, undefined),\n Layer.succeed(SandboxSecretInjection, undefined),\n Layer.succeed(SandboxSnapshots, undefined),\n Layer.succeed(SandboxVolumes, undefined),\n )\n}\n"],"mappings":";;;;;;;;;;;AAuDA,MAAM,WAAW;AA0DjB,IAAa,sBAAb,cAAyC,QAAQ,QAG/C,CAAC,CAAC,iEAAiE,CAAC,CAAC,CAAC;;AAOxE,MAAM,cAAc,OAAO,KAAK,KAAK,OAAO,KAAK,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAMnF,MAAM,YAAY,MAAgB,aAAa,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI,CAAC;AAEhF,MAAM,kBAAkB,MACtB,aAAa,2BACT,IAAI,aAAa,qBAAqB;CACpC,UAAU;CACV,IAAI,EAAE;AACR,CAAC,IACD,aAAa,uBACX,IAAI,aAAa,gBAAgB;CAAE,UAAU;CAAU,IAAI,EAAE;AAAQ,CAAC,IACtE,IAAI,aAAa,oBAAoB;CACnC,UAAU;CACV,KAAK;CACL,GAAG,SAAS,CAAC;AACf,CAAC;AAET,MAAM,gBAAgB,MACpB,aAAa,mBACT,IAAI,aAAa,eAAe;CAC9B,UAAU;CACV,WAAW;CACX,KAAK;AACP,CAAC,IACD,IAAI,aAAa,kBAAkB;CACjC,UAAU;CACV,KAAK;CACL,GAAG,SAAS,CAAC;AACf,CAAC;AAEP,MAAM,cAAc,MAClB,IAAI,aAAa,kBAAkB;CACjC,UAAU;CACV,KAAK;CACL,GAAG,SAAS,CAAC;AACf,CAAC;AAEH,MAAM,kBACH,QACA,MACC,aAAa,uBACT,IAAI,aAAa,gBAAgB;CAAE,UAAU;CAAU;AAAG,CAAC,IAC3D,eAAe,CAAC;AAoBxB,MAAM,iBAAiB,SAAS,YAAY,WAAW;AACvD,MAAM,iBAAiB;;;;;;;;AASvB,MAAM,kBAAkB,MACtB,EAAE,SAAS,0BACV,EAAE,SAAS,yBACV,OAAO,EAAE,WAAW,YACpB,gCAAgC,KAAK,EAAE,MAAM;AAEjD,MAAM,iBACJ,WAEA,OAAO,MAAM,QAAQ;CACnB,UAAU;CACV,OAAO;CACP,OAAO;AACT,CAAC;;AAGH,MAAM,eAAe,OACnB,OAAO,WAAW;CAChB,WAAWA,UAAW,IAAI,EAAE;CAC5B,OAAO,eAAe,EAAE;AAC1B,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,WACd,OAAO,WAAW,YACd,OAAO,WAAW;CAChB,WAAW,OAAO,KAAK;CACvB,OAAO,eAAe,EAAE;AAC1B,CAAC,IACD,OAAO,IACb,GACA,OAAO,SAAS,yBAAyB,OAAO,IAAI,CACtD;;AAGF,MAAM,eAAe,OACnB,YAAY,EAAE,CAAC,CAAC,KACd,OAAO,QACL,cACE,OAAO,WAAW;CAChB,WAAWA,UAAW,OAAO,EAAE;CAC/B,OAAO,eAAe,EAAE;AAC1B,CAAC,CACH,CACF,GACA,OAAO,SAAS,yBAAyB,OAAO,IAAI,CACtD;AASF,MAAM,QAAc,MAAM;AAE1B,MAAM,QAAW,OAAsB,SACrC,UAAU,KAAA,IAAY,OAAO,KAAK,KAAK;AAOzC,MAAM,aACH,kBACA,UAAgF;CAC/E,MAAM,cACJ,iBAAiB,KAAA,IACb,OAAO,KACL,IAAI,aAAa,mBAAmB;EAClC,UAAU;EACV,YAAY;EACZ,QACE;CACJ,CAAC,CACH,IACA,OAAO,SAAS,MAAM,EAAE,MAAM,YAAY,CAAC;CAEjD,IAAI,UAAU,KAAA,GAAW,OAAO;CAEhC,OAAO,MAAM,MAAM,KAAK,CAAC,CAAC,KACxB,MAAM,IAAI,iBAAiB,WAAW,GACtC,MAAM,IAAI,aAAa,EAAE,UACvB,OAAO,SAAS,MAAM,EAAE,MAAM,GAAG,CAAC,CACpC,GACA,MAAM,IAAI,aAAa,EAAE,SACvB,OAAO,SAAS,MAAM,EAAE,aAAa,EAAE,CAAC,CAC1C,GACA,MAAM,IAAI,oBACR,OAAO,KACL,IAAI,aAAa,mBAAmB;EAClC,UAAU;EACV,YAAY;EACZ,QAAQ;CACV,CAAC,CACH,CACF,GACA,MAAM,UACR;AACF;AAMF,MAAM,eAAe,OAA8B,UAAiC;CAClF,MAAM,YAAYC,MAAI,OAAO,OAAO,IAAI,qBAAqB,CAAC,CAAC,YAAY,IAAI,IAAI,SACjF,GAAG,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,YAAY,IAAI,CAAC,CAC/C;CACA,OAAOA,MAAI,OAAO,OAAO,YAAY,IAAI,SACvC,GAAG,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,OAAO,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC,CACxD;AACF;AAEA,MAAM,eAAe,WACnB,MAAM,MAAM,MAAM,CAAC,CAAC,KAClB,MAAM,IAAI,cAAoB,IAAI,GAClC,MAAM,IAAI,kBAAwB,MAAM,EAAE,eAAe,CAAC,GAC1D,MAAM,IACJ,cACC,EAAE,OAAO,aACP,MACC,EAAE,SAAS,MAAM,EAAE,kBAAkB,YAAY,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CACjF,GACA,MAAM,UACR;AAOF,MAAM,cACH,YAKA,MACC,EAAE,QAAQ,OACRA,MAAI,OACF,OAAO,OACP,GAAG,IAAI,OAAO,IAAI,CAAC,CAAC,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,IACrD,KAAK,SAAS,IAAI,UAAU,IAAI,CACnC,CAAC,CAAC,cAAc,IAAI,CACtB;AAEJ,MAAM,cACH,SACA,MACC,EAAE,OAAO,IAAI,YAAY,MAAO,IAAI,WAAW,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE,MAAM,IAAI,EAAE,CAAE;AAEhG,MAAM,eAAe,YACnB,YAAY,QACP,MAAM,EAAE,QAAQ,IACjB,OAAO,YAAY,YAChB,MAAM,EAAE,mBAAmB,QAAQ,OAAO,IAC3C;AAOR,MAAM,QACJ,QAKA,OAAO,QAAQ,WACX,OAAO,QAAQ;CAAE;CAAK,MAAM,CAAC;AAA2B,CAAC,IACzD,OAAO,MAAMA,MAAI,KAAK,GAAG,GAAG;CAC1B,cACE,OAAO,KACL,IAAI,aAAa,sBAAsB;EACrC,UAAU;EACV,OAAO;EACP,QAAQ;CACV,CAAC,CACH;CACF,SAAS,SAAS,OAAO,QAAQ;EAAE,KAAK;EAAM,MAAMA,MAAI,KAAK,KAAK,CAAC;CAAE,CAAC;AACxE,CAAC;AAQP,MAAM,YAAY,UAChB,OAAO,UAAU,WAAW,OAAO,KAAK,OAAO,OAAO,IAAI,OAAO,KAAK,KAAK;;;;;AAM7E,MAAM,iBACJ,UAEA,UAAU,KAAA,KAAa,OAAO,UAAU,YAAY,EAAE,iBAAiB;AAEzE,MAAM,iBACH,MAA6B,aAC7B,MAAM;CACL,MAAM,WAAW,KAAK,WAAW,IAAI,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CACzD,MAAM,UAAU,QAAQ,QAAQ,KAAA,IAAY,WAAW,SAAS,IAAI,QAAQ,GAAG;CAC/E,MAAM,UACJ,QAAQ,QAAQ,KAAA,IACZ,UACA,OAAO,OAAO,QAAQ,KAAK,UAAU,KAAK,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC;CACtE,MAAM,cACJ,QAAQ,YAAY,KAAA,IAChB,UACA,QAAQ,QAAQ,SAAS,SAAS,SAAS,gBAAgB,QAAQ,OAAO,CAAC,CAAC;CAClF,IAAI,QAAQ,UAAU,KAAA,GAAW,OAAO;CACxC,IAAI,cAAc,QAAQ,KAAK,GAAG,OAAO,YAAY,UAAU;CAC/D,OAAO,YAAY,WAAW,SAAS,QAAQ,KAAK,CAAC;AACvD;AAUF,MAAM,mBACJ,QACA,WAEA,OAAO,WAAW;CAChB,WAAW,OAAO,UAAU;CAC5B,OAAO;AACT,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,SACd,SAAS,OACL,OAAO,KACL,IAAI,aAAa,sBAAsB;CACrC,UAAU;CACV,OAAO;CACP,QAAQ;AACV,CAAC,CACH,IACA,OAAO,WAAW,SAAS,UACzB,OAAO,WAAW;CAChB,WAAW,KAAK,MAAM,OAAO,KAAK,KAAK,CAAC;CACxC,OAAO;AACT,CAAC,CACH,CAAC,CAAC,KACA,OAAO,QACL,OAAO,WAAW;CAChB,WAAW,KAAK,MAAM;CACtB,OAAO;AACT,CAAC,CACH,CACF,CACN,CACF;AAQF,MAAM,oBAAoB,OAAqB,eAC7C,MAAM,MAAM,KAAK,CAAC,CAAC,KACjB,MAAM,eAAe,MAAM,CAAC,CAAC;CAC3B,eAAe,OAAO,KAAoB;CAC1C,SAAS,EAAE,WAAW,OAAO,KAAKC,UAAc,OAAO,EAAE,OAAO,KAAK,CAAC,CAAC;CACvE,SAAS,EAAE,WAAW,OAAO,KAAKA,UAAc,OAAO,EAAE,OAAO,KAAK,CAAC,CAAC;CACvE,SAAS,EAAE,WAAW,OAAO,KAAKA,UAAc,SAAS;EAAE,UAAU;EAAM;CAAW,CAAC,CAAC;AAC1F,CAAC,GACD,MAAM,UACR;AAEF,MAAM,YAAY,OAAO,qBAAqB,MAAoC,CAAC;AAEnF,MAAM,eAAe,QAAqC,cACxD,OAAO,kBAAkB,QAAQ,YAAY,CAAC,CAAC,KAC7C,OAAO,WAAW,UAChB,OAAO,IAAI,MAAM,oBAAoB,QAAQ,iBAAiB,OAAO,MAAM,SAAS,CAAC,CACvF,GACA,OAAO,UAAU,SAAS,CAC5B;AAMF,MAAM,iBAAiB,QAAqC;CAC1D,MAAM,KAAK,UAAU,IAAI,IAAI;CAE7B,MAAM,kBAAkB,YACtB,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,KAAK,SAAS,OAAO,KAAK,QAAQ,GAAG;EAC7C,MAAM,YAAY,OAAO,MAAM;EAK/B,MAAM,SAAS,OAAO,OAAO,eAC3B,OAAO,WAAW;GAChB,WAAW,IAAI,eAAe,KAAK,cAAc,MAAM,OAAO,CAAC;GAC/D,OAAO;EACT,CAAC,IACA,MACC,OAAO,WAAW;GAChB,WAAW,EAAE,KAAK;GAClB,aAAa,KAAA;EACf,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,OAAO,QAAQ,OAAO,cAAc,EAAE,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,CACzF;EAIA,IAAI,cAAc,QAAQ,KAAK,GAC7B,OAAO,OAAO,WAAW,gBAAgB,QAAQ,QAAQ,KAAK,CAAC;EAEjE,OAAO;GAAE;GAAQ;EAAU;CAC7B,CAAC;CAEH,OAAO;EACL;EAEA,OAAO,YACL,OAAO,IAAI,aAAa;GACtB,MAAM,EAAE,KAAK,SAAS,OAAO,KAAK,QAAQ,GAAG;GAC7C,MAAM,YAAY,OAAO,MAAM;GAC/B,MAAM,SAAS,OAAO,OAAO,WAAW;IACtC,WAAW,IAAI,SAAS,KAAK,cAAc,MAAM,OAAO,CAAC;IACzD,OAAO;GACT,CAAC;GACD,MAAM,cAAc,OAAO,MAAM;GACjC,OAAO;IACL,UAAU,OAAO;IACjB,QAAQ,OAAO,OAAO;IACtB,QAAQ,OAAO,OAAO;IACtB,YAAY,cAAc;GAC5B;EACF,CAAC;EAEH,aAAa,YACX,OAAO,OACL,OAAO,IAAI,eAAe,OAAO,IAAI,EAAE,QAAQ,gBAC7C,YAAY,QAAQ,SAAS,CAC/B,CACF;EAEF,QAAQ,YACN,OAAO,IAAI,eAAe,OAAO,IAAI,EAAE,QAAQ,iBAAgC;GAG7E,KAAK;GACL,QAAQ,YAAY,QAAQ,SAAS;GACrC,MAAM,OAAO,WAAW;IACtB,WAAW,OAAO,KAAK;IACvB,OAAO;GACT,CAAC;GACD,MAAM,OAAO,WAAW;IACtB,WAAW,OAAO,KAAK;IACvB,OAAO;GACT,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,YAAY,EAAE,UAAU,OAAO,KAAK,EAAE,CAAC;EAC7D,EAAE;EAEJ,OAAO;GACL,OAAO,SACL,OAAO,WAAW;IAChB,WAAW,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI;IAC7B,OAAO;GACT,CAAC;GACH,QAAQ,MAAM,aACZ,OAAO,WAAW;IAChB,WAAW,IAAI,GAAG,CAAC,CAAC,MAAM,MAAM,QAAQ;IACxC,OAAO;GACT,CAAC;GACH,SAAS,SACP,OAAO,WAAW;IAChB,WAAW,IAAI,GAAG,CAAC,CAAC,OAAO,IAAI;IAC/B,OAAO;GACT,CAAC;GACH,QAAQ,SACN,OAAO,WAAW;IAChB,WAAW,IAAI,GAAG,CAAC,CAAC,MAAM,IAAI;IAC9B,OAAO;GACT,CAAC;GACH,OAAO,SACL,OAAO,WAAW;IAChB,WAAW,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI;IAC7B,OAAO;GACT,CAAC,CAAC,CAAC,KAAK,OAAO,IAAID,MAAI,KAAK,OAAO;IAAE,MAAM,EAAE;IAAM,MAAM,EAAE;GAAK,EAAE,CAAC,CAAC;GACtE,SAAS,SACP,OAAO,WAAW;IAChB,WAAW,IAAI,GAAG,CAAC,CAAC,OAAO,IAAI;IAC/B,OAAO;GACT,CAAC;EACL;CACF;AACF;AAMA,MAAM,gBAAgB,WAA2D;CAC/E,MAAM,mBAAmB,UAAU,OAAO,YAAY;CAEtD,MAAM,kBAAkB,SAAoC,SAC1D,OAAO,IAAI,aAAa;EAGtB,MAAM,QAA6B;GACjC,OAHiB,iBAAiB,QAAQ,KAAK;GAI/C,KAAK,QAAQ,OAAO,OAAO,MAAM,EAAE,KAAK,CAAC,CAAC;GAC1C,KAAK,QAAQ,SAAS,OAAO,MAAM,EAAE,OAAO,KAAK,KAAK,OAAO,QAAQ,CAAC,IAAK,OAAY,CAAC,CAAC;GACzF,KAAK,QAAQ,UAAU,OAAO,MAAM,EAAE,QAAQ,CAAC,CAAC;GAChD,KAAK,QAAQ,OAAO,OAAO,MAAM,EAAE,KAAK,CAAC,CAAC;GAC1C,KACE,QAAQ,cACP,OAAO,MACN,EAAE,YAAY,KAAK,KAAK,SAAS,SAAS,SAAS,gBAAgB,CAAC,CAAC,IAAI,GAAI,CAAC,CAClF;GACA,KACE,QAAQ,cACP,OAAO,MACN,EAAE,YAAY,KAAK,KAAK,SAAS,SAAS,SAAS,gBAAgB,CAAC,CAAC,IAAI,GAAI,CAAC,CAClF;GACA,KACE,QAAQ,UACP,OAAO,MACN,EAAE,YAAY,KAAK,KAAK,SAAS,SAAS,SAAS,gBAAgB,CAAC,CAAC,IAAI,GAAI,CAAC,CAClF;GACA,KAAK,QAAQ,MAAM,SAAS,MAAM,EAAE,KAAK,GAAG,CAAC;GAC7C,KAAK,QAAQ,SAAS,WAAW;GACjC,GAAGA,MAAI,IAAI,QAAQ,WAAW,CAAC,GAAG,UAAU;GAC5C,GAAGA,MAAI,IAAI,QAAQ,WAAW,CAAC,GAAG,UAAU;GAC5C,YAAY,QAAQ,OAAO;EAC7B;EAEA,MAAM,QAAQA,MAAI,OAAO,OAAOD,UAAW,QAAQ,IAAI,IAAI,GAAG,SAAS,KAAK,CAAC,CAAC;EAC9E,OAAO,OAAO,OAAO,WAAW;GAC9B,YAAY,QAAQ,WAAW,MAAM,SAAS,IAAI,IAAI,MAAA,CAAO,OAAO;GACpE,OAAO;EACT,CAAC;CACH,CAAC;CAMH,MAAM,mBAAmB,OACvB,OAAO,WAAW;EAChB,WAAWA,UAAW,IAAI,EAAE;EAC5B,OAAO,eAAe,EAAE;CAC1B,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,WACd,OAAO,WAAW;EAChB,KAAK,OAAO,WAAW,kBAAkB,OAAO,QAAQ,UAAU,OAAO,cAAc;EACvF,OAAO,eAAe,EAAE;CAC1B,CAAC,CACH,CACF;CAEF,OAAO;EACL,SAAS,YACP,OAAO,IAAI,aAAa;GACtB,MAAM,QAAQ,OAAO;GACrB,MAAM,OAAO,UAAU,QAAQ,QAAQ,WAAW,OAAO;GACzD,MAAM,WAAW,QAAQ,aAAa;GAGtC,MAAM,MAAM,OAAO,OAAO,eAAe,eAAe,SAAS,IAAI,SACnE,WAAW,OAAO,OAAO,OAAO,OAAO,YAAY,IAAI,CAAC,CAC1D;GACA,OAAO,cAAc,GAAG;EAC1B,CAAC;EAEH,SAAS,OACP,OAAO,eACL,gBAAgB,EAAE,SAEZ,OAAO,IACf,CAAC,CAAC,KAAK,OAAO,IAAI,aAAa,CAAC;EAIlC,MAAM,OAAO,IAAI,aAAa;GAC5B,MAAM,OAA0B,CAAC;GACjC,IAAI;GACJ,OAAO,MAAM;IACX,MAAM,OAAO,OAAO,OAAO,WAAW;KACpC,WACE,WAAW,KAAA,IACPA,UAAW,KAAK,IAChBA,UAAW,UAAU,MAAM,EAAE,OAAO,MAAgB,CAAC;KAC3D,OAAO;IACT,CAAC;IACD,KAAK,KACH,GAAGC,MAAI,IAAI,KAAK,YAAY,OAAmB;KAAE,IAAI,UAAU,EAAE,IAAI;KAAG,MAAM,EAAE;IAAK,EAAE,CACzF;IACA,IAAI,KAAK,eAAe,KAAA,GAAW,OAAO;IAC1C,SAAS,KAAK;GAChB;EACF,CAAC;EAED,SAAS;EAET,WAAW;GAcT,SAAS,MAAM,SACb,OAAO,IAAI,aAAa;IACtB,MAAM,QAAQ,OAAO;IACrB,MAAM,WAAW,QAAQ,gBAAgB;IACzC,OAAO,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,OAAO,YAAY,KAAK,EAAE;IAI1B,OAAO,cACL,OAAO,WAAW;KAChB,WAAWD,UAAW,IAAI,KAAK,EAAE;KACjC,OAAO,eAAe,KAAK,EAAE;IAC/B,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,WACd,OAAO,WAAW;KAChB,WAAW,OAAO,SAAS,QAAQ;KACnC,OAAO;IACT,CAAC,CACH,CACF,CACF;IACA,OAAO,WAAW,QAAQ;GAC5B,CAAC;GACH,UAAU,QACR,OAAO,WAAW;IAChB,WAAWG,SAAY,IAAI,GAAG;IAC9B,OAAO,eAAe,GAAG;GAC3B,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,MACd,OAAO,WAAW;IAChB,WAAW,EAAE,OAAO;IACpB,OAAO,eAAe,GAAG;GAC3B,CAAC,CACH,CACF;GACF,MAAM,OAAO,WAAW;IACtB,WAAWA,SAAY,KAAK;IAC5B,OAAO;GACT,CAAC,CAAC,CAAC,KACD,OAAO,IACLF,MAAI,WAAW,MACb,EAAE,SAAS,OACP,OAAO,WACP,OAAO,QAAQ;IAAE,IAAI,WAAW,EAAE,IAAI;IAAG,MAAM,EAAE;GAAK,CAAC,CAC7D,CACF,CACF;EACF;EAEA,SAAS;GACP,SAAS,MAAM,YAAY;IACzB,MAAM,UAAUG,OAAU,QAAQ,IAAI;IACtC,MAAM,QACJ,SAAS,eAAe,KAAA,IACpB,UACA,QAAQ,MAAM,KAAK,KAAK,QAAQ,aAAc,OAAY,CAAC;IACjE,OAAO,OAAO,WAAW;KACvB,WAAW,MAAM,OAAO;KACxB,OAAO;IACT,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,QAAQ,SAAS,IAAI,IAAI,CAAC,CAAC;GACjD;GACA,UAAU,QACR,OAAO,WAAW;IAChB,WAAWA,OAAU,OAAO,GAAG;IAC/B,OAAO,eAAe,GAAG;GAC3B,CAAC;GACH,MAAM,OAAO,WAAW;IACtB,WAAWA,OAAU,KAAK;IAC1B,OAAO;GACT,CAAC,CAAC,CAAC,KAAK,OAAO,IAAIH,MAAI,KAAK,OAAO;IAAE,IAAI,SAAS,EAAE,IAAI;IAAG,MAAM,EAAE;GAAK,EAAE,CAAC,CAAC;EAC9E;EAEA,OAAO,EAKL,cACE,OAAO,KACL,IAAI,aAAa,mBAAmB;GAClC,UAAU;GACV,YAAY;GACZ,QACE;EACJ,CAAC,CACH,EACJ;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAM,sBACJ,YAEA,YAAY,KAAA,KAAa,CAAC,QAAQ,MAAM,MAAM,EAAE,WAAW,KAAA,CAAS,IAChE,OAAO,OACP,OAAO,KACL,IAAI,aAAa,mBAAmB;CAClC,UAAU;CACV,YAAY;CACZ,QACE;AACJ,CAAC,CACH;AAEN,MAAM,iBAAiB,OAAmD;CACxE,GAAG;CACH,SAAS,YACP,mBAAmB,QAAQ,OAAO,CAAC,CAAC,KAClC,OAAO,QAAQ,EAAE,OAAO,OAAoC,CAAC,CAC/D;AACJ;AAEA,MAAa,SAAS,SAA6B,CAAC,MAAM;CACxD,MAAM,UAAU,aAAa,MAAM;CACnC,OAAO,MAAM,SACX,MAAM,QAAQ,qBAAqB,OAAO,GAC1C,MAAM,QAAQI,SAAa,cAAc,OAAO,CAAC,GACjD,MAAM,QAAQ,0BAA0B,KAAA,CAAS,GACjD,MAAM,QAAQ,wBAAwB,KAAA,CAAS,GAC/C,MAAM,QAAQ,kBAAkB,KAAA,CAAS,GACzC,MAAM,QAAQ,gBAAgB,KAAA,CAAS,CACzC;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/microsandbox",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "Microsandbox local microVM sandbox provider for @effect-uai/core.",
5
5
  "keywords": [
6
6
  "agents",
@@ -44,15 +44,15 @@
44
44
  "access": "public"
45
45
  },
46
46
  "devDependencies": {
47
- "effect": "4.0.0-beta.94",
48
- "microsandbox": "^0.4.6",
49
- "typescript": "^6.0.3",
50
- "@effect-uai/core": "0.11.0"
47
+ "effect": "4.0.0-rc.111",
48
+ "microsandbox": "^0.6.12",
49
+ "typescript": "^7.0.2",
50
+ "@effect-uai/core": "0.12.1"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@effect-uai/core": ">=0.5.0 <1",
54
- "effect": ">=4.0.0-beta.94 <5.0.0",
55
- "microsandbox": "^0.4.0"
54
+ "effect": ">=4.0.0-rc.111 <5.0.0",
55
+ "microsandbox": "^0.6.0"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsdown",
@@ -173,7 +173,7 @@ const mapLookupError =
173
173
  // ---------------------------------------------------------------------------
174
174
  // Stopping & post-kill DB sync.
175
175
  //
176
- // Empirically (spike + SDK 0.4.6):
176
+ // Empirically (spike + SDK 0.4.6; not re-verified on 0.6.x):
177
177
  // - `handle.connect()` + `live.stopAndWait()` resolves in 0ms on a
178
178
  // non-owning connection — the VM keeps running. Useless.
179
179
  // - `handle.kill()` signals the runtime to terminate, but the DB row's
@@ -280,26 +280,20 @@ const imageStep =
280
280
 
281
281
  return Match.value(image).pipe(
282
282
  Match.tag("Default", () => fromDefault),
283
- Match.tag(
284
- "Registry",
285
- ({ ref }): Effect.Effect<Step, SandboxError.SandboxError> =>
286
- Effect.succeed((b) => b.image(ref)),
283
+ Match.tag("Registry", ({ ref }): Effect.Effect<Step, SandboxError.SandboxError> =>
284
+ Effect.succeed((b) => b.image(ref)),
287
285
  ),
288
- Match.tag(
289
- "Snapshot",
290
- ({ id }): Effect.Effect<Step, SandboxError.SandboxError> =>
291
- Effect.succeed((b) => b.fromSnapshot(id)),
286
+ Match.tag("Snapshot", ({ id }): Effect.Effect<Step, SandboxError.SandboxError> =>
287
+ Effect.succeed((b) => b.fromSnapshot(id)),
292
288
  ),
293
- Match.tag(
294
- "Dockerfile",
295
- (): Effect.Effect<Step, SandboxError.SandboxError> =>
296
- Effect.fail(
297
- new SandboxError.SandboxUnsupported({
298
- provider: PROVIDER,
299
- capability: "image",
300
- reason: "microsandbox accepts OCI registry refs or snapshots, not Dockerfiles",
301
- }),
302
- ),
289
+ Match.tag("Dockerfile", (): Effect.Effect<Step, SandboxError.SandboxError> =>
290
+ Effect.fail(
291
+ new SandboxError.SandboxUnsupported({
292
+ provider: PROVIDER,
293
+ capability: "image",
294
+ reason: "microsandbox accepts OCI registry refs or snapshots, not Dockerfiles",
295
+ }),
296
+ ),
303
297
  ),
304
298
  Match.exhaustive,
305
299
  )
@@ -360,7 +354,7 @@ const replaceStep = (replace: MicrosandboxCreateRequest["replace"]): Step =>
360
354
  replace === true
361
355
  ? (b) => b.replace()
362
356
  : typeof replace === "object"
363
- ? (b) => b.replaceWithGrace(replace.graceMs)
357
+ ? (b) => b.replaceWithTimeout(replace.graceMs)
364
358
  : noop
365
359
 
366
360
  // ---------------------------------------------------------------------------
@@ -555,23 +549,20 @@ const adaptInstance = (msb: MsbSandbox): SandboxInstance => {
555
549
  ),
556
550
 
557
551
  spawn: (request) =>
558
- Effect.map(
559
- openExecStream(request),
560
- ({ handle, startedAt }): ProcessHandle => ({
561
- // Microsandbox surfaces pid via the "started" event; the
562
- // handle exposes no sync getter. Surface 0 until it does.
563
- pid: 0,
564
- events: eventStream(handle, startedAt),
565
- kill: Effect.tryPromise({
566
- try: () => handle.kill(),
567
- catch: mapExecError,
568
- }),
569
- exit: Effect.tryPromise({
570
- try: () => handle.wait(),
571
- catch: mapExecError,
572
- }).pipe(Effect.map((status) => ({ exitCode: status.code }))),
552
+ Effect.map(openExecStream(request), ({ handle, startedAt }): ProcessHandle => ({
553
+ // Microsandbox surfaces pid via the "started" event; the
554
+ // handle exposes no sync getter. Surface 0 until it does.
555
+ pid: 0,
556
+ events: eventStream(handle, startedAt),
557
+ kill: Effect.tryPromise({
558
+ try: () => handle.kill(),
559
+ catch: mapExecError,
573
560
  }),
574
- ),
561
+ exit: Effect.tryPromise({
562
+ try: () => handle.wait(),
563
+ catch: mapExecError,
564
+ }).pipe(Effect.map((status) => ({ exitCode: status.code }))),
565
+ })),
575
566
 
576
567
  files: {
577
568
  read: (path) =>
@@ -649,7 +640,7 @@ const buildService = (config: MicrosandboxConfig): MicrosandboxSandboxService =>
649
640
 
650
641
  const built = Arr.reduce(steps, MsbSandbox.builder(name), (b, step) => step(b))
651
642
  return yield* Effect.tryPromise({
652
- try: () => (request.detached ? built.createDetached() : built.create()),
643
+ try: () => (request.detached ? built.detached(true) : built).create(),
653
644
  catch: mapCreateError,
654
645
  })
655
646
  })
@@ -692,10 +683,26 @@ const buildService = (config: MicrosandboxConfig): MicrosandboxSandboxService =>
692
683
  () => Effect.void,
693
684
  ).pipe(Effect.map(adaptInstance)),
694
685
 
695
- list: Effect.tryPromise({
696
- try: () => MsbSandbox.list(),
697
- catch: mapCreateError,
698
- }).pipe(Effect.map(Arr.map((h): SandboxRef => ({ id: SandboxId(h.name), name: h.name })))),
686
+ // `list()` is paginated from 0.6 on; walk the cursor so the
687
+ // service contract stays "every visible sandbox".
688
+ list: Effect.gen(function* () {
689
+ const refs: Array<SandboxRef> = []
690
+ let cursor: string | undefined
691
+ while (true) {
692
+ const page = yield* Effect.tryPromise({
693
+ try: () =>
694
+ cursor === undefined
695
+ ? MsbSandbox.list()
696
+ : MsbSandbox.listWith((l) => l.cursor(cursor as string)),
697
+ catch: mapCreateError,
698
+ })
699
+ refs.push(
700
+ ...Arr.map(page.sandboxes, (h): SandboxRef => ({ id: SandboxId(h.name), name: h.name })),
701
+ )
702
+ if (page.nextCursor === undefined) return refs
703
+ cursor = page.nextCursor
704
+ }
705
+ }),
699
706
 
700
707
  destroy: destroyById,
701
708
 
@@ -703,10 +710,10 @@ const buildService = (config: MicrosandboxConfig): MicrosandboxSandboxService =>
703
710
  // Microsandbox requires the source sandbox to be stopped before
704
711
  // snapshotting. We must also flush root-FS writes BEFORE stop:
705
712
  // SDK 0.4.6's stop path races the guest poweroff and `fs().write`
706
- // data sitting in page cache never reaches the upper.ext4. Fix
707
- // landed upstream as microsandbox#746 but isn't released — we
708
- // call `sync` via exec first. Drop this `flush` step once the
709
- // SDK is bumped past the fix.
713
+ // data sitting in page cache never reaches the upper.ext4, so we
714
+ // call `sync` via exec first. The upstream fix (microsandbox#746)
715
+ // should be in 0.6.x; drop this `flush` step once a live snapshot
716
+ // run confirms it.
710
717
  //
711
718
  // `SandboxHandle.snapshot(name)` registers the artifact in the
712
719
  // DB index (visible to `Snapshot.list` / `msb snapshot list` /