@_linked/cli 1.29.0 → 1.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.30.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#177](https://github.com/linked-fw/cli/pull/177) [`833c2e6`](https://github.com/linked-fw/cli/commit/833c2e6c3c5716ff9ae092f7644aae499ce216af) Thanks [@flyon](https://github.com/flyon)! - `build-app` now checks every file of the compiled backend for a compiled-in copy of a package, not only `backend.js`, `App.js` and `routes.js`. Each relative import in `lib/` is resolved and the module it reaches is traced back through its sourcemap to the source it was compiled from; if that source's real path is inside a workspace package, `packages-local/`, or an installed `@_linked/*` package, the build fails. This catches a copy reached from deep inside a feature folder, and a localized checkout whose real path has no `node_modules` in it. The build also fails if `lib/packages/`, `lib/packages-local/` or `lib/node_modules/` exists (unless the app has a `src/` directory of that name). The error names the importing file and the import, and points at the package's public export.
8
+
9
+ ## 1.30.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#175](https://github.com/linked-fw/cli/pull/175) [`816f961`](https://github.com/linked-fw/cli/commit/816f961709b03ea05341f1a2f62713f721f0e20a) Thanks [@flyon](https://github.com/flyon)! - `linked build` now checks that loading a shape module registers every shape its properties point at.
14
+
15
+ A property that names its value shape by `[package, name]` (`shape: ['@_linked/schema', 'ImageObject']`)
16
+ does not load that shape, and consumers deep-import single shape modules. So a package could ship a
17
+ module whose query `workspace.image.contentUrl` threw `Shape class not found for …/ImageObject` in a
18
+ production bundle where nothing else happened to load ImageObject — which is how Create Now came to
19
+ show "No organizations found". `@_linked/sioc` also named shapes under its old package name
20
+ (`lincd-sioc`), which could never resolve.
21
+
22
+ The new step, **Checking shape references**, runs after the ESM output is final. It loads every module
23
+ under `lib/esm/shapes/` (and any other module that declares a `@linkedShape`) in a `node` process of
24
+ its own, with nothing imported first, and then **fails the build** for:
25
+
26
+ - a module that throws when loaded on its own (e.g. `Cannot access 'X' before initialization`);
27
+ - a property of one of the package's shapes whose value shape is not registered — naming the
28
+ property, the missing shape's IRI and the modules that showed it, and whether the target package's
29
+ entry registers it (a missing import), does not (a wrong name), or the IRI belongs to no dependency
30
+ (an old package name).
31
+
32
+ `*.class.js` modules are skipped: they are the class half of a split shape module and are checked
33
+ through the public module that re-exports them. Asset imports (`.css`, images, fonts) load as stubs.
34
+ `@_linked/core`'s `PropertyShape.in → List` is a known, tracked gap and warns instead of failing.
35
+
3
36
  ## 1.29.0
4
37
 
5
38
  ### Minor Changes
@@ -27,18 +27,75 @@ export declare const workspacePackagesToExternalize: (appRoot: string, discover?
27
27
  name: string;
28
28
  }[]>) => Promise<string[]>;
29
29
  /**
30
- * A relative import from `lib/` into `packages/` means a workspace package was
31
- * compiled in after all. One into `node_modules/@_linked/` means an installed
32
- * framework package was: `lib/node_modules/@_linked/server-utils` is a second
30
+ * Every module specifier a compiled file imports: static `from "…"`, side-effect
31
+ * `import "…"`, dynamic `import("…")`, and `require("…")`.
32
+ *
33
+ * Deliberately loose — it can match text inside a string or a comment. That is
34
+ * harmless: only specifiers that resolve to a file on disk are acted on, and
35
+ * only when that file turns out to be a copy of a package.
36
+ */
37
+ export declare const findImportSpecifiers: (source: string) => string[];
38
+ /** One import in `lib/` that reaches a compiled-in copy of a package. */
39
+ export interface InlinedPackageImport {
40
+ /** The importing file, relative to the app root (`lib/…/PageView.js`). */
41
+ file: string;
42
+ /** The specifier exactly as it appears in that file. */
43
+ specifier: string;
44
+ /** Real path of the package source the imported module was compiled from. */
45
+ origin: string;
46
+ /** Name of the package that source belongs to, when it is known. */
47
+ packageName?: string;
48
+ }
49
+ /**
50
+ * A directory whose real path is package code the backend must import rather
51
+ * than compile: a workspace package, a localized checkout, an installed
52
+ * framework package.
53
+ */
54
+ export interface PackageRoot {
55
+ root: string;
56
+ name?: string;
57
+ }
58
+ /**
59
+ * The package roots an app's compiled backend must never contain a copy of,
60
+ * as real paths: every discovered workspace package, everything under
61
+ * `packages-local/`, and every installed `@_linked/*` package (whose real path
62
+ * is a localized checkout when it has been localized).
63
+ */
64
+ export declare const packageRootsForApp: (appRoot: string, discover?: (globs: string[], cwd: string) => Promise<{
65
+ name: string;
66
+ srcDir: string;
67
+ }[]>) => Promise<PackageRoot[]>;
68
+ /**
69
+ * Find every import in the compiled backend that reaches a compiled-in copy of
70
+ * a package.
71
+ *
72
+ * Each relative specifier is resolved against its file, and the module it
73
+ * lands on is traced back to the source it was compiled from through that
74
+ * module's sourcemap. The source's REAL path is then compared with the
75
+ * package roots — so it does not matter what the copy's directory in `lib/` is
76
+ * called, or whether the package was reached through a symlink. An import that
77
+ * leaves `lib/` altogether is judged by its own real path.
78
+ *
79
+ * Only imports from the app's own modules are reported: they are the ones to
80
+ * change, and every compiled-in copy is reached through one of them.
81
+ */
82
+ export declare const findInlinedPackageImports: (appRoot: string, packageRoots: PackageRoot[]) => Promise<{
83
+ imports: InlinedPackageImport[];
84
+ strayDirs: string[];
85
+ }>;
86
+ /**
87
+ * Fail the build when the compiled backend contains a copy of a package.
88
+ *
89
+ * A copy compiles and runs — and then fails somewhere else entirely: a second
90
+ * `@_linked/core` splits `LinkedStorage`'s routing state from the one the
91
+ * storage config configures, and a second `@_linked/server-utils` is a second
33
92
  * `ShapeProvider` class, so the server's `instanceof` check rejects every
34
- * provider the app exports.
93
+ * provider the app exports. Neither message points anywhere near here.
35
94
  *
36
- * Worth failing the build over rather than leaving to be discovered: the
37
- * output is perfectly valid JavaScript, and the symptom is the app refusing to
38
- * boot with a message about storage routing that points nowhere near here.
95
+ * Every file in `lib/` is checked, not only the entries: a copy reached from
96
+ * a feature folder three imports deep is just as much a second copy.
39
97
  */
