@mostra/sdk 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +37 -2
- package/dist/bundles.json +31 -0
- package/dist/index.d.ts +366 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +482 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime-HLIV9wFH.js +998 -0
- package/dist/runtime-HLIV9wFH.js.map +1 -0
- package/dist/setup-main.d.ts +1 -0
- package/dist/setup-main.js +49 -0
- package/dist/setup-main.js.map +1 -0
- package/package.json +63 -3
- package/src/bundle/cache.ts +349 -0
- package/src/bundle/download.ts +255 -0
- package/src/bundle/extract.ts +60 -0
- package/src/bundle/setup.ts +278 -0
- package/src/bundle/tree.ts +176 -0
- package/src/events.ts +276 -0
- package/src/index.ts +67 -0
- package/src/mostra.ts +589 -0
- package/src/platform.ts +81 -0
- package/src/runtime.ts +179 -0
- package/src/setup-main.ts +49 -0
- package/src/version.ts +38 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-HLIV9wFH.js","names":["invalid","open","BundleAssetSchema"],"sources":["../src/bundle/download.ts","../src/bundle/extract.ts","../src/bundle/tree.ts","../src/bundle/setup.ts","../src/bundle/cache.ts","../src/platform.ts","../src/version.ts","../src/runtime.ts"],"sourcesContent":["/**\n * Fetching a pinned archive (RT-01): streamed to disk while it is hashed, never longer than the\n * pin says, through the environment's proxy (`HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY`), retried on\n * failures that a retry can cure, and checked against the pin before anyone reads it.\n */\nimport { createHash } from \"node:crypto\";\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { rm } from \"node:fs/promises\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { createDiagnostic, RpcError } from \"@mostra/protocol\";\nimport { EnvHttpProxyAgent, fetch } from \"undici\";\n\n/** What a download must match. */\nexport interface Expected {\n readonly sha256: string;\n readonly size: number;\n}\n\n/** Progress of one download, in bytes. */\nexport interface DownloadProgress {\n /** Bytes received so far. */\n readonly received: number;\n /** Bytes the pin says the archive has. */\n readonly total: number;\n}\n\n/** Options of {@link download}. */\nexport interface DownloadOptions {\n /**\n * The environment whose proxy settings apply (`HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY`, either\n * case): a host's own, never silently `process.env`'s. Default `process.env`.\n */\n readonly env?: Readonly<Record<string, string | undefined>> | undefined;\n readonly signal?: AbortSignal | undefined;\n readonly onProgress?: ((progress: DownloadProgress) => void) | undefined;\n /** How long the connection may stay silent. Default 60 s. */\n readonly stallMs?: number | undefined;\n /** Attempts in all, for failures a retry can cure. Default 3. */\n readonly attempts?: number | undefined;\n}\n\n/** A failure a retry won't cure (an HTTP 4xx other than 408 and 429, a wrong size or digest). */\nclass Final extends Error {}\n\n/**\n * Downloads `url` (`https:`, `http:` or `file:`) to `dest` and checks its size and SHA-256.\n * Throws `MOSTRA_ENV_BUNDLE_INVALID` when the bytes aren't the pinned ones and\n * `MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED` otherwise; `dest` never survives a failure.\n */\nexport async function download(\n url: string,\n dest: string,\n expected: Expected,\n options: DownloadOptions = {},\n): Promise<void> {\n const attempts = options.attempts ?? 3;\n let last: unknown;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n const actual = await once(url, dest, expected, options);\n if (actual !== expected.sha256) {\n throw invalid(\n `The download from ${redactUrl(url)} has SHA-256 ${actual}, not the pinned ${expected.sha256}.`,\n );\n }\n return;\n } catch (error) {\n await rm(dest, { force: true });\n last = error;\n if (error instanceof RpcError || error instanceof Final || options.signal?.aborted) break;\n if ((error as NodeJS.ErrnoException).code === \"ENOSPC\") break;\n if (attempt < attempts) await delay(1000 * 4 ** (attempt - 1), options.signal);\n }\n }\n if (last instanceof RpcError) throw last;\n if (options.signal?.aborted) throw options.signal.reason;\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED\", {\n message: `Couldn't download ${redactUrl(url)}: ${scrubUrls(describe(last))}`,\n }),\n );\n}\n\nasync function once(\n url: string,\n dest: string,\n expected: Expected,\n options: DownloadOptions,\n): Promise<string> {\n const hash = createHash(\"sha256\");\n let received = 0;\n const stallMs = options.stallMs ?? 60_000;\n const controller = new AbortController();\n const abort = (): void => controller.abort(options.signal?.reason);\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const arm = (): void => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(\n () => controller.abort(new Error(`no data for ${stallMs / 1000} s`)),\n stallMs,\n );\n };\n try {\n arm();\n const body = await open(url, controller.signal, options.env ?? process.env);\n const counter = async function* (source: AsyncIterable<Uint8Array>) {\n for await (const chunk of source) {\n arm();\n received += chunk.length;\n if (received > expected.size) {\n throw invalid(\n `The download from ${redactUrl(url)} is larger than the pinned ${expected.size} bytes.`,\n );\n }\n hash.update(chunk);\n options.onProgress?.({ received, total: expected.size });\n yield chunk;\n }\n };\n await pipeline(body, counter, createWriteStream(dest, { mode: 0o600 }), {\n signal: controller.signal,\n });\n if (received !== expected.size) {\n throw invalid(\n `The download from ${redactUrl(url)} has ${received} bytes, not the pinned ${expected.size}.`,\n );\n }\n return hash.digest(\"hex\");\n } catch (error) {\n if (controller.signal.aborted && !(error instanceof RpcError)) {\n const reason: unknown = controller.signal.reason;\n throw reason instanceof Error ? reason : new Error(String(reason));\n }\n throw error;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", abort);\n }\n}\n\n/** The body of `url` as a stream. */\nasync function open(\n url: string,\n signal: AbortSignal,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<AsyncIterable<Uint8Array>> {\n const parsed = new URL(url);\n if (parsed.protocol === \"file:\") {\n return createReadStream(fileURLToPath(parsed), { signal }) as AsyncIterable<Uint8Array>;\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n throw new Final(`${parsed.protocol} URLs aren't supported`);\n }\n // fetch refuses a URL with credentials, so a mirror's (`https://user:pass@host/…`) travel as\n // Basic authorization, which fetch drops on a redirect to another origin.\n const headers: Record<string, string> = {\n \"user-agent\": \"mostra-sdk\",\n accept: \"application/octet-stream\",\n };\n if (parsed.username !== \"\" || parsed.password !== \"\") {\n const user = decodeURIComponent(parsed.username);\n const password = decodeURIComponent(parsed.password);\n headers[\"authorization\"] = `Basic ${Buffer.from(`${user}:${password}`).toString(\"base64\")}`;\n parsed.username = \"\";\n parsed.password = \"\";\n }\n const response = await fetch(parsed, {\n dispatcher: proxyAgent(env),\n redirect: \"follow\",\n signal,\n headers,\n });\n if (!response.ok || response.body === null) {\n const status = response.status;\n await response.body?.cancel().catch(() => undefined);\n const message = `HTTP ${status}${response.statusText ? ` ${response.statusText}` : \"\"}`;\n if (status >= 400 && status < 500 && status !== 408 && status !== 429) throw new Final(message);\n throw new Error(message);\n }\n return Readable.fromWeb(response.body as import(\"node:stream/web\").ReadableStream<Uint8Array>);\n}\n\nconst agents = new Map<string, EnvHttpProxyAgent>();\n/**\n * The agent for `env`'s `HTTPS_PROXY`, `HTTP_PROXY` and `NO_PROXY` (lowercase first, as curl\n * reads them), one per distinct setting. Each is passed explicitly, an empty one included, so\n * undici never falls back to `process.env` (GPT review finding 6).\n */\nfunction proxyAgent(env: Readonly<Record<string, string | undefined>>): EnvHttpProxyAgent {\n const settings = {\n httpProxy: env[\"http_proxy\"] ?? env[\"HTTP_PROXY\"] ?? \"\",\n httpsProxy: env[\"https_proxy\"] ?? env[\"HTTPS_PROXY\"] ?? \"\",\n noProxy: env[\"no_proxy\"] ?? env[\"NO_PROXY\"] ?? \"\",\n };\n const key = JSON.stringify(settings);\n let agent = agents.get(key);\n if (agent === undefined) {\n agent = new EnvHttpProxyAgent(settings);\n agents.set(key, agent);\n }\n return agent;\n}\n\n/**\n * `text` with every URL in it reduced to {@link redactUrl}'s form: an error from the network stack\n * repeats the URL it failed on, credentials, query and all (a mirror's or a proxy's), and a\n * diagnostic is printed (GPT review finding 2).\n */\nexport function scrubUrls(text: string): string {\n return text.replace(/\\b[a-z][a-z0-9+.-]*:\\/\\/[^\\s\"'<>()]+/gi, (url) => redactUrl(url));\n}\n\nfunction invalid(message: string): RpcError {\n return new RpcError(createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", { message }));\n}\n\n/** A URL without credentials or a query, safe to print. */\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.username = \"\";\n parsed.password = \"\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return parsed.toString();\n } catch {\n return \"(an invalid URL)\";\n }\n}\n\nfunction describe(error: unknown): string {\n if (!(error instanceof Error)) return String(error);\n const cause = (error as { cause?: unknown }).cause;\n const code = (cause as { code?: string } | undefined)?.code ?? (error as { code?: string }).code;\n return code !== undefined && !error.message.includes(code)\n ? `${error.message} (${code})`\n : error.message;\n}\n\nfunction delay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n return new Promise((done) => {\n const timer = setTimeout(done, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n done();\n },\n { once: true },\n );\n });\n}\n","/**\n * Unpacking a downloaded archive (RT-01). Only regular files, directories and symbolic links are\n * accepted, all under the archive's one top directory, which is stripped. node-tar refuses\n * absolute paths, `..` and writing through a link; it does create a link whatever its target, so\n * setup then checks the whole tree against the bundle's file list (`checkTree`), which refuses any\n * file or link it doesn't list and any link that leaves the bundle. A pinned archive's SHA-256 is\n * checked before any of this.\n */\nimport { createDiagnostic, RpcError } from \"@mostra/protocol\";\nimport { x } from \"tar\";\n\nconst ACCEPTED = new Set([\"File\", \"OldFile\", \"ContiguousFile\", \"Directory\", \"SymbolicLink\"]);\n\n/** Extracts `archive` (a `.tar.gz` with one top directory `top`) into the empty directory `into`. */\nexport async function extractBundle(archive: string, into: string, top: string): Promise<void> {\n let refused: string | undefined;\n try {\n await x({\n file: archive,\n cwd: into,\n strip: 1,\n strict: true,\n preservePaths: false,\n preserveOwner: false,\n // Owner-only directories are tightened later; files keep their 0644/0755 modes.\n noChmod: false,\n filter: (path, entry) => {\n const type = \"type\" in entry ? String(entry.type) : \"File\";\n const inside = path === `${top}/` || path === top || path.startsWith(`${top}/`);\n if (!inside || !ACCEPTED.has(type)) {\n refused ??= `${path} (${type})`;\n return false;\n }\n return true;\n },\n });\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n // The file system failing (a full disk, a permission) isn't the archive's fault.\n if (typeof code === \"string\" && /^E[A-Z]+$/.test(code) && code !== \"EOF\") {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED\", {\n message: `The runtime bundle couldn't be written to ${into}: ${(error as Error).message}${code === \"ENOSPC\" ? \" (the disk is full)\" : \"\"}`,\n }),\n );\n }\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", {\n message: `The runtime bundle's archive couldn't be read: ${(error as Error).message}`,\n }),\n );\n }\n if (refused !== undefined) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", {\n message: `The runtime bundle's archive holds an entry a bundle never has: ${refused}.`,\n }),\n );\n }\n}\n","/**\n * A bundle's files against its manifest (RT-01): one walk that both writes `files.json` (the\n * assembler) and checks an extracted bundle against it (setup), so the two can't disagree about\n * what counts. Links must stay inside the bundle; nothing may be missing, changed or extra.\n */\nimport { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { lstat, readdir, readlink } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve, sep } from \"node:path\";\nimport type { BundleFileEntry, BundleFiles, BundleLinkEntry } from \"@mostra/protocol\";\n\n/** The SHA-256 and size of one file, read as a stream. */\nexport async function hashFile(path: string): Promise<{ sha256: string; size: number }> {\n const hash = createHash(\"sha256\");\n let size = 0;\n for await (const chunk of createReadStream(path)) {\n hash.update(chunk as Buffer);\n size += (chunk as Buffer).length;\n }\n return { sha256: hash.digest(\"hex\"), size };\n}\n\n/** One entry of a walk: a regular file or a link, by `/`-separated path from the root. */\ntype Walked =\n | { readonly kind: \"file\"; readonly path: string; readonly executable: boolean }\n | { readonly kind: \"link\"; readonly path: string; readonly target: string }\n | { readonly kind: \"other\"; readonly path: string };\n\n/** Every file and link under `root`, sorted by path, skipping `exclude`d paths (and below). */\nasync function walk(root: string, exclude: (path: string) => boolean): Promise<Walked[]> {\n const out: Walked[] = [];\n const visit = async (dir: string): Promise<void> => {\n const entries = await readdir(join(root, dir), { withFileTypes: true });\n for (const entry of entries) {\n const path = dir === \"\" ? entry.name : `${dir}/${entry.name}`;\n if (exclude(path)) continue;\n if (entry.isDirectory()) await visit(path);\n else if (entry.isSymbolicLink()) {\n out.push({ kind: \"link\", path, target: await readlink(join(root, path)) });\n } else if (entry.isFile()) {\n const stats = await lstat(join(root, path));\n out.push({ kind: \"file\", path, executable: (stats.mode & 0o100) !== 0 });\n } else out.push({ kind: \"other\", path });\n }\n };\n await visit(\"\");\n return out.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n}\n\n/** Runs `task` over `items`, at most `limit` at a time, keeping the order of results. */\nasync function mapLimit<T, R>(\n items: readonly T[],\n limit: number,\n task: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const worker = async (): Promise<void> => {\n while (next < items.length) {\n const index = next++;\n results[index] = await task(items[index] as T);\n }\n };\n await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));\n return results;\n}\n\n/** Whether a link's target is relative and resolves inside `root`. */\nexport function linkStaysInside(root: string, path: string, target: string): boolean {\n if (isAbsolute(target)) return false;\n const base = resolve(root);\n const resolved = resolve(base, dirname(path), target);\n return resolved === base || resolved.startsWith(base + sep);\n}\n\n/** Whether a manifest path is a plain relative path: no absolute start, no `.` or `..` segment. */\nexport function safeRelative(path: string): boolean {\n if (path === \"\" || isAbsolute(path) || path.includes(\"\\\\\") || path.includes(\"\\0\")) return false;\n return path.split(\"/\").every((segment) => segment !== \"\" && segment !== \".\" && segment !== \"..\");\n}\n\n/**\n * The manifest of the tree under `root`: every regular file with its SHA-256, size and execute\n * bit, every link with its target. Throws on anything else (a device, a socket, a link leaving\n * the tree), which a bundle must never contain.\n */\nexport async function describeTree(\n root: string,\n exclude: (path: string) => boolean = () => false,\n): Promise<BundleFiles> {\n const walked = await walk(root, exclude);\n const files: BundleFileEntry[] = [];\n const links: BundleLinkEntry[] = [];\n const regular = walked.filter((entry) => entry.kind === \"file\");\n const hashed = await mapLimit(regular, 32, (entry) => hashFile(join(root, entry.path)));\n regular.forEach((entry, index) => {\n const { sha256, size } = hashed[index] as { sha256: string; size: number };\n files.push({ path: entry.path, size, sha256, executable: entry.executable });\n });\n for (const entry of walked) {\n if (entry.kind === \"other\") throw new Error(`${entry.path} is neither a file nor a link.`);\n if (entry.kind !== \"link\") continue;\n if (!linkStaysInside(root, entry.path, entry.target))\n throw new Error(`${entry.path} links outside the tree (${entry.target}).`);\n links.push({ path: entry.path, target: entry.target });\n }\n return { schemaVersion: 1, files, links };\n}\n\n/** What a check found: an empty list means the tree matches. Paths are relative to the root. */\nexport type TreeProblems = readonly string[];\n\n/**\n * Checks the tree under `root` against `manifest`: each listed file present, regular, with its\n * size, SHA-256 and execute bit; each link present with its target, staying inside; and nothing\n * else besides what `allowExtra` accepts. Reports at most `limit` problems.\n */\nexport async function checkTree(\n root: string,\n manifest: BundleFiles,\n options: { readonly allowExtra?: (path: string) => boolean; readonly limit?: number } = {},\n): Promise<TreeProblems> {\n const limit = options.limit ?? 20;\n const allowExtra = options.allowExtra ?? (() => false);\n const problems: string[] = [];\n const add = (problem: string): void => {\n if (problems.length < limit) problems.push(problem);\n };\n const expectedFiles = new Map(manifest.files.map((entry) => [entry.path, entry]));\n const expectedLinks = new Map(manifest.links.map((entry) => [entry.path, entry]));\n for (const path of [...expectedFiles.keys(), ...expectedLinks.keys()]) {\n if (!safeRelative(path)) add(`${path}: not a plain relative path`);\n }\n if (problems.length > 0) return problems;\n // An allowed extra is skipped whole unless something listed lies at or below it.\n const listedDirs = new Set<string>();\n for (const path of [...expectedFiles.keys(), ...expectedLinks.keys()]) {\n const segments = path.split(\"/\");\n for (let index = 1; index < segments.length; index++)\n listedDirs.add(segments.slice(0, index).join(\"/\"));\n }\n const walked = await walk(\n root,\n (path) =>\n allowExtra(path) &&\n !expectedFiles.has(path) &&\n !expectedLinks.has(path) &&\n !listedDirs.has(path),\n );\n const found = new Map(walked.map((entry) => [entry.path, entry]));\n for (const entry of walked) {\n if (!expectedFiles.has(entry.path) && !expectedLinks.has(entry.path)) {\n if (!allowExtra(entry.path)) add(`${entry.path}: not in the bundle's file list`);\n }\n }\n for (const [path, link] of expectedLinks) {\n const actual = found.get(path);\n if (actual?.kind !== \"link\") add(`${path}: missing link`);\n else if (actual.target !== link.target)\n add(`${path}: links to ${actual.target}, not ${link.target}`);\n else if (!linkStaysInside(root, path, link.target)) add(`${path}: links outside the bundle`);\n }\n const files = [...expectedFiles.values()];\n const results = await mapLimit(files, 32, async (entry) => {\n const actual = found.get(entry.path);\n if (actual?.kind !== \"file\") return `${entry.path}: missing file`;\n if (actual.executable !== entry.executable)\n return `${entry.path}: ${entry.executable ? \"not executable\" : \"executable\"}`;\n const { sha256, size } = await hashFile(join(root, entry.path));\n if (size !== entry.size) return `${entry.path}: ${size} bytes, not ${entry.size}`;\n if (sha256 !== entry.sha256) return `${entry.path}: its SHA-256 differs`;\n return undefined;\n });\n for (const result of results) if (result !== undefined) add(result);\n return problems;\n}\n","/**\n * Making an extracted bundle usable (RT-01, D142): its files checked against `files.json`, which\n * `bundle.json` pins by SHA-256; the verify browser fetched through the bundle's own Playwright\n * and checked against the bundle's pin; then `.mostra-setup.json`, the one marker every reader\n * trusts. The SDK runs it after a download; `bin/mostra-setup` runs it for a bundle extracted by\n * hand, and for the Rust crate (WP-12), so there is one implementation of what \"ready\" means.\n */\nimport { spawn } from \"node:child_process\";\nimport { readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n BUNDLE_SETUP_MARKER,\n BundleFiles,\n BundleInfo,\n BundleSetup,\n createDiagnostic,\n RpcError,\n} from \"@mostra/protocol\";\nimport { scrubUrls } from \"./download.ts\";\nimport { checkTree, hashFile, safeRelative } from \"./tree.ts\";\n\n/** The environment setup reads. */\nexport type Environment = Readonly<Record<string, string | undefined>>;\n\n/** An extracted bundle and what its `bundle.json` says. */\nexport interface Bundle {\n /** Its root directory, holding `bundle.json`. */\n readonly root: string;\n /** Its parsed `bundle.json`. */\n readonly info: BundleInfo;\n}\n\n/** One step of setup, for progress reports. */\nexport type SetupStep = \"files\" | \"browser\";\n\n/** Options of {@link setupBundle}. */\nexport interface SetupOptions {\n /** The environment: `MOSTRA_OFFLINE`, proxies, Playwright's download mirror. */\n readonly env?: Environment | undefined;\n /** Gives up the browser's download. */\n readonly signal?: AbortSignal | undefined;\n /** Each step as it starts. */\n readonly onStep?: ((step: SetupStep) => void) | undefined;\n /** Skip checking the files, for a tree the caller checked a moment ago. */\n readonly filesChecked?: boolean | undefined;\n}\n\n/** The directory Playwright's browsers live in, inside a bundle. */\nexport function browsersDir(root: string): string {\n return join(root, \"browsers\");\n}\n\n/** Whether `MOSTRA_OFFLINE` says Mostra is offline: any value but empty, `0`, `false` or `no`. */\nexport function offline(env: Environment): boolean {\n const value = env[\"MOSTRA_OFFLINE\"]?.trim().toLowerCase();\n return (\n value !== undefined && value !== \"\" && value !== \"0\" && value !== \"false\" && value !== \"no\"\n );\n}\n\nfunction invalid(message: string): RpcError {\n return new RpcError(createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", { message }));\n}\n\n/** Reads `bundle.json` at `root`. Throws `MOSTRA_ENV_BUNDLE_INVALID` when it isn't a bundle's. */\nexport async function readBundle(root: string): Promise<Bundle> {\n let text: string;\n try {\n text = await readFile(join(root, \"bundle.json\"), \"utf8\");\n } catch (error) {\n throw invalid(`${root} has no readable bundle.json (${(error as Error).message}).`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw invalid(`${join(root, \"bundle.json\")} isn't JSON.`);\n }\n const result = BundleInfo.safeParse(parsed);\n if (!result.success) throw invalid(`${join(root, \"bundle.json\")} isn't a runtime bundle's.`);\n const info = result.data;\n const paths = [\n info.node.path,\n ...Object.values(info.entries),\n info.files.path,\n info.browser.installer,\n ];\n if (!paths.every(safeRelative))\n throw invalid(`${join(root, \"bundle.json\")} names a path outside the bundle.`);\n return { root, info };\n}\n\n/** The setup marker, when it describes exactly this bundle. */\nexport async function readSetup(bundle: Bundle): Promise<BundleSetup | undefined> {\n try {\n const marker = BundleSetup.parse(\n JSON.parse(await readFile(join(bundle.root, BUNDLE_SETUP_MARKER), \"utf8\")),\n );\n const { info } = bundle;\n return marker.files === info.files.sha256 &&\n marker.version === info.version &&\n marker.platform === info.platform &&\n marker.browser.revision === info.browser.revision\n ? marker\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** What `checkTree` may find besides the listed files: the bundle's own records and browsers. */\nexport function setupExtras(path: string): boolean {\n return (\n path === \"bundle.json\" ||\n path === \"files.json\" ||\n path === \"browsers\" ||\n path.startsWith(\"browsers/\") ||\n path === BUNDLE_SETUP_MARKER ||\n path.startsWith(`${BUNDLE_SETUP_MARKER}.tmp-`)\n );\n}\n\n/** Checks the bundle's files; throws `MOSTRA_ENV_BUNDLE_INVALID` naming what differs. */\nexport async function checkFiles(bundle: Bundle): Promise<void> {\n const { root, info } = bundle;\n const listing = join(root, info.files.path);\n const { sha256 } = await hashFile(listing).catch(() => ({ sha256: \"\" }));\n if (sha256 !== info.files.sha256) {\n throw invalid(`${info.files.path} doesn't match the SHA-256 that bundle.json pins.`);\n }\n const manifest = BundleFiles.safeParse(JSON.parse(await readFile(listing, \"utf8\")));\n if (!manifest.success) throw invalid(`${info.files.path} isn't a bundle's file list.`);\n const problems = await checkTree(root, manifest.data, { allowExtra: setupExtras });\n if (problems.length > 0) {\n throw invalid(\n `Mostra ${info.version}'s runtime bundle for ${info.platform} differs from its file list: ${problems.join(\"; \")}.`,\n );\n }\n}\n\n/** The browser files that differ from the pin, relative to `browsers/`. */\nexport async function checkBrowser(bundle: Bundle): Promise<readonly string[]> {\n const problems = await checkTree(\n browsersDir(bundle.root),\n { schemaVersion: 1, files: bundle.info.browser.files, links: [] },\n // Playwright's own markers, its `.links` registry and any other browser it fetched.\n { allowExtra: () => true },\n ).catch((error: unknown) => [`browsers: ${(error as Error).message}`]);\n return problems;\n}\n\n/** The environment the browser install runs in: proxies and Playwright's mirror pass through. */\nfunction installEnvironment(bundle: Bundle, env: Environment): NodeJS.ProcessEnv {\n const out: NodeJS.ProcessEnv = {};\n for (const [name, value] of Object.entries(env)) {\n if (value !== undefined && !name.startsWith(\"MOSTRA_\") && name !== \"PLAYWRIGHT_BROWSERS_PATH\")\n out[name] = value;\n }\n out[\"PLAYWRIGHT_BROWSERS_PATH\"] = browsersDir(bundle.root);\n return out;\n}\n\n/** The variables whose URLs may carry credentials the browser's fetch uses. */\nconst CREDENTIAL_URLS = [\n \"PLAYWRIGHT_DOWNLOAD_HOST\",\n \"HTTPS_PROXY\",\n \"https_proxy\",\n \"HTTP_PROXY\",\n \"http_proxy\",\n \"ALL_PROXY\",\n \"all_proxy\",\n];\n\n/** `text` without URLs' credentials or queries, and without any password `env`'s URLs carry. */\nexport function scrubSecrets(text: string, env: Environment): string {\n let out = scrubUrls(text);\n for (const name of CREDENTIAL_URLS) {\n const value = env[name];\n if (!value) continue;\n // A proxy is often written without a scheme (`user:pass@host:3128`), which `URL` would read\n // as the scheme `user:`.\n const spelled = value.includes(\"://\") ? value : `http://${value}`;\n const parsed = URL.canParse(spelled) ? new URL(spelled) : undefined;\n for (const secret of [parsed?.password, parsed?.username]) {\n if (!secret) continue;\n for (const form of new Set([secret, decodeURIComponent(secret)]))\n if (form.length >= 3) out = out.split(form).join(\"***\");\n }\n }\n return out;\n}\n\n/** Runs the bundle's Playwright to fetch the pinned browser; at most 15 minutes. */\nasync function installBrowser(bundle: Bundle, options: SetupOptions): Promise<void> {\n const { root, info } = bundle;\n const output: string[] = [];\n const code = await new Promise<number | string>((resolve) => {\n const child = spawn(\n join(root, info.node.path),\n [join(root, info.browser.installer), \"install\", \"chromium-headless-shell\"],\n {\n cwd: root,\n env: installEnvironment(bundle, options.env ?? process.env),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n ...(options.signal ? { signal: options.signal } : {}),\n timeout: 15 * 60_000,\n },\n );\n const keep = (chunk: Buffer): void => {\n output.push(chunk.toString(\"utf8\"));\n if (output.length > 40) output.shift();\n };\n child.stdout.on(\"data\", keep);\n child.stderr.on(\"data\", keep);\n child.on(\"error\", (error) => resolve(error.message));\n child.on(\"close\", (exit, signal) => resolve(exit ?? signal ?? \"unknown\"));\n });\n if (code === 0) return;\n // Playwright prints the URLs it fetches, and a mirror's or proxy's may carry credentials\n // (Opus review finding 3): every URL is reduced to its printable form, and any password the\n // environment names is removed wherever it appears.\n const tail = scrubSecrets(\n output.join(\"\").trim().split(\"\\n\").slice(-6).join(\" | \"),\n options.env ?? process.env,\n );\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED\", {\n message: `Fetching the verify browser (${info.browser.name} ${info.browser.browserVersion}) failed (${code}): ${tail}`,\n }),\n );\n}\n\n/**\n * Makes the bundle at `root` ready: checks its files, fetches and checks the browser when it is\n * missing or differs, and writes `.mostra-setup.json`. Idempotent: a ready bundle returns its\n * marker after the checks. Throws `MOSTRA_ENV_BUNDLE_INVALID`, `MOSTRA_ENV_BUNDLE_UNAVAILABLE`\n * (offline with no browser) or `MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED`.\n */\nexport async function setupBundle(root: string, options: SetupOptions = {}): Promise<BundleSetup> {\n const env = options.env ?? process.env;\n const bundle = await readBundle(root);\n if (!options.filesChecked) {\n options.onStep?.(\"files\");\n await checkFiles(bundle);\n }\n options.onStep?.(\"browser\");\n if ((await checkBrowser(bundle)).length > 0) {\n if (offline(env)) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_UNAVAILABLE\", {\n message: `The runtime bundle at ${root} has no verify browser yet, and MOSTRA_OFFLINE keeps Mostra from fetching it.`,\n }),\n );\n }\n // Fresh, never over what's there: a directory that differs from the pin may still carry\n // Playwright's \"installation complete\" marker, and Playwright would then fetch nothing.\n await rm(browsersDir(root), { recursive: true, force: true });\n await installBrowser(bundle, options);\n const problems = await checkBrowser(bundle);\n if (problems.length > 0) {\n throw invalid(\n `The verify browser Playwright fetched differs from the bundle's pin: ${problems.join(\"; \")}.`,\n );\n }\n }\n const marker: BundleSetup = {\n schemaVersion: 1,\n version: bundle.info.version,\n platform: bundle.info.platform,\n files: bundle.info.files.sha256,\n browser: { revision: bundle.info.browser.revision },\n at: new Date().toISOString(),\n };\n const temporary = join(root, `${BUNDLE_SETUP_MARKER}.tmp-${process.pid}`);\n await writeFile(temporary, `${JSON.stringify(marker, null, 2)}\\n`);\n await rename(temporary, join(root, BUNDLE_SETUP_MARKER));\n return marker;\n}\n","/**\n * The local cache of runtime bundles (RT-01): one directory per archive digest, so a bundle is\n * found by what it is, not by what it's called. A bundle enters the cache only through\n * {@link installPinned}: downloaded against its pin, extracted into a temporary directory, its\n * files checked, renamed into place, its browser fetched, and only then marked ready. Concurrent\n * installers of one bundle share a lock, so it is downloaded once; a crash leaves a temporary\n * directory the next install removes, never a half-ready bundle.\n */\nimport { randomBytes } from \"node:crypto\";\nimport { link, mkdir, open, readdir, readFile, rename, rm, stat, statfs } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport {\n type BundleAsset,\n BundleAsset as BundleAssetSchema,\n type BundlePins,\n type BundlePlatform,\n bundleAssetName,\n createDiagnostic,\n RpcError,\n} from \"@mostra/protocol\";\nimport { type DownloadProgress, download } from \"./download.ts\";\nimport { extractBundle } from \"./extract.ts\";\nimport {\n type Bundle,\n checkFiles,\n type Environment,\n offline,\n readBundle,\n readSetup,\n type SetupStep,\n setupBundle,\n} from \"./setup.ts\";\n\n/** Where the cache is: `MOSTRA_CACHE_DIR`, else the platform's per-user cache directory. */\nexport function cacheRoot(env: Environment, platform: string = process.platform): string {\n const override = env[\"MOSTRA_CACHE_DIR\"];\n if (override) return resolve(override);\n const home = env[\"HOME\"] || homedir();\n if (platform === \"darwin\") return join(home, \"Library\", \"Caches\", \"mostra\");\n const xdg = env[\"XDG_CACHE_HOME\"];\n return join(xdg?.startsWith(\"/\") ? xdg : join(home, \".cache\"), \"mostra\");\n}\n\n/** The directory a bundle with this archive digest lives in. */\nexport function bundleDir(env: Environment, sha256: string): string {\n return join(cacheRoot(env), \"bundles\", sha256);\n}\n\n/** What an install reports while it works. */\nexport type InstallProgress =\n | ({ readonly step: \"download\" } & DownloadProgress)\n | { readonly step: \"extract\" | \"lock\" }\n | { readonly step: SetupStep };\n\n/** Options of {@link installPinned}. */\nexport interface InstallOptions {\n /** The environment: the cache, mirror and offline variables, proxies. */\n readonly env: Environment;\n /** The platform whose archive to install. */\n readonly platform: BundlePlatform;\n /** Gives up the install; nothing partial is kept. */\n readonly signal?: AbortSignal | undefined;\n /** Each step, and the bytes received while downloading. */\n readonly onProgress?: ((progress: InstallProgress) => void) | undefined;\n}\n\n/** The space an install needs beyond the archive and its files: the browser and some margin. */\nconst BROWSER_ALLOWANCE = 500 * 1024 * 1024;\n\n/**\n * The pinned bundle for this platform, ready to run: from the cache when it is there and ready,\n * else installed. `MOSTRA_BUNDLE_MIRROR` replaces the release URL (files keep their names).\n */\nexport async function installPinned(pins: BundlePins, options: InstallOptions): Promise<Bundle> {\n const asset = pins.assets[options.platform];\n // Checked before any I/O: the asset's name becomes a path in the cache's scratch directory and\n // its digest the bundle's directory (Opus review finding 8), so the asset must be well-formed\n // and named exactly as its release's archive for this platform.\n if (\n asset !== undefined &&\n (!BundleAssetSchema.safeParse(asset).success ||\n asset.file !== bundleAssetName(pins.version, options.platform))\n ) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", {\n message: `The pins name ${JSON.stringify(asset.file)} for ${options.platform}, not Mostra ${pins.version}'s archive ${bundleAssetName(pins.version, options.platform)}.`,\n }),\n );\n }\n if (asset === undefined) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_UNAVAILABLE\", {\n message: `Mostra ${pins.version} has no runtime bundle for ${options.platform}.`,\n }),\n );\n }\n const dir = bundleDir(options.env, asset.sha256);\n const ready = await readyAt(dir);\n if (ready) return ready;\n if (offline(options.env)) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_UNAVAILABLE\", {\n message: `Mostra ${pins.version}'s runtime bundle isn't in the cache (${dir}), and MOSTRA_OFFLINE keeps Mostra from fetching it.`,\n }),\n );\n }\n const bundles = join(cacheRoot(options.env), \"bundles\");\n await mkdir(bundles, { recursive: true, mode: 0o700 });\n options.onProgress?.({ step: \"lock\" });\n const release = await lock(join(bundles, `${asset.sha256}.lock`), options.signal);\n try {\n const raced = await readyAt(dir);\n if (raced) return raced;\n await sweep(bundles);\n if (await exists(dir)) {\n // A bundle whose setup didn't finish (no network for the browser, a crash). Only its own\n // files decide whether it is downloaded afresh: a file that differs from the pins can't be\n // repaired in place, but the browser can be fetched again, and downloading 200 MB again\n // never changes what Playwright serves (Opus review finding 5). Anything else, such as a\n // permission error, is thrown: it says nothing about the bundle, so nothing is deleted.\n if (await filesIntact(dir)) return await finish(dir, { ...options, filesChecked: true });\n await rm(dir, { recursive: true, force: true });\n }\n await fetchInto(pins, asset, dir, bundles, options);\n return await finish(dir, { ...options, filesChecked: true });\n } finally {\n await release();\n }\n}\n\n/**\n * Whether the bundle at `dir` holds exactly what its `files.json` lists. `false` only for\n * `MOSTRA_ENV_BUNDLE_INVALID` (a missing or changed file, a `bundle.json` that doesn't read);\n * every other error is thrown.\n */\nasync function filesIntact(dir: string): Promise<boolean> {\n try {\n await checkFiles(await readBundle(dir));\n return true;\n } catch (error) {\n if (error instanceof RpcError && error.diagnostic.code === \"MOSTRA_ENV_BUNDLE_INVALID\")\n return false;\n throw error;\n }\n}\n\n/** The bundle at `dir` when it exists and its setup marker matches it. */\nasync function readyAt(dir: string): Promise<Bundle | undefined> {\n const bundle = await readBundle(dir).catch(() => undefined);\n if (bundle === undefined) return undefined;\n return (await readSetup(bundle)) ? bundle : undefined;\n}\n\nasync function finish(\n dir: string,\n options: InstallOptions & { readonly filesChecked?: boolean },\n): Promise<Bundle> {\n await setupBundle(dir, {\n env: options.env,\n signal: options.signal,\n filesChecked: options.filesChecked,\n onStep: (step) => options.onProgress?.({ step }),\n });\n return readBundle(dir);\n}\n\n/** Downloads, extracts and checks the archive, then renames it into `dir`. */\nasync function fetchInto(\n pins: BundlePins,\n asset: BundleAsset,\n dir: string,\n bundles: string,\n options: InstallOptions,\n): Promise<void> {\n await requireSpace(bundles, asset);\n const scratch = join(bundles, `.tmp-${process.pid}-${randomBytes(6).toString(\"hex\")}`);\n await mkdir(scratch, { mode: 0o700 });\n try {\n const archive = join(scratch, asset.file);\n const base = options.env[\"MOSTRA_BUNDLE_MIRROR\"] || pins.release;\n const url = `${withoutTrailingSlashes(base)}/${encodeURIComponent(asset.file)}`;\n await download(url, archive, asset, {\n env: options.env,\n signal: options.signal,\n onProgress: (progress) => options.onProgress?.({ step: \"download\", ...progress }),\n });\n options.onProgress?.({ step: \"extract\" });\n const root = join(scratch, \"root\");\n await mkdir(root);\n const top = asset.file.replace(/\\.tar\\.gz$/, \"\");\n if (top !== bundleAssetName(pins.version, options.platform).replace(/\\.tar\\.gz$/, \"\")) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", {\n message: `The pinned archive ${asset.file} isn't Mostra ${pins.version}'s bundle for ${options.platform}.`,\n }),\n );\n }\n await extractBundle(archive, root, top);\n await rm(archive, { force: true });\n const bundle = await readBundle(root);\n if (bundle.info.version !== pins.version || bundle.info.platform !== options.platform) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", {\n message: `The archive holds Mostra ${bundle.info.version} for ${bundle.info.platform}, not ${pins.version} for ${options.platform}.`,\n }),\n );\n }\n options.onProgress?.({ step: \"files\" });\n await checkFiles(bundle);\n try {\n await rename(root, dir);\n } catch (error) {\n // Another installer finished first (the lock is an optimization, never what correctness\n // rests on): its directory is used, whose files it checked before renaming them into place.\n const code = (error as NodeJS.ErrnoException).code;\n if (!(code === \"ENOTEMPTY\" || code === \"EEXIST\") || !(await exists(dir))) throw error;\n }\n } finally {\n await rm(scratch, { recursive: true, force: true });\n }\n}\n\n/** Fails early when the cache's file system can't hold the bundle. */\nasync function requireSpace(dir: string, asset: BundleAsset): Promise<void> {\n const fs = await statfs(dir).catch(() => undefined);\n if (fs === undefined) return;\n const free = Number(fs.bavail) * Number(fs.bsize);\n const needed = asset.size + asset.unpackedSize + BROWSER_ALLOWANCE;\n if (free < needed) {\n const gib = (bytes: number): string => `${(bytes / 1024 ** 3).toFixed(1)} GiB`;\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED\", {\n message: `The runtime bundle needs about ${gib(needed)} free in ${dir}, and ${gib(free)} is free (the disk is full).`,\n }),\n );\n }\n}\n\n/** Removes temporary directories an interrupted install left, when their process is gone. */\nasync function sweep(bundles: string): Promise<void> {\n for (const name of await readdir(bundles).catch(() => [] as string[])) {\n const match = /^\\.tmp-(\\d+)-/.exec(name);\n if (match && !alive(Number(match[1]))) {\n await rm(join(bundles, name), { recursive: true, force: true });\n }\n }\n}\n\nasync function exists(path: string): Promise<boolean> {\n return stat(path).then(\n () => true,\n () => false,\n );\n}\n\nfunction alive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/** How old a lock may get before another installer takes it over whatever its owner. */\nconst STALE_LOCK_MS = 60 * 60_000;\n\n/** `url` without trailing slashes, in linear time (a regex would be quadratic on many slashes). */\nfunction withoutTrailingSlashes(url: string): string {\n let end = url.length;\n while (end > 0 && url[end - 1] === \"/\") end -= 1;\n return url.slice(0, end);\n}\n\n/**\n * Removes the lock at `path` when it is stale (its owner gone, or older than an hour) and says\n * whether it did. The lock is read and judged through one descriptor, then moved aside, and only\n * the file judged is removed: a fresh lock another installer took in between is put back (or,\n * if a third took one meanwhile, left to the next round). The lock only saves a second download;\n * the scratch directory and its rename keep the cache correct whatever happens here.\n */\nasync function takeOverIfStale(path: string): Promise<boolean> {\n let handle: Awaited<ReturnType<typeof open>>;\n try {\n handle = await open(path, \"r\");\n } catch {\n return true; // gone already: try to take it\n }\n let judged: { ino: number; dev: number };\n try {\n const info = await handle.stat();\n const owner = Number.parseInt(await handle.readFile(\"utf8\"), 10);\n const stale =\n Date.now() - info.mtimeMs > STALE_LOCK_MS ||\n (Number.isInteger(owner) && owner > 0 && !alive(owner));\n if (!stale) return false;\n judged = { ino: info.ino, dev: info.dev };\n } finally {\n await handle.close();\n }\n const aside = `${path}.stale-${randomBytes(6).toString(\"hex\")}`;\n try {\n await rename(path, aside);\n } catch {\n return true; // someone else moved or removed it\n }\n const moved = await stat(aside).catch(() => undefined);\n if (moved && (moved.ino !== judged.ino || moved.dev !== judged.dev)) {\n // Not the file judged stale: a fresh lock. Put it back unless a newer one exists.\n await link(aside, path).catch(() => undefined);\n }\n await rm(aside, { force: true });\n return true;\n}\n\n/**\n * Takes the install lock at `path`: an exclusive create holding the owner's PID. A lock whose\n * owner is gone, or older than an hour, is taken over; otherwise the caller waits for it.\n */\nasync function lock(path: string, signal: AbortSignal | undefined): Promise<() => Promise<void>> {\n const token = randomBytes(8).toString(\"hex\");\n for (;;) {\n signal?.throwIfAborted();\n try {\n const handle = await open(path, \"wx\", 0o600);\n await handle.writeFile(`${process.pid} ${token}\\n`);\n await handle.close();\n // Released by moving it aside and removing it only if it is still this installer's own.\n return async () => {\n const aside = `${path}.done-${randomBytes(6).toString(\"hex\")}`;\n if (\n !(await rename(path, aside).then(\n () => true,\n () => false,\n ))\n )\n return;\n const text = await readFile(aside, \"utf8\").catch(() => \"\");\n if (!text.includes(token)) await link(aside, path).catch(() => undefined);\n await rm(aside, { force: true });\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n }\n if (await takeOverIfStale(path)) continue;\n await new Promise((done) => setTimeout(done, 250));\n }\n}\n","/**\n * Which runtime bundle this machine takes (RT-01, D35): one per operating system and architecture\n * of v1, glibc only on Linux. Anything else fails closed before a download starts.\n */\nimport {\n BUNDLE_PLATFORMS,\n type BundlePlatform,\n createDiagnostic,\n RpcError,\n} from \"@mostra/protocol\";\n\n/** What the platform check reads: the running process by default. */\nexport interface PlatformFacts {\n /** `process.platform`. */\n readonly platform: string;\n /** `process.arch`. */\n readonly arch: string;\n /** The glibc release on Linux, `undefined` on musl or elsewhere. */\n readonly glibc?: string | undefined;\n}\n\n/** What {@link glibcRuntime} needs of `process.report`. */\ninterface Reporter {\n /** Node.js 22.13 and 23.3 or later; `@types/node` 24.19 doesn't declare it yet. */\n excludeNetwork?: boolean;\n getReport(): object;\n}\n\n/**\n * The glibc release Node.js reports, read from its diagnostic report's header. The report runs in\n * the caller's process (a host's server, say) and by default resolves the name of every open TCP\n * handle, synchronously; with `excludeNetwork` it does none of that (Opus review finding 4), as\n * detect-libc does. The setting is restored after.\n */\nexport function glibcRuntime(report: Reporter | undefined): string | undefined {\n if (report === undefined) return undefined;\n const before = report.excludeNetwork ?? false;\n report.excludeNetwork = true;\n try {\n return (report.getReport() as { header?: { glibcVersionRuntime?: string } }).header\n ?.glibcVersionRuntime;\n } finally {\n report.excludeNetwork = before;\n }\n}\n\nlet facts: PlatformFacts | undefined;\n\n/** The facts of the running process, read once. */\nexport function currentPlatform(): PlatformFacts {\n facts ??=\n process.platform === \"linux\"\n ? { platform: process.platform, arch: process.arch, glibc: glibcRuntime(process.report) }\n : { platform: process.platform, arch: process.arch };\n return facts;\n}\n\n/**\n * The bundle platform for these facts. Throws `MOSTRA_PLATFORM_UNSUPPORTED` for Windows, other\n * architectures and Linux without glibc, whose libraries the bundle's Node.js and browser need.\n */\nexport function bundlePlatform(facts: PlatformFacts = currentPlatform()): BundlePlatform {\n const name = `${facts.platform}-${facts.arch}`;\n const known = (BUNDLE_PLATFORMS as readonly string[]).includes(name);\n if (known && facts.platform === \"linux\" && facts.glibc === undefined) {\n throw unsupported(\n `Mostra's Linux bundle needs glibc, and this system has none (musl, as on Alpine Linux); it supports macOS and glibc-based Linux on x64 and arm64.`,\n );\n }\n if (!known) {\n const label = facts.platform === \"win32\" ? `Windows (${name})` : name;\n throw unsupported(\n `Mostra doesn't run on ${label}; it supports macOS and Linux on x64 and arm64.`,\n );\n }\n return name as BundlePlatform;\n}\n\nfunction unsupported(message: string): RpcError {\n return new RpcError(createDiagnostic(\"MOSTRA_PLATFORM_UNSUPPORTED\", { message }));\n}\n","/** The SDK's own package: its root directory and its release. */\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nlet found: { readonly root: string; readonly version: string } | undefined;\n\nfunction own(): { readonly root: string; readonly version: string } {\n if (found) return found;\n let dir = dirname(fileURLToPath(import.meta.url));\n for (;;) {\n try {\n const manifest = JSON.parse(readFileSync(join(dir, \"package.json\"), \"utf8\")) as {\n name?: string;\n version?: string;\n };\n if (manifest.name === \"@mostra/sdk\" && manifest.version) {\n found = { root: dir, version: manifest.version };\n return found;\n }\n } catch {\n // Keep looking upwards.\n }\n const parent = dirname(dir);\n if (parent === dir) throw new Error(\"Couldn't find @mostra/sdk's package.json.\");\n dir = parent;\n }\n}\n\n/** This SDK's release: the client version an SDK host reports by default. */\nexport function sdkVersion(): string {\n return own().version;\n}\n\n/** The SDK package's directory; `dist/bundles.json` lives under it in a release. */\nexport function packageRoot(): string {\n return own().root;\n}\n","/**\n * Which runtime a host runs (RT-01, D85). In order:\n *\n * 1. `bundle`, a directory the caller names (the SDK's option), then `MOSTRA_BUNDLE`;\n * 2. `MOSTRA_RUNTIME_BIN`, a `mostra-runtime` entry run with this process's Node (tests and\n * development);\n * 3. the bundle this package itself sits in (the CLI inside a bundle);\n * 4. the bundle this package's release pins (`bundles.json`), from the cache or downloaded;\n * 5. a development checkout's built runtime beside this package.\n *\n * Anything a bundle supplies is checked first: its setup marker must match it, or setup runs.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport { BundlePins, createDiagnostic, RpcError } from \"@mostra/protocol\";\nimport { type InstallProgress, installPinned } from \"./bundle/cache.ts\";\nimport {\n type Bundle,\n type Environment,\n readBundle,\n readSetup,\n type SetupStep,\n setupBundle,\n} from \"./bundle/setup.ts\";\nimport { bundlePlatform } from \"./platform.ts\";\nimport { packageRoot } from \"./version.ts\";\n\n/** A runtime to spawn: the Node.js to run it with and its entry points. */\nexport interface Runtime {\n /** How it was found. */\n readonly source: \"bundle\" | \"override\" | \"development\";\n /** The Node.js executable: the bundle's own, or this process's for the others. */\n readonly node: string;\n /** `mostra-runtime`'s entry (`host`, `daemon`, `service`). */\n readonly runtimeEntry: string;\n /** The `mostra` CLI's entry, when this runtime has one. */\n readonly cliEntry?: string;\n /** The bundle, when the runtime is one. */\n readonly bundle?: Bundle;\n}\n\n/** Options of {@link resolveRuntime}. */\nexport interface RuntimeOptions {\n /** An extracted bundle to use, ahead of everything else. */\n readonly bundle?: string | undefined;\n /** The environment: `MOSTRA_BUNDLE`, `MOSTRA_RUNTIME_BIN`, the cache's variables. */\n readonly env?: Environment | undefined;\n /** Gives up a download or setup. */\n readonly signal?: AbortSignal | undefined;\n /** Progress of a download or setup, for a person waiting (the CLI prints it on stderr). */\n readonly onProgress?: ((progress: InstallProgress) => void) | undefined;\n}\n\n/**\n * Where the pins are read from: `<package>/dist/bundles.json`, which the release writes before\n * publishing. `MOSTRA_TEST_BUNDLE_PINS` names another file only for a package that runs from a\n * development checkout (its real path outside any `node_modules`), where the tests use it: an\n * installed copy (npm's `node_modules`, or a bundle's `lib/node_modules`) ignores it, so a\n * variable leaked into a user's environment can't swap the pins npm's provenance covers (Opus\n * review finding 8).\n */\nexport function pinsFile(env: Environment, root: string): string {\n const override = env[\"MOSTRA_TEST_BUNDLE_PINS\"];\n const installed = root.split(sep).includes(\"node_modules\");\n return override && !installed ? override : join(root, \"dist\", \"bundles.json\");\n}\n\n/** The pins this build carries: `dist/bundles.json` (a test override applies only in a development checkout). */\nexport function readPins(env: Environment): BundlePins | undefined {\n const file = pinsFile(env, packageRoot());\n if (!existsSync(file)) return undefined;\n let data: unknown;\n try {\n data = JSON.parse(readFileSync(file, \"utf8\"));\n } catch {\n data = undefined; // not JSON (or unreadable): the same refusal as a file of the wrong shape\n }\n const parsed = BundlePins.safeParse(data);\n if (!parsed.success) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_INVALID\", {\n message: `${file} isn't a release's bundle pins.`,\n }),\n );\n }\n return parsed.data;\n}\n\n/** The bundle this package was installed into, if any: `<root>/lib/node_modules/@mostra/sdk`. */\nexport function enclosingBundle(): string | undefined {\n const root = resolve(packageRoot(), \"..\", \"..\", \"..\", \"..\");\n return existsSync(join(root, \"bundle.json\")) &&\n existsSync(join(root, \"lib\", \"node_modules\", \"@mostra\", \"sdk\"))\n ? root\n : undefined;\n}\n\n/** The runtime described by a bundle, once it is set up. */\nasync function fromBundle(root: string, options: RuntimeOptions): Promise<Runtime> {\n let bundle = await readBundle(resolve(root));\n if (!(await readSetup(bundle))) {\n await setupBundle(bundle.root, {\n env: options.env,\n signal: options.signal,\n onStep: (step: SetupStep) => options.onProgress?.({ step }),\n });\n bundle = await readBundle(bundle.root);\n }\n return runtimeOf(bundle);\n}\n\n/** A bundle's entry points as a runtime. */\nexport function runtimeOf(bundle: Bundle): Runtime {\n const { root, info } = bundle;\n return {\n source: \"bundle\",\n node: join(root, info.node.path),\n runtimeEntry: join(root, info.entries.runtime),\n cliEntry: join(root, info.entries.cli),\n bundle,\n };\n}\n\n/** A development checkout's runtime: `packages/runtime/dist/bin.js` beside this package. */\nfunction development(): Runtime | undefined {\n const root = packageRoot();\n const entry = resolve(root, \"..\", \"runtime\", \"dist\", \"bin.js\");\n if (!existsSync(entry)) return undefined;\n const cli = resolve(root, \"..\", \"cli\", \"dist\", \"bin.js\");\n return {\n source: \"development\",\n node: process.execPath,\n runtimeEntry: entry,\n ...(existsSync(cli) ? { cliEntry: cli } : {}),\n };\n}\n\n/**\n * Finds the runtime to spawn, downloading and setting up the pinned bundle when nothing nearer\n * exists. Throws `MOSTRA_PLATFORM_UNSUPPORTED`, `MOSTRA_ENV_RUNTIME_MISSING` (a\n * `MOSTRA_RUNTIME_BIN` that doesn't exist), `MOSTRA_ENV_BUNDLE_UNAVAILABLE`,\n * `MOSTRA_ENV_BUNDLE_INVALID` or `MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED`.\n */\nexport async function resolveRuntime(options: RuntimeOptions = {}): Promise<Runtime> {\n const env = options.env ?? process.env;\n const named = options.bundle ?? (env[\"MOSTRA_BUNDLE\"] || undefined);\n if (named !== undefined) return fromBundle(named, { ...options, env });\n const override = env[\"MOSTRA_RUNTIME_BIN\"];\n if (override) {\n if (!existsSync(override)) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_RUNTIME_MISSING\", {\n message: `MOSTRA_RUNTIME_BIN names ${override}, which doesn't exist.`,\n }),\n );\n }\n return { source: \"override\", node: process.execPath, runtimeEntry: override };\n }\n const enclosing = enclosingBundle();\n if (enclosing !== undefined) return fromBundle(enclosing, { ...options, env });\n const pins = readPins(env);\n if (pins !== undefined) {\n const bundle = await installPinned(pins, {\n env,\n platform: bundlePlatform(),\n signal: options.signal,\n onProgress: options.onProgress,\n });\n return runtimeOf(bundle);\n }\n const checkout = development();\n if (checkout !== undefined) return checkout;\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_UNAVAILABLE\", {\n message:\n \"This build of @mostra/sdk pins no runtime bundle and has no runtime beside it; set MOSTRA_BUNDLE to an extracted bundle.\",\n }),\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { _ as setupBundle, t as enclosingBundle } from "./runtime-HLIV9wFH.js";
|
|
3
|
+
import { RpcError, createDiagnostic } from "@mostra/protocol";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
//#region src/setup-main.ts
|
|
6
|
+
/**
|
|
7
|
+
* `mostra-setup [--root <bundle>]`: makes an extracted runtime bundle ready (D142). It checks every
|
|
8
|
+
* file against `files.json`, fetches the pinned verify browser and writes `.mostra-setup.json`.
|
|
9
|
+
* The bundle's `bin/mostra-setup` runs it for the bundle it sits in; the Rust crate (WP-12) and
|
|
10
|
+
* anyone who extracts an archive by hand run it once. It prints one JSON line on stdout,
|
|
11
|
+
* `{ "status": "ok", "bundle": { … } }` or `{ "status": "failed", "diagnostic": { … } }` (exit 3),
|
|
12
|
+
* and its progress on stderr.
|
|
13
|
+
*/
|
|
14
|
+
const STEPS = {
|
|
15
|
+
files: "Checking the bundle's files",
|
|
16
|
+
browser: "Fetching the verify browser"
|
|
17
|
+
};
|
|
18
|
+
async function main() {
|
|
19
|
+
const { values } = parseArgs({
|
|
20
|
+
options: { root: { type: "string" } },
|
|
21
|
+
strict: true
|
|
22
|
+
});
|
|
23
|
+
const root = values.root ?? enclosingBundle();
|
|
24
|
+
if (root === void 0) throw new RpcError(createDiagnostic("MOSTRA_ENV_BUNDLE_UNAVAILABLE", { message: "mostra-setup isn't inside a runtime bundle; pass --root <bundle directory>." }));
|
|
25
|
+
const marker = await setupBundle(root, { onStep: (step) => process.stderr.write(`mostra-setup: ${STEPS[step]}…\n`) });
|
|
26
|
+
process.stdout.write(`${JSON.stringify({
|
|
27
|
+
status: "ok",
|
|
28
|
+
bundle: {
|
|
29
|
+
root,
|
|
30
|
+
...marker
|
|
31
|
+
}
|
|
32
|
+
})}\n`);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
main().then((code) => {
|
|
36
|
+
process.exitCode = code;
|
|
37
|
+
}, (error) => {
|
|
38
|
+
const diagnostic = error instanceof RpcError ? error.diagnostic : createDiagnostic("MOSTRA_HOST_INTERNAL_ERROR", { message: `mostra-setup failed: ${error.message}` });
|
|
39
|
+
process.stdout.write(`${JSON.stringify({
|
|
40
|
+
status: "failed",
|
|
41
|
+
diagnostic
|
|
42
|
+
})}\n`);
|
|
43
|
+
process.stderr.write(`mostra-setup: ${diagnostic.message}\n`);
|
|
44
|
+
process.exitCode = 3;
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
export {};
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=setup-main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-main.js","names":[],"sources":["../src/setup-main.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `mostra-setup [--root <bundle>]`: makes an extracted runtime bundle ready (D142). It checks every\n * file against `files.json`, fetches the pinned verify browser and writes `.mostra-setup.json`.\n * The bundle's `bin/mostra-setup` runs it for the bundle it sits in; the Rust crate (WP-12) and\n * anyone who extracts an archive by hand run it once. It prints one JSON line on stdout,\n * `{ \"status\": \"ok\", \"bundle\": { … } }` or `{ \"status\": \"failed\", \"diagnostic\": { … } }` (exit 3),\n * and its progress on stderr.\n */\nimport { parseArgs } from \"node:util\";\nimport { createDiagnostic, RpcError } from \"@mostra/protocol\";\nimport { setupBundle } from \"./bundle/setup.ts\";\nimport { enclosingBundle } from \"./runtime.ts\";\n\nconst STEPS = { files: \"Checking the bundle's files\", browser: \"Fetching the verify browser\" };\n\nasync function main(): Promise<number> {\n const { values } = parseArgs({ options: { root: { type: \"string\" } }, strict: true });\n const root = values.root ?? enclosingBundle();\n if (root === undefined) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_ENV_BUNDLE_UNAVAILABLE\", {\n message: \"mostra-setup isn't inside a runtime bundle; pass --root <bundle directory>.\",\n }),\n );\n }\n const marker = await setupBundle(root, {\n onStep: (step) => process.stderr.write(`mostra-setup: ${STEPS[step]}…\\n`),\n });\n process.stdout.write(`${JSON.stringify({ status: \"ok\", bundle: { root, ...marker } })}\\n`);\n return 0;\n}\n\nmain().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n const diagnostic =\n error instanceof RpcError\n ? error.diagnostic\n : createDiagnostic(\"MOSTRA_HOST_INTERNAL_ERROR\", {\n message: `mostra-setup failed: ${(error as Error).message}`,\n });\n process.stdout.write(`${JSON.stringify({ status: \"failed\", diagnostic })}\\n`);\n process.stderr.write(`mostra-setup: ${diagnostic.message}\\n`);\n process.exitCode = 3;\n },\n);\n"],"mappings":";;;;;;;;;;;;;AAcA,MAAM,QAAQ;CAAE,OAAO;CAA+B,SAAS;AAA8B;AAE7F,eAAe,OAAwB;CACrC,MAAM,EAAE,WAAW,UAAU;EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,EAAE;EAAG,QAAQ;CAAK,CAAC;CACpF,MAAM,OAAO,OAAO,QAAQ,gBAAgB;CAC5C,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,SACR,iBAAiB,iCAAiC,EAChD,SAAS,8EACX,CAAC,CACH;CAEF,MAAM,SAAS,MAAM,YAAY,MAAM,EACrC,SAAS,SAAS,QAAQ,OAAO,MAAM,iBAAiB,MAAM,MAAM,IAAI,EAC1E,CAAC;CACD,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU;EAAE,QAAQ;EAAM,QAAQ;GAAE;GAAM,GAAG;EAAO;CAAE,CAAC,EAAE,GAAG;CACzF,OAAO;AACT;AAEA,KAAK,CAAC,CAAC,MACJ,SAAS;CACR,QAAQ,WAAW;AACrB,IACC,UAAmB;CAClB,MAAM,aACJ,iBAAiB,WACb,MAAM,aACN,iBAAiB,8BAA8B,EAC7C,SAAS,wBAAyB,MAAgB,UACpD,CAAC;CACP,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU;EAAE,QAAQ;EAAU;CAAW,CAAC,EAAE,GAAG;CAC5E,QAAQ,OAAO,MAAM,iBAAiB,WAAW,QAAQ,GAAG;CAC5D,QAAQ,WAAW;AACrB,CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostra/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Embed Mostra in a JavaScript host: createMostra({ home, ports }) spawns a verified runtime bundle, serves your ports and speaks the host protocol.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "The Mostra Authors",
|
|
7
|
+
"homepage": "https://github.com/mostra-dev/mostra/tree/main/packages/sdk#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/mostra-dev/mostra.git",
|
|
11
|
+
"directory": "packages/sdk"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/mostra-dev/mostra/issues",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"@mostra/source": "./src/index.ts",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"src",
|
|
27
|
+
"!src/**/*.test.ts"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22.19"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"provenance": true
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@mostra/protocol": "0.1.0",
|
|
38
|
+
"tar": "7.5.22",
|
|
39
|
+
"undici": "8.11.2"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@mostra/runtime": "0.1.0",
|
|
43
|
+
"@mostra/tools": "0.0.0",
|
|
44
|
+
"@types/node": "24.19.1",
|
|
45
|
+
"tsdown": "0.23.0",
|
|
46
|
+
"typescript": "7.0.2",
|
|
47
|
+
"vitest": "5.0.3"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"mostra",
|
|
51
|
+
"agent",
|
|
52
|
+
"artifact",
|
|
53
|
+
"sdk",
|
|
54
|
+
"host"
|
|
55
|
+
],
|
|
56
|
+
"bin": {
|
|
57
|
+
"mostra-setup": "./dist/setup-main.js"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsdown",
|
|
61
|
+
"typecheck": "tsc -b",
|
|
62
|
+
"test": "vitest run --project unit",
|
|
63
|
+
"api": "mostra-tools api",
|
|
64
|
+
"test:integration": "vitest run --project integration"
|
|
65
|
+
}
|
|
6
66
|
}
|