@wildo-ai/wildo-module-client 1.1.6 → 1.1.7
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/esm/index.d.ts.map +1 -1
- package/dist/esm/services/_http-client.d.ts.map +1 -1
- package/dist/esm/services/_http-client.js.map +1 -1
- package/dist/esm/services/_zod-issue-formatting.d.ts.map +1 -1
- package/dist/esm/services/index.d.ts.map +1 -1
- package/dist/esm/services/lockfile-repair.service.d.ts.map +1 -1
- package/dist/esm/services/module-adopter.service.d.ts.map +1 -1
- package/dist/esm/services/module-adopter.service.js.map +1 -1
- package/dist/esm/services/module-packager.service.d.ts.map +1 -1
- package/dist/esm/services/module-packager.service.js.map +1 -1
- package/dist/esm/services/provider-materialization-hook.d.ts.map +1 -1
- package/dist/esm/services/provider-sync-runner.d.ts.map +1 -1
- package/dist/esm/services/provider-sync-runner.js.map +1 -1
- package/dist/esm/services/registry-companion-client.d.ts.map +1 -1
- package/dist/esm/services/registry-companion-client.js.map +1 -1
- package/dist/esm/services/registry-lockfile.service.d.ts.map +1 -1
- package/dist/esm/services/registry-lockfile.service.js.map +1 -1
- package/dist/esm/services/registry-server-client.d.ts.map +1 -1
- package/dist/esm/services/registry-server-client.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,cAAc,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_http-client.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"_http-client.d.ts","sourceRoot":"","sources":["../../../src/services/_http-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAExD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,QAAQ,CAAC,CA0BnB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ7H;AAED,MAAM,WAAW,YAAa,SAAQ,oBAAoB;IACxD,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;CAAE,CAAC,CAqD7I;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,QAAQ,CAAC,CAQnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_http-client.js","sourceRoot":"","sources":["../../../../src/services/_http-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Internal HTTP client utilities shared by `RegistryServerClient`\n * and `RegistryCompanionClient`.\n *\n * Both clients want the same primitives:\n * - `joinUrl(base, path)` — single-source-of-truth path joiner\n * that tolerates leading/trailing slashes;\n * - `fetchWithTimeout(url, init)` — one budget for a metadata\n * exchange; an abort becomes a typed `RegistryRequestTimeoutError`;\n * - `readJsonBody(...)` — reads that exchange's JSON body, typing a\n * body cut short by the same budget as a `READING_BODY` timeout;\n * - `fetchTransfer(url, init)` — an artifact download: a response\n * budget plus an idle budget between body chunks (#1763);\n * - `fetchJsonOk(...)` — convenience for liveness probes that\n * want a boolean answer.\n *\n * The leading underscore signals \"package-internal\" — these are\n * intentionally NOT re-exported from `services/index.ts`. Phase 2\n * services that need fancier HTTP (multipart upload, streaming\n * download) extend this file rather than copy the primitives.\n */\n\nimport { isAbortLikeError, RegistryRequestTimeoutError, RegistryTimeoutPhase } from '@wildo-ai/platform-config-lib';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * How long a DOWNLOAD may go without receiving a single byte (#1763). An idle budget, not a cap on the\n * whole body: a large artifact over a slow but moving link finishes, a stalled one fails. 30 s is the\n * order npm and cargo tolerate before calling a transfer stuck.\n */\nexport const REGISTRY_TRANSFER_IDLE_TIMEOUT_MS = 30_000;\n\nexport function joinUrl(base: string, path: string): string {\n const normalized = path.startsWith('/') ? path : `/${path}`;\n return `${base.replace(/\\/$/, '')}${normalized}`;\n}\n\nexport interface FetchWithTimeoutInit extends RequestInit {\n timeoutMs?: number;\n /** Used in the diagnostic timeout message (e.g. \"Registry\", \"Companion registry\"). */\n diagnosticLabel?: string;\n}\n\nexport async function fetchWithTimeout(\n url: string,\n init: FetchWithTimeoutInit = {},\n): Promise<Response> {\n const timeoutMs = init.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const label = init.diagnosticLabel ?? 'HTTP';\n const signal = AbortSignal.timeout(timeoutMs);\n // Strip the wrapper-only fields before forwarding to `fetch`. The\n // `_` names are conventional unused-binding markers.\n //\n // 6th-pass M1 — tsconfig premise (corrected): the wider repo's\n // `engine/tsconfig.common.json` currently sets both `noUnusedLocals`\n // and `noUnusedParameters` to `false`, so any unused binding (with\n // or without `_` prefix) compiles clean today. If either flag is\n // ever flipped to `true`, TypeScript's underscore-prefix convention\n // applies to parameters reliably and to destructured `let`/`const`\n // bindings depending on TS version + setting — so the `_` prefix\n // here is a defensive signal of \"intentional discard\" should that\n // happen. Today it's purely cosmetic.\n const { timeoutMs: _timeoutMs, diagnosticLabel: _diagnosticLabel, ...rest } = init;\n try {\n return await fetch(url, { ...rest, signal });\n } catch (err) {\n // Typed, so an `isRegistryError(err)` handler sees it (#1763). The budget spans the whole exchange,\n // which is right for a small metadata response; a body read the same signal aborts is translated by\n // the reader (see `readJsonBody`).\n if (isAbortLikeError(err)) throw new RegistryRequestTimeoutError(url, label, RegistryTimeoutPhase.AWAITING_RESPONSE, timeoutMs);\n throw err;\n }\n}\n\n/**\n * Read a small JSON body fetched through {@link fetchWithTimeout}. A read cut short by that request's\n * timeout is a TIMEOUT, never a malformed payload (it used to be reported as one).\n */\nexport async function readJsonBody(res: Response, url: string, label: string, timeoutMs: number | undefined): Promise<unknown> {\n try {\n return await res.json();\n } catch (err) {\n // The headers arrived; the body is what ran out of time (#1763 review).\n if (isAbortLikeError(err)) throw new RegistryRequestTimeoutError(url, label, RegistryTimeoutPhase.READING_BODY, timeoutMs ?? DEFAULT_TIMEOUT_MS);\n throw err;\n }\n}\n\nexport interface TransferInit extends FetchWithTimeoutInit {\n /** No-bytes budget for the body (default {@link REGISTRY_TRANSFER_IDLE_TIMEOUT_MS}). */\n idleTimeoutMs?: number;\n}\n\n/**\n * Fetch for a TRANSFER — an artifact download (#1763). Two budgets, because a metadata timeout cannot\n * be sized for a body of unknown length:\n * - `timeoutMs` bounds the wait for the RESPONSE (status + headers);\n * - `idleTimeoutMs` bounds the silence between body chunks, reset on every chunk.\n * Both aborts surface as `RegistryRequestTimeoutError`, with the phase that fired.\n */\nexport async function fetchTransfer(url: string, init: TransferInit = {}): Promise<{ response: Response; readAll: () => Promise<Uint8Array> }> {\n const timeoutMs = init.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const idleTimeoutMs = init.idleTimeoutMs ?? REGISTRY_TRANSFER_IDLE_TIMEOUT_MS;\n const label = init.diagnosticLabel ?? 'HTTP';\n const { timeoutMs: _t, idleTimeoutMs: _i, diagnosticLabel: _d, ...rest } = init;\n const controller = new AbortController();\n let phase = RegistryTimeoutPhase.AWAITING_RESPONSE;\n let timer = setTimeout(() => controller.abort(), timeoutMs);\n const timeoutError = () =>\n new RegistryRequestTimeoutError(url, label, phase, phase === RegistryTimeoutPhase.AWAITING_RESPONSE ? timeoutMs : idleTimeoutMs);\n let response: Response;\n try {\n response = await fetch(url, { ...rest, signal: controller.signal });\n } catch (err) {\n clearTimeout(timer);\n if (isAbortLikeError(err)) throw timeoutError();\n throw err;\n }\n clearTimeout(timer);\n const readAll = async (): Promise<Uint8Array> => {\n phase = RegistryTimeoutPhase.TRANSFER_STALLED;\n const chunks: Uint8Array[] = [];\n let total = 0;\n const reader = response.body?.getReader();\n if (!reader) return new Uint8Array(0);\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => controller.abort(), idleTimeoutMs);\n };\n arm();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n total += value.byteLength;\n arm();\n }\n } catch (err) {\n if (isAbortLikeError(err) || controller.signal.aborted) throw timeoutError();\n throw err;\n } finally {\n clearTimeout(timer);\n }\n const bytes = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n };\n return { response, readAll };\n}\n\n/**\n * Throws on non-2xx; returns the Response otherwise.\n *\n * C-L2 (4th-pass review) waiver: this helper deliberately throws\n * bare `Error` and is NOT part of the typed `RegistryError`\n * vocabulary. It exists for liveness probes (`ping()`) that wrap\n * the call in their own try/catch and convert any thrown exception\n * to `false`. Future callers MUST do the same — if a caller wants\n * to surface a typed error to the user, they should not use\n * `fetchJsonOk` and should call `fetchWithTimeout` directly +\n * inspect `res.ok` themselves to throw the right\n * `RegistryUnexpectedStatusError` / `RegistryAuthRequiredError` /\n * etc. variant.\n *\n * @internal — internal lib helper, not re-exported from the\n * package root.\n */\nexport async function fetchJsonOk(\n url: string,\n init: FetchWithTimeoutInit = {},\n): Promise<Response> {\n const res = await fetchWithTimeout(url, init);\n if (!res.ok) {\n throw new Error(\n `${init.diagnosticLabel ?? 'HTTP'} request rejected (${res.status} ${res.statusText}) at ${url}`,\n );\n }\n return res;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"_http-client.js","sourceRoot":"","sources":["../../../src/services/_http-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAEpH,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,MAAM,CAAC;AAExD,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC5D,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC;AACnD,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAW,EACX,OAA6B,EAAE;IAE/B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC;IAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9C,kEAAkE;IAClE,qDAAqD;IACrD,EAAE;IACF,+DAA+D;IAC/D,qEAAqE;IACrE,mEAAmE;IACnE,iEAAiE;IACjE,oEAAoE;IACpE,mEAAmE;IACnE,iEAAiE;IACjE,kEAAkE;IAClE,sCAAsC;IACtC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACnF,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,oGAAoG;QACpG,oGAAoG;QACpG,mCAAmC;QACnC,IAAI,gBAAgB,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,2BAA2B,CAAC,GAAG,EAAE,KAAK,EAAE,oBAAoB,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;QAChI,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAa,EAAE,GAAW,EAAE,KAAa,EAAE,SAA6B;IACzG,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,IAAI,gBAAgB,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,2BAA2B,CAAC,GAAG,EAAE,KAAK,EAAE,oBAAoB,CAAC,YAAY,EAAE,SAAS,IAAI,kBAAkB,CAAC,CAAC;QACjJ,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,OAAqB,EAAE;IACtE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACvD,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,iCAAiC,CAAC;IAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC;IAC7C,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAChF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,KAAK,GAAG,oBAAoB,CAAC,iBAAiB,CAAC;IACnD,IAAI,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,IAAI,2BAA2B,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,KAAK,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACnI,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,gBAAgB,CAAC,GAAG,CAAC;YAAE,MAAM,YAAY,EAAE,CAAC;QAChD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,YAAY,CAAC,KAAK,CAAC,CAAC;IACpB,MAAM,OAAO,GAAG,KAAK,IAAyB,EAAE;QAC9C,KAAK,GAAG,oBAAoB,CAAC,gBAAgB,CAAC;QAC9C,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,EAAE;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,aAAa,CAAC,CAAC;QAC9D,CAAC,CAAC;QACF,GAAG,EAAE,CAAC;QACN,IAAI,CAAC;YACH,SAAS,CAAC;gBACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI;oBAAE,MAAM;gBAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnB,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;gBAC1B,GAAG,EAAE,CAAC;YACR,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;gBAAE,MAAM,YAAY,EAAE,CAAC;YAC7E,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,OAA6B,EAAE;IAE/B,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,eAAe,IAAI,MAAM,sBAAsB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,QAAQ,GAAG,EAAE,CACjG,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * Internal HTTP client utilities shared by `RegistryServerClient`\n * and `RegistryCompanionClient`.\n *\n * Both clients want the same primitives:\n * - `joinUrl(base, path)` — single-source-of-truth path joiner\n * that tolerates leading/trailing slashes;\n * - `fetchWithTimeout(url, init)` — one budget for a metadata\n * exchange; an abort becomes a typed `RegistryRequestTimeoutError`;\n * - `readJsonBody(...)` — reads that exchange's JSON body, typing a\n * body cut short by the same budget as a `READING_BODY` timeout;\n * - `fetchTransfer(url, init)` — an artifact download: a response\n * budget plus an idle budget between body chunks (#1763);\n * - `fetchJsonOk(...)` — convenience for liveness probes that\n * want a boolean answer.\n *\n * The leading underscore signals \"package-internal\" — these are\n * intentionally NOT re-exported from `services/index.ts`. Phase 2\n * services that need fancier HTTP (multipart upload, streaming\n * download) extend this file rather than copy the primitives.\n */\n\nimport { isAbortLikeError, RegistryRequestTimeoutError, RegistryTimeoutPhase } from '@wildo-ai/platform-config-lib';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * How long a DOWNLOAD may go without receiving a single byte (#1763). An idle budget, not a cap on the\n * whole body: a large artifact over a slow but moving link finishes, a stalled one fails. 30 s is the\n * order npm and cargo tolerate before calling a transfer stuck.\n */\nexport const REGISTRY_TRANSFER_IDLE_TIMEOUT_MS = 30_000;\n\nexport function joinUrl(base: string, path: string): string {\n const normalized = path.startsWith('/') ? path : `/${path}`;\n return `${base.replace(/\\/$/, '')}${normalized}`;\n}\n\nexport interface FetchWithTimeoutInit extends RequestInit {\n timeoutMs?: number;\n /** Used in the diagnostic timeout message (e.g. \"Registry\", \"Companion registry\"). */\n diagnosticLabel?: string;\n}\n\nexport async function fetchWithTimeout(\n url: string,\n init: FetchWithTimeoutInit = {},\n): Promise<Response> {\n const timeoutMs = init.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const label = init.diagnosticLabel ?? 'HTTP';\n const signal = AbortSignal.timeout(timeoutMs);\n // Strip the wrapper-only fields before forwarding to `fetch`. The\n // `_` names are conventional unused-binding markers.\n //\n // 6th-pass M1 — tsconfig premise (corrected): the wider repo's\n // `engine/tsconfig.common.json` currently sets both `noUnusedLocals`\n // and `noUnusedParameters` to `false`, so any unused binding (with\n // or without `_` prefix) compiles clean today. If either flag is\n // ever flipped to `true`, TypeScript's underscore-prefix convention\n // applies to parameters reliably and to destructured `let`/`const`\n // bindings depending on TS version + setting — so the `_` prefix\n // here is a defensive signal of \"intentional discard\" should that\n // happen. Today it's purely cosmetic.\n const { timeoutMs: _timeoutMs, diagnosticLabel: _diagnosticLabel, ...rest } = init;\n try {\n return await fetch(url, { ...rest, signal });\n } catch (err) {\n // Typed, so an `isRegistryError(err)` handler sees it (#1763). The budget spans the whole exchange,\n // which is right for a small metadata response; a body read the same signal aborts is translated by\n // the reader (see `readJsonBody`).\n if (isAbortLikeError(err)) throw new RegistryRequestTimeoutError(url, label, RegistryTimeoutPhase.AWAITING_RESPONSE, timeoutMs);\n throw err;\n }\n}\n\n/**\n * Read a small JSON body fetched through {@link fetchWithTimeout}. A read cut short by that request's\n * timeout is a TIMEOUT, never a malformed payload (it used to be reported as one).\n */\nexport async function readJsonBody(res: Response, url: string, label: string, timeoutMs: number | undefined): Promise<unknown> {\n try {\n return await res.json();\n } catch (err) {\n // The headers arrived; the body is what ran out of time (#1763 review).\n if (isAbortLikeError(err)) throw new RegistryRequestTimeoutError(url, label, RegistryTimeoutPhase.READING_BODY, timeoutMs ?? DEFAULT_TIMEOUT_MS);\n throw err;\n }\n}\n\nexport interface TransferInit extends FetchWithTimeoutInit {\n /** No-bytes budget for the body (default {@link REGISTRY_TRANSFER_IDLE_TIMEOUT_MS}). */\n idleTimeoutMs?: number;\n}\n\n/**\n * Fetch for a TRANSFER — an artifact download (#1763). Two budgets, because a metadata timeout cannot\n * be sized for a body of unknown length:\n * - `timeoutMs` bounds the wait for the RESPONSE (status + headers);\n * - `idleTimeoutMs` bounds the silence between body chunks, reset on every chunk.\n * Both aborts surface as `RegistryRequestTimeoutError`, with the phase that fired.\n */\nexport async function fetchTransfer(url: string, init: TransferInit = {}): Promise<{ response: Response; readAll: () => Promise<Uint8Array> }> {\n const timeoutMs = init.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const idleTimeoutMs = init.idleTimeoutMs ?? REGISTRY_TRANSFER_IDLE_TIMEOUT_MS;\n const label = init.diagnosticLabel ?? 'HTTP';\n const { timeoutMs: _t, idleTimeoutMs: _i, diagnosticLabel: _d, ...rest } = init;\n const controller = new AbortController();\n let phase = RegistryTimeoutPhase.AWAITING_RESPONSE;\n let timer = setTimeout(() => controller.abort(), timeoutMs);\n const timeoutError = () =>\n new RegistryRequestTimeoutError(url, label, phase, phase === RegistryTimeoutPhase.AWAITING_RESPONSE ? timeoutMs : idleTimeoutMs);\n let response: Response;\n try {\n response = await fetch(url, { ...rest, signal: controller.signal });\n } catch (err) {\n clearTimeout(timer);\n if (isAbortLikeError(err)) throw timeoutError();\n throw err;\n }\n clearTimeout(timer);\n const readAll = async (): Promise<Uint8Array> => {\n phase = RegistryTimeoutPhase.TRANSFER_STALLED;\n const chunks: Uint8Array[] = [];\n let total = 0;\n const reader = response.body?.getReader();\n if (!reader) return new Uint8Array(0);\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => controller.abort(), idleTimeoutMs);\n };\n arm();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n total += value.byteLength;\n arm();\n }\n } catch (err) {\n if (isAbortLikeError(err) || controller.signal.aborted) throw timeoutError();\n throw err;\n } finally {\n clearTimeout(timer);\n }\n const bytes = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n };\n return { response, readAll };\n}\n\n/**\n * Throws on non-2xx; returns the Response otherwise.\n *\n * C-L2 (4th-pass review) waiver: this helper deliberately throws\n * bare `Error` and is NOT part of the typed `RegistryError`\n * vocabulary. It exists for liveness probes (`ping()`) that wrap\n * the call in their own try/catch and convert any thrown exception\n * to `false`. Future callers MUST do the same — if a caller wants\n * to surface a typed error to the user, they should not use\n * `fetchJsonOk` and should call `fetchWithTimeout` directly +\n * inspect `res.ok` themselves to throw the right\n * `RegistryUnexpectedStatusError` / `RegistryAuthRequiredError` /\n * etc. variant.\n *\n * @internal — internal lib helper, not re-exported from the\n * package root.\n */\nexport async function fetchJsonOk(\n url: string,\n init: FetchWithTimeoutInit = {},\n): Promise<Response> {\n const res = await fetchWithTimeout(url, init);\n if (!res.ok) {\n throw new Error(\n `${init.diagnosticLabel ?? 'HTTP'} request rejected (${res.status} ${res.statusText}) at ${url}`,\n );\n }\n return res;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_zod-issue-formatting.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"_zod-issue-formatting.d.ts","sourceRoot":"","sources":["../../../src/services/_zod-issue-formatting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAiCpC;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAOnE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC;AAChD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lockfile-repair.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"lockfile-repair.service.d.ts","sourceRoot":"","sources":["../../../src/services/lockfile-repair.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EAGL,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AAcvC,MAAM,MAAM,qBAAqB,GAC7B;IACE,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACD;IACE,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACD;IACE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC5C;AAWD,eAAO,MAAM,qBAAqB;IAChC,iDAAiD;iCAC/B,MAAM,KAAG,MAAM;IAIjC;;OAEG;iCACqB,MAAM,KAAG,OAAO,CAAC,oBAAoB,CAAC;IA8E9D;;OAEG;8CAES,MAAM,YACN,MAAM,SACT,wBAAwB,YACrB,qBAAqB,EAAE,KAChC,OAAO,CAAC,IAAI,CAAC;CAaR,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-adopter.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"module-adopter.service.d.ts","sourceRoot":"","sources":["../../../src/services/module-adopter.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAAuD,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACzH,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAErF,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,wEAAwE;IACxE,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,oDAAoD;IACpD,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;CAChB;AAuCD,eAAO,MAAM,oBAAoB;IAC/B;;;OAGG;6CAES,MAAM,YACN,cAAc,KACvB,OAAO,CAAC,YAAY,CAAC;IAyBxB;;;OAGG;wCAES,MAAM,YACN,cAAc,KACvB,OAAO,CAAC,cAAc,CAAC;IAO1B;;;;OAIG;yCAES,MAAM,YACN,cAAc,QAClB,YAAY,KACjB,OAAO,CAAC;QAAE,OAAO,EAAE,YAAY,CAAC;QAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;CAezD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-adopter.service.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"module-adopter.service.js","sourceRoot":"","sources":["../../../src/services/module-adopter.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `ModuleAdopterService` — Phase 2 CLI-direct adoption flow.\n *\n * `wildo registry adopt` takes existing app code that fits the\n * Wildo module-artifact shape and prepares it for publication\n * (KD-14). Adoption is intentionally CLI-DIRECT (Review-pass-3 /\n * MEDIUM-G) — it only reads source slices and stages files. AST\n * mutations on the host app's source are NOT part of adopt; if a\n * future flow needs them, they go through the companion HTTP\n * surface like every other source-mutating verb.\n *\n * Service surface:\n * - `discoverModuleFiles(saasRoot, manifest)` — walks each\n * declared `boundaries.*` allow-list and returns the set of\n * files that exist on disk and are within the boundary.\n * - `adoptToStaging(saasRoot, manifest)` — clears + populates\n * `<saasRoot>/.wildo-saas/generated/modules-artifacts/<id>/`\n * with the manifest + every discovered file, then computes\n * the staging digest. Phase 6 plugs this into the publish\n * flow.\n */\n\nimport { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport { isModuleArtifactPathAllowed, MODULE_BOUNDARY_LAYERS, type ModuleManifest } from '@wildo-ai/platform-config-lib';\nimport { ModulePackagerService, type StagingPaths } from './module-packager.service';\n\nexport interface AdoptionPlan {\n /** Per-layer file list, relative to saas root. */\n files: readonly string[];\n /** Empty when every declared boundary contributed at least one file. */\n emptyBoundaries: readonly string[];\n}\n\nexport interface AdoptionResult {\n manifest: ModuleManifest;\n staging: StagingPaths;\n /** Files that were copied into the staging root. */\n staged: readonly string[];\n /** sha256 digest of the staged tree (matches `Sha256DigestSchema`). */\n digest: string;\n}\n\nasync function fileExists(absPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(absPath);\n return stat.isFile() || stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function walkBoundary(\n saasRoot: string,\n appRelative: string,\n): Promise<string[]> {\n const abs = path.resolve(saasRoot, appRelative);\n if (!(await fileExists(abs))) return [];\n const stat = await fs.stat(abs);\n if (stat.isFile()) return [appRelative];\n const out: string[] = [];\n const queue: string[] = [appRelative];\n while (queue.length > 0) {\n const cur = queue.shift()!;\n const entries = await fs.readdir(path.resolve(saasRoot, cur), { withFileTypes: true });\n for (const entry of entries) {\n const rel = path.join(cur, entry.name);\n // Skip what a module never ships, exactly as `wildo registry publish` does — otherwise the\n // packager (which refuses those paths) throws on a module's own `.env` or `node_modules`.\n if (!isModuleArtifactPathAllowed(rel.split(path.sep).join('/'))) continue;\n if (entry.isDirectory()) {\n queue.push(rel);\n } else if (entry.isFile()) {\n out.push(rel);\n }\n }\n }\n return out;\n}\n\nexport const ModuleAdopterService = {\n /**\n * Walk every declared `boundaries.*` allow-list and return the\n * files that actually exist on disk.\n */\n async discoverModuleFiles(\n saasRoot: string,\n manifest: ModuleManifest,\n ): Promise<AdoptionPlan> {\n const boundaries = manifest.boundaries;\n if (!boundaries) {\n return { files: [], emptyBoundaries: [] };\n }\n // Every layer the registry knows, not a hand-kept copy: a copy here missed `providers` (#2014).\n const layers = MODULE_BOUNDARY_LAYERS;\n const aggregate = new Set<string>();\n const empty: string[] = [];\n for (const layer of layers) {\n const allows = boundaries[layer];\n let layerCount = 0;\n for (const rel of allows) {\n const collected = await walkBoundary(saasRoot, rel);\n for (const file of collected) aggregate.add(file);\n layerCount += collected.length;\n }\n if (allows.length > 0 && layerCount === 0) empty.push(layer);\n }\n return {\n files: [...aggregate].sort(),\n emptyBoundaries: empty,\n };\n },\n\n /**\n * Stage the module from existing app source. Idempotent — calling\n * twice with the same source produces the same digest.\n */\n async adoptToStaging(\n saasRoot: string,\n manifest: ModuleManifest,\n ): Promise<AdoptionResult> {\n const plan = await this.discoverModuleFiles(saasRoot, manifest);\n const { staging, written } = await this.runAdoptionPlan(saasRoot, manifest, plan);\n const digest = await ModulePackagerService.computeStagingDigest(saasRoot, manifest.id);\n return { manifest, staging, staged: written, digest };\n },\n\n /**\n * Re-usable apply step: writes manifest + copies every file in\n * the plan. Exposed so Phase 6 publish can reuse it after a\n * separate staging-prep step.\n */\n async runAdoptionPlan(\n saasRoot: string,\n manifest: ModuleManifest,\n plan: AdoptionPlan,\n ): Promise<{ staging: StagingPaths; written: readonly string[] }> {\n const staging = await ModulePackagerService.stageFresh(saasRoot, manifest.id);\n await ModulePackagerService.writeManifest({ saasRoot, manifest });\n const written: string[] = [];\n for (const appRelativePath of plan.files) {\n const result = await ModulePackagerService.copyFile({\n saasRoot,\n moduleId: manifest.id,\n appRelativePath,\n manifest,\n });\n written.push(result.appRelativePath);\n }\n return { staging, written };\n },\n} as const;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-packager.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"module-packager.service.d.ts","sourceRoot":"","sources":["../../../src/services/module-packager.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AAEvC,eAAO,MAAM,8BAA8B,4CAA4C,CAAC;AAExF,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAyBtF;AA+BD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,wBAAwB,GAAG,SAAS,GAC/C,MAAM,CAgBR;AAED,eAAO,MAAM,qBAAqB;IAChC;;OAEG;+BACa,MAAM,YAAY,MAAM,KAAG,YAAY;IAIvD;;;;OAIG;oCACwB,MAAM,YAAY,MAAM,KAAG,OAAO,CAAC,YAAY,CAAC;IAO3E;;;;;;;;OAQG;8BACkB;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,EAAE,cAAc,CAAC;KAC1B,KAAG,OAAO,CAAC;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC;IAehE;;;;OAIG;mCACuB;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,cAAc,CAAC;KAC1B,KAAG,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAA;KAAE,CAAC;IAQ/D;;;;;;;;;;;;OAYG;8CACkC,MAAM,YAAY,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;CAmBvE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-packager.service.js","sourceRoot":"","sources":["../../../../src/services/module-packager.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `ModulePackagerService` — Phase 2 staging logic for module\n * publishing.\n *\n * Per KD-8 / `module-registry-analysis.md`:\n * - Published artifacts are zip archives staged under\n * `<saasRoot>/.wildo-saas/generated/modules-artifacts/<module.id>/`.\n * - The staged folder is the source of the artifact. It must\n * include the `wildo.module.json` manifest, copied source\n * files, and dependency declarations.\n *\n * Phase 2 ships the staging-folder primitives (path resolution,\n * stage-fresh, copy-source-tree, write-manifest, compute-digest).\n * Phase 6 wires `wildo registry publish` to call these and the zip\n * step. Phase 5 install consumes the same digest.\n *\n * Hard contracts:\n * - Staging is always a fresh tree per call (`stageFresh`\n * removes the destination first). The artifact's content\n * digest is over-the-wire deterministic — leftover bytes\n * from a previous failed stage MUST NOT leak into the digest.\n * - The staged tree is a CHILD of `<saasRoot>/.wildo-saas/`,\n * never reaches outside `saasRoot`.\n * - Boundary enforcement (KD-12) lives in this service: the\n * staging primitive rejects file paths that escape the\n * declared `boundaries.<layer>` allow-list, so a publish\n * can never claim app surface it doesn't own.\n */\n\nimport { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport {\n flattenModuleBoundaries,\n isModuleArtifactPathAllowed,\n isModuleId,\n ModuleManifestSchema,\n RegistryBoundaryViolationError,\n type ModuleManifest,\n type ModuleManifestBoundaries,\n MODULE_MANIFEST_FILE_NAME as MANIFEST_FILE_NAME,\n} from '@wildo-ai/platform-config-lib';\n\nexport const MODULES_ARTIFACTS_RELATIVE_DIR = '.wildo-saas/generated/modules-artifacts';\n\nexport interface StagingPaths {\n /** Absolute path to the per-module staging root. */\n stagingRoot: string;\n /** Absolute path to the manifest file inside the staging root. */\n manifestPath: string;\n}\n\n/**\n * Resolve the per-module staging paths. Pure path arithmetic — no\n * fs side effects.\n */\nexport function getModuleStagingPaths(saasRoot: string, moduleId: string): StagingPaths {\n // The full `<scope>/<name>` shape, not merely \"contains a `/`\": `stageFresh` runs a recursive delete\n // on the path built here, and `a/../../../..` contained a slash.\n if (!isModuleId(moduleId)) {\n // C-L3 (4th-pass review): `TypeError` is Node's standard for\n // argument-shape violations. The typed `RegistryError` subclasses\n // model registry-runtime conditions (auth, integrity, version\n // not found); a malformed `moduleId` argument is a developer\n // contract violation that downstream `isRegistryError(err)`\n // handlers should NOT catch. `TypeError` keeps the error visible\n // and stops the typed-error vocabulary from absorbing pure\n // argument-validation concerns.\n throw new TypeError(\n `Module id \"${moduleId}\" must be in <scope>/<name> form (e.g. \"acme/billing\"), each half lowercase letters, digits, \".\", \"_\" or \"-\".`,\n );\n }\n const artifactsRoot = path.resolve(saasRoot, MODULES_ARTIFACTS_RELATIVE_DIR);\n const stagingRoot = path.resolve(artifactsRoot, moduleId);\n if (!isPathInside(stagingRoot, artifactsRoot) || stagingRoot === artifactsRoot) {\n throw new TypeError(`Module id \"${moduleId}\" resolves outside ${MODULES_ARTIFACTS_RELATIVE_DIR}.`);\n }\n return {\n stagingRoot,\n manifestPath: path.join(stagingRoot, MANIFEST_FILE_NAME),\n };\n}\n\n/**\n * Returns `true` iff `child` is the same path as `parent` or\n * a descendant of it. Both arguments are expected to be absolute,\n * already resolved (no `..` segments). Tail-`/` arithmetic prevents\n * the classic `/foo/barx` → `/foo/bar` false-positive.\n *\n * Extracted as a helper (5th-pass C-L2) so the boundary check below\n * and the future zip-slip / symlink-escape guards in this package\n * share one reading of the containment rule.\n *\n * 6th-pass C-L1 — root edge case: when `parent` is the filesystem\n * root (`/` on POSIX, `C:\\` on Windows), appending `path.sep` would\n * produce `//` or `C:\\\\` and `startsWith` would reject every child.\n * Treat the root as a special case: any absolute child path is\n * \"inside\" the root by definition. Vanishingly unlikely in practice\n * (containerized SaaS roots are not literally `/`) but the helper\n * is also reusable for zip-slip guards where the assumption is\n * weaker.\n */\nfunction isPathInside(child: string, parent: string): boolean {\n // Special-case the filesystem root: any absolute child is inside it.\n if (parent === path.sep || /^[a-zA-Z]:[\\\\/]?$/.test(parent)) {\n return path.isAbsolute(child);\n }\n const childWithSep = child + path.sep;\n const parentWithSep = parent + path.sep;\n return childWithSep.startsWith(parentWithSep);\n}\n\n/**\n * Verify a candidate file path is contained inside one of the\n * manifest's declared `boundaries` (KD-12). Returns the resolved\n * absolute path on success; throws `RegistryBoundaryViolationError`\n * otherwise.\n */\nexport function assertWithinBoundaries(\n saasRoot: string,\n moduleId: string,\n appRelativePath: string,\n boundaries: ModuleManifestBoundaries | undefined,\n): string {\n const absolute = path.resolve(saasRoot, appRelativePath);\n // Path must stay inside saasRoot (no `..` escapes), and be a path a module artifact may carry at\n // all — no dot-segment (`.env`, `.git`), no `node_modules` — whatever the boundaries say.\n if (!isPathInside(absolute, path.resolve(saasRoot)) || !isModuleArtifactPathAllowed(appRelativePath.split(path.sep).join('/'))) {\n throw new RegistryBoundaryViolationError(moduleId, appRelativePath);\n }\n // No declared boundary means the module may write NOWHERE. This used to return early and admit\n // every path in the application — the fail-open reading of an absent declaration.\n const allowed: readonly string[] = flattenModuleBoundaries(boundaries);\n // The candidate must be inside at least one declared boundary.\n const isInside = allowed.some((rel) => isPathInside(absolute, path.resolve(saasRoot, rel)));\n if (!isInside) {\n throw new RegistryBoundaryViolationError(moduleId, appRelativePath);\n }\n return absolute;\n}\n\nexport const ModulePackagerService = {\n /**\n * Compute the per-module staging paths.\n */\n paths(saasRoot: string, moduleId: string): StagingPaths {\n return getModuleStagingPaths(saasRoot, moduleId);\n },\n\n /**\n * Remove and recreate the staging root. The freshness guarantee\n * is critical for digest determinism — `stageFresh` is the only\n * way to enter the per-module staging root.\n */\n async stageFresh(saasRoot: string, moduleId: string): Promise<StagingPaths> {\n const paths = getModuleStagingPaths(saasRoot, moduleId);\n await fs.rm(paths.stagingRoot, { recursive: true, force: true });\n await fs.mkdir(paths.stagingRoot, { recursive: true });\n return paths;\n },\n\n /**\n * Copy a single file from the app source into the staging tree.\n * Path is verified against the manifest's declared boundaries\n * (KD-12) — files outside `boundaries.*` are rejected with\n * `RegistryBoundaryViolationError`. The relative path INSIDE the\n * staging root mirrors the relative path inside the saas root,\n * so callers don't need to translate paths between the two\n * trees.\n */\n async copyFile(args: {\n saasRoot: string;\n moduleId: string;\n appRelativePath: string;\n manifest: ModuleManifest;\n }): Promise<{ stagedAbsolute: string; appRelativePath: string }> {\n const { saasRoot, moduleId, appRelativePath, manifest } = args;\n const sourceAbsolute = assertWithinBoundaries(\n saasRoot,\n moduleId,\n appRelativePath,\n manifest.boundaries,\n );\n const { stagingRoot } = getModuleStagingPaths(saasRoot, moduleId);\n const destAbsolute = path.join(stagingRoot, appRelativePath);\n await fs.mkdir(path.dirname(destAbsolute), { recursive: true });\n await fs.copyFile(sourceAbsolute, destAbsolute);\n return { stagedAbsolute: destAbsolute, appRelativePath };\n },\n\n /**\n * Validate the manifest, then write `wildo.module.json` into the\n * staging root. Manifest authors who pass a typo-laden object\n * get a Zod parse error here, before any zip work.\n */\n async writeManifest(args: {\n saasRoot: string;\n manifest: ModuleManifest;\n }): Promise<{ manifestPath: string; manifest: ModuleManifest }> {\n const validated = ModuleManifestSchema.parse(args.manifest);\n const { manifestPath, stagingRoot } = getModuleStagingPaths(args.saasRoot, validated.id);\n await fs.mkdir(stagingRoot, { recursive: true });\n await fs.writeFile(manifestPath, JSON.stringify(validated, null, 2) + '\\n', 'utf8');\n return { manifestPath, manifest: validated };\n },\n\n /**\n * Compute the sha256 digest of every file in the staging tree, in\n * stable lexicographic path order. Returns the canonical\n * `sha256:<64-hex>` form.\n *\n * The digest is over-the-wire deterministic for the same set of\n * staged files because:\n * 1. File order is sorted lexicographically (no fs traversal\n * randomness leaks in).\n * 2. The path prefix is the relative-from-staging-root path\n * (no absolute-path noise).\n * 3. We append the file content bytes verbatim.\n */\n async computeStagingDigest(saasRoot: string, moduleId: string): Promise<string> {\n const { stagingRoot } = getModuleStagingPaths(saasRoot, moduleId);\n const files = await collectFilesRelative(stagingRoot, '');\n // Normalize separators to POSIX before sorting + hashing — the\n // digest must reproduce across platforms for the same staged\n // tree, so the bytes fed into the hash cannot depend on the\n // publisher's OS path-separator convention.\n const normalized = files.map((f) => f.split(path.sep).join(path.posix.sep));\n normalized.sort();\n const hash = createHash('sha256');\n for (const rel of normalized) {\n const abs = path.join(stagingRoot, rel.split(path.posix.sep).join(path.sep));\n hash.update(rel);\n hash.update('\\0');\n hash.update(await fs.readFile(abs));\n hash.update('\\0');\n }\n return `sha256:${hash.digest('hex')}`;\n },\n} as const;\n\nasync function collectFilesRelative(rootAbs: string, prefix: string): Promise<string[]> {\n const here = path.join(rootAbs, prefix);\n const entries = await fs.readdir(here, { withFileTypes: true });\n const out: string[] = [];\n for (const entry of entries) {\n const rel = path.join(prefix, entry.name);\n if (entry.isDirectory()) {\n out.push(...(await collectFilesRelative(rootAbs, rel)));\n } else if (entry.isFile()) {\n out.push(rel);\n }\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"module-packager.service.js","sourceRoot":"","sources":["../../../src/services/module-packager.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `ModulePackagerService` — Phase 2 staging logic for module\n * publishing.\n *\n * Per KD-8 / `module-registry-analysis.md`:\n * - Published artifacts are zip archives staged under\n * `<saasRoot>/.wildo-saas/generated/modules-artifacts/<module.id>/`.\n * - The staged folder is the source of the artifact. It must\n * include the `wildo.module.json` manifest, copied source\n * files, and dependency declarations.\n *\n * Phase 2 ships the staging-folder primitives (path resolution,\n * stage-fresh, copy-source-tree, write-manifest, compute-digest).\n * Phase 6 wires `wildo registry publish` to call these and the zip\n * step. Phase 5 install consumes the same digest.\n *\n * Hard contracts:\n * - Staging is always a fresh tree per call (`stageFresh`\n * removes the destination first). The artifact's content\n * digest is over-the-wire deterministic — leftover bytes\n * from a previous failed stage MUST NOT leak into the digest.\n * - The staged tree is a CHILD of `<saasRoot>/.wildo-saas/`,\n * never reaches outside `saasRoot`.\n * - Boundary enforcement (KD-12) lives in this service: the\n * staging primitive rejects file paths that escape the\n * declared `boundaries.<layer>` allow-list, so a publish\n * can never claim app surface it doesn't own.\n */\n\nimport { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport {\n flattenModuleBoundaries,\n isModuleArtifactPathAllowed,\n isModuleId,\n ModuleManifestSchema,\n RegistryBoundaryViolationError,\n type ModuleManifest,\n type ModuleManifestBoundaries,\n MODULE_MANIFEST_FILE_NAME as MANIFEST_FILE_NAME,\n} from '@wildo-ai/platform-config-lib';\n\nexport const MODULES_ARTIFACTS_RELATIVE_DIR = '.wildo-saas/generated/modules-artifacts';\n\nexport interface StagingPaths {\n /** Absolute path to the per-module staging root. */\n stagingRoot: string;\n /** Absolute path to the manifest file inside the staging root. */\n manifestPath: string;\n}\n\n/**\n * Resolve the per-module staging paths. Pure path arithmetic — no\n * fs side effects.\n */\nexport function getModuleStagingPaths(saasRoot: string, moduleId: string): StagingPaths {\n // The full `<scope>/<name>` shape, not merely \"contains a `/`\": `stageFresh` runs a recursive delete\n // on the path built here, and `a/../../../..` contained a slash.\n if (!isModuleId(moduleId)) {\n // C-L3 (4th-pass review): `TypeError` is Node's standard for\n // argument-shape violations. The typed `RegistryError` subclasses\n // model registry-runtime conditions (auth, integrity, version\n // not found); a malformed `moduleId` argument is a developer\n // contract violation that downstream `isRegistryError(err)`\n // handlers should NOT catch. `TypeError` keeps the error visible\n // and stops the typed-error vocabulary from absorbing pure\n // argument-validation concerns.\n throw new TypeError(\n `Module id \"${moduleId}\" must be in <scope>/<name> form (e.g. \"acme/billing\"), each half lowercase letters, digits, \".\", \"_\" or \"-\".`,\n );\n }\n const artifactsRoot = path.resolve(saasRoot, MODULES_ARTIFACTS_RELATIVE_DIR);\n const stagingRoot = path.resolve(artifactsRoot, moduleId);\n if (!isPathInside(stagingRoot, artifactsRoot) || stagingRoot === artifactsRoot) {\n throw new TypeError(`Module id \"${moduleId}\" resolves outside ${MODULES_ARTIFACTS_RELATIVE_DIR}.`);\n }\n return {\n stagingRoot,\n manifestPath: path.join(stagingRoot, MANIFEST_FILE_NAME),\n };\n}\n\n/**\n * Returns `true` iff `child` is the same path as `parent` or\n * a descendant of it. Both arguments are expected to be absolute,\n * already resolved (no `..` segments). Tail-`/` arithmetic prevents\n * the classic `/foo/barx` → `/foo/bar` false-positive.\n *\n * Extracted as a helper (5th-pass C-L2) so the boundary check below\n * and the future zip-slip / symlink-escape guards in this package\n * share one reading of the containment rule.\n *\n * 6th-pass C-L1 — root edge case: when `parent` is the filesystem\n * root (`/` on POSIX, `C:\\` on Windows), appending `path.sep` would\n * produce `//` or `C:\\\\` and `startsWith` would reject every child.\n * Treat the root as a special case: any absolute child path is\n * \"inside\" the root by definition. Vanishingly unlikely in practice\n * (containerized SaaS roots are not literally `/`) but the helper\n * is also reusable for zip-slip guards where the assumption is\n * weaker.\n */\nfunction isPathInside(child: string, parent: string): boolean {\n // Special-case the filesystem root: any absolute child is inside it.\n if (parent === path.sep || /^[a-zA-Z]:[\\\\/]?$/.test(parent)) {\n return path.isAbsolute(child);\n }\n const childWithSep = child + path.sep;\n const parentWithSep = parent + path.sep;\n return childWithSep.startsWith(parentWithSep);\n}\n\n/**\n * Verify a candidate file path is contained inside one of the\n * manifest's declared `boundaries` (KD-12). Returns the resolved\n * absolute path on success; throws `RegistryBoundaryViolationError`\n * otherwise.\n */\nexport function assertWithinBoundaries(\n saasRoot: string,\n moduleId: string,\n appRelativePath: string,\n boundaries: ModuleManifestBoundaries | undefined,\n): string {\n const absolute = path.resolve(saasRoot, appRelativePath);\n // Path must stay inside saasRoot (no `..` escapes), and be a path a module artifact may carry at\n // all — no dot-segment (`.env`, `.git`), no `node_modules` — whatever the boundaries say.\n if (!isPathInside(absolute, path.resolve(saasRoot)) || !isModuleArtifactPathAllowed(appRelativePath.split(path.sep).join('/'))) {\n throw new RegistryBoundaryViolationError(moduleId, appRelativePath);\n }\n // No declared boundary means the module may write NOWHERE. This used to return early and admit\n // every path in the application — the fail-open reading of an absent declaration.\n const allowed: readonly string[] = flattenModuleBoundaries(boundaries);\n // The candidate must be inside at least one declared boundary.\n const isInside = allowed.some((rel) => isPathInside(absolute, path.resolve(saasRoot, rel)));\n if (!isInside) {\n throw new RegistryBoundaryViolationError(moduleId, appRelativePath);\n }\n return absolute;\n}\n\nexport const ModulePackagerService = {\n /**\n * Compute the per-module staging paths.\n */\n paths(saasRoot: string, moduleId: string): StagingPaths {\n return getModuleStagingPaths(saasRoot, moduleId);\n },\n\n /**\n * Remove and recreate the staging root. The freshness guarantee\n * is critical for digest determinism — `stageFresh` is the only\n * way to enter the per-module staging root.\n */\n async stageFresh(saasRoot: string, moduleId: string): Promise<StagingPaths> {\n const paths = getModuleStagingPaths(saasRoot, moduleId);\n await fs.rm(paths.stagingRoot, { recursive: true, force: true });\n await fs.mkdir(paths.stagingRoot, { recursive: true });\n return paths;\n },\n\n /**\n * Copy a single file from the app source into the staging tree.\n * Path is verified against the manifest's declared boundaries\n * (KD-12) — files outside `boundaries.*` are rejected with\n * `RegistryBoundaryViolationError`. The relative path INSIDE the\n * staging root mirrors the relative path inside the saas root,\n * so callers don't need to translate paths between the two\n * trees.\n */\n async copyFile(args: {\n saasRoot: string;\n moduleId: string;\n appRelativePath: string;\n manifest: ModuleManifest;\n }): Promise<{ stagedAbsolute: string; appRelativePath: string }> {\n const { saasRoot, moduleId, appRelativePath, manifest } = args;\n const sourceAbsolute = assertWithinBoundaries(\n saasRoot,\n moduleId,\n appRelativePath,\n manifest.boundaries,\n );\n const { stagingRoot } = getModuleStagingPaths(saasRoot, moduleId);\n const destAbsolute = path.join(stagingRoot, appRelativePath);\n await fs.mkdir(path.dirname(destAbsolute), { recursive: true });\n await fs.copyFile(sourceAbsolute, destAbsolute);\n return { stagedAbsolute: destAbsolute, appRelativePath };\n },\n\n /**\n * Validate the manifest, then write `wildo.module.json` into the\n * staging root. Manifest authors who pass a typo-laden object\n * get a Zod parse error here, before any zip work.\n */\n async writeManifest(args: {\n saasRoot: string;\n manifest: ModuleManifest;\n }): Promise<{ manifestPath: string; manifest: ModuleManifest }> {\n const validated = ModuleManifestSchema.parse(args.manifest);\n const { manifestPath, stagingRoot } = getModuleStagingPaths(args.saasRoot, validated.id);\n await fs.mkdir(stagingRoot, { recursive: true });\n await fs.writeFile(manifestPath, JSON.stringify(validated, null, 2) + '\\n', 'utf8');\n return { manifestPath, manifest: validated };\n },\n\n /**\n * Compute the sha256 digest of every file in the staging tree, in\n * stable lexicographic path order. Returns the canonical\n * `sha256:<64-hex>` form.\n *\n * The digest is over-the-wire deterministic for the same set of\n * staged files because:\n * 1. File order is sorted lexicographically (no fs traversal\n * randomness leaks in).\n * 2. The path prefix is the relative-from-staging-root path\n * (no absolute-path noise).\n * 3. We append the file content bytes verbatim.\n */\n async computeStagingDigest(saasRoot: string, moduleId: string): Promise<string> {\n const { stagingRoot } = getModuleStagingPaths(saasRoot, moduleId);\n const files = await collectFilesRelative(stagingRoot, '');\n // Normalize separators to POSIX before sorting + hashing — the\n // digest must reproduce across platforms for the same staged\n // tree, so the bytes fed into the hash cannot depend on the\n // publisher's OS path-separator convention.\n const normalized = files.map((f) => f.split(path.sep).join(path.posix.sep));\n normalized.sort();\n const hash = createHash('sha256');\n for (const rel of normalized) {\n const abs = path.join(stagingRoot, rel.split(path.posix.sep).join(path.sep));\n hash.update(rel);\n hash.update('\\0');\n hash.update(await fs.readFile(abs));\n hash.update('\\0');\n }\n return `sha256:${hash.digest('hex')}`;\n },\n} as const;\n\nasync function collectFilesRelative(rootAbs: string, prefix: string): Promise<string[]> {\n const here = path.join(rootAbs, prefix);\n const entries = await fs.readdir(here, { withFileTypes: true });\n const out: string[] = [];\n for (const entry of entries) {\n const rel = path.join(prefix, entry.name);\n if (entry.isDirectory()) {\n out.push(...(await collectFilesRelative(rootAbs, rel)));\n } else if (entry.isFile()) {\n out.push(rel);\n }\n }\n return out;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-materialization-hook.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"provider-materialization-hook.d.ts","sourceRoot":"","sources":["../../../src/services/provider-materialization-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAE3E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;IAC5D,GAAG,CAAC,EAAE,oBAAoB,CAAC;CAC5B;AAED,MAAM,WAAW,iCAAiC;IAChD,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,WAAW,CAAC;IAC9B,gBAAgB,EAAE,KAAK,CAAC;IACxB,yBAAyB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,0BAA0B,EAAE,MAAM,CAAC;IACnC,uBAAuB,EAAE,OAAO,0BAA0B,CAAC;IAC3D,MAAM,EAAE,gCAAgC,CAAC,QAAQ,CAAC,CAAC;CACpD;AAED,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,gCAAgC,GACtC,OAAO,CAAC,iCAAiC,CAAC,CAgB5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-sync-runner.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"provider-sync-runner.d.ts","sourceRoot":"","sources":["../../../src/services/provider-sync-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,EACL,0BAA0B,EAI3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAapD,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;IAC5D,0CAA0C;IAC1C,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAC3B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,IAAI,CAAC;IACd;;;OAGG;IACH,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAC1C,8DAA8D;IAC9D,yBAAyB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,+CAA+C;IAC/C,0BAA0B,EAAE,MAAM,CAAC;IACnC,8DAA8D;IAC9D,uBAAuB,EAAE,OAAO,0BAA0B,CAAC;CAC5D;AAkJD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,wBAAwB,CAAC,CAuDnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-sync-runner.js","sourceRoot":"","sources":["../../../../src/services/provider-sync-runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `runProviderSync` — Phase 2 real shell-out to\n * `wildo config sync --domain config`.\n *\n * Module-registry install/update/remove/adopt flows mutate app\n * source. When that source changes provider implementations,\n * provider companion exports, or provider scopes, the\n * provider-runtime delivery layer must regenerate its outputs\n * (KD-18). The canonical command is owned by the provider\n * workstream — module-registry MUST delegate, not fork.\n *\n * Phase 0.5 / 1 shipped a no-op `runProviderMaterializationHook`\n * that recorded intent. Phase 2 replaces it with a real\n * `child_process.spawn`-based runner that:\n * - resolves the `wildo` CLI binary from the saas root's\n * `node_modules/.bin/wildo` (the workspace's own version);\n * - shells `wildo config sync --domain config` in the saas root;\n * - times out at the operator-configurable budget;\n * - classifies stderr-tail patterns into the\n * `RegistryProviderSyncFailedError.failureKind` discriminator\n * (`companion-discovery` / `runtime-import-reachability` /\n * `invalid-scope` / `unknown`) so callers report repairable\n * failures with first-class UX rather than generic install\n * noise (`module-registry-analysis.md` / Provider Migration\n * WIP Seams §1).\n *\n * Hard contract (KD-18): the runner NEVER writes provider runtime\n * artifacts itself. It only invokes the provider workstream's\n * canonical command. Tests assert no provider artifact is touched\n * by this code path.\n */\n\nimport { spawn } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport {\n PROVIDER_LOCK_SECTION_PATH,\n PROVIDER_RUNTIME_ARTIFACT_RELATIVE_PATHS,\n PROVIDER_RUNTIME_GENERATED_MODULE_RELATIVE_PATH,\n RegistryProviderSyncFailedError,\n} from '@wildo-ai/platform-config-lib';\nimport type { RegistryClientLogger } from './types';\n\n/**\n * How long the post-mutation `wildo config sync` may run before it is treated as wedged and killed.\n *\n * Five minutes, not two: the budget exists to stop a WEDGED sync, and a wall clock cannot tell wedged\n * from slow. Measured 2026-09-27 on a scaffolded application (#1765): the same sync took 14.6 s on a\n * quiet machine, 91 s while the framework's watchers were recompiling, and exceeded the old 120 s during\n * an install under that load — so a healthy sync was killed part-way and the install reported a provider\n * sync failure it did not have. The kill stays: a genuinely stuck sync still ends, five minutes on.\n */\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ProviderSyncRunnerInput {\n /** Absolute path to the SaaS application root. */\n saasRoot: string;\n /** Reason for the call — drives diagnostic copy. */\n reason: 'install' | 'update' | 'remove' | 'adopt' | 'smoke';\n /** Optional logger. Defaults to no-op. */\n log?: RegistryClientLogger;\n /**\n * Override the wildo CLI binary path. Defaults to\n * `<saasRoot>/node_modules/.bin/wildo`. Phase 2 tests override\n * this to point at a stub script.\n */\n wildoBinPath?: string;\n /**\n * Maximum wall-time before SIGTERM. Default {@link DEFAULT_TIMEOUT_MS} (five minutes): it only ever\n * elapses on a wedged sync, and a healthy one under load has been measured past two minutes.\n */\n timeoutMs?: number;\n /**\n * If true, do NOT actually shell out — log the intent and\n * resolve as `mode: 'dry-run'`. Used by the Phase 0.5 smoke\n * command which intentionally cannot rely on a working\n * `wildo` binary in the smoke sandbox.\n */\n dryRun?: boolean;\n}\n\nexport interface ProviderSyncRunnerResult {\n invoked: true;\n /**\n * `'shell-out'` when the runner spawned `wildo config sync`.\n * `'dry-run'` when `dryRun: true` was passed (smoke flow).\n */\n mode: 'shell-out' | 'dry-run';\n /** Exit code reported by the wildo binary (0 on success). */\n exitCode: number | null;\n /** Wall-clock duration (ms). */\n durationMs: number;\n /** Reason that was passed in. */\n reason: ProviderSyncRunnerInput['reason'];\n /** Provider-output paths the canonical sync would refresh. */\n providerJsonRelativePaths: readonly string[];\n /** Source module the Node-runtime consumes. */\n providerSourceRelativePath: string;\n /** Provider lock section the materializer owns end-to-end. */\n providerLockSectionPath: typeof PROVIDER_LOCK_SECTION_PATH;\n}\n\n/**\n * Provider artifact paths sourced from the canonical\n * `PROVIDER_RUNTIME_ARTIFACT_RELATIVE_PATHS` constant in\n * `platform-config-lib`. Refactored on 2026-05-06 to import the\n * single source of truth instead of duplicating the literal paths\n * here — the artifacts moved from `.wildo-saas/providers/` to\n * `.wildo-saas/generated/providers/` and any duplication would\n * silently drift.\n */\nconst PROVIDER_JSON_RELATIVE_PATHS = Object.values(\n PROVIDER_RUNTIME_ARTIFACT_RELATIVE_PATHS,\n) as readonly string[];\n\nconst PROVIDER_SOURCE_RELATIVE_PATH = PROVIDER_RUNTIME_GENERATED_MODULE_RELATIVE_PATH;\n\n/**\n * Classify a `wildo config sync` failure based on its stderr tail.\n * The matchers mirror the failure modes the provider workstream\n * surfaces today; new modes get a new branch + a new\n * discriminator value (out of `RegistryProviderSyncFailedError`).\n */\nfunction classifyStderr(\n stderr: string,\n): 'companion-discovery' | 'runtime-import-reachability' | 'invalid-scope' | 'unknown' {\n const tail = stderr.slice(-2000);\n // Companion-export discovery failure — the provider sync walks\n // each owner package's `./companion` export to discover provider\n // contributions. A package whose export contract is broken\n // surfaces a \"companion export\" / \"DiscoveredProviderCompanionContribution\"\n // error.\n if (\n /companion[- ]export|DiscoveredProviderCompanionContribution|companion-discovery/i.test(tail)\n ) {\n return 'companion-discovery';\n }\n // Runtime-import reachability — the materializer can't resolve a\n // contributed `runtimeImport` against the owning runtime package\n // graph. Typical messages mention `runtimeImport`, `Cannot find\n // module`, or `MODULE_NOT_FOUND`.\n if (\n /runtimeImport|MODULE_NOT_FOUND|Cannot find module|cannot resolve/i.test(tail)\n ) {\n return 'runtime-import-reachability';\n }\n // Scope validation — `defineSaaSProviders({ scopes })` rejects\n // malformed scope inputs ahead of materialization.\n if (\n /defineSaaSProviders|invalid[- ]scope|providers\\.scopes/i.test(tail)\n ) {\n return 'invalid-scope';\n }\n return 'unknown';\n}\n\nasync function resolveWildoBin(input: ProviderSyncRunnerInput): Promise<string> {\n if (input.wildoBinPath) return input.wildoBinPath;\n const candidate = path.join(input.saasRoot, 'node_modules', '.bin', 'wildo');\n try {\n await fs.access(candidate);\n return candidate;\n } catch {\n // Fall back to PATH-resolved `wildo`. spawn will raise ENOENT\n // if it's not on PATH either, surfaced as\n // `RegistryProviderSyncFailedError(failureKind: 'unknown')`.\n return 'wildo';\n }\n}\n\n/**\n * Grace window between SIGTERM and SIGKILL. A well-behaved\n * `wildo config sync` should react to SIGTERM in well under a\n * second — the grace exists for tools that need to flush a buffer\n * or release a file lock. After the window we escalate to SIGKILL\n * so a hung child cannot pin the parent forever.\n */\nconst SIGKILL_GRACE_MS = 5_000;\n\nfunction runWildoConfigSync(\n binPath: string,\n cwd: string,\n timeoutMs: number,\n): Promise<{ exitCode: number | null; stderr: string; durationMs: number; signaled: boolean }> {\n return new Promise((resolve) => {\n const startedAt = Date.now();\n const child = spawn(binPath, ['config', 'sync', '--domain', 'config'], {\n cwd,\n // stdout is IGNORED, not piped: nothing here reads it, and an unread pipe fills at the OS buffer\n // (~64 KB) and blocks the child mid-write — a finished sync then looked like a wedged one and\n // was killed at the timeout. stderr stays piped because the diagnostic reads it (bounded below).\n stdio: ['ignore', 'ignore', 'pipe'],\n });\n let stderr = '';\n let signaled = false;\n let killTimer: NodeJS.Timeout | undefined;\n child.stderr?.on('data', (b: Buffer) => {\n // Cap captured stderr so a runaway sync can't OOM the parent.\n stderr += b.toString();\n if (stderr.length > 16_384) stderr = stderr.slice(-16_384);\n });\n const termTimer = setTimeout(() => {\n // Soft-kill first; record so the caller can synthesize a\n // diagnostic message that distinguishes a TERM-induced exit\n // from a normal one.\n signaled = true;\n stderr += `\\n[provider-sync] timeout ${timeoutMs}ms exceeded — sent SIGTERM.`;\n child.kill('SIGTERM');\n // Escalate to SIGKILL if the child doesn't react within the\n // grace window. Without this a child stuck in a syscall (or\n // deliberately ignoring SIGTERM) would leave the parent\n // blocked on the spawn promise forever.\n killTimer = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) {\n stderr += `\\n[provider-sync] SIGTERM grace ${SIGKILL_GRACE_MS}ms exceeded — escalating to SIGKILL.`;\n try {\n child.kill('SIGKILL');\n } catch {\n /* swallow — best-effort escalation */\n }\n }\n }, SIGKILL_GRACE_MS);\n }, timeoutMs);\n child.on('exit', (code) => {\n clearTimeout(termTimer);\n if (killTimer) clearTimeout(killTimer);\n resolve({\n exitCode: code,\n stderr,\n durationMs: Date.now() - startedAt,\n signaled,\n });\n });\n child.on('error', (err) => {\n clearTimeout(termTimer);\n if (killTimer) clearTimeout(killTimer);\n resolve({\n exitCode: null,\n stderr: stderr + `\\n[spawn error] ${err.message}`,\n durationMs: Date.now() - startedAt,\n signaled,\n });\n });\n });\n}\n\n/**\n * Run the canonical provider-sync command. Throws\n * `RegistryProviderSyncFailedError` (with classified `failureKind`)\n * when the spawned process exits non-zero or fails to start.\n */\nexport async function runProviderSync(\n input: ProviderSyncRunnerInput,\n): Promise<ProviderSyncRunnerResult> {\n const log = input.log;\n const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const baseResult = {\n invoked: true as const,\n reason: input.reason,\n providerJsonRelativePaths: PROVIDER_JSON_RELATIVE_PATHS,\n providerSourceRelativePath: PROVIDER_SOURCE_RELATIVE_PATH,\n providerLockSectionPath: PROVIDER_LOCK_SECTION_PATH,\n };\n\n if (input.dryRun) {\n log?.info?.(\n `[registry] post-${input.reason} provider sync (dry-run): would shell ` +\n `\\`wildo config sync --domain config\\` in ${input.saasRoot}.`,\n );\n return { ...baseResult, mode: 'dry-run', exitCode: 0, durationMs: 0 };\n }\n\n const binPath = await resolveWildoBin(input);\n log?.info?.(\n `[registry] post-${input.reason} provider sync: spawning ` +\n `${binPath} config sync --domain config (cwd=${input.saasRoot}, timeout=${timeoutMs}ms)`,\n );\n const { exitCode, stderr, durationMs, signaled } = await runWildoConfigSync(\n binPath,\n input.saasRoot,\n timeoutMs,\n );\n\n if (exitCode === 0) {\n log?.success?.(`[registry] provider sync succeeded in ${durationMs}ms.`);\n return { ...baseResult, mode: 'shell-out', exitCode, durationMs };\n }\n\n // H5: distinguish a timeout-signaled exit from a generic non-zero\n // exit. `classifyStderr` runs regex against the appended\n // `[provider-sync] timeout ... SIGTERM/SIGKILL` lines but those\n // tails match no failure-mode regex — so prior to this branch\n // operators saw `failureKind: 'unknown'` for a hard timeout. The\n // typed error now carries the discriminator + a hint to either\n // raise the timeout or investigate the wedge.\n const failureKind = signaled ? ('timeout' as const) : classifyStderr(stderr);\n log?.error?.(\n `[registry] provider sync failed (${failureKind}, exit=${exitCode}, ${durationMs}ms).`,\n );\n const messageSuffix = failureKind === 'timeout'\n ? `Wall-clock exceeded ${timeoutMs}ms; child was sent SIGTERM (then SIGKILL after grace). ` +\n 'Either raise `timeoutMs` for legitimately heavy syncs or investigate why the sync wedged.'\n : 'Run `wildo config sync --domain config` manually to inspect.';\n throw new RegistryProviderSyncFailedError(\n `Post-${input.reason} provider sync failed (${failureKind}). ${messageSuffix}`,\n failureKind,\n stderr.slice(-1024),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provider-sync-runner.js","sourceRoot":"","sources":["../../../src/services/provider-sync-runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `runProviderSync` — Phase 2 real shell-out to\n * `wildo config sync --domain config`.\n *\n * Module-registry install/update/remove/adopt flows mutate app\n * source. When that source changes provider implementations,\n * provider companion exports, or provider scopes, the\n * provider-runtime delivery layer must regenerate its outputs\n * (KD-18). The canonical command is owned by the provider\n * workstream — module-registry MUST delegate, not fork.\n *\n * Phase 0.5 / 1 shipped a no-op `runProviderMaterializationHook`\n * that recorded intent. Phase 2 replaces it with a real\n * `child_process.spawn`-based runner that:\n * - resolves the `wildo` CLI binary from the saas root's\n * `node_modules/.bin/wildo` (the workspace's own version);\n * - shells `wildo config sync --domain config` in the saas root;\n * - times out at the operator-configurable budget;\n * - classifies stderr-tail patterns into the\n * `RegistryProviderSyncFailedError.failureKind` discriminator\n * (`companion-discovery` / `runtime-import-reachability` /\n * `invalid-scope` / `unknown`) so callers report repairable\n * failures with first-class UX rather than generic install\n * noise (`module-registry-analysis.md` / Provider Migration\n * WIP Seams §1).\n *\n * Hard contract (KD-18): the runner NEVER writes provider runtime\n * artifacts itself. It only invokes the provider workstream's\n * canonical command. Tests assert no provider artifact is touched\n * by this code path.\n */\n\nimport { spawn } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport {\n PROVIDER_LOCK_SECTION_PATH,\n PROVIDER_RUNTIME_ARTIFACT_RELATIVE_PATHS,\n PROVIDER_RUNTIME_GENERATED_MODULE_RELATIVE_PATH,\n RegistryProviderSyncFailedError,\n} from '@wildo-ai/platform-config-lib';\nimport type { RegistryClientLogger } from './types';\n\n/**\n * How long the post-mutation `wildo config sync` may run before it is treated as wedged and killed.\n *\n * Five minutes, not two: the budget exists to stop a WEDGED sync, and a wall clock cannot tell wedged\n * from slow. Measured 2026-09-27 on a scaffolded application (#1765): the same sync took 14.6 s on a\n * quiet machine, 91 s while the framework's watchers were recompiling, and exceeded the old 120 s during\n * an install under that load — so a healthy sync was killed part-way and the install reported a provider\n * sync failure it did not have. The kill stays: a genuinely stuck sync still ends, five minutes on.\n */\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ProviderSyncRunnerInput {\n /** Absolute path to the SaaS application root. */\n saasRoot: string;\n /** Reason for the call — drives diagnostic copy. */\n reason: 'install' | 'update' | 'remove' | 'adopt' | 'smoke';\n /** Optional logger. Defaults to no-op. */\n log?: RegistryClientLogger;\n /**\n * Override the wildo CLI binary path. Defaults to\n * `<saasRoot>/node_modules/.bin/wildo`. Phase 2 tests override\n * this to point at a stub script.\n */\n wildoBinPath?: string;\n /**\n * Maximum wall-time before SIGTERM. Default {@link DEFAULT_TIMEOUT_MS} (five minutes): it only ever\n * elapses on a wedged sync, and a healthy one under load has been measured past two minutes.\n */\n timeoutMs?: number;\n /**\n * If true, do NOT actually shell out — log the intent and\n * resolve as `mode: 'dry-run'`. Used by the Phase 0.5 smoke\n * command which intentionally cannot rely on a working\n * `wildo` binary in the smoke sandbox.\n */\n dryRun?: boolean;\n}\n\nexport interface ProviderSyncRunnerResult {\n invoked: true;\n /**\n * `'shell-out'` when the runner spawned `wildo config sync`.\n * `'dry-run'` when `dryRun: true` was passed (smoke flow).\n */\n mode: 'shell-out' | 'dry-run';\n /** Exit code reported by the wildo binary (0 on success). */\n exitCode: number | null;\n /** Wall-clock duration (ms). */\n durationMs: number;\n /** Reason that was passed in. */\n reason: ProviderSyncRunnerInput['reason'];\n /** Provider-output paths the canonical sync would refresh. */\n providerJsonRelativePaths: readonly string[];\n /** Source module the Node-runtime consumes. */\n providerSourceRelativePath: string;\n /** Provider lock section the materializer owns end-to-end. */\n providerLockSectionPath: typeof PROVIDER_LOCK_SECTION_PATH;\n}\n\n/**\n * Provider artifact paths sourced from the canonical\n * `PROVIDER_RUNTIME_ARTIFACT_RELATIVE_PATHS` constant in\n * `platform-config-lib`. Refactored on 2026-05-06 to import the\n * single source of truth instead of duplicating the literal paths\n * here — the artifacts moved from `.wildo-saas/providers/` to\n * `.wildo-saas/generated/providers/` and any duplication would\n * silently drift.\n */\nconst PROVIDER_JSON_RELATIVE_PATHS = Object.values(\n PROVIDER_RUNTIME_ARTIFACT_RELATIVE_PATHS,\n) as readonly string[];\n\nconst PROVIDER_SOURCE_RELATIVE_PATH = PROVIDER_RUNTIME_GENERATED_MODULE_RELATIVE_PATH;\n\n/**\n * Classify a `wildo config sync` failure based on its stderr tail.\n * The matchers mirror the failure modes the provider workstream\n * surfaces today; new modes get a new branch + a new\n * discriminator value (out of `RegistryProviderSyncFailedError`).\n */\nfunction classifyStderr(\n stderr: string,\n): 'companion-discovery' | 'runtime-import-reachability' | 'invalid-scope' | 'unknown' {\n const tail = stderr.slice(-2000);\n // Companion-export discovery failure — the provider sync walks\n // each owner package's `./companion` export to discover provider\n // contributions. A package whose export contract is broken\n // surfaces a \"companion export\" / \"DiscoveredProviderCompanionContribution\"\n // error.\n if (\n /companion[- ]export|DiscoveredProviderCompanionContribution|companion-discovery/i.test(tail)\n ) {\n return 'companion-discovery';\n }\n // Runtime-import reachability — the materializer can't resolve a\n // contributed `runtimeImport` against the owning runtime package\n // graph. Typical messages mention `runtimeImport`, `Cannot find\n // module`, or `MODULE_NOT_FOUND`.\n if (\n /runtimeImport|MODULE_NOT_FOUND|Cannot find module|cannot resolve/i.test(tail)\n ) {\n return 'runtime-import-reachability';\n }\n // Scope validation — `defineSaaSProviders({ scopes })` rejects\n // malformed scope inputs ahead of materialization.\n if (\n /defineSaaSProviders|invalid[- ]scope|providers\\.scopes/i.test(tail)\n ) {\n return 'invalid-scope';\n }\n return 'unknown';\n}\n\nasync function resolveWildoBin(input: ProviderSyncRunnerInput): Promise<string> {\n if (input.wildoBinPath) return input.wildoBinPath;\n const candidate = path.join(input.saasRoot, 'node_modules', '.bin', 'wildo');\n try {\n await fs.access(candidate);\n return candidate;\n } catch {\n // Fall back to PATH-resolved `wildo`. spawn will raise ENOENT\n // if it's not on PATH either, surfaced as\n // `RegistryProviderSyncFailedError(failureKind: 'unknown')`.\n return 'wildo';\n }\n}\n\n/**\n * Grace window between SIGTERM and SIGKILL. A well-behaved\n * `wildo config sync` should react to SIGTERM in well under a\n * second — the grace exists for tools that need to flush a buffer\n * or release a file lock. After the window we escalate to SIGKILL\n * so a hung child cannot pin the parent forever.\n */\nconst SIGKILL_GRACE_MS = 5_000;\n\nfunction runWildoConfigSync(\n binPath: string,\n cwd: string,\n timeoutMs: number,\n): Promise<{ exitCode: number | null; stderr: string; durationMs: number; signaled: boolean }> {\n return new Promise((resolve) => {\n const startedAt = Date.now();\n const child = spawn(binPath, ['config', 'sync', '--domain', 'config'], {\n cwd,\n // stdout is IGNORED, not piped: nothing here reads it, and an unread pipe fills at the OS buffer\n // (~64 KB) and blocks the child mid-write — a finished sync then looked like a wedged one and\n // was killed at the timeout. stderr stays piped because the diagnostic reads it (bounded below).\n stdio: ['ignore', 'ignore', 'pipe'],\n });\n let stderr = '';\n let signaled = false;\n let killTimer: NodeJS.Timeout | undefined;\n child.stderr?.on('data', (b: Buffer) => {\n // Cap captured stderr so a runaway sync can't OOM the parent.\n stderr += b.toString();\n if (stderr.length > 16_384) stderr = stderr.slice(-16_384);\n });\n const termTimer = setTimeout(() => {\n // Soft-kill first; record so the caller can synthesize a\n // diagnostic message that distinguishes a TERM-induced exit\n // from a normal one.\n signaled = true;\n stderr += `\\n[provider-sync] timeout ${timeoutMs}ms exceeded — sent SIGTERM.`;\n child.kill('SIGTERM');\n // Escalate to SIGKILL if the child doesn't react within the\n // grace window. Without this a child stuck in a syscall (or\n // deliberately ignoring SIGTERM) would leave the parent\n // blocked on the spawn promise forever.\n killTimer = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) {\n stderr += `\\n[provider-sync] SIGTERM grace ${SIGKILL_GRACE_MS}ms exceeded — escalating to SIGKILL.`;\n try {\n child.kill('SIGKILL');\n } catch {\n /* swallow — best-effort escalation */\n }\n }\n }, SIGKILL_GRACE_MS);\n }, timeoutMs);\n child.on('exit', (code) => {\n clearTimeout(termTimer);\n if (killTimer) clearTimeout(killTimer);\n resolve({\n exitCode: code,\n stderr,\n durationMs: Date.now() - startedAt,\n signaled,\n });\n });\n child.on('error', (err) => {\n clearTimeout(termTimer);\n if (killTimer) clearTimeout(killTimer);\n resolve({\n exitCode: null,\n stderr: stderr + `\\n[spawn error] ${err.message}`,\n durationMs: Date.now() - startedAt,\n signaled,\n });\n });\n });\n}\n\n/**\n * Run the canonical provider-sync command. Throws\n * `RegistryProviderSyncFailedError` (with classified `failureKind`)\n * when the spawned process exits non-zero or fails to start.\n */\nexport async function runProviderSync(\n input: ProviderSyncRunnerInput,\n): Promise<ProviderSyncRunnerResult> {\n const log = input.log;\n const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const baseResult = {\n invoked: true as const,\n reason: input.reason,\n providerJsonRelativePaths: PROVIDER_JSON_RELATIVE_PATHS,\n providerSourceRelativePath: PROVIDER_SOURCE_RELATIVE_PATH,\n providerLockSectionPath: PROVIDER_LOCK_SECTION_PATH,\n };\n\n if (input.dryRun) {\n log?.info?.(\n `[registry] post-${input.reason} provider sync (dry-run): would shell ` +\n `\\`wildo config sync --domain config\\` in ${input.saasRoot}.`,\n );\n return { ...baseResult, mode: 'dry-run', exitCode: 0, durationMs: 0 };\n }\n\n const binPath = await resolveWildoBin(input);\n log?.info?.(\n `[registry] post-${input.reason} provider sync: spawning ` +\n `${binPath} config sync --domain config (cwd=${input.saasRoot}, timeout=${timeoutMs}ms)`,\n );\n const { exitCode, stderr, durationMs, signaled } = await runWildoConfigSync(\n binPath,\n input.saasRoot,\n timeoutMs,\n );\n\n if (exitCode === 0) {\n log?.success?.(`[registry] provider sync succeeded in ${durationMs}ms.`);\n return { ...baseResult, mode: 'shell-out', exitCode, durationMs };\n }\n\n // H5: distinguish a timeout-signaled exit from a generic non-zero\n // exit. `classifyStderr` runs regex against the appended\n // `[provider-sync] timeout ... SIGTERM/SIGKILL` lines but those\n // tails match no failure-mode regex — so prior to this branch\n // operators saw `failureKind: 'unknown'` for a hard timeout. The\n // typed error now carries the discriminator + a hint to either\n // raise the timeout or investigate the wedge.\n const failureKind = signaled ? ('timeout' as const) : classifyStderr(stderr);\n log?.error?.(\n `[registry] provider sync failed (${failureKind}, exit=${exitCode}, ${durationMs}ms).`,\n );\n const messageSuffix = failureKind === 'timeout'\n ? `Wall-clock exceeded ${timeoutMs}ms; child was sent SIGTERM (then SIGKILL after grace). ` +\n 'Either raise `timeoutMs` for legitimately heavy syncs or investigate why the sync wedged.'\n : 'Run `wildo config sync --domain config` manually to inspect.';\n throw new RegistryProviderSyncFailedError(\n `Post-${input.reason} provider sync failed (${failureKind}). ${messageSuffix}`,\n failureKind,\n stderr.slice(-1024),\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-companion-client.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"registry-companion-client.d.ts","sourceRoot":"","sources":["../../../src/services/registry-companion-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,uBAAuB;IAClC;;;OAGG;kBACiB,8BAA8B,GAAG,OAAO,CAAC,OAAO,CAAC;CAatE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-companion-client.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"registry-companion-client.js","sourceRoot":"","sources":["../../../src/services/registry-companion-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE3D,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAO9C,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,OAAuC;QAChD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE;gBACtC,MAAM,EAAE,KAAK;gBACb,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,eAAe,EAAE,gBAAgB;aAClC,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF,CAAC","sourcesContent":["/**\n * `RegistryCompanionClient` — liveness probe for the local dev companion, used by\n * `wildo registry ping` beside the registry-server probe.\n *\n * That is all it is. It used to carry four mutation methods (install / update / remove / publish)\n * against `/api/companion/registry/*` routes that only ever answered a \"Phase 5/6 deliverable\"\n * not-implemented envelope and had no caller. Installation shipped CLI-direct instead\n * (`wildo registry add` / `update` / `remove` / `publish` do the work themselves), so the routes,\n * these methods and their wire schemas were deleted on 2026-09-25 rather than left describing a\n * design that was never built. A future companion-owned mutation lane starts from the CLI commands,\n * not from this file.\n */\n\nimport { fetchWithTimeout, joinUrl } from './_http-client';\n\nconst DIAGNOSTIC_LABEL = 'Companion registry';\n\nexport interface RegistryCompanionClientOptions {\n baseUrl: string;\n timeoutMs?: number;\n}\n\nexport const RegistryCompanionClient = {\n /**\n * Liveness probe against `/health` (the same endpoint the\n * dev-supervisor monitors). Used by `wildo registry ping`.\n */\n async ping(options: RegistryCompanionClientOptions): Promise<boolean> {\n const url = joinUrl(options.baseUrl, '/health');\n try {\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n return res.ok;\n } catch {\n return false;\n }\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-lockfile.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"registry-lockfile.service.d.ts","sourceRoot":"","sources":["../../../src/services/registry-lockfile.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAIL,KAAK,0BAA0B,EAE/B,KAAK,6BAA6B,EACnC,MAAM,+BAA+B,CAAC;AAevC,eAAO,MAAM,uBAAuB;IAClC;;;;OAIG;8BACkB,MAAM,KAAG,OAAO,CAAC,0BAA0B,CAAC;IAOjE;;;;;;OAMG;gCAES,MAAM,WACP,CACP,OAAO,EAAE,0BAA0B,KAEjC,0BAA0B,GAC1B,IAAI,GACJ,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,KAC7C,OAAO,CAAC,0BAA0B,CAAC;IAYtC;;;;OAIG;qCACyB,MAAM,SAAS,6BAA6B,KAAG,OAAO,CAAC,IAAI,CAAC;IAQxF;;;;;;;;;OASG;oCACwB;QACzB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;KACzB,KAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAgB1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-lockfile.service.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"registry-lockfile.service.js","sourceRoot":"","sources":["../../../src/services/registry-lockfile.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,iBAAiB,EAEjB,8BAA8B,GAE/B,MAAM,+BAA+B,CAAC;AACvC,oEAAoE;AACpE,qEAAqE;AACrE,sEAAsE;AACtE,8DAA8D;AAC9D,kEAAkE;AAClE,qEAAqE;AACrE,mCAAmC;AAEnC,MAAM,WAAW,GAAG,SAAkB,CAAC;AAEvC,SAAS,YAAY;IACnB,OAAO,gCAAgC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC;;;;OAIG;IACH,KAAK,CAAC,IAAI,CAAC,QAAgB;QACzB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QACtC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,YAAY,EAAE,CAAC;QAC7C,OAAO,gCAAgC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CACV,QAAgB,EAChB,OAK8C;QAE9C,OAAO,yBAAyB,CAC9B;YACE,QAAQ;YACR,UAAU,EAAE,WAAW;YACvB,aAAa,EAAE,gCAAgC;YAC/C,cAAc,EAAE,YAAY;SAC7B,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,KAAoC;QACtE,MAAM,KAAK,GAAG,8BAA8B,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACxC,GAAG,OAAO;YACV,SAAS,EAAE,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE;SAC7D,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,cAAc,CAAC,IAIpB;QACC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC9C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK;YAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjD,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3D,IAAI,aAAa,KAAK,IAAI,CAAC,eAAe;gBAAE,SAAS;YACrD,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACpD,IAAI,CAAC,UAAU;gBAAE,SAAS;YAC1B,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;gBACzC,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC7B,SAAS,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACO,CAAC","sourcesContent":["/**\n * `RegistryLockfileService` — section-scoped reader/writer for the\n * `sections.modules` slice of `wildo-saas.lock.json` (KD-4).\n *\n * Phase 1 graduates the locking + atomic-write primitives into\n * `@wildo-ai/platform-config-lib` (validated by the Phase 0.B\n * contention spike). This service is a thin wrapper around\n * `withLockfileSectionMutate` that pre-binds the `modules` section\n * key + schema, so module-registry callers cannot accidentally\n * touch sibling sections.\n *\n * Hard contracts (KD-4 / KD-15 / KD-18):\n * - Mutates ONLY `sections.modules`. The shared library preserves\n * `sections.providers`, `sections.i18n`, and every unknown\n * `sections.*` payload verbatim — no defensive logic needed\n * here.\n * - Never writes `.wildo-saas/generated/providers/*.runtime-providers.generated.json`\n * or `src/generated/wildo-provider-runtime.generated.ts` —\n * those are produced by the provider materialization workflow.\n * - Never mutates `sections.providers.runtimeScopes`.\n */\n\nimport {\n RegistryModulesLockSectionSchema,\n withLockfileSectionMutate,\n readWildoSaasLock,\n type RegistryModulesLockSection,\n RegistryModulesLockEntrySchema,\n type RegistryModulesLockEntryInput,\n} from '@wildo-ai/platform-config-lib';\n// L6 (third-pass review): the package's barrel-discipline rule says\n// \"Never re-export (except in the root `index.ts` of each package).\"\n// The previous `export { WILDO_SAAS_LOCK_RELATIVE_PATH }` here AND in\n// `lockfile-repair.service.ts` surfaced the symbol twice from\n// `wildo-module-client`'s root. Consumers that need it can import\n// directly from `@wildo-ai/platform-config-lib`, OR rely on the root\n// `index.ts` to re-export it once.\n\nconst SECTION_KEY = 'modules' as const;\n\nfunction emptySection(): RegistryModulesLockSection {\n return RegistryModulesLockSectionSchema.parse({});\n}\n\nexport const RegistryLockfileService = {\n /**\n * Read the current `sections.modules` payload (or an empty section\n * when missing). Unsynchronized — callers needing read-after-write\n * coherence should read INSIDE `mutate`.\n */\n async read(saasRoot: string): Promise<RegistryModulesLockSection> {\n const envelope = await readWildoSaasLock({ saasRoot });\n const raw = envelope.sections.modules;\n if (raw === undefined) return emptySection();\n return RegistryModulesLockSectionSchema.parse(raw);\n },\n\n /**\n * Run `mutator` against the current `sections.modules` payload\n * under an OS-level lock + atomic-write commit. The mutator can\n * either mutate-in-place or return a new value; either way the\n * result is re-validated against `RegistryModulesLockSectionSchema`\n * before commit.\n */\n async mutate(\n saasRoot: string,\n mutator: (\n current: RegistryModulesLockSection,\n ) =>\n | RegistryModulesLockSection\n | void\n | Promise<RegistryModulesLockSection | void>,\n ): Promise<RegistryModulesLockSection> {\n return withLockfileSectionMutate(\n {\n saasRoot,\n sectionKey: SECTION_KEY,\n sectionSchema: RegistryModulesLockSectionSchema,\n initialSection: emptySection,\n },\n mutator,\n );\n },\n\n /**\n * Insert or replace one module's entry. The entry is parsed here, so its defaults (`distribution`,\n * `files`) apply in one place and a malformed entry is refused naming the module, before the lockfile\n * is touched (`mutate` then re-validates the whole section).\n */\n async upsertEntry(saasRoot: string, input: RegistryModulesLockEntryInput): Promise<void> {\n const entry = RegistryModulesLockEntrySchema.parse(input);\n await this.mutate(saasRoot, (current) => ({\n ...current,\n installed: { ...current.installed, [entry.moduleId]: entry },\n }));\n },\n\n /**\n * Find every other lockfile entry whose `files[]` claims any of the\n * given paths. Used by `update`/`remove` to skip deletes that would\n * silently pull files out from under modules that own them too\n * (cross-module file overlap).\n *\n * Returns a `Map<relPath, owners[]>` where `owners` excludes\n * `excludeModuleId`. Empty array → uniquely owned by the excluded\n * module, safe to delete.\n */\n async findFileOwners(args: {\n saasRoot: string;\n paths: readonly string[];\n excludeModuleId: string;\n }): Promise<Map<string, string[]>> {\n const section = await this.read(args.saasRoot);\n const claimedBy = new Map<string, string[]>();\n for (const p of args.paths) claimedBy.set(p, []);\n for (const otherModuleId of Object.keys(section.installed)) {\n if (otherModuleId === args.excludeModuleId) continue;\n const otherEntry = section.installed[otherModuleId];\n if (!otherEntry) continue;\n for (const otherFile of otherEntry.files) {\n if (claimedBy.has(otherFile)) {\n claimedBy.get(otherFile)!.push(otherModuleId);\n }\n }\n }\n return claimedBy;\n },\n} as const;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-server-client.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"registry-server-client.d.ts","sourceRoot":"","sources":["../../../src/services/registry-server-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAwBL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,+BAA+B,CAAC;AAsBvC,MAAM,WAAW,2BAA2B;IAC1C,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6DD,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,sDAAsD;IACtD,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACxC;AAED,+FAA+F;AAC/F,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD,eAAO,MAAM,oBAAoB;IAC/B;;;;;;OAMG;6BACiB,2BAA2B,KAAG,OAAO,CAAC,OAAO,CAAC;IAalE;;;;OAIG;gCAEQ,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KACxD,OAAO,CAAC,qBAAqB,CAAC;IAkDjC;;;OAGG;6BAEQ,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KACzC,OAAO,CAAC,kBAAkB,CAAC;IAyB9B;;;OAGG;+BAEQ,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,kBAAkB,CAAA;KAAE,KACnE,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC;IA2BxC;;;;;OAKG;iCAEQ,2BAA2B,QAC9B;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;KACxB,KACA,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,kBAAkB,CAAA;KAAE,CAAC;IAiDjF;;;;OAIG;6BAEQ,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAC3E,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAIrC,oGAAoG;+BAEzF,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAC1D,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAG7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-server-client.js","sourceRoot":"","sources":["../../../../src/services/registry-server-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `RegistryServerClient` — HTTP client for the central registry\n * server (`platform-module-registry`, KD-7).\n *\n * Phase 2 fills out the read + download surface (`resolve`,\n * `info`, `search`, `download`). The wire shapes mirror the\n * gateway endpoints documented in the analysis plan's \"Registry\n * HTTP API\" section. The actual server (Phase 3) ships these\n * routes; until it does, the client throws typed errors when it\n * can't reach the server.\n *\n * Auth (KD-11): if `authToken` is supplied, every request adds\n * `Authorization: Bearer <token>`. Public read paths work without\n * a token; restricted paths return 401/403, surfaced as\n * `RegistryAuthRequiredError` (no key sent), `RegistryCredentialRejectedError` (a key sent and refused)\n * or `RegistryAuthForbiddenError`; a 429 is `RegistryRateLimitedError`.\n */\n\nimport { z } from 'zod';\nimport { formatZodIssuesAsSingleLine } from './_zod-issue-formatting';\nimport {\n ModuleManifestSchema,\n ModuleVersionRecordSchema,\n RegistryArtifactIntegrityMismatchError,\n RegistryAuthForbiddenError,\n RegistryAuthRequiredError,\n RegistryCredentialRejectedError,\n RegistryError,\n RegistryRateLimitedError,\n isRegistryError,\n isRegistryReleaseStateConflictBody,\n RegistryMalformedPayloadError,\n RegistryModuleNotFoundError,\n RegistryUnexpectedStatusError,\n RegistryVersionNotFoundError,\n RegistryYankNoticeSchema,\n RegistryYankStateConflictError,\n RegistryYankVerb,\n REGISTRY_YANK_REASON_HEADER,\n REGISTRY_YANKED_AT_HEADER,\n Sha256DigestSchema,\n ModuleSearchHitSchema,\n moduleSearchFilterQueryPairs,\n moduleSearchHitMatchesFilter,\n type ModuleManifest,\n type ModuleSearchFilter,\n type ModuleSearchHit,\n type RegistryYankNotice,\n type ModuleVersionRecord,\n} from '@wildo-ai/platform-config-lib';\nimport { fetchJsonOk, fetchTransfer, fetchWithTimeout, joinUrl, readJsonBody } from './_http-client';\n\n/**\n * Zod schema for the `info()` response payload — mirrors\n * `RegistryInfoResult` and is enforced at the client boundary so a\n * server schema drift fails fast instead of returning malformed data\n * to downstream consumers.\n */\nconst RegistryInfoResponseSchema = z.object({\n moduleId: z.string().min(1),\n manifest: ModuleManifestSchema,\n versions: z.array(ModuleVersionRecordSchema),\n tags: z.record(z.string(), z.string()),\n});\n\nconst RegistrySearchResponseSchema = z.object({\n hits: z.array(ModuleSearchHitSchema),\n});\n\nconst DIAGNOSTIC_LABEL = 'Registry';\n\nexport interface RegistryServerClientOptions {\n /** Registry origin (e.g. `https://registry.wildo.ai`). */\n baseUrl: string;\n /** Optional bearer / API-key. CLI credentials are per-machine (KD-11). */\n authToken?: string;\n /** Request timeout in ms. */\n timeoutMs?: number;\n}\n\nfunction authHeaders(options: RegistryServerClientOptions): Record<string, string> {\n return options.authToken ? { Authorization: `Bearer ${options.authToken}` } : {};\n}\n\n/**\n * Throw the typed error for a non-2xx response, after releasing its body (#1763 review: an unread body\n * holds the connection until garbage collection). A 401 is told apart by whether a key was SENT — \"log\n * in\" and \"your key no longer works\" are different remedies (#1759 review).\n */\nasync function refuseUnlessOk(\n res: Response,\n options: RegistryServerClientOptions,\n action: string,\n notFound?: () => RegistryError,\n): Promise<void> {\n if (res.ok) return;\n let error: RegistryError;\n if (res.status === 404 && notFound) error = notFound();\n else if (res.status === 401) error = options.authToken ? new RegistryCredentialRejectedError(options.baseUrl) : new RegistryAuthRequiredError(options.baseUrl);\n else if (res.status === 403) error = new RegistryAuthForbiddenError(action);\n else if (res.status === 429) error = new RegistryRateLimitedError(options.baseUrl, action, parseRetryAfterSeconds(res.headers.get('retry-after')));\n else error = new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, action);\n await res.body?.cancel().catch(() => undefined);\n throw error;\n}\n\n/** `Retry-After` in its delta-seconds form; the HTTP-date form is not produced by a Wildo backend. */\nfunction parseRetryAfterSeconds(value: string | null): number | undefined {\n if (!value || !/^\\d+$/.test(value.trim())) return undefined;\n return Number(value.trim());\n}\n\n/**\n * 6th-pass M3: typed JSON-parse helper. A misconfigured proxy that\n * returns HTML at 2xx (or a truncated stream) would otherwise throw a\n * bare `SyntaxError` from `await res.json()`, bypassing every\n * `isRegistryError(err)` handler. This helper translates the parse\n * failure into a `RegistryMalformedPayloadError` so the typed-error\n * contract is universal across the client surface.\n */\nasync function parseJsonOrThrow(\n res: Response,\n registryUrl: string,\n action: string,\n timeoutMs: number | undefined,\n): Promise<unknown> {\n try {\n return await readJsonBody(res, registryUrl, action, timeoutMs);\n } catch (err) {\n // A body cut short by the request budget is a timeout (#1763), not a malformed payload.\n if (isRegistryError(err)) throw err;\n throw new RegistryMalformedPayloadError(\n registryUrl,\n action,\n `response is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nexport interface RegistryResolveResult {\n /** Resolved exact version (matches `Sha256DigestSchema` for digest). */\n version: string;\n artifactDigest: string;\n /**\n * Present when the resolved release is yanked. Only an EXACT-version request can resolve to one\n * (#1758) — ranges and tags never do — so the caller is pinned to it and should warn, not refuse.\n */\n yanked?: RegistryYankNotice;\n}\n\nexport interface RegistryInfoResult {\n moduleId: string;\n manifest: ModuleManifest;\n versions: readonly ModuleVersionRecord[];\n /** dist-tag → version map (e.g. `latest → 1.2.3`). */\n tags: Readonly<Record<string, string>>;\n}\n\n/** One search hit: the module, its latest version, and (#2014) its kind and provider facts. */\nexport type RegistrySearchHit = ModuleSearchHit;\n\nexport const RegistryServerClient = {\n /**\n * Liveness probe against `/health`. Returns boolean — used by\n * `wildo registry ping` smoke. The registry server now relies on\n * the framework's auto-mounted `HealthController` at the engine\n * root (`GET /health` always 200; `GET /health/ready` enforces\n * dependency readiness), so the path has NO `/v1` prefix.\n */\n async ping(options: RegistryServerClientOptions): Promise<boolean> {\n try {\n await fetchJsonOk(joinUrl(options.baseUrl, '/health'), {\n method: 'GET',\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Resolve a semver range / tag against a registry domain. The\n * server returns the concrete version + artifact digest so the\n * caller can verify the download against `artifactDigest`.\n */\n async resolve(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; range: string },\n ): Promise<RegistryResolveResult> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/resolve?range=${encodeURIComponent(args.range)}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, `resolve ${args.moduleId}`, () => new RegistryVersionNotFoundError(args.moduleId, args.range));\n // 6th-pass M3: typed JSON-parse (was bare `SyntaxError` for\n // malformed proxy responses).\n const json = (await parseJsonOrThrow(res, options.baseUrl, `resolve ${args.moduleId}`, options.timeoutMs)) as {\n version?: unknown;\n artifactDigest?: unknown;\n yanked?: unknown;\n };\n const digest = String(json.artifactDigest ?? '');\n // 6th-pass M4: typed digest validation (was bare `ZodError`).\n const digestParse = Sha256DigestSchema.safeParse(digest);\n if (!digestParse.success) {\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n `resolve ${args.moduleId}`,\n `artifactDigest is not a valid sha256:<64-hex> string: ${formatZodIssuesAsSingleLine(digestParse.error)}`,\n );\n }\n if (typeof json.version !== 'string' || json.version.length === 0) {\n // 3rd-pass M6: typed `RegistryMalformedPayloadError` instead of\n // bare `Error` so callers' `isRegistryError(err)` handlers fire\n // correctly.\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n `resolve ${args.moduleId}`,\n 'response missing required `version` string',\n );\n }\n let yanked: RegistryYankNotice | undefined;\n if (json.yanked !== undefined) {\n const yankParse = RegistryYankNoticeSchema.safeParse(json.yanked);\n if (!yankParse.success) {\n throw new RegistryMalformedPayloadError(options.baseUrl, `resolve ${args.moduleId}`, `yanked: ${formatZodIssuesAsSingleLine(yankParse.error)}`);\n }\n yanked = yankParse.data;\n }\n return { version: json.version, artifactDigest: digest, ...(yanked ? { yanked } : {}) };\n },\n\n /**\n * Fetch full info for a module: manifest, every published\n * version, dist-tags. Used by `wildo registry info` (Phase 4).\n */\n async info(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string },\n ): Promise<RegistryInfoResult> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, `info ${args.moduleId}`, () => new RegistryModuleNotFoundError(args.moduleId));\n // 6th-pass M3: typed JSON-parse.\n const json = await parseJsonOrThrow(res, options.baseUrl, `info ${args.moduleId}`, options.timeoutMs);\n const parsed = RegistryInfoResponseSchema.safeParse(json);\n if (!parsed.success) {\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n `info ${args.moduleId}`,\n formatZodIssuesAsSingleLine(parsed.error),\n );\n }\n return parsed.data;\n },\n\n /**\n * Search the registry's metadata index: a module-id substring, and (#2014) the manifest filters —\n * kind, engine capability and provider maturity. The server refuses an unknown filter value.\n */\n async search(\n options: RegistryServerClientOptions,\n args: { domain: string; query: string; filter?: ModuleSearchFilter },\n ): Promise<readonly RegistrySearchHit[]> {\n const params = new URLSearchParams([['q', args.query], ...moduleSearchFilterQueryPairs(args.filter ?? {})]);\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules?${params.toString()}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, 'search');\n // 6th-pass M3: typed JSON-parse.\n const json = await parseJsonOrThrow(res, options.baseUrl, 'search', options.timeoutMs);\n const parsed = RegistrySearchResponseSchema.safeParse(json);\n if (!parsed.success) {\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n 'search',\n formatZodIssuesAsSingleLine(parsed.error),\n );\n }\n // Re-applied here: a server that predates the filters ignores them and answers every module (#2014 review F9).\n return parsed.data.hits.filter((hit) => moduleSearchHitMatchesFilter(hit, args.filter ?? {}));\n },\n\n /**\n * Stream-download a published artifact's bytes and verify the\n * sha256 integrity matches `expectedDigest`. Throws\n * `RegistryArtifactIntegrityMismatchError` on mismatch — the\n * digest check is non-negotiable per KD-9 / Security model.\n */\n async download(\n options: RegistryServerClientOptions,\n args: {\n domain: string;\n moduleId: string;\n version: string;\n expectedDigest: string;\n },\n ): Promise<{ bytes: Uint8Array; integrity: string; yanked?: RegistryYankNotice }> {\n // 7th-pass C-M1: caller-supplied digest is a developer-contract\n // violation if malformed, not a registry-runtime condition.\n // Throw `TypeError` (matching `C-L3` precedent for\n // `getModuleStagingPaths` argument-shape violations) so the\n // typed `RegistryError` vocabulary stays reserved for\n // registry-runtime errors. Prior `Sha256DigestSchema.parse(...)`\n // leaked a bare `ZodError` that bypassed\n // `isRegistryError(err)` handlers but ALSO confused\n // typed-handler maintainers about the contract.\n const digestParse = Sha256DigestSchema.safeParse(args.expectedDigest);\n if (!digestParse.success) {\n throw new TypeError(\n `download() expectedDigest must be a valid sha256:<64-hex> string (got: ${JSON.stringify(args.expectedDigest)}). ${formatZodIssuesAsSingleLine(digestParse.error)}`,\n );\n }\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/${encodeURIComponent(args.version)}/artifact`,\n );\n // A transfer, not a metadata call: the response is bounded by `timeoutMs`, the body by an IDLE budget\n // reset on every chunk, so a large artifact over a slow link installs and a stalled one fails (#1763).\n const { response: res, readAll } = await fetchTransfer(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, `download ${args.moduleId}@${args.version}`, () => new RegistryVersionNotFoundError(args.moduleId, args.version));\n const buf = await readAll();\n const { createHash } = await import('node:crypto');\n const observed = `sha256:${createHash('sha256').update(buf).digest('hex')}`;\n if (observed !== args.expectedDigest) {\n throw new RegistryArtifactIntegrityMismatchError(\n args.moduleId,\n args.version,\n args.expectedDigest,\n observed,\n );\n }\n // A yanked release is served by exact version (#1758) and says so in headers.\n const yankedAt = res.headers.get(REGISTRY_YANKED_AT_HEADER);\n const encodedReason = res.headers.get(REGISTRY_YANK_REASON_HEADER);\n let reason: string | undefined;\n if (encodedReason) {\n try { reason = decodeURIComponent(encodedReason); } catch { reason = encodedReason; }\n }\n return { bytes: buf, integrity: observed, ...(yankedAt ? { yanked: { yankedAt, ...(reason ? { reason } : {}) } } : {}) };\n },\n /**\n * Yank a release (#1758): ranges and `latest` stop selecting it, and `latest` moves to the highest\n * live release; an exact pin still installs it, with a warning. Needs a key holding the version UPDATE\n * role in the domain's owning organization. Returns where `latest` points afterwards.\n */\n async yank(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; version: string; reason?: string },\n ): Promise<{ latest: string | null }> {\n return changeYankState(options, args, RegistryYankVerb.YANK);\n },\n\n /** Restore a yanked release (#1758); `latest` returns to it when it outranks the current target. */\n async unyank(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; version: string },\n ): Promise<{ latest: string | null }> {\n return changeYankState(options, args, RegistryYankVerb.UNYANK);\n },\n} as const;\n\nconst RegistryYankResponseSchema = z.object({ ok: z.literal(true), latest: z.string().nullable().optional() });\n\nasync function changeYankState(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; version: string; reason?: string },\n verb: RegistryYankVerb,\n): Promise<{ latest: string | null }> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/${verb}`,\n );\n const action = `${verb} ${args.moduleId}@${args.version}`;\n const res = await fetchWithTimeout(url, {\n method: 'POST',\n headers: { ...authHeaders(options), 'content-type': 'application/json' },\n body: JSON.stringify({ version: args.version, ...(args.reason !== undefined ? { reason: args.reason } : {}) }),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n if (res.status === 409) {\n // Only the release-state refusal is the no-op; a 409 for anything else (the registry giving up after\n // lost optimistic checks) is a FAILED yank and must not be reported as done (#1758 re-review R3).\n const body = await res.json().catch(() => undefined);\n if (isRegistryReleaseStateConflictBody(body)) throw new RegistryYankStateConflictError(args.moduleId, args.version, verb);\n throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, action);\n }\n // A 404 names the module or the version; the sanitized envelope does not say which.\n await refuseUnlessOk(res, options, action, () => new RegistryVersionNotFoundError(args.moduleId, args.version));\n const parsed = RegistryYankResponseSchema.safeParse(await parseJsonOrThrow(res, options.baseUrl, action, options.timeoutMs));\n if (!parsed.success) {\n throw new RegistryMalformedPayloadError(options.baseUrl, action, formatZodIssuesAsSingleLine(parsed.error));\n }\n return { latest: parsed.data.latest ?? null };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"registry-server-client.js","sourceRoot":"","sources":["../../../src/services/registry-server-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `RegistryServerClient` — HTTP client for the central registry\n * server (`platform-module-registry`, KD-7).\n *\n * Phase 2 fills out the read + download surface (`resolve`,\n * `info`, `search`, `download`). The wire shapes mirror the\n * gateway endpoints documented in the analysis plan's \"Registry\n * HTTP API\" section. The actual server (Phase 3) ships these\n * routes; until it does, the client throws typed errors when it\n * can't reach the server.\n *\n * Auth (KD-11): if `authToken` is supplied, every request adds\n * `Authorization: Bearer <token>`. Public read paths work without\n * a token; restricted paths return 401/403, surfaced as\n * `RegistryAuthRequiredError` (no key sent), `RegistryCredentialRejectedError` (a key sent and refused)\n * or `RegistryAuthForbiddenError`; a 429 is `RegistryRateLimitedError`.\n */\n\nimport { z } from 'zod';\nimport { formatZodIssuesAsSingleLine } from './_zod-issue-formatting';\nimport {\n ModuleManifestSchema,\n ModuleVersionRecordSchema,\n RegistryArtifactIntegrityMismatchError,\n RegistryAuthForbiddenError,\n RegistryAuthRequiredError,\n RegistryCredentialRejectedError,\n RegistryError,\n RegistryRateLimitedError,\n isRegistryError,\n isRegistryReleaseStateConflictBody,\n RegistryMalformedPayloadError,\n RegistryModuleNotFoundError,\n RegistryUnexpectedStatusError,\n RegistryVersionNotFoundError,\n RegistryYankNoticeSchema,\n RegistryYankStateConflictError,\n RegistryYankVerb,\n REGISTRY_YANK_REASON_HEADER,\n REGISTRY_YANKED_AT_HEADER,\n Sha256DigestSchema,\n ModuleSearchHitSchema,\n moduleSearchFilterQueryPairs,\n moduleSearchHitMatchesFilter,\n type ModuleManifest,\n type ModuleSearchFilter,\n type ModuleSearchHit,\n type RegistryYankNotice,\n type ModuleVersionRecord,\n} from '@wildo-ai/platform-config-lib';\nimport { fetchJsonOk, fetchTransfer, fetchWithTimeout, joinUrl, readJsonBody } from './_http-client';\n\n/**\n * Zod schema for the `info()` response payload — mirrors\n * `RegistryInfoResult` and is enforced at the client boundary so a\n * server schema drift fails fast instead of returning malformed data\n * to downstream consumers.\n */\nconst RegistryInfoResponseSchema = z.object({\n moduleId: z.string().min(1),\n manifest: ModuleManifestSchema,\n versions: z.array(ModuleVersionRecordSchema),\n tags: z.record(z.string(), z.string()),\n});\n\nconst RegistrySearchResponseSchema = z.object({\n hits: z.array(ModuleSearchHitSchema),\n});\n\nconst DIAGNOSTIC_LABEL = 'Registry';\n\nexport interface RegistryServerClientOptions {\n /** Registry origin (e.g. `https://registry.wildo.ai`). */\n baseUrl: string;\n /** Optional bearer / API-key. CLI credentials are per-machine (KD-11). */\n authToken?: string;\n /** Request timeout in ms. */\n timeoutMs?: number;\n}\n\nfunction authHeaders(options: RegistryServerClientOptions): Record<string, string> {\n return options.authToken ? { Authorization: `Bearer ${options.authToken}` } : {};\n}\n\n/**\n * Throw the typed error for a non-2xx response, after releasing its body (#1763 review: an unread body\n * holds the connection until garbage collection). A 401 is told apart by whether a key was SENT — \"log\n * in\" and \"your key no longer works\" are different remedies (#1759 review).\n */\nasync function refuseUnlessOk(\n res: Response,\n options: RegistryServerClientOptions,\n action: string,\n notFound?: () => RegistryError,\n): Promise<void> {\n if (res.ok) return;\n let error: RegistryError;\n if (res.status === 404 && notFound) error = notFound();\n else if (res.status === 401) error = options.authToken ? new RegistryCredentialRejectedError(options.baseUrl) : new RegistryAuthRequiredError(options.baseUrl);\n else if (res.status === 403) error = new RegistryAuthForbiddenError(action);\n else if (res.status === 429) error = new RegistryRateLimitedError(options.baseUrl, action, parseRetryAfterSeconds(res.headers.get('retry-after')));\n else error = new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, action);\n await res.body?.cancel().catch(() => undefined);\n throw error;\n}\n\n/** `Retry-After` in its delta-seconds form; the HTTP-date form is not produced by a Wildo backend. */\nfunction parseRetryAfterSeconds(value: string | null): number | undefined {\n if (!value || !/^\\d+$/.test(value.trim())) return undefined;\n return Number(value.trim());\n}\n\n/**\n * 6th-pass M3: typed JSON-parse helper. A misconfigured proxy that\n * returns HTML at 2xx (or a truncated stream) would otherwise throw a\n * bare `SyntaxError` from `await res.json()`, bypassing every\n * `isRegistryError(err)` handler. This helper translates the parse\n * failure into a `RegistryMalformedPayloadError` so the typed-error\n * contract is universal across the client surface.\n */\nasync function parseJsonOrThrow(\n res: Response,\n registryUrl: string,\n action: string,\n timeoutMs: number | undefined,\n): Promise<unknown> {\n try {\n return await readJsonBody(res, registryUrl, action, timeoutMs);\n } catch (err) {\n // A body cut short by the request budget is a timeout (#1763), not a malformed payload.\n if (isRegistryError(err)) throw err;\n throw new RegistryMalformedPayloadError(\n registryUrl,\n action,\n `response is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nexport interface RegistryResolveResult {\n /** Resolved exact version (matches `Sha256DigestSchema` for digest). */\n version: string;\n artifactDigest: string;\n /**\n * Present when the resolved release is yanked. Only an EXACT-version request can resolve to one\n * (#1758) — ranges and tags never do — so the caller is pinned to it and should warn, not refuse.\n */\n yanked?: RegistryYankNotice;\n}\n\nexport interface RegistryInfoResult {\n moduleId: string;\n manifest: ModuleManifest;\n versions: readonly ModuleVersionRecord[];\n /** dist-tag → version map (e.g. `latest → 1.2.3`). */\n tags: Readonly<Record<string, string>>;\n}\n\n/** One search hit: the module, its latest version, and (#2014) its kind and provider facts. */\nexport type RegistrySearchHit = ModuleSearchHit;\n\nexport const RegistryServerClient = {\n /**\n * Liveness probe against `/health`. Returns boolean — used by\n * `wildo registry ping` smoke. The registry server now relies on\n * the framework's auto-mounted `HealthController` at the engine\n * root (`GET /health` always 200; `GET /health/ready` enforces\n * dependency readiness), so the path has NO `/v1` prefix.\n */\n async ping(options: RegistryServerClientOptions): Promise<boolean> {\n try {\n await fetchJsonOk(joinUrl(options.baseUrl, '/health'), {\n method: 'GET',\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Resolve a semver range / tag against a registry domain. The\n * server returns the concrete version + artifact digest so the\n * caller can verify the download against `artifactDigest`.\n */\n async resolve(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; range: string },\n ): Promise<RegistryResolveResult> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/resolve?range=${encodeURIComponent(args.range)}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, `resolve ${args.moduleId}`, () => new RegistryVersionNotFoundError(args.moduleId, args.range));\n // 6th-pass M3: typed JSON-parse (was bare `SyntaxError` for\n // malformed proxy responses).\n const json = (await parseJsonOrThrow(res, options.baseUrl, `resolve ${args.moduleId}`, options.timeoutMs)) as {\n version?: unknown;\n artifactDigest?: unknown;\n yanked?: unknown;\n };\n const digest = String(json.artifactDigest ?? '');\n // 6th-pass M4: typed digest validation (was bare `ZodError`).\n const digestParse = Sha256DigestSchema.safeParse(digest);\n if (!digestParse.success) {\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n `resolve ${args.moduleId}`,\n `artifactDigest is not a valid sha256:<64-hex> string: ${formatZodIssuesAsSingleLine(digestParse.error)}`,\n );\n }\n if (typeof json.version !== 'string' || json.version.length === 0) {\n // 3rd-pass M6: typed `RegistryMalformedPayloadError` instead of\n // bare `Error` so callers' `isRegistryError(err)` handlers fire\n // correctly.\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n `resolve ${args.moduleId}`,\n 'response missing required `version` string',\n );\n }\n let yanked: RegistryYankNotice | undefined;\n if (json.yanked !== undefined) {\n const yankParse = RegistryYankNoticeSchema.safeParse(json.yanked);\n if (!yankParse.success) {\n throw new RegistryMalformedPayloadError(options.baseUrl, `resolve ${args.moduleId}`, `yanked: ${formatZodIssuesAsSingleLine(yankParse.error)}`);\n }\n yanked = yankParse.data;\n }\n return { version: json.version, artifactDigest: digest, ...(yanked ? { yanked } : {}) };\n },\n\n /**\n * Fetch full info for a module: manifest, every published\n * version, dist-tags. Used by `wildo registry info` (Phase 4).\n */\n async info(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string },\n ): Promise<RegistryInfoResult> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, `info ${args.moduleId}`, () => new RegistryModuleNotFoundError(args.moduleId));\n // 6th-pass M3: typed JSON-parse.\n const json = await parseJsonOrThrow(res, options.baseUrl, `info ${args.moduleId}`, options.timeoutMs);\n const parsed = RegistryInfoResponseSchema.safeParse(json);\n if (!parsed.success) {\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n `info ${args.moduleId}`,\n formatZodIssuesAsSingleLine(parsed.error),\n );\n }\n return parsed.data;\n },\n\n /**\n * Search the registry's metadata index: a module-id substring, and (#2014) the manifest filters —\n * kind, engine capability and provider maturity. The server refuses an unknown filter value.\n */\n async search(\n options: RegistryServerClientOptions,\n args: { domain: string; query: string; filter?: ModuleSearchFilter },\n ): Promise<readonly RegistrySearchHit[]> {\n const params = new URLSearchParams([['q', args.query], ...moduleSearchFilterQueryPairs(args.filter ?? {})]);\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules?${params.toString()}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, 'search');\n // 6th-pass M3: typed JSON-parse.\n const json = await parseJsonOrThrow(res, options.baseUrl, 'search', options.timeoutMs);\n const parsed = RegistrySearchResponseSchema.safeParse(json);\n if (!parsed.success) {\n throw new RegistryMalformedPayloadError(\n options.baseUrl,\n 'search',\n formatZodIssuesAsSingleLine(parsed.error),\n );\n }\n // Re-applied here: a server that predates the filters ignores them and answers every module (#2014 review F9).\n return parsed.data.hits.filter((hit) => moduleSearchHitMatchesFilter(hit, args.filter ?? {}));\n },\n\n /**\n * Stream-download a published artifact's bytes and verify the\n * sha256 integrity matches `expectedDigest`. Throws\n * `RegistryArtifactIntegrityMismatchError` on mismatch — the\n * digest check is non-negotiable per KD-9 / Security model.\n */\n async download(\n options: RegistryServerClientOptions,\n args: {\n domain: string;\n moduleId: string;\n version: string;\n expectedDigest: string;\n },\n ): Promise<{ bytes: Uint8Array; integrity: string; yanked?: RegistryYankNotice }> {\n // 7th-pass C-M1: caller-supplied digest is a developer-contract\n // violation if malformed, not a registry-runtime condition.\n // Throw `TypeError` (matching `C-L3` precedent for\n // `getModuleStagingPaths` argument-shape violations) so the\n // typed `RegistryError` vocabulary stays reserved for\n // registry-runtime errors. Prior `Sha256DigestSchema.parse(...)`\n // leaked a bare `ZodError` that bypassed\n // `isRegistryError(err)` handlers but ALSO confused\n // typed-handler maintainers about the contract.\n const digestParse = Sha256DigestSchema.safeParse(args.expectedDigest);\n if (!digestParse.success) {\n throw new TypeError(\n `download() expectedDigest must be a valid sha256:<64-hex> string (got: ${JSON.stringify(args.expectedDigest)}). ${formatZodIssuesAsSingleLine(digestParse.error)}`,\n );\n }\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/${encodeURIComponent(args.version)}/artifact`,\n );\n // A transfer, not a metadata call: the response is bounded by `timeoutMs`, the body by an IDLE budget\n // reset on every chunk, so a large artifact over a slow link installs and a stalled one fails (#1763).\n const { response: res, readAll } = await fetchTransfer(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n await refuseUnlessOk(res, options, `download ${args.moduleId}@${args.version}`, () => new RegistryVersionNotFoundError(args.moduleId, args.version));\n const buf = await readAll();\n const { createHash } = await import('node:crypto');\n const observed = `sha256:${createHash('sha256').update(buf).digest('hex')}`;\n if (observed !== args.expectedDigest) {\n throw new RegistryArtifactIntegrityMismatchError(\n args.moduleId,\n args.version,\n args.expectedDigest,\n observed,\n );\n }\n // A yanked release is served by exact version (#1758) and says so in headers.\n const yankedAt = res.headers.get(REGISTRY_YANKED_AT_HEADER);\n const encodedReason = res.headers.get(REGISTRY_YANK_REASON_HEADER);\n let reason: string | undefined;\n if (encodedReason) {\n try { reason = decodeURIComponent(encodedReason); } catch { reason = encodedReason; }\n }\n return { bytes: buf, integrity: observed, ...(yankedAt ? { yanked: { yankedAt, ...(reason ? { reason } : {}) } } : {}) };\n },\n /**\n * Yank a release (#1758): ranges and `latest` stop selecting it, and `latest` moves to the highest\n * live release; an exact pin still installs it, with a warning. Needs a key holding the version UPDATE\n * role in the domain's owning organization. Returns where `latest` points afterwards.\n */\n async yank(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; version: string; reason?: string },\n ): Promise<{ latest: string | null }> {\n return changeYankState(options, args, RegistryYankVerb.YANK);\n },\n\n /** Restore a yanked release (#1758); `latest` returns to it when it outranks the current target. */\n async unyank(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; version: string },\n ): Promise<{ latest: string | null }> {\n return changeYankState(options, args, RegistryYankVerb.UNYANK);\n },\n} as const;\n\nconst RegistryYankResponseSchema = z.object({ ok: z.literal(true), latest: z.string().nullable().optional() });\n\nasync function changeYankState(\n options: RegistryServerClientOptions,\n args: { domain: string; moduleId: string; version: string; reason?: string },\n verb: RegistryYankVerb,\n): Promise<{ latest: string | null }> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/${verb}`,\n );\n const action = `${verb} ${args.moduleId}@${args.version}`;\n const res = await fetchWithTimeout(url, {\n method: 'POST',\n headers: { ...authHeaders(options), 'content-type': 'application/json' },\n body: JSON.stringify({ version: args.version, ...(args.reason !== undefined ? { reason: args.reason } : {}) }),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n if (res.status === 409) {\n // Only the release-state refusal is the no-op; a 409 for anything else (the registry giving up after\n // lost optimistic checks) is a FAILED yank and must not be reported as done (#1758 re-review R3).\n const body = await res.json().catch(() => undefined);\n if (isRegistryReleaseStateConflictBody(body)) throw new RegistryYankStateConflictError(args.moduleId, args.version, verb);\n throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, action);\n }\n // A 404 names the module or the version; the sanitized envelope does not say which.\n await refuseUnlessOk(res, options, action, () => new RegistryVersionNotFoundError(args.moduleId, args.version));\n const parsed = RegistryYankResponseSchema.safeParse(await parseJsonOrThrow(res, options.baseUrl, action, options.timeoutMs));\n if (!parsed.success) {\n throw new RegistryMalformedPayloadError(options.baseUrl, action, formatZodIssuesAsSingleLine(parsed.error));\n }\n return { latest: parsed.data.latest ?? null };\n}\n"]}
|