@_linked/server 2.16.2 → 2.18.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 +20 -0
- package/lib/esm/data/lincd-server.json +1 -1
- package/lib/esm/ontologies/lincd-server.d.ts +12 -0
- package/lib/esm/ontologies/lincd-server.js +13 -1
- package/lib/esm/ontologies/lincd-server.js.map +1 -1
- package/lib/esm/shapes/LinkedServer.d.ts +27 -4
- package/lib/esm/shapes/LinkedServer.js +164 -120
- package/lib/esm/shapes/LinkedServer.js.map +1 -1
- package/lib/esm/utils/linkedDependencies.d.ts +52 -2
- package/lib/esm/utils/linkedDependencies.js +181 -11
- package/lib/esm/utils/linkedDependencies.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @\_linked/server
|
|
2
2
|
|
|
3
|
+
## 2.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#128](https://github.com/linked-fw/server/pull/128) [`2b8e8ac`](https://github.com/linked-fw/server/commit/2b8e8acde912d91d8b706f09ca0a6e2663155c0c) Thanks [@flyon](https://github.com/flyon)! - The server ontology moves from `http://lincd.org/ont/lincd-server/` to `https://linked.cm/ont/server/`, the first-party scheme every public package uses (`https://linked.cm/ont/{publicSlug}/`, next to its shapes at `https://linked.cm/shape/server/`).
|
|
8
|
+
|
|
9
|
+
No data migration is needed. No stored data is typed with these terms (`LincdServer`, `LincdAPI`, `LincdWebApp`, `hasAPI`, …). The only store triples that carried them are the synced shape descriptions of `LinkedServer`, `LincdAPI` and `LincdWebApp` (`sh:targetClass`, `sh:path`); boot sync deletes and recreates each registered shape's description, so they move to the new IRIs the next time the server starts. With `syncShapesOnBoot: false` they keep the old IRIs until the next sync. The prefix key (`lincd-server`) and the `ontologies/lincd-server` module are unchanged; code that hard-codes `http://lincd.org/ont/lincd-server/` must be updated.
|
|
10
|
+
|
|
11
|
+
## 2.17.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#126](https://github.com/linked-fw/server/pull/126) [`93ebd50`](https://github.com/linked-fw/server/commit/93ebd5002d76ad9208cac63c09ad92e5f4f74c0a) Thanks [@flyon](https://github.com/flyon)! - Load each linked package's backend from the directory it is installed in, not by its bare name.
|
|
16
|
+
|
|
17
|
+
The backend entry used to be loaded with `import('<pkg>/backend')`, which Node resolves from @_linked/server's own location. A linked package installed only nested inside another package's `node_modules` (npm does this when the root cannot share one version, e.g. `@_linked/owl/node_modules/@_linked/rdfs`) could therefore never be loaded: boot logged a red "Cannot find package" error for packages without a backend, and a nested package WITH a backend never had its providers constructed, its request hooks never ran, and `/call` to it answered 501.
|
|
18
|
+
|
|
19
|
+
Now the server keeps the path discovery found for every linked package, resolves the `./backend` entry from that package's own `exports` (new `resolveBackendEntry`: exact key, `./*` patterns, `import`/`node`/`default` conditions; legacy layout without `exports`) and imports it by file URL. Whether a package has a backend is decided before anything is imported: no entry is quiet, and a backend file that fails to load is a loud error naming the package and the file, without stopping other packages. The error-text matching that used to tell the two apart is gone.
|
|
20
|
+
|
|
21
|
+
When a linked package is installed more than once, only the copy the app itself resolves is loaded, and the server warns once with every copy's version and path and a hint to run `npm dedupe`.
|
|
22
|
+
|
|
3
23
|
## 2.16.2
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"owl": "http://www.w3.org/2002/07/owl#",
|
|
5
5
|
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
|
6
6
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
|
7
|
-
"lincd-server": "
|
|
7
|
+
"lincd-server": "https://linked.cm/ont/server/"
|
|
8
8
|
},
|
|
9
9
|
"@graph": [
|
|
10
10
|
{
|
|
@@ -20,6 +20,18 @@ export declare var loadData: () => Promise<{
|
|
|
20
20
|
"rdfs:label": string;
|
|
21
21
|
}[];
|
|
22
22
|
}>;
|
|
23
|
+
/**
|
|
24
|
+
* The namespace of this ontology.
|
|
25
|
+
*
|
|
26
|
+
* First-party ontologies live on linked.cm: `https://linked.cm/ont/{ontologySlug}/`, and a
|
|
27
|
+
* package's own ontology takes the package's publicSlug (`@_linked/server` → `server`), the same
|
|
28
|
+
* slug its shapes use under `https://linked.cm/shape/server/`.
|
|
29
|
+
*
|
|
30
|
+
* Until this release it was `http://lincd.org/ont/lincd-server/`. No stored data is typed with
|
|
31
|
+
* these terms; the only store triples that carried them were the synced shape descriptions of
|
|
32
|
+
* `LinkedServer`, `LincdAPI` and `LincdWebApp` (`sh:targetClass`, `sh:path`), which boot sync
|
|
33
|
+
* rewrites (delete, then recreate) the next time the server starts.
|
|
34
|
+
*/
|
|
23
35
|
export declare var ns: (term: string) => import("@_linked/core/utils/NodeReference").NodeReferenceValue;
|
|
24
36
|
export declare var _self: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
|
|
25
37
|
export declare const lincdServer: {
|
|
@@ -10,7 +10,19 @@ export var loadData = async () => {
|
|
|
10
10
|
});
|
|
11
11
|
return data.default || data;
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The namespace of this ontology.
|
|
15
|
+
*
|
|
16
|
+
* First-party ontologies live on linked.cm: `https://linked.cm/ont/{ontologySlug}/`, and a
|
|
17
|
+
* package's own ontology takes the package's publicSlug (`@_linked/server` → `server`), the same
|
|
18
|
+
* slug its shapes use under `https://linked.cm/shape/server/`.
|
|
19
|
+
*
|
|
20
|
+
* Until this release it was `http://lincd.org/ont/lincd-server/`. No stored data is typed with
|
|
21
|
+
* these terms; the only store triples that carried them were the synced shape descriptions of
|
|
22
|
+
* `LinkedServer`, `LincdAPI` and `LincdWebApp` (`sh:targetClass`, `sh:path`), which boot sync
|
|
23
|
+
* rewrites (delete, then recreate) the next time the server starts.
|
|
24
|
+
*/
|
|
25
|
+
export var ns = createNameSpace('https://linked.cm/ont/server/');
|
|
14
26
|
export var _self = ns('');
|
|
15
27
|
// Terms are properties of the namespace object below, not module-scope
|
|
16
28
|
// exports. Most of these names are also SHAPE CLASS names in this package
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lincd-server.js","sourceRoot":"","sources":["../../../src/ontologies/lincd-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,IAAI,QAAQ,GAAG,KAAK,IAAI,EAAE;IAC/B,YAAY;IACZ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,2BAA2B,EAAE;QACrD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;KACvB,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,IAAI,EAAE,GAAG,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"lincd-server.js","sourceRoot":"","sources":["../../../src/ontologies/lincd-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,IAAI,QAAQ,GAAG,KAAK,IAAI,EAAE;IAC/B,YAAY;IACZ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,2BAA2B,EAAE;QACrD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;KACvB,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;AAC9B,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,IAAI,EAAE,GAAG,eAAe,CAAC,+BAA+B,CAAC,CAAC;AAEjE,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;AAE1B,uEAAuE;AACvE,0EAA0E;AAC1E,+EAA+E;AAC/E,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,WAAW,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;AACtC,MAAM,gBAAgB,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC;AAChD,MAAM,aAAa,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;AAC1C,MAAM,YAAY,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;AACxC,MAAM,eAAe,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC;AAC9C,MAAM,WAAW,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;AACtC,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC;AACpC,MAAM,gBAAgB,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC;AAChD,MAAM,WAAW,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;AACtC,MAAM,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;AAChC,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AAE5B,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,WAAW;IACX,gBAAgB;IAChB,aAAa;IACb,YAAY;IACZ,WAAW;IACX,eAAe;IACf,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,QAAQ;IACR,MAAM;CACP,CAAC","sourcesContent":["import { createNameSpace } from '@_linked/core/utils/NameSpace';\n\n/**\n * Load the data of this ontology.\n * In @_linked/core, loadData returns the raw JSON import — no JSONLD.parse() needed.\n */\nexport var loadData = async () => {\n //@ts-ignore\n const data = await import('../data/lincd-server.json', {\n with: { type: 'json' },\n });\n return data.default || data;\n};\n\n/**\n * The namespace of this ontology.\n *\n * First-party ontologies live on linked.cm: `https://linked.cm/ont/{ontologySlug}/`, and a\n * package's own ontology takes the package's publicSlug (`@_linked/server` → `server`), the same\n * slug its shapes use under `https://linked.cm/shape/server/`.\n *\n * Until this release it was `http://lincd.org/ont/lincd-server/`. No stored data is typed with\n * these terms; the only store triples that carried them were the synced shape descriptions of\n * `LinkedServer`, `LincdAPI` and `LincdWebApp` (`sh:targetClass`, `sh:path`), which boot sync\n * rewrites (delete, then recreate) the next time the server starts.\n */\nexport var ns = createNameSpace('https://linked.cm/ont/server/');\n\nexport var _self = ns('');\n\n// Terms are properties of the namespace object below, not module-scope\n// exports. Most of these names are also SHAPE CLASS names in this package\n// (BackendAPIStore, LincdWebApp, LincdAPI, ...). Two bindings of the same name\n// in one bundle scope make the bundler rename one of them, and when the loser\n// is the class, `constructor.name` becomes `BackendAPIStore2` -- which is the\n// shape's IRI and the name `Server.call` routes on. The client then asks a\n// backend that has no such shape, and every store round-trip answers 501.\nconst LincdServer = ns('LincdServer');\nconst BackendFileStore = ns('BackendFileStore');\nconst NodeFileStore = ns('NodeFileStore');\nconst BackendStore = ns('BackendStore');\nconst BackendAPIStore = ns('BackendAPIStore');\nconst LincdWebApp = ns('LincdWebApp');\nconst ownPackage = ns('ownPackage');\nconst maintainsPackage = ns('maintainsPackage');\nconst N3FileStore = ns('N3FileStore');\nconst LincdAPI = ns('LincdAPI');\nconst hasAPI = ns('hasAPI');\n\nexport const lincdServer = {\n LincdServer,\n BackendFileStore,\n NodeFileStore,\n BackendStore,\n N3FileStore,\n BackendAPIStore,\n LincdWebApp,\n ownPackage,\n maintainsPackage,\n LincdAPI,\n hasAPI,\n};\n\n"]}
|
|
@@ -39,6 +39,16 @@ export declare class LinkedServer extends Shape {
|
|
|
39
39
|
private shapeProviders;
|
|
40
40
|
private genericProviders;
|
|
41
41
|
private providerIndexing;
|
|
42
|
+
/**
|
|
43
|
+
* Package name → realpath of the installed copy whose backend is loaded,
|
|
44
|
+
* as discovery found it. A package's backend is resolved from THIS
|
|
45
|
+
* directory, never by its bare name from @_linked/server's own location:
|
|
46
|
+
* Node would never look inside another package's nested node_modules, so a
|
|
47
|
+
* linked package installed only there (owl/node_modules/@_linked/rdfs)
|
|
48
|
+
* could not be loaded at all.
|
|
49
|
+
*/
|
|
50
|
+
private linkedPackageDirs;
|
|
51
|
+
private warnedDuplicateInstalls;
|
|
42
52
|
private resizePathsMap;
|
|
43
53
|
private api;
|
|
44
54
|
/**
|
|
@@ -98,9 +108,22 @@ export declare class LinkedServer extends Shape {
|
|
|
98
108
|
* Index the backend providers of every linked package in the app's
|
|
99
109
|
* dependency tree, dependencies first. Workspace members (`localPackages`)
|
|
100
110
|
* are also imported whole, as before; for anything else only its `/backend`
|
|
101
|
-
* entry is loaded
|
|
111
|
+
* entry is loaded — resolved from the directory discovery found the package
|
|
112
|
+
* in, and skipped without an import when the package has none.
|
|
102
113
|
*/
|
|
103
114
|
private indexLinkedDependencyProviders;
|
|
115
|
+
/**
|
|
116
|
+
* Two installed copies of one linked package mean two copies of its module
|
|
117
|
+
* state, and only one of them can own the backend. The one the app resolves
|
|
118
|
+
* is loaded (see discoverLinkedDependencies); the other is never loaded.
|
|
119
|
+
*/
|
|
120
|
+
private warnIfInstalledMoreThanOnce;
|
|
121
|
+
/**
|
|
122
|
+
* The directory a package's backend is resolved from: the copy discovery
|
|
123
|
+
* chose, or — for a package outside the linked tree, reached only by a lazy
|
|
124
|
+
* /call — the copy the app itself resolves.
|
|
125
|
+
*/
|
|
126
|
+
private packageDirFor;
|
|
104
127
|
/**
|
|
105
128
|
* Index a package's backend providers once. Shared by boot and the lazy
|
|
106
129
|
* path in callBackendMethod / callShapeMethod. `onSourceChange` bypasses it
|
|
@@ -108,8 +131,8 @@ export declare class LinkedServer extends Shape {
|
|
|
108
131
|
*/
|
|
109
132
|
ensurePackageBackendProviders(pkg: string, warnIfNotFound?: boolean): Promise<void>;
|
|
110
133
|
/**
|
|
111
|
-
* Node's `import()
|
|
112
|
-
*
|
|
134
|
+
* Node's `import()`. Called with the absolute file URL of a resolved backend
|
|
135
|
+
* entry (see resolveBackendEntry), never a bare name.
|
|
113
136
|
*/
|
|
114
137
|
protected importModule(specifier: string): Promise<any>;
|
|
115
138
|
/**
|
|
@@ -119,7 +142,7 @@ export declare class LinkedServer extends Shape {
|
|
|
119
142
|
private filterPackagesByDependencyTree;
|
|
120
143
|
resizeImage(req: any, res: any): Promise<void>;
|
|
121
144
|
indexLincdPackage(pkg: string, warnIfNotFound?: boolean): Promise<void>;
|
|
122
|
-
indexPackageBackendProviders(pkg: string, warnIfNotFound?: boolean
|
|
145
|
+
indexPackageBackendProviders(pkg: string, warnIfNotFound?: boolean): Promise<{
|
|
123
146
|
backendProviderExports: any;
|
|
124
147
|
shapeProviders: any[];
|
|
125
148
|
}>;
|
|
@@ -37,7 +37,7 @@ import { autoLoadOntologyData } from '@_linked/core/utils/Package';
|
|
|
37
37
|
import { getShapeClass, getSuperShapesClasses, } from '@_linked/core/utils/ShapeClass';
|
|
38
38
|
import path from 'path';
|
|
39
39
|
import { pathToFileURL } from 'node:url';
|
|
40
|
-
import { discoverLinkedDependencies, isBundledBySsr, ssrNoExternalOf, } from '../utils/linkedDependencies.js';
|
|
40
|
+
import { discoverLinkedDependencies, isBundledBySsr, NODE_IMPORT_CONDITIONS, readInstalledPackage, resolveBackendEntry, ssrNoExternalOf, } from '../utils/linkedDependencies.js';
|
|
41
41
|
/**
|
|
42
42
|
* `instanceof ShapeProvider`, tolerating a second copy of server-utils.
|
|
43
43
|
*
|
|
@@ -166,6 +166,16 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
166
166
|
// concurrent first calls (or a call racing boot) never construct a
|
|
167
167
|
// package's providers twice.
|
|
168
168
|
this.providerIndexing = new Map();
|
|
169
|
+
/**
|
|
170
|
+
* Package name → realpath of the installed copy whose backend is loaded,
|
|
171
|
+
* as discovery found it. A package's backend is resolved from THIS
|
|
172
|
+
* directory, never by its bare name from @_linked/server's own location:
|
|
173
|
+
* Node would never look inside another package's nested node_modules, so a
|
|
174
|
+
* linked package installed only there (owl/node_modules/@_linked/rdfs)
|
|
175
|
+
* could not be loaded at all.
|
|
176
|
+
*/
|
|
177
|
+
this.linkedPackageDirs = new Map();
|
|
178
|
+
this.warnedDuplicateInstalls = new Set();
|
|
169
179
|
//from resizedFileName to full resized path (CDN or similar)
|
|
170
180
|
this.resizePathsMap = new Map();
|
|
171
181
|
if (config && typeof config !== 'string' && !('id' in config)) {
|
|
@@ -624,16 +634,32 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
624
634
|
* Index the backend providers of every linked package in the app's
|
|
625
635
|
* dependency tree, dependencies first. Workspace members (`localPackages`)
|
|
626
636
|
* are also imported whole, as before; for anything else only its `/backend`
|
|
627
|
-
* entry is loaded
|
|
637
|
+
* entry is loaded — resolved from the directory discovery found the package
|
|
638
|
+
* in, and skipped without an import when the package has none.
|
|
628
639
|
*/
|
|
629
640
|
async indexLinkedDependencyProviders(localPackages) {
|
|
630
|
-
var _a;
|
|
641
|
+
var _a, _b;
|
|
631
642
|
const started = Date.now();
|
|
632
643
|
const installed = [];
|
|
633
644
|
const ordered = discoverLinkedDependencies(process.cwd(), this.package);
|
|
634
645
|
// A workspace member the walk cannot reach through node_modules still
|
|
635
646
|
// loads, after the rest, as it always did.
|
|
636
647
|
const remaining = new Set(localPackages.keys());
|
|
648
|
+
(_a = this.linkedPackageDirs) !== null && _a !== void 0 ? _a : (this.linkedPackageDirs = new Map());
|
|
649
|
+
for (const dep of ordered) {
|
|
650
|
+
this.linkedPackageDirs.set(dep.packageName, dep.path);
|
|
651
|
+
this.warnIfInstalledMoreThanOnce(dep);
|
|
652
|
+
}
|
|
653
|
+
for (const [packageName, local] of localPackages) {
|
|
654
|
+
if (!this.linkedPackageDirs.has(packageName) && (local === null || local === void 0 ? void 0 : local.path)) {
|
|
655
|
+
let dir = local.path;
|
|
656
|
+
try {
|
|
657
|
+
dir = fsNative.realpathSync(dir);
|
|
658
|
+
}
|
|
659
|
+
catch (_c) { }
|
|
660
|
+
this.linkedPackageDirs.set(packageName, dir);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
637
663
|
for (const { packageName } of ordered) {
|
|
638
664
|
const isLocal = remaining.delete(packageName);
|
|
639
665
|
await this.ensurePackageBackendProviders(packageName);
|
|
@@ -641,7 +667,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
641
667
|
await this.indexLincdPackage(packageName);
|
|
642
668
|
}
|
|
643
669
|
else if (this.genericProviders.get(packageName) ||
|
|
644
|
-
((
|
|
670
|
+
((_b = this.shapeProviders.get(packageName)) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
645
671
|
installed.push(packageName);
|
|
646
672
|
}
|
|
647
673
|
}
|
|
@@ -653,6 +679,44 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
653
679
|
console.log(paint('gray', `[linked] indexed backend providers of ${ordered.length} linked package(s) in ${Date.now() - started}ms; installed ones with providers: ${installed.join(', ')}`));
|
|
654
680
|
}
|
|
655
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Two installed copies of one linked package mean two copies of its module
|
|
684
|
+
* state, and only one of them can own the backend. The one the app resolves
|
|
685
|
+
* is loaded (see discoverLinkedDependencies); the other is never loaded.
|
|
686
|
+
*/
|
|
687
|
+
warnIfInstalledMoreThanOnce(dep) {
|
|
688
|
+
var _a, _b;
|
|
689
|
+
const copies = (_a = dep.copies) !== null && _a !== void 0 ? _a : [];
|
|
690
|
+
(_b = this.warnedDuplicateInstalls) !== null && _b !== void 0 ? _b : (this.warnedDuplicateInstalls = new Set());
|
|
691
|
+
if (copies.length < 2 || this.warnedDuplicateInstalls.has(dep.packageName)) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
this.warnedDuplicateInstalls.add(dep.packageName);
|
|
695
|
+
const list = copies
|
|
696
|
+
.map((c) => { var _a; return `${(_a = c.version) !== null && _a !== void 0 ? _a : '?'} at ${c.path}`; })
|
|
697
|
+
.join(', ');
|
|
698
|
+
console.warn(paint('yellow', `[linked] ${dep.packageName} is installed ${copies.length} times (${list}); loaded ${dep.path}. Run npm dedupe.`));
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* The directory a package's backend is resolved from: the copy discovery
|
|
702
|
+
* chose, or — for a package outside the linked tree, reached only by a lazy
|
|
703
|
+
* /call — the copy the app itself resolves.
|
|
704
|
+
*/
|
|
705
|
+
packageDirFor(pkg) {
|
|
706
|
+
var _a;
|
|
707
|
+
const known = (_a = this.linkedPackageDirs) === null || _a === void 0 ? void 0 : _a.get(pkg);
|
|
708
|
+
if (known)
|
|
709
|
+
return known;
|
|
710
|
+
const installed = readInstalledPackage(pkg, process.cwd());
|
|
711
|
+
if (!installed)
|
|
712
|
+
return null;
|
|
713
|
+
try {
|
|
714
|
+
return fsNative.realpathSync(installed.root);
|
|
715
|
+
}
|
|
716
|
+
catch (_b) {
|
|
717
|
+
return installed.root;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
656
720
|
/**
|
|
657
721
|
* Index a package's backend providers once. Shared by boot and the lazy
|
|
658
722
|
* path in callBackendMethod / callShapeMethod. `onSourceChange` bypasses it
|
|
@@ -675,8 +739,8 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
675
739
|
}
|
|
676
740
|
}
|
|
677
741
|
/**
|
|
678
|
-
* Node's `import()
|
|
679
|
-
*
|
|
742
|
+
* Node's `import()`. Called with the absolute file URL of a resolved backend
|
|
743
|
+
* entry (see resolveBackendEntry), never a bare name.
|
|
680
744
|
*/
|
|
681
745
|
importModule(specifier) {
|
|
682
746
|
return import(/* @vite-ignore */ specifier);
|
|
@@ -1008,19 +1072,11 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1008
1072
|
}
|
|
1009
1073
|
}
|
|
1010
1074
|
}
|
|
1011
|
-
async indexPackageBackendProviders(pkg, warnIfNotFound = false
|
|
1012
|
-
var _a, _b;
|
|
1013
|
-
if (!backendIndexFilePath) {
|
|
1014
|
-
backendIndexFilePath = `${pkg}/backend`;
|
|
1015
|
-
}
|
|
1075
|
+
async indexPackageBackendProviders(pkg, warnIfNotFound = false) {
|
|
1076
|
+
var _a, _b, _c, _d;
|
|
1016
1077
|
let backendProviderExports;
|
|
1017
|
-
let genericBackendProvider;
|
|
1078
|
+
let genericBackendProvider = null;
|
|
1018
1079
|
let shapeProviders = [];
|
|
1019
|
-
// Plan-010 phase 4/5: when Vite SSR is active, route module loading
|
|
1020
|
-
// through vite.ssrLoadModule. This handles the case where the user app
|
|
1021
|
-
// is the consuming workspace itself (self-reference like
|
|
1022
|
-
// @semantu/create-now/backend), which Node's ESM resolver can't resolve
|
|
1023
|
-
// from inside an installed package like @_linked/server.
|
|
1024
1080
|
const vite = (_a = this.config.server) === null || _a === void 0 ? void 0 : _a.vite;
|
|
1025
1081
|
// In dev, load a package's backend with the loader that owns the package
|
|
1026
1082
|
// (see isBundledBySsr): Vite for the app itself and for what the SSR
|
|
@@ -1032,126 +1088,114 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1032
1088
|
typeof vite.ssrLoadModule === 'function' &&
|
|
1033
1089
|
(pkg === ((_b = this.package) === null || _b === void 0 ? void 0 : _b.name) ||
|
|
1034
1090
|
isBundledBySsr(pkg, ssrNoExternalOf(vite)));
|
|
1035
|
-
|
|
1036
|
-
|
|
1091
|
+
// Decide whether there IS a backend before importing anything. A package
|
|
1092
|
+
// without one is the normal case (most linked packages have none) and is
|
|
1093
|
+
// quiet; once a backend file is known to exist, any failure to load it is
|
|
1094
|
+
// a real error. This used to be decided after the fact, by matching the
|
|
1095
|
+
// loader's error text — which Node and Vite word differently, so a nested
|
|
1096
|
+
// package's "Cannot find package" was reported as a broken backend.
|
|
1097
|
+
let entry = null;
|
|
1098
|
+
let load = null;
|
|
1099
|
+
if (pkg === ((_c = this.package) === null || _c === void 0 ? void 0 : _c.name)) {
|
|
1100
|
+
// The app's own backend cannot be imported by name: a self-reference
|
|
1101
|
+
// resolves only from inside the package that declares it, and this code
|
|
1102
|
+
// lives in node_modules/@_linked/server. Load it by path.
|
|
1103
|
+
const cwd = process.cwd();
|
|
1037
1104
|
if (viteOwnsPackage) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1105
|
+
const source = path.join(cwd, 'src', 'backend.ts');
|
|
1106
|
+
if (fsNative.existsSync(source)) {
|
|
1107
|
+
entry = source;
|
|
1108
|
+
load = () => vite.ssrLoadModule('/src/backend.ts');
|
|
1042
1109
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
entry = (_d = [
|
|
1113
|
+
path.join(cwd, 'lib', 'backend.js'),
|
|
1114
|
+
path.join(cwd, 'src', 'backend.ts'),
|
|
1115
|
+
].find((f) => fsNative.existsSync(f))) !== null && _d !== void 0 ? _d : null;
|
|
1116
|
+
if (entry) {
|
|
1117
|
+
const url = pathToFileURL(entry).href;
|
|
1118
|
+
load = () => this.importModule(url);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
const dir = this.packageDirFor(pkg);
|
|
1124
|
+
let json = null;
|
|
1125
|
+
if (dir) {
|
|
1055
1126
|
try {
|
|
1056
|
-
|
|
1057
|
-
if (!resolved) {
|
|
1058
|
-
// Synthesise the same error shape the catch expects so the
|
|
1059
|
-
// "no backend export, that's fine" branch fires.
|
|
1060
|
-
const err = new Error(`Failed to load url ${specifier} (resolved id: ${specifier}). Does the file exist?`);
|
|
1061
|
-
throw err;
|
|
1062
|
-
}
|
|
1127
|
+
json = JSON.parse(fsNative.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
|
|
1063
1128
|
}
|
|
1064
|
-
catch (
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1129
|
+
catch (_e) { }
|
|
1130
|
+
}
|
|
1131
|
+
if (dir && json) {
|
|
1132
|
+
if (viteOwnsPackage) {
|
|
1133
|
+
// Vite resolves a bundled package with the `development` condition
|
|
1134
|
+
// (a workspace's `./backend` may point at src only there). It is
|
|
1135
|
+
// still loaded by its bare name, so it is the same module id the
|
|
1136
|
+
// rest of the SSR graph imports.
|
|
1137
|
+
entry = resolveBackendEntry(dir, json, [
|
|
1138
|
+
'development',
|
|
1139
|
+
...NODE_IMPORT_CONDITIONS,
|
|
1140
|
+
]);
|
|
1141
|
+
if (entry)
|
|
1142
|
+
load = () => vite.ssrLoadModule(`${pkg}/backend`);
|
|
1143
|
+
}
|
|
1144
|
+
else {
|
|
1145
|
+
// Node caches ESM by resolved real file URL, and a bare import of
|
|
1146
|
+
// `<pkg>/backend` from the app resolves to this same real path — so
|
|
1147
|
+
// loading it by URL yields the instance the app's own imports get.
|
|
1148
|
+
entry = resolveBackendEntry(dir, json, NODE_IMPORT_CONDITIONS);
|
|
1149
|
+
if (entry) {
|
|
1150
|
+
const url = pathToFileURL(entry).href;
|
|
1151
|
+
load = () => this.importModule(url);
|
|
1073
1152
|
}
|
|
1074
1153
|
}
|
|
1075
|
-
return await vite.ssrLoadModule(specifier);
|
|
1076
1154
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
// silently fails to register. The Vite branch above already works around
|
|
1085
|
-
// this; the compiled runtime needs the same treatment, by path.
|
|
1086
|
-
if (specifier === `${this.package.name}/backend`) {
|
|
1087
|
-
const compiled = path.join(process.cwd(), 'lib', 'backend.js');
|
|
1088
|
-
const source = path.join(process.cwd(), 'src', 'backend.ts');
|
|
1089
|
-
const target = fsNative.existsSync(compiled) ? compiled : source;
|
|
1090
|
-
return await import(/* @vite-ignore */ pathToFileURL(target).href);
|
|
1155
|
+
}
|
|
1156
|
+
if (!load) {
|
|
1157
|
+
if (warnIfNotFound) {
|
|
1158
|
+
console.warn(paint('magenta', `Could not find backend file of package ${pkg}.
|
|
1159
|
+
Check:\n
|
|
1160
|
+
- Make sure backend.ts exists and is included in tsconfig.json\n
|
|
1161
|
+
- Make sure the package name in src/package.ts matches the package name in package.json`));
|
|
1091
1162
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
// Loud, naming the package and the file, and contained: one package's
|
|
1166
|
+
// broken backend does not stop the others from loading.
|
|
1167
|
+
let loaded = false;
|
|
1168
|
+
await runProviderHook(pkg, `backend ${entry}`, async () => {
|
|
1169
|
+
backendProviderExports = await load();
|
|
1170
|
+
loaded = true;
|
|
1171
|
+
});
|
|
1172
|
+
if (loaded) {
|
|
1173
|
+
for (const key of Object.keys(backendProviderExports)) {
|
|
1174
|
+
const providerClass = backendProviderExports[key];
|
|
1175
|
+
let provider;
|
|
1176
|
+
//always send an instance of the express server
|
|
1177
|
+
//TODO: do not create an instance, just save the class and instantiate it when needed
|
|
1178
|
+
await runProviderHook(pkg, `${key} constructor`, () => {
|
|
1179
|
+
provider = new providerClass(this.server, this);
|
|
1180
|
+
});
|
|
1181
|
+
if (!provider)
|
|
1182
|
+
continue;
|
|
1183
|
+
if (isShapeProvider(provider)) {
|
|
1184
|
+
shapeProviders.push(provider);
|
|
1185
|
+
if (!Object.getOwnPropertyNames(provider).includes('shape')) {
|
|
1186
|
+
console.warn(paint('red', `${Object.getPrototypeOf(provider).constructor.name} in package ${pkg}
|
|
1107
1187
|
is not properly linked to a shape. Use public shape = SomeShape.`));
|
|
1188
|
+
}
|
|
1108
1189
|
}
|
|
1109
|
-
|
|
1110
|
-
else {
|
|
1111
|
-
if (genericBackendProvider) {
|
|
1190
|
+
else if (genericBackendProvider) {
|
|
1112
1191
|
console.warn(`Package ${pkg} exports two generic backend providers. Only one will work`);
|
|
1113
1192
|
}
|
|
1114
1193
|
else {
|
|
1115
1194
|
genericBackendProvider = provider;
|
|
1116
1195
|
}
|
|
1117
1196
|
}
|
|
1118
|
-
});
|
|
1119
|
-
})
|
|
1120
|
-
.catch((e) => {
|
|
1121
|
-
var _a;
|
|
1122
|
-
// Recognize "no /backend export" failures across two loader
|
|
1123
|
-
// shapes:
|
|
1124
|
-
// Node's import() → ERR_MODULE_NOT_FOUND + "Cannot find module 'X/backend'"
|
|
1125
|
-
// Vite's ssrLoadModule() → "Failed to load url X/backend"
|
|
1126
|
-
// package `exports` without a ./backend entry (Node + Vite)
|
|
1127
|
-
// → 'Missing "./backend" specifier in "X" package'
|
|
1128
|
-
// In either case, missing /backend on a package that doesn't
|
|
1129
|
-
// ship a backend is expected; loud-error only on REAL load
|
|
1130
|
-
// failures (syntax error inside an existing backend.ts, etc).
|
|
1131
|
-
const nodeMatch = e.message.match(/module \'([^\']+)'/);
|
|
1132
|
-
const viteMatch = e.message.match(/Failed to load url ([^\s]+)/);
|
|
1133
|
-
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];
|
|
1134
|
-
const notExported = /Missing "\.\/backend" specifier in "[^"]+" package/.test(e.message);
|
|
1135
|
-
let providerNotFound = notExported ||
|
|
1136
|
-
(!!matchedSpec &&
|
|
1137
|
-
matchedSpec.includes('/backend') &&
|
|
1138
|
-
((e.code === 'ERR_MODULE_NOT_FOUND' &&
|
|
1139
|
-
e.message.indexOf(`Cannot find module`) !== -1) ||
|
|
1140
|
-
e.message.indexOf('Failed to load url') !== -1));
|
|
1141
|
-
if (providerNotFound) {
|
|
1142
|
-
// console.warn('Error loading ' + providerPath + ': ' + e.stack);
|
|
1143
|
-
if (warnIfNotFound) {
|
|
1144
|
-
console.warn(paint('magenta', `Could not find backend file of package ${pkg}.
|
|
1145
|
-
Check:\n
|
|
1146
|
-
- Make sure backend.ts exists and is included in tsconfig.json\n
|
|
1147
|
-
- Make sure the package name in src/package.ts matches the package name in package.json`));
|
|
1148
|
-
}
|
|
1149
1197
|
}
|
|
1150
|
-
|
|
1151
|
-
console.warn(paint('red', `Could not load backend file of module '${pkg}' from ${process.cwd()}:\n`), e.stack);
|
|
1152
|
-
}
|
|
1153
|
-
genericBackendProvider = null;
|
|
1154
|
-
});
|
|
1198
|
+
}
|
|
1155
1199
|
this.genericProviders.set(pkg, genericBackendProvider);
|
|
1156
1200
|
this.shapeProviders.set(pkg, shapeProviders);
|
|
1157
1201
|
return { backendProviderExports, shapeProviders };
|