{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @computesdk/tenki — ComputeSDK provider for Tenki Cloud sandboxes.\n *\n * Usage:\n *   import { tenki } from \"@computesdk/tenki\";\n *   import { compute } from \"computesdk\";\n *\n *   compute.setConfig({\n *     provider: tenki({ apiKey: \"tk_...\" }),\n *   });\n *\n *   const sandbox = await compute.sandbox.create();\n *   const result = await sandbox.runCommand(\"echo hello\");\n *   await sandbox.destroy();\n */\n\nimport { defineProvider, escapeShellArg, resolveVolumeRef, isUnifiedVolumeMounts, withVolumeSettle } from \"@computesdk/provider\";\nimport type { RunCommandOptions, CommandResult, InstanceInfo, CreateInstanceOptions, FileEntry } from \"computesdk\";\nimport {\n  TenkiSandbox,\n  Session,\n  type SessionState,\n  type CreateOptions,\n  type Output,\n  SessionNotFoundError,\n  stdoutText,\n  stderrText,\n} from \"@tenkicloud/sandbox\";\n\nexport interface TenkiConfig {\n  /** Tenki API key (tk_...). Falls back to TENKI_API_KEY / TENKI_AUTH_TOKEN env vars. */\n  apiKey?: string;\n  /** API base URL. Falls back to TENKI_API_URL, then https://api.tenki.cloud. */\n  baseUrl?: string;\n  /** Workspace to create sandboxes in. Falls back to TENKI_WORKSPACE_ID; workspace API keys infer it server-side. */\n  workspaceId?: string;\n  /** @deprecated Tenki no longer scopes sandboxes by project. */\n  projectId?: string;\n  /** Default runCommand timeout in milliseconds. */\n  timeout?: number;\n  /** Default sandbox resources applied at create() time. */\n  cpuCores?: number;\n  memoryMb?: number;\n  diskSizeGb?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Client resolution\n// ---------------------------------------------------------------------------\n\n/**\n * One TenkiSandbox client per (token, baseUrl) pair. The client owns a gRPC\n * transport, so we memoize rather than reconnecting on every collection-level\n * call (create/getById/list/destroy).\n */\nconst clients = new Map<string, TenkiSandbox>();\n\nfunction resolveApiKey(config: TenkiConfig): string {\n  const apiKey = config.apiKey ?? process.env.TENKI_API_KEY ?? process.env.TENKI_AUTH_TOKEN;\n  if (!apiKey) {\n    throw new Error(\n      \"Missing API key for Tenki.\\n\\n\" +\n        \"Create one at https://app.tenki.cloud (workspace settings > API Keys)\\n\" +\n        'Then pass it: tenki({ apiKey: \"tk_...\" })\\n' +\n        \"Or set TENKI_API_KEY (or TENKI_AUTH_TOKEN) in your environment.\",\n    );\n  }\n  return apiKey;\n}\n\nfunction clientKey(config: TenkiConfig): string {\n  return `${resolveApiKey(config)}::${config.baseUrl ?? process.env.TENKI_API_URL ?? \"\"}`;\n}\n\nfunction getClient(config: TenkiConfig): TenkiSandbox {\n  const key = clientKey(config);\n  let client = clients.get(key);\n  if (!client) {\n    client = new TenkiSandbox({\n      authToken: resolveApiKey(config),\n      baseUrl: config.baseUrl ?? process.env.TENKI_API_URL,\n    });\n    clients.set(key, client);\n  }\n  return client;\n}\n\n// ---------------------------------------------------------------------------\n// Session bookkeeping\n// ---------------------------------------------------------------------------\n\n/**\n * created_at is on the wire but not yet surfaced by the TS SDK Session, so we\n * record observation time as a best-effort createdAt for getInfo(). Instance\n * methods only receive the sandbox, so exec-time defaults (timeout) are\n * stashed per session as well.\n */\nconst observedAt = new WeakMap<Session, Date>();\nconst sessionConfig = new WeakMap<Session, TenkiConfig>();\n\nfunction rememberSession(session: Session, config: TenkiConfig): Session {\n  if (!observedAt.has(session)) observedAt.set(session, new Date());\n  sessionConfig.set(session, config);\n  return session;\n}\n\nfunction mapStatus(state: SessionState): InstanceInfo[\"status\"] {\n  switch (state) {\n    case \"RUNNING\":\n    case \"CREATING\":\n    case \"RESUMING\":\n      return \"running\";\n    case \"PAUSED\":\n    case \"PAUSING\":\n    case \"USER_SHUTDOWN\":\n    case \"TERMINATING\":\n    case \"TERMINATED\":\n      return \"stopped\";\n    default:\n      return \"error\";\n  }\n}\n\nfunction toCreateOptions(config: TenkiConfig, options?: CreateInstanceOptions): CreateOptions {\n  const opts: CreateOptions = {};\n  const workspaceId = config.workspaceId ?? process.env.TENKI_WORKSPACE_ID;\n  if (workspaceId) opts.workspaceId = workspaceId;\n  if (options?.name) opts.name = options.name;\n  if (options?.envs) opts.env = options.envs;\n  if (options?.metadata) {\n    // Tenki metadata values are strings.\n    opts.metadata = Object.fromEntries(Object.entries(options.metadata).map(([k, v]) => [k, String(v)]));\n  }\n  if (options?.templateId) opts.image = options.templateId;\n  if (options?.snapshotId) opts.snapshotId = options.snapshotId;\n  if (options?.timeout) opts.maxDurationMs = options.timeout;\n\n  // Resources: per-call override (via CreateInstanceOptions' index signature)\n  // wins over provider-level defaults.\n  const cpuCores = (options as Record<string, unknown> | undefined)?.cpuCores ?? config.cpuCores;\n  const memoryMb = (options as Record<string, unknown> | undefined)?.memoryMb ?? config.memoryMb;\n  const diskSizeGb = (options as Record<string, unknown> | undefined)?.diskSizeGb ?? config.diskSizeGb;\n  if (typeof cpuCores === \"number\") opts.cpuCores = cpuCores;\n  if (typeof memoryMb === \"number\") opts.memoryMb = memoryMb;\n  if (typeof diskSizeGb === \"number\") opts.diskSizeGb = diskSizeGb;\n\n  if (isUnifiedVolumeMounts(options?.volumes)) {\n    opts.volumes = options!.volumes!.map((m) => {\n      const ref = resolveVolumeRef(m.volume);\n      return { volumeId: ref.id ?? ref.name!, mountPath: m.mountPath, readOnly: m.readOnly };\n    });\n  }\n\n  return opts;\n}\n\n// ---------------------------------------------------------------------------\n// Command execution\n// ---------------------------------------------------------------------------\n\n/**\n * Treat \"no such sandbox\" uniformly: the API raises SessionNotFoundError for\n * unknown UUIDs, but rejects non-UUID ids with a validation error before the\n * lookup. Either way the id names no session.\n */\nfunction isMissingSession(err: unknown): boolean {\n  if (err instanceof SessionNotFoundError) return true;\n  return err instanceof Error && err.message.includes(\"session_id: value must be a valid UUID\");\n}\n\nfunction shellQuote(value: string): string {\n  return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * Run a command line through a shell. ComputeSDK passes runCommand a full\n * shell command string, whereas Tenki's Session.exec executes argv directly\n * (execve, no shell), so we wrap with `sh -lc`.\n */\nasync function runShell(session: Session, command: string, options?: RunCommandOptions): Promise<CommandResult> {\n  const config = sessionConfig.get(session) ?? {};\n  const line = options?.cwd ? `cd ${shellQuote(options.cwd)} && ${command}` : command;\n\n  if (options?.background) {\n    // Detach stdio so the background process does not hold the exec output\n    // stream open (a bare `&` would keep exec waiting forever).\n    const detached = `{ ${line} ; } >/dev/null 2>&1 </dev/null &`;\n    await session.exec(\"sh\", { args: [\"-lc\", detached], env: options?.env });\n    return { stdout: \"\", stderr: \"\", exitCode: 0, durationMs: 0 };\n  }\n\n  // Persistent streaming decoders so multi-byte UTF-8 sequences split across\n  // chunks are reassembled instead of corrupted.\n  const stdoutDecoder = new TextDecoder();\n  const stderrDecoder = new TextDecoder();\n  const onOutput =\n    options?.onStdout || options?.onStderr\n      ? (out: Output) => {\n          if (out.isStderr) {\n            const text = stderrDecoder.decode(out.data, { stream: true });\n            if (text) options?.onStderr?.(text);\n          } else {\n            const text = stdoutDecoder.decode(out.data, { stream: true });\n            if (text) options?.onStdout?.(text);\n          }\n        }\n      : undefined;\n\n  const result = await session.exec(\"sh\", {\n    args: [\"-lc\", line],\n    timeoutMs: options?.timeout ?? config.timeout,\n    env: options?.env,\n    onOutput,\n  });\n\n  if (onOutput) {\n    // Flush any buffered partial UTF-8 sequence left at stream end.\n    const stdoutTail = stdoutDecoder.decode();\n    if (stdoutTail) options?.onStdout?.(stdoutTail);\n    const stderrTail = stderrDecoder.decode();\n    if (stderrTail) options?.onStderr?.(stderrTail);\n  }\n\n  const timedOut = result.status === \"TIMED_OUT\";\n  const stderr = stderrText(result);\n  return {\n    stdout: stdoutText(result),\n    stderr: timedOut ? [stderr, \"Tenki command timed out.\"].filter(Boolean).join(\"\\n\") : stderr,\n    exitCode: timedOut ? 124 : result.exitCode,\n    durationMs: result.durationMs,\n  };\n}\n\nfunction basename(path: string): string {\n  const trimmed = path.replace(/\\/+$/, \"\");\n  const idx = trimmed.lastIndexOf(\"/\");\n  return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport const tenki = defineProvider<Session, TenkiConfig>({\n  name: \"tenki\",\n  methods: {\n    instances: {\n      create: async (config, options) => {\n        const client = getClient(config);\n        const session = await client.createAndWait(toCreateOptions(config, options));\n        return { instance: rememberSession(session, config), instanceId: session.id };\n      },\n\n      getById: async (config, sandboxId) => {\n        const client = getClient(config);\n        try {\n          const session = await client.get(sandboxId);\n          return { instance: rememberSession(session, config), instanceId: session.id };\n        } catch (err) {\n          if (isMissingSession(err)) return null;\n          throw err;\n        }\n      },\n\n      list: async (config) => {\n        const client = getClient(config);\n        const sessions = await client.list();\n        return sessions.map((session) => ({ instance: rememberSession(session, config), instanceId: session.id,\n        }));\n      },\n\n      destroy: async (config, sandboxId) => {\n        const client = getClient(config);\n        try {\n          const session = await client.get(sandboxId);\n          await session.close();\n        } catch (err) {\n          if (isMissingSession(err)) return; // already gone\n          throw err;\n        }\n      },\n\n      runCommand: (sandbox, command, options) => runShell(sandbox, command, options),\n\n      getInfo: async (sandbox) => {\n        const remaining = sandbox.timeoutAt.getTime() - Date.now();\n        return {\n          id: sandbox.id,\n          provider: \"tenki\",\n          status: mapStatus(sandbox.state),\n          createdAt: observedAt.get(sandbox) ?? new Date(),\n          timeout: remaining > 0 ? remaining : 0,\n          metadata: {\n            name: sandbox.name,\n            state: sandbox.state,\n            cpuCores: sandbox.cpuCores,\n            memoryMb: sandbox.memoryMb,\n            diskSizeGb: sandbox.diskSizeGb,\n            workspaceId: sandbox.workspaceId,\n            tags: sandbox.tags,\n          },\n        };\n      },\n\n      getUrl: async (sandbox, options) => {\n        const exposed = await sandbox.exposePort(options.port);\n        return exposed.previewUrl;\n      },\n\n      getInstance: (sandbox) => sandbox,\n\n      attachVolume: async (sandbox, volume, mountPath) => {\n        const ref = resolveVolumeRef(volume);\n        await (sandbox as Session).attachVolume(ref.id ?? ref.name!, mountPath);\n      },\n      detachVolume: async (sandbox, volume) => {\n        const ref = resolveVolumeRef(volume);\n        await (sandbox as Session).detachVolume(ref.id ?? ref.name!);\n      },\n\n      // Native filesystem: Tenki exposes real file primitives over its data\n      // plane, so we bypass the shell-based fallback (and its escaping\n      // hazards). The runCommand parameter is intentionally unused.\n      filesystem: {\n        readFile: async (sandbox, path) => {\n          const bytes = await sandbox.readFile(path);\n          return new TextDecoder().decode(bytes);\n        },\n        writeFile: async (sandbox, path, content) => {\n          await sandbox.writeFile(path, content);\n        },\n        mkdir: async (sandbox, path) => {\n          await sandbox.mkdir(path);\n        },\n        readdir: async (sandbox, path): Promise<FileEntry[]> => {\n          const entries = await sandbox.list(path);\n          return entries.map((entry) => ({\n            name: basename(entry.path),\n            type: entry.isDir ? (\"directory\" as const) : (\"file\" as const),\n            size: Number(entry.size),\n            modified: new Date(Number(entry.modifiedUnixNs / 1_000_000n)),\n          }));\n        },\n        // exists goes through the shell: the data-plane stat can briefly\n        // report a just-removed file as present, while `test -e` is always\n        // consistent with the guest filesystem.\n        exists: async (sandbox, path, runCommand) => {\n          const result = await runCommand(sandbox, `test -e \"${escapeShellArg(path)}\"`);\n          return result.exitCode === 0;\n        },\n        remove: async (sandbox, path) => {\n          await sandbox.remove(path);\n        },\n      },\n    },\n\n    volume: {\n      create: async (config, options) => {\n        const client = getClient(config);\n        const v = await client.createVolume({\n          name: options.name,\n          sizeBytes: options.sizeBytes ?? 10 * 1024 * 1024 * 1024,\n          ...(config.workspaceId ?? process.env.TENKI_WORKSPACE_ID\n            ? { workspaceId: config.workspaceId ?? process.env.TENKI_WORKSPACE_ID }\n            : {}),\n        });\n        // SYNC_PENDING on a fresh volume is the create-time equivalent of the\n        // attach race the API already reports; wait before handing it back.\n        const ready = await client.waitVolumeReady(v.id);\n        return { id: ready.id, name: ready.name, native: ready };\n      },\n      get: async (config, volumeIdOrName: string) => {\n        const client = getClient(config);\n        try {\n          const v = await client.getVolume(volumeIdOrName);\n          return v ? { id: v.id, name: v.name, native: v } : null;\n        } catch { return null; }\n      },\n      list: async (config) => {\n        const client = getClient(config);\n        const volumes = await client.listVolumes();\n        return (volumes ?? []).map((v) => ({ id: v.id, name: v.name, native: v }));\n      },\n      delete: async (config, volumeIdOrName: string) => {\n        const client = getClient(config);\n        await withVolumeSettle(() => client.deleteVolume(volumeIdOrName));\n      },\n    }\n  },\n});\n\nexport default tenki;\n"],"mappings":"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","names":[]}