@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.
Files changed (98) hide show
  1. package/LICENSE +34 -0
  2. package/dist/esm/.builder.pid +9 -0
  3. package/dist/esm/__tests__/lockfile-repair.service.test.d.ts +0 -0
  4. package/dist/esm/__tests__/lockfile-repair.service.test.d.ts.map +0 -0
  5. package/dist/esm/__tests__/lockfile-repair.service.test.js.map +0 -0
  6. package/dist/esm/__tests__/module-adopter.service.test.d.ts +0 -0
  7. package/dist/esm/__tests__/module-adopter.service.test.d.ts.map +0 -0
  8. package/dist/esm/__tests__/module-adopter.service.test.js.map +0 -0
  9. package/dist/esm/__tests__/module-packager.service.test.d.ts +0 -0
  10. package/dist/esm/__tests__/module-packager.service.test.d.ts.map +0 -0
  11. package/dist/esm/__tests__/module-packager.service.test.js.map +0 -0
  12. package/dist/esm/__tests__/provider-materialization-hook.test.d.ts +0 -0
  13. package/dist/esm/__tests__/provider-materialization-hook.test.d.ts.map +0 -0
  14. package/dist/esm/__tests__/provider-materialization-hook.test.js.map +0 -0
  15. package/dist/esm/__tests__/provider-sync-runner.test.d.ts +0 -0
  16. package/dist/esm/__tests__/provider-sync-runner.test.d.ts.map +0 -0
  17. package/dist/esm/__tests__/provider-sync-runner.test.js.map +0 -0
  18. package/dist/esm/__tests__/registry-lockfile.service.test.d.ts +0 -0
  19. package/dist/esm/__tests__/registry-lockfile.service.test.d.ts.map +0 -0
  20. package/dist/esm/__tests__/registry-lockfile.service.test.js.map +0 -0
  21. package/dist/esm/__tests__/registry-server-client.test.d.ts +0 -0
  22. package/dist/esm/__tests__/registry-server-client.test.d.ts.map +0 -0
  23. package/dist/esm/__tests__/registry-server-client.test.js.map +0 -0
  24. package/dist/esm/index.d.ts +18 -0
  25. package/dist/esm/index.d.ts.map +1 -0
  26. package/dist/esm/index.js +18 -0
  27. package/dist/esm/index.js.map +1 -0
  28. package/dist/esm/services/_http-client.d.ts +44 -0
  29. package/dist/esm/services/_http-client.d.ts.map +1 -0
  30. package/dist/esm/services/_http-client.js +75 -0
  31. package/dist/esm/services/_http-client.js.map +1 -0
  32. package/dist/esm/services/_zod-issue-formatting.d.ts +12 -0
  33. package/dist/esm/services/_zod-issue-formatting.d.ts.map +1 -0
  34. package/dist/esm/services/_zod-issue-formatting.js +47 -0
  35. package/dist/esm/services/_zod-issue-formatting.js.map +1 -0
  36. package/dist/esm/services/index.d.ts +10 -0
  37. package/dist/esm/services/index.d.ts.map +1 -0
  38. package/dist/esm/services/index.js +10 -0
  39. package/dist/esm/services/index.js.map +1 -0
  40. package/dist/esm/services/lockfile-repair.service.d.ts +68 -0
  41. package/dist/esm/services/lockfile-repair.service.d.ts.map +1 -0
  42. package/dist/esm/services/lockfile-repair.service.js +160 -0
  43. package/dist/esm/services/lockfile-repair.service.js.map +1 -0
  44. package/dist/esm/services/module-adopter.service.d.ts +59 -0
  45. package/dist/esm/services/module-adopter.service.d.ts.map +1 -0
  46. package/dist/esm/services/module-adopter.service.js +126 -0
  47. package/dist/esm/services/module-adopter.service.js.map +1 -0
  48. package/dist/esm/services/module-packager.service.d.ts +105 -0
  49. package/dist/esm/services/module-packager.service.d.ts.map +1 -0
  50. package/dist/esm/services/module-packager.service.js +212 -0
  51. package/dist/esm/services/module-packager.service.js.map +1 -0
  52. package/dist/esm/services/provider-materialization-hook.d.ts +32 -0
  53. package/dist/esm/services/provider-materialization-hook.d.ts.map +1 -0
  54. package/dist/esm/services/provider-materialization-hook.js +33 -0
  55. package/dist/esm/services/provider-materialization-hook.js.map +1 -0
  56. package/dist/esm/services/provider-sync-runner.d.ts +87 -0
  57. package/dist/esm/services/provider-sync-runner.d.ts.map +1 -0
  58. package/dist/esm/services/provider-sync-runner.js +207 -0
  59. package/dist/esm/services/provider-sync-runner.js.map +1 -0
  60. package/dist/esm/services/registry-companion-client.d.ts +39 -0
  61. package/dist/esm/services/registry-companion-client.d.ts.map +1 -0
  62. package/dist/esm/services/registry-companion-client.js +109 -0
  63. package/dist/esm/services/registry-companion-client.js.map +1 -0
  64. package/dist/esm/services/registry-lockfile.service.d.ts +56 -0
  65. package/dist/esm/services/registry-lockfile.service.d.ts.map +1 -0
  66. package/dist/esm/services/registry-lockfile.service.js +99 -0
  67. package/dist/esm/services/registry-lockfile.service.js.map +1 -0
  68. package/dist/esm/services/registry-server-client.d.ts +94 -0
  69. package/dist/esm/services/registry-server-client.d.ts.map +1 -0
  70. package/dist/esm/services/registry-server-client.js +225 -0
  71. package/dist/esm/services/registry-server-client.js.map +1 -0
  72. package/dist/esm/services/types.d.ts +22 -0
  73. package/dist/esm/services/types.d.ts.map +1 -0
  74. package/dist/esm/services/types.js +16 -0
  75. package/dist/esm/services/types.js.map +1 -0
  76. package/dist/tsconfig.build.tsbuildinfo +1 -0
  77. package/dist/tsconfig.tsbuildinfo +1 -0
  78. package/package.json +51 -0
  79. package/src/__tests__/lockfile-repair.service.test.ts +106 -0
  80. package/src/__tests__/module-adopter.service.test.ts +96 -0
  81. package/src/__tests__/module-packager.service.test.ts +258 -0
  82. package/src/__tests__/provider-materialization-hook.test.ts +47 -0
  83. package/src/__tests__/provider-sync-runner.test.ts +113 -0
  84. package/src/__tests__/registry-lockfile.service.test.ts +134 -0
  85. package/src/__tests__/registry-server-client.test.ts +312 -0
  86. package/src/index.ts +18 -0
  87. package/src/services/_http-client.ts +91 -0
  88. package/src/services/_zod-issue-formatting.ts +50 -0
  89. package/src/services/index.ts +9 -0
  90. package/src/services/lockfile-repair.service.ts +215 -0
  91. package/src/services/module-adopter.service.ts +155 -0
  92. package/src/services/module-packager.service.ts +251 -0
  93. package/src/services/provider-materialization-hook.ts +54 -0
  94. package/src/services/provider-sync-runner.ts +298 -0
  95. package/src/services/registry-companion-client.ts +163 -0
  96. package/src/services/registry-lockfile.service.ts +122 -0
  97. package/src/services/registry-server-client.ts +334 -0
  98. package/src/services/types.ts +22 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * `RegistryLockfileService` — section-scoped reader/writer for the
