@specverse/engines 6.33.1 → 6.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/libs/instance-factories/communication/rabbitmq-events.yaml +11 -0
- package/dist/libs/instance-factories/controllers/fastify.yaml +11 -0
- package/dist/libs/instance-factories/managed/stripe-rest-sdk.yaml +78 -0
- package/dist/libs/instance-factories/managed/templates/stripe/stripe-client-generator.js +8 -0
- package/dist/libs/instance-factories/orms/prisma.yaml +11 -0
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +246 -1
- package/dist/realize/index.js.map +1 -1
- package/dist/realize/library/loader.d.ts.map +1 -1
- package/dist/realize/library/loader.js +81 -1
- package/dist/realize/library/loader.js.map +1 -1
- package/dist/realize/per-action-emitter.d.ts +9 -0
- package/dist/realize/per-action-emitter.d.ts.map +1 -1
- package/dist/realize/per-action-emitter.js.map +1 -1
- package/dist/realize/per-action-llm-emit.d.ts.map +1 -1
- package/dist/realize/per-action-llm-emit.js +5 -1
- package/dist/realize/per-action-llm-emit.js.map +1 -1
- package/dist/realize/per-action-runner.d.ts +45 -0
- package/dist/realize/per-action-runner.d.ts.map +1 -1
- package/dist/realize/per-action-runner.js +132 -0
- package/dist/realize/per-action-runner.js.map +1 -1
- package/dist/realize/resolver/index.d.ts +157 -0
- package/dist/realize/resolver/index.d.ts.map +1 -0
- package/dist/realize/resolver/index.js +307 -0
- package/dist/realize/resolver/index.js.map +1 -0
- package/dist/realize/runtime-emitters/dispatcher.d.ts +176 -0
- package/dist/realize/runtime-emitters/dispatcher.d.ts.map +1 -0
- package/dist/realize/runtime-emitters/dispatcher.js +76 -0
- package/dist/realize/runtime-emitters/dispatcher.js.map +1 -0
- package/dist/realize/runtime-emitters/executable.d.ts +57 -0
- package/dist/realize/runtime-emitters/executable.d.ts.map +1 -0
- package/dist/realize/runtime-emitters/executable.js +316 -0
- package/dist/realize/runtime-emitters/executable.js.map +1 -0
- package/dist/realize/runtime-emitters/library.d.ts +52 -0
- package/dist/realize/runtime-emitters/library.d.ts.map +1 -0
- package/dist/realize/runtime-emitters/library.js +349 -0
- package/dist/realize/runtime-emitters/library.js.map +1 -0
- package/dist/realize/runtime-emitters/managed.d.ts +44 -0
- package/dist/realize/runtime-emitters/managed.d.ts.map +1 -0
- package/dist/realize/runtime-emitters/managed.js +283 -0
- package/dist/realize/runtime-emitters/managed.js.map +1 -0
- package/dist/realize/runtime-emitters/messaging.d.ts +77 -0
- package/dist/realize/runtime-emitters/messaging.d.ts.map +1 -0
- package/dist/realize/runtime-emitters/messaging.js +423 -0
- package/dist/realize/runtime-emitters/messaging.js.map +1 -0
- package/dist/realize/runtime-emitters/service.d.ts +42 -0
- package/dist/realize/runtime-emitters/service.d.ts.map +1 -0
- package/dist/realize/runtime-emitters/service.js +355 -0
- package/dist/realize/runtime-emitters/service.js.map +1 -0
- package/dist/realize/types/instance-factory.d.ts +1 -1
- package/dist/realize/types/instance-factory.d.ts.map +1 -1
- package/libs/instance-factories/communication/rabbitmq-events.yaml +11 -0
- package/libs/instance-factories/controllers/fastify.yaml +11 -0
- package/libs/instance-factories/managed/stripe-rest-sdk.yaml +78 -0
- package/libs/instance-factories/managed/templates/stripe/stripe-client-generator.ts +26 -0
- package/libs/instance-factories/orms/prisma.yaml +11 -0
- package/package.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V2 Dependency Resolver — Phase 3 (Round 1)
|
|
3
|
+
*
|
|
4
|
+
* 4-step lookup chain for `import[].from` references:
|
|
5
|
+
* 1. Local component in same spec
|
|
6
|
+
* 2. Local npm package (node_modules/<name>/package.json)
|
|
7
|
+
* 3. Registry library (Library.type: component) — HTTP stubbed for Round 1
|
|
8
|
+
* 4. Registry factory (Library.type: factory) — HTTP stubbed for Round 1
|
|
9
|
+
*
|
|
10
|
+
* Decision points applied:
|
|
11
|
+
* D1: version defaults to ^latest (per-realize-run cache)
|
|
12
|
+
* Offline mode: skips steps 3 + 4, fails loudly if unresolvable
|
|
13
|
+
* Cache: <cacheDir>/registry-cache/ (default .specverse/registry-cache/)
|
|
14
|
+
* Fail-loud: throws DependencyResolutionError when nothing resolves
|
|
15
|
+
*
|
|
16
|
+
* @see docs/proposals/2026-05-08-COMPONENT-DEPENDENCIES-V2.md — "Realize bridge — Resolver"
|
|
17
|
+
*/
|
|
18
|
+
import type { SpecVerseAST, ComponentSpec } from '@specverse/types';
|
|
19
|
+
/**
|
|
20
|
+
* A spec that has been resolved from a `from:` reference.
|
|
21
|
+
* For Round 1 registry paths, `spec` is a minimal stub generated from
|
|
22
|
+
* the registry Library record.
|
|
23
|
+
*/
|
|
24
|
+
export interface ResolvedComponent {
|
|
25
|
+
/** The original `from:` value from the import entry that produced this. */
|
|
26
|
+
fromName: string;
|
|
27
|
+
/** Which step of the 4-step chain produced this result. */
|
|
28
|
+
source: 'local' | 'npm' | 'registry-component' | 'registry-factory';
|
|
29
|
+
/**
|
|
30
|
+
* The resolved SpecVerse spec. For local + npm sources this is the full
|
|
31
|
+
* parsed spec. For registry sources (stubs in Round 1) this is a minimal
|
|
32
|
+
* object bearing at least the component's `name` and `version`.
|
|
33
|
+
*/
|
|
34
|
+
spec: PartialSpec;
|
|
35
|
+
/**
|
|
36
|
+
* The resolved provider name (component name for local, npm package name
|
|
37
|
+
* for npm, registry library/factory name for registry-*).
|
|
38
|
+
*/
|
|
39
|
+
resolvedName: string;
|
|
40
|
+
/**
|
|
41
|
+
* Pinned version after ^latest expansion (or the version from the local
|
|
42
|
+
* spec / npm package.json). Optional because some local components may
|
|
43
|
+
* not declare a version field.
|
|
44
|
+
*/
|
|
45
|
+
resolvedVersion?: string;
|
|
46
|
+
/**
|
|
47
|
+
* For source = 'npm' or 'registry-*': the package specifier to use in
|
|
48
|
+
* generated `import` statements (e.g. '@stripe/stripe-js' or 'profit-calc').
|
|
49
|
+
* For source = 'local': not populated; callers compute relative paths
|
|
50
|
+
* from outputDir + resolvedName.
|
|
51
|
+
*/
|
|
52
|
+
packageSpecifier?: string;
|
|
53
|
+
/**
|
|
54
|
+
* For source = 'local': relative path from the consumer's outputDir to
|
|
55
|
+
* the provider's emitted module. Optional — when absent, callers fall
|
|
56
|
+
* back to `../{resolvedName}` or similar convention.
|
|
57
|
+
*/
|
|
58
|
+
localRelativePath?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Registry coordinates when source is 'registry-component' or 'registry-factory'.
|
|
61
|
+
*/
|
|
62
|
+
registryRef?: {
|
|
63
|
+
name: string;
|
|
64
|
+
version: string;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A factory reference returned when the registry resolves a capability match
|
|
69
|
+
* (step 4).
|
|
70
|
+
*/
|
|
71
|
+
export interface FactoryReference {
|
|
72
|
+
name: string;
|
|
73
|
+
version: string;
|
|
74
|
+
/** Factory metadata from registry — partial in Round 1 (HTTP is stubbed). */
|
|
75
|
+
metadata?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Options passed to each `resolve()` call. The full spec + workspace context
|
|
79
|
+
* allow the local-component and npm-package steps to work without extra
|
|
80
|
+
* configuration.
|
|
81
|
+
*/
|
|
82
|
+
export interface ResolveOptions {
|
|
83
|
+
/** The spec being realized — used for local-component lookup (step 1). */
|
|
84
|
+
spec: SpecVerseAST;
|
|
85
|
+
/**
|
|
86
|
+
* Absolute path to the workspace root. Used to locate node_modules for
|
|
87
|
+
* step 2. Defaults to `process.cwd()`.
|
|
88
|
+
*/
|
|
89
|
+
workspaceRoot?: string;
|
|
90
|
+
/**
|
|
91
|
+
* When true, steps 3 and 4 (registry) are skipped. If a `from:` reference
|
|
92
|
+
* cannot be resolved via steps 1–2, throws `DependencyResolutionError`.
|
|
93
|
+
*/
|
|
94
|
+
offline?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Directory where registry responses are cached.
|
|
97
|
+
* Defaults to `.specverse/registry-cache/` inside `workspaceRoot`.
|
|
98
|
+
*/
|
|
99
|
+
cacheDir?: string;
|
|
100
|
+
/**
|
|
101
|
+
* When true, treats the registry cache as stale and re-fetches even if a
|
|
102
|
+
* cached entry exists. Equivalent to the `--refresh-registry` flag.
|
|
103
|
+
* Can also be set via the `SPECVERSE_REFRESH_REGISTRY=1` environment variable.
|
|
104
|
+
*/
|
|
105
|
+
refreshRegistry?: boolean;
|
|
106
|
+
}
|
|
107
|
+
export interface DependencyResolver {
|
|
108
|
+
/**
|
|
109
|
+
* Resolve a `from:` reference to a component spec.
|
|
110
|
+
*
|
|
111
|
+
* Steps (in order):
|
|
112
|
+
* 1. Local component in spec.components
|
|
113
|
+
* 2. node_modules/<from>/package.json
|
|
114
|
+
* 3. GET /api/libraries/<from> (Registry, Library.type: component) — STUBBED
|
|
115
|
+
* 4. GET /api/libraries?type=factory&capability=<from> — STUBBED
|
|
116
|
+
*
|
|
117
|
+
* @param from The `from:` value from the import entry.
|
|
118
|
+
* @param version Semver range or pin. Defaults to `^latest` (D1).
|
|
119
|
+
* @param options Resolve-time context.
|
|
120
|
+
* @returns ResolvedComponent or null when offline + not locally found.
|
|
121
|
+
* @throws DependencyResolutionError when nothing resolves (not offline) or
|
|
122
|
+
* when offline and no local resolution is possible.
|
|
123
|
+
*/
|
|
124
|
+
resolve(from: string, version?: string, options?: ResolveOptions): Promise<ResolvedComponent | null>;
|
|
125
|
+
/**
|
|
126
|
+
* Resolve a capability tag to a factory reference.
|
|
127
|
+
* Used by realize emitters that need to find which factory covers a given
|
|
128
|
+
* capability string.
|
|
129
|
+
*
|
|
130
|
+
* Delegates to step 4 of the chain.
|
|
131
|
+
*
|
|
132
|
+
* @throws DependencyResolutionError when no factory matches and not offline.
|
|
133
|
+
*/
|
|
134
|
+
resolveCapability(capability: string, options?: ResolveOptions): Promise<FactoryReference | null>;
|
|
135
|
+
}
|
|
136
|
+
export declare class DependencyResolutionError extends Error {
|
|
137
|
+
readonly from: string;
|
|
138
|
+
readonly triedSteps: string[];
|
|
139
|
+
constructor(message: string, from: string, triedSteps: string[]);
|
|
140
|
+
}
|
|
141
|
+
/** Minimal spec shape accepted from all resolution sources. */
|
|
142
|
+
export interface PartialSpec {
|
|
143
|
+
name?: string;
|
|
144
|
+
version?: string;
|
|
145
|
+
components?: ComponentSpec[];
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create a `DependencyResolver` instance.
|
|
150
|
+
*
|
|
151
|
+
* The resolver is stateless between realize runs. A new instance should be
|
|
152
|
+
* created per-run (or per test) to avoid cross-run cache pollution in memory.
|
|
153
|
+
* On-disk cache in `<cacheDir>/registry-cache/` persists across runs and is
|
|
154
|
+
* shared across instances that use the same directory.
|
|
155
|
+
*/
|
|
156
|
+
export declare function createDependencyResolver(): DependencyResolver;
|
|
157
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/realize/resolver/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMpE;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;IACpE;;;;OAIG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,YAAY,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAErG;;;;;;;;OAQG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CACnG;AAMD,qBAAa,yBAA0B,SAAQ,KAAK;aAGhC,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM,EAAE;gBAFpC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAAE;CAKvC;AAMD,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA4TD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,CAE7D"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V2 Dependency Resolver — Phase 3 (Round 1)
|
|
3
|
+
*
|
|
4
|
+
* 4-step lookup chain for `import[].from` references:
|
|
5
|
+
* 1. Local component in same spec
|
|
6
|
+
* 2. Local npm package (node_modules/<name>/package.json)
|
|
7
|
+
* 3. Registry library (Library.type: component) — HTTP stubbed for Round 1
|
|
8
|
+
* 4. Registry factory (Library.type: factory) — HTTP stubbed for Round 1
|
|
9
|
+
*
|
|
10
|
+
* Decision points applied:
|
|
11
|
+
* D1: version defaults to ^latest (per-realize-run cache)
|
|
12
|
+
* Offline mode: skips steps 3 + 4, fails loudly if unresolvable
|
|
13
|
+
* Cache: <cacheDir>/registry-cache/ (default .specverse/registry-cache/)
|
|
14
|
+
* Fail-loud: throws DependencyResolutionError when nothing resolves
|
|
15
|
+
*
|
|
16
|
+
* @see docs/proposals/2026-05-08-COMPONENT-DEPENDENCIES-V2.md — "Realize bridge — Resolver"
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
19
|
+
import { join, resolve } from 'path';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Error
|
|
22
|
+
// ============================================================================
|
|
23
|
+
export class DependencyResolutionError extends Error {
|
|
24
|
+
from;
|
|
25
|
+
triedSteps;
|
|
26
|
+
constructor(message, from, triedSteps) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.from = from;
|
|
29
|
+
this.triedSteps = triedSteps;
|
|
30
|
+
this.name = 'DependencyResolutionError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Registry HTTP stub
|
|
35
|
+
// ============================================================================
|
|
36
|
+
/**
|
|
37
|
+
* Round-1 stub for registry component lookup.
|
|
38
|
+
*
|
|
39
|
+
* TODO: Replace with real HTTP fetch:
|
|
40
|
+
* GET <registryBase>/api/libraries/<name>
|
|
41
|
+
* Expected response shape (Library.type: component):
|
|
42
|
+
* { name, version, type: 'component', specContent: '<yaml>' }
|
|
43
|
+
*
|
|
44
|
+
* @returns null — no registry data in Round 1 (real HTTP not yet wired).
|
|
45
|
+
*/
|
|
46
|
+
async function fetchRegistryComponent(name, _version) {
|
|
47
|
+
// TODO(v2-p3-round2): implement real HTTP fetch to specverse registry.
|
|
48
|
+
// Endpoint: GET /api/libraries/<name>
|
|
49
|
+
// Auth: anonymous reads; OAuth for publish
|
|
50
|
+
// Filtering: check Library.type === 'component'
|
|
51
|
+
void name;
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Round-1 stub for registry factory lookup by capability.
|
|
56
|
+
*
|
|
57
|
+
* TODO: Replace with real HTTP fetch:
|
|
58
|
+
* GET <registryBase>/api/libraries?type=factory&capability=<capability>
|
|
59
|
+
* Expected response shape (array of Library.type: factory records):
|
|
60
|
+
* [{ name, version, type: 'factory', metadata: { topology, protocol, ... } }]
|
|
61
|
+
*
|
|
62
|
+
* @returns null — no registry data in Round 1.
|
|
63
|
+
*/
|
|
64
|
+
async function fetchRegistryFactory(_capability) {
|
|
65
|
+
// TODO(v2-p3-round2): implement real HTTP fetch to specverse registry.
|
|
66
|
+
// Endpoint: GET /api/libraries?type=factory&capability=<capability>
|
|
67
|
+
// Auth: anonymous reads
|
|
68
|
+
// Selection: pick highest semver-matching version
|
|
69
|
+
void _capability;
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Resolver implementation
|
|
74
|
+
// ============================================================================
|
|
75
|
+
/**
|
|
76
|
+
* Default semver range when the spec author omits `version:` (D1).
|
|
77
|
+
*/
|
|
78
|
+
const DEFAULT_VERSION = '^latest';
|
|
79
|
+
/**
|
|
80
|
+
* Resolve an effective cache directory from options + environment.
|
|
81
|
+
*/
|
|
82
|
+
function resolveCacheDir(options) {
|
|
83
|
+
if (options.cacheDir)
|
|
84
|
+
return options.cacheDir;
|
|
85
|
+
const root = options.workspaceRoot ?? process.cwd();
|
|
86
|
+
return join(root, '.specverse', 'registry-cache');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Determine whether the registry cache should be refreshed.
|
|
90
|
+
* Checks:
|
|
91
|
+
* 1. `options.refreshRegistry` flag
|
|
92
|
+
* 2. `SPECVERSE_REFRESH_REGISTRY` environment variable
|
|
93
|
+
*/
|
|
94
|
+
function shouldRefreshRegistry(options) {
|
|
95
|
+
if (options.refreshRegistry)
|
|
96
|
+
return true;
|
|
97
|
+
return process.env['SPECVERSE_REFRESH_REGISTRY'] === '1';
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Read a cache entry if it exists (and we are not refreshing).
|
|
101
|
+
*/
|
|
102
|
+
function readCache(cacheDir, key, refresh) {
|
|
103
|
+
if (refresh)
|
|
104
|
+
return null;
|
|
105
|
+
const filePath = join(cacheDir, `${key}.json`);
|
|
106
|
+
if (!existsSync(filePath))
|
|
107
|
+
return null;
|
|
108
|
+
try {
|
|
109
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
110
|
+
return JSON.parse(raw);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write a cache entry. Creates the cache directory if it doesn't exist.
|
|
118
|
+
*/
|
|
119
|
+
function writeCache(cacheDir, key, entry) {
|
|
120
|
+
try {
|
|
121
|
+
if (!existsSync(cacheDir)) {
|
|
122
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
123
|
+
}
|
|
124
|
+
const filePath = join(cacheDir, `${key}.json`);
|
|
125
|
+
writeFileSync(filePath, JSON.stringify(entry, null, 2), 'utf-8');
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Cache write failure is non-fatal — resolution can continue without it.
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Sanitise a `from:` value so it's safe as a filesystem key.
|
|
133
|
+
* Converts `@scope/pkg` → `scope__pkg`, slashes → `__`.
|
|
134
|
+
*/
|
|
135
|
+
function cacheKey(from) {
|
|
136
|
+
return from.replace(/^@/, '').replace(/\//g, '__');
|
|
137
|
+
}
|
|
138
|
+
class DependencyResolverImpl {
|
|
139
|
+
async resolve(from, version, options = { spec: { components: [], deployments: [], manifests: [] } }) {
|
|
140
|
+
const effectiveVersion = version ?? DEFAULT_VERSION;
|
|
141
|
+
const triedSteps = [];
|
|
142
|
+
// ── Step 1: Local component in same spec ────────────────────────────────
|
|
143
|
+
triedSteps.push('local-component');
|
|
144
|
+
const localMatch = (options.spec?.components ?? []).find((c) => c.name === from);
|
|
145
|
+
if (localMatch) {
|
|
146
|
+
return {
|
|
147
|
+
fromName: from,
|
|
148
|
+
source: 'local',
|
|
149
|
+
spec: { name: localMatch.name, version: localMatch.version, components: [localMatch] },
|
|
150
|
+
resolvedName: localMatch.name,
|
|
151
|
+
resolvedVersion: localMatch.version,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// ── Step 2: Local npm package ────────────────────────────────────────────
|
|
155
|
+
triedSteps.push('npm-package');
|
|
156
|
+
const workspaceRoot = resolve(options.workspaceRoot ?? process.cwd());
|
|
157
|
+
const pkgJsonPath = join(workspaceRoot, 'node_modules', from, 'package.json');
|
|
158
|
+
if (existsSync(pkgJsonPath)) {
|
|
159
|
+
try {
|
|
160
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
161
|
+
const pkgName = pkgJson['name'] ?? from;
|
|
162
|
+
const pkgVersion = pkgJson['version'] ?? effectiveVersion;
|
|
163
|
+
return {
|
|
164
|
+
fromName: from,
|
|
165
|
+
source: 'npm',
|
|
166
|
+
spec: { name: pkgName, version: pkgVersion },
|
|
167
|
+
resolvedName: pkgName,
|
|
168
|
+
resolvedVersion: pkgVersion,
|
|
169
|
+
packageSpecifier: pkgName,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Malformed package.json — fall through to registry steps.
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// ── Offline fence ────────────────────────────────────────────────────────
|
|
177
|
+
if (options.offline) {
|
|
178
|
+
throw new DependencyResolutionError(`Cannot resolve "${from}": not found as a local component or npm package, ` +
|
|
179
|
+
`and offline mode prevents registry lookup.\n` +
|
|
180
|
+
` Tried: ${triedSteps.join(', ')}`, from, triedSteps);
|
|
181
|
+
}
|
|
182
|
+
const cacheDir = resolveCacheDir(options);
|
|
183
|
+
const refresh = shouldRefreshRegistry(options);
|
|
184
|
+
const key = cacheKey(from);
|
|
185
|
+
// ── Step 3: Registry library (Library.type: component) ───────────────────
|
|
186
|
+
triedSteps.push('registry-component');
|
|
187
|
+
const cachedComponent = readCache(cacheDir, key, refresh);
|
|
188
|
+
if (cachedComponent && cachedComponent.source === 'registry-component') {
|
|
189
|
+
return {
|
|
190
|
+
fromName: from,
|
|
191
|
+
source: 'registry-component',
|
|
192
|
+
spec: { name: cachedComponent.name, version: cachedComponent.version },
|
|
193
|
+
resolvedName: cachedComponent.name,
|
|
194
|
+
resolvedVersion: cachedComponent.version,
|
|
195
|
+
packageSpecifier: cachedComponent.name,
|
|
196
|
+
registryRef: { name: cachedComponent.name, version: cachedComponent.version },
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const registryComponentResult = await fetchRegistryComponent(from, effectiveVersion);
|
|
200
|
+
if (registryComponentResult) {
|
|
201
|
+
const entry = {
|
|
202
|
+
cachedAt: new Date().toISOString(),
|
|
203
|
+
source: 'registry-component',
|
|
204
|
+
name: registryComponentResult.name,
|
|
205
|
+
version: registryComponentResult.version,
|
|
206
|
+
data: registryComponentResult,
|
|
207
|
+
};
|
|
208
|
+
writeCache(cacheDir, key, entry);
|
|
209
|
+
return {
|
|
210
|
+
fromName: from,
|
|
211
|
+
source: 'registry-component',
|
|
212
|
+
spec: { name: registryComponentResult.name, version: registryComponentResult.version },
|
|
213
|
+
resolvedName: registryComponentResult.name,
|
|
214
|
+
resolvedVersion: registryComponentResult.version,
|
|
215
|
+
packageSpecifier: registryComponentResult.name,
|
|
216
|
+
registryRef: { name: registryComponentResult.name, version: registryComponentResult.version },
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// ── Step 4: Registry factory (Library.type: factory) ─────────────────────
|
|
220
|
+
triedSteps.push('registry-factory');
|
|
221
|
+
const factoryKey = `factory__${key}`;
|
|
222
|
+
const cachedFactory = readCache(cacheDir, factoryKey, refresh);
|
|
223
|
+
if (cachedFactory && cachedFactory.source === 'registry-factory') {
|
|
224
|
+
return {
|
|
225
|
+
fromName: from,
|
|
226
|
+
source: 'registry-factory',
|
|
227
|
+
spec: { name: cachedFactory.name, version: cachedFactory.version },
|
|
228
|
+
resolvedName: cachedFactory.name,
|
|
229
|
+
resolvedVersion: cachedFactory.version,
|
|
230
|
+
packageSpecifier: cachedFactory.name,
|
|
231
|
+
registryRef: { name: cachedFactory.name, version: cachedFactory.version },
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const registryFactoryResult = await fetchRegistryFactory(from);
|
|
235
|
+
if (registryFactoryResult) {
|
|
236
|
+
const entry = {
|
|
237
|
+
cachedAt: new Date().toISOString(),
|
|
238
|
+
source: 'registry-factory',
|
|
239
|
+
name: registryFactoryResult.name,
|
|
240
|
+
version: registryFactoryResult.version,
|
|
241
|
+
data: registryFactoryResult,
|
|
242
|
+
};
|
|
243
|
+
writeCache(cacheDir, factoryKey, entry);
|
|
244
|
+
return {
|
|
245
|
+
fromName: from,
|
|
246
|
+
source: 'registry-factory',
|
|
247
|
+
spec: { name: registryFactoryResult.name, version: registryFactoryResult.version },
|
|
248
|
+
resolvedName: registryFactoryResult.name,
|
|
249
|
+
resolvedVersion: registryFactoryResult.version,
|
|
250
|
+
packageSpecifier: registryFactoryResult.name,
|
|
251
|
+
registryRef: { name: registryFactoryResult.name, version: registryFactoryResult.version },
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
// ── Nothing resolved ─────────────────────────────────────────────────────
|
|
255
|
+
throw new DependencyResolutionError(`Cannot resolve "${from}" (version: "${effectiveVersion}"): ` +
|
|
256
|
+
`exhausted all 4 lookup steps with no match.\n` +
|
|
257
|
+
` Tried: ${triedSteps.join(' → ')}\n` +
|
|
258
|
+
` Hint: check the component name, npm package name, or registry entry for "${from}".`, from, triedSteps);
|
|
259
|
+
}
|
|
260
|
+
async resolveCapability(capability, options = { spec: { components: [], deployments: [], manifests: [] } }) {
|
|
261
|
+
if (options.offline) {
|
|
262
|
+
// In offline mode we cannot query the registry for capability matches.
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
const cacheDir = resolveCacheDir(options);
|
|
266
|
+
const refresh = shouldRefreshRegistry(options);
|
|
267
|
+
const key = `capability__${cacheKey(capability)}`;
|
|
268
|
+
// Check cache first.
|
|
269
|
+
const cached = readCache(cacheDir, key, refresh);
|
|
270
|
+
if (cached && cached.source === 'registry-factory') {
|
|
271
|
+
return {
|
|
272
|
+
name: cached.name,
|
|
273
|
+
version: cached.version,
|
|
274
|
+
metadata: cached.data,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
// TODO(v2-p3-round2): real HTTP call stubbed below.
|
|
278
|
+
const result = await fetchRegistryFactory(capability);
|
|
279
|
+
if (result) {
|
|
280
|
+
const entry = {
|
|
281
|
+
cachedAt: new Date().toISOString(),
|
|
282
|
+
source: 'registry-factory',
|
|
283
|
+
name: result.name,
|
|
284
|
+
version: result.version,
|
|
285
|
+
data: result,
|
|
286
|
+
};
|
|
287
|
+
writeCache(cacheDir, key, entry);
|
|
288
|
+
return { name: result.name, version: result.version, metadata: result.metadata };
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// ============================================================================
|
|
294
|
+
// Factory function (public API)
|
|
295
|
+
// ============================================================================
|
|
296
|
+
/**
|
|
297
|
+
* Create a `DependencyResolver` instance.
|
|
298
|
+
*
|
|
299
|
+
* The resolver is stateless between realize runs. A new instance should be
|
|
300
|
+
* created per-run (or per test) to avoid cross-run cache pollution in memory.
|
|
301
|
+
* On-disk cache in `<cacheDir>/registry-cache/` persists across runs and is
|
|
302
|
+
* shared across instances that use the same directory.
|
|
303
|
+
*/
|
|
304
|
+
export function createDependencyResolver() {
|
|
305
|
+
return new DependencyResolverImpl();
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/realize/resolver/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AA8HrC,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAGhC;IACA;IAHlB,YACE,OAAe,EACC,IAAY,EACZ,UAAoB;QAEpC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAU;QAGpC,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAwBD,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,KAAK,UAAU,sBAAsB,CACnC,IAAY,EACZ,QAAgB;IAEhB,uEAAuE;IACvE,sCAAsC;IACtC,+CAA+C;IAC/C,gDAAgD;IAChD,KAAK,IAAI,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,oBAAoB,CACjC,WAAmB;IAEnB,uEAAuE;IACvE,oEAAoE;IACpE,4BAA4B;IAC5B,kDAAkD;IAClD,KAAK,WAAW,CAAC;IACjB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+EAA+E;AAC/E,0BAA0B;AAC1B,+EAA+E;AAE/E;;GAEG;AACH,MAAM,eAAe,GAAG,SAAS,CAAC;AAElC;;GAEG;AACH,SAAS,eAAe,CAAC,OAAuB;IAC9C,IAAI,OAAO,CAAC,QAAQ;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACpD,OAAO,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB,CAAC,OAAuB;IACpD,IAAI,OAAO,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,KAAK,GAAG,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,QAAgB,EAAE,GAAW,EAAE,OAAgB;IAChE,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,QAAgB,EAAE,GAAW,EAAE,KAAiB;IAClE,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAC/C,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,sBAAsB;IAC1B,KAAK,CAAC,OAAO,CACX,IAAY,EACZ,OAAgB,EAChB,UAA0B,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE;QAEtF,MAAM,gBAAgB,GAAG,OAAO,IAAI,eAAe,CAAC;QACpD,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,2EAA2E;QAC3E,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACnC,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CACtD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CACvB,CAAC;QACF,IAAI,UAAU,EAAE,CAAC;YACf,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,OAAO;gBACf,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,UAAU,CAAC,EAAE;gBACtF,YAAY,EAAE,UAAU,CAAC,IAAI;gBAC7B,eAAe,EAAE,UAAU,CAAC,OAAO;aACpC,CAAC;QACJ,CAAC;QAED,4EAA4E;QAC5E,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACtE,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAC9E,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAA4B,CAAC;gBAC1F,MAAM,OAAO,GAAI,OAAO,CAAC,MAAM,CAAY,IAAI,IAAI,CAAC;gBACpD,MAAM,UAAU,GAAI,OAAO,CAAC,SAAS,CAAY,IAAI,gBAAgB,CAAC;gBACtE,OAAO;oBACL,QAAQ,EAAE,IAAI;oBACd,MAAM,EAAE,KAAK;oBACb,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE;oBAC5C,YAAY,EAAE,OAAO;oBACrB,eAAe,EAAE,UAAU;oBAC3B,gBAAgB,EAAE,OAAO;iBAC1B,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,2DAA2D;YAC7D,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,yBAAyB,CACjC,mBAAmB,IAAI,oDAAoD;gBACzE,8CAA8C;gBAC9C,YAAY,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACrC,IAAI,EACJ,UAAU,CACX,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE3B,4EAA4E;QAC5E,UAAU,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACtC,MAAM,eAAe,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QAC1D,IAAI,eAAe,IAAI,eAAe,CAAC,MAAM,KAAK,oBAAoB,EAAE,CAAC;YACvE,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,oBAAoB;gBAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,eAAe,CAAC,OAAO,EAAE;gBACtE,YAAY,EAAE,eAAe,CAAC,IAAI;gBAClC,eAAe,EAAE,eAAe,CAAC,OAAO;gBACxC,gBAAgB,EAAE,eAAe,CAAC,IAAI;gBACtC,WAAW,EAAE,EAAE,IAAI,EAAE,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,eAAe,CAAC,OAAO,EAAE;aAC9E,CAAC;QACJ,CAAC;QAED,MAAM,uBAAuB,GAAG,MAAM,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QACrF,IAAI,uBAAuB,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAe;gBACxB,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAClC,MAAM,EAAE,oBAAoB;gBAC5B,IAAI,EAAE,uBAAuB,CAAC,IAAI;gBAClC,OAAO,EAAE,uBAAuB,CAAC,OAAO;gBACxC,IAAI,EAAE,uBAA6D;aACpE,CAAC;YACF,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YACjC,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,oBAAoB;gBAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,uBAAuB,CAAC,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,OAAO,EAAE;gBACtF,YAAY,EAAE,uBAAuB,CAAC,IAAI;gBAC1C,eAAe,EAAE,uBAAuB,CAAC,OAAO;gBAChD,gBAAgB,EAAE,uBAAuB,CAAC,IAAI;gBAC9C,WAAW,EAAE,EAAE,IAAI,EAAE,uBAAuB,CAAC,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,OAAO,EAAE;aAC9F,CAAC;QACJ,CAAC;QAED,4EAA4E;QAC5E,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,YAAY,GAAG,EAAE,CAAC;QACrC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAC/D,IAAI,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,kBAAkB,EAAE,CAAC;YACjE,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,kBAAkB;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE;gBAClE,YAAY,EAAE,aAAa,CAAC,IAAI;gBAChC,eAAe,EAAE,aAAa,CAAC,OAAO;gBACtC,gBAAgB,EAAE,aAAa,CAAC,IAAI;gBACpC,WAAW,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE;aAC1E,CAAC;QACJ,CAAC;QAED,MAAM,qBAAqB,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC/D,IAAI,qBAAqB,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAe;gBACxB,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAClC,MAAM,EAAE,kBAAkB;gBAC1B,IAAI,EAAE,qBAAqB,CAAC,IAAI;gBAChC,OAAO,EAAE,qBAAqB,CAAC,OAAO;gBACtC,IAAI,EAAE,qBAA2D;aAClE,CAAC;YACF,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;YACxC,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,kBAAkB;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,qBAAqB,CAAC,OAAO,EAAE;gBAClF,YAAY,EAAE,qBAAqB,CAAC,IAAI;gBACxC,eAAe,EAAE,qBAAqB,CAAC,OAAO;gBAC9C,gBAAgB,EAAE,qBAAqB,CAAC,IAAI;gBAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,qBAAqB,CAAC,OAAO,EAAE;aAC1F,CAAC;QACJ,CAAC;QAED,4EAA4E;QAC5E,MAAM,IAAI,yBAAyB,CACjC,mBAAmB,IAAI,gBAAgB,gBAAgB,MAAM;YAC3D,+CAA+C;YAC/C,YAAY,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;YACtC,8EAA8E,IAAI,IAAI,EACxF,IAAI,EACJ,UAAU,CACX,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,UAAkB,EAClB,UAA0B,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE;QAEtF,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,uEAAuE;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,eAAe,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAElD,qBAAqB;QACrB,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,kBAAkB,EAAE,CAAC;YACnD,OAAO;gBACL,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,QAAQ,EAAE,MAAM,CAAC,IAA+B;aACjD,CAAC;QACJ,CAAC;QAED,oDAAoD;QACpD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,KAAK,GAAe;gBACxB,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAClC,MAAM,EAAE,kBAAkB;gBAC1B,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAA4C;aACnD,CAAC;YACF,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YACjC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnF,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,+EAA+E;AAC/E,gCAAgC;AAChC,+EAA+E;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,IAAI,sBAAsB,EAAE,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-runtime emitter dispatcher — V2 Phase 3, Round 1.
|
|
3
|
+
*
|
|
4
|
+
* Proposal: 2026-05-08-COMPONENT-DEPENDENCIES-V2.md, "Realize bridge" section.
|
|
5
|
+
*
|
|
6
|
+
* The dispatcher is a small registry + lookup framework. The real work lives in
|
|
7
|
+
* each topology-specific emitter implementation (library.ts, and future
|
|
8
|
+
* service.ts / managed.ts / executable.ts / messaging.ts files).
|
|
9
|
+
*
|
|
10
|
+
* Round 1 ships: dispatcher framework + library topology emitter (this file +
|
|
11
|
+
* library.ts). The two cross-branch types — `ResolvedComponent` (Agent A) and
|
|
12
|
+
* `FactoryV2Metadata` / `InstanceFactory` (Agent B) — are imported from their
|
|
13
|
+
* canonical locations: Round 1d (this commit) reconciled the local stubs with
|
|
14
|
+
* the merged real types.
|
|
15
|
+
*
|
|
16
|
+
* Round 2 will add: service, managed, executable, messaging emitters + CLI wiring.
|
|
17
|
+
*/
|
|
18
|
+
import type { ComponentSpec, SpecVerseAST, InstanceFactory, FactoryTopology } from '@specverse/types';
|
|
19
|
+
import type { ResolvedComponent } from '../resolver/index.js';
|
|
20
|
+
export type { ResolvedComponent } from '../resolver/index.js';
|
|
21
|
+
export type { FactoryTopology, InstanceFactory } from '@specverse/types';
|
|
22
|
+
/** Alias kept for back-compat with the Round-1 stub naming. */
|
|
23
|
+
export type FactoryMetadata = InstanceFactory;
|
|
24
|
+
/**
|
|
25
|
+
* A single entry in a component's `import:` block.
|
|
26
|
+
* Mirrors the V2 Phase 1 schema additions (commit bb4b99b):
|
|
27
|
+
* - from: provider name (resolved via 4-step lookup)
|
|
28
|
+
* - version?: semver range (optional, defaults to ^latest)
|
|
29
|
+
* - select: array of bare or dotted operation names
|
|
30
|
+
*/
|
|
31
|
+
export interface ImportEntry {
|
|
32
|
+
from: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
select: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Context passed to every runtime emitter.
|
|
38
|
+
* Carries the consumer-side view (component + import entry) alongside
|
|
39
|
+
* the resolved provider (Agent A) and the factory metadata (Agent B).
|
|
40
|
+
*/
|
|
41
|
+
export interface RuntimeEmitterContext {
|
|
42
|
+
/** The component that contains the `import:` block. */
|
|
43
|
+
consumerComponent: ComponentSpec;
|
|
44
|
+
/** The specific {from, version?, select} entry being emitted. */
|
|
45
|
+
importEntry: ImportEntry;
|
|
46
|
+
/**
|
|
47
|
+
* Resolver result for this import entry.
|
|
48
|
+
* Round 1 stub: callers construct this manually; Agent A's resolver will
|
|
49
|
+
* produce it automatically when integrated in Round 2.
|
|
50
|
+
*/
|
|
51
|
+
resolved: ResolvedComponent;
|
|
52
|
+
/**
|
|
53
|
+
* Factory metadata from the manifest's capabilityMappings.
|
|
54
|
+
* Round 1 stub: callers construct this manually; Agent B's schema +
|
|
55
|
+
* the registry-aware manifest-emitter will produce it when integrated.
|
|
56
|
+
*/
|
|
57
|
+
factory: FactoryMetadata;
|
|
58
|
+
/**
|
|
59
|
+
* Absolute path to the consumer component's realize output directory.
|
|
60
|
+
* Generated clients land at `<outputDir>/clients/<provider-name>.ts`.
|
|
61
|
+
*/
|
|
62
|
+
outputDir: string;
|
|
63
|
+
/**
|
|
64
|
+
* The full parsed spec, for cross-component type lookups.
|
|
65
|
+
* Optional in Round 1 — the library emitter doesn't need cross-spec
|
|
66
|
+
* lookups yet; future emitters may need it for server-bind code.
|
|
67
|
+
*/
|
|
68
|
+
spec?: SpecVerseAST;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Structured deployment-instance suggestion an emitter produces alongside
|
|
72
|
+
* its files/imports. The realize pipeline collects every emitter's
|
|
73
|
+
* suggestions into `<outputDir>/v2-deployment-suggestions.yaml` (V2 P3
|
|
74
|
+
* Round 3 follow-up), which the user merges into their deployment block
|
|
75
|
+
* manually. Auto-merge isn't safe — deployment shape is user-controlled
|
|
76
|
+
* (env-specific values, secrets, scaling parameters).
|
|
77
|
+
*
|
|
78
|
+
* Library-topology emitters do NOT produce suggestions (libraries are
|
|
79
|
+
* in-process imports, not deployment instances).
|
|
80
|
+
*/
|
|
81
|
+
export interface DeploymentInstanceSuggestion {
|
|
82
|
+
/** Provider name (importEntry.from) — anchors the suggestion to its import. */
|
|
83
|
+
provider: string;
|
|
84
|
+
/** Component that declared the import — for cross-checking which
|
|
85
|
+
* deployment-instance scope the suggestion belongs to. */
|
|
86
|
+
consumerComponent?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Which deployment-instance category this provider lands in. Mirrors
|
|
89
|
+
* the schema's InstancesSection keys (services, communications,
|
|
90
|
+
* infrastructure, …). Out-of-band categories should not be used.
|
|
91
|
+
*/
|
|
92
|
+
category: 'services' | 'communications' | 'infrastructure' | 'storage' | 'security' | 'monitoring';
|
|
93
|
+
/** Instance key under the category (lower-camelCase client name). */
|
|
94
|
+
key: string;
|
|
95
|
+
/** Pre-built config block — placeholder values use `<...>` markers. */
|
|
96
|
+
config: Record<string, unknown>;
|
|
97
|
+
/** Factory name driving the choice (manifest.capabilityMappings). */
|
|
98
|
+
factory: string;
|
|
99
|
+
/** Topology that emitted this suggestion. */
|
|
100
|
+
topology: FactoryTopology;
|
|
101
|
+
/** Optional review-time hints (TODOs, OAuth flows, etc.). */
|
|
102
|
+
reviewNotes?: string[];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* What a runtime emitter produces.
|
|
106
|
+
*/
|
|
107
|
+
export interface RuntimeEmitterResult {
|
|
108
|
+
/**
|
|
109
|
+
* Files to write into the consumer's output directory.
|
|
110
|
+
* Paths are relative to `outputDir`.
|
|
111
|
+
*/
|
|
112
|
+
files: Array<{
|
|
113
|
+
path: string;
|
|
114
|
+
content: string;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* Import statements the consumer's main module (SalesReportController.ts)
|
|
118
|
+
* should add to wire up the generated client.
|
|
119
|
+
*/
|
|
120
|
+
imports: Array<{
|
|
121
|
+
from: string;
|
|
122
|
+
specifier: string;
|
|
123
|
+
}>;
|
|
124
|
+
/**
|
|
125
|
+
* Optional realize-time hints or warnings.
|
|
126
|
+
*/
|
|
127
|
+
notes?: string[];
|
|
128
|
+
/**
|
|
129
|
+
* V2 P3 R3 follow-up: structured deployment-instance suggestion. The
|
|
130
|
+
* free-text equivalent is in `notes` for human review; this field is
|
|
131
|
+
* the machine-readable version that the realize pipeline aggregates
|
|
132
|
+
* into v2-deployment-suggestions.yaml. Library-topology emissions
|
|
133
|
+
* omit this field.
|
|
134
|
+
*/
|
|
135
|
+
deploymentSuggestion?: DeploymentInstanceSuggestion;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Contract every topology-specific emitter must satisfy.
|
|
139
|
+
*/
|
|
140
|
+
export interface RuntimeEmitter {
|
|
141
|
+
/** The topology this emitter handles. Drives dispatch lookup. */
|
|
142
|
+
topology: FactoryTopology;
|
|
143
|
+
/** Emit files for one import entry. */
|
|
144
|
+
emit(ctx: RuntimeEmitterContext): Promise<RuntimeEmitterResult>;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Look up the correct emitter for the factory's topology.
|
|
148
|
+
*
|
|
149
|
+
* The emitters map is injected by the caller, making the dispatcher
|
|
150
|
+
* extensible without engine changes: register new emitters by adding
|
|
151
|
+
* entries to the map.
|
|
152
|
+
*
|
|
153
|
+
* @param factory - The resolved factory metadata (drives the topology lookup).
|
|
154
|
+
* @param emitters - Registry of topology → RuntimeEmitter. Typically built
|
|
155
|
+
* once per realize run by `buildDefaultEmitters()`.
|
|
156
|
+
* @returns The matching RuntimeEmitter.
|
|
157
|
+
* @throws Error if no emitter is registered for the factory's topology.
|
|
158
|
+
*/
|
|
159
|
+
export declare function dispatchRuntimeEmitter(factory: FactoryMetadata, emitters: Map<string, RuntimeEmitter>): RuntimeEmitter;
|
|
160
|
+
/**
|
|
161
|
+
* Build the default emitter registry for a realize run.
|
|
162
|
+
*
|
|
163
|
+
* Round 1 shipped library; Round 2 added service / managed / executable /
|
|
164
|
+
* messaging. All 5 are registered here so the realize-side dispatcher can
|
|
165
|
+
* pick whichever the factory's v2metadata.topology selects.
|
|
166
|
+
*
|
|
167
|
+
* The 'external' topology is intentionally NOT registered — V2's design
|
|
168
|
+
* defines it as a passthrough requiring manual wiring (no auto-emission).
|
|
169
|
+
* Specs that bind a factory with topology: 'external' will trip a clear
|
|
170
|
+
* "No runtime emitter registered" error, which is the desired behavior.
|
|
171
|
+
*
|
|
172
|
+
* Imports are deferred to avoid circular deps — each emitter file imports
|
|
173
|
+
* only from dispatcher.ts, not vice versa.
|
|
174
|
+
*/
|
|
175
|
+
export declare function buildDefaultEmitters(): Promise<Map<string, RuntimeEmitter>>;
|
|
176
|
+
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../../src/realize/runtime-emitters/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEzE,+DAA+D;AAC/D,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;AAI9C;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAID;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,iBAAiB,EAAE,aAAa,CAAC;IACjC,iEAAiE;IACjE,WAAW,EAAE,WAAW,CAAC;IACzB;;;;OAIG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,4BAA4B;IAC3C,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB;+DAC2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,UAAU,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAAC;IACnG,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,QAAQ,EAAE,eAAe,CAAC;IAC1B,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD;;;OAGG;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,4BAA4B,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,eAAe,CAAC;IAC1B,uCAAuC;IACvC,IAAI,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACjE;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACpC,cAAc,CAchB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAsBjF"}
|