@_linked/server 2.0.3 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +13 -1
- package/CHANGELOG.md +32 -0
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/ontologies/lincd-server.d.ts +42 -25
- package/lib/esm/shapes/LincdAPI.d.ts +3 -3
- package/lib/esm/shapes/LincdWebApp.d.ts +1 -1
- package/lib/esm/shapes/{LincdServer.d.ts → LinkedServer.d.ts} +30 -2
- package/lib/esm/shapes/{LincdServer.js → LinkedServer.js} +444 -158
- package/lib/esm/shapes/LinkedServer.js.map +1 -0
- package/lib/esm/shapes/quadstores/BackendAPIStore.d.ts +1 -1
- package/lib/esm/shapes/quadstores/BackendAPIStore.js +7 -7
- package/lib/esm/shapes/quadstores/BackendAPIStore.js.map +1 -1
- package/lib/esm/shapes/quadstores/BackendAPIStoreProvider.d.ts +10 -5
- package/lib/esm/shapes/quadstores/BackendAPIStoreProvider.js +15 -9
- package/lib/esm/shapes/quadstores/BackendAPIStoreProvider.js.map +1 -1
- package/lib/esm/utils/Shapes.d.ts +1 -1
- package/lib/esm/utils/Shapes.js +4 -3
- package/lib/esm/utils/Shapes.js.map +1 -1
- package/package.json +15 -17
- package/readme.md +100 -0
- package/tsconfig-esm.json +1 -1
- package/lib/cjs/backend.d.ts +0 -6
- package/lib/cjs/backend.js +0 -58
- package/lib/cjs/backend.js.map +0 -1
- package/lib/cjs/data/lincd-server.json +0 -47
- package/lib/cjs/index.d.ts +0 -9
- package/lib/cjs/index.js +0 -13
- package/lib/cjs/index.js.map +0 -1
- package/lib/cjs/ontologies/lincd-server.d.ts +0 -31
- package/lib/cjs/ontologies/lincd-server.js +0 -86
- package/lib/cjs/ontologies/lincd-server.js.map +0 -1
- package/lib/cjs/package.d.ts +0 -4
- package/lib/cjs/package.js +0 -7
- package/lib/cjs/package.js.map +0 -1
- package/lib/cjs/package.json +0 -90
- package/lib/cjs/shapes/LincdAPI.d.ts +0 -41
- package/lib/cjs/shapes/LincdAPI.js +0 -124
- package/lib/cjs/shapes/LincdAPI.js.map +0 -1
- package/lib/cjs/shapes/LincdServer.d.ts +0 -79
- package/lib/cjs/shapes/LincdServer.js +0 -1339
- package/lib/cjs/shapes/LincdServer.js.map +0 -1
- package/lib/cjs/shapes/LincdWebApp.d.ts +0 -7
- package/lib/cjs/shapes/LincdWebApp.js +0 -43
- package/lib/cjs/shapes/LincdWebApp.js.map +0 -1
- package/lib/cjs/shapes/filestores/LocalFileStore.d.ts +0 -42
- package/lib/cjs/shapes/filestores/LocalFileStore.js +0 -146
- package/lib/cjs/shapes/filestores/LocalFileStore.js.map +0 -1
- package/lib/cjs/shapes/quadstores/BackendAPIStore.d.ts +0 -33
- package/lib/cjs/shapes/quadstores/BackendAPIStore.js +0 -79
- package/lib/cjs/shapes/quadstores/BackendAPIStore.js.map +0 -1
- package/lib/cjs/shapes/quadstores/BackendAPIStoreProvider.d.ts +0 -13
- package/lib/cjs/shapes/quadstores/BackendAPIStoreProvider.js +0 -30
- package/lib/cjs/shapes/quadstores/BackendAPIStoreProvider.js.map +0 -1
- package/lib/cjs/types/RouteConfig.d.ts +0 -56
- package/lib/cjs/types/RouteConfig.js +0 -3
- package/lib/cjs/types/RouteConfig.js.map +0 -1
- package/lib/cjs/types.d.ts +0 -12
- package/lib/cjs/types.js +0 -1
- package/lib/cjs/types.js.map +0 -1
- package/lib/cjs/utils/Shapes.d.ts +0 -7
- package/lib/cjs/utils/Shapes.js +0 -76
- package/lib/cjs/utils/Shapes.js.map +0 -1
- package/lib/cjs/utils/accessUrl.d.ts +0 -6
- package/lib/cjs/utils/accessUrl.js +0 -13
- package/lib/cjs/utils/accessUrl.js.map +0 -1
- package/lib/esm/package.json +0 -90
- package/lib/esm/shapes/LincdServer.js.map +0 -1
|
@@ -9,20 +9,23 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
import chalk from 'chalk';
|
|
12
|
+
import { timingSafeEqual } from 'crypto';
|
|
12
13
|
import events from 'events';
|
|
13
14
|
import express from 'express';
|
|
14
15
|
import fetchCookie from 'fetch-cookie';
|
|
15
16
|
import * as fsNative from 'fs';
|
|
16
17
|
import * as fs from 'fs/promises';
|
|
17
|
-
|
|
18
|
-
import
|
|
18
|
+
// Plan-011: imports from @_linked/cli now go through ./lifecycle (a
|
|
19
|
+
// dynamic-import-free file) so Vite's SSR module graph doesn't pull
|
|
20
|
+
// in the legacy webpack flow and emit dozens of unanalyzable-import
|
|
21
|
+
// warnings on every boot.
|
|
22
|
+
import { getLincdPackages } from '@_linked/cli/lifecycle';
|
|
19
23
|
import { getPackageJSON } from '@_linked/cli/utils';
|
|
20
24
|
import { AppContextProvider } from '@_linked/server-utils/components/AppContext';
|
|
21
25
|
import { JSONParser } from '@_linked/server-utils/utils/JSONParser';
|
|
22
26
|
import { JSONWriter } from '@_linked/server-utils/utils/JSONWriter';
|
|
23
27
|
import { Server } from '@_linked/server-utils/utils/Server';
|
|
24
28
|
import { ShapeProvider } from '@_linked/server-utils/utils/ShapeProvider';
|
|
25
|
-
import { CoreMap } from '@_linked/core/collections/CoreMap';
|
|
26
29
|
import { Shape } from '@_linked/core/shapes/Shape';
|
|
27
30
|
import { LinkedErrorLogging } from '@_linked/core/utils/LinkedErrorLogging';
|
|
28
31
|
import { LinkedFileStorage } from '@_linked/core/utils/LinkedFileStorage';
|
|
@@ -34,16 +37,12 @@ import process from 'process';
|
|
|
34
37
|
import * as React from 'react';
|
|
35
38
|
import { renderToPipeableStream, renderToStaticMarkup } from 'react-dom/server';
|
|
36
39
|
import { StaticRouter } from 'react-router-dom/server.js';
|
|
37
|
-
import { rimraf } from 'rimraf';
|
|
38
40
|
import sharp from 'sharp';
|
|
39
41
|
import { Transform } from 'stream';
|
|
40
42
|
import { CookieJar } from 'tough-cookie';
|
|
41
|
-
import webpack from 'webpack';
|
|
42
|
-
import webpackDevMiddleware from 'webpack-dev-middleware';
|
|
43
|
-
import webpackHotMiddleware from 'webpack-hot-middleware';
|
|
44
43
|
import { lincdServer } from '../ontologies/lincd-server.js';
|
|
45
44
|
import { linkedShape } from '../package.js';
|
|
46
|
-
import {
|
|
45
|
+
import { indexShapesIntoMemory } from '../utils/Shapes.js';
|
|
47
46
|
import { LincdAPI } from './LincdAPI.js';
|
|
48
47
|
//prevent errors in node.js when (s)css files are imported in js
|
|
49
48
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
@@ -79,7 +78,7 @@ events.EventEmitter.prototype.setMaxListeners(500);
|
|
|
79
78
|
// global['document'] = document;
|
|
80
79
|
global['reactStaticRenderer'] = renderToStaticMarkup;
|
|
81
80
|
autoLoadOntologyData(true);
|
|
82
|
-
let
|
|
81
|
+
let LinkedServer = class LinkedServer extends Shape {
|
|
83
82
|
/**
|
|
84
83
|
* yarn linked start sends the contents of linked.config.js as an object to this constructor
|
|
85
84
|
* @param n
|
|
@@ -92,8 +91,8 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
92
91
|
this.latestManifest = null;
|
|
93
92
|
this.cssMode = 'scss-modules';
|
|
94
93
|
this.analyse = false;
|
|
95
|
-
this.shapeProviders = new
|
|
96
|
-
this.genericProviders = new
|
|
94
|
+
this.shapeProviders = new Map();
|
|
95
|
+
this.genericProviders = new Map();
|
|
97
96
|
//from resizedFileName to full resized path (CDN or similar)
|
|
98
97
|
this.resizePathsMap = new Map();
|
|
99
98
|
if (config && typeof config !== 'string' && !('id' in config)) {
|
|
@@ -152,9 +151,57 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
152
151
|
this.initPackage();
|
|
153
152
|
this.server = express();
|
|
154
153
|
await this.initBackendProviders();
|
|
155
|
-
|
|
154
|
+
indexShapesIntoMemory();
|
|
155
|
+
await this.materializeShapesIntoStore();
|
|
156
156
|
return this;
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Materialize this server's registered shapes into the RDF store as SHACL
|
|
160
|
+
* (core `syncShapes` → pure `sh:NodeShape` + property shapes), so a running
|
|
161
|
+
* app's app-data holds the shapes its instances validate/query against
|
|
162
|
+
* (plan-010 T1e.2). This is the canonical, uniform reuse+create mechanism:
|
|
163
|
+
* whatever shapes the app package registers (published re-exports + generated)
|
|
164
|
+
* get materialized on boot (and re-run on shape-file HMR).
|
|
165
|
+
*
|
|
166
|
+
* Gated to servers whose DEFAULT dataset is a **concrete** materializable store
|
|
167
|
+
* (detected via `rawQuery`) — i.e. an app pointing at its app-data FusekiStore.
|
|
168
|
+
* CN's default is the context-routing `AppDataRouter` (no `rawQuery`; a bare
|
|
169
|
+
* `syncShapes` orphan-read would throw with no active project), so CN is skipped
|
|
170
|
+
* here — it materializes its own pinned native shapes in its storage config.
|
|
171
|
+
*/
|
|
172
|
+
async materializeShapesIntoStore() {
|
|
173
|
+
var _a;
|
|
174
|
+
// Opt-out via `linked.config` `syncShapesOnBoot` (default true); env
|
|
175
|
+
// LINKED_SYNC_SHAPES_ON_BOOT overrides for deployment. CN sets
|
|
176
|
+
// `syncShapesOnBoot: false` in its own linked.config — its default dataset is
|
|
177
|
+
// a context-router that can't materialize context-free, and it syncs its own
|
|
178
|
+
// pinned shapes separately (linked.backend.storage.js).
|
|
179
|
+
const configFlag = (_a = this.config) === null || _a === void 0 ? void 0 : _a.syncShapesOnBoot;
|
|
180
|
+
const envFlag = process.env.LINKED_SYNC_SHAPES_ON_BOOT;
|
|
181
|
+
if (configFlag === false || envFlag === 'false') {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const appData = LinkedStorage.getDefaultDataset();
|
|
185
|
+
if (!appData)
|
|
186
|
+
return;
|
|
187
|
+
try {
|
|
188
|
+
const { syncShapes } = await import('@_linked/core');
|
|
189
|
+
// Explicit target: materialize EVERY registered shape into the app's own
|
|
190
|
+
// data store regardless of per-shape routing/pins — syncShapes(ds) threads
|
|
191
|
+
// ds through the orphan-read + every delete→recreate. (No reliance on
|
|
192
|
+
// "whatever the default resolves to per shape".)
|
|
193
|
+
const thunks = await syncShapes(appData);
|
|
194
|
+
// Batched (not all-at-once) so we don't overwhelm Fuseki — the API hands
|
|
195
|
+
// back unexecuted thunks precisely so the caller paces them.
|
|
196
|
+
for (let i = 0; i < thunks.length; i += 8) {
|
|
197
|
+
await Promise.all(thunks.slice(i, i + 8).map((run) => run()));
|
|
198
|
+
}
|
|
199
|
+
console.log(`[LinkedServer] materialized ${thunks.length} shape(s) into app-data`);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
console.warn('[LinkedServer] shape materialization failed (non-fatal):', err);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
158
205
|
// async serveData(req,res) {
|
|
159
206
|
// let nodeURI = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
|
|
160
207
|
//
|
|
@@ -163,6 +210,7 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
163
210
|
// })
|
|
164
211
|
// }
|
|
165
212
|
async start() {
|
|
213
|
+
var _a, _b, _c, _d;
|
|
166
214
|
this.initPackage();
|
|
167
215
|
// Static assets should come from the static store URL (versioned path),
|
|
168
216
|
// not the upload store URL. storage-config sets STATIC_ACCESS_URL accordingly.
|
|
@@ -177,21 +225,40 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
177
225
|
LinkedFileStorage.accessURL ||
|
|
178
226
|
'').replace(/\/$/, '');
|
|
179
227
|
const staticAsset = (assetPath) => `${staticAccessURL}/public${assetPath}`;
|
|
180
|
-
//
|
|
228
|
+
// Bundle/manifest read (plan-011: Vite is the only supported build).
|
|
229
|
+
// Vite manifest lives at public/bundles/.vite/manifest.json.
|
|
181
230
|
this.assets = {
|
|
182
|
-
'main.js': staticAsset('/bundles/main.bundle.js') + '?v=' + this.package.version,
|
|
183
|
-
'main.css': staticAsset('/bundles/main.css'),
|
|
231
|
+
'main.js': staticAsset('/bundles/main.bundle.js') + '?v=' + this.package.version,
|
|
232
|
+
'main.css': staticAsset('/bundles/main.css'),
|
|
184
233
|
};
|
|
185
234
|
try {
|
|
186
|
-
const
|
|
187
|
-
if (fsNative.existsSync(
|
|
188
|
-
const manifestRaw = fsNative.readFileSync(
|
|
189
|
-
|
|
235
|
+
const viteManifestPath = path.resolve(process.cwd(), 'public/bundles/.vite/manifest.json');
|
|
236
|
+
if (fsNative.existsSync(viteManifestPath)) {
|
|
237
|
+
const manifestRaw = fsNative.readFileSync(viteManifestPath, 'utf-8');
|
|
238
|
+
const viteManifest = JSON.parse(manifestRaw);
|
|
239
|
+
this.assets.manifest = viteManifest;
|
|
240
|
+
// Resolve main entry per Vite manifest shape:
|
|
241
|
+
// { "src/index.tsx": { file: "assets/main-<hash>.js", css: [...] } }
|
|
242
|
+
const mainEntry = viteManifest['src/index.tsx'] ||
|
|
243
|
+
viteManifest['src/index.ts'] ||
|
|
244
|
+
Object.values(viteManifest).find((e) => e === null || e === void 0 ? void 0 : e.isEntry);
|
|
245
|
+
if (mainEntry === null || mainEntry === void 0 ? void 0 : mainEntry.file) {
|
|
246
|
+
this.assets['main.js'] = staticAsset(`/bundles/${mainEntry.file}`);
|
|
247
|
+
}
|
|
248
|
+
if ((_a = mainEntry === null || mainEntry === void 0 ? void 0 : mainEntry.css) === null || _a === void 0 ? void 0 : _a[0]) {
|
|
249
|
+
this.assets['main.css'] = staticAsset(`/bundles/${mainEntry.css[0]}`);
|
|
250
|
+
}
|
|
190
251
|
}
|
|
191
252
|
}
|
|
192
253
|
catch (err) {
|
|
193
254
|
console.warn('Could not load bundle manifest:', err);
|
|
194
255
|
}
|
|
256
|
+
// Vite dev marker: when Vite is in use AND no Vite manifest exists yet
|
|
257
|
+
// (= dev mode, no `vite build` run), the HTML renderer skips
|
|
258
|
+
// pre-built CSS/JS link tags. Vite handles asset injection itself.
|
|
259
|
+
if (((_b = this.config.server) === null || _b === void 0 ? void 0 : _b.vite) && !((_c = this.assets.manifest) === null || _c === void 0 ? void 0 : _c['src/index.tsx'])) {
|
|
260
|
+
this.assets['__viteDev'] = '1';
|
|
261
|
+
}
|
|
195
262
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
196
263
|
if (!isProduction && this.config.cssMode === 'tailwind') {
|
|
197
264
|
this.assets['tailwind-cdn'] = 'https://cdn.tailwindcss.com';
|
|
@@ -214,7 +281,8 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
214
281
|
// });
|
|
215
282
|
// before controllers
|
|
216
283
|
await this.initBackendProviders();
|
|
217
|
-
|
|
284
|
+
indexShapesIntoMemory();
|
|
285
|
+
await this.materializeShapesIntoStore();
|
|
218
286
|
//START OF EXPRESS ROUTES AND MIDDLEWARE
|
|
219
287
|
//use cors
|
|
220
288
|
// var corsOptions = {
|
|
@@ -230,116 +298,20 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
230
298
|
//UPDATE ive set level to 2 (low compression fast speed) because responses were taking too long (98% of server time was used by compress)
|
|
231
299
|
// this.server.use(compress({level: 2}));
|
|
232
300
|
await this.callGenericBackendProvidersMethod('setupBeforeControllers');
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// let webpackConfig = await getWebpackConfig();
|
|
241
|
-
let webpackConfig = await getWebpackAppConfig();
|
|
242
|
-
// const compare = (c1,c2,path?='') => {
|
|
243
|
-
// for(let key1 of Object.keys(c1)) {
|
|
244
|
-
// if(typeof c1[key1] === 'object') {
|
|
245
|
-
// compare(c1[key1],c2[key1],path+='.'+key1);
|
|
246
|
-
// } else {
|
|
247
|
-
// if(c1[key1] !== c2[key1]) {
|
|
248
|
-
// console.log("Difference "+path+": ");
|
|
249
|
-
// console.log(c1[key1]);
|
|
250
|
-
// console.log(c2[key1]);
|
|
251
|
-
// }
|
|
252
|
-
// }
|
|
253
|
-
// }
|
|
254
|
-
// }
|
|
255
|
-
// compare(webpackConfig,webpackConfig2);
|
|
256
|
-
//default to having webpack cache on and filesystem, unless explicitly set to false
|
|
257
|
-
if (this.cacheWebpack === false) {
|
|
258
|
-
webpackConfig.cache.type = 'memory';
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
webpackConfig.cache.type = 'filesystem';
|
|
262
|
-
}
|
|
263
|
-
//clean dist/build folder
|
|
264
|
-
await rimraf(webpackConfig.output.path).catch((err) => {
|
|
265
|
-
if (err) {
|
|
266
|
-
console.warn(err);
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
const compiler = webpack(webpackConfig, (err, stats) => {
|
|
270
|
-
//watch build completed
|
|
271
|
-
if (err) {
|
|
272
|
-
console.error(err);
|
|
273
|
-
}
|
|
274
|
-
// Output stats JSON for analysis
|
|
275
|
-
if (this.analyse) {
|
|
276
|
-
fs.writeFile('./data/webpack-stats.json', JSON.stringify(stats.toJson({ all: true }), null, 2)).then(() => {
|
|
277
|
-
console.log('Webpack stats written to ./data/webpack-stats.json');
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
if (!compiler) {
|
|
282
|
-
//something went wrong with webpack config, error will be logged above
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
compiler.hooks.afterEmit.tap('cleanup-the-require-cache', () => {
|
|
286
|
-
// After webpack rebuild, clear the files from the require cache,
|
|
287
|
-
// so that next server side render wil be in sync
|
|
288
|
-
// console.log(Object.keys(require.cache).filter(k => k.includes(dirName)).join("\n"));
|
|
289
|
-
// if (typeof require !== 'undefined') {
|
|
290
|
-
// Object.keys(require.cache)
|
|
291
|
-
// .filter((key) => key.includes(dirName))
|
|
292
|
-
// .forEach((key) => delete require.cache[key]);
|
|
293
|
-
// }
|
|
294
|
-
});
|
|
295
|
-
//after the first emit (which means bundles are ready and the site is running) also rebuild the index files of the site
|
|
296
|
-
let updatedMetadata = false;
|
|
297
|
-
compiler.hooks.afterEmit.tap('update-metadata', () => {
|
|
298
|
-
if (!updatedMetadata) {
|
|
299
|
-
updatedMetadata = true;
|
|
300
|
-
//log updated paths
|
|
301
|
-
// buildMetadata()
|
|
302
|
-
// .then((updatedPaths) => {
|
|
303
|
-
// // if(updatedPaths && updatedPaths.length)
|
|
304
|
-
// // {
|
|
305
|
-
// // console.log(chalk.blueBright('Updated metadata:\n - '+updatedPaths.join('\n - ')));
|
|
306
|
-
// // }
|
|
307
|
-
// })
|
|
308
|
-
// .catch((err) => {
|
|
309
|
-
// console.warn('Could not update metadata: ' + err);
|
|
310
|
-
// });
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
this.server.use(webpackDevMiddleware(compiler, {
|
|
314
|
-
serverSideRender: true,
|
|
315
|
-
publicPath: webpackConfig.output.publicPath,
|
|
316
|
-
stats: {
|
|
317
|
-
children: true,
|
|
318
|
-
version: false,
|
|
319
|
-
chunks: false,
|
|
320
|
-
assets: false,
|
|
321
|
-
entrypoints: false,
|
|
322
|
-
modules: false,
|
|
323
|
-
},
|
|
324
|
-
writeToDisk: true,
|
|
325
|
-
}));
|
|
326
|
-
compiler.hooks.afterEmit.tap('store-manifest', (compilation) => {
|
|
327
|
-
try {
|
|
328
|
-
// Read manifest from the filesystem after webpack writes it
|
|
329
|
-
const manifestPath = path.resolve(compilation.options.output.path, 'manifest.json');
|
|
330
|
-
if (fsNative.existsSync(manifestPath)) {
|
|
331
|
-
const manifestContent = fsNative.readFileSync(manifestPath, 'utf-8');
|
|
332
|
-
this.latestManifest = JSON.parse(manifestContent);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
catch (err) {
|
|
336
|
-
console.warn('Failed to parse manifest from webpack emit:', err);
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
this.server.use(webpackHotMiddleware(compiler, {
|
|
340
|
-
log: false,
|
|
341
|
-
}));
|
|
301
|
+
// Vite middleware (plan 010): when the user app starts via Vite
|
|
302
|
+
// (`linked start --vite`), the orchestrator passes the Vite handle
|
|
303
|
+
// through config.server.viteMiddleware. We mount it and skip the
|
|
304
|
+
// entire webpack-dev-middleware setup below.
|
|
305
|
+
const viteMiddleware = (_d = this.config.server) === null || _d === void 0 ? void 0 : _d.viteMiddleware;
|
|
306
|
+
if (viteMiddleware) {
|
|
307
|
+
this.server.use(viteMiddleware);
|
|
342
308
|
}
|
|
309
|
+
// Plan-011: legacy webpack-dev-middleware branch removed. Under Vite
|
|
310
|
+
// (the only supported dev path now) `viteMiddleware` is set, which
|
|
311
|
+
// previously forced `skipBuild = true` and made this whole block
|
|
312
|
+
// dead. Removing it ends the static dependency on @_linked/cli/
|
|
313
|
+
// config-webpack-app (full of dynamic imports Vite couldn't analyze)
|
|
314
|
+
// and shrinks LinkedServer's import surface considerably.
|
|
343
315
|
// //map URL routes to file paths
|
|
344
316
|
const oneYear = 1000 * 60 * 60 * 24 * 365; // in milliseconds
|
|
345
317
|
const oneMonth = 1000 * 60 * 60 * 24 * 30; // in milliseconds
|
|
@@ -392,6 +364,43 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
392
364
|
this.server.head('__health', (_req, res) => {
|
|
393
365
|
res.sendStatus(200);
|
|
394
366
|
});
|
|
367
|
+
// CN control channel (plan-010 T1b.3). Present only when CN spawned this
|
|
368
|
+
// process with a shared secret (CN_APP_ADMIN_SECRET); a standalone app run
|
|
369
|
+
// without the secret leaves the channel closed (404). Auth is the
|
|
370
|
+
// x-cn-admin-secret header matching that env value.
|
|
371
|
+
const adminSecret = process.env.CN_APP_ADMIN_SECRET;
|
|
372
|
+
// Constant-time compare so the secret can't be recovered by timing the 401
|
|
373
|
+
// response. timingSafeEqual requires equal-length buffers, so guard length.
|
|
374
|
+
const secretMatches = (provided) => {
|
|
375
|
+
if (!adminSecret || !provided)
|
|
376
|
+
return false;
|
|
377
|
+
const a = Buffer.from(provided);
|
|
378
|
+
const b = Buffer.from(adminSecret);
|
|
379
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
380
|
+
};
|
|
381
|
+
const requireAdmin = (req, res) => {
|
|
382
|
+
if (!adminSecret) {
|
|
383
|
+
res.sendStatus(404); // no control channel in this mode
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
if (!secretMatches(req.get('x-cn-admin-secret'))) {
|
|
387
|
+
res.sendStatus(401);
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
};
|
|
392
|
+
this.server.get('/admin/health', (req, res) => {
|
|
393
|
+
if (!requireAdmin(req, res))
|
|
394
|
+
return;
|
|
395
|
+
res.status(200).json({ status: 'ok' });
|
|
396
|
+
});
|
|
397
|
+
this.server.post('/admin/restart', (req, res) => {
|
|
398
|
+
if (!requireAdmin(req, res))
|
|
399
|
+
return;
|
|
400
|
+
res.sendStatus(202);
|
|
401
|
+
// CN's provisioner respawns on exit (see ChildProcessProvisioner).
|
|
402
|
+
setTimeout(() => process.exit(0), 50);
|
|
403
|
+
});
|
|
395
404
|
this.server.get('*', this.handleErrors(async (req, res) => {
|
|
396
405
|
//make sure the frontend bundle has finished building
|
|
397
406
|
// await this.waitForWebpack();
|
|
@@ -491,7 +500,19 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
491
500
|
.readFile(path.join(process.cwd(), 'package.json'), 'utf-8')
|
|
492
501
|
.then(async (contents) => {
|
|
493
502
|
let pkg = JSON.parse(contents);
|
|
494
|
-
|
|
503
|
+
// Route through default ${pkg}/backend resolution. The app's
|
|
504
|
+
// package.json `exports`./backend field handles dev vs prod:
|
|
505
|
+
// "exports": {
|
|
506
|
+
// "./backend": {
|
|
507
|
+
// "development": "./src/backend.ts",
|
|
508
|
+
// "default": "./lib/esm/backend.js"
|
|
509
|
+
// }
|
|
510
|
+
// }
|
|
511
|
+
// Removed plan-010 D10: the source-direct
|
|
512
|
+
// path.join(cwd, 'src', 'backend.ts') override that forced TS
|
|
513
|
+
// runtime loading. Vite SSR's ssrLoadModule handles the
|
|
514
|
+
// transform; production runs from lib/esm/.
|
|
515
|
+
await this.indexPackageBackendProviders(pkg.name, false);
|
|
495
516
|
});
|
|
496
517
|
}
|
|
497
518
|
catch (err) {
|
|
@@ -727,6 +748,7 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
727
748
|
res.sendFile(resizedFilePath);
|
|
728
749
|
}
|
|
729
750
|
async indexLincdPackage(pkg, warnIfNotFound = false) {
|
|
751
|
+
var _a;
|
|
730
752
|
if (pkg === this.package.name) {
|
|
731
753
|
return;
|
|
732
754
|
}
|
|
@@ -737,7 +759,22 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
737
759
|
//@ts-ignore
|
|
738
760
|
// await import.meta.resolve(pkg)
|
|
739
761
|
// );
|
|
740
|
-
|
|
762
|
+
// plan-011 §P6 — prefer Vite's SSR loader so workspace packages register
|
|
763
|
+
// on the SINGLE @_linked/core instance the rest of the SSR graph uses.
|
|
764
|
+
// The bare Node `import()` fallback resolves `default`→lib, evaluating a
|
|
765
|
+
// SECOND core copy (benign post-§P1, but a needless second instance).
|
|
766
|
+
// Node import stays as the fallback when Vite isn't active (production /
|
|
767
|
+
// Node-only CLI commands). Mirrors indexPackageBackendProviders.
|
|
768
|
+
const vite = (_a = this.config.server) === null || _a === void 0 ? void 0 : _a.vite;
|
|
769
|
+
if (vite && typeof vite.ssrLoadModule === 'function') {
|
|
770
|
+
await vite.ssrLoadModule(pkg);
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
// @vite-ignore — dynamic specifier is intentional: this checks
|
|
774
|
+
// whether `pkg` is resolvable at runtime, then catches the error.
|
|
775
|
+
// eslint-disable-next-line no-unsanitized/method
|
|
776
|
+
await import(/* @vite-ignore */ pkg);
|
|
777
|
+
}
|
|
741
778
|
// console.log(`✅ Successfully loaded: ${pkg}`);
|
|
742
779
|
}
|
|
743
780
|
catch (e) {
|
|
@@ -761,13 +798,66 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
761
798
|
}
|
|
762
799
|
}
|
|
763
800
|
async indexPackageBackendProviders(pkg, warnIfNotFound = false, backendIndexFilePath) {
|
|
801
|
+
var _a;
|
|
764
802
|
if (!backendIndexFilePath) {
|
|
765
803
|
backendIndexFilePath = `${pkg}/backend`;
|
|
766
804
|
}
|
|
767
805
|
let backendProviderExports;
|
|
768
806
|
let genericBackendProvider;
|
|
769
807
|
let shapeProviders = [];
|
|
770
|
-
|
|
808
|
+
// Plan-010 phase 4/5: when Vite SSR is active, route module loading
|
|
809
|
+
// through vite.ssrLoadModule. This handles the case where the user app
|
|
810
|
+
// is the consuming workspace itself (self-reference like
|
|
811
|
+
// @semantu/create-now/backend), which Node's ESM resolver can't resolve
|
|
812
|
+
// from inside an installed package like @_linked/server.
|
|
813
|
+
const vite = (_a = this.config.server) === null || _a === void 0 ? void 0 : _a.vite;
|
|
814
|
+
const loadModule = async (specifier) => {
|
|
815
|
+
var _a, _b, _c;
|
|
816
|
+
if (vite && typeof vite.ssrLoadModule === 'function') {
|
|
817
|
+
// For the user app's own backend, resolve to ./src/backend.ts directly.
|
|
818
|
+
// Vite reads the app's package.json exports.development condition.
|
|
819
|
+
if (specifier === `${this.package.name}/backend`) {
|
|
820
|
+
return await vite.ssrLoadModule('/src/backend.ts');
|
|
821
|
+
}
|
|
822
|
+
// Plan-011: ssr.external is now an npm-only allowlist. Workspace
|
|
823
|
+
// packages MUST go through Vite's SSR loader so they share the
|
|
824
|
+
// same module instance as everything else in the SSR call graph
|
|
825
|
+
// (otherwise we get duplicate React contexts, duplicate Linked
|
|
826
|
+
// package registrations, etc).
|
|
827
|
+
//
|
|
828
|
+
// Pre-check whether the specifier actually resolves before
|
|
829
|
+
// calling ssrLoadModule — many packages have no `/backend`
|
|
830
|
+
// export, and ssrLoadModule logs a "Failed to load url" error
|
|
831
|
+
// INTERNALLY before throwing, which spams stdout even when the
|
|
832
|
+
// surrounding catch handles it. pluginContainer.resolveId is
|
|
833
|
+
// quiet: it returns null when no plugin can resolve the id.
|
|
834
|
+
try {
|
|
835
|
+
const resolved = await ((_b = (_a = vite.pluginContainer) === null || _a === void 0 ? void 0 : _a.resolveId) === null || _b === void 0 ? void 0 : _b.call(_a, specifier));
|
|
836
|
+
if (!resolved) {
|
|
837
|
+
// Synthesise the same error shape the catch expects so the
|
|
838
|
+
// "no backend export, that's fine" branch fires.
|
|
839
|
+
const err = new Error(`Failed to load url ${specifier} (resolved id: ${specifier}). Does the file exist?`);
|
|
840
|
+
throw err;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
catch (e) {
|
|
844
|
+
// If the pre-check itself errored (e.g. plugin threw on a
|
|
845
|
+
// pkg name it doesn't know), let the call below surface the
|
|
846
|
+
// real error path.
|
|
847
|
+
if (!((_c = e === null || e === void 0 ? void 0 : e.message) === null || _c === void 0 ? void 0 : _c.includes('Failed to load url'))) {
|
|
848
|
+
// fall through to ssrLoadModule which will throw + log
|
|
849
|
+
}
|
|
850
|
+
else {
|
|
851
|
+
throw e;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
return await vite.ssrLoadModule(specifier);
|
|
855
|
+
}
|
|
856
|
+
// No-vite path (e.g. production runtime). Fall back to Node's
|
|
857
|
+
// resolver. The dynamic specifier is intentional.
|
|
858
|
+
return await import(/* @vite-ignore */ specifier);
|
|
859
|
+
};
|
|
860
|
+
await loadModule(backendIndexFilePath)
|
|
771
861
|
.then((backendProviderExports) => {
|
|
772
862
|
//instantiate the exported provider classes and add them to the right place
|
|
773
863
|
Object.keys(backendProviderExports).forEach((key) => {
|
|
@@ -793,13 +883,22 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
793
883
|
});
|
|
794
884
|
})
|
|
795
885
|
.catch((e) => {
|
|
796
|
-
|
|
797
|
-
//
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
886
|
+
var _a;
|
|
887
|
+
// Recognize "no /backend export" failures across two loader
|
|
888
|
+
// shapes:
|
|
889
|
+
// Node's import() → ERR_MODULE_NOT_FOUND + "Cannot find module 'X/backend'"
|
|
890
|
+
// Vite's ssrLoadModule() → "Failed to load url X/backend"
|
|
891
|
+
// In either case, missing /backend on a package that doesn't
|
|
892
|
+
// ship a backend is expected; loud-error only on REAL load
|
|
893
|
+
// failures (syntax error inside an existing backend.ts, etc).
|
|
894
|
+
const nodeMatch = e.message.match(/module \'([^\']+)'/);
|
|
895
|
+
const viteMatch = e.message.match(/Failed to load url ([^\s]+)/);
|
|
896
|
+
const matchedSpec = (_a = nodeMatch === null || nodeMatch === void 0 ? void 0 : nodeMatch[1]) !== null && _a !== void 0 ? _a : viteMatch === null || viteMatch === void 0 ? void 0 : viteMatch[1];
|
|
897
|
+
let providerNotFound = !!matchedSpec &&
|
|
898
|
+
matchedSpec.includes('/backend') &&
|
|
899
|
+
((e.code === 'ERR_MODULE_NOT_FOUND' &&
|
|
900
|
+
e.message.indexOf(`Cannot find module`) !== -1) ||
|
|
901
|
+
e.message.indexOf('Failed to load url') !== -1);
|
|
803
902
|
if (providerNotFound) {
|
|
804
903
|
// console.warn('Error loading ' + providerPath + ': ' + e.stack);
|
|
805
904
|
if (warnIfNotFound) {
|
|
@@ -818,6 +917,69 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
818
917
|
this.shapeProviders.set(pkg, shapeProviders);
|
|
819
918
|
return { backendProviderExports, shapeProviders };
|
|
820
919
|
}
|
|
920
|
+
/**
|
|
921
|
+
* Plan-011 phase 2 — HMR re-index entry point.
|
|
922
|
+
*
|
|
923
|
+
* Called by the CLI orchestrator's Vite watcher whenever a `.ts`/`.tsx`
|
|
924
|
+
* file inside a workspace package changes. Disposes the package's
|
|
925
|
+
* existing providers (so routes, listeners, timers don't accumulate),
|
|
926
|
+
* drops them from the registry, and re-runs indexPackageBackendProviders
|
|
927
|
+
* to pick up the freshly-imported module.
|
|
928
|
+
*
|
|
929
|
+
* Dispose calls have a 5 s soft timeout. A hanging dispose logs a
|
|
930
|
+
* warning and is abandoned so HMR doesn't stall the whole dev loop.
|
|
931
|
+
*/
|
|
932
|
+
async onSourceChange(pkg) {
|
|
933
|
+
var _a, _b, _c, _d, _e;
|
|
934
|
+
const disposeWithTimeout = async (p, label) => {
|
|
935
|
+
if (!(p === null || p === void 0 ? void 0 : p.dispose))
|
|
936
|
+
return;
|
|
937
|
+
try {
|
|
938
|
+
await Promise.race([
|
|
939
|
+
Promise.resolve().then(() => p.dispose()),
|
|
940
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`dispose timeout after 5s`)), 5000)),
|
|
941
|
+
]);
|
|
942
|
+
}
|
|
943
|
+
catch (err) {
|
|
944
|
+
console.warn(chalk.yellow(`[linked] ${label} dispose failed: ${err.message}`));
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
const generic = this.genericProviders.get(pkg);
|
|
948
|
+
if (generic) {
|
|
949
|
+
await disposeWithTimeout(generic, `${pkg} generic provider`);
|
|
950
|
+
this.genericProviders.delete(pkg);
|
|
951
|
+
}
|
|
952
|
+
const shapeProvs = (_a = this.shapeProviders.get(pkg)) !== null && _a !== void 0 ? _a : [];
|
|
953
|
+
for (const p of shapeProvs) {
|
|
954
|
+
await disposeWithTimeout(p, `${pkg} ${(_d = (_c = (_b = Object.getPrototypeOf(p)) === null || _b === void 0 ? void 0 : _b.constructor) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : 'shape provider'}`);
|
|
955
|
+
}
|
|
956
|
+
this.shapeProviders.delete(pkg);
|
|
957
|
+
await this.indexPackageBackendProviders(pkg, true);
|
|
958
|
+
// Run the boot lifecycle on the FRESHLY-loaded provider so it
|
|
959
|
+
// re-registers its Express routes/middleware after dispose. Without
|
|
960
|
+
// this, dispose() tears the old routes off and the new instance is
|
|
961
|
+
// constructed but never gets a chance to register the replacements.
|
|
962
|
+
const fresh = this.genericProviders.get(pkg);
|
|
963
|
+
if (fresh === null || fresh === void 0 ? void 0 : fresh.setupBeforeControllers) {
|
|
964
|
+
try {
|
|
965
|
+
await fresh.setupBeforeControllers();
|
|
966
|
+
}
|
|
967
|
+
catch (err) {
|
|
968
|
+
console.warn(chalk.yellow(`[linked] ${pkg} setupBeforeControllers after reload failed: ${err.message}`));
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
const freshShapes = (_e = this.shapeProviders.get(pkg)) !== null && _e !== void 0 ? _e : [];
|
|
972
|
+
for (const p of freshShapes) {
|
|
973
|
+
if (p === null || p === void 0 ? void 0 : p.setupBeforeControllers) {
|
|
974
|
+
try {
|
|
975
|
+
await p.setupBeforeControllers();
|
|
976
|
+
}
|
|
977
|
+
catch (err) {
|
|
978
|
+
console.warn(chalk.yellow(`[linked] ${pkg} shape-provider setupBeforeControllers after reload failed: ${err.message}`));
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
821
983
|
async processBackendMethodCall(request, response) {
|
|
822
984
|
this.noCache(response);
|
|
823
985
|
await this.initRequest(request, response);
|
|
@@ -1001,7 +1163,7 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
1001
1163
|
}
|
|
1002
1164
|
}
|
|
1003
1165
|
async render(req, res) {
|
|
1004
|
-
var _a, _b, _c, _d;
|
|
1166
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1005
1167
|
res.socket.on('error', (error) => {
|
|
1006
1168
|
console.error('Fatal socket error', error);
|
|
1007
1169
|
});
|
|
@@ -1029,6 +1191,69 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
1029
1191
|
let App = ((_b = this.config.server) === null || _b === void 0 ? void 0 : _b.loadAppComponent)
|
|
1030
1192
|
? await this.config.server.loadAppComponent()
|
|
1031
1193
|
: null;
|
|
1194
|
+
// Vite dev CSS collection (plan-010 iteration 1 — gap A):
|
|
1195
|
+
// 1. Preload the matched route's module via ssrLoadModule so all
|
|
1196
|
+
// page-level dependencies (SigninLayout, CreateAccount, etc.)
|
|
1197
|
+
// enter Vite's moduleGraph BEFORE we collect CSS. Without this,
|
|
1198
|
+
// only App's eager imports are in the graph and lazy routes'
|
|
1199
|
+
// CSS would be missing — page renders unstyled until hydration.
|
|
1200
|
+
// 2. Walk moduleGraph for CSS entries, load each via `?inline`
|
|
1201
|
+
// (Vite returns raw CSS string as default export).
|
|
1202
|
+
// 3. Inject as inline <style> in HTML head (Html.tsx).
|
|
1203
|
+
const vite = (_c = this.config.server) === null || _c === void 0 ? void 0 : _c.vite;
|
|
1204
|
+
// Vite SSR module preload (plan-010 iter1 gap A):
|
|
1205
|
+
// Pages are loaded lazily via React.lazy — their modules only enter
|
|
1206
|
+
// Vite's moduleGraph after the lazy resolves. For SSR CSS collection
|
|
1207
|
+
// we need the page modules in the graph BEFORE the first render of
|
|
1208
|
+
// each route. The orchestrator passes a preloadPagesFn that lists
|
|
1209
|
+
// all page files (typically via `import.meta.glob`); we call
|
|
1210
|
+
// ssrLoadModule on each path once. After the first render of a
|
|
1211
|
+
// session everything is cached.
|
|
1212
|
+
const preloadPagesFn = (_d = this.config.server) === null || _d === void 0 ? void 0 : _d.viteSsrPreload;
|
|
1213
|
+
if ((vite === null || vite === void 0 ? void 0 : vite.ssrLoadModule) && preloadPagesFn && !this._viteSsrPreloaded) {
|
|
1214
|
+
try {
|
|
1215
|
+
const pagePaths = await preloadPagesFn();
|
|
1216
|
+
for (const p of pagePaths) {
|
|
1217
|
+
try {
|
|
1218
|
+
await vite.ssrLoadModule(p);
|
|
1219
|
+
}
|
|
1220
|
+
catch ( /* skip — page may not exist or have ssr errors */_k) { /* skip — page may not exist or have ssr errors */ }
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
catch ( /* ignore */_l) { /* ignore */ }
|
|
1224
|
+
this._viteSsrPreloaded = true;
|
|
1225
|
+
}
|
|
1226
|
+
let ssrCss = '';
|
|
1227
|
+
if ((_e = vite === null || vite === void 0 ? void 0 : vite.moduleGraph) === null || _e === void 0 ? void 0 : _e.idToModuleMap) {
|
|
1228
|
+
const cssChunks = [];
|
|
1229
|
+
const seen = new Set();
|
|
1230
|
+
// Walk the moduleGraph for CSS modules pulled in by app/pages.
|
|
1231
|
+
// Note: Tailwind v4 `@theme` directives in app theme CSS files are
|
|
1232
|
+
// NOT processed at SSR collection time — the @tailwindcss/vite
|
|
1233
|
+
// plugin expands them at production build only. In dev mode, the
|
|
1234
|
+
// theme variables (—color-primary-*, etc.) are injected by Vite's
|
|
1235
|
+
// runtime AFTER client hydration, which causes a brief flash of
|
|
1236
|
+
// unthemed content (logos render black until ~hydration+200ms).
|
|
1237
|
+
// Production (vite build) is unaffected — the static main.css
|
|
1238
|
+
// contains expanded :root variables.
|
|
1239
|
+
for (const [id] of vite.moduleGraph.idToModuleMap) {
|
|
1240
|
+
if (seen.has(id))
|
|
1241
|
+
continue;
|
|
1242
|
+
if (!/\.(module\.)?css(\?(?!.*inline)[^?]*)?$/.test(id))
|
|
1243
|
+
continue;
|
|
1244
|
+
seen.add(id);
|
|
1245
|
+
try {
|
|
1246
|
+
const inlineUrl = id + (id.includes('?') ? '&' : '?') + 'inline';
|
|
1247
|
+
const cssModule = await vite.ssrLoadModule(inlineUrl);
|
|
1248
|
+
if (typeof (cssModule === null || cssModule === void 0 ? void 0 : cssModule.default) === 'string') {
|
|
1249
|
+
cssChunks.push(cssModule.default);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
catch ( /* skip */_m) { /* skip */ }
|
|
1253
|
+
}
|
|
1254
|
+
ssrCss = cssChunks.join('\n');
|
|
1255
|
+
}
|
|
1256
|
+
this.assets['__viteSsrCss'] = ssrCss;
|
|
1032
1257
|
await this.initRequest(req, res);
|
|
1033
1258
|
let { requestLD, requestObject } = await this.getRequestData(req, res);
|
|
1034
1259
|
//on the backend we need to inform the hook of the request-data value
|
|
@@ -1052,12 +1277,18 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
1052
1277
|
let preloadScripts = [];
|
|
1053
1278
|
let preloadStyles = [];
|
|
1054
1279
|
let matchedRouteKey = null;
|
|
1280
|
+
// Plan-010 Vite dev mode: skip preload resolution entirely. Vite
|
|
1281
|
+
// handles dynamic import() at runtime — there are no pre-built
|
|
1282
|
+
// chunks to preload, and the webpack-shape fallback would pick up
|
|
1283
|
+
// stale bundles on disk (public/bundles/*.bundle.js from a prior
|
|
1284
|
+
// webpack build) and link them, breaking hydration.
|
|
1285
|
+
const usingViteDev = !!((_f = this.config.server) === null || _f === void 0 ? void 0 : _f.vite) && !this.latestManifest;
|
|
1055
1286
|
// Load routes config if available and extract preload chunks for the current route
|
|
1056
|
-
if ((
|
|
1287
|
+
if ((_g = this.config.server) === null || _g === void 0 ? void 0 : _g.loadRoutes) {
|
|
1057
1288
|
try {
|
|
1058
1289
|
const routesModule = await this.config.server.loadRoutes();
|
|
1059
1290
|
const ROUTES = routesModule.ROUTES ||
|
|
1060
|
-
((
|
|
1291
|
+
((_h = routesModule.default) === null || _h === void 0 ? void 0 : _h.ROUTES) ||
|
|
1061
1292
|
routesModule;
|
|
1062
1293
|
// Match the current request path to a route
|
|
1063
1294
|
let matchedRoute = null;
|
|
@@ -1074,18 +1305,52 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
1074
1305
|
break;
|
|
1075
1306
|
}
|
|
1076
1307
|
}
|
|
1077
|
-
// If we found a matching route with preloadChunks, resolve them to URLs (both JS and CSS)
|
|
1078
|
-
|
|
1308
|
+
// If we found a matching route with preloadChunks, resolve them to URLs (both JS and CSS).
|
|
1309
|
+
// Manifest format detection: Vite manifest entries are objects with .file/.css; webpack
|
|
1310
|
+
// manifest entries are bare strings. Try Vite shape first, fall back to webpack.
|
|
1311
|
+
// Skip entirely in Vite dev mode — no pre-built chunks exist; Vite handles dynamic
|
|
1312
|
+
// imports at runtime.
|
|
1313
|
+
if (!usingViteDev &&
|
|
1314
|
+
(matchedRoute === null || matchedRoute === void 0 ? void 0 : matchedRoute.preloadChunks) &&
|
|
1079
1315
|
Array.isArray(matchedRoute.preloadChunks)) {
|
|
1316
|
+
const resolveJs = (chunkName) => {
|
|
1317
|
+
// Vite shape: keyed by source path. Look up by source-path keys
|
|
1318
|
+
// that match the chunk name's tail.
|
|
1319
|
+
const viteEntry = manifest[`src/pages/${chunkName}.tsx`] ||
|
|
1320
|
+
manifest[`src/pages/${chunkName}.ts`] ||
|
|
1321
|
+
Object.values(manifest).find((e) => {
|
|
1322
|
+
var _a, _b;
|
|
1323
|
+
return ((_a = e === null || e === void 0 ? void 0 : e.src) === null || _a === void 0 ? void 0 : _a.endsWith(`${chunkName}.tsx`)) ||
|
|
1324
|
+
((_b = e === null || e === void 0 ? void 0 : e.src) === null || _b === void 0 ? void 0 : _b.endsWith(`${chunkName}.ts`));
|
|
1325
|
+
});
|
|
1326
|
+
if (viteEntry && typeof viteEntry === 'object' && viteEntry.file) {
|
|
1327
|
+
return `/bundles/${viteEntry.file}`;
|
|
1328
|
+
}
|
|
1329
|
+
// Webpack shape: keyed by output name.
|
|
1330
|
+
return (manifest[`${chunkName}.js`] ||
|
|
1331
|
+
manifest[`${chunkName}.bundle.js`] ||
|
|
1332
|
+
manifest[`${chunkName}.mjs`] ||
|
|
1333
|
+
null);
|
|
1334
|
+
};
|
|
1335
|
+
const resolveCss = (chunkName) => {
|
|
1336
|
+
const viteEntry = manifest[`src/pages/${chunkName}.tsx`] ||
|
|
1337
|
+
manifest[`src/pages/${chunkName}.ts`] ||
|
|
1338
|
+
Object.values(manifest).find((e) => {
|
|
1339
|
+
var _a, _b;
|
|
1340
|
+
return ((_a = e === null || e === void 0 ? void 0 : e.src) === null || _a === void 0 ? void 0 : _a.endsWith(`${chunkName}.tsx`)) ||
|
|
1341
|
+
((_b = e === null || e === void 0 ? void 0 : e.src) === null || _b === void 0 ? void 0 : _b.endsWith(`${chunkName}.ts`));
|
|
1342
|
+
});
|
|
1343
|
+
if (viteEntry && typeof viteEntry === 'object' && Array.isArray(viteEntry.css)) {
|
|
1344
|
+
return viteEntry.css.map((c) => `/bundles/${c}`);
|
|
1345
|
+
}
|
|
1346
|
+
const webpackCss = manifest[`${chunkName}.css`];
|
|
1347
|
+
return webpackCss ? [webpackCss] : [];
|
|
1348
|
+
};
|
|
1080
1349
|
preloadScripts = matchedRoute.preloadChunks
|
|
1081
|
-
.map(
|
|
1082
|
-
manifest[`${chunkName}.bundle.js`] ||
|
|
1083
|
-
manifest[`${chunkName}.mjs`])
|
|
1350
|
+
.map(resolveJs)
|
|
1084
1351
|
.filter(Boolean);
|
|
1085
|
-
// Also collect CSS chunks for the same routes
|
|
1086
1352
|
preloadStyles = matchedRoute.preloadChunks
|
|
1087
|
-
.
|
|
1088
|
-
.filter(Boolean);
|
|
1353
|
+
.flatMap(resolveCss);
|
|
1089
1354
|
}
|
|
1090
1355
|
}
|
|
1091
1356
|
catch (err) {
|
|
@@ -1098,9 +1363,30 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
1098
1363
|
React.createElement(StaticRouter, { location: req.url },
|
|
1099
1364
|
React.createElement(AppContextProvider, { assets: this.assets, requestLD: requestLD, requestObject: requestObject, preloadScripts: preloadScripts, preloadStyles: preloadStyles, expressRequest: req, expressResponse: res },
|
|
1100
1365
|
React.createElement(App, null)))), {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1366
|
+
// Bootstrap scripts:
|
|
1367
|
+
// - Vite dev mode: use bootstrapModules so the browser loads them
|
|
1368
|
+
// as ES modules. Vite middleware intercepts /src/index.tsx and
|
|
1369
|
+
// transforms+serves it; /@vite/client provides the HMR client.
|
|
1370
|
+
// @vitejs/plugin-react requires a "preamble" inline script
|
|
1371
|
+
// defining $RefreshReg$/$RefreshSig$ — without it, the first
|
|
1372
|
+
// React module throws "can't detect preamble" and hydration
|
|
1373
|
+
// blows up. Inline via bootstrapScriptContent.
|
|
1374
|
+
// - Production: bootstrapScripts with the hashed main.js from the
|
|
1375
|
+
// Vite (or legacy webpack) build manifest.
|
|
1376
|
+
...(((_j = this.config.server) === null || _j === void 0 ? void 0 : _j.vite)
|
|
1377
|
+
? {
|
|
1378
|
+
bootstrapScriptContent: `
|
|
1379
|
+
import("/@vite/client");
|
|
1380
|
+
import("/@react-refresh").then(RefreshRuntime => {
|
|
1381
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
1382
|
+
window.$RefreshReg$ = () => {};
|
|
1383
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
1384
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
1385
|
+
return import("/src/index.tsx");
|
|
1386
|
+
});
|
|
1387
|
+
`,
|
|
1388
|
+
}
|
|
1389
|
+
: { bootstrapScripts: [this.assets['main.js']] }),
|
|
1104
1390
|
onShellReady: function () {
|
|
1105
1391
|
var _a;
|
|
1106
1392
|
res.statusCode = didError ? 500 : 200;
|
|
@@ -1248,10 +1534,10 @@ let LincdServer = class LincdServer extends Shape {
|
|
|
1248
1534
|
/**
|
|
1249
1535
|
* indicates that instances of this shape need to have this rdf.type
|
|
1250
1536
|
*/
|
|
1251
|
-
|
|
1252
|
-
|
|
1537
|
+
LinkedServer.targetClass = lincdServer.LincdServer;
|
|
1538
|
+
LinkedServer = __decorate([
|
|
1253
1539
|
linkedShape,
|
|
1254
1540
|
__metadata("design:paramtypes", [Object])
|
|
1255
|
-
],
|
|
1256
|
-
export {
|
|
1257
|
-
//# sourceMappingURL=
|
|
1541
|
+
], LinkedServer);
|
|
1542
|
+
export { LinkedServer };
|
|
1543
|
+
//# sourceMappingURL=LinkedServer.js.map
|