40
- export declare const findInlinedWorkspaceImports: (source: string) => string[];
41
- export declare const assertNoInlinedWorkspaces: (appRoot: string, readFile?: (p: string) => Promise<string>) => Promise<void>;
98
+ export declare const assertNoInlinedWorkspaces: (appRoot: string, packageRoots?: PackageRoot[]) => Promise<void>;
42
99
  /**
43
100
  * Turn Rollup's unresolved-import error into one that names the actual cause.
44
101
  *
@@ -1 +1 @@
1
- {"version":3,"file":"build-backend.d.ts","sourceRoot":"","sources":["../../../src/app-release/build-backend.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,EACf,SAAQ,CAAC,CAAC,EAAE,MAAM,KAAK,OAAuB,KAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAWvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,8BAA8B,GACzC,SAAS,MAAM,EACf,WAAU,CACR,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,EAAE,CAG5B,KACA,OAAO,CAAC,MAAM,EAAE,CAGlB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,GAAI,QAAQ,MAAM,KAAG,MAAM,EAQlE,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,EACf,WAAU,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAiC,KACvE,OAAO,CAAC,IAAI,CAwBd,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,GAC3C,SAAS,MAAM,EACf,oBAAoB,MAAM,EAAE,KAC3B,MAAM,GAAG,IAgBX,CAAC;AAqBF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAS;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,EAChC,eAAc;IAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAM,KACjE,OAAO,CAAC,IAAI,CAqFd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,SAAS,MAAM,EACf,cAAc,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,KAC/C,OAAO,CAAC,MAAM,CAYhB,CAAC"}
1
+ {"version":3,"file":"build-backend.d.ts","sourceRoot":"","sources":["../../../src/app-release/build-backend.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,EACf,SAAQ,CAAC,CAAC,EAAE,MAAM,KAAK,OAAuB,KAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAWvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,8BAA8B,GACzC,SAAS,MAAM,EACf,WAAU,CACR,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,EAAE,CAG5B,KACA,OAAO,CAAC,MAAM,EAAE,CAGlB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,KAAG,MAAM,EAK3D,CAAC;AAEF,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA4CD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,EACf,WAAU,CACR,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,EAAE,CAG5C,KACA,OAAO,CAAC,WAAW,EAAE,CA0BvB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,EACf,cAAc,WAAW,EAAE,KAC1B,OAAO,CAAC;IAAC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAC,CAgFhE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,EACf,eAAe,WAAW,EAAE,KAC3B,OAAO,CAAC,IAAI,CA4Bd,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,GAC3C,SAAS,MAAM,EACf,oBAAoB,MAAM,EAAE,KAC3B,MAAM,GAAG,IAgBX,CAAC;AAqBF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAS;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,EAChC,eAAc;IAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAM,KACjE,OAAO,CAAC,IAAI,CAqFd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,SAAS,MAAM,EACf,cAAc,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,KAC/C,OAAO,CAAC,MAAM,CAYhB,CAAC"}
@@ -87,46 +87,220 @@ export const workspacePackagesToExternalize = (appRoot_1, ...args_1) => __awaite
87
87
  return [...new Set(workspaces.map((w) => w.name))].sort();
88
88
  });
89
89
  /**
90
- * A relative import from `lib/` into `packages/` means a workspace package was
91
- * compiled in after all. One into `node_modules/@_linked/` means an installed
92
- * framework package was: `lib/node_modules/@_linked/server-utils` is a second
93
- * `ShapeProvider` class, so the server's `instanceof` check rejects every
94
- * provider the app exports.
90
+ * Every module specifier a compiled file imports: static `from "…"`, side-effect
91
+ * `import "…"`, dynamic `import("…")`, and `require("…")`.
95
92
  *
96
- * Worth failing the build over rather than leaving to be discovered: the
97
- * output is perfectly valid JavaScript, and the symptom is the app refusing to
98
- * boot with a message about storage routing that points nowhere near here.
93
+ * Deliberately loose — it can match text inside a string or a comment. That is
94
+ * harmless: only specifiers that resolve to a file on disk are acted on, and
95
+ * only when that file turns out to be a copy of a package.
99
96
  */
