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