@_linked/server 2.15.0 → 2.16.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/CHANGELOG.md +18 -0
- package/lib/esm/shapes/LinkedServer.d.ts +28 -0
- package/lib/esm/shapes/LinkedServer.js +163 -43
- package/lib/esm/shapes/LinkedServer.js.map +1 -1
- package/lib/esm/utils/linkedDependencies.d.ts +66 -0
- package/lib/esm/utils/linkedDependencies.js +123 -0
- package/lib/esm/utils/linkedDependencies.js.map +1 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @\_linked/server
|
|
2
2
|
|
|
3
|
+
## 2.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#122](https://github.com/linked-fw/server/pull/122) [`b6c2c9a`](https://github.com/linked-fw/server/commit/b6c2c9ac689c614966f97f39cf18c0bab7683e16) Thanks [@flyon](https://github.com/flyon)! - Load the backend providers of installed linked packages at boot, not only those of local workspace packages.
|
|
8
|
+
|
|
9
|
+
Every package in the app's dependency tree whose package.json declares `"linkedPackage": true` — registry install, localized checkout or workspace member — now has its `/backend` providers indexed at startup, each after the linked packages it depends on. Before, a registry-installed package's provider was indexed only on the first `/call/<pkg>/...`, so its `initRequest` / `supplyDataForRequest` hooks were silent until then and its `setupBeforeControllers` / `setupAfterControllers` never ran at all. With `@_linked/auth` installed from the registry, that meant a signed-in SSR page after a restart shipped an empty request-json and failed to hydrate.
|
|
10
|
+
|
|
11
|
+
The `"linkedPackage": true` flag is the only test, whatever the package's scope: an `@_linked/*` package without it (such as the `@_linked/localize` CLI tool) is not loaded, and a package in any other scope with it is. Legacy `"lincd": true` packages are still not loaded at boot.
|
|
12
|
+
|
|
13
|
+
Lazy indexing on `/call` stays as a fallback and shares one in-flight indexing per package with boot, so a provider is never constructed twice.
|
|
14
|
+
|
|
15
|
+
A provider whose hook throws no longer takes the server down with it. Boot lifecycle hooks (`setupBeforeControllers`, `setupBeforeCatchAllControllers`, `setupAfterControllers`) and per-request hooks (`initRequest`, `supplyDataForRequest`) now run per provider: an error is logged as `[linked] <package> <hook> failed: …` and the remaining providers still run. Before, a throwing boot hook aborted startup, and a synchronous throw in `supplyDataForRequest` failed every page request without naming the provider. This applies to local workspace providers as well as installed ones.
|
|
16
|
+
|
|
17
|
+
In dev, a package's backend is now loaded by the loader that owns the package: `vite.ssrLoadModule` for what the SSR runner bundles (`ssr.noExternal` — workspaces and `SSR_ENTRY_PACKAGES`), Node's `import()` for what it leaves external. Loading an external package's `/backend` through `ssrLoadModule` evaluated that package a second time, apart from the copy the app's own imports use.
|
|
18
|
+
|
|
19
|
+
Apps should be on `@_linked/sentry` 1.1.3 or later: before that, its `setupBeforeControllers` called `require` in ESM and threw `ReferenceError: require is not defined` whenever `SENTRY_DSN` and `SITE_ROOT` are set outside development. Now that that hook runs at boot, an older version logs the error instead of aborting startup, but Sentry stays inactive.
|
|
20
|
+
|
|
3
21
|
## 2.15.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
|
@@ -38,6 +38,7 @@ export declare class LinkedServer extends Shape {
|
|
|
38
38
|
private analyse;
|
|
39
39
|
private shapeProviders;
|
|
40
40
|
private genericProviders;
|
|
41
|
+
private providerIndexing;
|
|
41
42
|
private resizePathsMap;
|
|
42
43
|
private api;
|
|
43
44
|
/**
|
|
@@ -76,6 +77,15 @@ export declare class LinkedServer extends Shape {
|
|
|
76
77
|
* @todo Check if default file store is set, if not, set it
|
|
77
78
|
*/
|
|
78
79
|
initStores(): Promise<any[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Run a lifecycle hook (setupBeforeControllers, setupBeforeCatchAllControllers,
|
|
82
|
+
* setupAfterControllers) on every generic provider, in indexing order.
|
|
83
|
+
*
|
|
84
|
+
* Each provider is isolated: a hook that throws (or rejects) is logged with
|
|
85
|
+
* the package and hook name and the next provider still runs, so one broken
|
|
86
|
+
* provider does not abort boot. That provider's routes or middleware from
|
|
87
|
+
* that hook may be missing, but the rest of the app starts.
|
|
88
|
+
*/
|
|
79
89
|
callGenericBackendProvidersMethod(method: string, ...args: any[]): Promise<void>;
|
|
80
90
|
/**
|
|
81
91
|
* Removes temporary nodes from memory if they've been seen twice
|
|
@@ -84,6 +94,24 @@ export declare class LinkedServer extends Shape {
|
|
|
84
94
|
*/
|
|
85
95
|
initGarbageCollection(): void;
|
|
86
96
|
initBackendProviders(): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Index the backend providers of every linked package in the app's
|
|
99
|
+
* dependency tree, dependencies first. Workspace members (`localPackages`)
|
|
100
|
+
* are also imported whole, as before; for anything else only its `/backend`
|
|
101
|
+
* entry is loaded, and a package without one costs a failed resolve.
|
|
102
|
+
*/
|
|
103
|
+
private indexLinkedDependencyProviders;
|
|
104
|
+
/**
|
|
105
|
+
* Index a package's backend providers once. Shared by boot and the lazy
|
|
106
|
+
* path in callBackendMethod / callShapeMethod. `onSourceChange` bypasses it
|
|
107
|
+
* on purpose: an HMR reload must re-index.
|
|
108
|
+
*/
|
|
109
|
+
ensurePackageBackendProviders(pkg: string, warnIfNotFound?: boolean): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Node's `import()`, as a method so a test can resolve a fixture app's
|
|
112
|
+
* node_modules (a test runner resolves bare specifiers from this file).
|
|
113
|
+
*/
|
|
114
|
+
protected importModule(specifier: string): Promise<any>;
|
|
87
115
|
/**
|
|
88
116
|
* Filters local workspace packages to only those reachable from the app's
|
|
89
117
|
* dependency tree. Mirrors the logic used by `buildAll` in lincd-cli.
|
|
@@ -36,6 +36,42 @@ import { autoLoadOntologyData } from '@_linked/core/utils/Package';
|
|
|
36
36
|
import { getShapeClass, getSuperShapesClasses, } from '@_linked/core/utils/ShapeClass';
|
|
37
37
|
import path from 'path';
|
|
38
38
|
import { pathToFileURL } from 'node:url';
|
|
39
|
+
import { discoverLinkedDependencies, isBundledBySsr, ssrNoExternalOf, } from '../utils/linkedDependencies.js';
|
|
40
|
+
/**
|
|
41
|
+
* `instanceof ShapeProvider`, tolerating a second copy of server-utils.
|
|
42
|
+
*
|
|
43
|
+
* A registry-installed package's backend is loaded by Node (see
|
|
44
|
+
* isBundledBySsr), so in a dev runner that BUNDLES server-utils — the
|
|
45
|
+
* standalone case — its providers extend Node's copy of ShapeProvider, not the
|
|
46
|
+
* one this module imported. Fall back to the class name along the prototype
|
|
47
|
+
* chain. Production has one loader and one copy, so instanceof decides there.
|
|
48
|
+
*/
|
|
49
|
+
function isShapeProvider(provider) {
|
|
50
|
+
var _a;
|
|
51
|
+
if (provider instanceof ShapeProvider)
|
|
52
|
+
return true;
|
|
53
|
+
for (let proto = provider ? Object.getPrototypeOf(provider) : null; proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
|
|
54
|
+
if (((_a = proto.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'ShapeProvider')
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Call one provider's hook and contain its failure: a synchronous throw or a
|
|
61
|
+
* rejection is logged, naming the package and the hook, and swallowed. Used
|
|
62
|
+
* for hooks that run for every provider (boot lifecycle hooks and per-request
|
|
63
|
+
* hooks), where one provider's bug must not take down boot or every request
|
|
64
|
+
* without saying which provider it was.
|
|
65
|
+
*/
|
|
66
|
+
async function runProviderHook(pkg, hook, call) {
|
|
67
|
+
var _a;
|
|
68
|
+
try {
|
|
69
|
+
await call();
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
console.error(chalk.red(`[linked] ${pkg} ${hook} failed: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`), (err === null || err === void 0 ? void 0 : err.stack) ? `\n${err.stack}` : '');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
39
75
|
import process from 'process';
|
|
40
76
|
import * as React from 'react';
|
|
41
77
|
import { renderToPipeableStream, renderToStaticMarkup } from 'react-dom/server';
|
|
@@ -125,6 +161,10 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
125
161
|
this.analyse = false;
|
|
126
162
|
this.shapeProviders = new Map();
|
|
127
163
|
this.genericProviders = new Map();
|
|
164
|
+
// One indexing per package: boot and the lazy /call path share it, so two
|
|
165
|
+
// concurrent first calls (or a call racing boot) never construct a
|
|
166
|
+
// package's providers twice.
|
|
167
|
+
this.providerIndexing = new Map();
|
|
128
168
|
//from resizedFileName to full resized path (CDN or similar)
|
|
129
169
|
this.resizePathsMap = new Map();
|
|
130
170
|
if (config && typeof config !== 'string' && !('id' in config)) {
|
|
@@ -499,15 +539,21 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
499
539
|
return store.init ? store.init() : Promise.resolve();
|
|
500
540
|
}));
|
|
501
541
|
}
|
|
502
|
-
|
|
542
|
+
/**
|
|
543
|
+
* Run a lifecycle hook (setupBeforeControllers, setupBeforeCatchAllControllers,
|
|
544
|
+
* setupAfterControllers) on every generic provider, in indexing order.
|
|
545
|
+
*
|
|
546
|
+
* Each provider is isolated: a hook that throws (or rejects) is logged with
|
|
547
|
+
* the package and hook name and the next provider still runs, so one broken
|
|
548
|
+
* provider does not abort boot. That provider's routes or middleware from
|
|
549
|
+
* that hook may be missing, but the rest of the app starts.
|
|
550
|
+
*/
|
|
503
551
|
async callGenericBackendProvidersMethod(method, ...args) {
|
|
504
|
-
for (let genericProvider of this.genericProviders.
|
|
505
|
-
if (!genericProvider ||
|
|
552
|
+
for (let [pkg, genericProvider] of this.genericProviders.entries()) {
|
|
553
|
+
if (!genericProvider || typeof genericProvider[method] !== 'function') {
|
|
506
554
|
continue;
|
|
507
555
|
}
|
|
508
|
-
|
|
509
|
-
await Promise.resolve(genericProvider[method](...args));
|
|
510
|
-
}
|
|
556
|
+
await runProviderHook(pkg, method, () => genericProvider[method](...args));
|
|
511
557
|
}
|
|
512
558
|
}
|
|
513
559
|
/**
|
|
@@ -535,16 +581,21 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
535
581
|
// // }, 1000 * 60 * 60); //every hour
|
|
536
582
|
}
|
|
537
583
|
async initBackendProviders() {
|
|
538
|
-
//
|
|
539
|
-
//
|
|
540
|
-
//legacy packages that may use an old version of the core.
|
|
584
|
+
// Local workspace packages in this app's dependency tree. These are also
|
|
585
|
+
// imported whole at boot (indexLincdPackage), not only their /backend.
|
|
541
586
|
const allLocalPackages = getLincdPackages();
|
|
542
587
|
const localPackageMap = new Map(allLocalPackages.map((pkg) => [pkg.packageName, pkg]));
|
|
543
588
|
const relevantPackages = this.filterPackagesByDependencyTree(localPackageMap, this.package);
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
589
|
+
// Every linked package in the dependency tree, installed or local, each
|
|
590
|
+
// after the linked packages it depends on. Registry installs and
|
|
591
|
+
// localized checkouts are not workspace members, and used to be indexed
|
|
592
|
+
// only lazily, on the first /call/<pkg>/... A provider can hook every
|
|
593
|
+
// request (initRequest, supplyDataForRequest, setupBeforeControllers
|
|
594
|
+
// routes), so those hooks stayed silent until some RPC to the package
|
|
595
|
+
// happened — an installed @_linked/auth did not put the session into a
|
|
596
|
+
// page's request data until then, and its setupBeforeControllers
|
|
597
|
+
// middleware never registered at all.
|
|
598
|
+
await this.indexLinkedDependencyProviders(relevantPackages);
|
|
548
599
|
try {
|
|
549
600
|
await fs
|
|
550
601
|
.readFile(path.join(process.cwd(), 'package.json'), 'utf-8')
|
|
@@ -569,6 +620,67 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
569
620
|
console.warn(err);
|
|
570
621
|
}
|
|
571
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Index the backend providers of every linked package in the app's
|
|
625
|
+
* dependency tree, dependencies first. Workspace members (`localPackages`)
|
|
626
|
+
* are also imported whole, as before; for anything else only its `/backend`
|
|
627
|
+
* entry is loaded, and a package without one costs a failed resolve.
|
|
628
|
+
*/
|
|
629
|
+
async indexLinkedDependencyProviders(localPackages) {
|
|
630
|
+
var _a;
|
|
631
|
+
const started = Date.now();
|
|
632
|
+
const installed = [];
|
|
633
|
+
const ordered = discoverLinkedDependencies(process.cwd(), this.package);
|
|
634
|
+
// A workspace member the walk cannot reach through node_modules still
|
|
635
|
+
// loads, after the rest, as it always did.
|
|
636
|
+
const remaining = new Set(localPackages.keys());
|
|
637
|
+
for (const { packageName } of ordered) {
|
|
638
|
+
const isLocal = remaining.delete(packageName);
|
|
639
|
+
await this.ensurePackageBackendProviders(packageName);
|
|
640
|
+
if (isLocal) {
|
|
641
|
+
await this.indexLincdPackage(packageName);
|
|
642
|
+
}
|
|
643
|
+
else if (this.genericProviders.get(packageName) ||
|
|
644
|
+
((_a = this.shapeProviders.get(packageName)) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
645
|
+
installed.push(packageName);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
for (const packageName of remaining) {
|
|
649
|
+
await this.ensurePackageBackendProviders(packageName);
|
|
650
|
+
await this.indexLincdPackage(packageName);
|
|
651
|
+
}
|
|
652
|
+
if (installed.length > 0) {
|
|
653
|
+
console.log(chalk.gray(`[linked] indexed backend providers of ${ordered.length} linked package(s) in ${Date.now() - started}ms; installed ones with providers: ${installed.join(', ')}`));
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Index a package's backend providers once. Shared by boot and the lazy
|
|
658
|
+
* path in callBackendMethod / callShapeMethod. `onSourceChange` bypasses it
|
|
659
|
+
* on purpose: an HMR reload must re-index.
|
|
660
|
+
*/
|
|
661
|
+
async ensurePackageBackendProviders(pkg, warnIfNotFound = false) {
|
|
662
|
+
if (this.genericProviders.has(pkg) && this.shapeProviders.has(pkg)) {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
let indexing = this.providerIndexing.get(pkg);
|
|
666
|
+
if (!indexing) {
|
|
667
|
+
indexing = this.indexPackageBackendProviders(pkg, warnIfNotFound).then(() => undefined);
|
|
668
|
+
this.providerIndexing.set(pkg, indexing);
|
|
669
|
+
}
|
|
670
|
+
try {
|
|
671
|
+
await indexing;
|
|
672
|
+
}
|
|
673
|
+
finally {
|
|
674
|
+
this.providerIndexing.delete(pkg);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Node's `import()`, as a method so a test can resolve a fixture app's
|
|
679
|
+
* node_modules (a test runner resolves bare specifiers from this file).
|
|
680
|
+
*/
|
|
681
|
+
importModule(specifier) {
|
|
682
|
+
return import(/* @vite-ignore */ specifier);
|
|
683
|
+
}
|
|
572
684
|
/**
|
|
573
685
|
* Filters local workspace packages to only those reachable from the app's
|
|
574
686
|
* dependency tree. Mirrors the logic used by `buildAll` in lincd-cli.
|
|
@@ -897,7 +1009,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
897
1009
|
}
|
|
898
1010
|
}
|
|
899
1011
|
async indexPackageBackendProviders(pkg, warnIfNotFound = false, backendIndexFilePath) {
|
|
900
|
-
var _a;
|
|
1012
|
+
var _a, _b;
|
|
901
1013
|
if (!backendIndexFilePath) {
|
|
902
1014
|
backendIndexFilePath = `${pkg}/backend`;
|
|
903
1015
|
}
|
|
@@ -910,9 +1022,19 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
910
1022
|
// @semantu/create-now/backend), which Node's ESM resolver can't resolve
|
|
911
1023
|
// from inside an installed package like @_linked/server.
|
|
912
1024
|
const vite = (_a = this.config.server) === null || _a === void 0 ? void 0 : _a.vite;
|
|
1025
|
+
// In dev, load a package's backend with the loader that owns the package
|
|
1026
|
+
// (see isBundledBySsr): Vite for the app itself and for what the SSR
|
|
1027
|
+
// runner bundles (workspaces, SSR_ENTRY_PACKAGES), Node for what it
|
|
1028
|
+
// leaves external (registry installs). ssrLoadModule of an EXTERNAL
|
|
1029
|
+
// package's /backend evaluated that package a second time, apart from the
|
|
1030
|
+
// copy the app's own imports reach.
|
|
1031
|
+
const viteOwnsPackage = !!vite &&
|
|
1032
|
+
typeof vite.ssrLoadModule === 'function' &&
|
|
1033
|
+
(pkg === ((_b = this.package) === null || _b === void 0 ? void 0 : _b.name) ||
|
|
1034
|
+
isBundledBySsr(pkg, ssrNoExternalOf(vite)));
|
|
913
1035
|
const loadModule = async (specifier) => {
|
|
914
1036
|
var _a, _b, _c;
|
|
915
|
-
if (
|
|
1037
|
+
if (viteOwnsPackage) {
|
|
916
1038
|
// For the user app's own backend, resolve to ./src/backend.ts directly.
|
|
917
1039
|
// Vite reads the app's package.json exports.development condition.
|
|
918
1040
|
if (specifier === `${this.package.name}/backend`) {
|
|
@@ -952,7 +1074,8 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
952
1074
|
}
|
|
953
1075
|
return await vite.ssrLoadModule(specifier);
|
|
954
1076
|
}
|
|
955
|
-
//
|
|
1077
|
+
// Node path: production runtime, or a package the dev SSR runner
|
|
1078
|
+
// leaves external.
|
|
956
1079
|
//
|
|
957
1080
|
// The app's own backend cannot be imported by name here. A self-reference
|
|
958
1081
|
// resolves only from inside the package that declares it, and this code
|
|
@@ -967,7 +1090,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
967
1090
|
return await import(/* @vite-ignore */ pathToFileURL(target).href);
|
|
968
1091
|
}
|
|
969
1092
|
// Fall back to Node's resolver. The dynamic specifier is intentional.
|
|
970
|
-
return await
|
|
1093
|
+
return await this.importModule(specifier);
|
|
971
1094
|
};
|
|
972
1095
|
await loadModule(backendIndexFilePath)
|
|
973
1096
|
.then((backendProviderExports) => {
|
|
@@ -977,7 +1100,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
977
1100
|
//always send an instance of the express server
|
|
978
1101
|
//TODO: do not create an instance, just save the class and instantiate it when needed
|
|
979
1102
|
let provider = new providerClass(this.server, this);
|
|
980
|
-
if (provider
|
|
1103
|
+
if (isShapeProvider(provider)) {
|
|
981
1104
|
shapeProviders.push(provider);
|
|
982
1105
|
if (!Object.getOwnPropertyNames(provider).includes('shape')) {
|
|
983
1106
|
console.warn(chalk.red(`${Object.getPrototypeOf(provider).constructor.name} in package ${pkg}
|
|
@@ -1192,7 +1315,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1192
1315
|
var _a;
|
|
1193
1316
|
//- index module providers if not done yet
|
|
1194
1317
|
if (!this.shapeProviders.has(pkg)) {
|
|
1195
|
-
await this.
|
|
1318
|
+
await this.ensurePackageBackendProviders(pkg, true);
|
|
1196
1319
|
}
|
|
1197
1320
|
let packageShapeProviders = this.shapeProviders.get(pkg);
|
|
1198
1321
|
let findProviderForShape = (nodeShapeId) => {
|
|
@@ -1200,7 +1323,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1200
1323
|
var _a, _b;
|
|
1201
1324
|
//access the static shape (which is a linkedShape() / Shape class)
|
|
1202
1325
|
//then access the SHACL NodeShape of that shape class, and its id
|
|
1203
|
-
return (provider
|
|
1326
|
+
return (isShapeProvider(provider) &&
|
|
1204
1327
|
((_b = (_a = provider.shape) === null || _a === void 0 ? void 0 : _a.shape) === null || _b === void 0 ? void 0 : _b.id) === nodeShapeId);
|
|
1205
1328
|
});
|
|
1206
1329
|
};
|
|
@@ -1649,32 +1772,29 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1649
1772
|
res.json(jsonObject);
|
|
1650
1773
|
}
|
|
1651
1774
|
async initRequest(request, response) {
|
|
1652
|
-
// initialise the request for all providers,
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
.catch((err) => {
|
|
1662
|
-
console.warn(`Error during initRequest for provider ${Object.getPrototypeOf(backendProvider).constructor.name}: `, err);
|
|
1663
|
-
});
|
|
1664
|
-
});
|
|
1665
|
-
return p;
|
|
1775
|
+
// initialise the request for all providers, one after the other (order
|
|
1776
|
+
// matters: later providers may read what earlier ones put on the request).
|
|
1777
|
+
// A provider that throws is logged by package name and skipped.
|
|
1778
|
+
for (const [pkg, backendProvider] of this.genericProviders.entries()) {
|
|
1779
|
+
if (!backendProvider || typeof backendProvider.initRequest !== 'function') {
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
await runProviderHook(pkg, 'initRequest', () => backendProvider.initRequest(request, response));
|
|
1783
|
+
}
|
|
1666
1784
|
}
|
|
1667
1785
|
async getRequestData(request, response) {
|
|
1668
|
-
//
|
|
1669
|
-
// requestLD is kept as empty string for now
|
|
1670
|
-
//
|
|
1786
|
+
// Providers return plain JSON data via supplyDataForRequest.
|
|
1787
|
+
// requestLD is kept as empty string for now; SSR data seeding will
|
|
1788
|
+
// inject query results instead of graph data.
|
|
1789
|
+
// A provider that throws (synchronously or not) is logged by package
|
|
1790
|
+
// name; the page still renders with the other providers' data.
|
|
1671
1791
|
let requestData = {};
|
|
1672
|
-
await Promise.all([...this.genericProviders.
|
|
1673
|
-
if (backendProvider
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
});
|
|
1792
|
+
await Promise.all([...this.genericProviders.entries()].map(([pkg, backendProvider]) => {
|
|
1793
|
+
if (!backendProvider ||
|
|
1794
|
+
typeof backendProvider.supplyDataForRequest !== 'function') {
|
|
1795
|
+
return;
|
|
1677
1796
|
}
|
|
1797
|
+
return runProviderHook(pkg, 'supplyDataForRequest', () => backendProvider.supplyDataForRequest(request, response, requestData));
|
|
1678
1798
|
}));
|
|
1679
1799
|
let requestLD = '';
|
|
1680
1800
|
let requestObject = JSONWriter.stringify(request['frontendData']);
|
|
@@ -1682,7 +1802,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1682
1802
|
}
|
|
1683
1803
|
async callBackendMethod(pkg, method, args, request, response) {
|
|
1684
1804
|
if (!this.genericProviders.has(pkg)) {
|
|
1685
|
-
await this.
|
|
1805
|
+
await this.ensurePackageBackendProviders(pkg, true);
|
|
1686
1806
|
}
|
|
1687
1807
|
//retrieve the indexed provider class and create a new instance for this request
|
|
1688
1808
|
let genericBackendProvider = this.genericProviders.get(pkg);
|