100
- export const findInlinedWorkspaceImports = (source) => {
101
- // Both static `from "…"` and dynamic `import("…")`: a lazily imported page
102
- // can drag a workspace package in on its own, and only the second form
103
- // appears in the output for it.
104
- const matches = source.matchAll(/(?:from|import)\s*\(?\s*["'](\.[^"']*\/(?:packages|node_modules\/@_linked)\/[^"']+)["']/g);
97
+ export const findImportSpecifiers = (source) => {
98
+ const matches = source.matchAll(/(?:\bfrom\s*|\bimport\s*\(?\s*|\brequire\s*\(\s*)["']([^"'\n]+)["']/g);
105
99
  return [...new Set([...matches].map((m) => m[1]))].sort();
106
100
  };
107
- export const assertNoInlinedWorkspaces = (appRoot_1, ...args_1) => __awaiter(void 0, [appRoot_1, ...args_1], void 0, function* (appRoot, readFile = (p) => fs.readFile(p, 'utf8')) {
108
- // Every entry, not just the backend: `App.js` and `routes.js` reach code the
109
- // backend never imports, so a package can be inlined through either of them.
110
- const inlined = new Set();
111
- for (const name of Object.keys(BACKEND_ENTRIES)) {
112
- const entryPath = path.join(appRoot, 'lib', `${name}.js`);
113
- if (!fs.existsSync(entryPath))
101
+ /**
102
+ * Top-level directories of `lib/` that only exist when code from outside
103
+ * `src/` was compiled in.
104
+ *
105
+ * `preserveModules` lays `lib/` out relative to the common ancestor of every
106
+ * module in the build. With `preserveModulesRoot: src` the app's own files lose
107
+ * their `src/` prefix, and anything else keeps its path from the app root — so
108
+ * a compiled-in workspace package lands at `lib/packages/…`, an installed one at
109
+ * `lib/node_modules/…`. Only when the app has no `src/` directory of that name,
110
+ * since an app is free to have its own `src/packages/`.
111
+ */
112
+ const STRAY_OUTPUT_DIRS = ['packages', 'packages-local', 'node_modules'];
113
+ const realpathOr = (p) => {
114
+ try {
115
+ return fs.realpathSync(p);
116
+ }
117
+ catch (_a) {
118
+ return path.resolve(p);
119
+ }
120
+ };
121
+ const isInside = (child, parent) => {
122
+ const rel = path.relative(parent, child);
123
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
124
+ };
125
+ const listJsFiles = (dir) => __awaiter(void 0, void 0, void 0, function* () {
126
+ const out = [];
127
+ const walk = (current) => __awaiter(void 0, void 0, void 0, function* () {
128
+ const entries = yield fs.promises.readdir(current, { withFileTypes: true });
129
+ yield Promise.all(entries.map((entry) => __awaiter(void 0, void 0, void 0, function* () {
130
+ const full = path.join(current, entry.name);
131
+ if (entry.isDirectory())
132
+ yield walk(full);
133
+ else if (/\.(?:m|c)?js$/.test(entry.name))
134
+ out.push(full);
135
+ })));
136
+ });
137
+ yield walk(dir);
138
+ return out.sort();
139
+ });
140
+ /**
141
+ * The package roots an app's compiled backend must never contain a copy of,
142
+ * as real paths: every discovered workspace package, everything under
143
+ * `packages-local/`, and every installed `@_linked/*` package (whose real path
144
+ * is a localized checkout when it has been localized).
145
+ */
146
+ export const packageRootsForApp = (appRoot_1, ...args_1) => __awaiter(void 0, [appRoot_1, ...args_1], void 0, function* (appRoot, discover = (globs, cwd) => __awaiter(void 0, void 0, void 0, function* () {
147
+ const { discoverWorkspaces } = yield import('../vite-config.js');
148
+ return discoverWorkspaces(globs, cwd);
149
+ })) {
150
+ const roots = [];
151
+ for (const ws of yield discover([], appRoot)) {
152
+ roots.push({ root: realpathOr(path.dirname(ws.srcDir)), name: ws.name });
153
+ }
154
+ const packagesLocal = path.join(appRoot, 'packages-local');
155
+ if (fs.existsSync(packagesLocal)) {
156
+ for (const entry of yield fs.readdir(packagesLocal)) {
157
+ roots.push({ root: realpathOr(path.join(packagesLocal, entry)) });
158
+ }
159
+ roots.push({ root: realpathOr(packagesLocal) });
160
+ }
161
+ const linkedScope = path.join(appRoot, 'node_modules', '@_linked');
162
+ if (fs.existsSync(linkedScope)) {
163
+ for (const entry of yield fs.readdir(linkedScope)) {
164
+ roots.push({
165
+ root: realpathOr(path.join(linkedScope, entry)),
166
+ name: `@_linked/${entry}`,
167
+ });
168
+ }
169
+ roots.push({ root: realpathOr(linkedScope) });
170
+ }
171
+ // The app itself can be discovered as a workspace; its own source is not a
172
+ // second copy of anything.
173
+ const appSrc = realpathOr(path.join(appRoot, 'src'));
174
+ return roots.filter(({ root }) => !isInside(appSrc, root));
175
+ });
176
+ /**
177
+ * Find every import in the compiled backend that reaches a compiled-in copy of
178
+ * a package.
179
+ *
180
+ * Each relative specifier is resolved against its file, and the module it
181
+ * lands on is traced back to the source it was compiled from through that
182
+ * module's sourcemap. The source's REAL path is then compared with the
183
+ * package roots — so it does not matter what the copy's directory in `lib/` is
184
+ * called, or whether the package was reached through a symlink. An import that
185
+ * leaves `lib/` altogether is judged by its own real path.
186
+ *
187
+ * Only imports from the app's own modules are reported: they are the ones to
188
+ * change, and every compiled-in copy is reached through one of them.
189
+ */
190
+ export const findInlinedPackageImports = (appRoot, packageRoots) => __awaiter(void 0, void 0, void 0, function* () {
191
+ const libDir = path.join(appRoot, 'lib');
192
+ const strayDirs = STRAY_OUTPUT_DIRS.filter((name) => fs.existsSync(path.join(libDir, name)) &&
193
+ !fs.existsSync(path.join(appRoot, 'src', name))).map((name) => `lib/${name}/`);
194
+ if (!fs.existsSync(libDir))
195
+ return { imports: [], strayDirs };
196
+ const ownerOf = (real) => packageRoots
197
+ .filter(({ root }) => isInside(real, root))
198
+ // The most specific root names the package; a named one wins a tie.
199
+ .sort((a, b) => b.root.length - a.root.length || Number(!!b.name) - Number(!!a.name))[0];
200
+ // Where a module in lib/ was compiled from, via its sourcemap.
201
+ const originCache = new Map();
202
+ const originsOf = (moduleFile) => __awaiter(void 0, void 0, void 0, function* () {
203
+ const cached = originCache.get(moduleFile);
204
+ if (cached)
205
+ return cached;
206
+ let origins = [];
207
+ try {
208
+ const map = JSON.parse(yield fs.readFile(`${moduleFile}.map`, 'utf8'));
209
+ const base = path.resolve(path.dirname(moduleFile), map.sourceRoot || '');
210
+ origins = (map.sources || [])
211
+ .filter((s) => typeof s === 'string' && !s.startsWith('\0'))
212
+ .map((s) => realpathOr(path.resolve(base, s.replace(/^file:\/\//, ''))));
213
+ }
214
+ catch (_a) {
215
+ // No sourcemap: nothing to trace. The stray-directory check still
216
+ // catches the usual layout of a compiled-in package.
217
+ }
218
+ originCache.set(moduleFile, origins);
219
+ return origins;
220
+ });
221
+ const packageSourceOf = (moduleFile) => __awaiter(void 0, void 0, void 0, function* () {
222
+ for (const origin of yield originsOf(moduleFile)) {
223
+ const owner = ownerOf(origin);
224
+ if (owner)
225
+ return { origin, owner };
226
+ }
227
+ return undefined;
228
+ });
229
+ const imports = [];
230
+ for (const file of yield listJsFiles(libDir)) {
231
+ // A compiled-in copy importing its own siblings is noise; report where the
232
+ // app reaches into it.
233
+ if (yield packageSourceOf(file))
114
234
  continue;
115
- for (const found of findInlinedWorkspaceImports(yield readFile(entryPath))) {
116
- inlined.add(found);
235
+ const source = yield fs.readFile(file, 'utf8');
236
+ for (const specifier of findImportSpecifiers(source)) {
237
+ const isPath = specifier.startsWith('./') ||
238
+ specifier.startsWith('../') ||
239
+ specifier.startsWith('/') ||
240
+ specifier.startsWith('file://');
241
+ if (!isPath)
242
+ continue;
243
+ const target = specifier.startsWith('file://')
244
+ ? specifier.slice('file://'.length)
245
+ : path.resolve(path.dirname(file), specifier);
246
+ let found;
247
+ if (isInside(target, libDir)) {
248
+ found = yield packageSourceOf(target);
249
+ }
250
+ else {
251
+ const real = realpathOr(target);
252
+ const owner = ownerOf(real);
253
+ if (owner)
254
+ found = { origin: real, owner };
255
+ }
256
+ if (!found)
257
+ continue;
258
+ imports.push({
259
+ file: path.relative(appRoot, file),
260
+ specifier,
261
+ origin: found.origin,
262
+ packageName: found.owner.name,
263
+ });
117
264
  }
118
265
  }
119
- if (inlined.size === 0)
266
+ return { imports, strayDirs };
267
+ });
268
+ /**
269
+ * Fail the build when the compiled backend contains a copy of a package.
270
+ *
271
+ * A copy compiles and runs — and then fails somewhere else entirely: a second
272
+ * `@_linked/core` splits `LinkedStorage`'s routing state from the one the
273
+ * storage config configures, and a second `@_linked/server-utils` is a second
274
+ * `ShapeProvider` class, so the server's `instanceof` check rejects every
275
+ * provider the app exports. Neither message points anywhere near here.
276
+ *
277
+ * Every file in `lib/` is checked, not only the entries: a copy reached from
278
+ * a feature folder three imports deep is just as much a second copy.
279
+ */
280
+ export const assertNoInlinedWorkspaces = (appRoot, packageRoots) => __awaiter(void 0, void 0, void 0, function* () {
281
+ const roots = packageRoots || (yield packageRootsForApp(appRoot));
282
+ const { imports, strayDirs } = yield findInlinedPackageImports(appRoot, roots);
283
+ if (imports.length === 0 && strayDirs.length === 0)
120
284
  return;
121
- const named = [...inlined].sort();
122
- throw new Error('The compiled backend inlined workspace packages instead of importing ' +
123
- 'them: ' +
124
- named.slice(0, 3).join(', ') +
125
- (named.length > 3 ? `, and ${named.length - 3} more` : '') +
126
- '. Each one is a second copy of that package, and a second copy of ' +
127
- '@_linked/core splits LinkedStorage\'s routing state from the one the ' +
128
- 'storage config configures. Check that the package is discoverable as a ' +
129
- 'workspace, so it can be named in ssr.external.');
285
+ const lines = imports.slice(0, 8).map((found) => ` ${found.file} imports "${found.specifier}"\n` +
286
+ ` — a compiled-in copy of ${found.origin}` +
287
+ (found.packageName ? ` (${found.packageName})` : ''));
288
+ if (imports.length > 8)
289
+ lines.push(` …and ${imports.length - 8} more`);
290
+ const names = [
291
+ ...new Set(imports.map((i) => i.packageName).filter(Boolean)),
292
+ ];
293
+ throw new Error('The compiled backend contains a copy of package code instead of importing it:\n' +
294
+ (lines.length ? lines.join('\n') + '\n' : '') +
295
+ (strayDirs.length
296
+ ? ` ${strayDirs.join(', ')} exists — only code compiled from outside src/ lands there\n`
297
+ : '') +
298
+ 'Each copy is a second instance of that package: its classes fail `instanceof` ' +
299
+ 'and its registries are empty. Import the package through its public export ' +
300
+ (names.length ? `(${names.map((n) => `"${n}" or "${n}/…"`).join(', ')}) ` : '') +
301
+ 'rather than a path into its files, and check that nothing — a resolve.alias, ' +
302
+ 'a `development` export condition — maps that import to its source. A ' +
303
+ 'workspace package must also be discoverable, so it can be named in ssr.external.');
130
304
  });
131
305
  /**
132
306
  * Turn Rollup's unresolved-import error into one that names the actual cause.
@@ -1 +1 @@
1
- {"version":3,"file":"build-backend.js","sourceRoot":"","sources":["../../../src/app-release/build-backend.ts"],"names":[],"mappings":"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","sourcesContent":["import {builtinModules} from 'module';\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * The backend entry points a compiled app is started from.\n *\n * `serve-app` requires all three on disk and `startServer` imports `lib/App.js`\n * and `lib/routes.js` by those exact paths, so the names are a contract, not a\n * convention.\n */\nconst BACKEND_ENTRIES: Record<string, string[]> = {\n backend: ['src/backend.ts', 'src/backend.tsx'],\n App: ['src/App.tsx', 'src/App.ts'],\n routes: ['src/routes.tsx', 'src/routes.ts'],\n};\n\n/**\n * Vite's default server conditions minus the `development|production` token.\n *\n * See the note at the `resolve` option below: dropping the token is what stops\n * a workspace package resolving to its TypeScript source.\n */\nconst SERVER_CONDITIONS = ['module', 'node'];\n\n/** Both spellings, because a backend may use either. */\nconst NODE_BUILTINS = [\n ...builtinModules,\n ...builtinModules.map((name) => `node:${name}`),\n];\n\nexport const resolveBackendEntries = (\n appRoot: string,\n exists: (p: string) => boolean = fs.existsSync\n): Record<string, string> => {\n const entries: Record<string, string> = {};\n for (const [name, candidates] of Object.entries(BACKEND_ENTRIES)) {\n const found = candidates.find((candidate) =>\n exists(path.join(appRoot, candidate))\n );\n if (found) {\n entries[name] = path.join(appRoot, found);\n }\n }\n return entries;\n};\n\n/**\n * Workspace package names to list as `ssr.external`.\n *\n * Vite will not externalise these on its own, and the reason is worth\n * recording because it is entirely non-obvious. `node_modules/@_linked/core`\n * is a symlink into `packages/core`; Vite resolves package data with\n * `preserveSymlinks: false`, so the resolved id realpaths *out* of\n * `node_modules`; and Vite refuses to externalise anything that does not look\n * like it lives there:\n *\n * if (!configuredAsExternal && !isInNodeModules(resolved.id)) return false;\n *\n * So every workspace package got compiled into `lib/`. That is not merely\n * wasteful — `linked.backend.storage.js` is loaded from the APP ROOT by a raw\n * Node `import()` and resolves `@_linked/core` through node_modules, so the\n * storage config configured one copy of `LinkedStorage` while the compiled\n * backend queried another. `LinkedStorage`'s routing state is a per-copy\n * static, so the app's single-instance guard refuses to boot. The old `tsc`\n * build never hit this: it emitted bare specifiers and Node converged on one\n * copy. Naming the packages here restores that.\n *\n * `configuredAsExternal` is the one thing that overrides the symlink rule, and\n * it is keyed on exact package names — no regexes.\n */\nexport const workspacePackagesToExternalize = async (\n appRoot: string,\n discover: (\n globs: string[],\n cwd: string\n ) => Promise<{name: string}[]> = async (globs, cwd) => {\n const {discoverWorkspaces} = await import('../vite-config.js');\n return discoverWorkspaces(globs, cwd);\n }\n): Promise<string[]> => {\n const workspaces = await discover([], appRoot);\n return [...new Set(workspaces.map((w) => w.name))].sort();\n};\n\n/**\n * A relative import from `lib/` into `packages/` means a workspace package was\n * compiled in after all. One into `node_modules/@_linked/` means an installed\n * framework package was: `lib/node_modules/@_linked/server-utils` is a second\n * `ShapeProvider` class, so the server's `instanceof` check rejects every\n * provider the app exports.\n *\n * Worth failing the build over rather than leaving to be discovered: the\n * output is perfectly valid JavaScript, and the symptom is the app refusing to\n * boot with a message about storage routing that points nowhere near here.\n */\nexport const findInlinedWorkspaceImports = (source: string): string[] => {\n // Both static `from \"…\"` and dynamic `import(\"…\")`: a lazily imported page\n // can drag a workspace package in on its own, and only the second form\n // appears in the output for it.\n const matches = source.matchAll(\n /(?:from|import)\\s*\\(?\\s*[\"'](\\.[^\"']*\\/(?:packages|node_modules\\/@_linked)\\/[^\"']+)[\"']/g\n );\n return [...new Set([...matches].map((m) => m[1]))].sort();\n};\n\nexport const assertNoInlinedWorkspaces = async (\n appRoot: string,\n readFile: (p: string) => Promise<string> = (p) => fs.readFile(p, 'utf8')\n): Promise<void> => {\n // Every entry, not just the backend: `App.js` and `routes.js` reach code the\n // backend never imports, so a package can be inlined through either of them.\n const inlined = new Set<string>();\n for (const name of Object.keys(BACKEND_ENTRIES)) {\n const entryPath = path.join(appRoot, 'lib', `${name}.js`);\n if (!fs.existsSync(entryPath)) continue;\n for (const found of findInlinedWorkspaceImports(await readFile(entryPath))) {\n inlined.add(found);\n }\n }\n if (inlined.size === 0) return;\n\n const named = [...inlined].sort();\n throw new Error(\n 'The compiled backend inlined workspace packages instead of importing ' +\n 'them: ' +\n named.slice(0, 3).join(', ') +\n (named.length > 3 ? `, and ${named.length - 3} more` : '') +\n '. Each one is a second copy of that package, and a second copy of ' +\n '@_linked/core splits LinkedStorage\\'s routing state from the one the ' +\n 'storage config configures. Check that the package is discoverable as a ' +\n 'workspace, so it can be named in ssr.external.'\n );\n};\n\n/**\n * Turn Rollup's unresolved-import error into one that names the actual cause.\n *\n * Externalizing a workspace package means the build now resolves it through\n * its published `exports` — its `lib/`, not its `src/`. A package whose `lib/`\n * is stale therefore fails here, on a file that plainly exists in source.\n * Rollup's own message (\"failed to resolve import X\") sends you looking at the\n * import, which is fine.\n */\nexport const explainUnresolvedWorkspaceImport = (\n message: string,\n externalWorkspaces: string[]\n): string | null => {\n const match = message.match(/failed to resolve import \"([^\"]+)\"/i);\n if (!match) return null;\n const specifier = match[1];\n const pkg = externalWorkspaces.find(\n (name) => specifier === name || specifier.startsWith(`${name}/`)\n );\n if (!pkg) return null;\n return (\n `${message}\\n\\n` +\n `\"${pkg}\" is a workspace package, so a release build resolves it through its ` +\n `published exports — its lib/, not its src/. If this file exists in ` +\n `${pkg}/src but not in its build output, that package's lib/ is stale. ` +\n `Build it first (\\`linked build\\` in the package, or \\`linked build-workspace\\`) ` +\n `and run build-app again.`\n );\n};\n\n/**\n * Strip the client build's `manualChunks` from the SSR output options.\n *\n * Rollup refuses `manualChunks` together with `preserveModules`, and passing\n * `undefined` in the inline config does not remove it — Vite's config merge\n * keeps the app's value. So it is cleared in the output hook instead, after\n * the merge. Chunk grouping is a client concern; the backend wants one output\n * file per source file.\n */\nconst dropManualChunks = () => ({\n name: 'linked:backend-no-manual-chunks',\n enforce: 'post' as const,\n outputOptions(options: Record<string, unknown>) {\n if (!options.manualChunks) return null;\n const {manualChunks: _dropped, ...rest} = options;\n return rest;\n },\n});\n\n/**\n * Compile the app's backend to `lib/`.\n *\n * This runs Vite in SSR mode against the app's own `vite.config`, which is the\n * point: `linked start` already loads `src/backend.ts`, `src/App.tsx` and\n * `src/routes.tsx` through `vite.ssrLoadModule`, so a production build that\n * used anything else was resolving the same source differently from dev. The\n * workspace resolver, the decorator transform and extensionless relative\n * imports all come along for free.\n *\n * `preserveModules` keeps `src/`'s file layout in `lib/`, so the entry paths\n * stay where `serve-app` and `startServer` look for them and lazily imported\n * pages keep their own files. `manualChunks` is cleared because Rollup refuses\n * to run it alongside `preserveModules` — and it is a client-side concern\n * anyway.\n *\n * Workspace packages are named as `ssr.external` explicitly; see\n * `workspacePackagesToExternalize` for why Vite does not do it on its own.\n * Node's built-ins are listed by hand for a related reason: Vite externalises\n * them for SSR only when it recognises the specifier, and a bare `crypto` —\n * which a backend written for Node may perfectly well import — resolved\n * instead to the abandoned `crypto` shim package sitting in node_modules, and\n * failed the build.\n *\n * `copyPublicDir` is off because `public/` is the client build's output, not\n * the backend's. Left on, it copied 38MB of already-built bundles into `lib/`.\n */\nexport const buildBackendWithVite = async (\n options: {appRoot?: string} = {},\n dependencies: {viteBuild?: (config: any) => Promise<unknown>} = {}\n): Promise<void> => {\n const appRoot = options.appRoot || process.cwd();\n const entries = resolveBackendEntries(appRoot);\n\n if (!entries.backend) {\n throw new Error(\n 'No backend entry found: expected src/backend.ts in ' + appRoot\n );\n }\n\n const viteBuild =\n dependencies.viteBuild ||\n (async (config: any) => {\n const {build} = await import('vite');\n return build(config);\n });\n\n const externalWorkspaces = await workspacePackagesToExternalize(appRoot);\n\n try {\n await viteBuild({\n root: appRoot,\n mode: 'production',\n isProduction: true,\n // The client build sets `base` to the release URL. The backend emits no\n // asset URLs of its own, so it must not inherit one.\n base: '/',\n // Never resolve a `development` export condition in a release build.\n //\n // The workspace-source convention is\n // \"development\": \"./src/*.ts\", \"import\": \"./lib/esm/*.js\"\n // and Vite expands its `development|production` token from NODE_ENV —\n // which during a release build is whatever the app's `.env` says,\n // routinely `development`. The package then resolves to TypeScript, which\n // cannot be externalised because Node could not load it, so it is\n // compiled in regardless of what `ssr.external` says.\n //\n // Dropping the token (rather than pinning it to `production`) leaves\n // `import` — which Vite always appends last — to win. Same treatment\n // `createViteConfig` already applies to a standalone install, for the\n // mirror-image reason.\n //\n // All three lists have to say it: `ssr.resolve.conditions` does not\n // inherit from `resolve.conditions` here, and `externalConditions`\n // governs the packages that end up external.\n resolve: {conditions: SERVER_CONDITIONS},\n ssr: {\n // Merged with the app's own ssr.external rather than replacing it.\n external: externalWorkspaces,\n resolve: {\n conditions: SERVER_CONDITIONS,\n externalConditions: SERVER_CONDITIONS,\n },\n },\n plugins: [dropManualChunks()],\n build: {\n ssr: true,\n outDir: 'lib',\n emptyOutDir: true,\n copyPublicDir: false,\n manifest: false,\n sourcemap: true,\n rollupOptions: {\n input: entries,\n external: NODE_BUILTINS,\n output: {\n format: 'es',\n preserveModules: true,\n preserveModulesRoot: path.join(appRoot, 'src'),\n entryFileNames: '[name].js',\n chunkFileNames: '[name].js',\n },\n },\n },\n });\n } catch (err) {\n const explained = explainUnresolvedWorkspaceImport(\n err instanceof Error ? err.message : String(err),\n externalWorkspaces\n );\n if (!explained) throw err;\n throw new Error(explained);\n }\n\n await assertNoInlinedWorkspaces(appRoot);\n};\n\n/**\n * Copy `src`'s CSS next to the compiled backend.\n *\n * The server reads stylesheets like `lib/css/theme.css` off disk by path, so\n * they have to exist as files whether or not any module imported them.\n */\nexport const copyBackendStylesheets = async (\n appRoot: string,\n listCssFiles: (dir: string) => Promise<string[]>\n): Promise<number> => {\n const sourceFolder = path.join(appRoot, 'src');\n const targetFolder = path.join(appRoot, 'lib');\n const cssFiles = await listCssFiles(sourceFolder);\n await Promise.all(\n cssFiles.map((file) => {\n const targetFile = file.replace(sourceFolder, targetFolder);\n fs.mkdirpSync(path.dirname(targetFile));\n return fs.copyFile(file, targetFile);\n })\n );\n return cssFiles.length;\n};\n"]}
1
+ {"version":3,"file":"build-backend.js","sourceRoot":"","sources":["../../../src/app-release/build-backend.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,eAAe,GAA6B;IAChD,OAAO,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC9C,GAAG,EAAE,CAAC,aAAa,EAAE,YAAY,CAAC;IAClC,MAAM,EAAE,CAAC,gBAAgB,EAAE,eAAe,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAE7C,wDAAwD;AACxD,MAAM,aAAa,GAAG;IACpB,GAAG,cAAc;IACjB,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC;CAChD,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACf,SAAiC,EAAE,CAAC,UAAU,EACtB,EAAE;IAC1B,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QACjE,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAC1C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CACtC,CAAC;QACF,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBASzB,EAAE,8DARrB,OAAe,EACf,WAGiC,CAAO,KAAK,EAAE,GAAG,EAAE,EAAE;IACpD,MAAM,EAAC,kBAAkB,EAAC,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/D,OAAO,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC,CAAA;IAED,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC,CAAA,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAc,EAAY,EAAE;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAC7B,sEAAsE,CACvE,CAAC;IACF,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC,CAAC;AAwBF;;;;;;;;;;GAUG;AACH,MAAM,iBAAiB,GAAG,CAAC,UAAU,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;AAEzE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE;IACvC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,MAAc,EAAW,EAAE;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACxE,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAO,GAAW,EAAqB,EAAE;IAC3D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAO,OAAe,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAC,aAAa,EAAE,IAAI,EAAC,CAAC,CAAC;QAC1E,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,GAAG,CAAC,CAAO,KAAK,EAAE,EAAE;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,KAAK,CAAC,WAAW,EAAE;gBAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;iBACrC,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,CAAC,CAAA,CAAC,CACH,CAAC;IACJ,CAAC,CAAA,CAAC;IACF,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC,CAAA,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBASR,EAAE,8DAR1B,OAAe,EACf,WAGiD,CAAO,KAAK,EAAE,GAAG,EAAE,EAAE;IACpE,MAAM,EAAC,kBAAkB,EAAC,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/D,OAAO,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC,CAAA;IAED,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,KAAK,MAAM,EAAE,IAAI,MAAM,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAC,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC3D,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,EAAC,CAAC,CAAC;QAClE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,EAAC,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;gBAC/C,IAAI,EAAE,YAAY,KAAK,EAAE;aAC1B,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,EAAC,CAAC,CAAC;IAC9C,CAAC;IACD,2EAA2E;IAC3E,2BAA2B;IAC3B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC,CAAA,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAe,EACf,YAA2B,EACsC,EAAE;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CACxC,CAAC,IAAI,EAAE,EAAE,CACP,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAClD,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,SAAS,EAAC,CAAC;IAE5D,MAAM,OAAO,GAAG,CAAC,IAAY,EAA2B,EAAE,CACxD,YAAY;SACT,MAAM,CAAC,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACzC,oEAAoE;SACnE,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CACvE,CAAC,CAAC,CAAC,CAAC;IAET,+DAA+D;IAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAChD,MAAM,SAAS,GAAG,CAAO,UAAkB,EAAqB,EAAE;QAChE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAC1B,IAAI,OAAO,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,UAAU,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;YACvE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;YAC1E,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;iBAC1B,MAAM,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;iBACpE,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;QAAC,WAAM,CAAC;YACP,kEAAkE;YAClE,qDAAqD;QACvD,CAAC;QACD,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC,CAAA,CAAC;IACF,MAAM,eAAe,GAAG,CAAO,UAAkB,EAAE,EAAE;QACnD,KAAK,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9B,IAAI,KAAK;gBAAE,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,CAAC;QACpC,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAA,CAAC;IAEF,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7C,2EAA2E;QAC3E,uBAAuB;QACvB,IAAI,MAAM,eAAe,CAAC,IAAI,CAAC;YAAE,SAAS;QAC1C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/C,KAAK,MAAM,SAAS,IAAI,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,MAAM,MAAM,GACV,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC;gBAC1B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC;gBAC3B,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;gBACzB,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC;gBAC5C,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;gBACnC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;YAEhD,IAAI,KAAuD,CAAC;YAC5D,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;gBAC7B,KAAK,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;gBAChC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,KAAK;oBAAE,KAAK,GAAG,EAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAC,CAAC;YAC3C,CAAC;YACD,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;gBAClC,SAAS;gBACT,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,EAAC,OAAO,EAAE,SAAS,EAAC,CAAC;AAC9B,CAAC,CAAA,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAe,EACf,YAA4B,EACb,EAAE;IACjB,MAAM,KAAK,GAAG,YAAY,IAAI,CAAC,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,MAAM,EAAC,OAAO,EAAE,SAAS,EAAC,GAAG,MAAM,yBAAyB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC7E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE3D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CACnC,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,KAAK,CAAC,IAAI,aAAa,KAAK,CAAC,SAAS,KAAK;QAChD,+BAA+B,KAAK,CAAC,MAAM,EAAE;QAC7C,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CACvD,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG;QACZ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;KAClD,CAAC;IACd,MAAM,IAAI,KAAK,CACb,iFAAiF;QAC/E,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,CAAC,SAAS,CAAC,MAAM;YACf,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,8DAA8D;YACzF,CAAC,CAAC,EAAE,CAAC;QACP,gFAAgF;QAChF,6EAA6E;QAC7E,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,+EAA+E;QAC/E,uEAAuE;QACvE,kFAAkF,CACrF,CAAC;AACJ,CAAC,CAAA,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,OAAe,EACf,kBAA4B,EACb,EAAE;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CACjC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CACjE,CAAC;IACF,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,CACL,GAAG,OAAO,MAAM;QAChB,IAAI,GAAG,uEAAuE;QAC9E,qEAAqE;QACrE,GAAG,GAAG,kEAAkE;QACxE,kFAAkF;QAClF,0BAA0B,CAC3B,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,CAAC;IAC9B,IAAI,EAAE,iCAAiC;IACvC,OAAO,EAAE,MAAe;IACxB,aAAa,CAAC,OAAgC;QAC5C,IAAI,CAAC,OAAO,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC;QACvC,MAAM,EAAC,YAAY,EAAE,QAAQ,KAAa,OAAO,EAAf,IAAI,UAAI,OAAO,EAA3C,gBAAiC,CAAU,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAGnB,EAAE,mDAFjB,UAA8B,EAAE,EAChC,eAAgE,EAAE;IAElE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE/C,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,qDAAqD,GAAG,OAAO,CAChE,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GACb,YAAY,CAAC,SAAS;QACtB,CAAC,CAAO,MAAW,EAAE,EAAE;YACrB,MAAM,EAAC,KAAK,EAAC,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;YACrC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC,CAAA,CAAC,CAAC;IAEL,MAAM,kBAAkB,GAAG,MAAM,8BAA8B,CAAC,OAAO,CAAC,CAAC;IAEzE,IAAI,CAAC;QACH,MAAM,SAAS,CAAC;YACd,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,YAAY;YAClB,YAAY,EAAE,IAAI;YAClB,wEAAwE;YACxE,qDAAqD;YACrD,IAAI,EAAE,GAAG;YACT,qEAAqE;YACrE,EAAE;YACF,qCAAqC;YACrC,6DAA6D;YAC7D,sEAAsE;YACtE,kEAAkE;YAClE,0EAA0E;YAC1E,kEAAkE;YAClE,sDAAsD;YACtD,EAAE;YACF,qEAAqE;YACrE,qEAAqE;YACrE,sEAAsE;YACtE,uBAAuB;YACvB,EAAE;YACF,oEAAoE;YACpE,mEAAmE;YACnE,6CAA6C;YAC7C,OAAO,EAAE,EAAC,UAAU,EAAE,iBAAiB,EAAC;YACxC,GAAG,EAAE;gBACH,mEAAmE;gBACnE,QAAQ,EAAE,kBAAkB;gBAC5B,OAAO,EAAE;oBACP,UAAU,EAAE,iBAAiB;oBAC7B,kBAAkB,EAAE,iBAAiB;iBACtC;aACF;YACD,OAAO,EAAE,CAAC,gBAAgB,EAAE,CAAC;YAC7B,KAAK,EAAE;gBACL,GAAG,EAAE,IAAI;gBACT,MAAM,EAAE,KAAK;gBACb,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,KAAK;gBACpB,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,IAAI;gBACf,aAAa,EAAE;oBACb,KAAK,EAAE,OAAO;oBACd,QAAQ,EAAE,aAAa;oBACvB,MAAM,EAAE;wBACN,MAAM,EAAE,IAAI;wBACZ,eAAe,EAAE,IAAI;wBACrB,mBAAmB,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC;wBAC9C,cAAc,EAAE,WAAW;wBAC3B,cAAc,EAAE,WAAW;qBAC5B;iBACF;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,gCAAgC,CAChD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAChD,kBAAkB,CACnB,CAAC;QACF,IAAI,CAAC,SAAS;YAAE,MAAM,GAAG,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,yBAAyB,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAA,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,OAAe,EACf,YAAgD,EAC/B,EAAE;IACnB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,OAAO,CAAC,GAAG,CACf,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACpB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC5D,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QACxC,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC,CAAC,CACH,CAAC;IACF,OAAO,QAAQ,CAAC,MAAM,CAAC;AACzB,CAAC,CAAA,CAAC","sourcesContent":["import {builtinModules} from 'module';\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * The backend entry points a compiled app is started from.\n *\n * `serve-app` requires all three on disk and `startServer` imports `lib/App.js`\n * and `lib/routes.js` by those exact paths, so the names are a contract, not a\n * convention.\n */\nconst BACKEND_ENTRIES: Record<string, string[]> = {\n backend: ['src/backend.ts', 'src/backend.tsx'],\n App: ['src/App.tsx', 'src/App.ts'],\n routes: ['src/routes.tsx', 'src/routes.ts'],\n};\n\n/**\n * Vite's default server conditions minus the `development|production` token.\n *\n * See the note at the `resolve` option below: dropping the token is what stops\n * a workspace package resolving to its TypeScript source.\n */\nconst SERVER_CONDITIONS = ['module', 'node'];\n\n/** Both spellings, because a backend may use either. */\nconst NODE_BUILTINS = [\n ...builtinModules,\n ...builtinModules.map((name) => `node:${name}`),\n];\n\nexport const resolveBackendEntries = (\n appRoot: string,\n exists: (p: string) => boolean = fs.existsSync\n): Record<string, string> => {\n const entries: Record<string, string> = {};\n for (const [name, candidates] of Object.entries(BACKEND_ENTRIES)) {\n const found = candidates.find((candidate) =>\n exists(path.join(appRoot, candidate))\n );\n if (found) {\n entries[name] = path.join(appRoot, found);\n }\n }\n return entries;\n};\n\n/**\n * Workspace package names to list as `ssr.external`.\n *\n * Vite will not externalise these on its own, and the reason is worth\n * recording because it is entirely non-obvious. `node_modules/@_linked/core`\n * is a symlink into `packages/core`; Vite resolves package data with\n * `preserveSymlinks: false`, so the resolved id realpaths *out* of\n * `node_modules`; and Vite refuses to externalise anything that does not look\n * like it lives there:\n *\n * if (!configuredAsExternal && !isInNodeModules(resolved.id)) return false;\n *\n * So every workspace package got compiled into `lib/`. That is not merely\n * wasteful — `linked.backend.storage.js` is loaded from the APP ROOT by a raw\n * Node `import()` and resolves `@_linked/core` through node_modules, so the\n * storage config configured one copy of `LinkedStorage` while the compiled\n * backend queried another. `LinkedStorage`'s routing state is a per-copy\n * static, so the app's single-instance guard refuses to boot. The old `tsc`\n * build never hit this: it emitted bare specifiers and Node converged on one\n * copy. Naming the packages here restores that.\n *\n * `configuredAsExternal` is the one thing that overrides the symlink rule, and\n * it is keyed on exact package names — no regexes.\n */\nexport const workspacePackagesToExternalize = async (\n appRoot: string,\n discover: (\n globs: string[],\n cwd: string\n ) => Promise<{name: string}[]> = async (globs, cwd) => {\n const {discoverWorkspaces} = await import('../vite-config.js');\n return discoverWorkspaces(globs, cwd);\n }\n): Promise<string[]> => {\n const workspaces = await discover([], appRoot);\n return [...new Set(workspaces.map((w) => w.name))].sort();\n};\n\n/**\n * Every module specifier a compiled file imports: static `from \"…\"`, side-effect\n * `import \"…\"`, dynamic `import(\"…\")`, and `require(\"…\")`.\n *\n * Deliberately loose — it can match text inside a string or a comment. That is\n * harmless: only specifiers that resolve to a file on disk are acted on, and\n * only when that file turns out to be a copy of a package.\n */\nexport const findImportSpecifiers = (source: string): string[] => {\n const matches = source.matchAll(\n /(?:\\bfrom\\s*|\\bimport\\s*\\(?\\s*|\\brequire\\s*\\(\\s*)[\"']([^\"'\\n]+)[\"']/g\n );\n return [...new Set([...matches].map((m) => m[1]))].sort();\n};\n\n/** One import in `lib/` that reaches a compiled-in copy of a package. */\nexport interface InlinedPackageImport {\n /** The importing file, relative to the app root (`lib/…/PageView.js`). */\n file: string;\n /** The specifier exactly as it appears in that file. */\n specifier: string;\n /** Real path of the package source the imported module was compiled from. */\n origin: string;\n /** Name of the package that source belongs to, when it is known. */\n packageName?: string;\n}\n\n/**\n * A directory whose real path is package code the backend must import rather\n * than compile: a workspace package, a localized checkout, an installed\n * framework package.\n */\nexport interface PackageRoot {\n root: string;\n name?: string;\n}\n\n/**\n * Top-level directories of `lib/` that only exist when code from outside\n * `src/` was compiled in.\n *\n * `preserveModules` lays `lib/` out relative to the common ancestor of every\n * module in the build. With `preserveModulesRoot: src` the app's own files lose\n * their `src/` prefix, and anything else keeps its path from the app root — so\n * a compiled-in workspace package lands at `lib/packages/…`, an installed one at\n * `lib/node_modules/…`. Only when the app has no `src/` directory of that name,\n * since an app is free to have its own `src/packages/`.\n */\nconst STRAY_OUTPUT_DIRS = ['packages', 'packages-local', 'node_modules'];\n\nconst realpathOr = (p: string): string => {\n try {\n return fs.realpathSync(p);\n } catch {\n return path.resolve(p);\n }\n};\n\nconst isInside = (child: string, parent: string): boolean => {\n const rel = path.relative(parent, child);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n};\n\nconst listJsFiles = async (dir: string): Promise<string[]> => {\n const out: string[] = [];\n const walk = async (current: string) => {\n const entries = await fs.promises.readdir(current, {withFileTypes: true});\n await Promise.all(\n entries.map(async (entry) => {\n const full = path.join(current, entry.name);\n if (entry.isDirectory()) await walk(full);\n else if (/\\.(?:m|c)?js$/.test(entry.name)) out.push(full);\n })\n );\n };\n await walk(dir);\n return out.sort();\n};\n\n/**\n * The package roots an app's compiled backend must never contain a copy of,\n * as real paths: every discovered workspace package, everything under\n * `packages-local/`, and every installed `@_linked/*` package (whose real path\n * is a localized checkout when it has been localized).\n */\nexport const packageRootsForApp = async (\n appRoot: string,\n discover: (\n globs: string[],\n cwd: string\n ) => Promise<{name: string; srcDir: string}[]> = async (globs, cwd) => {\n const {discoverWorkspaces} = await import('../vite-config.js');\n return discoverWorkspaces(globs, cwd);\n }\n): Promise<PackageRoot[]> => {\n const roots: PackageRoot[] = [];\n for (const ws of await discover([], appRoot)) {\n roots.push({root: realpathOr(path.dirname(ws.srcDir)), name: ws.name});\n }\n const packagesLocal = path.join(appRoot, 'packages-local');\n if (fs.existsSync(packagesLocal)) {\n for (const entry of await fs.readdir(packagesLocal)) {\n roots.push({root: realpathOr(path.join(packagesLocal, entry))});\n }\n roots.push({root: realpathOr(packagesLocal)});\n }\n const linkedScope = path.join(appRoot, 'node_modules', '@_linked');\n if (fs.existsSync(linkedScope)) {\n for (const entry of await fs.readdir(linkedScope)) {\n roots.push({\n root: realpathOr(path.join(linkedScope, entry)),\n name: `@_linked/${entry}`,\n });\n }\n roots.push({root: realpathOr(linkedScope)});\n }\n // The app itself can be discovered as a workspace; its own source is not a\n // second copy of anything.\n const appSrc = realpathOr(path.join(appRoot, 'src'));\n return roots.filter(({root}) => !isInside(appSrc, root));\n};\n\n/**\n * Find every import in the compiled backend that reaches a compiled-in copy of\n * a package.\n *\n * Each relative specifier is resolved against its file, and the module it\n * lands on is traced back to the source it was compiled from through that\n * module's sourcemap. The source's REAL path is then compared with the\n * package roots — so it does not matter what the copy's directory in `lib/` is\n * called, or whether the package was reached through a symlink. An import that\n * leaves `lib/` altogether is judged by its own real path.\n *\n * Only imports from the app's own modules are reported: they are the ones to\n * change, and every compiled-in copy is reached through one of them.\n */\nexport const findInlinedPackageImports = async (\n appRoot: string,\n packageRoots: PackageRoot[]\n): Promise<{imports: InlinedPackageImport[]; strayDirs: string[]}> => {\n const libDir = path.join(appRoot, 'lib');\n const strayDirs = STRAY_OUTPUT_DIRS.filter(\n (name) =>\n fs.existsSync(path.join(libDir, name)) &&\n !fs.existsSync(path.join(appRoot, 'src', name))\n ).map((name) => `lib/${name}/`);\n if (!fs.existsSync(libDir)) return {imports: [], strayDirs};\n\n const ownerOf = (real: string): PackageRoot | undefined =>\n packageRoots\n .filter(({root}) => isInside(real, root))\n // The most specific root names the package; a named one wins a tie.\n .sort(\n (a, b) =>\n b.root.length - a.root.length || Number(!!b.name) - Number(!!a.name)\n )[0];\n\n // Where a module in lib/ was compiled from, via its sourcemap.\n const originCache = new Map<string, string[]>();\n const originsOf = async (moduleFile: string): Promise<string[]> => {\n const cached = originCache.get(moduleFile);\n if (cached) return cached;\n let origins: string[] = [];\n try {\n const map = JSON.parse(await fs.readFile(`${moduleFile}.map`, 'utf8'));\n const base = path.resolve(path.dirname(moduleFile), map.sourceRoot || '');\n origins = (map.sources || [])\n .filter((s: unknown) => typeof s === 'string' && !s.startsWith('\\0'))\n .map((s: string) => realpathOr(path.resolve(base, s.replace(/^file:\\/\\//, ''))));\n } catch {\n // No sourcemap: nothing to trace. The stray-directory check still\n // catches the usual layout of a compiled-in package.\n }\n originCache.set(moduleFile, origins);\n return origins;\n };\n const packageSourceOf = async (moduleFile: string) => {\n for (const origin of await originsOf(moduleFile)) {\n const owner = ownerOf(origin);\n if (owner) return {origin, owner};\n }\n return undefined;\n };\n\n const imports: InlinedPackageImport[] = [];\n for (const file of await listJsFiles(libDir)) {\n // A compiled-in copy importing its own siblings is noise; report where the\n // app reaches into it.\n if (await packageSourceOf(file)) continue;\n const source = await fs.readFile(file, 'utf8');\n for (const specifier of findImportSpecifiers(source)) {\n const isPath =\n specifier.startsWith('./') ||\n specifier.startsWith('../') ||\n specifier.startsWith('/') ||\n specifier.startsWith('file://');\n if (!isPath) continue;\n const target = specifier.startsWith('file://')\n ? specifier.slice('file://'.length)\n : path.resolve(path.dirname(file), specifier);\n\n let found: {origin: string; owner: PackageRoot} | undefined;\n if (isInside(target, libDir)) {\n found = await packageSourceOf(target);\n } else {\n const real = realpathOr(target);\n const owner = ownerOf(real);\n if (owner) found = {origin: real, owner};\n }\n if (!found) continue;\n imports.push({\n file: path.relative(appRoot, file),\n specifier,\n origin: found.origin,\n packageName: found.owner.name,\n });\n }\n }\n return {imports, strayDirs};\n};\n\n/**\n * Fail the build when the compiled backend contains a copy of a package.\n *\n * A copy compiles and runs — and then fails somewhere else entirely: a second\n * `@_linked/core` splits `LinkedStorage`'s routing state from the one the\n * storage config configures, and a second `@_linked/server-utils` is a second\n * `ShapeProvider` class, so the server's `instanceof` check rejects every\n * provider the app exports. Neither message points anywhere near here.\n *\n * Every file in `lib/` is checked, not only the entries: a copy reached from\n * a feature folder three imports deep is just as much a second copy.\n */\nexport const assertNoInlinedWorkspaces = async (\n appRoot: string,\n packageRoots?: PackageRoot[]\n): Promise<void> => {\n const roots = packageRoots || (await packageRootsForApp(appRoot));\n const {imports, strayDirs} = await findInlinedPackageImports(appRoot, roots);\n if (imports.length === 0 && strayDirs.length === 0) return;\n\n const lines = imports.slice(0, 8).map(\n (found) =>\n ` ${found.file} imports \"${found.specifier}\"\\n` +\n ` — a compiled-in copy of ${found.origin}` +\n (found.packageName ? ` (${found.packageName})` : '')\n );\n if (imports.length > 8) lines.push(` …and ${imports.length - 8} more`);\n const names = [\n ...new Set(imports.map((i) => i.packageName).filter(Boolean)),\n ] as string[];\n throw new Error(\n 'The compiled backend contains a copy of package code instead of importing it:\\n' +\n (lines.length ? lines.join('\\n') + '\\n' : '') +\n (strayDirs.length\n ? ` ${strayDirs.join(', ')} exists — only code compiled from outside src/ lands there\\n`\n : '') +\n 'Each copy is a second instance of that package: its classes fail `instanceof` ' +\n 'and its registries are empty. Import the package through its public export ' +\n (names.length ? `(${names.map((n) => `\"${n}\" or \"${n}/…\"`).join(', ')}) ` : '') +\n 'rather than a path into its files, and check that nothing — a resolve.alias, ' +\n 'a `development` export condition — maps that import to its source. A ' +\n 'workspace package must also be discoverable, so it can be named in ssr.external.'\n );\n};\n\n/**\n * Turn Rollup's unresolved-import error into one that names the actual cause.\n *\n * Externalizing a workspace package means the build now resolves it through\n * its published `exports` — its `lib/`, not its `src/`. A package whose `lib/`\n * is stale therefore fails here, on a file that plainly exists in source.\n * Rollup's own message (\"failed to resolve import X\") sends you looking at the\n * import, which is fine.\n */\nexport const explainUnresolvedWorkspaceImport = (\n message: string,\n externalWorkspaces: string[]\n): string | null => {\n const match = message.match(/failed to resolve import \"([^\"]+)\"/i);\n if (!match) return null;\n const specifier = match[1];\n const pkg = externalWorkspaces.find(\n (name) => specifier === name || specifier.startsWith(`${name}/`)\n );\n if (!pkg) return null;\n return (\n `${message}\\n\\n` +\n `\"${pkg}\" is a workspace package, so a release build resolves it through its ` +\n `published exports — its lib/, not its src/. If this file exists in ` +\n `${pkg}/src but not in its build output, that package's lib/ is stale. ` +\n `Build it first (\\`linked build\\` in the package, or \\`linked build-workspace\\`) ` +\n `and run build-app again.`\n );\n};\n\n/**\n * Strip the client build's `manualChunks` from the SSR output options.\n *\n * Rollup refuses `manualChunks` together with `preserveModules`, and passing\n * `undefined` in the inline config does not remove it — Vite's config merge\n * keeps the app's value. So it is cleared in the output hook instead, after\n * the merge. Chunk grouping is a client concern; the backend wants one output\n * file per source file.\n */\nconst dropManualChunks = () => ({\n name: 'linked:backend-no-manual-chunks',\n enforce: 'post' as const,\n outputOptions(options: Record<string, unknown>) {\n if (!options.manualChunks) return null;\n const {manualChunks: _dropped, ...rest} = options;\n return rest;\n },\n});\n\n/**\n * Compile the app's backend to `lib/`.\n *\n * This runs Vite in SSR mode against the app's own `vite.config`, which is the\n * point: `linked start` already loads `src/backend.ts`, `src/App.tsx` and\n * `src/routes.tsx` through `vite.ssrLoadModule`, so a production build that\n * used anything else was resolving the same source differently from dev. The\n * workspace resolver, the decorator transform and extensionless relative\n * imports all come along for free.\n *\n * `preserveModules` keeps `src/`'s file layout in `lib/`, so the entry paths\n * stay where `serve-app` and `startServer` look for them and lazily imported\n * pages keep their own files. `manualChunks` is cleared because Rollup refuses\n * to run it alongside `preserveModules` — and it is a client-side concern\n * anyway.\n *\n * Workspace packages are named as `ssr.external` explicitly; see\n * `workspacePackagesToExternalize` for why Vite does not do it on its own.\n * Node's built-ins are listed by hand for a related reason: Vite externalises\n * them for SSR only when it recognises the specifier, and a bare `crypto` —\n * which a backend written for Node may perfectly well import — resolved\n * instead to the abandoned `crypto` shim package sitting in node_modules, and\n * failed the build.\n *\n * `copyPublicDir` is off because `public/` is the client build's output, not\n * the backend's. Left on, it copied 38MB of already-built bundles into `lib/`.\n */\nexport const buildBackendWithVite = async (\n options: {appRoot?: string} = {},\n dependencies: {viteBuild?: (config: any) => Promise<unknown>} = {}\n): Promise<void> => {\n const appRoot = options.appRoot || process.cwd();\n const entries = resolveBackendEntries(appRoot);\n\n if (!entries.backend) {\n throw new Error(\n 'No backend entry found: expected src/backend.ts in ' + appRoot\n );\n }\n\n const viteBuild =\n dependencies.viteBuild ||\n (async (config: any) => {\n const {build} = await import('vite');\n return build(config);\n });\n\n const externalWorkspaces = await workspacePackagesToExternalize(appRoot);\n\n try {\n await viteBuild({\n root: appRoot,\n mode: 'production',\n isProduction: true,\n // The client build sets `base` to the release URL. The backend emits no\n // asset URLs of its own, so it must not inherit one.\n base: '/',\n // Never resolve a `development` export condition in a release build.\n //\n // The workspace-source convention is\n // \"development\": \"./src/*.ts\", \"import\": \"./lib/esm/*.js\"\n // and Vite expands its `development|production` token from NODE_ENV —\n // which during a release build is whatever the app's `.env` says,\n // routinely `development`. The package then resolves to TypeScript, which\n // cannot be externalised because Node could not load it, so it is\n // compiled in regardless of what `ssr.external` says.\n //\n // Dropping the token (rather than pinning it to `production`) leaves\n // `import` — which Vite always appends last — to win. Same treatment\n // `createViteConfig` already applies to a standalone install, for the\n // mirror-image reason.\n //\n // All three lists have to say it: `ssr.resolve.conditions` does not\n // inherit from `resolve.conditions` here, and `externalConditions`\n // governs the packages that end up external.\n resolve: {conditions: SERVER_CONDITIONS},\n ssr: {\n // Merged with the app's own ssr.external rather than replacing it.\n external: externalWorkspaces,\n resolve: {\n conditions: SERVER_CONDITIONS,\n externalConditions: SERVER_CONDITIONS,\n },\n },\n plugins: [dropManualChunks()],\n build: {\n ssr: true,\n outDir: 'lib',\n emptyOutDir: true,\n copyPublicDir: false,\n manifest: false,\n sourcemap: true,\n rollupOptions: {\n input: entries,\n external: NODE_BUILTINS,\n output: {\n format: 'es',\n preserveModules: true,\n preserveModulesRoot: path.join(appRoot, 'src'),\n entryFileNames: '[name].js',\n chunkFileNames: '[name].js',\n },\n },\n },\n });\n } catch (err) {\n const explained = explainUnresolvedWorkspaceImport(\n err instanceof Error ? err.message : String(err),\n externalWorkspaces\n );\n if (!explained) throw err;\n throw new Error(explained);\n }\n\n await assertNoInlinedWorkspaces(appRoot);\n};\n\n/**\n * Copy `src`'s CSS next to the compiled backend.\n *\n * The server reads stylesheets like `lib/css/theme.css` off disk by path, so\n * they have to exist as files whether or not any module imported them.\n */\nexport const copyBackendStylesheets = async (\n appRoot: string,\n listCssFiles: (dir: string) => Promise<string[]>\n): Promise<number> => {\n const sourceFolder = path.join(appRoot, 'src');\n const targetFolder = path.join(appRoot, 'lib');\n const cssFiles = await listCssFiles(sourceFolder);\n await Promise.all(\n cssFiles.map((file) => {\n const targetFile = file.replace(sourceFolder, targetFolder);\n fs.mkdirpSync(path.dirname(targetFile));\n return fs.copyFile(file, targetFile);\n })\n );\n return cssFiles.length;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cli-methods.d.ts","sourceRoot":"","sources":["../../src/cli-methods.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli-methods.d.ts","sourceRoot":"","sources":["../../src/cli-methods.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,7 @@ import { planPackageSetup } from './utils/packageSetup.js';
20
20
  import { detectPackageManager, execBinCommand, runScriptCommand, } from './utils/packageManager.js';
21
21
  import { rewriteExtensionlessImports } from './utils/esmSpecifiers.js';
22
22
  import { checkShapeNames } from './utils/shapeNames.js';
23
+ import { checkShapeReferences } from './utils/shapeReferences.js';
23
24
  import { spawn as spawnChild } from 'child_process';
24
25
  import { findNearestPackageJson } from 'find-nearest-package-json';
25
26
  import { statSync } from 'fs';
@@ -2273,6 +2274,13 @@ export const planBuildSteps = (pkgJson, packagePath) => [
2273
2274
  name: 'Checking shape names',
2274
2275
  apply: () => checkShapeNames(packagePath),
2275
2276
  },
2277
+ {
2278
+ // Loads each compiled shape module on its own, so it needs the final
2279
+ // lib/esm too. Fails the build: an unresolved reference is a query that
2280
+ // throws "Shape class not found" in a consumer's bundle.
2281
+ name: 'Checking shape references',
2282
+ apply: () => checkShapeReferences(packagePath),
2283
+ },
2276
2284
  {
2277
2285
  name: 'Checking dependencies',
2278
2286
  apply: () => depCheck(packagePath),