@happyvertical/smrt-core 0.49.5 → 0.49.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -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 +214 -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 +5 -4
- 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 +25 -40
- 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/package.json +6 -5
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifies an output path by its physical location without requiring the
|
|
3
|
+
* final generated directory to exist. Resolving the nearest existing ancestor
|
|
4
|
+
* follows symlinks in either an artifact root or a route-path segment, then
|
|
5
|
+
* appends the prospective descendants unchanged.
|
|
6
|
+
*/
|
|
7
|
+
export declare function canonicalSvelteKitPath(path: string): string;
|
|
8
|
+
//# sourceMappingURL=sveltekit-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-path.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/sveltekit-path.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa3D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, resolve } from "node:path";
|
|
3
|
+
//#region src/vite-plugin/sveltekit-path.ts
|
|
4
|
+
/**
|
|
5
|
+
* Identifies an output path by its physical location without requiring the
|
|
6
|
+
* final generated directory to exist. Resolving the nearest existing ancestor
|
|
7
|
+
* follows symlinks in either an artifact root or a route-path segment, then
|
|
8
|
+
* appends the prospective descendants unchanged.
|
|
9
|
+
*/
|
|
10
|
+
function canonicalSvelteKitPath(path) {
|
|
11
|
+
const descendants = [];
|
|
12
|
+
let existing = resolve(path);
|
|
13
|
+
while (!existsSync(existing)) {
|
|
14
|
+
const parent = dirname(existing);
|
|
15
|
+
if (parent === existing) return existing;
|
|
16
|
+
descendants.unshift(basename(existing));
|
|
17
|
+
existing = parent;
|
|
18
|
+
}
|
|
19
|
+
const physical = realpathSync.native(existing);
|
|
20
|
+
return descendants.length === 0 ? physical : resolve(physical, ...descendants);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { canonicalSvelteKitPath };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=sveltekit-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-path.js","names":[],"sources":["../../src/vite-plugin/sveltekit-path.ts"],"sourcesContent":["import { existsSync, realpathSync } from 'node:fs';\nimport { basename, dirname, resolve } from 'node:path';\n\n/**\n * Identifies an output path by its physical location without requiring the\n * final generated directory to exist. Resolving the nearest existing ancestor\n * follows symlinks in either an artifact root or a route-path segment, then\n * appends the prospective descendants unchanged.\n */\nexport function canonicalSvelteKitPath(path: string): string {\n const descendants: string[] = [];\n let existing = resolve(path);\n while (!existsSync(existing)) {\n const parent = dirname(existing);\n if (parent === existing) return existing;\n descendants.unshift(basename(existing));\n existing = parent;\n }\n const physical = realpathSync.native(existing);\n return descendants.length === 0\n ? physical\n : resolve(physical, ...descendants);\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,uBAAuB,MAAsB;CAC3D,MAAM,cAAwB,CAAC;CAC/B,IAAI,WAAW,QAAQ,IAAI;CAC3B,OAAO,CAAC,WAAW,QAAQ,GAAG;EAC5B,MAAM,SAAS,QAAQ,QAAQ;EAC/B,IAAI,WAAW,UAAU,OAAO;EAChC,YAAY,QAAQ,SAAS,QAAQ,CAAC;EACtC,WAAW;CACb;CACA,MAAM,WAAW,aAAa,OAAO,QAAQ;CAC7C,OAAO,YAAY,WAAW,IAC1B,WACA,QAAQ,UAAU,GAAG,WAAW;AACtC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ConfigEnv, Plugin } from 'vite';
|
|
2
|
+
import { SmartObjectManifest } from '../scanner/types.js';
|
|
3
|
+
import { SvelteKitOptions } from './sveltekit-generator.js';
|
|
4
|
+
export type SvelteKitRouteOwner = 'producer' | 'consumer';
|
|
5
|
+
interface RouteContribution {
|
|
6
|
+
owner: SvelteKitRouteOwner;
|
|
7
|
+
/** Keep the caller's lexical artifact root for its resolved output context. */
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
routeManifest: SmartObjectManifest;
|
|
10
|
+
semanticManifest: SmartObjectManifest;
|
|
11
|
+
options: SvelteKitOptions;
|
|
12
|
+
reservedRoutePaths?: ReadonlySet<string>;
|
|
13
|
+
beforeCleanup?: () => void | Promise<void>;
|
|
14
|
+
afterGenerate?: () => void | Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
type RouteContributionInput = Omit<RouteContribution, 'projectRoot'>;
|
|
17
|
+
export interface ActiveSvelteKitRouteParticipant {
|
|
18
|
+
owner: SvelteKitRouteOwner;
|
|
19
|
+
projectRoot: string;
|
|
20
|
+
routesDir: string;
|
|
21
|
+
resolveKnowledge?: ProducerKnowledgeResolver;
|
|
22
|
+
}
|
|
23
|
+
type ProducerKnowledgeResolver = (projectRoot: string) => Promise<{
|
|
24
|
+
api?: {
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
basePath?: string;
|
|
27
|
+
};
|
|
28
|
+
}>;
|
|
29
|
+
type ProjectRootResolver = (userConfig: unknown) => string;
|
|
30
|
+
/** Marks an enabled plugin instance so only real same-target participants block
|
|
31
|
+
* the initial shared route transaction. The marker is intentionally private to
|
|
32
|
+
* the plugin objects supplied to one Vite config invocation. */
|
|
33
|
+
export declare function markSvelteKitRouteParticipant(plugin: Plugin, owner: SvelteKitRouteOwner, enabled: boolean, routesDir: string, resolveKnowledge?: ProducerKnowledgeResolver, resolveProjectRoot?: ProjectRootResolver): void;
|
|
34
|
+
export declare function expectedSvelteKitRouteOwners(userConfig: unknown, projectRoot: string, routesDir: string, env?: ConfigEnv): Promise<SvelteKitRouteOwner[]>;
|
|
35
|
+
/** Active roots are either one shared target or separate directory owners. */
|
|
36
|
+
export declare function activeSvelteKitRouteParticipants(userConfig: unknown, projectRoot: string, env?: ConfigEnv): Promise<ActiveSvelteKitRouteParticipant[]>;
|
|
37
|
+
/**
|
|
38
|
+
* A durable consumer ownership record can outlive the route configuration
|
|
39
|
+
* that created it. Reconciliation uses this same guard before it sweeps a
|
|
40
|
+
* former lexical root, so an old child symlink cannot cross into a current
|
|
41
|
+
* active route surface and make the journal's ownership ambiguous.
|
|
42
|
+
*/
|
|
43
|
+
export declare function assertNoSvelteKitRouteRootSymlinkConflict(routeRoot: string, foreignRouteRoots: Iterable<string>): void;
|
|
44
|
+
/**
|
|
45
|
+
* Bind generated route ownership to one Vite configuration lifecycle. Both
|
|
46
|
+
* SMRT plugins run pre-config hooks, so the later hook regenerates the complete
|
|
47
|
+
* current plan rather than deleting the earlier plugin's route files.
|
|
48
|
+
*/
|
|
49
|
+
export declare function contributeSvelteKitRoutes(lifecycle: object, expectedOwners: Iterable<SvelteKitRouteOwner>, projectRoot: string, contribution: RouteContributionInput): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Reconcile a disabled consumer's formerly hosted route root through the
|
|
52
|
+
* active target transaction. This lets a current producer re-emit its own
|
|
53
|
+
* surface rather than a later consumer cleanup deleting it.
|
|
54
|
+
*/
|
|
55
|
+
export declare function revokeSvelteKitRoutes(lifecycle: object, expectedOwners: Iterable<SvelteKitRouteOwner>, projectRoot: string, routesDir: string, afterGenerate?: () => void | Promise<void>): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Config hooks are the primary synchronization point because SvelteKit reads
|
|
58
|
+
* its route inventory immediately afterwards. This is a fail-closed backstop
|
|
59
|
+
* for Vite configurations where a marked, active peer never ran its hook.
|
|
60
|
+
*/
|
|
61
|
+
export declare function assertSvelteKitRouteCoordinationComplete(lifecycle: object): void;
|
|
62
|
+
/** Current producer-owned knowledge handlers, which may sit outside its API root. */
|
|
63
|
+
export declare function producerKnowledgeRoutePaths(lifecycle: object): Set<string>;
|
|
64
|
+
/** Resolve active producer knowledge claims before consumer route mutation. */
|
|
65
|
+
export declare function activeProducerKnowledgeRoutePaths(userConfig: unknown, projectRoot: string, env?: ConfigEnv): Promise<Set<string>>;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=sveltekit-route-coordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-route-coordinator.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/sveltekit-route-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { canonicalSvelteKitPath } from "./sveltekit-path.js";
|
|
2
|
+
import { assertNoCrossObjectRouteCollisions, generateSvelteKitRoutes, knowledgeRoutePath } from "./sveltekit-generator.js";
|
|
3
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
4
|
+
import { join, relative, resolve, sep } from "node:path";
|
|
5
|
+
//#region src/vite-plugin/sveltekit-route-coordinator.ts
|
|
6
|
+
var ROUTE_PARTICIPANT = Symbol("smrt.sveltekit-route-participant");
|
|
7
|
+
var coordinators = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
/** Marks an enabled plugin instance so only real same-target participants block
|
|
9
|
+
* the initial shared route transaction. The marker is intentionally private to
|
|
10
|
+
* the plugin objects supplied to one Vite config invocation. */
|
|
11
|
+
function markSvelteKitRouteParticipant(plugin, owner, enabled, routesDir, resolveKnowledge, resolveProjectRoot) {
|
|
12
|
+
Object.defineProperty(plugin, ROUTE_PARTICIPANT, {
|
|
13
|
+
value: {
|
|
14
|
+
owner,
|
|
15
|
+
enabled,
|
|
16
|
+
routesDir,
|
|
17
|
+
resolveKnowledge,
|
|
18
|
+
resolveProjectRoot
|
|
19
|
+
},
|
|
20
|
+
enumerable: false
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function expectedSvelteKitRouteOwners(userConfig, projectRoot, routesDir, env) {
|
|
24
|
+
const participants = await activeSvelteKitRouteParticipants(userConfig, projectRoot, env);
|
|
25
|
+
assertCompatibleSvelteKitRouteTargets(participants);
|
|
26
|
+
const target = canonicalSvelteKitPath(resolve(projectRoot, routesDir));
|
|
27
|
+
const owners = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const participant of participants) if (participant.routesDir === target) owners.add(participant.owner);
|
|
29
|
+
return [...owners];
|
|
30
|
+
}
|
|
31
|
+
/** Mirrors Vite's supported recursive PluginOption normalization for config hooks. */
|
|
32
|
+
async function flattenPluginOptions(value) {
|
|
33
|
+
let values = Array.isArray(value) ? value : [];
|
|
34
|
+
do
|
|
35
|
+
values = (await Promise.all(values)).flat(Infinity);
|
|
36
|
+
while (values.some((entry) => entry && typeof entry.then === "function"));
|
|
37
|
+
return values.filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
/** Applies the same supported `Plugin.apply` gate Vite uses before config hooks. */
|
|
40
|
+
function appliesToConfig(plugin, userConfig, env) {
|
|
41
|
+
const apply = plugin.apply;
|
|
42
|
+
if (!apply) return true;
|
|
43
|
+
if (!env) return false;
|
|
44
|
+
if (typeof apply === "function") return apply({
|
|
45
|
+
...userConfig ?? {},
|
|
46
|
+
mode: env.mode
|
|
47
|
+
}, env);
|
|
48
|
+
return apply === env.command;
|
|
49
|
+
}
|
|
50
|
+
/** Active roots are either one shared target or separate directory owners. */
|
|
51
|
+
async function activeSvelteKitRouteParticipants(userConfig, projectRoot, env) {
|
|
52
|
+
const plugins = await flattenPluginOptions(userConfig?.plugins);
|
|
53
|
+
const participants = [];
|
|
54
|
+
for (const plugin of plugins) {
|
|
55
|
+
if (!appliesToConfig(plugin, userConfig, env)) continue;
|
|
56
|
+
const participant = plugin?.[ROUTE_PARTICIPANT];
|
|
57
|
+
if (!participant?.enabled) continue;
|
|
58
|
+
const participantRoot = canonicalSvelteKitPath(participant.resolveProjectRoot?.(userConfig) ?? projectRoot);
|
|
59
|
+
participants.push({
|
|
60
|
+
owner: participant.owner,
|
|
61
|
+
projectRoot: participantRoot,
|
|
62
|
+
routesDir: canonicalSvelteKitPath(resolve(participantRoot, participant.routesDir)),
|
|
63
|
+
resolveKnowledge: participant.resolveKnowledge
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return participants;
|
|
67
|
+
}
|
|
68
|
+
function assertCompatibleSvelteKitRouteTargets(participants) {
|
|
69
|
+
for (const [index, first] of participants.entries()) for (const second of participants.slice(index + 1)) {
|
|
70
|
+
if (first.routesDir === second.routesDir) continue;
|
|
71
|
+
if (second.routesDir.startsWith(`${first.routesDir}${sep}`) || first.routesDir.startsWith(`${second.routesDir}${sep}`)) throw new Error(`[smrt] Incompatible nested SvelteKit routesDir ownership: ${JSON.stringify(first.routesDir)} and ${JSON.stringify(second.routesDir)}. Use one shared routesDir or disjoint directories.`);
|
|
72
|
+
}
|
|
73
|
+
assertNoSymlinkedSvelteKitRouteTargetConflicts(participants);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Route generation and SvelteKit both traverse directory symlinks. A lexical
|
|
77
|
+
* disjointness check alone therefore cannot let one active route root recurse
|
|
78
|
+
* into another active root during cleanup.
|
|
79
|
+
*/
|
|
80
|
+
function assertNoSymlinkedSvelteKitRouteTargetConflicts(participants) {
|
|
81
|
+
for (const participant of participants) {
|
|
82
|
+
const foreignRoots = participants.filter(({ routesDir }) => routesDir !== participant.routesDir).map(({ routesDir }) => routesDir);
|
|
83
|
+
if (foreignRoots.length === 0) continue;
|
|
84
|
+
assertRouteTreeDoesNotReachForeignRoot(participant.routesDir, foreignRoots, /* @__PURE__ */ new Set());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A durable consumer ownership record can outlive the route configuration
|
|
89
|
+
* that created it. Reconciliation uses this same guard before it sweeps a
|
|
90
|
+
* former lexical root, so an old child symlink cannot cross into a current
|
|
91
|
+
* active route surface and make the journal's ownership ambiguous.
|
|
92
|
+
*/
|
|
93
|
+
function assertNoSvelteKitRouteRootSymlinkConflict(routeRoot, foreignRouteRoots) {
|
|
94
|
+
const foreignRoots = [...foreignRouteRoots].filter((candidate) => candidate !== canonicalSvelteKitPath(routeRoot));
|
|
95
|
+
if (foreignRoots.length === 0) return;
|
|
96
|
+
assertRouteTreeDoesNotReachForeignRoot(routeRoot, foreignRoots, /* @__PURE__ */ new Set());
|
|
97
|
+
}
|
|
98
|
+
function assertRouteTreeDoesNotReachForeignRoot(routeRoot, foreignRoots, visitedRoots) {
|
|
99
|
+
const canonicalRoot = canonicalSvelteKitPath(routeRoot);
|
|
100
|
+
if (visitedRoots.has(canonicalRoot) || !existsSync(routeRoot)) return;
|
|
101
|
+
visitedRoots.add(canonicalRoot);
|
|
102
|
+
for (const entry of readdirSync(routeRoot, { withFileTypes: true })) {
|
|
103
|
+
const entryPath = join(routeRoot, entry.name);
|
|
104
|
+
if (entry.isDirectory()) {
|
|
105
|
+
assertRouteTreeDoesNotReachForeignRoot(entryPath, foreignRoots, visitedRoots);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!entry.isSymbolicLink()) continue;
|
|
109
|
+
try {
|
|
110
|
+
if (!statSync(entryPath).isDirectory()) continue;
|
|
111
|
+
} catch {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const canonicalEntry = canonicalSvelteKitPath(entryPath);
|
|
115
|
+
const foreignRoot = foreignRoots.find((candidate) => svelteKitPathsOverlap(canonicalEntry, candidate));
|
|
116
|
+
if (foreignRoot) throw new Error(`[smrt] Incompatible SvelteKit routesDir ownership: ${JSON.stringify(routeRoot)} reaches active ${JSON.stringify(foreignRoot)} through directory symlink ${JSON.stringify(entryPath)}. Use one shared routesDir or disjoint physical directories.`);
|
|
117
|
+
assertRouteTreeDoesNotReachForeignRoot(entryPath, foreignRoots, visitedRoots);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function svelteKitPathsOverlap(first, second) {
|
|
121
|
+
return first === second || first.startsWith(`${second}${sep}`) || second.startsWith(`${first}${sep}`);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Bind generated route ownership to one Vite configuration lifecycle. Both
|
|
125
|
+
* SMRT plugins run pre-config hooks, so the later hook regenerates the complete
|
|
126
|
+
* current plan rather than deleting the earlier plugin's route files.
|
|
127
|
+
*/
|
|
128
|
+
async function contributeSvelteKitRoutes(lifecycle, expectedOwners, projectRoot, contribution) {
|
|
129
|
+
const target = routeTarget(projectRoot, contribution.options.routesDir);
|
|
130
|
+
const sessions = coordinators.get(lifecycle) ?? /* @__PURE__ */ new Map();
|
|
131
|
+
coordinators.set(lifecycle, sessions);
|
|
132
|
+
const coordinator = sessions.get(target) ?? {
|
|
133
|
+
contributions: /* @__PURE__ */ new Map(),
|
|
134
|
+
expectedOwners: new Set(expectedOwners),
|
|
135
|
+
afterRevocation: []
|
|
136
|
+
};
|
|
137
|
+
sessions.set(target, coordinator);
|
|
138
|
+
coordinator.contributions.set(contribution.owner, {
|
|
139
|
+
...contribution,
|
|
140
|
+
projectRoot
|
|
141
|
+
});
|
|
142
|
+
await generateWhenReady(sessions, coordinator, projectRoot);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Reconcile a disabled consumer's formerly hosted route root through the
|
|
146
|
+
* active target transaction. This lets a current producer re-emit its own
|
|
147
|
+
* surface rather than a later consumer cleanup deleting it.
|
|
148
|
+
*/
|
|
149
|
+
async function revokeSvelteKitRoutes(lifecycle, expectedOwners, projectRoot, routesDir, afterGenerate) {
|
|
150
|
+
const target = routeTarget(projectRoot, routesDir);
|
|
151
|
+
const sessions = coordinators.get(lifecycle) ?? /* @__PURE__ */ new Map();
|
|
152
|
+
coordinators.set(lifecycle, sessions);
|
|
153
|
+
const coordinator = sessions.get(target) ?? {
|
|
154
|
+
contributions: /* @__PURE__ */ new Map(),
|
|
155
|
+
expectedOwners: new Set(expectedOwners),
|
|
156
|
+
afterRevocation: []
|
|
157
|
+
};
|
|
158
|
+
sessions.set(target, coordinator);
|
|
159
|
+
if (afterGenerate) coordinator.afterRevocation.push(afterGenerate);
|
|
160
|
+
await generateWhenReady(sessions, coordinator, projectRoot);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Config hooks are the primary synchronization point because SvelteKit reads
|
|
164
|
+
* its route inventory immediately afterwards. This is a fail-closed backstop
|
|
165
|
+
* for Vite configurations where a marked, active peer never ran its hook.
|
|
166
|
+
*/
|
|
167
|
+
function assertSvelteKitRouteCoordinationComplete(lifecycle) {
|
|
168
|
+
for (const [target, coordinator] of coordinators.get(lifecycle) ?? []) {
|
|
169
|
+
const missing = [...coordinator.expectedOwners].filter((owner) => !coordinator.contributions.has(owner));
|
|
170
|
+
if (missing.length === 0) continue;
|
|
171
|
+
throw new Error(`[smrt] Incomplete SvelteKit route coordination for ${JSON.stringify(target)}; active ${missing.join(", ")} plugin contribution${missing.length === 1 ? "" : "s"} did not run before config resolution.`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/** Current producer-owned knowledge handlers, which may sit outside its API root. */
|
|
175
|
+
function producerKnowledgeRoutePaths(lifecycle) {
|
|
176
|
+
const paths = /* @__PURE__ */ new Set();
|
|
177
|
+
for (const coordinator of coordinators.get(lifecycle)?.values() ?? []) {
|
|
178
|
+
const producer = coordinator.contributions.get("producer");
|
|
179
|
+
if (!producer?.options.knowledge?.api?.enabled) continue;
|
|
180
|
+
paths.add(canonicalSvelteKitPath(knowledgeRoutePath(producer.projectRoot, producer.options)));
|
|
181
|
+
}
|
|
182
|
+
return paths;
|
|
183
|
+
}
|
|
184
|
+
/** Resolve active producer knowledge claims before consumer route mutation. */
|
|
185
|
+
async function activeProducerKnowledgeRoutePaths(userConfig, projectRoot, env) {
|
|
186
|
+
const paths = /* @__PURE__ */ new Set();
|
|
187
|
+
for (const participant of await activeSvelteKitRouteParticipants(userConfig, projectRoot, env)) {
|
|
188
|
+
if (participant.owner !== "producer" || !participant.resolveKnowledge) continue;
|
|
189
|
+
const knowledge = await participant.resolveKnowledge(participant.projectRoot);
|
|
190
|
+
if (!knowledge.api?.enabled) continue;
|
|
191
|
+
paths.add(canonicalSvelteKitPath(knowledgeRoutePath(participant.projectRoot, {
|
|
192
|
+
enabled: true,
|
|
193
|
+
routesDir: relative(participant.projectRoot, participant.routesDir),
|
|
194
|
+
objectsDir: "",
|
|
195
|
+
knowledge
|
|
196
|
+
})));
|
|
197
|
+
}
|
|
198
|
+
return paths;
|
|
199
|
+
}
|
|
200
|
+
async function generateWhenReady(sessions, coordinator, _projectRoot) {
|
|
201
|
+
if ([...coordinator.expectedOwners].some((owner) => !coordinator.contributions.has(owner))) return;
|
|
202
|
+
const contributions = [...coordinator.contributions.values()];
|
|
203
|
+
const primary = primaryContribution(contributions);
|
|
204
|
+
assertNoForeignKnowledgeRouteCollisions(sessions);
|
|
205
|
+
const registrationContributions = [...sessions.values()].flatMap(({ contributions }) => [...contributions.values()].filter((contribution) => configTarget(contribution.projectRoot, contribution.options) === configTarget(primary.projectRoot, primary.options)));
|
|
206
|
+
const registrationPaths = consumerRegistrationPaths(registrationContributions);
|
|
207
|
+
const options = {
|
|
208
|
+
...mergeOptions(contributions),
|
|
209
|
+
...registrationPaths.length > 0 ? { consumerRegistrationPaths: registrationPaths } : {}
|
|
210
|
+
};
|
|
211
|
+
const hooks = { beforeCleanup: async () => {
|
|
212
|
+
for (const contribution of contributions) await contribution.beforeCleanup?.();
|
|
213
|
+
} };
|
|
214
|
+
await generateSvelteKitRoutes(primary.projectRoot, mergeManifests(contributions.map(({ routeManifest }) => routeManifest)), options, mergeManifests(contributions.map(({ semanticManifest }) => semanticManifest)), utilityManifests(contributions, protectedProducerKnowledgeRoutePaths(sessions, coordinator), new Set([...sessions.entries()].filter(([target, candidate]) => target !== routeTarget(primary.projectRoot, primary.options.routesDir) && candidate.contributions.size > 0).map(([target]) => target))), mergeManifests(registrationContributions.map(({ routeManifest }) => routeManifest)), hooks);
|
|
215
|
+
for (const contribution of contributions) await contribution.afterGenerate?.();
|
|
216
|
+
const afterRevocation = coordinator.afterRevocation.splice(0);
|
|
217
|
+
for (const callback of afterRevocation) await callback();
|
|
218
|
+
}
|
|
219
|
+
function routeTarget(projectRoot, routesDir) {
|
|
220
|
+
return canonicalSvelteKitPath(resolve(projectRoot, routesDir));
|
|
221
|
+
}
|
|
222
|
+
function configTarget(projectRoot, options) {
|
|
223
|
+
return canonicalSvelteKitPath(resolve(projectRoot, options.configPath || "src/lib/server"));
|
|
224
|
+
}
|
|
225
|
+
function effectiveConfigFileName(options) {
|
|
226
|
+
return options.configFileName || "smrt.ts";
|
|
227
|
+
}
|
|
228
|
+
function consumerRegistrationPaths(contributions) {
|
|
229
|
+
return [...new Set(contributions.filter(({ owner }) => owner === "consumer").map(({ projectRoot }) => canonicalSvelteKitPath(resolve(projectRoot, ".smrt/register.js"))))].sort();
|
|
230
|
+
}
|
|
231
|
+
function utilityManifests(contributions, protectedRoutePaths, protectedRouteRoots) {
|
|
232
|
+
const selected = (key) => contributions.find(({ options }) => options[key]?.enabled !== false) ?? contributions[0];
|
|
233
|
+
const changes = selected("changesRoute");
|
|
234
|
+
const events = selected("eventsRoute");
|
|
235
|
+
return {
|
|
236
|
+
sync: mergeManifests(contributions.map(({ routeManifest }) => routeManifest)),
|
|
237
|
+
changes: changes.routeManifest,
|
|
238
|
+
events: events.routeManifest,
|
|
239
|
+
eventsSemantic: events.semanticManifest,
|
|
240
|
+
clearKnowledgeRoute: contributions.some(({ options }) => options.knowledge !== void 0),
|
|
241
|
+
protectedRoutePaths,
|
|
242
|
+
protectedRouteRoots
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function producerKnowledgeContributions(sessions) {
|
|
246
|
+
return [...sessions.values()].flatMap(({ contributions }) => [...contributions.values()].filter((contribution) => contribution.owner === "producer" && contribution.options.knowledge?.api?.enabled === true));
|
|
247
|
+
}
|
|
248
|
+
function foreignProducerKnowledgeRoutePaths(sessions, current) {
|
|
249
|
+
const paths = /* @__PURE__ */ new Set();
|
|
250
|
+
for (const contribution of producerKnowledgeContributions(sessions)) {
|
|
251
|
+
if (current.contributions.get("producer") === contribution) continue;
|
|
252
|
+
paths.add(canonicalSvelteKitPath(knowledgeRoutePath(contribution.projectRoot, contribution.options)));
|
|
253
|
+
}
|
|
254
|
+
return paths;
|
|
255
|
+
}
|
|
256
|
+
function currentProducerKnowledgeRoutePaths(coordinator) {
|
|
257
|
+
const producer = coordinator.contributions.get("producer");
|
|
258
|
+
if (!producer?.options.knowledge?.api?.enabled) return /* @__PURE__ */ new Set();
|
|
259
|
+
return /* @__PURE__ */ new Set([canonicalSvelteKitPath(knowledgeRoutePath(producer.projectRoot, producer.options))]);
|
|
260
|
+
}
|
|
261
|
+
function protectedProducerKnowledgeRoutePaths(sessions, current) {
|
|
262
|
+
const ownPaths = currentProducerKnowledgeRoutePaths(current);
|
|
263
|
+
return /* @__PURE__ */ new Set([...foreignProducerKnowledgeRoutePaths(sessions, current), ...[...current.contributions.values()].flatMap((contribution) => [...contribution.reservedRoutePaths ?? []].filter((path) => !ownPaths.has(canonicalSvelteKitPath(path))))]);
|
|
264
|
+
}
|
|
265
|
+
function assertNoForeignKnowledgeRouteCollisions(sessions) {
|
|
266
|
+
const knowledgeContributions = producerKnowledgeContributions(sessions);
|
|
267
|
+
for (const routeCoordinator of sessions.values()) {
|
|
268
|
+
const ownPaths = currentProducerKnowledgeRoutePaths(routeCoordinator);
|
|
269
|
+
for (const contribution of routeCoordinator.contributions.values()) {
|
|
270
|
+
if (!contribution.options.rejectRouteCollisions) continue;
|
|
271
|
+
const foreignPaths = new Set(knowledgeContributions.filter((knowledge) => knowledge !== contribution).map((knowledge) => canonicalSvelteKitPath(knowledgeRoutePath(knowledge.projectRoot, knowledge.options))));
|
|
272
|
+
for (const path of contribution.reservedRoutePaths ?? []) if (!ownPaths.has(canonicalSvelteKitPath(path))) foreignPaths.add(path);
|
|
273
|
+
if (foreignPaths.size === 0) continue;
|
|
274
|
+
assertNoCrossObjectRouteCollisions(contribution.projectRoot, contribution.routeManifest, contribution.options, contribution.semanticManifest, foreignPaths);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function primaryContribution(contributions) {
|
|
279
|
+
const primary = contributions.find(({ owner }) => owner === "producer") ?? contributions[0];
|
|
280
|
+
if (!primary) throw new Error("[smrt] Missing SvelteKit route contribution");
|
|
281
|
+
return primary;
|
|
282
|
+
}
|
|
283
|
+
function mergeOptions(contributions) {
|
|
284
|
+
const primary = primaryContribution(contributions);
|
|
285
|
+
const merged = { ...primary.options };
|
|
286
|
+
for (const contribution of contributions) if (routeTarget(contribution.projectRoot, contribution.options.routesDir) !== routeTarget(primary.projectRoot, primary.options.routesDir) || canonicalSvelteKitPath(resolve(contribution.projectRoot, contribution.options.objectsDir)) !== canonicalSvelteKitPath(resolve(primary.projectRoot, primary.options.objectsDir)) || configTarget(contribution.projectRoot, contribution.options) !== configTarget(primary.projectRoot, primary.options) || effectiveConfigFileName(contribution.options) !== effectiveConfigFileName(primary.options) || contribution.options.kebabRoutes !== primary.options.kebabRoutes) throw new Error(`[smrt] Incompatible SvelteKit route settings for shared routesDir ${JSON.stringify(primary.options.routesDir)}`);
|
|
287
|
+
for (const key of [
|
|
288
|
+
"changesRoute",
|
|
289
|
+
"eventsRoute",
|
|
290
|
+
"resourcesRoute"
|
|
291
|
+
]) {
|
|
292
|
+
const owners = contributions.filter(({ options }) => options[key]?.enabled !== false);
|
|
293
|
+
if (owners.length > 1) throw new Error(`[smrt] Conflicting SvelteKit utility route owner for ${key} in shared routesDir ${JSON.stringify(primary.options.routesDir)}`);
|
|
294
|
+
if (owners.length === 1) merged[key] = owners[0]?.options[key];
|
|
295
|
+
}
|
|
296
|
+
merged.rejectRouteCollisions = contributions.some(({ options }) => options.rejectRouteCollisions === true);
|
|
297
|
+
return merged;
|
|
298
|
+
}
|
|
299
|
+
function mergeManifests(manifests) {
|
|
300
|
+
const first = manifests[0];
|
|
301
|
+
if (!first) throw new Error("[smrt] Missing SvelteKit route manifest");
|
|
302
|
+
const objects = {};
|
|
303
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
304
|
+
for (const manifest of manifests) {
|
|
305
|
+
for (const dependency of manifest.smrtDependencies ?? []) dependencies.add(dependency);
|
|
306
|
+
for (const [key, objectDef] of Object.entries(manifest.objects)) {
|
|
307
|
+
const existing = objects[key];
|
|
308
|
+
if (existing && JSON.stringify(existing) !== JSON.stringify(objectDef)) throw new Error(`[smrt] Conflicting SvelteKit route object definition for ${JSON.stringify(key)}`);
|
|
309
|
+
objects[key] = objectDef;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
...first,
|
|
314
|
+
objects,
|
|
315
|
+
smrtDependencies: [...dependencies].sort()
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
319
|
+
export { activeProducerKnowledgeRoutePaths, activeSvelteKitRouteParticipants, assertNoSvelteKitRouteRootSymlinkConflict, assertSvelteKitRouteCoordinationComplete, contributeSvelteKitRoutes, expectedSvelteKitRouteOwners, markSvelteKitRouteParticipant, producerKnowledgeRoutePaths, revokeSvelteKitRoutes };
|
|
320
|
+
|
|
321
|
+
//# sourceMappingURL=sveltekit-route-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-route-coordinator.js","names":[],"sources":["../../src/vite-plugin/sveltekit-route-coordinator.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\nimport type { ConfigEnv, Plugin } from 'vite';\nimport type { SmartObjectManifest } from '../scanner/types.js';\nimport {\n assertNoCrossObjectRouteCollisions,\n generateSvelteKitRoutes,\n knowledgeRoutePath,\n type SvelteKitGenerationHooks,\n type SvelteKitOptions,\n type SvelteKitUtilityManifests,\n} from './sveltekit-generator.js';\nimport { canonicalSvelteKitPath } from './sveltekit-path.js';\n\nexport type SvelteKitRouteOwner = 'producer' | 'consumer';\n\nconst ROUTE_PARTICIPANT = Symbol('smrt.sveltekit-route-participant');\nconst coordinators = new WeakMap<object, Map<string, RouteCoordinator>>();\n\ninterface RouteContribution {\n owner: SvelteKitRouteOwner;\n /** Keep the caller's lexical artifact root for its resolved output context. */\n projectRoot: string;\n routeManifest: SmartObjectManifest;\n semanticManifest: SmartObjectManifest;\n options: SvelteKitOptions;\n reservedRoutePaths?: ReadonlySet<string>;\n beforeCleanup?: () => void | Promise<void>;\n afterGenerate?: () => void | Promise<void>;\n}\ntype RouteContributionInput = Omit<RouteContribution, 'projectRoot'>;\n\ninterface RouteCoordinator {\n contributions: Map<SvelteKitRouteOwner, RouteContribution>;\n expectedOwners: Set<SvelteKitRouteOwner>;\n afterRevocation: Array<() => void | Promise<void>>;\n}\n\nexport interface ActiveSvelteKitRouteParticipant {\n owner: SvelteKitRouteOwner;\n projectRoot: string;\n routesDir: string;\n resolveKnowledge?: ProducerKnowledgeResolver;\n}\n\ntype ProducerKnowledgeResolver = (projectRoot: string) => Promise<{\n api?: { enabled?: boolean; basePath?: string };\n}>;\ntype ProjectRootResolver = (userConfig: unknown) => string;\n\n/** Marks an enabled plugin instance so only real same-target participants block\n * the initial shared route transaction. The marker is intentionally private to\n * the plugin objects supplied to one Vite config invocation. */\nexport function markSvelteKitRouteParticipant(\n plugin: Plugin,\n owner: SvelteKitRouteOwner,\n enabled: boolean,\n routesDir: string,\n resolveKnowledge?: ProducerKnowledgeResolver,\n resolveProjectRoot?: ProjectRootResolver,\n): void {\n Object.defineProperty(plugin, ROUTE_PARTICIPANT, {\n value: { owner, enabled, routesDir, resolveKnowledge, resolveProjectRoot },\n enumerable: false,\n });\n}\n\nexport async function expectedSvelteKitRouteOwners(\n userConfig: unknown,\n projectRoot: string,\n routesDir: string,\n env?: ConfigEnv,\n): Promise<SvelteKitRouteOwner[]> {\n const participants = await activeSvelteKitRouteParticipants(\n userConfig,\n projectRoot,\n env,\n );\n assertCompatibleSvelteKitRouteTargets(participants);\n const target = canonicalSvelteKitPath(resolve(projectRoot, routesDir));\n const owners = new Set<SvelteKitRouteOwner>();\n for (const participant of participants) {\n if (participant.routesDir === target) owners.add(participant.owner);\n }\n return [...owners];\n}\n\n/** Mirrors Vite's supported recursive PluginOption normalization for config hooks. */\nasync function flattenPluginOptions(value: unknown): Promise<unknown[]> {\n let values = Array.isArray(value) ? value : [];\n do {\n values = (await Promise.all(values)).flat(Infinity);\n } while (\n values.some(\n (entry) =>\n entry && typeof (entry as Promise<unknown>).then === 'function',\n )\n );\n return values.filter(Boolean);\n}\n\n/** Applies the same supported `Plugin.apply` gate Vite uses before config hooks. */\nfunction appliesToConfig(\n plugin: Plugin,\n userConfig: unknown,\n env: ConfigEnv | undefined,\n): boolean {\n const apply = plugin.apply;\n if (!apply) return true;\n if (!env) return false;\n if (typeof apply === 'function') {\n return apply(\n {\n ...((userConfig as Record<string, unknown> | undefined) ?? {}),\n mode: env.mode,\n },\n env,\n );\n }\n return apply === env.command;\n}\n\n/** Active roots are either one shared target or separate directory owners. */\nexport async function activeSvelteKitRouteParticipants(\n userConfig: unknown,\n projectRoot: string,\n env?: ConfigEnv,\n): Promise<ActiveSvelteKitRouteParticipant[]> {\n const plugins = await flattenPluginOptions(\n (userConfig as { plugins?: unknown } | undefined)?.plugins,\n );\n const participants: ActiveSvelteKitRouteParticipant[] = [];\n for (const plugin of plugins) {\n if (!appliesToConfig(plugin as Plugin, userConfig, env)) continue;\n const participant = (\n plugin as\n | {\n [ROUTE_PARTICIPANT]?: {\n owner: SvelteKitRouteOwner;\n enabled: boolean;\n routesDir: string;\n resolveKnowledge?: ProducerKnowledgeResolver;\n resolveProjectRoot?: ProjectRootResolver;\n };\n }\n | undefined\n )?.[ROUTE_PARTICIPANT];\n if (!participant?.enabled) continue;\n const participantRoot = canonicalSvelteKitPath(\n participant.resolveProjectRoot?.(userConfig) ?? projectRoot,\n );\n participants.push({\n owner: participant.owner,\n projectRoot: participantRoot,\n routesDir: canonicalSvelteKitPath(\n resolve(participantRoot, participant.routesDir),\n ),\n resolveKnowledge: participant.resolveKnowledge,\n });\n }\n return participants;\n}\n\nfunction assertCompatibleSvelteKitRouteTargets(\n participants: ActiveSvelteKitRouteParticipant[],\n): void {\n for (const [index, first] of participants.entries()) {\n for (const second of participants.slice(index + 1)) {\n if (first.routesDir === second.routesDir) continue;\n if (\n second.routesDir.startsWith(`${first.routesDir}${sep}`) ||\n first.routesDir.startsWith(`${second.routesDir}${sep}`)\n ) {\n throw new Error(\n `[smrt] Incompatible nested SvelteKit routesDir ownership: ${JSON.stringify(first.routesDir)} and ${JSON.stringify(second.routesDir)}. Use one shared routesDir or disjoint directories.`,\n );\n }\n }\n }\n assertNoSymlinkedSvelteKitRouteTargetConflicts(participants);\n}\n\n/**\n * Route generation and SvelteKit both traverse directory symlinks. A lexical\n * disjointness check alone therefore cannot let one active route root recurse\n * into another active root during cleanup.\n */\nfunction assertNoSymlinkedSvelteKitRouteTargetConflicts(\n participants: ActiveSvelteKitRouteParticipant[],\n): void {\n for (const participant of participants) {\n const foreignRoots = participants\n .filter(({ routesDir }) => routesDir !== participant.routesDir)\n .map(({ routesDir }) => routesDir);\n if (foreignRoots.length === 0) continue;\n assertRouteTreeDoesNotReachForeignRoot(\n participant.routesDir,\n foreignRoots,\n new Set(),\n );\n }\n}\n\n/**\n * A durable consumer ownership record can outlive the route configuration\n * that created it. Reconciliation uses this same guard before it sweeps a\n * former lexical root, so an old child symlink cannot cross into a current\n * active route surface and make the journal's ownership ambiguous.\n */\nexport function assertNoSvelteKitRouteRootSymlinkConflict(\n routeRoot: string,\n foreignRouteRoots: Iterable<string>,\n): void {\n const foreignRoots = [...foreignRouteRoots].filter(\n (candidate) => candidate !== canonicalSvelteKitPath(routeRoot),\n );\n if (foreignRoots.length === 0) return;\n assertRouteTreeDoesNotReachForeignRoot(routeRoot, foreignRoots, new Set());\n}\n\nfunction assertRouteTreeDoesNotReachForeignRoot(\n routeRoot: string,\n foreignRoots: readonly string[],\n visitedRoots: Set<string>,\n): void {\n const canonicalRoot = canonicalSvelteKitPath(routeRoot);\n if (visitedRoots.has(canonicalRoot) || !existsSync(routeRoot)) return;\n visitedRoots.add(canonicalRoot);\n\n for (const entry of readdirSync(routeRoot, { withFileTypes: true })) {\n const entryPath = join(routeRoot, entry.name);\n if (entry.isDirectory()) {\n assertRouteTreeDoesNotReachForeignRoot(\n entryPath,\n foreignRoots,\n visitedRoots,\n );\n continue;\n }\n if (!entry.isSymbolicLink()) continue;\n try {\n if (!statSync(entryPath).isDirectory()) continue;\n } catch {\n continue;\n }\n const canonicalEntry = canonicalSvelteKitPath(entryPath);\n const foreignRoot = foreignRoots.find((candidate) =>\n svelteKitPathsOverlap(canonicalEntry, candidate),\n );\n if (foreignRoot) {\n throw new Error(\n `[smrt] Incompatible SvelteKit routesDir ownership: ${JSON.stringify(routeRoot)} reaches active ${JSON.stringify(foreignRoot)} through directory symlink ${JSON.stringify(entryPath)}. Use one shared routesDir or disjoint physical directories.`,\n );\n }\n assertRouteTreeDoesNotReachForeignRoot(\n entryPath,\n foreignRoots,\n visitedRoots,\n );\n }\n}\n\nfunction svelteKitPathsOverlap(first: string, second: string): boolean {\n return (\n first === second ||\n first.startsWith(`${second}${sep}`) ||\n second.startsWith(`${first}${sep}`)\n );\n}\n\n/**\n * Bind generated route ownership to one Vite configuration lifecycle. Both\n * SMRT plugins run pre-config hooks, so the later hook regenerates the complete\n * current plan rather than deleting the earlier plugin's route files.\n */\nexport async function contributeSvelteKitRoutes(\n lifecycle: object,\n expectedOwners: Iterable<SvelteKitRouteOwner>,\n projectRoot: string,\n contribution: RouteContributionInput,\n): Promise<void> {\n const target = routeTarget(projectRoot, contribution.options.routesDir);\n const sessions = coordinators.get(lifecycle) ?? new Map();\n coordinators.set(lifecycle, sessions);\n const coordinator =\n sessions.get(target) ??\n ({\n contributions: new Map(),\n expectedOwners: new Set(expectedOwners),\n afterRevocation: [],\n } satisfies RouteCoordinator);\n sessions.set(target, coordinator);\n coordinator.contributions.set(contribution.owner, {\n ...contribution,\n projectRoot,\n });\n\n await generateWhenReady(sessions, coordinator, projectRoot);\n}\n\n/**\n * Reconcile a disabled consumer's formerly hosted route root through the\n * active target transaction. This lets a current producer re-emit its own\n * surface rather than a later consumer cleanup deleting it.\n */\nexport async function revokeSvelteKitRoutes(\n lifecycle: object,\n expectedOwners: Iterable<SvelteKitRouteOwner>,\n projectRoot: string,\n routesDir: string,\n afterGenerate?: () => void | Promise<void>,\n): Promise<void> {\n const target = routeTarget(projectRoot, routesDir);\n const sessions = coordinators.get(lifecycle) ?? new Map();\n coordinators.set(lifecycle, sessions);\n const coordinator =\n sessions.get(target) ??\n ({\n contributions: new Map(),\n expectedOwners: new Set(expectedOwners),\n afterRevocation: [],\n } satisfies RouteCoordinator);\n sessions.set(target, coordinator);\n if (afterGenerate) coordinator.afterRevocation.push(afterGenerate);\n\n await generateWhenReady(sessions, coordinator, projectRoot);\n}\n\n/**\n * Config hooks are the primary synchronization point because SvelteKit reads\n * its route inventory immediately afterwards. This is a fail-closed backstop\n * for Vite configurations where a marked, active peer never ran its hook.\n */\nexport function assertSvelteKitRouteCoordinationComplete(\n lifecycle: object,\n): void {\n for (const [target, coordinator] of coordinators.get(lifecycle) ?? []) {\n const missing = [...coordinator.expectedOwners].filter(\n (owner) => !coordinator.contributions.has(owner),\n );\n if (missing.length === 0) continue;\n throw new Error(\n `[smrt] Incomplete SvelteKit route coordination for ${JSON.stringify(target)}; active ${missing.join(', ')} plugin contribution${missing.length === 1 ? '' : 's'} did not run before config resolution.`,\n );\n }\n}\n\n/** Current producer-owned knowledge handlers, which may sit outside its API root. */\nexport function producerKnowledgeRoutePaths(lifecycle: object): Set<string> {\n const paths = new Set<string>();\n for (const coordinator of coordinators.get(lifecycle)?.values() ?? []) {\n const producer = coordinator.contributions.get('producer');\n if (!producer?.options.knowledge?.api?.enabled) continue;\n paths.add(\n canonicalSvelteKitPath(\n knowledgeRoutePath(producer.projectRoot, producer.options),\n ),\n );\n }\n return paths;\n}\n\n/** Resolve active producer knowledge claims before consumer route mutation. */\nexport async function activeProducerKnowledgeRoutePaths(\n userConfig: unknown,\n projectRoot: string,\n env?: ConfigEnv,\n): Promise<Set<string>> {\n const paths = new Set<string>();\n for (const participant of await activeSvelteKitRouteParticipants(\n userConfig,\n projectRoot,\n env,\n )) {\n if (participant.owner !== 'producer' || !participant.resolveKnowledge)\n continue;\n const knowledge = await participant.resolveKnowledge(\n participant.projectRoot,\n );\n if (!knowledge.api?.enabled) continue;\n paths.add(\n canonicalSvelteKitPath(\n knowledgeRoutePath(participant.projectRoot, {\n enabled: true,\n routesDir: relative(participant.projectRoot, participant.routesDir),\n objectsDir: '',\n knowledge,\n }),\n ),\n );\n }\n return paths;\n}\n\nasync function generateWhenReady(\n sessions: Map<string, RouteCoordinator>,\n coordinator: RouteCoordinator,\n _projectRoot: string,\n): Promise<void> {\n if (\n [...coordinator.expectedOwners].some(\n (owner) => !coordinator.contributions.has(owner),\n )\n )\n return;\n\n const contributions = [...coordinator.contributions.values()];\n const primary = primaryContribution(contributions);\n assertNoForeignKnowledgeRouteCollisions(sessions);\n const registrationContributions = [...sessions.values()].flatMap(\n ({ contributions }) =>\n [...contributions.values()].filter(\n (contribution) =>\n configTarget(contribution.projectRoot, contribution.options) ===\n configTarget(primary.projectRoot, primary.options),\n ),\n );\n const registrationPaths = consumerRegistrationPaths(\n registrationContributions,\n );\n const options = {\n ...mergeOptions(contributions),\n ...(registrationPaths.length > 0\n ? { consumerRegistrationPaths: registrationPaths }\n : {}),\n };\n const hooks: SvelteKitGenerationHooks = {\n beforeCleanup: async () => {\n for (const contribution of contributions) {\n await contribution.beforeCleanup?.();\n }\n },\n };\n await generateSvelteKitRoutes(\n primary.projectRoot,\n mergeManifests(contributions.map(({ routeManifest }) => routeManifest)),\n options,\n mergeManifests(\n contributions.map(({ semanticManifest }) => semanticManifest),\n ),\n utilityManifests(\n contributions,\n protectedProducerKnowledgeRoutePaths(sessions, coordinator),\n new Set(\n [...sessions.entries()]\n .filter(\n ([target, candidate]) =>\n target !==\n routeTarget(primary.projectRoot, primary.options.routesDir) &&\n candidate.contributions.size > 0,\n )\n .map(([target]) => target),\n ),\n ),\n mergeManifests(\n registrationContributions.map(({ routeManifest }) => routeManifest),\n ),\n hooks,\n );\n for (const contribution of contributions) {\n await contribution.afterGenerate?.();\n }\n const afterRevocation = coordinator.afterRevocation.splice(0);\n for (const callback of afterRevocation) await callback();\n}\n\nfunction routeTarget(projectRoot: string, routesDir: string): string {\n return canonicalSvelteKitPath(resolve(projectRoot, routesDir));\n}\n\nfunction configTarget(projectRoot: string, options: SvelteKitOptions): string {\n return canonicalSvelteKitPath(\n resolve(projectRoot, options.configPath || 'src/lib/server'),\n );\n}\n\nfunction effectiveConfigFileName(options: SvelteKitOptions): string {\n return options.configFileName || 'smrt.ts';\n}\n\nfunction consumerRegistrationPaths(\n contributions: RouteContribution[],\n): string[] {\n return [\n ...new Set(\n contributions\n .filter(({ owner }) => owner === 'consumer')\n .map(({ projectRoot }) =>\n canonicalSvelteKitPath(resolve(projectRoot, '.smrt/register.js')),\n ),\n ),\n ].sort();\n}\n\nfunction utilityManifests(\n contributions: RouteContribution[],\n protectedRoutePaths: ReadonlySet<string>,\n protectedRouteRoots: ReadonlySet<string>,\n): SvelteKitUtilityManifests {\n const selected = (key: 'changesRoute' | 'eventsRoute') =>\n contributions.find(({ options }) => options[key]?.enabled !== false) ??\n contributions[0]!;\n const changes = selected('changesRoute');\n const events = selected('eventsRoute');\n return {\n // sync/apply deliberately composes selected targets from every contributor.\n sync: mergeManifests(\n contributions.map(({ routeManifest }) => routeManifest),\n ),\n changes: changes.routeManifest,\n events: events.routeManifest,\n eventsSemantic: events.semanticManifest,\n // Knowledge routes are rooted at the SvelteKit app, rather than an API\n // routesDir. An external consumer must not reconcile a producer-owned\n // knowledge endpoint merely because it emits a separate route target.\n clearKnowledgeRoute: contributions.some(\n ({ options }) => options.knowledge !== undefined,\n ),\n protectedRoutePaths,\n protectedRouteRoots,\n };\n}\n\nfunction producerKnowledgeContributions(\n sessions: Map<string, RouteCoordinator>,\n): RouteContribution[] {\n return [...sessions.values()].flatMap(({ contributions }) =>\n [...contributions.values()].filter(\n (contribution) =>\n contribution.owner === 'producer' &&\n contribution.options.knowledge?.api?.enabled === true,\n ),\n );\n}\n\nfunction foreignProducerKnowledgeRoutePaths(\n sessions: Map<string, RouteCoordinator>,\n current: RouteCoordinator,\n): Set<string> {\n const paths = new Set<string>();\n for (const contribution of producerKnowledgeContributions(sessions)) {\n if (current.contributions.get('producer') === contribution) continue;\n paths.add(\n canonicalSvelteKitPath(\n knowledgeRoutePath(contribution.projectRoot, contribution.options),\n ),\n );\n }\n return paths;\n}\n\nfunction currentProducerKnowledgeRoutePaths(\n coordinator: RouteCoordinator,\n): Set<string> {\n const producer = coordinator.contributions.get('producer');\n if (!producer?.options.knowledge?.api?.enabled) return new Set();\n return new Set([\n canonicalSvelteKitPath(\n knowledgeRoutePath(producer.projectRoot, producer.options),\n ),\n ]);\n}\n\nfunction protectedProducerKnowledgeRoutePaths(\n sessions: Map<string, RouteCoordinator>,\n current: RouteCoordinator,\n): Set<string> {\n const ownPaths = currentProducerKnowledgeRoutePaths(current);\n return new Set([\n ...foreignProducerKnowledgeRoutePaths(sessions, current),\n ...[...current.contributions.values()].flatMap((contribution) =>\n [...(contribution.reservedRoutePaths ?? [])].filter(\n (path) => !ownPaths.has(canonicalSvelteKitPath(path)),\n ),\n ),\n ]);\n}\n\nfunction assertNoForeignKnowledgeRouteCollisions(\n sessions: Map<string, RouteCoordinator>,\n): void {\n const knowledgeContributions = producerKnowledgeContributions(sessions);\n for (const routeCoordinator of sessions.values()) {\n const ownPaths = currentProducerKnowledgeRoutePaths(routeCoordinator);\n for (const contribution of routeCoordinator.contributions.values()) {\n if (!contribution.options.rejectRouteCollisions) continue;\n const foreignPaths = new Set(\n knowledgeContributions\n .filter((knowledge) => knowledge !== contribution)\n .map((knowledge) =>\n canonicalSvelteKitPath(\n knowledgeRoutePath(knowledge.projectRoot, knowledge.options),\n ),\n ),\n );\n for (const path of contribution.reservedRoutePaths ?? []) {\n if (!ownPaths.has(canonicalSvelteKitPath(path))) foreignPaths.add(path);\n }\n if (foreignPaths.size === 0) continue;\n assertNoCrossObjectRouteCollisions(\n contribution.projectRoot,\n contribution.routeManifest,\n contribution.options,\n contribution.semanticManifest,\n foreignPaths,\n );\n }\n }\n}\n\nfunction primaryContribution(\n contributions: RouteContribution[],\n): RouteContribution {\n const primary =\n contributions.find(({ owner }) => owner === 'producer') ?? contributions[0];\n if (!primary) throw new Error('[smrt] Missing SvelteKit route contribution');\n return primary;\n}\n\nfunction mergeOptions(contributions: RouteContribution[]): SvelteKitOptions {\n const primary = primaryContribution(contributions);\n const merged: SvelteKitOptions = { ...primary.options };\n for (const contribution of contributions) {\n const incompatible =\n routeTarget(contribution.projectRoot, contribution.options.routesDir) !==\n routeTarget(primary.projectRoot, primary.options.routesDir) ||\n canonicalSvelteKitPath(\n resolve(contribution.projectRoot, contribution.options.objectsDir),\n ) !==\n canonicalSvelteKitPath(\n resolve(primary.projectRoot, primary.options.objectsDir),\n ) ||\n configTarget(contribution.projectRoot, contribution.options) !==\n configTarget(primary.projectRoot, primary.options) ||\n effectiveConfigFileName(contribution.options) !==\n effectiveConfigFileName(primary.options) ||\n contribution.options.kebabRoutes !== primary.options.kebabRoutes;\n if (incompatible) {\n throw new Error(\n `[smrt] Incompatible SvelteKit route settings for shared routesDir ${JSON.stringify(primary.options.routesDir)}`,\n );\n }\n }\n for (const key of [\n 'changesRoute',\n 'eventsRoute',\n 'resourcesRoute',\n ] as const) {\n const owners = contributions.filter(\n ({ options }) => options[key]?.enabled !== false,\n );\n if (owners.length > 1) {\n throw new Error(\n `[smrt] Conflicting SvelteKit utility route owner for ${key} in shared routesDir ${JSON.stringify(primary.options.routesDir)}`,\n );\n }\n if (owners.length === 1) merged[key] = owners[0]?.options[key];\n }\n // A hosted consumer always requests collision preflight. Preserve that\n // fail-closed policy when the producer provides the primary options.\n merged.rejectRouteCollisions = contributions.some(\n ({ options }) => options.rejectRouteCollisions === true,\n );\n return merged;\n}\n\nfunction mergeManifests(manifests: SmartObjectManifest[]): SmartObjectManifest {\n const first = manifests[0];\n if (!first) throw new Error('[smrt] Missing SvelteKit route manifest');\n const objects: SmartObjectManifest['objects'] = {};\n const dependencies = new Set<string>();\n for (const manifest of manifests) {\n for (const dependency of manifest.smrtDependencies ?? [])\n dependencies.add(dependency);\n for (const [key, objectDef] of Object.entries(manifest.objects)) {\n const existing = objects[key];\n if (existing && JSON.stringify(existing) !== JSON.stringify(objectDef)) {\n throw new Error(\n `[smrt] Conflicting SvelteKit route object definition for ${JSON.stringify(key)}`,\n );\n }\n objects[key] = objectDef;\n }\n }\n return { ...first, objects, smrtDependencies: [...dependencies].sort() };\n}\n"],"mappings":"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"}
|
|
@@ -28,7 +28,7 @@ export declare function collectSyncApplyTargets(manifest: SmartObjectManifest):
|
|
|
28
28
|
* Render the generated `+server.ts` content for the sync-apply route.
|
|
29
29
|
* Exported for tests.
|
|
30
30
|
*/
|
|
31
|
-
export declare function generateSyncApplyRouteTemplate(targets: SyncTargetSpec[]): string;
|
|
31
|
+
export declare function generateSyncApplyRouteTemplate(targets: SyncTargetSpec[], configImport: string): string;
|
|
32
32
|
/**
|
|
33
33
|
* Generate `{routesDir}/sync/apply/+server.ts` for the manifest's syncable
|
|
34
34
|
* models. Returns true when a route was written. Skips generation (with a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-apply-route.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/sync-apply-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAEV,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"sync-apply-route.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/sync-apply-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAEV,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,QAAA,MAAM,gBAAgB,yCAA0C,CAAC;AAEjE,KAAK,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,wDAAwD;AACxD,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,cAAc,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACnC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,YAAY,EAAE,OAAO,CAAC;CACvB;AAmED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mBAAmB,GAC5B,cAAc,EAAE,CAgClB;AAgBD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,cAAc,EAAE,EACzB,YAAY,EAAE,MAAM,GACnB,MAAM,CA0GR;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAiCT"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isFrameworkBaseClass } from "../registry/framework-base-classes.js";
|
|
2
2
|
import { AUTO_GENERATED_ROUTE_HEADER } from "./route-header.js";
|
|
3
|
+
import { resolveSvelteKitConfigImport } from "./sveltekit-config-import.js";
|
|
3
4
|
import { isCollectionManifestClass } from "./web-collections.js";
|
|
4
5
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
6
|
import { join } from "node:path";
|
|
@@ -109,7 +110,7 @@ function serializeTargets(targets) {
|
|
|
109
110
|
* Render the generated `+server.ts` content for the sync-apply route.
|
|
110
111
|
* Exported for tests.
|
|
111
112
|
*/
|
|
112
|
-
function generateSyncApplyRouteTemplate(targets) {
|
|
113
|
+
function generateSyncApplyRouteTemplate(targets, configImport) {
|
|
113
114
|
const anyTenantScoped = targets.some((target) => target.tenantScoped);
|
|
114
115
|
return `${AUTO_GENERATED_ROUTE_HEADER}
|
|
115
116
|
// DO NOT EDIT - changes will be overwritten
|
|
@@ -125,7 +126,7 @@ import {
|
|
|
125
126
|
type SyncApplyTarget,
|
|
126
127
|
} from '@happyvertical/smrt-core';
|
|
127
128
|
import { json } from '@sveltejs/kit';
|
|
128
|
-
import { getCollection } from '$
|
|
129
|
+
import { getCollection } from '${configImport}';
|
|
129
130
|
import type { RequestHandler } from './$types';
|
|
130
131
|
${anyTenantScoped ? `
|
|
131
132
|
import { enterTenantContext, hasTenantContext } from '@happyvertical/smrt-tenancy';
|
|
@@ -229,7 +230,7 @@ function generateSyncApplyRoute(projectRoot, manifest, options) {
|
|
|
229
230
|
}
|
|
230
231
|
}
|
|
231
232
|
if (!existsSync(routeDir)) mkdirSync(routeDir, { recursive: true });
|
|
232
|
-
writeFileSync(routePath, generateSyncApplyRouteTemplate(targets), "utf-8");
|
|
233
|
+
writeFileSync(routePath, generateSyncApplyRouteTemplate(targets, resolveSvelteKitConfigImport(projectRoot, routeDir, options)), "utf-8");
|
|
233
234
|
console.log(`[smrt] Generated: ${routePath}`);
|
|
234
235
|
return true;
|
|
235
236
|
}
|