@wildo-ai/wildo-module-client 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +34 -0
- package/dist/esm/.builder.pid +9 -0
- package/dist/esm/__tests__/lockfile-repair.service.test.d.ts +0 -0
- package/dist/esm/__tests__/lockfile-repair.service.test.d.ts.map +0 -0
- package/dist/esm/__tests__/lockfile-repair.service.test.js.map +0 -0
- package/dist/esm/__tests__/module-adopter.service.test.d.ts +0 -0
- package/dist/esm/__tests__/module-adopter.service.test.d.ts.map +0 -0
- package/dist/esm/__tests__/module-adopter.service.test.js.map +0 -0
- package/dist/esm/__tests__/module-packager.service.test.d.ts +0 -0
- package/dist/esm/__tests__/module-packager.service.test.d.ts.map +0 -0
- package/dist/esm/__tests__/module-packager.service.test.js.map +0 -0
- package/dist/esm/__tests__/provider-materialization-hook.test.d.ts +0 -0
- package/dist/esm/__tests__/provider-materialization-hook.test.d.ts.map +0 -0
- package/dist/esm/__tests__/provider-materialization-hook.test.js.map +0 -0
- package/dist/esm/__tests__/provider-sync-runner.test.d.ts +0 -0
- package/dist/esm/__tests__/provider-sync-runner.test.d.ts.map +0 -0
- package/dist/esm/__tests__/provider-sync-runner.test.js.map +0 -0
- package/dist/esm/__tests__/registry-lockfile.service.test.d.ts +0 -0
- package/dist/esm/__tests__/registry-lockfile.service.test.d.ts.map +0 -0
- package/dist/esm/__tests__/registry-lockfile.service.test.js.map +0 -0
- package/dist/esm/__tests__/registry-server-client.test.d.ts +0 -0
- package/dist/esm/__tests__/registry-server-client.test.d.ts.map +0 -0
- package/dist/esm/__tests__/registry-server-client.test.js.map +0 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +18 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/services/_http-client.d.ts +44 -0
- package/dist/esm/services/_http-client.d.ts.map +1 -0
- package/dist/esm/services/_http-client.js +75 -0
- package/dist/esm/services/_http-client.js.map +1 -0
- package/dist/esm/services/_zod-issue-formatting.d.ts +12 -0
- package/dist/esm/services/_zod-issue-formatting.d.ts.map +1 -0
- package/dist/esm/services/_zod-issue-formatting.js +47 -0
- package/dist/esm/services/_zod-issue-formatting.js.map +1 -0
- package/dist/esm/services/index.d.ts +10 -0
- package/dist/esm/services/index.d.ts.map +1 -0
- package/dist/esm/services/index.js +10 -0
- package/dist/esm/services/index.js.map +1 -0
- package/dist/esm/services/lockfile-repair.service.d.ts +68 -0
- package/dist/esm/services/lockfile-repair.service.d.ts.map +1 -0
- package/dist/esm/services/lockfile-repair.service.js +160 -0
- package/dist/esm/services/lockfile-repair.service.js.map +1 -0
- package/dist/esm/services/module-adopter.service.d.ts +59 -0
- package/dist/esm/services/module-adopter.service.d.ts.map +1 -0
- package/dist/esm/services/module-adopter.service.js +126 -0
- package/dist/esm/services/module-adopter.service.js.map +1 -0
- package/dist/esm/services/module-packager.service.d.ts +105 -0
- package/dist/esm/services/module-packager.service.d.ts.map +1 -0
- package/dist/esm/services/module-packager.service.js +212 -0
- package/dist/esm/services/module-packager.service.js.map +1 -0
- package/dist/esm/services/provider-materialization-hook.d.ts +32 -0
- package/dist/esm/services/provider-materialization-hook.d.ts.map +1 -0
- package/dist/esm/services/provider-materialization-hook.js +33 -0
- package/dist/esm/services/provider-materialization-hook.js.map +1 -0
- package/dist/esm/services/provider-sync-runner.d.ts +87 -0
- package/dist/esm/services/provider-sync-runner.d.ts.map +1 -0
- package/dist/esm/services/provider-sync-runner.js +207 -0
- package/dist/esm/services/provider-sync-runner.js.map +1 -0
- package/dist/esm/services/registry-companion-client.d.ts +39 -0
- package/dist/esm/services/registry-companion-client.d.ts.map +1 -0
- package/dist/esm/services/registry-companion-client.js +109 -0
- package/dist/esm/services/registry-companion-client.js.map +1 -0
- package/dist/esm/services/registry-lockfile.service.d.ts +56 -0
- package/dist/esm/services/registry-lockfile.service.d.ts.map +1 -0
- package/dist/esm/services/registry-lockfile.service.js +99 -0
- package/dist/esm/services/registry-lockfile.service.js.map +1 -0
- package/dist/esm/services/registry-server-client.d.ts +94 -0
- package/dist/esm/services/registry-server-client.d.ts.map +1 -0
- package/dist/esm/services/registry-server-client.js +225 -0
- package/dist/esm/services/registry-server-client.js.map +1 -0
- package/dist/esm/services/types.d.ts +22 -0
- package/dist/esm/services/types.d.ts.map +1 -0
- package/dist/esm/services/types.js +16 -0
- package/dist/esm/services/types.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +51 -0
- package/src/__tests__/lockfile-repair.service.test.ts +106 -0
- package/src/__tests__/module-adopter.service.test.ts +96 -0
- package/src/__tests__/module-packager.service.test.ts +258 -0
- package/src/__tests__/provider-materialization-hook.test.ts +47 -0
- package/src/__tests__/provider-sync-runner.test.ts +113 -0
- package/src/__tests__/registry-lockfile.service.test.ts +134 -0
- package/src/__tests__/registry-server-client.test.ts +312 -0
- package/src/index.ts +18 -0
- package/src/services/_http-client.ts +91 -0
- package/src/services/_zod-issue-formatting.ts +50 -0
- package/src/services/index.ts +9 -0
- package/src/services/lockfile-repair.service.ts +215 -0
- package/src/services/module-adopter.service.ts +155 -0
- package/src/services/module-packager.service.ts +251 -0
- package/src/services/provider-materialization-hook.ts +54 -0
- package/src/services/provider-sync-runner.ts +298 -0
- package/src/services/registry-companion-client.ts +163 -0
- package/src/services/registry-lockfile.service.ts +122 -0
- package/src/services/registry-server-client.ts +334 -0
- package/src/services/types.ts +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Copyright (c) 2026 P2C Consulting, s.à r.l.-S
|
|
2
|
+
RCS Luxembourg B307591
|
|
3
|
+
6C, Porte de France, L-4360 Esch-sur-Alzette, Luxembourg
|
|
4
|
+
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
This software and its accompanying materials (the "Software") are the
|
|
8
|
+
confidential and proprietary property of P2C Consulting, s.à r.l.-S (the
|
|
9
|
+
"Licensor"). The Software is made available for viewing only. No licence,
|
|
10
|
+
right, or permission of any kind is granted by its publication or by its
|
|
11
|
+
availability on any package registry or source repository.
|
|
12
|
+
|
|
13
|
+
Without the Licensor's prior written permission, you may not use, copy,
|
|
14
|
+
reproduce, modify, adapt, translate, merge, publish, distribute, sublicense,
|
|
15
|
+
sell, host, or create derivative works of the Software, in whole or in part,
|
|
16
|
+
nor use it to provide a service to any third party.
|
|
17
|
+
|
|
18
|
+
Publication of the Software in any public registry is for distribution to
|
|
19
|
+
authorised recipients and for technical evaluation of its packaging only. It
|
|
20
|
+
does not place the Software in the public domain, does not constitute an open
|
|
21
|
+
source release, and does not waive any right of the Licensor.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
27
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
28
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
29
|
+
|
|
30
|
+
Third-party components distributed with the Software remain governed by their
|
|
31
|
+
own licences.
|
|
32
|
+
|
|
33
|
+
Contact: P2C Consulting, s.à r.l.-S, 6C, Porte de France, L-4360
|
|
34
|
+
Esch-sur-Alzette, Luxembourg.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"writerPid": 95348,
|
|
4
|
+
"orchestratorPid": 94847,
|
|
5
|
+
"orchestratorSessionId": null,
|
|
6
|
+
"orchestratorStartedAt": "Mon Aug 31 09:18:19 2026",
|
|
7
|
+
"distDirectory": "/Users/paulcayon/Projects/Wildo.ai/dev/wildo-ai/platform/factory/wildo-module-client/dist/esm",
|
|
8
|
+
"acquiredAt": "2026-08-31T07:18:20.844Z"
|
|
9
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@wildo-ai/wildo-module-client` — runtime services for the Wildo
|
|
3
|
+
* module-registry workstream (KD-3).
|
|
4
|
+
*
|
|
5
|
+
* Phase 0.5 surface:
|
|
6
|
+
* - `RegistryServerClient` — HTTP client for the registry server.
|
|
7
|
+
* - `RegistryCompanionClient` — HTTP client for the dev companion.
|
|
8
|
+
* - `RegistryLockfileService` — section-scoped `sections.modules`
|
|
9
|
+
* reader/writer.
|
|
10
|
+
* - `runProviderMaterializationHook` — post-mutation no-op hook
|
|
11
|
+
* that delegates to `wildo config sync --domain config`.
|
|
12
|
+
*
|
|
13
|
+
* Phase 1+ adds `ModulePackagerService`, `ModuleAdopterService`,
|
|
14
|
+
* `LockfileRepairService`, and the real (locked + atomic) lockfile
|
|
15
|
+
* mutation surface.
|
|
16
|
+
*/
|
|
17
|
+
export * from './services';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@wildo-ai/wildo-module-client` — runtime services for the Wildo
|
|
3
|
+
* module-registry workstream (KD-3).
|
|
4
|
+
*
|
|
5
|
+
* Phase 0.5 surface:
|
|
6
|
+
* - `RegistryServerClient` — HTTP client for the registry server.
|
|
7
|
+
* - `RegistryCompanionClient` — HTTP client for the dev companion.
|
|
8
|
+
* - `RegistryLockfileService` — section-scoped `sections.modules`
|
|
9
|
+
* reader/writer.
|
|
10
|
+
* - `runProviderMaterializationHook` — post-mutation no-op hook
|
|
11
|
+
* that delegates to `wildo config sync --domain config`.
|
|
12
|
+
*
|
|
13
|
+
* Phase 1+ adds `ModulePackagerService`, `ModuleAdopterService`,
|
|
14
|
+
* `LockfileRepairService`, and the real (locked + atomic) lockfile
|
|
15
|
+
* mutation surface.
|
|
16
|
+
*/
|
|
17
|
+
export * from './services/index.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,cAAc,YAAY,CAAC","sourcesContent":["/**\n * `@wildo-ai/wildo-module-client` — runtime services for the Wildo\n * module-registry workstream (KD-3).\n *\n * Phase 0.5 surface:\n * - `RegistryServerClient` — HTTP client for the registry server.\n * - `RegistryCompanionClient` — HTTP client for the dev companion.\n * - `RegistryLockfileService` — section-scoped `sections.modules`\n * reader/writer.\n * - `runProviderMaterializationHook` — post-mutation no-op hook\n * that delegates to `wildo config sync --domain config`.\n *\n * Phase 1+ adds `ModulePackagerService`, `ModuleAdopterService`,\n * `LockfileRepairService`, and the real (locked + atomic) lockfile\n * mutation surface.\n */\n\nexport * from './services';\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal HTTP client utilities shared by `RegistryServerClient`
|
|
3
|
+
* and `RegistryCompanionClient`.
|
|
4
|
+
*
|
|
5
|
+
* Both clients want the same primitives:
|
|
6
|
+
* - `joinUrl(base, path)` — single-source-of-truth path joiner
|
|
7
|
+
* that tolerates leading/trailing slashes;
|
|
8
|
+
* - `fetchWithTimeout(url, init, timeoutMs)` — abort-on-timeout
|
|
9
|
+
* wrapper that converts `AbortError`/`TimeoutError` into a
|
|
10
|
+
* uniform diagnostic message;
|
|
11
|
+
* - `fetchJsonOk(...)` — convenience for liveness probes that
|
|
12
|
+
* want a boolean answer.
|
|
13
|
+
*
|
|
14
|
+
* The leading underscore signals "package-internal" — these are
|
|
15
|
+
* intentionally NOT re-exported from `services/index.ts`. Phase 2
|
|
16
|
+
* services that need fancier HTTP (multipart upload, streaming
|
|
17
|
+
* download) extend this file rather than copy the primitives.
|
|
18
|
+
*/
|
|
19
|
+
export declare function joinUrl(base: string, path: string): string;
|
|
20
|
+
export interface FetchWithTimeoutInit extends RequestInit {
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
/** Used in the diagnostic timeout message (e.g. "Registry", "Companion registry"). */
|
|
23
|
+
diagnosticLabel?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function fetchWithTimeout(url: string, init?: FetchWithTimeoutInit): Promise<Response>;
|
|
26
|
+
/**
|
|
27
|
+
* Throws on non-2xx; returns the Response otherwise.
|
|
28
|
+
*
|
|
29
|
+
* C-L2 (4th-pass review) waiver: this helper deliberately throws
|
|
30
|
+
* bare `Error` and is NOT part of the typed `RegistryError`
|
|
31
|
+
* vocabulary. It exists for liveness probes (`ping()`) that wrap
|
|
32
|
+
* the call in their own try/catch and convert any thrown exception
|
|
33
|
+
* to `false`. Future callers MUST do the same — if a caller wants
|
|
34
|
+
* to surface a typed error to the user, they should not use
|
|
35
|
+
* `fetchJsonOk` and should call `fetchWithTimeout` directly +
|
|
36
|
+
* inspect `res.ok` themselves to throw the right
|
|
37
|
+
* `RegistryUnexpectedStatusError` / `RegistryAuthRequiredError` /
|
|
38
|
+
* etc. variant.
|
|
39
|
+
*
|
|
40
|
+
* @internal — internal lib helper, not re-exported from the
|
|
41
|
+
* package root.
|
|
42
|
+
*/
|
|
43
|
+
export declare function fetchJsonOk(url: string, init?: FetchWithTimeoutInit): Promise<Response>;
|
|
44
|
+
//# sourceMappingURL=_http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_http-client.d.ts","sourceRoot":"","sources":["../../../../src/services/_http-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,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,CAyBnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,QAAQ,CAAC,CAQnB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal HTTP client utilities shared by `RegistryServerClient`
|
|
3
|
+
* and `RegistryCompanionClient`.
|
|
4
|
+
*
|
|
5
|
+
* Both clients want the same primitives:
|
|
6
|
+
* - `joinUrl(base, path)` — single-source-of-truth path joiner
|
|
7
|
+
* that tolerates leading/trailing slashes;
|
|
8
|
+
* - `fetchWithTimeout(url, init, timeoutMs)` — abort-on-timeout
|
|
9
|
+
* wrapper that converts `AbortError`/`TimeoutError` into a
|
|
10
|
+
* uniform diagnostic message;
|
|
11
|
+
* - `fetchJsonOk(...)` — convenience for liveness probes that
|
|
12
|
+
* want a boolean answer.
|
|
13
|
+
*
|
|
14
|
+
* The leading underscore signals "package-internal" — these are
|
|
15
|
+
* intentionally NOT re-exported from `services/index.ts`. Phase 2
|
|
16
|
+
* services that need fancier HTTP (multipart upload, streaming
|
|
17
|
+
* download) extend this file rather than copy the primitives.
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
20
|
+
export function joinUrl(base, path) {
|
|
21
|
+
const normalized = path.startsWith('/') ? path : `/${path}`;
|
|
22
|
+
return `${base.replace(/\/$/, '')}${normalized}`;
|
|
23
|
+
}
|
|
24
|
+
export async function fetchWithTimeout(url, init = {}) {
|
|
25
|
+
const timeoutMs = init.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
26
|
+
const label = init.diagnosticLabel ?? 'HTTP';
|
|
27
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
28
|
+
// Strip the wrapper-only fields before forwarding to `fetch`. The
|
|
29
|
+
// `_` names are conventional unused-binding markers.
|
|
30
|
+
//
|
|
31
|
+
// 6th-pass M1 — tsconfig premise (corrected): the wider repo's
|
|
32
|
+
// `engine/tsconfig.common.json` currently sets both `noUnusedLocals`
|
|
33
|
+
// and `noUnusedParameters` to `false`, so any unused binding (with
|
|
34
|
+
// or without `_` prefix) compiles clean today. If either flag is
|
|
35
|
+
// ever flipped to `true`, TypeScript's underscore-prefix convention
|
|
36
|
+
// applies to parameters reliably and to destructured `let`/`const`
|
|
37
|
+
// bindings depending on TS version + setting — so the `_` prefix
|
|
38
|
+
// here is a defensive signal of "intentional discard" should that
|
|
39
|
+
// happen. Today it's purely cosmetic.
|
|
40
|
+
const { timeoutMs: _timeoutMs, diagnosticLabel: _diagnosticLabel, ...rest } = init;
|
|
41
|
+
try {
|
|
42
|
+
return await fetch(url, { ...rest, signal });
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (err instanceof Error && (err.name === 'AbortError' || err.name === 'TimeoutError')) {
|
|
46
|
+
throw new Error(`${label} request timed out after ${timeoutMs}ms (${url})`);
|
|
47
|
+
}
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Throws on non-2xx; returns the Response otherwise.
|
|
53
|
+
*
|
|
54
|
+
* C-L2 (4th-pass review) waiver: this helper deliberately throws
|
|
55
|
+
* bare `Error` and is NOT part of the typed `RegistryError`
|
|
56
|
+
* vocabulary. It exists for liveness probes (`ping()`) that wrap
|
|
57
|
+
* the call in their own try/catch and convert any thrown exception
|
|
58
|
+
* to `false`. Future callers MUST do the same — if a caller wants
|
|
59
|
+
* to surface a typed error to the user, they should not use
|
|
60
|
+
* `fetchJsonOk` and should call `fetchWithTimeout` directly +
|
|
61
|
+
* inspect `res.ok` themselves to throw the right
|
|
62
|
+
* `RegistryUnexpectedStatusError` / `RegistryAuthRequiredError` /
|
|
63
|
+
* etc. variant.
|
|
64
|
+
*
|
|
65
|
+
* @internal — internal lib helper, not re-exported from the
|
|
66
|
+
* package root.
|
|
67
|
+
*/
|
|
68
|
+
export async function fetchJsonOk(url, init = {}) {
|
|
69
|
+
const res = await fetchWithTimeout(url, init);
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
throw new Error(`${init.diagnosticLabel ?? 'HTTP'} request rejected (${res.status} ${res.statusText}) at ${url}`);
|
|
72
|
+
}
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=_http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_http-client.js","sourceRoot":"","sources":["../../../../src/services/_http-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,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,IAAI,GAAG,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,CAAC,EAAE,CAAC;YACvF,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,4BAA4B,SAAS,OAAO,GAAG,GAAG,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,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, timeoutMs)` — abort-on-timeout\n * wrapper that converts `AbortError`/`TimeoutError` into a\n * uniform diagnostic message;\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\nconst DEFAULT_TIMEOUT_MS = 10_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 if (err instanceof Error && (err.name === 'AbortError' || err.name === 'TimeoutError')) {\n throw new Error(`${label} request timed out after ${timeoutMs}ms (${url})`);\n }\n throw err;\n }\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"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ZodError } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Render a `ZodError` as one operator-readable line —
|
|
4
|
+
* `path: message; path: message; …` — bounded at {@link ISSUE_RENDER_LIMIT}
|
|
5
|
+
* with an explicit `(+N more)` so truncation is never silent.
|
|
6
|
+
*
|
|
7
|
+
* Used as the `detail` on `RegistryMalformedPayloadError` and on lockfile
|
|
8
|
+
* repair findings. The raw `error.message` in Zod 4 is the JSON-stringified
|
|
9
|
+
* issues array — verbose, multi-line, and unreadable in CLI / SIEM output.
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatZodIssuesAsSingleLine(error: ZodError): string;
|
|
12
|
+
//# sourceMappingURL=_zod-issue-formatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-internal mirror of `summarizeZodIssues` from `@wildo-ai/saas-models`,
|
|
3
|
+
* which is the canonical authority every other Wildo surface delegates to.
|
|
4
|
+
*
|
|
5
|
+
* zod-issue-formatter-mirror: engine/saas-models/src/errors/zod-issue-formatting.shared.utils.ts
|
|
6
|
+
*
|
|
7
|
+
* Why a mirror rather than an import: this package declares exactly ONE
|
|
8
|
+
* workspace dependency (`@wildo-ai/platform-config-lib`) plus a `zod` peer.
|
|
9
|
+
* Importing `saas-models` would pull its decorator-bound schema tree into a
|
|
10
|
+
* lean registry client to save a handful of lines — a bad trade. The boundary
|
|
11
|
+
* is the reason for the duplication; keep the RENDERING identical, and mirror
|
|
12
|
+
* any change to the canonical helper's path / root-label / overflow semantics
|
|
13
|
+
* here.
|
|
14
|
+
*
|
|
15
|
+
* The marker above is not decoration — `pnpm check:zod-issue-formatter-mirror`
|
|
16
|
+
* discovers this file by it and fails if the constants below drift from the
|
|
17
|
+
* canonical source it names. If the dependency constraint that justifies this
|
|
18
|
+
* mirror ever stops holding, delete the file and import the canonical formatter
|
|
19
|
+
* rather than keeping a mirror nobody needs.
|
|
20
|
+
*
|
|
21
|
+
* Within this package this is the single source: `registry-server-client.ts`
|
|
22
|
+
* and `lockfile-repair.service.ts` both call it instead of re-inlining the
|
|
23
|
+
* `.slice(0, 5).map(...).join('; ')` chain.
|
|
24
|
+
*/
|
|
25
|
+
/** Label for an issue whose `path` is empty — the value itself failed. */
|
|
26
|
+
const ROOT_ISSUE_PATH_LABEL = '<root>';
|
|
27
|
+
/** Issue cap; a malformed payload can fail on hundreds of paths. */
|
|
28
|
+
const ISSUE_RENDER_LIMIT = 5;
|
|
29
|
+
/**
|
|
30
|
+
* Render a `ZodError` as one operator-readable line —
|
|
31
|
+
* `path: message; path: message; …` — bounded at {@link ISSUE_RENDER_LIMIT}
|
|
32
|
+
* with an explicit `(+N more)` so truncation is never silent.
|
|
33
|
+
*
|
|
34
|
+
* Used as the `detail` on `RegistryMalformedPayloadError` and on lockfile
|
|
35
|
+
* repair findings. The raw `error.message` in Zod 4 is the JSON-stringified
|
|
36
|
+
* issues array — verbose, multi-line, and unreadable in CLI / SIEM output.
|
|
37
|
+
*/
|
|
38
|
+
export function formatZodIssuesAsSingleLine(error) {
|
|
39
|
+
const rendered = error.issues
|
|
40
|
+
.slice(0, ISSUE_RENDER_LIMIT)
|
|
41
|
+
.map((issue) => `${issue.path.join('.') || ROOT_ISSUE_PATH_LABEL}: ${issue.message}`);
|
|
42
|
+
const omitted = error.issues.length - ISSUE_RENDER_LIMIT;
|
|
43
|
+
if (omitted > 0)
|
|
44
|
+
rendered.push(`(+${omitted} more)`);
|
|
45
|
+
return rendered.join('; ');
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=_zod-issue-formatting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_zod-issue-formatting.js","sourceRoot":"","sources":["../../../../src/services/_zod-issue-formatting.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,0EAA0E;AAC1E,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAEvC,oEAAoE;AACpE,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CAAC,KAAe;IACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM;SAC1B,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC;SAC5B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,qBAAqB,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,kBAAkB,CAAC;IACzD,IAAI,OAAO,GAAG,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,OAAO,QAAQ,CAAC,CAAC;IACrD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["import type { ZodError } from 'zod';\n\n/**\n * Package-internal mirror of `summarizeZodIssues` from `@wildo-ai/saas-models`,\n * which is the canonical authority every other Wildo surface delegates to.\n *\n * zod-issue-formatter-mirror: engine/saas-models/src/errors/zod-issue-formatting.shared.utils.ts\n *\n * Why a mirror rather than an import: this package declares exactly ONE\n * workspace dependency (`@wildo-ai/platform-config-lib`) plus a `zod` peer.\n * Importing `saas-models` would pull its decorator-bound schema tree into a\n * lean registry client to save a handful of lines — a bad trade. The boundary\n * is the reason for the duplication; keep the RENDERING identical, and mirror\n * any change to the canonical helper's path / root-label / overflow semantics\n * here.\n *\n * The marker above is not decoration — `pnpm check:zod-issue-formatter-mirror`\n * discovers this file by it and fails if the constants below drift from the\n * canonical source it names. If the dependency constraint that justifies this\n * mirror ever stops holding, delete the file and import the canonical formatter\n * rather than keeping a mirror nobody needs.\n *\n * Within this package this is the single source: `registry-server-client.ts`\n * and `lockfile-repair.service.ts` both call it instead of re-inlining the\n * `.slice(0, 5).map(...).join('; ')` chain.\n */\n\n/** Label for an issue whose `path` is empty — the value itself failed. */\nconst ROOT_ISSUE_PATH_LABEL = '<root>';\n\n/** Issue cap; a malformed payload can fail on hundreds of paths. */\nconst ISSUE_RENDER_LIMIT = 5;\n\n/**\n * Render a `ZodError` as one operator-readable line —\n * `path: message; path: message; …` — bounded at {@link ISSUE_RENDER_LIMIT}\n * with an explicit `(+N more)` so truncation is never silent.\n *\n * Used as the `detail` on `RegistryMalformedPayloadError` and on lockfile\n * repair findings. The raw `error.message` in Zod 4 is the JSON-stringified\n * issues array — verbose, multi-line, and unreadable in CLI / SIEM output.\n */\nexport function formatZodIssuesAsSingleLine(error: ZodError): string {\n const rendered = error.issues\n .slice(0, ISSUE_RENDER_LIMIT)\n .map((issue) => `${issue.path.join('.') || ROOT_ISSUE_PATH_LABEL}: ${issue.message}`);\n const omitted = error.issues.length - ISSUE_RENDER_LIMIT;\n if (omitted > 0) rendered.push(`(+${omitted} more)`);\n return rendered.join('; ');\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './registry-server-client';
|
|
3
|
+
export * from './registry-companion-client';
|
|
4
|
+
export * from './registry-lockfile.service';
|
|
5
|
+
export * from './provider-sync-runner';
|
|
6
|
+
export * from './provider-materialization-hook';
|
|
7
|
+
export * from './module-packager.service';
|
|
8
|
+
export * from './module-adopter.service';
|
|
9
|
+
export * from './lockfile-repair.service';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './registry-server-client.js';
|
|
3
|
+
export * from './registry-companion-client.js';
|
|
4
|
+
export * from './registry-lockfile.service.js';
|
|
5
|
+
export * from './provider-sync-runner.js';
|
|
6
|
+
export * from './provider-materialization-hook.js';
|
|
7
|
+
export * from './module-packager.service.js';
|
|
8
|
+
export * from './module-adopter.service.js';
|
|
9
|
+
export * from './lockfile-repair.service.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","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","sourcesContent":["export * from './types';\nexport * from './registry-server-client';\nexport * from './registry-companion-client';\nexport * from './registry-lockfile.service';\nexport * from './provider-sync-runner';\nexport * from './provider-materialization-hook';\nexport * from './module-packager.service';\nexport * from './module-adopter.service';\nexport * from './lockfile-repair.service';\n"]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `LockfileRepairService` — Phase 2 read-only lockfile diagnostics.
|
|
3
|
+
*
|
|
4
|
+
* Backs `wildo registry repair-lockfile` (CLI command lands in a
|
|
5
|
+
* later step). The service does NOT mutate the lockfile by
|
|
6
|
+
* default — its job is to surface a structured diagnostic the
|
|
7
|
+
* operator can act on:
|
|
8
|
+
* - validate the canonical envelope shape;
|
|
9
|
+
* - validate `sections.modules` against
|
|
10
|
+
* `RegistryModulesLockSectionSchema`;
|
|
11
|
+
* - report which `installed[*].files` are missing on disk
|
|
12
|
+
* (drift between the lockfile and the source tree);
|
|
13
|
+
* - report which `installed[*].artifactDigest` strings are not
|
|
14
|
+
* `Sha256DigestSchema`-shaped (residue from pre-tightening
|
|
15
|
+
* publishes).
|
|
16
|
+
*
|
|
17
|
+
* Mutating repair is a Phase 7 deliverable — surfacing the gaps is
|
|
18
|
+
* what unblocks the operator now.
|
|
19
|
+
*
|
|
20
|
+
* `i18n` validation is intentionally NOT performed here (KD-15 +
|
|
21
|
+
* Review-pass-2 / MEDIUM-5): repair is the wrong place to
|
|
22
|
+
* second-guess companion-owned section semantics. The shared
|
|
23
|
+
* lockfile library STILL validates i18n on the companion-owned
|
|
24
|
+
* read path; this service only owns module diagnostics.
|
|
25
|
+
*/
|
|
26
|
+
import { type RegistryModulesLockEntry } from '@wildo-ai/platform-config-lib';
|
|
27
|
+
export type LockfileRepairFinding = {
|
|
28
|
+
severity: 'error';
|
|
29
|
+
kind: 'envelope-malformed';
|
|
30
|
+
message: string;
|
|
31
|
+
detail?: string;
|
|
32
|
+
} | {
|
|
33
|
+
severity: 'error';
|
|
34
|
+
kind: 'modules-section-malformed';
|
|
35
|
+
message: string;
|
|
36
|
+
detail?: string;
|
|
37
|
+
} | {
|
|
38
|
+
severity: 'warn';
|
|
39
|
+
kind: 'module-file-missing';
|
|
40
|
+
moduleId: string;
|
|
41
|
+
filePath: string;
|
|
42
|
+
} | {
|
|
43
|
+
severity: 'warn';
|
|
44
|
+
kind: 'module-digest-not-sha256';
|
|
45
|
+
moduleId: string;
|
|
46
|
+
observedDigest: string;
|
|
47
|
+
};
|
|
48
|
+
export interface LockfileRepairReport {
|
|
49
|
+
/** Absolute path the report covers. */
|
|
50
|
+
lockfilePath: string;
|
|
51
|
+
/** True when no errors were produced (warnings allowed). */
|
|
52
|
+
ok: boolean;
|
|
53
|
+
findings: readonly LockfileRepairFinding[];
|
|
54
|
+
}
|
|
55
|
+
export declare const LockfileRepairService: {
|
|
56
|
+
/** Compute the lockfile path for a saas root. */
|
|
57
|
+
readonly pathFor: (saasRoot: string) => string;
|
|
58
|
+
/**
|
|
59
|
+
* Read the envelope + run every diagnostic. Read-only.
|
|
60
|
+
*/
|
|
61
|
+
readonly inspect: (saasRoot: string) => Promise<LockfileRepairReport>;
|
|
62
|
+
/**
|
|
63
|
+
* Per-entry diagnostic helper. Exposed so Phase 7 mutating-
|
|
64
|
+
* repair flows can reuse the same predicates.
|
|
65
|
+
*/
|
|
66
|
+
readonly collectEntryFindings: (saasRoot: string, moduleId: string, entry: RegistryModulesLockEntry, findings: LockfileRepairFinding[]) => Promise<void>;
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=lockfile-repair.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile-repair.service.d.ts","sourceRoot":"","sources":["../../../../src/services/lockfile-repair.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH,OAAO,EAIL,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,GACD;IACE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,0BAA0B,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB,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;;;OAGG;8CAES,MAAM,YACN,MAAM,SACT,wBAAwB,YACrB,qBAAqB,EAAE,KAChC,OAAO,CAAC,IAAI,CAAC;CAqBR,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `LockfileRepairService` — Phase 2 read-only lockfile diagnostics.
|
|
3
|
+
*
|
|
4
|
+
* Backs `wildo registry repair-lockfile` (CLI command lands in a
|
|
5
|
+
* later step). The service does NOT mutate the lockfile by
|
|
6
|
+
* default — its job is to surface a structured diagnostic the
|
|
7
|
+
* operator can act on:
|
|
8
|
+
* - validate the canonical envelope shape;
|
|
9
|
+
* - validate `sections.modules` against
|
|
10
|
+
* `RegistryModulesLockSectionSchema`;
|
|
11
|
+
* - report which `installed[*].files` are missing on disk
|
|
12
|
+
* (drift between the lockfile and the source tree);
|
|
13
|
+
* - report which `installed[*].artifactDigest` strings are not
|
|
14
|
+
* `Sha256DigestSchema`-shaped (residue from pre-tightening
|
|
15
|
+
* publishes).
|
|
16
|
+
*
|
|
17
|
+
* Mutating repair is a Phase 7 deliverable — surfacing the gaps is
|
|
18
|
+
* what unblocks the operator now.
|
|
19
|
+
*
|
|
20
|
+
* `i18n` validation is intentionally NOT performed here (KD-15 +
|
|
21
|
+
* Review-pass-2 / MEDIUM-5): repair is the wrong place to
|
|
22
|
+
* second-guess companion-owned section semantics. The shared
|
|
23
|
+
* lockfile library STILL validates i18n on the companion-owned
|
|
24
|
+
* read path; this service only owns module diagnostics.
|
|
25
|
+
*/
|
|
26
|
+
import { promises as fs } from 'node:fs';
|
|
27
|
+
import * as path from 'node:path';
|
|
28
|
+
import { z } from 'zod';
|
|
29
|
+
import { formatZodIssuesAsSingleLine } from './_zod-issue-formatting.js';
|
|
30
|
+
import { RegistryModulesLockSectionSchema, Sha256DigestSchema, getWildoSaasLockPath, } from '@wildo-ai/platform-config-lib';
|
|
31
|
+
/**
|
|
32
|
+
* Permissive envelope schema used by repair only — it accepts any
|
|
33
|
+
* `sections.*` payload without delegating to per-section schemas
|
|
34
|
+
* so the repair flow can isolate "envelope is malformed" from
|
|
35
|
+
* "envelope is fine but modules section is malformed".
|
|
36
|
+
*/
|
|
37
|
+
const RelaxedEnvelopeSchema = z.strictObject({
|
|
38
|
+
schemaVersion: z.literal(2),
|
|
39
|
+
generatedAt: z.iso.datetime({ offset: true }),
|
|
40
|
+
sections: z.record(z.string(), z.unknown()),
|
|
41
|
+
});
|
|
42
|
+
async function fileExists(absPath) {
|
|
43
|
+
try {
|
|
44
|
+
await fs.access(absPath);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export const LockfileRepairService = {
|
|
52
|
+
/** Compute the lockfile path for a saas root. */
|
|
53
|
+
pathFor(saasRoot) {
|
|
54
|
+
return getWildoSaasLockPath(saasRoot);
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Read the envelope + run every diagnostic. Read-only.
|
|
58
|
+
*/
|
|
59
|
+
async inspect(saasRoot) {
|
|
60
|
+
const lockfilePath = getWildoSaasLockPath(saasRoot);
|
|
61
|
+
const findings = [];
|
|
62
|
+
// Read raw bytes ourselves so we can produce per-section
|
|
63
|
+
// diagnostics: a malformed `modules` section under an
|
|
64
|
+
// otherwise-valid envelope should report `modules-section-malformed`,
|
|
65
|
+
// NOT `envelope-malformed` (the latter would tell the operator
|
|
66
|
+
// to re-author the whole file when only one section is bad).
|
|
67
|
+
let raw;
|
|
68
|
+
try {
|
|
69
|
+
raw = await fs.readFile(lockfilePath, 'utf8');
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
const errno = err?.code;
|
|
73
|
+
if (errno === 'ENOENT') {
|
|
74
|
+
// Missing lockfile is "ok" from a repair POV.
|
|
75
|
+
return { lockfilePath, ok: true, findings: [] };
|
|
76
|
+
}
|
|
77
|
+
findings.push({
|
|
78
|
+
severity: 'error',
|
|
79
|
+
kind: 'envelope-malformed',
|
|
80
|
+
message: 'Failed to read lockfile bytes.',
|
|
81
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
82
|
+
});
|
|
83
|
+
return { lockfilePath, ok: false, findings };
|
|
84
|
+
}
|
|
85
|
+
let parsedJson;
|
|
86
|
+
try {
|
|
87
|
+
parsedJson = JSON.parse(raw);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
findings.push({
|
|
91
|
+
severity: 'error',
|
|
92
|
+
kind: 'envelope-malformed',
|
|
93
|
+
message: 'Lockfile is not valid JSON.',
|
|
94
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
95
|
+
});
|
|
96
|
+
return { lockfilePath, ok: false, findings };
|
|
97
|
+
}
|
|
98
|
+
const envelopeParsed = RelaxedEnvelopeSchema.safeParse(parsedJson);
|
|
99
|
+
if (!envelopeParsed.success) {
|
|
100
|
+
findings.push({
|
|
101
|
+
severity: 'error',
|
|
102
|
+
kind: 'envelope-malformed',
|
|
103
|
+
message: 'Top-level envelope failed to parse.',
|
|
104
|
+
detail: formatZodIssuesAsSingleLine(envelopeParsed.error),
|
|
105
|
+
});
|
|
106
|
+
return { lockfilePath, ok: false, findings };
|
|
107
|
+
}
|
|
108
|
+
const envelope = envelopeParsed.data;
|
|
109
|
+
const modulesPayload = envelope.sections.modules;
|
|
110
|
+
if (modulesPayload === undefined) {
|
|
111
|
+
// No modules section present — nothing to inspect.
|
|
112
|
+
return { lockfilePath, ok: true, findings };
|
|
113
|
+
}
|
|
114
|
+
const parsed = RegistryModulesLockSectionSchema.safeParse(modulesPayload);
|
|
115
|
+
if (!parsed.success) {
|
|
116
|
+
findings.push({
|
|
117
|
+
severity: 'error',
|
|
118
|
+
kind: 'modules-section-malformed',
|
|
119
|
+
message: '`sections.modules` failed schema validation.',
|
|
120
|
+
detail: formatZodIssuesAsSingleLine(parsed.error),
|
|
121
|
+
});
|
|
122
|
+
return { lockfilePath, ok: false, findings };
|
|
123
|
+
}
|
|
124
|
+
const modules = parsed.data;
|
|
125
|
+
for (const [moduleId, entry] of Object.entries(modules.installed)) {
|
|
126
|
+
await this.collectEntryFindings(saasRoot, moduleId, entry, findings);
|
|
127
|
+
}
|
|
128
|
+
const ok = findings.every((f) => f.severity !== 'error');
|
|
129
|
+
return { lockfilePath, ok, findings };
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* Per-entry diagnostic helper. Exposed so Phase 7 mutating-
|
|
133
|
+
* repair flows can reuse the same predicates.
|
|
134
|
+
*/
|
|
135
|
+
async collectEntryFindings(saasRoot, moduleId, entry, findings) {
|
|
136
|
+
if (!Sha256DigestSchema.safeParse(entry.artifactDigest).success) {
|
|
137
|
+
findings.push({
|
|
138
|
+
severity: 'warn',
|
|
139
|
+
kind: 'module-digest-not-sha256',
|
|
140
|
+
moduleId,
|
|
141
|
+
observedDigest: entry.artifactDigest,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
for (const filePath of entry.files) {
|
|
145
|
+
const abs = path.resolve(saasRoot, filePath);
|
|
146
|
+
if (!(await fileExists(abs))) {
|
|
147
|
+
findings.push({
|
|
148
|
+
severity: 'warn',
|
|
149
|
+
kind: 'module-file-missing',
|
|
150
|
+
moduleId,
|
|
151
|
+
filePath,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
// L6 (third-pass review): re-export removed — barrel-discipline rule
|
|
158
|
+
// says "Never re-export except in the root `index.ts`." Consumers
|
|
159
|
+
// import the symbol directly from `@wildo-ai/platform-config-lib`.
|
|
160
|
+
//# sourceMappingURL=lockfile-repair.service.js.map
|