@jskit-ai/kernel 0.1.147 → 0.1.149
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/client/moduleBootstrap.js +54 -54
- package/client/moduleBootstrap.test.js +12 -12
- package/client/{descriptorSections.js → packageMetadataSections.js} +15 -15
- package/client/vite/clientBootstrapPlugin.js +67 -100
- package/client/vite/clientBootstrapPlugin.test.js +177 -238
- package/internal/node/installedPackages.js +283 -0
- package/package.json +1 -1
- package/server/platform/providerRuntime/{descriptorCatalog.js → packageCatalog.js} +32 -47
- package/server/platform/providerRuntime/providerLoader.js +18 -18
- package/server/platform/providerRuntime.js +15 -22
- package/server/platform/providerRuntime.test.js +56 -171
- package/server/platform/surfaceRuntime.test.js +1 -1
- package/server/support/index.js +6 -0
- package/server/support/shellOutlets.js +15 -51
- package/server/support/shellOutlets.test.js +23 -26
- package/shared/support/generatedUiContract.js +1 -1
- package/shared/support/generatedUiContract.test.js +11 -1
- package/shared/validators/schemaDefinitions.test.js +39 -0
- package/internal/node/installedPackageDescriptor.js +0 -125
- package/server/platform/providerRuntime/lockfile.js +0 -27
- package/shared/support/packageDescriptor.test.js +0 -147
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { readFile, realpath } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { normalizeObject } from "../../shared/support/normalize.js";
|
|
4
|
+
import { sortStrings } from "../../shared/support/sorting.js";
|
|
5
|
+
import { fileExists } from "./fileSystem.js";
|
|
6
|
+
|
|
7
|
+
const ROOT_DEPENDENCY_SECTIONS = Object.freeze([
|
|
8
|
+
"dependencies",
|
|
9
|
+
"optionalDependencies",
|
|
10
|
+
"peerDependencies",
|
|
11
|
+
"devDependencies"
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
async function readJsonFile(filePath, fallback = {}) {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
17
|
+
} catch {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function collectRootDependencySpecifiers(packageJson = {}) {
|
|
23
|
+
const specifiers = new Map();
|
|
24
|
+
for (const sectionName of ROOT_DEPENDENCY_SECTIONS) {
|
|
25
|
+
for (const [packageId, specifier] of Object.entries(normalizeObject(packageJson?.[sectionName]))) {
|
|
26
|
+
const normalizedPackageId = String(packageId || "").trim();
|
|
27
|
+
if (!normalizedPackageId || specifiers.has(normalizedPackageId)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
specifiers.set(normalizedPackageId, String(specifier || "").trim());
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return specifiers;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function collectPackageDependencyIds(packageJson = {}) {
|
|
37
|
+
const dependencyIds = new Set();
|
|
38
|
+
for (const sectionName of ["dependencies", "optionalDependencies", "peerDependencies"]) {
|
|
39
|
+
for (const packageId of Object.keys(normalizeObject(packageJson?.[sectionName]))) {
|
|
40
|
+
const normalizedPackageId = String(packageId || "").trim();
|
|
41
|
+
if (normalizedPackageId) {
|
|
42
|
+
dependencyIds.add(normalizedPackageId);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return sortStrings([...dependencyIds]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function createPackageMetadata(packageJson = {}) {
|
|
50
|
+
const jskit = normalizeObject(packageJson.jskit);
|
|
51
|
+
if (Object.keys(jskit).length === 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const packageId = String(packageJson.name || "").trim();
|
|
56
|
+
const version = String(packageJson.version || "").trim();
|
|
57
|
+
if (!packageId || !version) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return Object.freeze({
|
|
62
|
+
...jskit,
|
|
63
|
+
packageId,
|
|
64
|
+
version,
|
|
65
|
+
...(String(packageJson.description || "").trim()
|
|
66
|
+
? { description: String(packageJson.description).trim() }
|
|
67
|
+
: {})
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveFileDependencyRoot(appRoot, specifier = "") {
|
|
72
|
+
const normalizedSpecifier = String(specifier || "").trim();
|
|
73
|
+
if (!normalizedSpecifier.startsWith("file:")) {
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
const relativePath = normalizedSpecifier.slice("file:".length).trim();
|
|
77
|
+
return relativePath ? path.resolve(appRoot, relativePath) : "";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function resolveInstalledPackageRoot({ appRoot, packageId, parentPackageRoot = "" }) {
|
|
81
|
+
const candidates = [];
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
const appendCandidate = (candidateRoot) => {
|
|
84
|
+
const normalized = path.resolve(candidateRoot);
|
|
85
|
+
if (!seen.has(normalized)) {
|
|
86
|
+
seen.add(normalized);
|
|
87
|
+
candidates.push(normalized);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (parentPackageRoot) {
|
|
92
|
+
let currentRoot = path.resolve(parentPackageRoot);
|
|
93
|
+
while (true) {
|
|
94
|
+
appendCandidate(path.join(currentRoot, "node_modules", ...packageId.split("/")));
|
|
95
|
+
const parentRoot = path.dirname(currentRoot);
|
|
96
|
+
if (parentRoot === currentRoot) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
currentRoot = parentRoot;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
appendCandidate(path.resolve(appRoot, "node_modules", ...packageId.split("/")));
|
|
103
|
+
|
|
104
|
+
for (const candidateRoot of candidates) {
|
|
105
|
+
if (await fileExists(path.join(candidateRoot, "package.json"))) {
|
|
106
|
+
return candidateRoot;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return path.resolve(appRoot, "node_modules", ...packageId.split("/"));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function resolvePackageRoots({
|
|
113
|
+
appRoot,
|
|
114
|
+
packageId,
|
|
115
|
+
directSpecifier = "",
|
|
116
|
+
parentPackageRoot = ""
|
|
117
|
+
}) {
|
|
118
|
+
const installedPackageRoot = await resolveInstalledPackageRoot({
|
|
119
|
+
appRoot,
|
|
120
|
+
packageId,
|
|
121
|
+
parentPackageRoot
|
|
122
|
+
});
|
|
123
|
+
const fileDependencyRoot = resolveFileDependencyRoot(appRoot, directSpecifier);
|
|
124
|
+
let sourcePackageRoot = fileDependencyRoot && (await fileExists(fileDependencyRoot))
|
|
125
|
+
? fileDependencyRoot
|
|
126
|
+
: "";
|
|
127
|
+
|
|
128
|
+
if (!sourcePackageRoot && (await fileExists(installedPackageRoot))) {
|
|
129
|
+
try {
|
|
130
|
+
const resolvedRoot = await realpath(installedPackageRoot);
|
|
131
|
+
const relativeToNodeModules = path.relative(path.resolve(appRoot, "node_modules"), resolvedRoot);
|
|
132
|
+
if (
|
|
133
|
+
relativeToNodeModules === ".." ||
|
|
134
|
+
relativeToNodeModules.startsWith(`..${path.sep}`) ||
|
|
135
|
+
path.isAbsolute(relativeToNodeModules)
|
|
136
|
+
) {
|
|
137
|
+
sourcePackageRoot = resolvedRoot;
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
sourcePackageRoot = "";
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
installedPackageRoot,
|
|
146
|
+
sourcePackageRoot,
|
|
147
|
+
packageRoot: sourcePackageRoot || installedPackageRoot,
|
|
148
|
+
sourceType: sourcePackageRoot ? "local-package" : "npm-package"
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function discoverInstalledPackages({ appRoot } = {}) {
|
|
153
|
+
const normalizedAppRoot = String(appRoot || "").trim();
|
|
154
|
+
if (!normalizedAppRoot) {
|
|
155
|
+
throw new TypeError("discoverInstalledPackages requires appRoot.");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const rootPackageJson = await readJsonFile(path.resolve(normalizedAppRoot, "package.json"), {});
|
|
159
|
+
const directSpecifiers = collectRootDependencySpecifiers(rootPackageJson);
|
|
160
|
+
const directPackageIds = new Set(directSpecifiers.keys());
|
|
161
|
+
const runtimeRootPackageIds = new Set(
|
|
162
|
+
["dependencies", "optionalDependencies", "peerDependencies"]
|
|
163
|
+
.flatMap((sectionName) => Object.keys(normalizeObject(rootPackageJson?.[sectionName])))
|
|
164
|
+
);
|
|
165
|
+
const visited = new Set();
|
|
166
|
+
const queue = [];
|
|
167
|
+
const queued = new Map();
|
|
168
|
+
const packages = [];
|
|
169
|
+
|
|
170
|
+
const sortQueue = () => {
|
|
171
|
+
queue.sort((left, right) => {
|
|
172
|
+
if (left.traverseDependencies !== right.traverseDependencies) {
|
|
173
|
+
return left.traverseDependencies ? -1 : 1;
|
|
174
|
+
}
|
|
175
|
+
return left.packageId.localeCompare(right.packageId);
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
const enqueue = ({ packageId, parentPackageRoot = "", traverseDependencies = false }) => {
|
|
179
|
+
const normalizedPackageId = String(packageId || "").trim();
|
|
180
|
+
if (!normalizedPackageId || visited.has(normalizedPackageId)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const existing = queued.get(normalizedPackageId);
|
|
184
|
+
if (existing) {
|
|
185
|
+
if (traverseDependencies && !existing.traverseDependencies) {
|
|
186
|
+
existing.traverseDependencies = true;
|
|
187
|
+
existing.parentPackageRoot = parentPackageRoot || existing.parentPackageRoot;
|
|
188
|
+
sortQueue();
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const entry = {
|
|
193
|
+
packageId: normalizedPackageId,
|
|
194
|
+
parentPackageRoot,
|
|
195
|
+
traverseDependencies: Boolean(traverseDependencies)
|
|
196
|
+
};
|
|
197
|
+
queue.push(entry);
|
|
198
|
+
queued.set(normalizedPackageId, entry);
|
|
199
|
+
sortQueue();
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
for (const packageId of sortStrings([...directPackageIds])) {
|
|
203
|
+
enqueue({
|
|
204
|
+
packageId,
|
|
205
|
+
traverseDependencies: runtimeRootPackageIds.has(packageId)
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
while (queue.length > 0) {
|
|
210
|
+
const { packageId, parentPackageRoot, traverseDependencies } = queue.shift();
|
|
211
|
+
queued.delete(packageId);
|
|
212
|
+
if (!packageId || visited.has(packageId)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
visited.add(packageId);
|
|
216
|
+
|
|
217
|
+
const directSpecifier = directSpecifiers.get(packageId) || "";
|
|
218
|
+
const roots = await resolvePackageRoots({
|
|
219
|
+
appRoot: normalizedAppRoot,
|
|
220
|
+
packageId,
|
|
221
|
+
directSpecifier,
|
|
222
|
+
parentPackageRoot
|
|
223
|
+
});
|
|
224
|
+
const packageJsonPath = path.join(roots.packageRoot, "package.json");
|
|
225
|
+
if (!(await fileExists(packageJsonPath))) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const packageJson = await readJsonFile(packageJsonPath, {});
|
|
230
|
+
const manifestPackageId = String(packageJson.name || "").trim();
|
|
231
|
+
if (manifestPackageId && manifestPackageId !== packageId) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
`Installed package manifest mismatch: expected ${packageId}, received ${manifestPackageId}.`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const dependencyIds = collectPackageDependencyIds(packageJson);
|
|
238
|
+
if (traverseDependencies) {
|
|
239
|
+
for (const dependencyId of dependencyIds) {
|
|
240
|
+
const normalizedDependencyId = String(dependencyId || "").trim();
|
|
241
|
+
enqueue({
|
|
242
|
+
packageId: normalizedDependencyId,
|
|
243
|
+
parentPackageRoot: roots.packageRoot,
|
|
244
|
+
traverseDependencies: true
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const packageMetadata = createPackageMetadata(packageJson);
|
|
250
|
+
if (!packageMetadata) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
packages.push(
|
|
255
|
+
Object.freeze({
|
|
256
|
+
packageId,
|
|
257
|
+
version: String(packageJson.version || "").trim(),
|
|
258
|
+
packageMetadata,
|
|
259
|
+
manifestPath: packageJsonPath,
|
|
260
|
+
packageJson: Object.freeze({ ...normalizeObject(packageJson) }),
|
|
261
|
+
packageRoot: roots.packageRoot,
|
|
262
|
+
installedPackageRoot: roots.installedPackageRoot,
|
|
263
|
+
sourcePackageRoot: roots.sourcePackageRoot || roots.packageRoot,
|
|
264
|
+
sourceType: roots.sourceType,
|
|
265
|
+
direct: directPackageIds.has(packageId),
|
|
266
|
+
directSpecifier,
|
|
267
|
+
dependencyIds: Object.freeze(dependencyIds)
|
|
268
|
+
})
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return Object.freeze(
|
|
273
|
+
packages.sort((left, right) => left.packageId.localeCompare(right.packageId))
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export {
|
|
278
|
+
ROOT_DEPENDENCY_SECTIONS,
|
|
279
|
+
collectPackageDependencyIds,
|
|
280
|
+
collectRootDependencySpecifiers,
|
|
281
|
+
createPackageMetadata,
|
|
282
|
+
discoverInstalledPackages
|
|
283
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
import { sortStrings } from "../../../shared/support/sorting.js";
|
|
3
|
-
import {
|
|
2
|
+
import { discoverInstalledPackages } from "../../../internal/node/installedPackages.js";
|
|
4
3
|
|
|
5
4
|
const EXCLUSIVE_CAPABILITIES = Object.freeze(["auth.provider"]);
|
|
6
5
|
|
|
@@ -18,13 +17,13 @@ function normalizeUiRoutePath(pathValue) {
|
|
|
18
17
|
return normalizedPath.replace(/\/+$/, "") || "/";
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
function collectGlobalUiPaths(
|
|
20
|
+
function collectGlobalUiPaths(packageEntries) {
|
|
22
21
|
const globalUiPaths = [];
|
|
23
|
-
const entries = Array.isArray(
|
|
22
|
+
const entries = Array.isArray(packageEntries) ? packageEntries : [];
|
|
24
23
|
|
|
25
|
-
for (const
|
|
26
|
-
const uiRoutes = Array.isArray(
|
|
27
|
-
?
|
|
24
|
+
for (const packageEntry of entries) {
|
|
25
|
+
const uiRoutes = Array.isArray(packageEntry?.packageMetadata?.metadata?.ui?.routes)
|
|
26
|
+
? packageEntry.packageMetadata.metadata.ui.routes
|
|
28
27
|
: [];
|
|
29
28
|
|
|
30
29
|
for (const routeEntry of uiRoutes) {
|
|
@@ -51,34 +50,21 @@ function collectGlobalUiPaths(descriptorEntries) {
|
|
|
51
50
|
return Object.freeze(sortStrings(globalUiPaths));
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
async function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
installedPackageState,
|
|
66
|
-
packageId,
|
|
67
|
-
required: true
|
|
68
|
-
});
|
|
69
|
-
descriptorEntries.push({
|
|
70
|
-
packageId,
|
|
71
|
-
descriptor: descriptorRecord.descriptor,
|
|
72
|
-
descriptorPath: descriptorRecord.descriptorPath,
|
|
73
|
-
packageRoot: path.dirname(descriptorRecord.descriptorPath)
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return descriptorEntries;
|
|
53
|
+
async function resolveInstalledJskitPackages({ appRoot }) {
|
|
54
|
+
return (await discoverInstalledPackages({ appRoot })).map((entry) => ({
|
|
55
|
+
packageId: entry.packageId,
|
|
56
|
+
packageMetadata: entry.packageMetadata,
|
|
57
|
+
manifestPath: entry.manifestPath,
|
|
58
|
+
packageRoot: entry.packageRoot,
|
|
59
|
+
dependencyIds: entry.dependencyIds,
|
|
60
|
+
sourceType: entry.sourceType,
|
|
61
|
+
direct: entry.direct,
|
|
62
|
+
version: entry.version
|
|
63
|
+
}));
|
|
78
64
|
}
|
|
79
65
|
|
|
80
|
-
function
|
|
81
|
-
const byPackageId = new Map(
|
|
66
|
+
function resolvePackageLoadOrder(packageEntries) {
|
|
67
|
+
const byPackageId = new Map(packageEntries.map((entry) => [entry.packageId, entry]));
|
|
82
68
|
const visiting = new Set();
|
|
83
69
|
const visited = new Set();
|
|
84
70
|
const ordered = [];
|
|
@@ -97,8 +83,7 @@ function resolveDescriptorLoadOrder(descriptorEntries) {
|
|
|
97
83
|
}
|
|
98
84
|
|
|
99
85
|
visiting.add(packageId);
|
|
100
|
-
const
|
|
101
|
-
for (const dependencyPackageId of dependsOn) {
|
|
86
|
+
for (const dependencyPackageId of Array.isArray(entry.dependencyIds) ? entry.dependencyIds : []) {
|
|
102
87
|
if (byPackageId.has(dependencyPackageId)) {
|
|
103
88
|
visit(dependencyPackageId, [...lineage, packageId]);
|
|
104
89
|
}
|
|
@@ -128,13 +113,13 @@ function registerCapabilityProvider(providersByCapability, capabilityId, provide
|
|
|
128
113
|
providersByCapability.get(normalizedCapabilityId).add(normalizedProviderPackageId);
|
|
129
114
|
}
|
|
130
115
|
|
|
131
|
-
function
|
|
116
|
+
function validatePackageCapabilities(packageEntries, { builtinProvidersByCapability = {} } = {}) {
|
|
132
117
|
const providersByCapability = new Map();
|
|
133
|
-
for (const
|
|
134
|
-
for (const capabilityId of Array.isArray(
|
|
135
|
-
?
|
|
118
|
+
for (const packageEntry of packageEntries) {
|
|
119
|
+
for (const capabilityId of Array.isArray(packageEntry.packageMetadata?.capabilities?.provides)
|
|
120
|
+
? packageEntry.packageMetadata.capabilities.provides
|
|
136
121
|
: []) {
|
|
137
|
-
registerCapabilityProvider(providersByCapability, capabilityId,
|
|
122
|
+
registerCapabilityProvider(providersByCapability, capabilityId, packageEntry.packageId);
|
|
138
123
|
}
|
|
139
124
|
}
|
|
140
125
|
|
|
@@ -146,9 +131,9 @@ function validateDescriptorCapabilities(descriptorEntries, { builtinProvidersByC
|
|
|
146
131
|
}
|
|
147
132
|
}
|
|
148
133
|
|
|
149
|
-
for (const
|
|
150
|
-
for (const capabilityId of Array.isArray(
|
|
151
|
-
?
|
|
134
|
+
for (const packageEntry of packageEntries) {
|
|
135
|
+
for (const capabilityId of Array.isArray(packageEntry.packageMetadata?.capabilities?.requires)
|
|
136
|
+
? packageEntry.packageMetadata.capabilities.requires
|
|
152
137
|
: []) {
|
|
153
138
|
const normalizedCapabilityId = String(capabilityId || "").trim();
|
|
154
139
|
if (!normalizedCapabilityId) {
|
|
@@ -157,7 +142,7 @@ function validateDescriptorCapabilities(descriptorEntries, { builtinProvidersByC
|
|
|
157
142
|
const providers = providersByCapability.get(normalizedCapabilityId);
|
|
158
143
|
if (!providers || providers.size < 1) {
|
|
159
144
|
throw new Error(
|
|
160
|
-
`Package ${
|
|
145
|
+
`Package ${packageEntry.packageId} requires capability ${normalizedCapabilityId}, but no installed package provides it.`
|
|
161
146
|
);
|
|
162
147
|
}
|
|
163
148
|
}
|
|
@@ -175,7 +160,7 @@ function validateDescriptorCapabilities(descriptorEntries, { builtinProvidersByC
|
|
|
175
160
|
|
|
176
161
|
export {
|
|
177
162
|
collectGlobalUiPaths,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
163
|
+
resolveInstalledJskitPackages,
|
|
164
|
+
resolvePackageLoadOrder,
|
|
165
|
+
validatePackageCapabilities
|
|
181
166
|
};
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
toAbsoluteSortedUniquePaths
|
|
11
11
|
} from "./helpers.js";
|
|
12
12
|
|
|
13
|
-
function normalizeServerProviderDefinitions(
|
|
13
|
+
function normalizeServerProviderDefinitions(packageMetadata, packageId) {
|
|
14
14
|
const runtime =
|
|
15
|
-
|
|
16
|
-
?
|
|
15
|
+
packageMetadata && typeof packageMetadata.runtime === "object" && packageMetadata.runtime && !Array.isArray(packageMetadata.runtime)
|
|
16
|
+
? packageMetadata.runtime
|
|
17
17
|
: {};
|
|
18
18
|
const server =
|
|
19
19
|
runtime && typeof runtime.server === "object" && runtime.server && !Array.isArray(runtime.server)
|
|
@@ -162,11 +162,11 @@ function resolveProviderClassesFromModule(moduleNamespace, { packageId, provider
|
|
|
162
162
|
return discovered;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
async function collectDiscoveredProviderModulePaths({
|
|
166
|
-
const discoverRoot = path.resolve(
|
|
167
|
-
if (!isInsidePackageRoot(
|
|
165
|
+
async function collectDiscoveredProviderModulePaths({ packageEntry, providerDefinition }) {
|
|
166
|
+
const discoverRoot = path.resolve(packageEntry.packageRoot, providerDefinition.discoverDir);
|
|
167
|
+
if (!isInsidePackageRoot(packageEntry.packageRoot, discoverRoot)) {
|
|
168
168
|
throw new Error(
|
|
169
|
-
`Package ${
|
|
169
|
+
`Package ${packageEntry.packageId} runtime.server.providers[] discover.dir escapes package root: ${providerDefinition.discoverDir}`
|
|
170
170
|
);
|
|
171
171
|
}
|
|
172
172
|
if (!(await fileExists(discoverRoot))) {
|
|
@@ -176,7 +176,7 @@ async function collectDiscoveredProviderModulePaths({ descriptorEntry, providerD
|
|
|
176
176
|
const patternMatcher = createWildcardMatcher(providerDefinition.discoverPattern);
|
|
177
177
|
if (!(patternMatcher instanceof RegExp)) {
|
|
178
178
|
throw new Error(
|
|
179
|
-
`Package ${
|
|
179
|
+
`Package ${packageEntry.packageId} runtime.server.providers[] discover.pattern is invalid: ${providerDefinition.discoverPattern}`
|
|
180
180
|
);
|
|
181
181
|
}
|
|
182
182
|
const collectedPaths = [];
|
|
@@ -227,8 +227,8 @@ function registerProviderClass({ providerClass, sourceId, seenProviderIds, order
|
|
|
227
227
|
orderedProviderClasses.push(providerClass);
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
async function loadPackageProviders({
|
|
231
|
-
const providerDefinitions = normalizeServerProviderDefinitions(
|
|
230
|
+
async function loadPackageProviders({ packageEntry }) {
|
|
231
|
+
const providerDefinitions = normalizeServerProviderDefinitions(packageEntry.packageMetadata, packageEntry.packageId);
|
|
232
232
|
if (providerDefinitions.length < 1) {
|
|
233
233
|
return Object.freeze([]);
|
|
234
234
|
}
|
|
@@ -237,7 +237,7 @@ async function loadPackageProviders({ descriptorEntry }) {
|
|
|
237
237
|
for (const providerDefinition of providerDefinitions) {
|
|
238
238
|
if (providerDefinition.type === "discover") {
|
|
239
239
|
const discoveredProviderPaths = await collectDiscoveredProviderModulePaths({
|
|
240
|
-
|
|
240
|
+
packageEntry,
|
|
241
241
|
providerDefinition
|
|
242
242
|
});
|
|
243
243
|
|
|
@@ -245,8 +245,8 @@ async function loadPackageProviders({ descriptorEntry }) {
|
|
|
245
245
|
const providerModule = await import(pathToFileURL(discoveredProviderPath).href);
|
|
246
246
|
providerClasses.push(
|
|
247
247
|
...resolveProviderClassesFromModule(providerModule, {
|
|
248
|
-
packageId: `${
|
|
249
|
-
|
|
248
|
+
packageId: `${packageEntry.packageId} (${normalizeRelativePath(
|
|
249
|
+
packageEntry.packageRoot,
|
|
250
250
|
discoveredProviderPath
|
|
251
251
|
)})`,
|
|
252
252
|
providerExport: ""
|
|
@@ -256,22 +256,22 @@ async function loadPackageProviders({ descriptorEntry }) {
|
|
|
256
256
|
continue;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
const providerModulePath = path.resolve(
|
|
260
|
-
if (!isInsidePackageRoot(
|
|
259
|
+
const providerModulePath = path.resolve(packageEntry.packageRoot, providerDefinition.providerEntrypoint);
|
|
260
|
+
if (!isInsidePackageRoot(packageEntry.packageRoot, providerModulePath)) {
|
|
261
261
|
throw new Error(
|
|
262
|
-
`Package ${
|
|
262
|
+
`Package ${packageEntry.packageId} runtime.server.providers[] entrypoint escapes package root: ${providerDefinition.providerEntrypoint}`
|
|
263
263
|
);
|
|
264
264
|
}
|
|
265
265
|
if (!(await fileExists(providerModulePath))) {
|
|
266
266
|
throw new Error(
|
|
267
|
-
`Package ${
|
|
267
|
+
`Package ${packageEntry.packageId} runtime.server.providers[] entrypoint not found: ${providerDefinition.providerEntrypoint}`
|
|
268
268
|
);
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
const providerModule = await import(pathToFileURL(providerModulePath).href);
|
|
272
272
|
providerClasses.push(
|
|
273
273
|
...resolveProviderClassesFromModule(providerModule, {
|
|
274
|
-
packageId:
|
|
274
|
+
packageId: packageEntry.packageId,
|
|
275
275
|
providerExport: providerDefinition.providerExport
|
|
276
276
|
})
|
|
277
277
|
);
|
|
@@ -2,13 +2,12 @@ import { ActionRuntimeServiceProvider } from "../actions/ActionRuntimeServicePro
|
|
|
2
2
|
import { ServerRuntimeCoreServiceProvider } from "../runtime/ServerRuntimeCoreServiceProvider.js";
|
|
3
3
|
import { createApplication } from "../kernel/index.js";
|
|
4
4
|
import { createHttpRuntime } from "../http/lib/kernel.js";
|
|
5
|
-
import { readLockFromApp } from "./providerRuntime/lockfile.js";
|
|
6
5
|
import {
|
|
7
6
|
collectGlobalUiPaths,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "./providerRuntime/
|
|
7
|
+
resolveInstalledJskitPackages,
|
|
8
|
+
resolvePackageLoadOrder,
|
|
9
|
+
validatePackageCapabilities
|
|
10
|
+
} from "./providerRuntime/packageCatalog.js";
|
|
12
11
|
import { loadPackageProviders, registerProviderClass } from "./providerRuntime/providerLoader.js";
|
|
13
12
|
|
|
14
13
|
const KERNEL_BUILTIN_CAPABILITY_PROVIDERS = Object.freeze({
|
|
@@ -62,7 +61,6 @@ async function createProviderRuntimeApp({
|
|
|
62
61
|
|
|
63
62
|
async function createProviderRuntimeFromApp({
|
|
64
63
|
appRoot,
|
|
65
|
-
lockPath = ".jskit/lock.json",
|
|
66
64
|
profile = "",
|
|
67
65
|
env = {},
|
|
68
66
|
logger = console,
|
|
@@ -72,39 +70,34 @@ async function createProviderRuntimeFromApp({
|
|
|
72
70
|
throw new TypeError("createProviderRuntimeFromApp requires appRoot.");
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
const
|
|
76
|
-
appRoot
|
|
77
|
-
lockPath
|
|
73
|
+
const installedPackages = await resolveInstalledJskitPackages({
|
|
74
|
+
appRoot
|
|
78
75
|
});
|
|
79
|
-
|
|
80
|
-
appRoot,
|
|
81
|
-
lock
|
|
82
|
-
});
|
|
83
|
-
validateDescriptorCapabilities(descriptors, {
|
|
76
|
+
validatePackageCapabilities(installedPackages, {
|
|
84
77
|
builtinProvidersByCapability: KERNEL_BUILTIN_CAPABILITY_PROVIDERS
|
|
85
78
|
});
|
|
86
|
-
const
|
|
79
|
+
const orderedPackages = resolvePackageLoadOrder(installedPackages);
|
|
87
80
|
const catalog = Object.freeze({
|
|
88
|
-
packageOrder: Object.freeze(
|
|
89
|
-
globalUiPaths: collectGlobalUiPaths(
|
|
90
|
-
|
|
81
|
+
packageOrder: Object.freeze(orderedPackages.map((entry) => entry.packageId)),
|
|
82
|
+
globalUiPaths: collectGlobalUiPaths(orderedPackages),
|
|
83
|
+
packages: Object.freeze(orderedPackages)
|
|
91
84
|
});
|
|
92
85
|
|
|
93
86
|
const orderedProviderClasses = [];
|
|
94
87
|
const providerPackageIds = [];
|
|
95
88
|
const seenProviderIds = new Map();
|
|
96
89
|
|
|
97
|
-
for (const
|
|
98
|
-
const packageProviders = await loadPackageProviders({
|
|
90
|
+
for (const packageEntry of catalog.packages) {
|
|
91
|
+
const packageProviders = await loadPackageProviders({ packageEntry });
|
|
99
92
|
if (packageProviders.length < 1) {
|
|
100
93
|
continue;
|
|
101
94
|
}
|
|
102
|
-
providerPackageIds.push(
|
|
95
|
+
providerPackageIds.push(packageEntry.packageId);
|
|
103
96
|
|
|
104
97
|
for (const providerClass of packageProviders) {
|
|
105
98
|
registerProviderClass({
|
|
106
99
|
providerClass,
|
|
107
|
-
sourceId:
|
|
100
|
+
sourceId: packageEntry.packageId,
|
|
108
101
|
seenProviderIds,
|
|
109
102
|
orderedProviderClasses
|
|
110
103
|
});
|