{"version":3,"file":"managed-provider-BsZGVQ4I.mjs","names":["managed: ManagedSandboxProvider","ownedTemplate: Promise<TemplateFile[]> | undefined","result: TemplateFile[]"],"sources":["../src/internal/managed-provider.ts"],"sourcesContent":["import { SandboxError } from \"../core/errors\";\nimport type {\n  ManagedSandboxProvider,\n  ManagedSandboxSession,\n  SandboxProvider,\n} from \"../core/provider\";\nimport { createSandbox } from \"../core/sandbox\";\nimport type { Sandbox } from \"../core/types\";\nimport type { SandboxNetworkPolicy } from \"../core/provider\";\n\ntype TemplateFile = { path: string; content: Uint8Array };\n\n/**\n * Shared managed lifecycle for built-in providers. Provider-native implementations\n * can replace this optional surface without changing `createSandbox()`.\n */\nexport function withManagedSessions<TRaw>(\n  provider: SandboxProvider<TRaw>,\n  configuredPorts: ReadonlyArray<number> = [],\n  lifecycle: {\n    stop?: (sandbox: Sandbox<TRaw>) => Promise<void>;\n    resume?: (sandbox: Sandbox<TRaw>) => Promise<void>;\n    destroy?: (sandbox: Sandbox<TRaw>) => Promise<void>;\n    setPorts?: (\n      sandbox: Sandbox<TRaw>,\n      ports: ReadonlyArray<number>,\n      signal?: AbortSignal,\n    ) => Promise<void>;\n    setNetworkPolicy?: (sandbox: Sandbox<TRaw>, policy: SandboxNetworkPolicy) => Promise<void>;\n  } = {},\n): SandboxProvider<TRaw> {\n  const sessions = new Map<string, ManagedSandboxSession>();\n  const templates = new Map<string, Promise<TemplateFile[]>>();\n\n  const managed: ManagedSandboxProvider = {\n    async create(options) {\n      const existing = sessions.get(options.sessionId);\n      if (existing) return existing;\n      const sandbox = await createSandbox({\n        provider,\n        cwd: options.cwd,\n        env: options.env,\n        signal: options.signal,\n      });\n      const ports = new Set([...configuredPorts, ...(options.ports ?? [])]);\n      let ownedTemplate: Promise<TemplateFile[]> | undefined;\n      try {\n        if (options.identity) {\n          let template = templates.get(options.identity);\n          if (!template) {\n            template = (async () => {\n              await options.onFirstCreate?.(sandbox);\n              return captureFiles(sandbox, sandbox.cwd);\n            })();\n            ownedTemplate = template;\n            templates.set(options.identity, template);\n            await template;\n          } else {\n            await restoreFiles(sandbox, await template);\n          }\n        } else {\n          await options.onFirstCreate?.(sandbox);\n        }\n        const session = createManagedSession(\n          options.sessionId,\n          sandbox,\n          ports,\n          sessions,\n          lifecycle,\n        );\n        sessions.set(options.sessionId, session);\n        return session;\n      } catch (error) {\n        if (\n          options.identity &&\n          ownedTemplate &&\n          templates.get(options.identity) === ownedTemplate\n        ) {\n          templates.delete(options.identity);\n        }\n        try {\n          if (lifecycle.destroy) await lifecycle.destroy(sandbox);\n          else await sandbox.stop();\n        } catch (cleanupError) {\n          if (error instanceof Error) {\n            Object.defineProperty(error, \"cleanupError\", {\n              value: cleanupError,\n              enumerable: false,\n            });\n          }\n        }\n        throw error;\n      }\n    },\n    async resume(options) {\n      const session = sessions.get(options.sessionId);\n      if (!session) {\n        throw new SandboxError({\n          code: \"not_found\",\n          provider: provider.id,\n          operation: \"managed.resume\",\n          message: `Managed sandbox session not found: ${options.sessionId}`,\n        });\n      }\n      await session.resume();\n      return session;\n    },\n  };\n  return { ...provider, managed };\n}\n\nfunction createManagedSession<TRaw>(\n  id: string,\n  sandbox: Sandbox<TRaw>,\n  initialPorts: Set<number>,\n  sessions: Map<string, ManagedSandboxSession>,\n  lifecycle: {\n    stop?: (sandbox: Sandbox<TRaw>) => Promise<void>;\n    resume?: (sandbox: Sandbox<TRaw>) => Promise<void>;\n    destroy?: (sandbox: Sandbox<TRaw>) => Promise<void>;\n    setPorts?: (\n      sandbox: Sandbox<TRaw>,\n      ports: ReadonlyArray<number>,\n      signal?: AbortSignal,\n    ) => Promise<void>;\n    setNetworkPolicy?: (sandbox: Sandbox<TRaw>, policy: SandboxNetworkPolicy) => Promise<void>;\n  },\n): ManagedSandboxSession {\n  let destroyed = false;\n  let stopped = false;\n  const assertActive = () => {\n    if (destroyed) {\n      throw new SandboxError({\n        code: \"terminated\",\n        provider: sandbox.provider,\n        operation: \"managed.session\",\n        message: `Managed sandbox session has been destroyed: ${id}`,\n      });\n    }\n  };\n  const session: ManagedSandboxSession = {\n    id,\n    sandbox,\n    defaultWorkingDirectory: sandbox.cwd,\n    get ports() {\n      return [...initialPorts];\n    },\n    async getPortUrl({ port, protocol }) {\n      assertActive();\n      if (!initialPorts.has(port)) {\n        throw new SandboxError({\n          code: \"invalid_input\",\n          provider: sandbox.provider,\n          operation: \"managed.getPortUrl\",\n          message: `Port ${port} is not exposed by this session`,\n        });\n      }\n      const exposed = await sandbox.ports.expose(port);\n      const url = new URL(exposed.url);\n      if (protocol) url.protocol = `${protocol}:`;\n      return url.toString().replace(/\\/$/, \"\");\n    },\n    async stop() {\n      assertActive();\n      if (stopped) return;\n      await lifecycle.stop?.(sandbox);\n      stopped = true;\n    },\n    async resume() {\n      assertActive();\n      if (!stopped) return;\n      await lifecycle.resume?.(sandbox);\n      stopped = false;\n    },\n    async destroy() {\n      if (destroyed) return;\n      destroyed = true;\n      sessions.delete(id);\n      if (lifecycle.destroy) await lifecycle.destroy(sandbox);\n      else await sandbox.stop();\n    },\n    ...(lifecycle.setPorts\n      ? {\n          async setPorts(ports: ReadonlyArray<number>, options?: { signal?: AbortSignal }) {\n            assertActive();\n            await lifecycle.setPorts!(sandbox, ports, options?.signal);\n            initialPorts.clear();\n            for (const port of ports) initialPorts.add(port);\n          },\n        }\n      : {}),\n    ...(lifecycle.setNetworkPolicy\n      ? {\n          setNetworkPolicy: (policy: SandboxNetworkPolicy) => {\n            assertActive();\n            return lifecycle.setNetworkPolicy!(sandbox, policy);\n          },\n        }\n      : {}),\n  };\n  return session;\n}\n\nasync function captureFiles(sandbox: Sandbox, path: string): Promise<TemplateFile[]> {\n  const result: TemplateFile[] = [];\n  for (const entry of await sandbox.files.list(path)) {\n    if (entry.type === \"directory\") result.push(...(await captureFiles(sandbox, entry.path)));\n    else if (entry.type === \"file\")\n      result.push({\n        path: entry.path,\n        content: await sandbox.files.read(entry.path),\n      });\n  }\n  return result;\n}\n\nasync function restoreFiles(sandbox: Sandbox, files: ReadonlyArray<TemplateFile>): Promise<void> {\n  await Promise.all(files.map((file) => sandbox.files.write(file.path, file.content)));\n}\n"],"mappings":"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"}