@mostra/sdk 0.1.0 → 0.3.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/dist/bundles.json +18 -18
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/{runtime-HLIV9wFH.js → runtime-CUbnK5Za.js} +14 -2
- package/dist/runtime-CUbnK5Za.js.map +1 -0
- package/dist/setup-main.js +1 -1
- package/package.json +3 -3
- package/src/bundle/cache.ts +27 -1
- package/src/mostra.ts +19 -1
- package/dist/runtime-HLIV9wFH.js.map +0 -1
package/dist/bundles.json
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.
|
|
4
|
-
"release": "https://github.com/mostra-dev/mostra/releases/download/v0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"release": "https://github.com/mostra-dev/mostra/releases/download/v0.3.0",
|
|
5
5
|
"assets": {
|
|
6
6
|
"darwin-arm64": {
|
|
7
|
-
"file": "mostra-0.
|
|
8
|
-
"sha256": "
|
|
9
|
-
"size":
|
|
10
|
-
"unpackedSize":
|
|
7
|
+
"file": "mostra-0.3.0-darwin-arm64.tar.gz",
|
|
8
|
+
"sha256": "8ef0bffea6c958eeef825b12d3b16457277c59cb7ad35f7de003a33488cbfd40",
|
|
9
|
+
"size": 198758975,
|
|
10
|
+
"unpackedSize": 782089171
|
|
11
11
|
},
|
|
12
12
|
"darwin-x64": {
|
|
13
|
-
"file": "mostra-0.
|
|
14
|
-
"sha256": "
|
|
15
|
-
"size":
|
|
16
|
-
"unpackedSize":
|
|
13
|
+
"file": "mostra-0.3.0-darwin-x64.tar.gz",
|
|
14
|
+
"sha256": "b1d52594404e39c8b177dc4696feec28c408dabf07449770185be3f942d87784",
|
|
15
|
+
"size": 201829020,
|
|
16
|
+
"unpackedSize": 790187035
|
|
17
17
|
},
|
|
18
18
|
"linux-x64": {
|
|
19
|
-
"file": "mostra-0.
|
|
20
|
-
"sha256": "
|
|
21
|
-
"size":
|
|
22
|
-
"unpackedSize":
|
|
19
|
+
"file": "mostra-0.3.0-linux-x64.tar.gz",
|
|
20
|
+
"sha256": "8058bab62f99f32a49812e011412461d223c9e0677e2577267a60e81c80f8372",
|
|
21
|
+
"size": 206055420,
|
|
22
|
+
"unpackedSize": 793045527
|
|
23
23
|
},
|
|
24
24
|
"linux-arm64": {
|
|
25
|
-
"file": "mostra-0.
|
|
26
|
-
"sha256": "
|
|
27
|
-
"size":
|
|
28
|
-
"unpackedSize":
|
|
25
|
+
"file": "mostra-0.3.0-linux-arm64.tar.gz",
|
|
26
|
+
"sha256": "6c9bdb802a9c1f2e1657867f76e29af4bcfe217efdd7f31d7db809ed01a63ccc",
|
|
27
|
+
"size": 204157448,
|
|
28
|
+
"unpackedSize": 783353480
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArtifactRef, ArtifactSummary, BundleFiles, BundleInfo, BundlePins, BundlePlatform, BundleSetup, CapabilityLink, ControlsPolicy, DependencyPolicy, Diagnostic, DraftMirror, EventFilter, EventRecord, InstanceCapabilities, InstanceInfo, LivePushParams, LivePushResult, MethodDefinition, PortSecretsGetParams, PortTrustedControlsActivatedParams, PublishReceipt, Results, ResultsMarkdown, SourceRef, StateGetResult, StatePatchParams, StatePatchResult, SubmissionEnvelope, SubmissionPolicy, SubmissionsDeliverResult, SubmitChannel, VerifyVerdict, ViewUrlParams, WaitCondition, WaitResult } from "@mostra/protocol";
|
|
1
|
+
import { ArtifactRef, ArtifactSummary, BundleFiles, BundleInfo, BundlePins, BundlePlatform, BundleSetup, CapabilityLink, ControlsPolicy, DependencyPolicy, Diagnostic, DraftMirror, EventFilter, EventRecord, InstanceCapabilities, InstanceInfo, LivePushParams, LivePushResult, MethodDefinition, PortIdentityResolveParams, PortSecretsGetParams, PortTrustedControlsActivatedParams, PublishReceipt, Results, ResultsMarkdown, SourceRef, StateGetResult, StatePatchParams, StatePatchResult, SubmissionEnvelope, SubmissionPolicy, SubmissionsDeliverResult, SubmitChannel, VerifyVerdict, ViewUrlParams, ViewerSpec, WaitCondition, WaitResult } from "@mostra/protocol";
|
|
2
2
|
//#region src/bundle/download.d.ts
|
|
3
3
|
/** Progress of one download, in bytes. */
|
|
4
4
|
interface DownloadProgress {
|
|
@@ -183,6 +183,14 @@ export declare function resolveRuntime(options?: RuntimeOptions): Promise<Runtim
|
|
|
183
183
|
* its stable ID, so a port may see the same call again after a crash.
|
|
184
184
|
*/
|
|
185
185
|
interface Ports {
|
|
186
|
+
/**
|
|
187
|
+
* Names the person behind a link minted without a viewer, from the request's headers (D143):
|
|
188
|
+
* `{ ref, name? }` (one viewer per `ref`), or `null` for the home's local user. Answer within
|
|
189
|
+
* 5 s; a failure refuses the link rather than guess.
|
|
190
|
+
*/
|
|
191
|
+
readonly identity?: {
|
|
192
|
+
resolve(request: PortIdentityResolveParams): ViewerSpec | null | Promise<ViewerSpec | null>;
|
|
193
|
+
};
|
|
186
194
|
/** Receives each submission once it is durable (D58, D105). Answer within 30 s. */
|
|
187
195
|
readonly submissions?: {
|
|
188
196
|
deliver(envelope: SubmissionEnvelope): SubmissionsDeliverResult | Promise<SubmissionsDeliverResult>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/bundle/download.ts","../src/bundle/setup.ts","../src/bundle/cache.ts","../src/bundle/tree.ts","../src/events.ts","../src/runtime.ts","../src/mostra.ts","../src/platform.ts","../src/version.ts"],"mappings":";;;UAqBiB;;WAEN;;WAEA;;;wBAmMK,UAAU;;;;KCtMd,cAAc,SAAS;;UAGlB;;WAEN;;WAEA,MAAM;;;KAIL;;UAGK;;WAEN,MAAM;;WAEN,SAAS;;WAET,WAAW,MAAM;;WAEjB;;;wBAIK,YAAY;;wBAKZ,QAAQ,KAAK;;wBAYP,WAAW,eAAe,QAAQ;;wBA4BlC,UAAU,QAAQ,SAAS,QAAQ;;wBAkBzC,YAAY;;wBAYN,WAAW,QAAQ,SAAS;;wBAkB5B,aAAa,QAAQ,SAAS;;;;;;;wBAiG9B,YAAY,cAAc,UAAS,eAAoB,QAAQ;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/bundle/download.ts","../src/bundle/setup.ts","../src/bundle/cache.ts","../src/bundle/tree.ts","../src/events.ts","../src/runtime.ts","../src/mostra.ts","../src/platform.ts","../src/version.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as safeRelative, S as linkStaysInside, _ as setupBundle, a as sdkVersion, b as describeTree, c as bundleDir, d as browsersDir, f as checkBrowser, g as readSetup, h as readBundle, i as runtimeOf, l as cacheRoot, m as offline, n as readPins, o as bundlePlatform, p as checkFiles, r as resolveRuntime, s as currentPlatform, t as enclosingBundle, u as installPinned, v as setupExtras, w as redactUrl, x as hashFile, y as checkTree } from "./runtime-
|
|
1
|
+
import { C as safeRelative, S as linkStaysInside, _ as setupBundle, a as sdkVersion, b as describeTree, c as bundleDir, d as browsersDir, f as checkBrowser, g as readSetup, h as readBundle, i as runtimeOf, l as cacheRoot, m as offline, n as readPins, o as bundlePlatform, p as checkFiles, r as resolveRuntime, s as currentPlatform, t as enclosingBundle, u as installPinned, v as setupExtras, w as redactUrl, x as hashFile, y as checkTree } from "./runtime-CUbnK5Za.js";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { ARTIFACT_PROGRESS, EVENTS_NOTIFY, EventsNotifyParams, HOST_PROTOCOL_REVISIONS, LineSplitter, RpcError, RpcPeer, WAIT_MAX_MS, artifactPublishMethod, artifactVerifyMethod, createDiagnostic, encodeLine, eventsAckMethod, eventsSubscribeMethod, eventsUnsubscribeMethod, livePushMethod, mostraInitializeMethod, portDraftsMirrorMethod, portSecretsGetMethod, portSubmissionsDeliverMethod, portTrustedControlsActivatedMethod, portTrustedControlsPolicyMethod, resultsGetMethod, stateGetMethod, statePatchMethod, viewUrlMethod, waitMethod } from "@mostra/protocol";
|
|
3
|
+
import { ARTIFACT_PROGRESS, EVENTS_NOTIFY, EventsNotifyParams, HOST_PROTOCOL_REVISIONS, LineSplitter, RpcError, RpcPeer, WAIT_MAX_MS, artifactPublishMethod, artifactVerifyMethod, createDiagnostic, encodeLine, eventsAckMethod, eventsSubscribeMethod, eventsUnsubscribeMethod, livePushMethod, mostraInitializeMethod, portDraftsMirrorMethod, portIdentityResolveMethod, portSecretsGetMethod, portSubmissionsDeliverMethod, portTrustedControlsActivatedMethod, portTrustedControlsPolicyMethod, resultsGetMethod, stateGetMethod, statePatchMethod, viewUrlMethod, waitMethod } from "@mostra/protocol";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
//#region src/events.ts
|
|
6
6
|
/**
|
|
@@ -221,6 +221,7 @@ var EventStream = class {
|
|
|
221
221
|
*/
|
|
222
222
|
/** The port methods the SDK serves, by port. */
|
|
223
223
|
const PORT_METHODS = {
|
|
224
|
+
identity: [portIdentityResolveMethod],
|
|
224
225
|
submissions: [portSubmissionsDeliverMethod],
|
|
225
226
|
drafts: [portDraftsMirrorMethod],
|
|
226
227
|
secrets: [portSecretsGetMethod],
|
|
@@ -239,6 +240,7 @@ function closedError(message) {
|
|
|
239
240
|
/** The handler for one port method, its params already checked. */
|
|
240
241
|
function portHandler(ports, method) {
|
|
241
242
|
switch (method) {
|
|
243
|
+
case portIdentityResolveMethod.method: return ports.identity && ((params) => ports.identity?.resolve(params));
|
|
242
244
|
case portSubmissionsDeliverMethod.method: return ports.submissions && ((params) => ports.submissions?.deliver(params));
|
|
243
245
|
case portDraftsMirrorMethod.method: return ports.drafts && ((params) => ports.drafts?.mirror(params));
|
|
244
246
|
case portSecretsGetMethod.method: return ports.secrets && ((params) => ports.secrets?.get(params));
|
|
@@ -379,7 +381,7 @@ async function createMostra(options) {
|
|
|
379
381
|
options.signal?.addEventListener("abort", abort, { once: true });
|
|
380
382
|
const homeConfig = {
|
|
381
383
|
path: home,
|
|
382
|
-
...options.expectPorts !== false
|
|
384
|
+
...options.expectPorts !== false ? { ports: names } : {},
|
|
383
385
|
...options.settings?.submission ? { submission: options.settings.submission } : {},
|
|
384
386
|
...options.settings?.submitChannels ? { submitChannels: options.settings.submitChannels } : {},
|
|
385
387
|
...options.settings?.dependencies ? { dependencies: options.settings.dependencies } : {}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/events.ts","../src/mostra.ts"],"sourcesContent":["/**\n * Events as an async iterator (IN-08, D101): pages from `events/subscribe`, in cursor order. A\n * consumer that falls behind pauses the subscription instead of buffering without bound or\n * stalling the connection's other calls: past `highWaterMark` pages it unsubscribes, and once it\n * has caught up it subscribes again after the last cursor it received, so nothing is missed or\n * repeated. With a `name`, a page is acknowledged (`events/ack`) when the next one is asked for,\n * which is when the consumer has handled it; a stream of the same name later resumes there.\n */\nimport {\n createDiagnostic,\n type Diagnostic,\n type EventFilter,\n type EventRecord,\n EventsNotifyParams,\n eventsAckMethod,\n eventsSubscribeMethod,\n eventsUnsubscribeMethod,\n type MethodDefinition,\n RpcError,\n} from \"@mostra/protocol\";\n\n/** One page of events. */\nexport interface EventPage {\n /** The events, in cursor order. */\n readonly events: readonly EventRecord[];\n /** Everything up to this cursor was examined: the cursor to resume after. */\n readonly cursor: string;\n /** Set when compaction removed events in this range (`MOSTRA_HOST_CURSOR_COMPACTED`). */\n readonly compacted?: Diagnostic;\n}\n\n/** Options of a stream. */\nexport interface EventStreamOptions {\n /** Which events: artifacts and type patterns. Default: every event. */\n readonly filter?: EventFilter;\n /** Start after this cursor. Default: a named stream's acknowledged cursor, else now. */\n readonly after?: string;\n /** A durable subscriber name: pages are acknowledged under it as they are handled. */\n readonly name?: string;\n /** Pages held before the subscription pauses. Default 16. */\n readonly highWaterMark?: number;\n /** Ends the stream. */\n readonly signal?: AbortSignal;\n}\n\n/** What a stream needs of the session. */\nexport interface EventSession {\n call<P, R>(method: MethodDefinition<P, R>, params: P): Promise<R>;\n /** Registers a handler for `events/notify`; returns its removal. */\n onNotification(handler: (params: unknown) => void): () => void;\n /** Resolves when the session ends. */\n readonly closed: Promise<void>;\n}\n\n/** Opens a stream; nothing is subscribed until the first page is asked for. */\nexport function openEventStream(\n session: EventSession,\n options: EventStreamOptions,\n): AsyncIterable<EventPage> {\n return {\n [Symbol.asyncIterator]: () => new EventStream(session, options),\n };\n}\n\nclass EventStream implements AsyncIterator<EventPage> {\n readonly #session: EventSession;\n readonly #options: EventStreamOptions;\n readonly #high: number;\n readonly #queue: EventPage[] = [];\n #subscription: string | undefined;\n /** The cursor of the last page received, where a resumed subscription starts. */\n #received: string | undefined;\n /** The cursor of the last page handed out; handled once the next page is asked for. */\n #handedOut: string | undefined;\n /** The cursor of the last page the consumer handled, and of the last acknowledged. */\n #handled: string | undefined;\n #acked: string | undefined;\n #paused = false;\n /**\n * Pages that arrived while a subscribe was in flight, for a subscription not known yet: the\n * answer and its first page can reach the session in one chunk, and the page is dispatched\n * before the code awaiting the answer resumes. Kept until the answer names its ID.\n */\n #early: EventsNotifyParams[] | undefined;\n /** The unsubscribe of a pause; its answer means no page of that subscription follows. */\n #pausing: Promise<void> | undefined;\n /** A subscribe whose answer is on its way (`#subscribe`). */\n #subscribing: Promise<void> | undefined;\n #started = false;\n #ended: { error?: unknown } | undefined;\n #wake: (() => void) | undefined;\n readonly #removeHandler: () => void;\n\n constructor(session: EventSession, options: EventStreamOptions) {\n this.#session = session;\n this.#options = options;\n this.#high = Math.max(1, options.highWaterMark ?? 16);\n this.#removeHandler = session.onNotification((params) => this.#receive(params));\n void session.closed.then(() =>\n this.#end(\n new RpcError(\n createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", {\n message: \"The Mostra instance exited while its events were being read.\",\n }),\n ),\n ),\n );\n options.signal?.addEventListener(\"abort\", () => void this.return(), { once: true });\n }\n\n #receive(params: unknown): void {\n const parsed = EventsNotifyParams.safeParse(params);\n if (!parsed.success) return;\n if (parsed.data.subscriptionId !== this.#subscription) {\n this.#early?.push(parsed.data);\n return;\n }\n this.#accept(parsed.data);\n }\n\n #accept({ events, cursor, compacted }: EventsNotifyParams): void {\n this.#queue.push({ events, cursor, ...(compacted ? { compacted } : {}) });\n this.#received = cursor;\n if (this.#queue.length >= this.#high && !this.#paused) this.#pausing = this.#pause();\n this.#wake?.();\n }\n\n /**\n * Subscribes after `after`. While the answer is on its way the call is `#subscribing`, so\n * `return()` can wait for it and end the subscription it names (GPT review finding 5).\n */\n #subscribe(after: string | undefined): Promise<void> {\n const opening = this.#open(after);\n this.#subscribing = opening;\n return opening.finally(() => {\n if (this.#subscribing === opening) this.#subscribing = undefined;\n });\n }\n\n async #open(after: string | undefined): Promise<void> {\n this.#early = [];\n let answer: { subscriptionId: string; cursor: string };\n let early: EventsNotifyParams[];\n try {\n answer = await this.#session.call(eventsSubscribeMethod, {\n ...(this.#options.filter ? { filter: this.#options.filter } : {}),\n ...(after !== undefined ? { after } : {}),\n ...(this.#options.name ? { name: this.#options.name } : {}),\n });\n } finally {\n early = this.#early;\n this.#early = undefined;\n }\n // Synchronous from here: no page can be dispatched before the ID is known.\n this.#subscription = answer.subscriptionId;\n this.#received ??= answer.cursor;\n // The pages of this subscription that came before its answer was handled, in order.\n for (const page of early) if (page.subscriptionId === answer.subscriptionId) this.#accept(page);\n }\n\n async #pause(): Promise<void> {\n this.#paused = true;\n const id = this.#subscription;\n if (id === undefined) return;\n // What the consumer handled is acknowledged while the subscription still exists: the ack goes\n // out before the unsubscribe on the connection, which keeps their order.\n const acked = this.#sendAck(id);\n // Pages already on their way still arrive under this ID and are kept. The answer comes after\n // them on the connection, so once it is here the subscription is over.\n await this.#session\n .call(eventsUnsubscribeMethod, { subscriptionId: id })\n .catch(() => undefined);\n // A pause runs from a page's arrival, where nobody awaits it, so it never rejects (Opus review\n // finding 7): an ack the instance refused (or a connection gone) ends the stream with that\n // error, which the consumer's next() then throws.\n await acked.catch((error: unknown) => this.#end(error));\n if (this.#subscription === id) this.#subscription = undefined;\n }\n\n async #resume(): Promise<void> {\n await this.#pausing;\n this.#pausing = undefined;\n this.#paused = false;\n await this.#subscribe(this.#received);\n }\n\n /**\n * Acknowledges what the consumer handled under subscription `id`, if a named stream has handled\n * more than it acknowledged. The line is written when this is called (the session writes each\n * call at once), so it is ordered before anything sent after it.\n */\n #sendAck(id: string): Promise<void> {\n const cursor = this.#handled;\n if (!this.#options.name || cursor === undefined || cursor === this.#acked)\n return Promise.resolve();\n this.#acked = cursor;\n return this.#session\n .call(eventsAckMethod, { subscriptionId: id, cursor })\n .then(() => undefined);\n }\n\n #end(error?: unknown): void {\n if (this.#ended) return;\n this.#ended = error === undefined ? {} : { error };\n this.#removeHandler();\n this.#wake?.();\n }\n\n async next(): Promise<IteratorResult<EventPage>> {\n if (!this.#started) {\n this.#started = true;\n await this.#subscribe(this.#options.after);\n }\n // Asking for the next page means the consumer handled the one before it.\n if (this.#handedOut !== undefined) this.#handled = this.#handedOut;\n if (this.#paused && !this.#ended && this.#queue.length <= this.#high / 2) await this.#resume();\n // Never under a subscription being paused: its unsubscribe may already be on its way, and\n // the pause acknowledges what was handled before it.\n if (!this.#paused && this.#subscription !== undefined) await this.#sendAck(this.#subscription);\n for (;;) {\n const page = this.#queue.shift();\n if (page !== undefined) {\n this.#handedOut = page.cursor;\n return { done: false, value: page };\n }\n if (this.#ended) {\n if (this.#ended.error !== undefined) throw this.#ended.error;\n return { done: true, value: undefined };\n }\n if (this.#paused) {\n await this.#resume();\n await this.#sendAck(this.#subscription as string);\n }\n await new Promise<void>((done) => {\n this.#wake = done;\n });\n this.#wake = undefined;\n }\n }\n\n /**\n * Ends the stream: the subscription ends, and a named stream acknowledges every page the\n * consumer handled, never the last one handed out (the loop may have stopped inside it).\n */\n async return(): Promise<IteratorResult<EventPage>> {\n this.#end();\n this.#queue.length = 0;\n await this.#pausing;\n // A subscribe on its way names a subscription that exists on the instance once it is\n // answered: wait for it, so it is ended below like any other.\n await this.#subscribing?.catch(() => undefined);\n const id = this.#subscription;\n if (id !== undefined) {\n this.#subscription = undefined;\n const acked = this.#sendAck(id);\n await this.#session\n .call(eventsUnsubscribeMethod, { subscriptionId: id })\n .catch(() => undefined);\n await acked.catch(() => undefined);\n } else if (this.#options.name && this.#handled !== undefined && this.#handled !== this.#acked) {\n // Paused when it ended, with pages handled since: a subscription of the name, just long\n // enough to acknowledge them (its pages are ignored; the handler is gone).\n await this.#subscribe(this.#received).catch(() => undefined);\n const again = this.#subscription;\n if (again !== undefined) {\n this.#subscription = undefined;\n const acked = this.#sendAck(again);\n await this.#session\n .call(eventsUnsubscribeMethod, { subscriptionId: again })\n .catch(() => undefined);\n await acked.catch(() => undefined);\n }\n }\n return { done: true, value: undefined };\n }\n}\n","/**\n * `createMostra` (HO-04, D25, D58, D59): a JavaScript host's handle on its own Mostra instance.\n * It finds a verified runtime (the pinned bundle, downloaded once), spawns `mostra-runtime host`\n * for the host's home over stdio, opens the protocol session, serves the host's ports and offers\n * the calls every host makes. The instance lives exactly as long as this handle: `close()` ends\n * it, and so does the host's process exiting.\n *\n * ```ts\n * const mostra = await createMostra({\n * home: \"/var/lib/inbox/mostra\",\n * client: { name: \"inbox-app\", version: \"1.4.0\" },\n * ports: { submissions: { deliver: async (envelope) => ({ accepted: true }) } },\n * });\n * const receipt = await mostra.publish(\"/work/inbox\");\n * const outcome = await mostra.wait(receipt.artifactId, \"submitted\");\n * await mostra.close();\n * ```\n */\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport {\n type AnyMethod,\n ARTIFACT_PROGRESS,\n type ArtifactRef,\n type ArtifactSummary,\n artifactPublishMethod,\n artifactVerifyMethod,\n type CapabilityLink,\n type ControlsPolicy,\n createDiagnostic,\n type DependencyPolicy,\n type Diagnostic,\n type DraftMirror,\n EVENTS_NOTIFY,\n encodeLine,\n HOST_PROTOCOL_REVISIONS,\n type HomeConfig,\n type InstanceCapabilities,\n type InstanceInfo,\n LineSplitter,\n type LivePushParams,\n type LivePushResult,\n livePushMethod,\n type MethodDefinition,\n type MostraInitializeResult,\n mostraInitializeMethod,\n type PortName,\n type PortSecretsGetParams,\n type PortTrustedControlsActivatedParams,\n type PublishReceipt,\n portDraftsMirrorMethod,\n portSecretsGetMethod,\n portSubmissionsDeliverMethod,\n portTrustedControlsActivatedMethod,\n portTrustedControlsPolicyMethod,\n type Results,\n type ResultsMarkdown,\n RpcError,\n RpcPeer,\n resultsGetMethod,\n type SourceRef,\n type StateGetResult,\n type StatePatchParams,\n type StatePatchResult,\n type SubmissionEnvelope,\n type SubmissionPolicy,\n type SubmissionsDeliverResult,\n type SubmitChannel,\n stateGetMethod,\n statePatchMethod,\n type VerifyVerdict,\n type ViewUrlParams,\n viewUrlMethod,\n WAIT_MAX_MS,\n type WaitCondition,\n type WaitResult,\n waitMethod,\n} from \"@mostra/protocol\";\nimport type { InstallProgress } from \"./bundle/cache.ts\";\nimport type { Environment } from \"./bundle/setup.ts\";\nimport { type EventPage, type EventStreamOptions, openEventStream } from \"./events.ts\";\nimport { type Runtime, resolveRuntime } from \"./runtime.ts\";\nimport { sdkVersion } from \"./version.ts\";\n\n/**\n * The ports a host may serve (INTERFACES §7). Each is optional and has a standalone default;\n * Mostra calls a port only on the instance this handle spawned, and every call is idempotent by\n * its stable ID, so a port may see the same call again after a crash.\n */\nexport interface Ports {\n /** Receives each submission once it is durable (D58, D105). Answer within 30 s. */\n readonly submissions?: {\n deliver(\n envelope: SubmissionEnvelope,\n ): SubmissionsDeliverResult | Promise<SubmissionsDeliverResult>;\n };\n /** Receives each viewer draft's latest revision, best effort, never retried (IN-06). */\n readonly drafts?: { mirror(draft: DraftMirror): void | Promise<void> };\n /** Answers `secret()` first, before the home's store (D131); `null` falls back. */\n readonly secrets?: {\n get(request: PortSecretsGetParams): string | null | Promise<string | null>;\n };\n /** Decides each view's submit channels and trusted controls (D108). Answer within 5 s. */\n readonly trustedControls?: {\n policy(artifact: ArtifactSummary): ControlsPolicy | Promise<ControlsPolicy>;\n activated?(event: PortTrustedControlsActivatedParams): void | Promise<void>;\n };\n}\n\n/** Home settings a host chooses (INTERFACES §6 `HomeConfig`), kept in the home's `config.json`. */\nexport interface HomeSettings {\n /** The submission policy for artifacts whose publish names none (D102). */\n readonly submission?: SubmissionPolicy;\n /** The channels that may submit (D40, D108); absent, both. */\n readonly submitChannels?: readonly SubmitChannel[];\n /** How packages enter an artifact's lockfile (D43, D95). */\n readonly dependencies?: DependencyPolicy;\n}\n\n/** Options of {@link createMostra}. */\nexport interface MostraOptions {\n /** The home this host owns (D45). Created 0700 when missing. */\n readonly home: string;\n /**\n * Who the host is. The name owns the host's deliveries across restarts (D105), so keep it\n * stable; it defaults to `mostra-sdk`.\n */\n readonly client?: { readonly name: string; readonly version?: string };\n /** The ports this host serves. */\n readonly ports?: Ports;\n /**\n * Whether submissions made while this host is away wait for it (D105): the registered ports\n * are recorded as ports this host always provides. Default `true`; `false` leaves the home's\n * record as it is.\n */\n readonly expectPorts?: boolean;\n /** Home settings, kept in the home's `config.json` for every later client. */\n readonly settings?: HomeSettings;\n /** An extracted runtime bundle to use instead of the pinned one. */\n readonly bundle?: string;\n /** The gateway's bind address and URL host (D99); loopback by default. */\n readonly bind?: string;\n /** The host name URLs use, which a wildcard `bind` needs (D99). */\n readonly urlHost?: string;\n /** The instance's environment. Default: this process's. */\n readonly env?: Environment;\n /** Each line the instance logs (JSON, on its stderr). A callback that throws is ignored. */\n readonly onLog?: (line: string) => void;\n /** Progress of the first download or setup of the runtime bundle. A throw is ignored. */\n readonly onProgress?: (progress: InstallProgress) => void;\n /**\n * An exception a port threw; the instance got `MOSTRA_HOST_INTERNAL_ERROR` and will retry. A\n * callback that throws is ignored, and the instance is answered all the same.\n */\n readonly onPortError?: (error: unknown, method: string) => void;\n /** Gives up finding the runtime and starting the instance. */\n readonly signal?: AbortSignal;\n}\n\n/** How the instance ended. */\nexport interface InstanceExit {\n /** Its exit code: 0 after a clean stop. */\n readonly code: number | null;\n /** The signal that ended it, if one did. */\n readonly signal: NodeJS.Signals | null;\n}\n\n/** An artifact by ID (`art_…`), by source path, or as the protocol's reference. */\nexport type ArtifactInput = string | ArtifactRef;\n\n/** A host's handle on its instance. */\nexport interface Mostra {\n /** The instance: release, home, platform, PID and mode. */\n readonly instance: InstanceInfo;\n /** What the instance serves. */\n readonly capabilities: InstanceCapabilities;\n /** The negotiated host protocol revision. */\n readonly revision: string;\n /** The session's warnings (an unsupported port, for example). */\n readonly warnings: readonly Diagnostic[];\n /** The runtime it runs on. */\n readonly runtime: Runtime;\n /** Resolves when the instance has exited, for whatever reason. */\n readonly closed: Promise<InstanceExit>;\n /** Calls any host protocol method by its definition from `@mostra/protocol`. */\n call<P, R>(method: MethodDefinition<P, R>, params: P, options?: CallOptions): Promise<R>;\n /** `artifact/publish`: verifies (D41) and publishes; durable before it resolves (H-07). */\n publish(\n source: ArtifactInput,\n options?: {\n readonly force?: boolean;\n readonly policy?: SubmissionPolicy;\n readonly requestId?: string;\n },\n ): Promise<PublishReceipt>;\n /** `artifact/verify`: one verdict, never a publish (D138). */\n verify(\n source: ArtifactInput,\n options?: { readonly screenshots?: \"on-failure\" | \"always\" | \"never\" },\n ): Promise<VerifyVerdict>;\n /**\n * `wait` (IN-10, D103): until the condition holds or `timeoutMs` passes (default: the longest\n * timer, about 24.8 days). `still_waiting` carries the cursor to wait from next; an aborted wait\n * rejects with the signal's reason and loses nothing.\n */\n wait(\n artifact: ArtifactInput,\n until: WaitCondition,\n options?: {\n readonly after?: string;\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n },\n ): Promise<WaitResult>;\n /** `results/get`: a submission as JSON (the default) or Markdown (INTERFACES §8). */\n results(\n artifact: ArtifactInput,\n options?: { readonly submission?: string; readonly format?: \"json\" },\n ): Promise<Results>;\n /** `results/get` as Markdown, for an agent to read. */\n results(\n artifact: ArtifactInput,\n options: { readonly submission?: string; readonly format: \"md\" },\n ): Promise<ResultsMarkdown>;\n /** `state/get`: artifact-scoped fields (D63). */\n getState(artifact: ArtifactInput, ids?: readonly string[]): Promise<StateGetResult>;\n /** `state/patch`: writes artifact-scoped fields through compare-and-set (D63). */\n patchState(\n artifact: ArtifactInput,\n patch: Omit<StatePatchParams, \"artifact\">,\n ): Promise<StatePatchResult>;\n /** `live/push`: a live source's next value (D56). */\n pushLive(\n artifact: ArtifactInput,\n push: Omit<LivePushParams, \"artifact\">,\n ): Promise<LivePushResult>;\n /** `view/url`: a new capability link (D97). */\n viewUrl(\n artifact: ArtifactInput,\n options?: Omit<ViewUrlParams, \"artifact\">,\n ): Promise<CapabilityLink>;\n /**\n * The events matching `options.filter`, page by page, in cursor order, with no gap across a\n * pause (`events/subscribe`). With a `name`, each page is acknowledged when the next one is\n * asked for, so a later stream of that name resumes after the last page handled.\n */\n events(options?: EventStreamOptions): AsyncIterable<EventPage>;\n /** Ends the instance: its stdio closes, and it is stopped if it doesn't exit within 10 s. */\n close(): Promise<InstanceExit>;\n}\n\n/** Options of one call. */\nexport interface CallOptions {\n /** Gives up after this many milliseconds with `MOSTRA_HOST_TIMEOUT`. Default: none. */\n readonly timeoutMs?: number;\n}\n\n/** The port methods the SDK serves, by port. */\nconst PORT_METHODS = {\n submissions: [portSubmissionsDeliverMethod],\n drafts: [portDraftsMirrorMethod],\n secrets: [portSecretsGetMethod],\n trustedControls: [portTrustedControlsPolicyMethod, portTrustedControlsActivatedMethod],\n} as const satisfies Record<keyof Ports, readonly AnyMethod[]>;\n\n/** The client name of an SDK host that names none. */\nexport const SDK_CLIENT_NAME = \"mostra-sdk\";\n\n/** `art_…` is an artifact ID; anything else a source path, resolved against the working directory. */\nexport function artifactRef(input: ArtifactInput): ArtifactRef & SourceRef {\n if (typeof input !== \"string\") return input as ArtifactRef & SourceRef;\n return input.startsWith(\"art_\") ? { artifactId: input } : { path: resolve(input) };\n}\n\nfunction closedError(message: string): RpcError {\n return new RpcError(createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", { message }));\n}\n\n/** The handler for one port method, its params already checked. */\nfunction portHandler(ports: Ports, method: string): ((params: unknown) => unknown) | undefined {\n switch (method) {\n case portSubmissionsDeliverMethod.method:\n return (\n ports.submissions && ((params) => ports.submissions?.deliver(params as SubmissionEnvelope))\n );\n case portDraftsMirrorMethod.method:\n return ports.drafts && ((params) => ports.drafts?.mirror(params as DraftMirror));\n case portSecretsGetMethod.method:\n return ports.secrets && ((params) => ports.secrets?.get(params as PortSecretsGetParams));\n case portTrustedControlsPolicyMethod.method:\n return (\n ports.trustedControls &&\n ((params) =>\n ports.trustedControls?.policy((params as { artifact: ArtifactSummary }).artifact))\n );\n case portTrustedControlsActivatedMethod.method:\n return (\n ports.trustedControls &&\n (async (params) => {\n await ports.trustedControls?.activated?.(params as PortTrustedControlsActivatedParams);\n return {};\n })\n );\n default:\n return undefined;\n }\n}\n\n/** The port names `ports` registers; anything unknown is a mistake worth failing on. */\nfunction portNames(ports: Ports): PortName[] {\n const names: PortName[] = [];\n for (const [name, value] of Object.entries(ports)) {\n if (value === undefined) continue;\n if (!(name in PORT_METHODS)) {\n throw new TypeError(\n `createMostra: no port \"${name}\" (the SDK serves ${Object.keys(PORT_METHODS).join(\", \")}).`,\n );\n }\n names.push(name as PortName);\n }\n return names;\n}\n\n/** Ends the child: stdin closed, then SIGTERM after `graceMs`, then SIGKILL after 5 s more. */\nfunction stopChild(\n child: ChildProcess,\n exited: Promise<InstanceExit>,\n graceMs: number,\n): Promise<InstanceExit> {\n child.stdin?.end();\n const term = setTimeout(() => child.kill(\"SIGTERM\"), graceMs);\n const kill = setTimeout(() => child.kill(\"SIGKILL\"), graceMs + 5000);\n return exited.finally(() => {\n clearTimeout(term);\n clearTimeout(kill);\n });\n}\n\n/** `callback`, made unable to throw into its caller. */\nfunction guarded<A extends unknown[]>(\n callback: ((...args: A) => void) | undefined,\n): ((...args: A) => void) | undefined {\n if (callback === undefined) return undefined;\n return (...args: A) => {\n try {\n callback(...args);\n } catch {\n // The host's own code failed; Mostra's work goes on.\n }\n };\n}\n\n/**\n * Spawns an instance for `home` and opens its session. Rejects with the instance's own diagnostic\n * when it can't start (`MOSTRA_HOME_LOCKED`, `MOSTRA_PLATFORM_UNSUPPORTED` …), or with the\n * runtime's (`MOSTRA_ENV_BUNDLE_*`) when no verified runtime can be found.\n */\nexport async function createMostra(options: MostraOptions): Promise<Mostra> {\n // The host's callbacks run inside Mostra's own handlers (a pipe's data listener, the RPC\n // peer's error path, a download's progress): one that throws must never escape into the host's\n // process as an uncaught exception or unhandled rejection, nor stop an answer (Opus review\n // finding 6). A callback that throws is ignored.\n const onLog = guarded(options.onLog);\n const onProgress = guarded(options.onProgress);\n const onPortError = guarded(options.onPortError);\n const ports = options.ports ?? {};\n const names = portNames(ports);\n const env = options.env ?? process.env;\n const home = resolve(options.home);\n const runtime = await resolveRuntime({\n bundle: options.bundle,\n env,\n signal: options.signal,\n ...(onProgress ? { onProgress } : {}),\n });\n options.signal?.throwIfAborted();\n const args = [runtime.runtimeEntry, \"host\", \"--home\", home];\n if (options.bind !== undefined) args.push(\"--bind\", options.bind);\n if (options.urlHost !== undefined) args.push(\"--url-host\", options.urlHost);\n const child = spawn(runtime.node, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: env as NodeJS.ProcessEnv,\n });\n const logTail: string[] = [];\n const exited = new Promise<InstanceExit>((done) => {\n child.on(\"close\", (code, signal) => done({ code, signal }));\n child.on(\"error\", () => done({ code: null, signal: null }));\n });\n let spawnError: Error | undefined;\n child.on(\"error\", (error) => {\n spawnError = error;\n });\n const errLines = new LineSplitter();\n child.stderr?.setEncoding(\"utf8\");\n child.stderr?.on(\"data\", (chunk: string) => {\n for (const line of errLines.push(chunk)) {\n logTail.push(line);\n if (logTail.length > 20) logTail.shift();\n onLog?.(line);\n }\n });\n\n const notificationHandlers = new Map<string, Set<(params: unknown) => void>>();\n const peer = new RpcPeer({\n send: (message) => {\n if (child.stdin?.writable) child.stdin.write(encodeLine(message));\n },\n onRequest: async (method, params) => {\n const definition = Object.values(PORT_METHODS)\n .flat()\n .find((candidate) => candidate.method === method) as\n | MethodDefinition<unknown, unknown>\n | undefined;\n const handler = definition && portHandler(ports, method);\n if (!definition || !handler) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_HOST_METHOD_UNKNOWN\", {\n message: `This host serves no method ${method}.`,\n }),\n -32601,\n );\n }\n const parsed = definition.params.safeParse(params);\n if (!parsed.success) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_HOST_INVALID_PARAMS\", {\n message: `The params of ${method} don't match its schema.`,\n }),\n -32602,\n );\n }\n const answer = await handler(parsed.data);\n const checked = definition.result.safeParse(answer ?? null);\n if (!checked.success) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_HOST_INTERNAL_ERROR\", {\n message: `The host's ${method} answered something its schema refuses.`,\n }),\n );\n }\n return checked.data;\n },\n onNotification: (method, params) => {\n for (const handler of notificationHandlers.get(method) ?? []) handler(params);\n },\n onInternalError: (error, method) => onPortError?.(error, method),\n });\n const lines = new LineSplitter();\n child.stdout?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n for (const line of lines.push(chunk)) peer.receiveLine(line);\n });\n child.stdout?.on(\"close\", () => {\n peer.close(\n createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", {\n message: `The Mostra instance for ${home} exited${logTail.length > 0 ? `; its last log line: ${logTail.at(-1)}` : \"\"}.`,\n }),\n );\n });\n // A pipe to an instance that died fails its next write (EPIPE) on its own schedule. Without a\n // listener that error is an uncaught exception in the host's own process: every pipe has one,\n // and a write that failed ends the session at once, as the instance's exit does.\n child.stdin?.on(\"error\", (error: NodeJS.ErrnoException) => {\n peer.close(\n createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", {\n message: `The Mostra instance for ${home} stopped reading (${error.code ?? error.message}).`,\n }),\n );\n });\n child.stdout?.on(\"error\", () => {});\n child.stderr?.on(\"error\", () => {});\n\n const abort = (): void => {\n void stopChild(child, exited, 0);\n };\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n const homeConfig: HomeConfig = {\n path: home,\n ...(options.expectPorts !== false && names.length > 0 ? { ports: names } : {}),\n ...(options.settings?.submission ? { submission: options.settings.submission } : {}),\n ...(options.settings?.submitChannels\n ? { submitChannels: options.settings.submitChannels }\n : {}),\n ...(options.settings?.dependencies ? { dependencies: options.settings.dependencies } : {}),\n };\n let session: MostraInitializeResult;\n try {\n session = await peer.call(mostraInitializeMethod, {\n client: {\n name: options.client?.name ?? SDK_CLIENT_NAME,\n version: options.client?.version ?? sdkVersion(),\n },\n revisions: [...HOST_PROTOCOL_REVISIONS],\n capabilities: { notifications: [EVENTS_NOTIFY, ARTIFACT_PROGRESS] },\n ports: names,\n home: homeConfig,\n });\n } catch (error) {\n await stopChild(child, exited, 2000);\n if (spawnError) throw closedError(`Couldn't start ${runtime.node}: ${spawnError.message}`);\n throw error;\n } finally {\n options.signal?.removeEventListener(\"abort\", abort);\n }\n\n const call = <P, R>(\n method: MethodDefinition<P, R>,\n params: P,\n callOptions?: CallOptions,\n ): Promise<R> =>\n peer.call(\n method,\n params,\n callOptions?.timeoutMs !== undefined ? { timeoutMs: callOptions.timeoutMs } : {},\n );\n let closing: Promise<InstanceExit> | undefined;\n\n const mostra: Mostra = {\n instance: session.instance,\n capabilities: session.capabilities,\n revision: session.revision,\n warnings: session.warnings,\n runtime,\n closed: exited,\n call,\n publish: (source, publishOptions = {}) =>\n call(artifactPublishMethod, { source: artifactRef(source), ...publishOptions }),\n verify: (source, verifyOptions = {}) =>\n call(artifactVerifyMethod, { source: artifactRef(source), ...verifyOptions }),\n wait: (artifact, until, waitOptions = {}) => {\n const signal = waitOptions.signal;\n // Checked before the request goes out: nothing is sent for a wait already given up, so no\n // answer is left without a handler (GPT review finding 4).\n if (signal?.aborted) return Promise.reject(signal.reason);\n const pending = call(waitMethod, {\n artifact: artifactRef(artifact),\n until,\n timeoutMs: waitOptions.timeoutMs ?? WAIT_MAX_MS,\n ...(waitOptions.after !== undefined ? { after: waitOptions.after } : {}),\n });\n if (!signal) return pending;\n // The instance's wait runs on until its own timeout; its late answer, or the connection's\n // end, is handled here and dropped.\n return new Promise<WaitResult>((done, fail) => {\n const onAbort = (): void => fail(signal.reason);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n pending.then(done, fail).finally(() => signal.removeEventListener(\"abort\", onAbort));\n });\n },\n results: ((\n artifact: ArtifactInput,\n resultsOptions: { submission?: string; format?: \"json\" | \"md\" } = {},\n ) =>\n call(resultsGetMethod, {\n artifact: artifactRef(artifact),\n ...resultsOptions,\n })) as Mostra[\"results\"],\n getState: (artifact, ids) =>\n call(stateGetMethod, { artifact: artifactRef(artifact), ...(ids ? { ids: [...ids] } : {}) }),\n patchState: (artifact, patch) =>\n call(statePatchMethod, { artifact: artifactRef(artifact), ...patch }),\n pushLive: (artifact, push) =>\n call(livePushMethod, { artifact: artifactRef(artifact), ...push }),\n viewUrl: (artifact, urlOptions = {}) =>\n call(viewUrlMethod, { artifact: artifactRef(artifact), ...urlOptions }),\n events: (streamOptions = {}) =>\n openEventStream(\n {\n call,\n onNotification: (handler) => {\n let set = notificationHandlers.get(EVENTS_NOTIFY);\n if (!set) {\n set = new Set();\n notificationHandlers.set(EVENTS_NOTIFY, set);\n }\n set.add(handler);\n return () => set?.delete(handler);\n },\n closed: exited.then(() => undefined),\n },\n streamOptions,\n ),\n close: () => {\n closing ??= stopChild(child, exited, 10_000);\n return closing;\n },\n };\n return mostra;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/events.ts","../src/mostra.ts"],"sourcesContent":["/**\n * Events as an async iterator (IN-08, D101): pages from `events/subscribe`, in cursor order. A\n * consumer that falls behind pauses the subscription instead of buffering without bound or\n * stalling the connection's other calls: past `highWaterMark` pages it unsubscribes, and once it\n * has caught up it subscribes again after the last cursor it received, so nothing is missed or\n * repeated. With a `name`, a page is acknowledged (`events/ack`) when the next one is asked for,\n * which is when the consumer has handled it; a stream of the same name later resumes there.\n */\nimport {\n createDiagnostic,\n type Diagnostic,\n type EventFilter,\n type EventRecord,\n EventsNotifyParams,\n eventsAckMethod,\n eventsSubscribeMethod,\n eventsUnsubscribeMethod,\n type MethodDefinition,\n RpcError,\n} from \"@mostra/protocol\";\n\n/** One page of events. */\nexport interface EventPage {\n /** The events, in cursor order. */\n readonly events: readonly EventRecord[];\n /** Everything up to this cursor was examined: the cursor to resume after. */\n readonly cursor: string;\n /** Set when compaction removed events in this range (`MOSTRA_HOST_CURSOR_COMPACTED`). */\n readonly compacted?: Diagnostic;\n}\n\n/** Options of a stream. */\nexport interface EventStreamOptions {\n /** Which events: artifacts and type patterns. Default: every event. */\n readonly filter?: EventFilter;\n /** Start after this cursor. Default: a named stream's acknowledged cursor, else now. */\n readonly after?: string;\n /** A durable subscriber name: pages are acknowledged under it as they are handled. */\n readonly name?: string;\n /** Pages held before the subscription pauses. Default 16. */\n readonly highWaterMark?: number;\n /** Ends the stream. */\n readonly signal?: AbortSignal;\n}\n\n/** What a stream needs of the session. */\nexport interface EventSession {\n call<P, R>(method: MethodDefinition<P, R>, params: P): Promise<R>;\n /** Registers a handler for `events/notify`; returns its removal. */\n onNotification(handler: (params: unknown) => void): () => void;\n /** Resolves when the session ends. */\n readonly closed: Promise<void>;\n}\n\n/** Opens a stream; nothing is subscribed until the first page is asked for. */\nexport function openEventStream(\n session: EventSession,\n options: EventStreamOptions,\n): AsyncIterable<EventPage> {\n return {\n [Symbol.asyncIterator]: () => new EventStream(session, options),\n };\n}\n\nclass EventStream implements AsyncIterator<EventPage> {\n readonly #session: EventSession;\n readonly #options: EventStreamOptions;\n readonly #high: number;\n readonly #queue: EventPage[] = [];\n #subscription: string | undefined;\n /** The cursor of the last page received, where a resumed subscription starts. */\n #received: string | undefined;\n /** The cursor of the last page handed out; handled once the next page is asked for. */\n #handedOut: string | undefined;\n /** The cursor of the last page the consumer handled, and of the last acknowledged. */\n #handled: string | undefined;\n #acked: string | undefined;\n #paused = false;\n /**\n * Pages that arrived while a subscribe was in flight, for a subscription not known yet: the\n * answer and its first page can reach the session in one chunk, and the page is dispatched\n * before the code awaiting the answer resumes. Kept until the answer names its ID.\n */\n #early: EventsNotifyParams[] | undefined;\n /** The unsubscribe of a pause; its answer means no page of that subscription follows. */\n #pausing: Promise<void> | undefined;\n /** A subscribe whose answer is on its way (`#subscribe`). */\n #subscribing: Promise<void> | undefined;\n #started = false;\n #ended: { error?: unknown } | undefined;\n #wake: (() => void) | undefined;\n readonly #removeHandler: () => void;\n\n constructor(session: EventSession, options: EventStreamOptions) {\n this.#session = session;\n this.#options = options;\n this.#high = Math.max(1, options.highWaterMark ?? 16);\n this.#removeHandler = session.onNotification((params) => this.#receive(params));\n void session.closed.then(() =>\n this.#end(\n new RpcError(\n createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", {\n message: \"The Mostra instance exited while its events were being read.\",\n }),\n ),\n ),\n );\n options.signal?.addEventListener(\"abort\", () => void this.return(), { once: true });\n }\n\n #receive(params: unknown): void {\n const parsed = EventsNotifyParams.safeParse(params);\n if (!parsed.success) return;\n if (parsed.data.subscriptionId !== this.#subscription) {\n this.#early?.push(parsed.data);\n return;\n }\n this.#accept(parsed.data);\n }\n\n #accept({ events, cursor, compacted }: EventsNotifyParams): void {\n this.#queue.push({ events, cursor, ...(compacted ? { compacted } : {}) });\n this.#received = cursor;\n if (this.#queue.length >= this.#high && !this.#paused) this.#pausing = this.#pause();\n this.#wake?.();\n }\n\n /**\n * Subscribes after `after`. While the answer is on its way the call is `#subscribing`, so\n * `return()` can wait for it and end the subscription it names (GPT review finding 5).\n */\n #subscribe(after: string | undefined): Promise<void> {\n const opening = this.#open(after);\n this.#subscribing = opening;\n return opening.finally(() => {\n if (this.#subscribing === opening) this.#subscribing = undefined;\n });\n }\n\n async #open(after: string | undefined): Promise<void> {\n this.#early = [];\n let answer: { subscriptionId: string; cursor: string };\n let early: EventsNotifyParams[];\n try {\n answer = await this.#session.call(eventsSubscribeMethod, {\n ...(this.#options.filter ? { filter: this.#options.filter } : {}),\n ...(after !== undefined ? { after } : {}),\n ...(this.#options.name ? { name: this.#options.name } : {}),\n });\n } finally {\n early = this.#early;\n this.#early = undefined;\n }\n // Synchronous from here: no page can be dispatched before the ID is known.\n this.#subscription = answer.subscriptionId;\n this.#received ??= answer.cursor;\n // The pages of this subscription that came before its answer was handled, in order.\n for (const page of early) if (page.subscriptionId === answer.subscriptionId) this.#accept(page);\n }\n\n async #pause(): Promise<void> {\n this.#paused = true;\n const id = this.#subscription;\n if (id === undefined) return;\n // What the consumer handled is acknowledged while the subscription still exists: the ack goes\n // out before the unsubscribe on the connection, which keeps their order.\n const acked = this.#sendAck(id);\n // Pages already on their way still arrive under this ID and are kept. The answer comes after\n // them on the connection, so once it is here the subscription is over.\n await this.#session\n .call(eventsUnsubscribeMethod, { subscriptionId: id })\n .catch(() => undefined);\n // A pause runs from a page's arrival, where nobody awaits it, so it never rejects (Opus review\n // finding 7): an ack the instance refused (or a connection gone) ends the stream with that\n // error, which the consumer's next() then throws.\n await acked.catch((error: unknown) => this.#end(error));\n if (this.#subscription === id) this.#subscription = undefined;\n }\n\n async #resume(): Promise<void> {\n await this.#pausing;\n this.#pausing = undefined;\n this.#paused = false;\n await this.#subscribe(this.#received);\n }\n\n /**\n * Acknowledges what the consumer handled under subscription `id`, if a named stream has handled\n * more than it acknowledged. The line is written when this is called (the session writes each\n * call at once), so it is ordered before anything sent after it.\n */\n #sendAck(id: string): Promise<void> {\n const cursor = this.#handled;\n if (!this.#options.name || cursor === undefined || cursor === this.#acked)\n return Promise.resolve();\n this.#acked = cursor;\n return this.#session\n .call(eventsAckMethod, { subscriptionId: id, cursor })\n .then(() => undefined);\n }\n\n #end(error?: unknown): void {\n if (this.#ended) return;\n this.#ended = error === undefined ? {} : { error };\n this.#removeHandler();\n this.#wake?.();\n }\n\n async next(): Promise<IteratorResult<EventPage>> {\n if (!this.#started) {\n this.#started = true;\n await this.#subscribe(this.#options.after);\n }\n // Asking for the next page means the consumer handled the one before it.\n if (this.#handedOut !== undefined) this.#handled = this.#handedOut;\n if (this.#paused && !this.#ended && this.#queue.length <= this.#high / 2) await this.#resume();\n // Never under a subscription being paused: its unsubscribe may already be on its way, and\n // the pause acknowledges what was handled before it.\n if (!this.#paused && this.#subscription !== undefined) await this.#sendAck(this.#subscription);\n for (;;) {\n const page = this.#queue.shift();\n if (page !== undefined) {\n this.#handedOut = page.cursor;\n return { done: false, value: page };\n }\n if (this.#ended) {\n if (this.#ended.error !== undefined) throw this.#ended.error;\n return { done: true, value: undefined };\n }\n if (this.#paused) {\n await this.#resume();\n await this.#sendAck(this.#subscription as string);\n }\n await new Promise<void>((done) => {\n this.#wake = done;\n });\n this.#wake = undefined;\n }\n }\n\n /**\n * Ends the stream: the subscription ends, and a named stream acknowledges every page the\n * consumer handled, never the last one handed out (the loop may have stopped inside it).\n */\n async return(): Promise<IteratorResult<EventPage>> {\n this.#end();\n this.#queue.length = 0;\n await this.#pausing;\n // A subscribe on its way names a subscription that exists on the instance once it is\n // answered: wait for it, so it is ended below like any other.\n await this.#subscribing?.catch(() => undefined);\n const id = this.#subscription;\n if (id !== undefined) {\n this.#subscription = undefined;\n const acked = this.#sendAck(id);\n await this.#session\n .call(eventsUnsubscribeMethod, { subscriptionId: id })\n .catch(() => undefined);\n await acked.catch(() => undefined);\n } else if (this.#options.name && this.#handled !== undefined && this.#handled !== this.#acked) {\n // Paused when it ended, with pages handled since: a subscription of the name, just long\n // enough to acknowledge them (its pages are ignored; the handler is gone).\n await this.#subscribe(this.#received).catch(() => undefined);\n const again = this.#subscription;\n if (again !== undefined) {\n this.#subscription = undefined;\n const acked = this.#sendAck(again);\n await this.#session\n .call(eventsUnsubscribeMethod, { subscriptionId: again })\n .catch(() => undefined);\n await acked.catch(() => undefined);\n }\n }\n return { done: true, value: undefined };\n }\n}\n","/**\n * `createMostra` (HO-04, D25, D58, D59): a JavaScript host's handle on its own Mostra instance.\n * It finds a verified runtime (the pinned bundle, downloaded once), spawns `mostra-runtime host`\n * for the host's home over stdio, opens the protocol session, serves the host's ports and offers\n * the calls every host makes. The instance lives exactly as long as this handle: `close()` ends\n * it, and so does the host's process exiting.\n *\n * ```ts\n * const mostra = await createMostra({\n * home: \"/var/lib/inbox/mostra\",\n * client: { name: \"inbox-app\", version: \"1.4.0\" },\n * ports: { submissions: { deliver: async (envelope) => ({ accepted: true }) } },\n * });\n * const receipt = await mostra.publish(\"/work/inbox\");\n * const outcome = await mostra.wait(receipt.artifactId, \"submitted\");\n * await mostra.close();\n * ```\n */\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport {\n type AnyMethod,\n ARTIFACT_PROGRESS,\n type ArtifactRef,\n type ArtifactSummary,\n artifactPublishMethod,\n artifactVerifyMethod,\n type CapabilityLink,\n type ControlsPolicy,\n createDiagnostic,\n type DependencyPolicy,\n type Diagnostic,\n type DraftMirror,\n EVENTS_NOTIFY,\n encodeLine,\n HOST_PROTOCOL_REVISIONS,\n type HomeConfig,\n type InstanceCapabilities,\n type InstanceInfo,\n LineSplitter,\n type LivePushParams,\n type LivePushResult,\n livePushMethod,\n type MethodDefinition,\n type MostraInitializeResult,\n mostraInitializeMethod,\n type PortIdentityResolveParams,\n type PortName,\n type PortSecretsGetParams,\n type PortTrustedControlsActivatedParams,\n type PublishReceipt,\n portDraftsMirrorMethod,\n portIdentityResolveMethod,\n portSecretsGetMethod,\n portSubmissionsDeliverMethod,\n portTrustedControlsActivatedMethod,\n portTrustedControlsPolicyMethod,\n type Results,\n type ResultsMarkdown,\n RpcError,\n RpcPeer,\n resultsGetMethod,\n type SourceRef,\n type StateGetResult,\n type StatePatchParams,\n type StatePatchResult,\n type SubmissionEnvelope,\n type SubmissionPolicy,\n type SubmissionsDeliverResult,\n type SubmitChannel,\n stateGetMethod,\n statePatchMethod,\n type VerifyVerdict,\n type ViewerSpec,\n type ViewUrlParams,\n viewUrlMethod,\n WAIT_MAX_MS,\n type WaitCondition,\n type WaitResult,\n waitMethod,\n} from \"@mostra/protocol\";\nimport type { InstallProgress } from \"./bundle/cache.ts\";\nimport type { Environment } from \"./bundle/setup.ts\";\nimport { type EventPage, type EventStreamOptions, openEventStream } from \"./events.ts\";\nimport { type Runtime, resolveRuntime } from \"./runtime.ts\";\nimport { sdkVersion } from \"./version.ts\";\n\n/**\n * The ports a host may serve (INTERFACES §7). Each is optional and has a standalone default;\n * Mostra calls a port only on the instance this handle spawned, and every call is idempotent by\n * its stable ID, so a port may see the same call again after a crash.\n */\nexport interface Ports {\n /**\n * Names the person behind a link minted without a viewer, from the request's headers (D143):\n * `{ ref, name? }` (one viewer per `ref`), or `null` for the home's local user. Answer within\n * 5 s; a failure refuses the link rather than guess.\n */\n readonly identity?: {\n resolve(request: PortIdentityResolveParams): ViewerSpec | null | Promise<ViewerSpec | null>;\n };\n /** Receives each submission once it is durable (D58, D105). Answer within 30 s. */\n readonly submissions?: {\n deliver(\n envelope: SubmissionEnvelope,\n ): SubmissionsDeliverResult | Promise<SubmissionsDeliverResult>;\n };\n /** Receives each viewer draft's latest revision, best effort, never retried (IN-06). */\n readonly drafts?: { mirror(draft: DraftMirror): void | Promise<void> };\n /** Answers `secret()` first, before the home's store (D131); `null` falls back. */\n readonly secrets?: {\n get(request: PortSecretsGetParams): string | null | Promise<string | null>;\n };\n /** Decides each view's submit channels and trusted controls (D108). Answer within 5 s. */\n readonly trustedControls?: {\n policy(artifact: ArtifactSummary): ControlsPolicy | Promise<ControlsPolicy>;\n activated?(event: PortTrustedControlsActivatedParams): void | Promise<void>;\n };\n}\n\n/** Home settings a host chooses (INTERFACES §6 `HomeConfig`), kept in the home's `config.json`. */\nexport interface HomeSettings {\n /** The submission policy for artifacts whose publish names none (D102). */\n readonly submission?: SubmissionPolicy;\n /** The channels that may submit (D40, D108); absent, both. */\n readonly submitChannels?: readonly SubmitChannel[];\n /** How packages enter an artifact's lockfile (D43, D95). */\n readonly dependencies?: DependencyPolicy;\n}\n\n/** Options of {@link createMostra}. */\nexport interface MostraOptions {\n /** The home this host owns (D45). Created 0700 when missing. */\n readonly home: string;\n /**\n * Who the host is. The name owns the host's deliveries across restarts (D105), so keep it\n * stable; it defaults to `mostra-sdk`.\n */\n readonly client?: { readonly name: string; readonly version?: string };\n /** The ports this host serves. */\n readonly ports?: Ports;\n /**\n * Whether submissions made while this host is away wait for it (D105): the registered ports\n * are recorded as ports this host always provides. Default `true`; `false` leaves the home's\n * record as it is.\n */\n readonly expectPorts?: boolean;\n /** Home settings, kept in the home's `config.json` for every later client. */\n readonly settings?: HomeSettings;\n /** An extracted runtime bundle to use instead of the pinned one. */\n readonly bundle?: string;\n /** The gateway's bind address and URL host (D99); loopback by default. */\n readonly bind?: string;\n /** The host name URLs use, which a wildcard `bind` needs (D99). */\n readonly urlHost?: string;\n /** The instance's environment. Default: this process's. */\n readonly env?: Environment;\n /** Each line the instance logs (JSON, on its stderr). A callback that throws is ignored. */\n readonly onLog?: (line: string) => void;\n /** Progress of the first download or setup of the runtime bundle. A throw is ignored. */\n readonly onProgress?: (progress: InstallProgress) => void;\n /**\n * An exception a port threw; the instance got `MOSTRA_HOST_INTERNAL_ERROR` and will retry. A\n * callback that throws is ignored, and the instance is answered all the same.\n */\n readonly onPortError?: (error: unknown, method: string) => void;\n /** Gives up finding the runtime and starting the instance. */\n readonly signal?: AbortSignal;\n}\n\n/** How the instance ended. */\nexport interface InstanceExit {\n /** Its exit code: 0 after a clean stop. */\n readonly code: number | null;\n /** The signal that ended it, if one did. */\n readonly signal: NodeJS.Signals | null;\n}\n\n/** An artifact by ID (`art_…`), by source path, or as the protocol's reference. */\nexport type ArtifactInput = string | ArtifactRef;\n\n/** A host's handle on its instance. */\nexport interface Mostra {\n /** The instance: release, home, platform, PID and mode. */\n readonly instance: InstanceInfo;\n /** What the instance serves. */\n readonly capabilities: InstanceCapabilities;\n /** The negotiated host protocol revision. */\n readonly revision: string;\n /** The session's warnings (an unsupported port, for example). */\n readonly warnings: readonly Diagnostic[];\n /** The runtime it runs on. */\n readonly runtime: Runtime;\n /** Resolves when the instance has exited, for whatever reason. */\n readonly closed: Promise<InstanceExit>;\n /** Calls any host protocol method by its definition from `@mostra/protocol`. */\n call<P, R>(method: MethodDefinition<P, R>, params: P, options?: CallOptions): Promise<R>;\n /** `artifact/publish`: verifies (D41) and publishes; durable before it resolves (H-07). */\n publish(\n source: ArtifactInput,\n options?: {\n readonly force?: boolean;\n readonly policy?: SubmissionPolicy;\n readonly requestId?: string;\n },\n ): Promise<PublishReceipt>;\n /** `artifact/verify`: one verdict, never a publish (D138). */\n verify(\n source: ArtifactInput,\n options?: { readonly screenshots?: \"on-failure\" | \"always\" | \"never\" },\n ): Promise<VerifyVerdict>;\n /**\n * `wait` (IN-10, D103): until the condition holds or `timeoutMs` passes (default: the longest\n * timer, about 24.8 days). `still_waiting` carries the cursor to wait from next; an aborted wait\n * rejects with the signal's reason and loses nothing.\n */\n wait(\n artifact: ArtifactInput,\n until: WaitCondition,\n options?: {\n readonly after?: string;\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n },\n ): Promise<WaitResult>;\n /** `results/get`: a submission as JSON (the default) or Markdown (INTERFACES §8). */\n results(\n artifact: ArtifactInput,\n options?: { readonly submission?: string; readonly format?: \"json\" },\n ): Promise<Results>;\n /** `results/get` as Markdown, for an agent to read. */\n results(\n artifact: ArtifactInput,\n options: { readonly submission?: string; readonly format: \"md\" },\n ): Promise<ResultsMarkdown>;\n /** `state/get`: artifact-scoped fields (D63). */\n getState(artifact: ArtifactInput, ids?: readonly string[]): Promise<StateGetResult>;\n /** `state/patch`: writes artifact-scoped fields through compare-and-set (D63). */\n patchState(\n artifact: ArtifactInput,\n patch: Omit<StatePatchParams, \"artifact\">,\n ): Promise<StatePatchResult>;\n /** `live/push`: a live source's next value (D56). */\n pushLive(\n artifact: ArtifactInput,\n push: Omit<LivePushParams, \"artifact\">,\n ): Promise<LivePushResult>;\n /** `view/url`: a new capability link (D97). */\n viewUrl(\n artifact: ArtifactInput,\n options?: Omit<ViewUrlParams, \"artifact\">,\n ): Promise<CapabilityLink>;\n /**\n * The events matching `options.filter`, page by page, in cursor order, with no gap across a\n * pause (`events/subscribe`). With a `name`, each page is acknowledged when the next one is\n * asked for, so a later stream of that name resumes after the last page handled.\n */\n events(options?: EventStreamOptions): AsyncIterable<EventPage>;\n /** Ends the instance: its stdio closes, and it is stopped if it doesn't exit within 10 s. */\n close(): Promise<InstanceExit>;\n}\n\n/** Options of one call. */\nexport interface CallOptions {\n /** Gives up after this many milliseconds with `MOSTRA_HOST_TIMEOUT`. Default: none. */\n readonly timeoutMs?: number;\n}\n\n/** The port methods the SDK serves, by port. */\nconst PORT_METHODS = {\n identity: [portIdentityResolveMethod],\n submissions: [portSubmissionsDeliverMethod],\n drafts: [portDraftsMirrorMethod],\n secrets: [portSecretsGetMethod],\n trustedControls: [portTrustedControlsPolicyMethod, portTrustedControlsActivatedMethod],\n} as const satisfies Record<keyof Ports, readonly AnyMethod[]>;\n\n/** The client name of an SDK host that names none. */\nexport const SDK_CLIENT_NAME = \"mostra-sdk\";\n\n/** `art_…` is an artifact ID; anything else a source path, resolved against the working directory. */\nexport function artifactRef(input: ArtifactInput): ArtifactRef & SourceRef {\n if (typeof input !== \"string\") return input as ArtifactRef & SourceRef;\n return input.startsWith(\"art_\") ? { artifactId: input } : { path: resolve(input) };\n}\n\nfunction closedError(message: string): RpcError {\n return new RpcError(createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", { message }));\n}\n\n/** The handler for one port method, its params already checked. */\nfunction portHandler(ports: Ports, method: string): ((params: unknown) => unknown) | undefined {\n switch (method) {\n case portIdentityResolveMethod.method:\n return (\n ports.identity && ((params) => ports.identity?.resolve(params as PortIdentityResolveParams))\n );\n case portSubmissionsDeliverMethod.method:\n return (\n ports.submissions && ((params) => ports.submissions?.deliver(params as SubmissionEnvelope))\n );\n case portDraftsMirrorMethod.method:\n return ports.drafts && ((params) => ports.drafts?.mirror(params as DraftMirror));\n case portSecretsGetMethod.method:\n return ports.secrets && ((params) => ports.secrets?.get(params as PortSecretsGetParams));\n case portTrustedControlsPolicyMethod.method:\n return (\n ports.trustedControls &&\n ((params) =>\n ports.trustedControls?.policy((params as { artifact: ArtifactSummary }).artifact))\n );\n case portTrustedControlsActivatedMethod.method:\n return (\n ports.trustedControls &&\n (async (params) => {\n await ports.trustedControls?.activated?.(params as PortTrustedControlsActivatedParams);\n return {};\n })\n );\n default:\n return undefined;\n }\n}\n\n/** The port names `ports` registers; anything unknown is a mistake worth failing on. */\nfunction portNames(ports: Ports): PortName[] {\n const names: PortName[] = [];\n for (const [name, value] of Object.entries(ports)) {\n if (value === undefined) continue;\n if (!(name in PORT_METHODS)) {\n throw new TypeError(\n `createMostra: no port \"${name}\" (the SDK serves ${Object.keys(PORT_METHODS).join(\", \")}).`,\n );\n }\n names.push(name as PortName);\n }\n return names;\n}\n\n/** Ends the child: stdin closed, then SIGTERM after `graceMs`, then SIGKILL after 5 s more. */\nfunction stopChild(\n child: ChildProcess,\n exited: Promise<InstanceExit>,\n graceMs: number,\n): Promise<InstanceExit> {\n child.stdin?.end();\n const term = setTimeout(() => child.kill(\"SIGTERM\"), graceMs);\n const kill = setTimeout(() => child.kill(\"SIGKILL\"), graceMs + 5000);\n return exited.finally(() => {\n clearTimeout(term);\n clearTimeout(kill);\n });\n}\n\n/** `callback`, made unable to throw into its caller. */\nfunction guarded<A extends unknown[]>(\n callback: ((...args: A) => void) | undefined,\n): ((...args: A) => void) | undefined {\n if (callback === undefined) return undefined;\n return (...args: A) => {\n try {\n callback(...args);\n } catch {\n // The host's own code failed; Mostra's work goes on.\n }\n };\n}\n\n/**\n * Spawns an instance for `home` and opens its session. Rejects with the instance's own diagnostic\n * when it can't start (`MOSTRA_HOME_LOCKED`, `MOSTRA_PLATFORM_UNSUPPORTED` …), or with the\n * runtime's (`MOSTRA_ENV_BUNDLE_*`) when no verified runtime can be found.\n */\nexport async function createMostra(options: MostraOptions): Promise<Mostra> {\n // The host's callbacks run inside Mostra's own handlers (a pipe's data listener, the RPC\n // peer's error path, a download's progress): one that throws must never escape into the host's\n // process as an uncaught exception or unhandled rejection, nor stop an answer (Opus review\n // finding 6). A callback that throws is ignored.\n const onLog = guarded(options.onLog);\n const onProgress = guarded(options.onProgress);\n const onPortError = guarded(options.onPortError);\n const ports = options.ports ?? {};\n const names = portNames(ports);\n const env = options.env ?? process.env;\n const home = resolve(options.home);\n const runtime = await resolveRuntime({\n bundle: options.bundle,\n env,\n signal: options.signal,\n ...(onProgress ? { onProgress } : {}),\n });\n options.signal?.throwIfAborted();\n const args = [runtime.runtimeEntry, \"host\", \"--home\", home];\n if (options.bind !== undefined) args.push(\"--bind\", options.bind);\n if (options.urlHost !== undefined) args.push(\"--url-host\", options.urlHost);\n const child = spawn(runtime.node, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: env as NodeJS.ProcessEnv,\n });\n const logTail: string[] = [];\n const exited = new Promise<InstanceExit>((done) => {\n child.on(\"close\", (code, signal) => done({ code, signal }));\n child.on(\"error\", () => done({ code: null, signal: null }));\n });\n let spawnError: Error | undefined;\n child.on(\"error\", (error) => {\n spawnError = error;\n });\n const errLines = new LineSplitter();\n child.stderr?.setEncoding(\"utf8\");\n child.stderr?.on(\"data\", (chunk: string) => {\n for (const line of errLines.push(chunk)) {\n logTail.push(line);\n if (logTail.length > 20) logTail.shift();\n onLog?.(line);\n }\n });\n\n const notificationHandlers = new Map<string, Set<(params: unknown) => void>>();\n const peer = new RpcPeer({\n send: (message) => {\n if (child.stdin?.writable) child.stdin.write(encodeLine(message));\n },\n onRequest: async (method, params) => {\n const definition = Object.values(PORT_METHODS)\n .flat()\n .find((candidate) => candidate.method === method) as\n | MethodDefinition<unknown, unknown>\n | undefined;\n const handler = definition && portHandler(ports, method);\n if (!definition || !handler) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_HOST_METHOD_UNKNOWN\", {\n message: `This host serves no method ${method}.`,\n }),\n -32601,\n );\n }\n const parsed = definition.params.safeParse(params);\n if (!parsed.success) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_HOST_INVALID_PARAMS\", {\n message: `The params of ${method} don't match its schema.`,\n }),\n -32602,\n );\n }\n const answer = await handler(parsed.data);\n const checked = definition.result.safeParse(answer ?? null);\n if (!checked.success) {\n throw new RpcError(\n createDiagnostic(\"MOSTRA_HOST_INTERNAL_ERROR\", {\n message: `The host's ${method} answered something its schema refuses.`,\n }),\n );\n }\n return checked.data;\n },\n onNotification: (method, params) => {\n for (const handler of notificationHandlers.get(method) ?? []) handler(params);\n },\n onInternalError: (error, method) => onPortError?.(error, method),\n });\n const lines = new LineSplitter();\n child.stdout?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n for (const line of lines.push(chunk)) peer.receiveLine(line);\n });\n child.stdout?.on(\"close\", () => {\n peer.close(\n createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", {\n message: `The Mostra instance for ${home} exited${logTail.length > 0 ? `; its last log line: ${logTail.at(-1)}` : \"\"}.`,\n }),\n );\n });\n // A pipe to an instance that died fails its next write (EPIPE) on its own schedule. Without a\n // listener that error is an uncaught exception in the host's own process: every pipe has one,\n // and a write that failed ends the session at once, as the instance's exit does.\n child.stdin?.on(\"error\", (error: NodeJS.ErrnoException) => {\n peer.close(\n createDiagnostic(\"MOSTRA_HOST_CONNECTION_CLOSED\", {\n message: `The Mostra instance for ${home} stopped reading (${error.code ?? error.message}).`,\n }),\n );\n });\n child.stdout?.on(\"error\", () => {});\n child.stderr?.on(\"error\", () => {});\n\n const abort = (): void => {\n void stopChild(child, exited, 0);\n };\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n const homeConfig: HomeConfig = {\n path: home,\n // What this host always provides, an empty list included: a host that stopped serving a port\n // clears the record, so its absence is never awaited (Opus review of WP-12, finding 7).\n ...(options.expectPorts !== false ? { ports: names } : {}),\n ...(options.settings?.submission ? { submission: options.settings.submission } : {}),\n ...(options.settings?.submitChannels\n ? { submitChannels: options.settings.submitChannels }\n : {}),\n ...(options.settings?.dependencies ? { dependencies: options.settings.dependencies } : {}),\n };\n let session: MostraInitializeResult;\n try {\n session = await peer.call(mostraInitializeMethod, {\n client: {\n name: options.client?.name ?? SDK_CLIENT_NAME,\n version: options.client?.version ?? sdkVersion(),\n },\n revisions: [...HOST_PROTOCOL_REVISIONS],\n capabilities: { notifications: [EVENTS_NOTIFY, ARTIFACT_PROGRESS] },\n ports: names,\n home: homeConfig,\n });\n } catch (error) {\n await stopChild(child, exited, 2000);\n if (spawnError) throw closedError(`Couldn't start ${runtime.node}: ${spawnError.message}`);\n throw error;\n } finally {\n options.signal?.removeEventListener(\"abort\", abort);\n }\n\n const call = <P, R>(\n method: MethodDefinition<P, R>,\n params: P,\n callOptions?: CallOptions,\n ): Promise<R> =>\n peer.call(\n method,\n params,\n callOptions?.timeoutMs !== undefined ? { timeoutMs: callOptions.timeoutMs } : {},\n );\n let closing: Promise<InstanceExit> | undefined;\n\n const mostra: Mostra = {\n instance: session.instance,\n capabilities: session.capabilities,\n revision: session.revision,\n warnings: session.warnings,\n runtime,\n closed: exited,\n call,\n publish: (source, publishOptions = {}) =>\n call(artifactPublishMethod, { source: artifactRef(source), ...publishOptions }),\n verify: (source, verifyOptions = {}) =>\n call(artifactVerifyMethod, { source: artifactRef(source), ...verifyOptions }),\n wait: (artifact, until, waitOptions = {}) => {\n const signal = waitOptions.signal;\n // Checked before the request goes out: nothing is sent for a wait already given up, so no\n // answer is left without a handler (GPT review finding 4).\n if (signal?.aborted) return Promise.reject(signal.reason);\n const pending = call(waitMethod, {\n artifact: artifactRef(artifact),\n until,\n timeoutMs: waitOptions.timeoutMs ?? WAIT_MAX_MS,\n ...(waitOptions.after !== undefined ? { after: waitOptions.after } : {}),\n });\n if (!signal) return pending;\n // The instance's wait runs on until its own timeout; its late answer, or the connection's\n // end, is handled here and dropped.\n return new Promise<WaitResult>((done, fail) => {\n const onAbort = (): void => fail(signal.reason);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n pending.then(done, fail).finally(() => signal.removeEventListener(\"abort\", onAbort));\n });\n },\n results: ((\n artifact: ArtifactInput,\n resultsOptions: { submission?: string; format?: \"json\" | \"md\" } = {},\n ) =>\n call(resultsGetMethod, {\n artifact: artifactRef(artifact),\n ...resultsOptions,\n })) as Mostra[\"results\"],\n getState: (artifact, ids) =>\n call(stateGetMethod, { artifact: artifactRef(artifact), ...(ids ? { ids: [...ids] } : {}) }),\n patchState: (artifact, patch) =>\n call(statePatchMethod, { artifact: artifactRef(artifact), ...patch }),\n pushLive: (artifact, push) =>\n call(livePushMethod, { artifact: artifactRef(artifact), ...push }),\n viewUrl: (artifact, urlOptions = {}) =>\n call(viewUrlMethod, { artifact: artifactRef(artifact), ...urlOptions }),\n events: (streamOptions = {}) =>\n openEventStream(\n {\n call,\n onNotification: (handler) => {\n let set = notificationHandlers.get(EVENTS_NOTIFY);\n if (!set) {\n set = new Set();\n notificationHandlers.set(EVENTS_NOTIFY, set);\n }\n set.add(handler);\n return () => set?.delete(handler);\n },\n closed: exited.then(() => undefined),\n },\n streamOptions,\n ),\n close: () => {\n closing ??= stopChild(child, exited, 10_000);\n return closing;\n },\n };\n return mostra;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
-
import { link, lstat, mkdir, open, readFile, readdir, readlink, rename, rm, stat, statfs, writeFile } from "node:fs/promises";
|
|
2
|
+
import { link, lstat, mkdir, open, readFile, readdir, readlink, rename, rm, stat, statfs, utimes, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
5
|
import { BUNDLE_PLATFORMS, BUNDLE_SETUP_MARKER, BundleAsset, BundleFiles, BundleInfo, BundlePins, BundleSetup, RpcError, bundleAssetName, createDiagnostic } from "@mostra/protocol";
|
|
@@ -723,6 +723,11 @@ function alive(pid) {
|
|
|
723
723
|
}
|
|
724
724
|
/** How old a lock may get before another installer takes it over whatever its owner. */
|
|
725
725
|
const STALE_LOCK_MS = 36e5;
|
|
726
|
+
/**
|
|
727
|
+
* How often a held lock is touched, so an install longer than {@link STALE_LOCK_MS} (a slow
|
|
728
|
+
* network, a large browser) is never taken from its live owner (Opus review of WP-12, finding 10).
|
|
729
|
+
*/
|
|
730
|
+
const LOCK_TOUCH_MS = 6e4;
|
|
726
731
|
/** `url` without trailing slashes, in linear time (a regex would be quadratic on many slashes). */
|
|
727
732
|
function withoutTrailingSlashes(url) {
|
|
728
733
|
let end = url.length;
|
|
@@ -778,7 +783,14 @@ async function lock(path, signal) {
|
|
|
778
783
|
const handle = await open(path, "wx", 384);
|
|
779
784
|
await handle.writeFile(`${process.pid} ${token}\n`);
|
|
780
785
|
await handle.close();
|
|
786
|
+
const touch = setInterval(() => {
|
|
787
|
+
readFile(path, "utf8").then((text) => {
|
|
788
|
+
if (text.includes(token)) return utimes(path, /* @__PURE__ */ new Date(), /* @__PURE__ */ new Date());
|
|
789
|
+
}).catch(() => void 0);
|
|
790
|
+
}, LOCK_TOUCH_MS);
|
|
791
|
+
touch.unref();
|
|
781
792
|
return async () => {
|
|
793
|
+
clearInterval(touch);
|
|
782
794
|
const aside = `${path}.done-${randomBytes(6).toString("hex")}`;
|
|
783
795
|
if (!await rename(path, aside).then(() => true, () => false)) return;
|
|
784
796
|
if (!(await readFile(aside, "utf8").catch(() => "")).includes(token)) await link(aside, path).catch(() => void 0);
|
|
@@ -995,4 +1007,4 @@ async function resolveRuntime(options = {}) {
|
|
|
995
1007
|
//#endregion
|
|
996
1008
|
export { safeRelative as C, linkStaysInside as S, setupBundle as _, sdkVersion as a, describeTree as b, bundleDir as c, browsersDir as d, checkBrowser as f, readSetup as g, readBundle as h, runtimeOf as i, cacheRoot as l, offline as m, readPins as n, bundlePlatform as o, checkFiles as p, resolveRuntime as r, currentPlatform as s, enclosingBundle as t, installPinned as u, setupExtras as v, redactUrl as w, hashFile as x, checkTree as y };
|
|
997
1009
|
|
|
998
|
-
//# sourceMappingURL=runtime-
|
|
1010
|
+
//# sourceMappingURL=runtime-CUbnK5Za.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-CUbnK5Za.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 {\n link,\n mkdir,\n open,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n statfs,\n utimes,\n} 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 * How often a held lock is touched, so an install longer than {@link STALE_LOCK_MS} (a slow\n * network, a large browser) is never taken from its live owner (Opus review of WP-12, finding 10).\n */\nconst LOCK_TOUCH_MS = 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 const touch = setInterval(() => {\n void readFile(path, \"utf8\")\n .then((text) => {\n if (text.includes(token)) return utimes(path, new Date(), new Date());\n return undefined;\n })\n .catch(() => undefined);\n }, LOCK_TOUCH_MS);\n touch.unref();\n // Released by moving it aside and removing it only if it is still this installer's own.\n return async () => {\n clearInterval(touch);\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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"}
|
package/dist/setup-main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { _ as setupBundle, t as enclosingBundle } from "./runtime-
|
|
2
|
+
import { _ as setupBundle, t as enclosingBundle } from "./runtime-CUbnK5Za.js";
|
|
3
3
|
import { RpcError, createDiagnostic } from "@mostra/protocol";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
//#region src/setup-main.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostra/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
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
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "The Mostra Authors",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"provenance": true
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@mostra/protocol": "0.
|
|
37
|
+
"@mostra/protocol": "0.3.0",
|
|
38
38
|
"tar": "7.5.22",
|
|
39
39
|
"undici": "8.11.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@mostra/runtime": "0.
|
|
42
|
+
"@mostra/runtime": "0.3.0",
|
|
43
43
|
"@mostra/tools": "0.0.0",
|
|
44
44
|
"@types/node": "24.19.1",
|
|
45
45
|
"tsdown": "0.23.0",
|
package/src/bundle/cache.ts
CHANGED
|
@@ -7,7 +7,18 @@
|
|
|
7
7
|
* directory the next install removes, never a half-ready bundle.
|
|
8
8
|
*/
|
|
9
9
|
import { randomBytes } from "node:crypto";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
link,
|
|
12
|
+
mkdir,
|
|
13
|
+
open,
|
|
14
|
+
readdir,
|
|
15
|
+
readFile,
|
|
16
|
+
rename,
|
|
17
|
+
rm,
|
|
18
|
+
stat,
|
|
19
|
+
statfs,
|
|
20
|
+
utimes,
|
|
21
|
+
} from "node:fs/promises";
|
|
11
22
|
import { homedir } from "node:os";
|
|
12
23
|
import { join, resolve } from "node:path";
|
|
13
24
|
import {
|
|
@@ -265,6 +276,11 @@ function alive(pid: number): boolean {
|
|
|
265
276
|
|
|
266
277
|
/** How old a lock may get before another installer takes it over whatever its owner. */
|
|
267
278
|
const STALE_LOCK_MS = 60 * 60_000;
|
|
279
|
+
/**
|
|
280
|
+
* How often a held lock is touched, so an install longer than {@link STALE_LOCK_MS} (a slow
|
|
281
|
+
* network, a large browser) is never taken from its live owner (Opus review of WP-12, finding 10).
|
|
282
|
+
*/
|
|
283
|
+
const LOCK_TOUCH_MS = 60_000;
|
|
268
284
|
|
|
269
285
|
/** `url` without trailing slashes, in linear time (a regex would be quadratic on many slashes). */
|
|
270
286
|
function withoutTrailingSlashes(url: string): string {
|
|
@@ -326,8 +342,18 @@ async function lock(path: string, signal: AbortSignal | undefined): Promise<() =
|
|
|
326
342
|
const handle = await open(path, "wx", 0o600);
|
|
327
343
|
await handle.writeFile(`${process.pid} ${token}\n`);
|
|
328
344
|
await handle.close();
|
|
345
|
+
const touch = setInterval(() => {
|
|
346
|
+
void readFile(path, "utf8")
|
|
347
|
+
.then((text) => {
|
|
348
|
+
if (text.includes(token)) return utimes(path, new Date(), new Date());
|
|
349
|
+
return undefined;
|
|
350
|
+
})
|
|
351
|
+
.catch(() => undefined);
|
|
352
|
+
}, LOCK_TOUCH_MS);
|
|
353
|
+
touch.unref();
|
|
329
354
|
// Released by moving it aside and removing it only if it is still this installer's own.
|
|
330
355
|
return async () => {
|
|
356
|
+
clearInterval(touch);
|
|
331
357
|
const aside = `${path}.done-${randomBytes(6).toString("hex")}`;
|
|
332
358
|
if (
|
|
333
359
|
!(await rename(path, aside).then(
|
package/src/mostra.ts
CHANGED
|
@@ -44,11 +44,13 @@ import {
|
|
|
44
44
|
type MethodDefinition,
|
|
45
45
|
type MostraInitializeResult,
|
|
46
46
|
mostraInitializeMethod,
|
|
47
|
+
type PortIdentityResolveParams,
|
|
47
48
|
type PortName,
|
|
48
49
|
type PortSecretsGetParams,
|
|
49
50
|
type PortTrustedControlsActivatedParams,
|
|
50
51
|
type PublishReceipt,
|
|
51
52
|
portDraftsMirrorMethod,
|
|
53
|
+
portIdentityResolveMethod,
|
|
52
54
|
portSecretsGetMethod,
|
|
53
55
|
portSubmissionsDeliverMethod,
|
|
54
56
|
portTrustedControlsActivatedMethod,
|
|
@@ -69,6 +71,7 @@ import {
|
|
|
69
71
|
stateGetMethod,
|
|
70
72
|
statePatchMethod,
|
|
71
73
|
type VerifyVerdict,
|
|
74
|
+
type ViewerSpec,
|
|
72
75
|
type ViewUrlParams,
|
|
73
76
|
viewUrlMethod,
|
|
74
77
|
WAIT_MAX_MS,
|
|
@@ -88,6 +91,14 @@ import { sdkVersion } from "./version.ts";
|
|
|
88
91
|
* its stable ID, so a port may see the same call again after a crash.
|
|
89
92
|
*/
|
|
90
93
|
export interface Ports {
|
|
94
|
+
/**
|
|
95
|
+
* Names the person behind a link minted without a viewer, from the request's headers (D143):
|
|
96
|
+
* `{ ref, name? }` (one viewer per `ref`), or `null` for the home's local user. Answer within
|
|
97
|
+
* 5 s; a failure refuses the link rather than guess.
|
|
98
|
+
*/
|
|
99
|
+
readonly identity?: {
|
|
100
|
+
resolve(request: PortIdentityResolveParams): ViewerSpec | null | Promise<ViewerSpec | null>;
|
|
101
|
+
};
|
|
91
102
|
/** Receives each submission once it is durable (D58, D105). Answer within 30 s. */
|
|
92
103
|
readonly submissions?: {
|
|
93
104
|
deliver(
|
|
@@ -257,6 +268,7 @@ export interface CallOptions {
|
|
|
257
268
|
|
|
258
269
|
/** The port methods the SDK serves, by port. */
|
|
259
270
|
const PORT_METHODS = {
|
|
271
|
+
identity: [portIdentityResolveMethod],
|
|
260
272
|
submissions: [portSubmissionsDeliverMethod],
|
|
261
273
|
drafts: [portDraftsMirrorMethod],
|
|
262
274
|
secrets: [portSecretsGetMethod],
|
|
@@ -279,6 +291,10 @@ function closedError(message: string): RpcError {
|
|
|
279
291
|
/** The handler for one port method, its params already checked. */
|
|
280
292
|
function portHandler(ports: Ports, method: string): ((params: unknown) => unknown) | undefined {
|
|
281
293
|
switch (method) {
|
|
294
|
+
case portIdentityResolveMethod.method:
|
|
295
|
+
return (
|
|
296
|
+
ports.identity && ((params) => ports.identity?.resolve(params as PortIdentityResolveParams))
|
|
297
|
+
);
|
|
282
298
|
case portSubmissionsDeliverMethod.method:
|
|
283
299
|
return (
|
|
284
300
|
ports.submissions && ((params) => ports.submissions?.deliver(params as SubmissionEnvelope))
|
|
@@ -476,7 +492,9 @@ export async function createMostra(options: MostraOptions): Promise<Mostra> {
|
|
|
476
492
|
options.signal?.addEventListener("abort", abort, { once: true });
|
|
477
493
|
const homeConfig: HomeConfig = {
|
|
478
494
|
path: home,
|
|
479
|
-
|
|
495
|
+
// What this host always provides, an empty list included: a host that stopped serving a port
|
|
496
|
+
// clears the record, so its absence is never awaited (Opus review of WP-12, finding 7).
|
|
497
|
+
...(options.expectPorts !== false ? { ports: names } : {}),
|
|
480
498
|
...(options.settings?.submission ? { submission: options.settings.submission } : {}),
|
|
481
499
|
...(options.settings?.submitChannels
|
|
482
500
|
? { submitChannels: options.settings.submitChannels }
|
|
@@ -1 +0,0 @@
|
|
|
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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"}
|