3
+ * `sections.modules` slice of `wildo-saas.lock.json` (KD-4).
4
+ *
5
+ * Phase 1 graduates the locking + atomic-write primitives into
6
+ * `@wildo-ai/platform-config-lib` (validated by the Phase 0.B
7
+ * contention spike). This service is a thin wrapper around
8
+ * `withLockfileSectionMutate` that pre-binds the `modules` section
9
+ * key + schema, so module-registry callers cannot accidentally
10
+ * touch sibling sections.
11
+ *
12
+ * Hard contracts (KD-4 / KD-15 / KD-18):
13
+ * - Mutates ONLY `sections.modules`. The shared library preserves
14
+ * `sections.providers`, `sections.i18n`, and every unknown
15
+ * `sections.*` payload verbatim — no defensive logic needed
16
+ * here.
17
+ * - Never writes `.wildo-saas/generated/providers/*.runtime-providers.generated.json`
18
+ * or `src/generated/wildo-provider-runtime.generated.ts` —
19
+ * those are produced by the provider materialization workflow.
20
+ * - Never mutates `sections.providers.runtimeScopes`.
21
+ */
22
+ import { RegistryModulesLockSectionSchema, withLockfileSectionMutate, readWildoSaasLock, } from '@wildo-ai/platform-config-lib';
23
+ // L6 (third-pass review): the package's barrel-discipline rule says
24
+ // "Never re-export (except in the root `index.ts` of each package)."
25
+ // The previous `export { WILDO_SAAS_LOCK_RELATIVE_PATH }` here AND in
26
+ // `lockfile-repair.service.ts` surfaced the symbol twice from
27
+ // `wildo-module-client`'s root. Consumers that need it can import
28
+ // directly from `@wildo-ai/platform-config-lib`, OR rely on the root
29
+ // `index.ts` to re-export it once.
30
+ const SECTION_KEY = 'modules';
31
+ function emptySection() {
32
+ return RegistryModulesLockSectionSchema.parse({});
33
+ }
34
+ export const RegistryLockfileService = {
35
+ /**
36
+ * Read the current `sections.modules` payload (or an empty section
37
+ * when missing). Unsynchronized — callers needing read-after-write
38
+ * coherence should read INSIDE `mutate`.
39
+ */
40
+ async read(saasRoot) {
41
+ const envelope = await readWildoSaasLock({ saasRoot });
42
+ const raw = envelope.sections.modules;
43
+ if (raw === undefined)
44
+ return emptySection();
45
+ return RegistryModulesLockSectionSchema.parse(raw);
46
+ },
47
+ /**
48
+ * Run `mutator` against the current `sections.modules` payload
49
+ * under an OS-level lock + atomic-write commit. The mutator can
50
+ * either mutate-in-place or return a new value; either way the
51
+ * result is re-validated against `RegistryModulesLockSectionSchema`
52
+ * before commit.
53
+ */
54
+ async mutate(saasRoot, mutator) {
55
+ return withLockfileSectionMutate({
56
+ saasRoot,
57
+ sectionKey: SECTION_KEY,
58
+ sectionSchema: RegistryModulesLockSectionSchema,
59
+ initialSection: emptySection,
60
+ }, mutator);
61
+ },
62
+ /** Convenience helper used by Phase 5+ install flow. */
63
+ async upsertEntry(saasRoot, entry) {
64
+ await this.mutate(saasRoot, (current) => ({
65
+ ...current,
66
+ installed: { ...current.installed, [entry.moduleId]: entry },
67
+ }));
68
+ },
69
+ /**
70
+ * Find every other lockfile entry whose `files[]` claims any of the
71
+ * given paths. Used by `update`/`remove` to skip deletes that would
72
+ * silently pull files out from under modules that own them too
73
+ * (cross-module file overlap).
74
+ *
75
+ * Returns a `Map<relPath, owners[]>` where `owners` excludes
76
+ * `excludeModuleId`. Empty array → uniquely owned by the excluded
77
+ * module, safe to delete.
78
+ */
79
+ async findFileOwners(args) {
80
+ const section = await this.read(args.saasRoot);
81
+ const claimedBy = new Map();
82
+ for (const p of args.paths)
83
+ claimedBy.set(p, []);
84
+ for (const otherModuleId of Object.keys(section.installed)) {
85
+ if (otherModuleId === args.excludeModuleId)
86
+ continue;
87
+ const otherEntry = section.installed[otherModuleId];
88
+ if (!otherEntry)
89
+ continue;
90
+ for (const otherFile of otherEntry.files) {
91
+ if (claimedBy.has(otherFile)) {
92
+ claimedBy.get(otherFile).push(otherModuleId);
93
+ }
94
+ }
95
+ }
96
+ return claimedBy;
97
+ },
98
+ };
99
+ //# sourceMappingURL=registry-lockfile.service.js.map
@@ -0,0 +1 @@
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,GAGlB,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,wDAAwD;IACxD,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,KAA+B;QACjE,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 type RegistryModulesLockEntry,\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 /** Convenience helper used by Phase 5+ install flow. */\n async upsertEntry(saasRoot: string, entry: RegistryModulesLockEntry): Promise<void> {\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"]}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * `RegistryServerClient` — HTTP client for the central registry
3
+ * server (`platform-module-registry`, KD-7).
4
+ *
5
+ * Phase 2 fills out the read + download surface (`resolve`,
6
+ * `info`, `search`, `download`). The wire shapes mirror the
7
+ * gateway endpoints documented in the analysis plan's "Registry
8
+ * HTTP API" section. The actual server (Phase 3) ships these
9
+ * routes; until it does, the client throws typed errors when it
10
+ * can't reach the server.
11
+ *
12
+ * Auth (KD-11): if `authToken` is supplied, every request adds
13
+ * `Authorization: Bearer <token>`. Public read paths work without
14
+ * a token; restricted paths return 401/403, surfaced as
15
+ * `RegistryAuthRequiredError` / `RegistryAuthForbiddenError`.
16
+ */
17
+ import { type ModuleManifest, type ModuleVersionRecord } from '@wildo-ai/platform-config-lib';
18
+ export interface RegistryServerClientOptions {
19
+ /** Registry origin (e.g. `https://registry.wildo.ai`). */
20
+ baseUrl: string;
21
+ /** Optional bearer / API-key. CLI credentials are per-machine (KD-11). */
22
+ authToken?: string;
23
+ /** Request timeout in ms. */
24
+ timeoutMs?: number;
25
+ }
26
+ export interface RegistryResolveResult {
27
+ /** Resolved exact version (matches `Sha256DigestSchema` for digest). */
28
+ version: string;
29
+ artifactDigest: string;
30
+ }
31
+ export interface RegistryInfoResult {
32
+ moduleId: string;
33
+ manifest: ModuleManifest;
34
+ versions: readonly ModuleVersionRecord[];
35
+ /** dist-tag → version map (e.g. `latest → 1.2.3`). */
36
+ tags: Readonly<Record<string, string>>;
37
+ }
38
+ export interface RegistrySearchHit {
39
+ moduleId: string;
40
+ description?: string;
41
+ latestVersion: string;
42
+ }
43
+ export declare const RegistryServerClient: {
44
+ /**
45
+ * Liveness probe against `/health`. Returns boolean — used by
46
+ * `wildo registry ping` smoke. The registry server now relies on
47
+ * the framework's auto-mounted `HealthController` at the engine
48
+ * root (`GET /health` always 200; `GET /health/ready` enforces
49
+ * dependency readiness), so the path has NO `/v1` prefix.
50
+ */
51
+ readonly ping: (options: RegistryServerClientOptions) => Promise<boolean>;
52
+ /**
53
+ * Resolve a semver range / tag against a registry domain. The
54
+ * server returns the concrete version + artifact digest so the
55
+ * caller can verify the download against `artifactDigest`.
56
+ */
57
+ readonly resolve: (options: RegistryServerClientOptions, args: {
58
+ domain: string;
59
+ moduleId: string;
60
+ range: string;
61
+ }) => Promise<RegistryResolveResult>;
62
+ /**
63
+ * Fetch full info for a module: manifest, every published
64
+ * version, dist-tags. Used by `wildo registry info` (Phase 4).
65
+ */
66
+ readonly info: (options: RegistryServerClientOptions, args: {
67
+ domain: string;
68
+ moduleId: string;
69
+ }) => Promise<RegistryInfoResult>;
70
+ /**
71
+ * Search the registry's metadata index. The shape is
72
+ * intentionally narrow until Phase 4 designs the search UX.
73
+ */
74
+ readonly search: (options: RegistryServerClientOptions, args: {
75
+ domain: string;
76
+ query: string;
77
+ }) => Promise<readonly RegistrySearchHit[]>;
78
+ /**
79
+ * Stream-download a published artifact's bytes and verify the
80
+ * sha256 integrity matches `expectedDigest`. Throws
81
+ * `RegistryArtifactIntegrityMismatchError` on mismatch — the
82
+ * digest check is non-negotiable per KD-9 / Security model.
83
+ */
84
+ readonly download: (options: RegistryServerClientOptions, args: {
85
+ domain: string;
86
+ moduleId: string;
87
+ version: string;
88
+ expectedDigest: string;
89
+ }) => Promise<{
90
+ bytes: Uint8Array;
91
+ integrity: string;
92
+ }>;
93
+ };
94
+ //# sourceMappingURL=registry-server-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-server-client.d.ts","sourceRoot":"","sources":["../../../../src/services/registry-server-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAYL,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACzB,MAAM,+BAA+B,CAAC;AA4BvC,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;AAoCD,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;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,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,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;IAgDjC;;;OAGG;6BAEQ,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KACzC,OAAO,CAAC,kBAAkB,CAAC;IA8B9B;;;OAGG;+BAEQ,2BAA2B,QAC9B;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KACtC,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC;IA6BxC;;;;;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,CAAA;KAAE,CAAC;CA6C5C,CAAC"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * `RegistryServerClient` — HTTP client for the central registry
3
+ * server (`platform-module-registry`, KD-7).
4
+ *
5
+ * Phase 2 fills out the read + download surface (`resolve`,
6
+ * `info`, `search`, `download`). The wire shapes mirror the
7
+ * gateway endpoints documented in the analysis plan's "Registry
8
+ * HTTP API" section. The actual server (Phase 3) ships these
9
+ * routes; until it does, the client throws typed errors when it
10
+ * can't reach the server.
11
+ *
12
+ * Auth (KD-11): if `authToken` is supplied, every request adds
13
+ * `Authorization: Bearer <token>`. Public read paths work without
14
+ * a token; restricted paths return 401/403, surfaced as
15
+ * `RegistryAuthRequiredError` / `RegistryAuthForbiddenError`.
16
+ */
17
+ import { z } from 'zod';
18
+ import { formatZodIssuesAsSingleLine } from './_zod-issue-formatting.js';
19
+ import { ModuleManifestSchema, ModuleVersionRecordSchema, RegistryArtifactIntegrityMismatchError, RegistryAuthForbiddenError, RegistryAuthRequiredError, RegistryMalformedPayloadError, RegistryModuleNotFoundError, RegistryUnexpectedStatusError, RegistryVersionNotFoundError, Sha256DigestSchema, } from '@wildo-ai/platform-config-lib';
20
+ import { fetchJsonOk, fetchWithTimeout, joinUrl } from './_http-client.js';
21
+ /**
22
+ * Zod schema for the `info()` response payload — mirrors
23
+ * `RegistryInfoResult` and is enforced at the client boundary so a
24
+ * server schema drift fails fast instead of returning malformed data
25
+ * to downstream consumers.
26
+ */
27
+ const RegistryInfoResponseSchema = z.object({
28
+ moduleId: z.string().min(1),
29
+ manifest: ModuleManifestSchema,
30
+ versions: z.array(ModuleVersionRecordSchema),
31
+ tags: z.record(z.string(), z.string()),
32
+ });
33
+ const RegistrySearchResponseSchema = z.object({
34
+ hits: z.array(z.object({
35
+ moduleId: z.string().min(1),
36
+ description: z.string().optional(),
37
+ latestVersion: z.string(),
38
+ })),
39
+ });
40
+ const DIAGNOSTIC_LABEL = 'Registry';
41
+ function authHeaders(options) {
42
+ return options.authToken ? { Authorization: `Bearer ${options.authToken}` } : {};
43
+ }
44
+ async function classifyAuthError(res, registryUrl, action) {
45
+ if (res.status === 401)
46
+ return new RegistryAuthRequiredError(registryUrl);
47
+ if (res.status === 403)
48
+ return new RegistryAuthForbiddenError(action);
49
+ return null;
50
+ }
51
+ /**
52
+ * 6th-pass M3: typed JSON-parse helper. A misconfigured proxy that
53
+ * returns HTML at 2xx (or a truncated stream) would otherwise throw a
54
+ * bare `SyntaxError` from `await res.json()`, bypassing every
55
+ * `isRegistryError(err)` handler. This helper translates the parse
56
+ * failure into a `RegistryMalformedPayloadError` so the typed-error
57
+ * contract is universal across the client surface.
58
+ */
59
+ async function parseJsonOrThrow(res, registryUrl, action) {
60
+ try {
61
+ return await res.json();
62
+ }
63
+ catch (err) {
64
+ throw new RegistryMalformedPayloadError(registryUrl, action, `response is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
65
+ }
66
+ }
67
+ export const RegistryServerClient = {
68
+ /**
69
+ * Liveness probe against `/health`. Returns boolean — used by
70
+ * `wildo registry ping` smoke. The registry server now relies on
71
+ * the framework's auto-mounted `HealthController` at the engine
72
+ * root (`GET /health` always 200; `GET /health/ready` enforces
73
+ * dependency readiness), so the path has NO `/v1` prefix.
74
+ */
75
+ async ping(options) {
76
+ try {
77
+ await fetchJsonOk(joinUrl(options.baseUrl, '/health'), {
78
+ method: 'GET',
79
+ timeoutMs: options.timeoutMs,
80
+ diagnosticLabel: DIAGNOSTIC_LABEL,
81
+ });
82
+ return true;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ },
88
+ /**
89
+ * Resolve a semver range / tag against a registry domain. The
90
+ * server returns the concrete version + artifact digest so the
91
+ * caller can verify the download against `artifactDigest`.
92
+ */
93
+ async resolve(options, args) {
94
+ const url = joinUrl(options.baseUrl, `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/resolve?range=${encodeURIComponent(args.range)}`);
95
+ const res = await fetchWithTimeout(url, {
96
+ method: 'GET',
97
+ headers: authHeaders(options),
98
+ timeoutMs: options.timeoutMs,
99
+ diagnosticLabel: DIAGNOSTIC_LABEL,
100
+ });
101
+ if (res.status === 404) {
102
+ throw new RegistryVersionNotFoundError(args.moduleId, args.range);
103
+ }
104
+ const authErr = await classifyAuthError(res, options.baseUrl, `resolve ${args.moduleId}`);
105
+ if (authErr)
106
+ throw authErr;
107
+ if (!res.ok) {
108
+ throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, `resolve ${args.moduleId}`);
109
+ }
110
+ // 6th-pass M3: typed JSON-parse (was bare `SyntaxError` for
111
+ // malformed proxy responses).
112
+ const json = (await parseJsonOrThrow(res, options.baseUrl, `resolve ${args.moduleId}`));
113
+ const digest = String(json.artifactDigest ?? '');
114
+ // 6th-pass M4: typed digest validation (was bare `ZodError`).
115
+ const digestParse = Sha256DigestSchema.safeParse(digest);
116
+ if (!digestParse.success) {
117
+ throw new RegistryMalformedPayloadError(options.baseUrl, `resolve ${args.moduleId}`, `artifactDigest is not a valid sha256:<64-hex> string: ${formatZodIssuesAsSingleLine(digestParse.error)}`);
118
+ }
119
+ if (typeof json.version !== 'string' || json.version.length === 0) {
120
+ // 3rd-pass M6: typed `RegistryMalformedPayloadError` instead of
121
+ // bare `Error` so callers' `isRegistryError(err)` handlers fire
122
+ // correctly.
123
+ throw new RegistryMalformedPayloadError(options.baseUrl, `resolve ${args.moduleId}`, 'response missing required `version` string');
124
+ }
125
+ return { version: json.version, artifactDigest: digest };
126
+ },
127
+ /**
128
+ * Fetch full info for a module: manifest, every published
129
+ * version, dist-tags. Used by `wildo registry info` (Phase 4).
130
+ */
131
+ async info(options, args) {
132
+ const url = joinUrl(options.baseUrl, `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}`);
133
+ const res = await fetchWithTimeout(url, {
134
+ method: 'GET',
135
+ headers: authHeaders(options),
136
+ timeoutMs: options.timeoutMs,
137
+ diagnosticLabel: DIAGNOSTIC_LABEL,
138
+ });
139
+ if (res.status === 404)
140
+ throw new RegistryModuleNotFoundError(args.moduleId);
141
+ const authErr = await classifyAuthError(res, options.baseUrl, `info ${args.moduleId}`);
142
+ if (authErr)
143
+ throw authErr;
144
+ if (!res.ok) {
145
+ throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, `info ${args.moduleId}`);
146
+ }
147
+ // 6th-pass M3: typed JSON-parse.
148
+ const json = await parseJsonOrThrow(res, options.baseUrl, `info ${args.moduleId}`);
149
+ const parsed = RegistryInfoResponseSchema.safeParse(json);
150
+ if (!parsed.success) {
151
+ throw new RegistryMalformedPayloadError(options.baseUrl, `info ${args.moduleId}`, formatZodIssuesAsSingleLine(parsed.error));
152
+ }
153
+ return parsed.data;
154
+ },
155
+ /**
156
+ * Search the registry's metadata index. The shape is
157
+ * intentionally narrow until Phase 4 designs the search UX.
158
+ */
159
+ async search(options, args) {
160
+ const url = joinUrl(options.baseUrl, `/v1/registry/${encodeURIComponent(args.domain)}/modules?q=${encodeURIComponent(args.query)}`);
161
+ const res = await fetchWithTimeout(url, {
162
+ method: 'GET',
163
+ headers: authHeaders(options),
164
+ timeoutMs: options.timeoutMs,
165
+ diagnosticLabel: DIAGNOSTIC_LABEL,
166
+ });
167
+ const authErr = await classifyAuthError(res, options.baseUrl, `search`);
168
+ if (authErr)
169
+ throw authErr;
170
+ if (!res.ok) {
171
+ throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, 'search');
172
+ }
173
+ // 6th-pass M3: typed JSON-parse.
174
+ const json = await parseJsonOrThrow(res, options.baseUrl, 'search');
175
+ const parsed = RegistrySearchResponseSchema.safeParse(json);
176
+ if (!parsed.success) {
177
+ throw new RegistryMalformedPayloadError(options.baseUrl, 'search', formatZodIssuesAsSingleLine(parsed.error));
178
+ }
179
+ return parsed.data.hits;
180
+ },
181
+ /**
182
+ * Stream-download a published artifact's bytes and verify the
183
+ * sha256 integrity matches `expectedDigest`. Throws
184
+ * `RegistryArtifactIntegrityMismatchError` on mismatch — the
185
+ * digest check is non-negotiable per KD-9 / Security model.
186
+ */
187
+ async download(options, args) {
188
+ // 7th-pass C-M1: caller-supplied digest is a developer-contract
189
+ // violation if malformed, not a registry-runtime condition.
190
+ // Throw `TypeError` (matching `C-L3` precedent for
191
+ // `getModuleStagingPaths` argument-shape violations) so the
192
+ // typed `RegistryError` vocabulary stays reserved for
193
+ // registry-runtime errors. Prior `Sha256DigestSchema.parse(...)`
194
+ // leaked a bare `ZodError` that bypassed
195
+ // `isRegistryError(err)` handlers but ALSO confused
196
+ // typed-handler maintainers about the contract.
197
+ const digestParse = Sha256DigestSchema.safeParse(args.expectedDigest);
198
+ if (!digestParse.success) {
199
+ throw new TypeError(`download() expectedDigest must be a valid sha256:<64-hex> string (got: ${JSON.stringify(args.expectedDigest)}). ${formatZodIssuesAsSingleLine(digestParse.error)}`);
200
+ }
201
+ const url = joinUrl(options.baseUrl, `/v1/registry/${encodeURIComponent(args.domain)}/modules/${encodeURIComponent(args.moduleId)}/${encodeURIComponent(args.version)}/artifact`);
202
+ const res = await fetchWithTimeout(url, {
203
+ method: 'GET',
204
+ headers: authHeaders(options),
205
+ timeoutMs: options.timeoutMs,
206
+ diagnosticLabel: DIAGNOSTIC_LABEL,
207
+ });
208
+ if (res.status === 404)
209
+ throw new RegistryVersionNotFoundError(args.moduleId, args.version);
210
+ const authErr = await classifyAuthError(res, options.baseUrl, `download ${args.moduleId}@${args.version}`);
211
+ if (authErr)
212
+ throw authErr;
213
+ if (!res.ok) {
214
+ throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, `download ${args.moduleId}@${args.version}`);
215
+ }
216
+ const buf = new Uint8Array(await res.arrayBuffer());
217
+ const { createHash } = await import('node:crypto');
218
+ const observed = `sha256:${createHash('sha256').update(buf).digest('hex')}`;
219
+ if (observed !== args.expectedDigest) {
220
+ throw new RegistryArtifactIntegrityMismatchError(args.moduleId, args.version, args.expectedDigest, observed);
221
+ }
222
+ return { bytes: buf, integrity: observed };
223
+ },
224
+ };
225
+ //# sourceMappingURL=registry-server-client.js.map
@@ -0,0 +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` / `RegistryAuthForbiddenError`.\n */\n\nimport { z } from 'zod';\nimport { formatZodIssuesAsSingleLine } from './_zod-issue-formatting';\nimport {\n ModuleManifestSchema,\n ModuleVersionRecordSchema,\n RegistryArtifactIntegrityMismatchError,\n RegistryAuthForbiddenError,\n RegistryAuthRequiredError,\n RegistryError,\n RegistryMalformedPayloadError,\n RegistryModuleNotFoundError,\n RegistryUnexpectedStatusError,\n RegistryVersionNotFoundError,\n Sha256DigestSchema,\n type ModuleManifest,\n type ModuleVersionRecord,\n} from '@wildo-ai/platform-config-lib';\nimport { fetchJsonOk, fetchWithTimeout, joinUrl } 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(\n z.object({\n moduleId: z.string().min(1),\n description: z.string().optional(),\n latestVersion: z.string(),\n }),\n ),\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\nasync function classifyAuthError(res: Response, registryUrl: string, action: string): Promise<RegistryError | null> {\n if (res.status === 401) return new RegistryAuthRequiredError(registryUrl);\n if (res.status === 403) return new RegistryAuthForbiddenError(action);\n return null;\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): Promise<unknown> {\n try {\n return await res.json();\n } catch (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\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\nexport interface RegistrySearchHit {\n moduleId: string;\n description?: string;\n latestVersion: string;\n}\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 if (res.status === 404) {\n throw new RegistryVersionNotFoundError(args.moduleId, args.range);\n }\n const authErr = await classifyAuthError(res, options.baseUrl, `resolve ${args.moduleId}`);\n if (authErr) throw authErr;\n if (!res.ok) {\n throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, `resolve ${args.moduleId}`);\n }\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}`)) as {\n version?: unknown;\n artifactDigest?: 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 return { version: json.version, artifactDigest: digest };\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 if (res.status === 404) throw new RegistryModuleNotFoundError(args.moduleId);\n const authErr = await classifyAuthError(res, options.baseUrl, `info ${args.moduleId}`);\n if (authErr) throw authErr;\n if (!res.ok) {\n throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, `info ${args.moduleId}`);\n }\n // 6th-pass M3: typed JSON-parse.\n const json = await parseJsonOrThrow(res, options.baseUrl, `info ${args.moduleId}`);\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. The shape is\n * intentionally narrow until Phase 4 designs the search UX.\n */\n async search(\n options: RegistryServerClientOptions,\n args: { domain: string; query: string },\n ): Promise<readonly RegistrySearchHit[]> {\n const url = joinUrl(\n options.baseUrl,\n `/v1/registry/${encodeURIComponent(args.domain)}/modules?q=${encodeURIComponent(args.query)}`,\n );\n const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n const authErr = await classifyAuthError(res, options.baseUrl, `search`);\n if (authErr) throw authErr;\n if (!res.ok) {\n throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, 'search');\n }\n // 6th-pass M3: typed JSON-parse.\n const json = await parseJsonOrThrow(res, options.baseUrl, 'search');\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 return parsed.data.hits;\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 }> {\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 const res = await fetchWithTimeout(url, {\n method: 'GET',\n headers: authHeaders(options),\n timeoutMs: options.timeoutMs,\n diagnosticLabel: DIAGNOSTIC_LABEL,\n });\n if (res.status === 404) throw new RegistryVersionNotFoundError(args.moduleId, args.version);\n const authErr = await classifyAuthError(res, options.baseUrl, `download ${args.moduleId}@${args.version}`);\n if (authErr) throw authErr;\n if (!res.ok) {\n throw new RegistryUnexpectedStatusError(options.baseUrl, res.status, res.statusText, `download ${args.moduleId}@${args.version}`);\n }\n const buf = new Uint8Array(await res.arrayBuffer());\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 return { bytes: buf, integrity: observed };\n },\n} as const;\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared structural types consumed across `wildo-module-client`
3
+ * services.
4
+ *
5
+ * The package intentionally avoids importing the CLI's full
6
+ * `CommandContext` (defined in `wildo-cli/src/kernel/types.ts`)
7
+ * to keep the dependency arrow CLI → wildo-module-client (KD-3
8
+ * forbids a reverse edge). Phase 2 services accept a structural
9
+ * subset of whatever the host (CLI / companion) needs to pass
10
+ * down — typically just `saasRoot` + a logger sink.
11
+ *
12
+ * The single shared type today is `RegistryClientLogger`. Adding
13
+ * more shared structural types here is fine; importing
14
+ * `wildo-cli` types is not.
15
+ */
16
+ export interface RegistryClientLogger {
17
+ info: (msg: string) => void;
18
+ success?: (msg: string) => void;
19
+ warn: (msg: string) => void;
20
+ error: (msg: string) => void;
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/services/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shared structural types consumed across `wildo-module-client`
3
+ * services.
4
+ *
5
+ * The package intentionally avoids importing the CLI's full
6
+ * `CommandContext` (defined in `wildo-cli/src/kernel/types.ts`)
7
+ * to keep the dependency arrow CLI → wildo-module-client (KD-3
8
+ * forbids a reverse edge). Phase 2 services accept a structural
9
+ * subset of whatever the host (CLI / companion) needs to pass
10
+ * down — typically just `saasRoot` + a logger sink.
11
+ *
12
+ * The single shared type today is `RegistryClientLogger`. Adding
13
+ * more shared structural types here is fine; importing
14
+ * `wildo-cli` types is not.
15
+ */
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/services/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG","sourcesContent":["/**\n * Shared structural types consumed across `wildo-module-client`\n * services.\n *\n * The package intentionally avoids importing the CLI's full\n * `CommandContext` (defined in `wildo-cli/src/kernel/types.ts`)\n * to keep the dependency arrow CLI → wildo-module-client (KD-3\n * forbids a reverse edge). Phase 2 services accept a structural\n * subset of whatever the host (CLI / companion) needs to pass\n * down — typically just `saasRoot` + a logger sink.\n *\n * The single shared type today is `RegistryClientLogger`. Adding\n * more shared structural types here is fine; importing\n * `wildo-cli` types is not.\n */\n\nexport interface RegistryClientLogger {\n info: (msg: string) => void;\n success?: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n}\n"]}