@happyvertical/smrt-core 0.49.4 → 0.49.6
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/README.md +65 -0
- package/dist/consumer-plugin/index.d.ts +19 -4
- package/dist/consumer-plugin/index.d.ts.map +1 -1
- package/dist/consumer-plugin/index.js +209 -6
- package/dist/consumer-plugin/index.js.map +1 -1
- package/dist/manifest/static-manifest.d.ts.map +1 -1
- package/dist/manifest/static-manifest.js +13 -7
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest.json +13 -7
- package/dist/scanner/manifest-generator.d.ts +39 -0
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +79 -12
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/smrt-knowledge.json +3 -3
- package/dist/vite-plugin/changes-route.d.ts.map +1 -1
- package/dist/vite-plugin/changes-route.js +4 -3
- package/dist/vite-plugin/changes-route.js.map +1 -1
- package/dist/vite-plugin/dev-plane-route.d.ts +2 -0
- package/dist/vite-plugin/dev-plane-route.d.ts.map +1 -1
- package/dist/vite-plugin/dev-plane-route.js +8 -5
- package/dist/vite-plugin/dev-plane-route.js.map +1 -1
- package/dist/vite-plugin/events-route.d.ts.map +1 -1
- package/dist/vite-plugin/events-route.js +4 -3
- package/dist/vite-plugin/events-route.js.map +1 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +26 -91
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/resources-route.d.ts +6 -0
- package/dist/vite-plugin/resources-route.d.ts.map +1 -1
- package/dist/vite-plugin/resources-route.js +30 -7
- package/dist/vite-plugin/resources-route.js.map +1 -1
- package/dist/vite-plugin/sveltekit-config-import.d.ts +19 -0
- package/dist/vite-plugin/sveltekit-config-import.d.ts.map +1 -0
- package/dist/vite-plugin/sveltekit-config-import.js +36 -0
- package/dist/vite-plugin/sveltekit-config-import.js.map +1 -0
- package/dist/vite-plugin/sveltekit-generator.d.ts +33 -2
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +181 -65
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/sveltekit-path.d.ts +8 -0
- package/dist/vite-plugin/sveltekit-path.d.ts.map +1 -0
- package/dist/vite-plugin/sveltekit-path.js +25 -0
- package/dist/vite-plugin/sveltekit-path.js.map +1 -0
- package/dist/vite-plugin/sveltekit-route-coordinator.d.ts +67 -0
- package/dist/vite-plugin/sveltekit-route-coordinator.d.ts.map +1 -0
- package/dist/vite-plugin/sveltekit-route-coordinator.js +321 -0
- package/dist/vite-plugin/sveltekit-route-coordinator.js.map +1 -0
- package/dist/vite-plugin/sync-apply-route.d.ts +1 -1
- package/dist/vite-plugin/sync-apply-route.d.ts.map +1 -1
- package/dist/vite-plugin/sync-apply-route.js +4 -3
- package/dist/vite-plugin/sync-apply-route.js.map +1 -1
- package/dist/vite-plugin/web-collections.d.ts +8 -0
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js +42 -1
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -191,12 +191,77 @@ generates routes, types, registration, and virtual modules, but it disables
|
|
|
191
191
|
source/package scans, watch rescans, and manifest writes. Omit
|
|
192
192
|
`generationSnapshot` for normal local development.
|
|
193
193
|
|
|
194
|
+
#### Consumer web collection definitions
|
|
195
|
+
|
|
196
|
+
`smrtConsumer()` also resolves `@smrt/web` for browser collection consumers:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { collectionDefinitions, getCollectionDefinition } from '@smrt/web';
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The module projects the consumer's aggregated dependency manifest through the
|
|
203
|
+
same web-definition generator as `smrtPlugin()`. Each definition retains its
|
|
204
|
+
provider-qualified `objectRef` (for example, `@acme/widgets:Widget`) and its
|
|
205
|
+
manifest-derived fields, actions, relationships, WebMCP descriptors, and
|
|
206
|
+
`manifestHash`. Consumer snapshots select the dependency view, so local project
|
|
207
|
+
objects are not included. During declaration generation the matching
|
|
208
|
+
`smrt-web.d.ts` module is written alongside the other consumer virtual modules.
|
|
209
|
+
|
|
194
210
|
### Generated SvelteKit routes
|
|
195
211
|
|
|
196
212
|
Enable SvelteKit route generation with `svelteKit: { enabled: true }`. Its
|
|
197
213
|
default output directory is `src/routes/api`; set `svelteKit.routesDir` when
|
|
198
214
|
your application uses a different route root.
|
|
199
215
|
|
|
216
|
+
A consumer can host selected dependency models with the same generator. This is
|
|
217
|
+
an explicit HTTP boundary that is separate from the broader `packages`
|
|
218
|
+
registration inventory. Name exact provider-qualified object references; a
|
|
219
|
+
simple class name, an unknown object, or an empty list fails the build before
|
|
220
|
+
any generated route is replaced:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
smrtConsumer({
|
|
224
|
+
packages: runtimeProviderPackages,
|
|
225
|
+
svelteKit: {
|
|
226
|
+
objects: ['@acme/widgets:Widget'],
|
|
227
|
+
routesDir: 'src/routes/api',
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`projectRoot` selects one artifact root for consumer route generation,
|
|
233
|
+
registration, manifests, and types; it defaults to the current working
|
|
234
|
+
directory. It remains the consumer artifact root when a Vite config declares a
|
|
235
|
+
different `root`; pass `projectRoot` explicitly when consumer artifacts should
|
|
236
|
+
share that Vite root or belong elsewhere.
|
|
237
|
+
|
|
238
|
+
Only the listed objects are passed to route generation, so another API model in
|
|
239
|
+
the same provider remains absent until it is named. `api: false` and an empty
|
|
240
|
+
`api.include` still suppress handlers, and generated auth, writable-field, and
|
|
241
|
+
tenant safeguards are unchanged. `svelteKit: true` remains a legacy consumer
|
|
242
|
+
integration flag and does not host dependency CRUD routes. Consumer-hosted
|
|
243
|
+
`_changes`, `_events`, and `_resources` routes are disabled unless their
|
|
244
|
+
existing option is explicitly enabled; `sync/apply` is generated when a selected model exposes a mutating API
|
|
245
|
+
action.
|
|
246
|
+
|
|
247
|
+
When `smrtPlugin()` and `smrtConsumer()` generate routes in one SvelteKit
|
|
248
|
+
application, they may use the same canonical `routesDir` and share one
|
|
249
|
+
generated surface, or use disjoint directories. Nested directories are
|
|
250
|
+
rejected before files are changed because a parent generated-root cleanup would
|
|
251
|
+
otherwise own and remove the child surface.
|
|
252
|
+
Canonical ownership resolves symlink aliases through the nearest existing
|
|
253
|
+
directory, so paths that name the same generated directory share one surface.
|
|
254
|
+
When separate artifact roots resolve to that same route directory, their
|
|
255
|
+
resolved object and config outputs must also agree; incompatible settings fail
|
|
256
|
+
before generated handlers or managed ownership records change.
|
|
257
|
+
|
|
258
|
+
The consumer keeps a private managed-root inventory under `.smrt` after a
|
|
259
|
+
successful explicit hosting plan is validated. Changing its `routesDir`,
|
|
260
|
+
setting `svelteKit: false`, returning to legacy `svelteKit: true`, or omitting
|
|
261
|
+
the option reconciles only consumer-managed generated handlers before SvelteKit
|
|
262
|
+
inventories routes. Handwritten handlers and current producer-owned routes are
|
|
263
|
+
preserved.
|
|
264
|
+
|
|
200
265
|
The plugin records only the concrete `+server.ts` files it generated in a
|
|
201
266
|
bounded `.gitignore` block. Handwritten handlers below `routesDir` remain
|
|
202
267
|
visible to Git, including routes that live beside generated resource handlers.
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
import { SmrtGenerationSnapshotOptions } from '../generation-snapshot.js';
|
|
3
|
+
import { SvelteKitOptions } from '../vite-plugin/sveltekit-generator.js';
|
|
3
4
|
export { loadVerifiedSmrtGenerationSnapshot, type SerializeSmrtGenerationSnapshotOptions, type SmrtGenerationSnapshotArtifact, type SmrtGenerationSnapshotOptions, type SmrtGenerationSnapshotView, serializeSmrtGenerationSnapshot, sha256SmrtGenerationSnapshot, } from '../generation-snapshot.js';
|
|
5
|
+
/**
|
|
6
|
+
* SvelteKit route-hosting options for dependency models. Unlike `packages`,
|
|
7
|
+
* `objects` is an HTTP exposure boundary: every entry must be an exact,
|
|
8
|
+
* provider-qualified manifest key (for example, `@acme/widgets:Widget`).
|
|
9
|
+
*/
|
|
10
|
+
export interface SmrtConsumerSvelteKitOptions extends Partial<Pick<SvelteKitOptions, 'routesDir' | 'configPath' | 'configFileName' | 'kebabRoutes' | 'changesRoute' | 'eventsRoute' | 'resourcesRoute'>> {
|
|
11
|
+
objects: readonly string[];
|
|
12
|
+
}
|
|
4
13
|
export interface SmrtConsumerOptions {
|
|
5
14
|
/** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */
|
|
6
15
|
packages?: string[];
|
|
@@ -8,7 +17,7 @@ export interface SmrtConsumerOptions {
|
|
|
8
17
|
generateTypes?: boolean;
|
|
9
18
|
/** Output directory for generated types */
|
|
10
19
|
typesDir?: string;
|
|
11
|
-
/** Project root path */
|
|
20
|
+
/** Project root path (defaults to the current working directory) */
|
|
12
21
|
projectRoot?: string;
|
|
13
22
|
/**
|
|
14
23
|
* Reuse an immutable, verified aggregated manifest instead of discovering
|
|
@@ -16,11 +25,17 @@ export interface SmrtConsumerOptions {
|
|
|
16
25
|
* types still consume the verified manifest.
|
|
17
26
|
*/
|
|
18
27
|
generationSnapshot?: SmrtGenerationSnapshotOptions;
|
|
19
|
-
/**
|
|
20
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Consumer SvelteKit integration. `true` retains the historical compatibility
|
|
30
|
+
* mode and does not generate dependency routes. Route hosting requires an
|
|
31
|
+
* explicit, provider-qualified object allowlist.
|
|
32
|
+
*/
|
|
33
|
+
svelteKit?: boolean | SmrtConsumerSvelteKitOptions;
|
|
21
34
|
/**
|
|
22
35
|
* Apply kebab-case to generated custom-method URL segments. This must match
|
|
23
|
-
* the producer plugin's `svelteKit.kebabRoutes` setting.
|
|
36
|
+
* the producer plugin's `svelteKit.kebabRoutes` setting. When explicit
|
|
37
|
+
* consumer SvelteKit hosting is configured, its `kebabRoutes` value takes
|
|
38
|
+
* precedence, including an explicit `false`.
|
|
24
39
|
*/
|
|
25
40
|
kebabRoutes?: boolean;
|
|
26
41
|
/** Use static types only (for federation builds) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consumer-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consumer-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAa,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAEL,KAAK,6BAA6B,EACnC,MAAM,2BAA2B,CAAC;AAWnC,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uCAAuC,CAAC;AAoB/C,OAAO,EACL,kCAAkC,EAClC,KAAK,sCAAsC,EAC3C,KAAK,8BAA8B,EACnC,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,+BAA+B,EAC/B,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAqDnC;;;;GAIG;AACH,MAAM,WAAW,4BACf,SAAQ,OAAO,CACb,IAAI,CACF,gBAAgB,EACd,WAAW,GACX,YAAY,GACZ,gBAAgB,GAChB,aAAa,GACb,cAAc,GACd,aAAa,GACb,gBAAgB,CACnB,CACF;IACD,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,6BAA6B,CAAC;IACnD;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,4BAA4B,CAAC;IACnD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA0VD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAwTtE"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import "../scanner/types.js";
|
|
2
|
+
import { canonicalSvelteKitPath } from "../vite-plugin/sveltekit-path.js";
|
|
3
|
+
import { clearGeneratedSvelteKitRouteFiles, reconcileSvelteKitRouteGitignore } from "../vite-plugin/sveltekit-generator.js";
|
|
4
|
+
import { generateWebModule, isCollectionManifestClass, resolveCollectionItemObject } from "../vite-plugin/web-collections.js";
|
|
2
5
|
import { buildDomainKnowledgeManifest } from "../knowledge.js";
|
|
3
6
|
import { loadVerifiedSmrtGenerationSnapshot, serializeSmrtGenerationSnapshot, sha256SmrtGenerationSnapshot } from "../generation-snapshot.js";
|
|
4
7
|
import { resolveFileKnowledgeConfig } from "../knowledge-config.js";
|
|
5
8
|
import { generateClientModule } from "../vite-plugin/generated-client.js";
|
|
9
|
+
import { activeProducerKnowledgeRoutePaths, activeSvelteKitRouteParticipants, assertNoSvelteKitRouteRootSymlinkConflict, assertSvelteKitRouteCoordinationComplete, contributeSvelteKitRoutes, expectedSvelteKitRouteOwners, markSvelteKitRouteParticipant, producerKnowledgeRoutePaths, revokeSvelteKitRoutes } from "../vite-plugin/sveltekit-route-coordinator.js";
|
|
6
10
|
import { generateDeclarations } from "../prebuild/index.js";
|
|
7
11
|
import { publishArtifactFiles } from "./artifact-publication.js";
|
|
8
12
|
import * as fs from "node:fs";
|
|
@@ -17,27 +21,220 @@ var VIRTUAL_MODULES = {
|
|
|
17
21
|
"@smrt/client": "smrt-consumer:client",
|
|
18
22
|
"@smrt/mcp": "smrt-consumer:mcp",
|
|
19
23
|
"@smrt/types": "smrt-consumer:types",
|
|
20
|
-
"@smrt/manifest": "smrt-consumer:manifest"
|
|
24
|
+
"@smrt/manifest": "smrt-consumer:manifest",
|
|
25
|
+
"@smrt/web": "smrt-consumer:web"
|
|
21
26
|
};
|
|
27
|
+
var CONSUMER_SVELTEKIT_ROUTES_ARTIFACT_VERSION = 1;
|
|
28
|
+
var CONSUMER_SVELTEKIT_ROUTES_ARTIFACT = "consumer-sveltekit-routes.json";
|
|
29
|
+
function consumerSvelteKitRoutesArtifactPath(projectRoot) {
|
|
30
|
+
return path.join(projectRoot, ".smrt", CONSUMER_SVELTEKIT_ROUTES_ARTIFACT);
|
|
31
|
+
}
|
|
32
|
+
/** Persist only project-relative consumer route roots, never an output file list. */
|
|
33
|
+
function canonicalConsumerRouteRoot(projectRoot, routesDir) {
|
|
34
|
+
const root = path.resolve(projectRoot);
|
|
35
|
+
const relative = path.relative(root, path.resolve(root, routesDir));
|
|
36
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) throw new Error(`[smrt:consumer] svelteKit.routesDir must be a project-relative subdirectory (received ${JSON.stringify(routesDir)})`);
|
|
37
|
+
return relative.split(path.sep).join("/");
|
|
38
|
+
}
|
|
39
|
+
function loadConsumerSvelteKitRouteRoots(projectRoot) {
|
|
40
|
+
const artifactPath = consumerSvelteKitRoutesArtifactPath(projectRoot);
|
|
41
|
+
if (!fs.existsSync(artifactPath)) return [];
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(fs.readFileSync(artifactPath, "utf-8"));
|
|
45
|
+
} catch {
|
|
46
|
+
throw new Error(`[smrt:consumer] Cannot read ${CONSUMER_SVELTEKIT_ROUTES_ARTIFACT}; refusing to leave hosted routes unreconciled`);
|
|
47
|
+
}
|
|
48
|
+
if (parsed?.version !== CONSUMER_SVELTEKIT_ROUTES_ARTIFACT_VERSION || !Array.isArray(parsed.routesDir) || parsed.routesDir.some((routesDir) => typeof routesDir !== "string")) throw new Error(`[smrt:consumer] Invalid ${CONSUMER_SVELTEKIT_ROUTES_ARTIFACT}; refusing to leave hosted routes unreconciled`);
|
|
49
|
+
return [...new Set(parsed.routesDir)].map((routesDir) => canonicalConsumerRouteRoot(projectRoot, routesDir));
|
|
50
|
+
}
|
|
51
|
+
function publishConsumerSvelteKitRouteRoots(projectRoot, routesDir) {
|
|
52
|
+
const artifactPath = consumerSvelteKitRoutesArtifactPath(projectRoot);
|
|
53
|
+
fs.mkdirSync(path.dirname(artifactPath), { recursive: true });
|
|
54
|
+
publishArtifactFiles([{
|
|
55
|
+
path: artifactPath,
|
|
56
|
+
content: JSON.stringify({
|
|
57
|
+
version: CONSUMER_SVELTEKIT_ROUTES_ARTIFACT_VERSION,
|
|
58
|
+
routesDir: [...new Set(routesDir)].sort()
|
|
59
|
+
}, null, 2)
|
|
60
|
+
}]);
|
|
61
|
+
}
|
|
62
|
+
function removeConsumerSvelteKitRouteRoots(projectRoot) {
|
|
63
|
+
const artifactPath = consumerSvelteKitRoutesArtifactPath(projectRoot);
|
|
64
|
+
if (fs.existsSync(artifactPath)) fs.unlinkSync(artifactPath);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A hosting-to-hosting move can replace one configured root with another in a
|
|
68
|
+
* fresh lifecycle. Validate every durable former root before the new target
|
|
69
|
+
* journals or clears anything, otherwise a rejected move could alter the
|
|
70
|
+
* prior generated surface before reconciliation notices the conflict.
|
|
71
|
+
*/
|
|
72
|
+
async function assertConsumerSvelteKitFormerRouteRootsAreSafe(userConfig, projectRoot, routesDir, env) {
|
|
73
|
+
if (routesDir.length === 0) return;
|
|
74
|
+
const activeRoots = (await activeSvelteKitRouteParticipants(userConfig, projectRoot, env)).map((participant) => participant.routesDir);
|
|
75
|
+
for (const priorRoutesDir of routesDir) assertNoSvelteKitRouteRootSymlinkConflict(canonicalSvelteKitPath(path.resolve(projectRoot, priorRoutesDir)), activeRoots);
|
|
76
|
+
}
|
|
77
|
+
async function reconcileConsumerSvelteKitRouteRoots(lifecycle, userConfig, projectRoot, routesDir, afterReconciled, env) {
|
|
78
|
+
const remaining = new Set(routesDir);
|
|
79
|
+
const reconcileOne = (routesDir) => {
|
|
80
|
+
remaining.delete(routesDir);
|
|
81
|
+
if (remaining.size === 0) afterReconciled();
|
|
82
|
+
};
|
|
83
|
+
if (remaining.size === 0) {
|
|
84
|
+
afterReconciled();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
for (const routesDir of [...remaining]) {
|
|
88
|
+
const routeRoot = canonicalSvelteKitPath(path.resolve(projectRoot, routesDir));
|
|
89
|
+
const activeParticipants = await activeSvelteKitRouteParticipants(userConfig, projectRoot, env);
|
|
90
|
+
assertNoSvelteKitRouteRootSymlinkConflict(routeRoot, activeParticipants.map((participant) => participant.routesDir));
|
|
91
|
+
if (activeParticipants.find((participant) => participant.owner === "consumer" && (routeRoot === participant.routesDir || routeRoot.startsWith(`${participant.routesDir}${path.sep}`)))) {
|
|
92
|
+
reconcileOne(routesDir);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const containingProducer = activeParticipants.find((participant) => participant.owner === "producer" && (routeRoot === participant.routesDir || routeRoot.startsWith(`${participant.routesDir}${path.sep}`)));
|
|
96
|
+
if (containingProducer) {
|
|
97
|
+
await revokeSvelteKitRoutes(lifecycle, await expectedSvelteKitRouteOwners(userConfig, containingProducer.projectRoot, containingProducer.routesDir, env), containingProducer.projectRoot, containingProducer.routesDir, () => reconcileOne(routesDir));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const owners = await expectedSvelteKitRouteOwners(userConfig, projectRoot, routesDir, env);
|
|
101
|
+
if (owners.includes("producer")) {
|
|
102
|
+
await revokeSvelteKitRoutes(lifecycle, owners, projectRoot, routesDir, () => reconcileOne(routesDir));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
clearGeneratedSvelteKitRouteFiles(routeRoot, producerKnowledgeRoutePaths(lifecycle), new Set(activeParticipants.map((participant) => participant.routesDir).filter((activeRoot) => activeRoot !== routeRoot)));
|
|
106
|
+
reconcileSvelteKitRouteGitignore(projectRoot, routesDir);
|
|
107
|
+
reconcileOne(routesDir);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function consumerRouteOptions(value) {
|
|
111
|
+
if (!value || value === true) return void 0;
|
|
112
|
+
if (!Array.isArray(value.objects) || value.objects.length === 0) throw new Error("[smrt:consumer] svelteKit.objects must list at least one provider-qualified object reference");
|
|
113
|
+
for (const objectRef of value.objects) if (typeof objectRef !== "string" || !objectRef.includes(":")) throw new Error(`[smrt:consumer] svelteKit.objects entries must be provider-qualified (received ${JSON.stringify(objectRef)})`);
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
function consumerUtilityOption(value) {
|
|
117
|
+
return value?.enabled === true ? value : { enabled: false };
|
|
118
|
+
}
|
|
119
|
+
function consumerObjectRef(manifestKey, objectDef) {
|
|
120
|
+
if (manifestKey.includes(":")) return manifestKey;
|
|
121
|
+
if (objectDef.qualifiedName?.includes(":")) return objectDef.qualifiedName;
|
|
122
|
+
if (objectDef.packageName && objectDef.className) return `${objectDef.packageName}:${objectDef.className}`;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Select exactly the dependency objects that a consumer explicitly hosts.
|
|
126
|
+
* Validation completes before the generator clears its managed files, so an
|
|
127
|
+
* invalid deployment cannot erase a previously generated route surface.
|
|
128
|
+
*/
|
|
129
|
+
function selectConsumerRouteManifest(manifest, options) {
|
|
130
|
+
const entriesByRef = /* @__PURE__ */ new Map();
|
|
131
|
+
for (const [manifestKey, objectDef] of Object.entries(manifest.objects)) {
|
|
132
|
+
const objectRef = consumerObjectRef(manifestKey, objectDef);
|
|
133
|
+
if (objectRef) entriesByRef.set(objectRef, [manifestKey, objectDef]);
|
|
134
|
+
}
|
|
135
|
+
const selected = /* @__PURE__ */ new Set();
|
|
136
|
+
const objects = {};
|
|
137
|
+
for (const objectRef of options.objects) {
|
|
138
|
+
const entry = entriesByRef.get(objectRef);
|
|
139
|
+
if (!entry) throw new Error(`[smrt:consumer] svelteKit.objects references unknown dependency object ${JSON.stringify(objectRef)}`);
|
|
140
|
+
if (selected.has(objectRef)) throw new Error(`[smrt:consumer] svelteKit.objects contains duplicate object ${JSON.stringify(objectRef)}`);
|
|
141
|
+
selected.add(objectRef);
|
|
142
|
+
const [, objectDef] = entry;
|
|
143
|
+
objects[objectRef] = {
|
|
144
|
+
...objectDef,
|
|
145
|
+
qualifiedName: objectRef
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const sourceManifest = manifest;
|
|
149
|
+
for (const [manifestKey, objectDef] of Object.entries(manifest.objects)) {
|
|
150
|
+
const candidate = objectDef;
|
|
151
|
+
if (!isCollectionManifestClass(sourceManifest, candidate)) continue;
|
|
152
|
+
const item = resolveCollectionItemObject(sourceManifest, candidate);
|
|
153
|
+
const itemEntry = item ? Object.entries(manifest.objects).find(([, value]) => value === item) : void 0;
|
|
154
|
+
const itemRef = itemEntry ? consumerObjectRef(itemEntry[0], itemEntry[1]) : void 0;
|
|
155
|
+
if (!itemRef || !selected.has(itemRef)) continue;
|
|
156
|
+
const collectionRef = consumerObjectRef(manifestKey, objectDef);
|
|
157
|
+
if (collectionRef) objects[collectionRef] = {
|
|
158
|
+
...objectDef,
|
|
159
|
+
qualifiedName: collectionRef
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
...manifest,
|
|
164
|
+
smrtDependencies: [...new Set(Object.values(manifest.objects).map((objectDef) => objectDef.packageName).filter((packageName) => typeof packageName === "string" && packageName !== manifest.packageName))].sort(),
|
|
165
|
+
objects
|
|
166
|
+
};
|
|
167
|
+
}
|
|
22
168
|
/**
|
|
23
169
|
* Consumer plugin for projects that use SMRT packages
|
|
24
170
|
*/
|
|
25
171
|
function smrtConsumer(options = {}) {
|
|
26
172
|
const { packages = [], generateTypes = true, typesDir = "src/types/smrt-generated", projectRoot = process.cwd(), generationSnapshot, disableScanning = false, kebabRoutes = false } = options;
|
|
173
|
+
const consumerSvelteKit = consumerRouteOptions(options.svelteKit);
|
|
174
|
+
const effectiveKebabRoutes = consumerSvelteKit?.kebabRoutes ?? kebabRoutes;
|
|
27
175
|
let smrtPackages = [];
|
|
28
176
|
let typeManifest = null;
|
|
29
177
|
let typesGenerated = false;
|
|
30
178
|
let producerApi;
|
|
179
|
+
let routeLifecycleConfig;
|
|
31
180
|
function loadGenerationSnapshot() {
|
|
32
181
|
if (!generationSnapshot) throw new Error("[smrt:consumer] Generation snapshot is not configured");
|
|
33
182
|
return loadVerifiedSmrtGenerationSnapshot(generationSnapshot, projectRoot, "dependencies");
|
|
34
183
|
}
|
|
35
|
-
|
|
184
|
+
const plugin = {
|
|
36
185
|
name: "smrt-consumer",
|
|
37
|
-
|
|
38
|
-
|
|
186
|
+
enforce: "pre",
|
|
187
|
+
config: {
|
|
188
|
+
order: "pre",
|
|
189
|
+
async handler(userConfig, env) {
|
|
190
|
+
const routeLifecycle = env ?? userConfig;
|
|
191
|
+
routeLifecycleConfig = routeLifecycle;
|
|
192
|
+
const previousConsumerRouteRoots = loadConsumerSvelteKitRouteRoots(projectRoot);
|
|
193
|
+
if (consumerSvelteKit) {
|
|
194
|
+
await assertConsumerSvelteKitFormerRouteRootsAreSafe(userConfig, projectRoot, previousConsumerRouteRoots, env);
|
|
195
|
+
const routePackages = packages.length === 0 && !disableScanning ? await discoverSmrtPackages(projectRoot) : packages;
|
|
196
|
+
const routeManifest = generationSnapshot ? loadGenerationSnapshot() : await aggregateTypeManifests(routePackages, projectRoot);
|
|
197
|
+
const hostedManifest = selectConsumerRouteManifest(routeManifest, consumerSvelteKit);
|
|
198
|
+
const routesDir = canonicalConsumerRouteRoot(projectRoot, consumerSvelteKit.routesDir ?? "src/routes/api");
|
|
199
|
+
const reservedRoutePaths = await activeProducerKnowledgeRoutePaths(userConfig, projectRoot, env);
|
|
200
|
+
const routeOptions = {
|
|
201
|
+
enabled: true,
|
|
202
|
+
routesDir,
|
|
203
|
+
objectsDir: "src/lib/objects",
|
|
204
|
+
configPath: consumerSvelteKit.configPath ?? "src/lib/server",
|
|
205
|
+
configFileName: consumerSvelteKit.configFileName ?? "smrt.ts",
|
|
206
|
+
kebabRoutes: effectiveKebabRoutes,
|
|
207
|
+
changesRoute: consumerUtilityOption(consumerSvelteKit.changesRoute),
|
|
208
|
+
eventsRoute: consumerUtilityOption(consumerSvelteKit.eventsRoute),
|
|
209
|
+
resourcesRoute: consumerUtilityOption(consumerSvelteKit.resourcesRoute),
|
|
210
|
+
rejectRouteCollisions: true
|
|
211
|
+
};
|
|
212
|
+
let ownershipJournaled = false;
|
|
213
|
+
let reconciliationScheduled = false;
|
|
214
|
+
await contributeSvelteKitRoutes(routeLifecycle, await expectedSvelteKitRouteOwners(userConfig, projectRoot, routeOptions.routesDir, env), projectRoot, {
|
|
215
|
+
owner: "consumer",
|
|
216
|
+
routeManifest: hostedManifest,
|
|
217
|
+
semanticManifest: routeManifest,
|
|
218
|
+
options: routeOptions,
|
|
219
|
+
reservedRoutePaths,
|
|
220
|
+
beforeCleanup: () => {
|
|
221
|
+
if (ownershipJournaled) return;
|
|
222
|
+
ownershipJournaled = true;
|
|
223
|
+
publishConsumerSvelteKitRouteRoots(projectRoot, [...previousConsumerRouteRoots, routesDir]);
|
|
224
|
+
},
|
|
225
|
+
afterGenerate: async () => {
|
|
226
|
+
if (reconciliationScheduled) return;
|
|
227
|
+
reconciliationScheduled = true;
|
|
228
|
+
const priorRoots = previousConsumerRouteRoots.filter((previousRoot) => previousRoot !== routesDir);
|
|
229
|
+
await reconcileConsumerSvelteKitRouteRoots(routeLifecycle, userConfig, projectRoot, priorRoots, () => publishConsumerSvelteKitRouteRoots(projectRoot, [routesDir]), env);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
} else if (previousConsumerRouteRoots.length > 0) await reconcileConsumerSvelteKitRouteRoots(routeLifecycle, userConfig, projectRoot, previousConsumerRouteRoots, () => removeConsumerSvelteKitRouteRoots(projectRoot), env);
|
|
233
|
+
return { build: { rollupOptions: { external: [/\.node$/] } } };
|
|
234
|
+
}
|
|
39
235
|
},
|
|
40
236
|
configResolved(resolvedConfig) {
|
|
237
|
+
if (consumerSvelteKit && routeLifecycleConfig) assertSvelteKitRouteCoordinationComplete(routeLifecycleConfig);
|
|
41
238
|
producerApi = (resolvedConfig.plugins ?? []).find((plugin) => plugin?.name === "smrt-auto-service")?.api;
|
|
42
239
|
},
|
|
43
240
|
async buildStart() {
|
|
@@ -75,6 +272,7 @@ function smrtConsumer(options = {}) {
|
|
|
75
272
|
},
|
|
76
273
|
resolveId(id, _importer) {
|
|
77
274
|
if (id in VIRTUAL_MODULES) {
|
|
275
|
+
if (id !== "@smrt/types") return `\0${VIRTUAL_MODULES[id]}`;
|
|
78
276
|
const typeFileName = getTypeFileName(id);
|
|
79
277
|
const typePath = path.join(projectRoot, typesDir, typeFileName);
|
|
80
278
|
if (fs.existsSync(typePath)) return typePath;
|
|
@@ -91,14 +289,17 @@ function smrtConsumer(options = {}) {
|
|
|
91
289
|
};
|
|
92
290
|
switch (cleanId) {
|
|
93
291
|
case "smrt-consumer:routes": return generateFallbackRoutesModule();
|
|
94
|
-
case "smrt-consumer:client": return generateFallbackClientModule(typeManifest, { kebabRoutes });
|
|
292
|
+
case "smrt-consumer:client": return generateFallbackClientModule(typeManifest, { kebabRoutes: effectiveKebabRoutes });
|
|
95
293
|
case "smrt-consumer:mcp": return generateFallbackMcpModule();
|
|
96
294
|
case "smrt-consumer:types": return generateFallbackTypesModule(typeManifest);
|
|
97
295
|
case "smrt-consumer:manifest": return generateFallbackManifestModule(typeManifest);
|
|
296
|
+
case "smrt-consumer:web": return generateWebModule(typeManifest, { kebabRoutes: effectiveKebabRoutes });
|
|
98
297
|
default: return null;
|
|
99
298
|
}
|
|
100
299
|
}
|
|
101
300
|
};
|
|
301
|
+
markSvelteKitRouteParticipant(plugin, "consumer", Boolean(consumerSvelteKit), consumerSvelteKit?.routesDir ?? "src/routes/api", void 0, () => projectRoot);
|
|
302
|
+
return plugin;
|
|
102
303
|
}
|
|
103
304
|
/**
|
|
104
305
|
* Discover SMRT packages from a consumer app's dependencies.
|
|
@@ -146,6 +347,7 @@ async function aggregateTypeManifests(packages, projectRoot) {
|
|
|
146
347
|
const aggregatedManifest = {
|
|
147
348
|
version: "1.0.0",
|
|
148
349
|
timestamp: 0,
|
|
350
|
+
smrtDependencies: [...packages],
|
|
149
351
|
objects: {}
|
|
150
352
|
};
|
|
151
353
|
for (const packageName of packages) try {
|
|
@@ -430,7 +632,8 @@ function getTypeFileName(virtualModule) {
|
|
|
430
632
|
"@smrt/client": "smrt-client.d.ts",
|
|
431
633
|
"@smrt/mcp": "smrt-mcp.d.ts",
|
|
432
634
|
"@smrt/types": "smrt-types.d.ts",
|
|
433
|
-
"@smrt/manifest": "smrt-manifest.d.ts"
|
|
635
|
+
"@smrt/manifest": "smrt-manifest.d.ts",
|
|
636
|
+
"@smrt/web": "smrt-web.d.ts"
|
|
434
637
|
}[virtualModule] || "smrt-unknown.d.ts";
|
|
435
638
|
}
|
|
436
639
|
/**
|