@jskit-ai/kernel 0.1.148 → 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.test.js +1 -1
- package/internal/node/installedPackageDescriptor.js +0 -125
- package/server/platform/providerRuntime/lockfile.js +0 -27
- package/shared/support/packageDescriptor.test.js +0 -147
|
@@ -8,75 +8,56 @@ import { createProviderRuntimeFromApp } from "./providerRuntime.js";
|
|
|
8
8
|
|
|
9
9
|
async function createTestAppRoot(prefix) {
|
|
10
10
|
const appRoot = await mkdtemp(path.join(tmpdir(), prefix));
|
|
11
|
-
await mkdir(path.join(appRoot, ".jskit"), { recursive: true });
|
|
12
11
|
await writeFile(
|
|
13
|
-
path.join(appRoot, ".
|
|
14
|
-
`${JSON.stringify({
|
|
12
|
+
path.join(appRoot, "package.json"),
|
|
13
|
+
`${JSON.stringify({ name: "fixture-app", private: true, type: "module" }, null, 2)}\n`,
|
|
15
14
|
"utf8"
|
|
16
15
|
);
|
|
17
16
|
return appRoot;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
async function declareLocalPackage(appRoot, packageId, packagePath, jskit = {}) {
|
|
20
|
+
await writeFile(
|
|
21
|
+
path.join(appRoot, "package.json"),
|
|
22
|
+
`${JSON.stringify({
|
|
23
|
+
name: "fixture-app",
|
|
24
|
+
private: true,
|
|
25
|
+
type: "module",
|
|
26
|
+
dependencies: {
|
|
27
|
+
[packageId]: `file:${packagePath}`
|
|
28
|
+
}
|
|
29
|
+
}, null, 2)}\n`,
|
|
30
|
+
"utf8"
|
|
31
|
+
);
|
|
32
|
+
const packageRoot = path.join(appRoot, packagePath);
|
|
33
|
+
await mkdir(packageRoot, { recursive: true });
|
|
34
|
+
await writeFile(
|
|
35
|
+
path.join(packageRoot, "package.json"),
|
|
36
|
+
`${JSON.stringify({
|
|
37
|
+
name: packageId,
|
|
38
|
+
version: "0.1.0",
|
|
39
|
+
description: "Local example package",
|
|
40
|
+
type: "module",
|
|
41
|
+
jskit
|
|
42
|
+
}, null, 2)}\n`,
|
|
43
|
+
"utf8"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
test("createProviderRuntimeFromApp discovers package providers from package metadata", async () => {
|
|
21
48
|
const appRoot = await createTestAppRoot("kernel-provider-runtime-discover-");
|
|
22
49
|
try {
|
|
23
50
|
await mkdir(path.join(appRoot, "packages", "local-example", "src", "server", "providers"), { recursive: true });
|
|
24
|
-
await
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
type: "local-package",
|
|
35
|
-
packagePath: "packages/local-example"
|
|
36
|
-
},
|
|
37
|
-
managed: {
|
|
38
|
-
packageJson: {
|
|
39
|
-
dependencies: {},
|
|
40
|
-
devDependencies: {},
|
|
41
|
-
scripts: {}
|
|
42
|
-
},
|
|
43
|
-
text: {},
|
|
44
|
-
files: []
|
|
45
|
-
},
|
|
46
|
-
options: {},
|
|
47
|
-
installedAt: "2026-01-01T00:00:00.000Z"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
null,
|
|
52
|
-
2
|
|
53
|
-
)}\n`,
|
|
54
|
-
"utf8"
|
|
55
|
-
);
|
|
56
|
-
await writeFile(
|
|
57
|
-
path.join(appRoot, "packages", "local-example", "package.descriptor.mjs"),
|
|
58
|
-
[
|
|
59
|
-
"export default Object.freeze({",
|
|
60
|
-
" packageVersion: 1,",
|
|
61
|
-
" packageId: \"@local/example\",",
|
|
62
|
-
" version: \"0.1.0\",",
|
|
63
|
-
" description: \"Local example package\",",
|
|
64
|
-
" dependsOn: [],",
|
|
65
|
-
" capabilities: {",
|
|
66
|
-
" provides: [],",
|
|
67
|
-
" requires: []",
|
|
68
|
-
" },",
|
|
69
|
-
" runtime: {",
|
|
70
|
-
" server: {",
|
|
71
|
-
" providers: [",
|
|
72
|
-
" { discover: { dir: \"src/server/providers\", pattern: \"*Provider.js\" } }",
|
|
73
|
-
" ]",
|
|
74
|
-
" }",
|
|
75
|
-
" }",
|
|
76
|
-
"});"
|
|
77
|
-
].join("\n"),
|
|
78
|
-
"utf8"
|
|
79
|
-
);
|
|
51
|
+
await declareLocalPackage(appRoot, "@local/example", "packages/local-example", {
|
|
52
|
+
capabilities: { provides: [], requires: [] },
|
|
53
|
+
runtime: {
|
|
54
|
+
server: {
|
|
55
|
+
providers: [
|
|
56
|
+
{ discover: { dir: "src/server/providers", pattern: "*Provider.js" } }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
80
61
|
await writeFile(
|
|
81
62
|
path.join(appRoot, "packages", "local-example", "src", "server", "providers", "AlphaProvider.js"),
|
|
82
63
|
[
|
|
@@ -145,64 +126,14 @@ test("createProviderRuntimeFromApp ignores app-local src/server/providers folder
|
|
|
145
126
|
}
|
|
146
127
|
});
|
|
147
128
|
|
|
148
|
-
test("createProviderRuntimeFromApp resolves
|
|
129
|
+
test("createProviderRuntimeFromApp resolves package metadata from a file dependency", async () => {
|
|
149
130
|
const appRoot = await createTestAppRoot("kernel-provider-runtime-local-package-");
|
|
150
131
|
try {
|
|
151
132
|
await mkdir(path.join(appRoot, "packages", "local-example"), { recursive: true });
|
|
152
|
-
await
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
lockVersion: 1,
|
|
157
|
-
installedPackages: {
|
|
158
|
-
"@local/example": {
|
|
159
|
-
packageId: "@local/example",
|
|
160
|
-
version: "0.1.0",
|
|
161
|
-
source: {
|
|
162
|
-
type: "local-package",
|
|
163
|
-
packagePath: "packages/local-example"
|
|
164
|
-
},
|
|
165
|
-
managed: {
|
|
166
|
-
packageJson: {
|
|
167
|
-
dependencies: {},
|
|
168
|
-
devDependencies: {},
|
|
169
|
-
scripts: {}
|
|
170
|
-
},
|
|
171
|
-
text: {},
|
|
172
|
-
files: []
|
|
173
|
-
},
|
|
174
|
-
options: {},
|
|
175
|
-
installedAt: "2026-01-01T00:00:00.000Z"
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
null,
|
|
180
|
-
2
|
|
181
|
-
)}\n`,
|
|
182
|
-
"utf8"
|
|
183
|
-
);
|
|
184
|
-
await writeFile(
|
|
185
|
-
path.join(appRoot, "packages", "local-example", "package.descriptor.mjs"),
|
|
186
|
-
[
|
|
187
|
-
"export default Object.freeze({",
|
|
188
|
-
" packageVersion: 1,",
|
|
189
|
-
" packageId: \"@local/example\",",
|
|
190
|
-
" version: \"0.1.0\",",
|
|
191
|
-
" description: \"Local example package\",",
|
|
192
|
-
" dependsOn: [],",
|
|
193
|
-
" capabilities: {",
|
|
194
|
-
" provides: [],",
|
|
195
|
-
" requires: []",
|
|
196
|
-
" },",
|
|
197
|
-
" runtime: {",
|
|
198
|
-
" server: {",
|
|
199
|
-
" providers: []",
|
|
200
|
-
" }",
|
|
201
|
-
" }",
|
|
202
|
-
"});"
|
|
203
|
-
].join("\n"),
|
|
204
|
-
"utf8"
|
|
205
|
-
);
|
|
133
|
+
await declareLocalPackage(appRoot, "@local/example", "packages/local-example", {
|
|
134
|
+
capabilities: { provides: [], requires: [] },
|
|
135
|
+
runtime: { server: { providers: [] } }
|
|
136
|
+
});
|
|
206
137
|
|
|
207
138
|
const runtime = await createProviderRuntimeFromApp({
|
|
208
139
|
appRoot,
|
|
@@ -220,62 +151,16 @@ test("createProviderRuntimeFromApp wires fastify onClose to provider shutdown ex
|
|
|
220
151
|
const appRoot = await createTestAppRoot("kernel-provider-runtime-fastify-close-");
|
|
221
152
|
try {
|
|
222
153
|
await mkdir(path.join(appRoot, "packages", "local-example", "src", "server", "providers"), { recursive: true });
|
|
223
|
-
await
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
{
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
type: "local-package",
|
|
234
|
-
packagePath: "packages/local-example"
|
|
235
|
-
},
|
|
236
|
-
managed: {
|
|
237
|
-
packageJson: {
|
|
238
|
-
dependencies: {},
|
|
239
|
-
devDependencies: {},
|
|
240
|
-
scripts: {}
|
|
241
|
-
},
|
|
242
|
-
text: {},
|
|
243
|
-
files: []
|
|
244
|
-
},
|
|
245
|
-
options: {},
|
|
246
|
-
installedAt: "2026-01-01T00:00:00.000Z"
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
null,
|
|
251
|
-
2
|
|
252
|
-
)}\n`,
|
|
253
|
-
"utf8"
|
|
254
|
-
);
|
|
255
|
-
await writeFile(
|
|
256
|
-
path.join(appRoot, "packages", "local-example", "package.descriptor.mjs"),
|
|
257
|
-
[
|
|
258
|
-
"export default Object.freeze({",
|
|
259
|
-
" packageVersion: 1,",
|
|
260
|
-
" packageId: \"@local/example\",",
|
|
261
|
-
" version: \"0.1.0\",",
|
|
262
|
-
" description: \"Local example package\",",
|
|
263
|
-
" dependsOn: [],",
|
|
264
|
-
" capabilities: {",
|
|
265
|
-
" provides: [],",
|
|
266
|
-
" requires: []",
|
|
267
|
-
" },",
|
|
268
|
-
" runtime: {",
|
|
269
|
-
" server: {",
|
|
270
|
-
" providers: [",
|
|
271
|
-
" { discover: { dir: \"src/server/providers\", pattern: \"*Provider.js\" } }",
|
|
272
|
-
" ]",
|
|
273
|
-
" }",
|
|
274
|
-
" }",
|
|
275
|
-
"});"
|
|
276
|
-
].join("\n"),
|
|
277
|
-
"utf8"
|
|
278
|
-
);
|
|
154
|
+
await declareLocalPackage(appRoot, "@local/example", "packages/local-example", {
|
|
155
|
+
capabilities: { provides: [], requires: [] },
|
|
156
|
+
runtime: {
|
|
157
|
+
server: {
|
|
158
|
+
providers: [
|
|
159
|
+
{ discover: { dir: "src/server/providers", pattern: "*Provider.js" } }
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
279
164
|
await writeFile(
|
|
280
165
|
path.join(appRoot, "packages", "local-example", "src", "server", "providers", "CloseAwareProvider.js"),
|
|
281
166
|
[
|
|
@@ -68,7 +68,7 @@ test("shouldServePathForSurface allows api and matching enabled surfaces", () =>
|
|
|
68
68
|
);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
test("shouldServePathForSurface allows
|
|
71
|
+
test("shouldServePathForSurface allows packageMetadata-declared global ui paths", () => {
|
|
72
72
|
const surfaceRuntime = createFakeSurfaceRuntime();
|
|
73
73
|
assert.equal(
|
|
74
74
|
shouldServePathForSurface({
|
package/server/support/index.js
CHANGED
|
@@ -2,6 +2,12 @@ export { symlinkSafeRequire } from "./symlinkSafeRequire.js";
|
|
|
2
2
|
export { resolveAppConfig, resolveMobileConfig, resolveClientAssetMode, resolveMobileCallbackUrls } from "./appConfig.js";
|
|
3
3
|
export { loadAppConfigFromAppRoot, loadAppConfigFromModuleUrl } from "./appConfigFiles.js";
|
|
4
4
|
export { importFreshModuleFromAbsolutePath } from "./importFreshModuleFromAbsolutePath.js";
|
|
5
|
+
export {
|
|
6
|
+
collectPackageDependencyIds,
|
|
7
|
+
collectRootDependencySpecifiers,
|
|
8
|
+
createPackageMetadata,
|
|
9
|
+
discoverInstalledPackages
|
|
10
|
+
} from "../../internal/node/installedPackages.js";
|
|
5
11
|
export { resolveRequiredAppRoot, toPosixPath } from "./path.js";
|
|
6
12
|
export {
|
|
7
13
|
DEFAULT_PAGE_LINK_COMPONENT_TOKEN,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { readdir, readFile } from "node:fs/promises";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import {
|
|
4
|
+
import { discoverInstalledPackages } from "../../internal/node/installedPackages.js";
|
|
5
5
|
import { normalizeObject, normalizeText } from "../../shared/support/normalize.js";
|
|
6
6
|
import { resolveRequiredAppRoot, toPosixPath } from "./path.js";
|
|
7
7
|
import {
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
} from "../../shared/support/shellLayoutTargets.js";
|
|
16
16
|
|
|
17
17
|
const VUE_DISCOVERY_IGNORED_ERROR_CODES = new Set(["ENOENT", "ENOTDIR", "EACCES", "EPERM"]);
|
|
18
|
-
const LOCK_FILE_RELATIVE_PATH = ".jskit/lock.json";
|
|
19
18
|
const PLACEMENT_TOPOLOGY_RELATIVE_PATH = "src/placementTopology.js";
|
|
20
19
|
const ROUTE_TAG_PATTERN = /<route\b([^>]*)>([\s\S]*?)<\/route>/g;
|
|
21
20
|
const ATTRIBUTE_PATTERN = /([:@]?[A-Za-z_][A-Za-z0-9_-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'))?/g;
|
|
@@ -174,33 +173,10 @@ async function collectVueFilePaths(rootDirectoryPath) {
|
|
|
174
173
|
return files.sort((left, right) => left.localeCompare(right));
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
async function readInstalledPackageStates(appRoot) {
|
|
178
|
-
const lockPath = path.resolve(appRoot, LOCK_FILE_RELATIVE_PATH);
|
|
179
|
-
let lockSource = "";
|
|
180
|
-
try {
|
|
181
|
-
lockSource = await readFile(lockPath, "utf8");
|
|
182
|
-
} catch (error) {
|
|
183
|
-
const errorCode = normalizeText(error?.code).toUpperCase();
|
|
184
|
-
if (errorCode === "ENOENT") {
|
|
185
|
-
return {};
|
|
186
|
-
}
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
let lockPayload = {};
|
|
191
|
-
try {
|
|
192
|
-
lockPayload = JSON.parse(lockSource);
|
|
193
|
-
} catch (error) {
|
|
194
|
-
throw new Error(`Invalid JSON in ${LOCK_FILE_RELATIVE_PATH}.`);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return normalizeObject(lockPayload.installedPackages);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
176
|
function normalizePackageOutletTarget({
|
|
201
177
|
packageId = "",
|
|
202
178
|
outlet = {},
|
|
203
|
-
|
|
179
|
+
manifestPath = ""
|
|
204
180
|
} = {}) {
|
|
205
181
|
const normalizedPackageId = normalizeText(packageId);
|
|
206
182
|
if (!normalizedPackageId) {
|
|
@@ -218,7 +194,7 @@ function normalizePackageOutletTarget({
|
|
|
218
194
|
const source = normalizeText(outletRecord.source);
|
|
219
195
|
const sourcePath = source
|
|
220
196
|
? `package:${normalizedPackageId}:${toPosixPath(source)}`
|
|
221
|
-
: `package:${normalizedPackageId}${
|
|
197
|
+
: `package:${normalizedPackageId}${manifestPath ? `:${toPosixPath(manifestPath)}` : ""}`;
|
|
222
198
|
|
|
223
199
|
return Object.freeze({
|
|
224
200
|
...normalizedTarget,
|
|
@@ -229,19 +205,13 @@ function normalizePackageOutletTarget({
|
|
|
229
205
|
}
|
|
230
206
|
|
|
231
207
|
async function collectInstalledPackageOutletTargets(appRoot) {
|
|
232
|
-
const
|
|
233
|
-
const packageIds = Object.keys(installedPackageStates).sort((left, right) => left.localeCompare(right));
|
|
208
|
+
const installedPackages = await discoverInstalledPackages({ appRoot });
|
|
234
209
|
const targets = [];
|
|
235
210
|
|
|
236
|
-
for (const
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
packageId,
|
|
241
|
-
installedPackageState
|
|
242
|
-
});
|
|
243
|
-
const descriptor = normalizeObject(descriptorRecord.descriptor);
|
|
244
|
-
const metadata = normalizeObject(descriptor.metadata);
|
|
211
|
+
for (const installedPackage of installedPackages) {
|
|
212
|
+
const packageId = installedPackage.packageId;
|
|
213
|
+
const packageMetadata = normalizeObject(installedPackage.packageMetadata);
|
|
214
|
+
const metadata = normalizeObject(packageMetadata.metadata);
|
|
245
215
|
const ui = normalizeObject(metadata.ui);
|
|
246
216
|
const placements = normalizeObject(ui.placements);
|
|
247
217
|
const outlets = Array.isArray(placements.outlets) ? placements.outlets : [];
|
|
@@ -249,7 +219,7 @@ async function collectInstalledPackageOutletTargets(appRoot) {
|
|
|
249
219
|
const normalizedTarget = normalizePackageOutletTarget({
|
|
250
220
|
packageId,
|
|
251
221
|
outlet,
|
|
252
|
-
|
|
222
|
+
manifestPath: installedPackage.manifestPath
|
|
253
223
|
});
|
|
254
224
|
if (normalizedTarget) {
|
|
255
225
|
targets.push(normalizedTarget);
|
|
@@ -297,19 +267,13 @@ async function loadAppPlacementTopology(appRoot) {
|
|
|
297
267
|
}
|
|
298
268
|
|
|
299
269
|
async function collectInstalledPackagePlacementTopology(appRoot) {
|
|
300
|
-
const
|
|
301
|
-
const packageIds = Object.keys(installedPackageStates).sort((left, right) => left.localeCompare(right));
|
|
270
|
+
const installedPackages = await discoverInstalledPackages({ appRoot });
|
|
302
271
|
const placements = [];
|
|
303
272
|
|
|
304
|
-
for (const
|
|
305
|
-
const
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
packageId,
|
|
309
|
-
installedPackageState
|
|
310
|
-
});
|
|
311
|
-
const descriptor = normalizeObject(descriptorRecord.descriptor);
|
|
312
|
-
const metadata = normalizeObject(descriptor.metadata);
|
|
273
|
+
for (const installedPackage of installedPackages) {
|
|
274
|
+
const packageId = installedPackage.packageId;
|
|
275
|
+
const packageMetadata = normalizeObject(installedPackage.packageMetadata);
|
|
276
|
+
const metadata = normalizeObject(packageMetadata.metadata);
|
|
313
277
|
const ui = normalizeObject(metadata.ui);
|
|
314
278
|
const placementsMeta = normalizeObject(ui.placements);
|
|
315
279
|
const topology = placementsMeta.topology;
|
|
@@ -324,7 +288,7 @@ async function collectInstalledPackagePlacementTopology(appRoot) {
|
|
|
324
288
|
placements.push(
|
|
325
289
|
withTopologySource(
|
|
326
290
|
placement,
|
|
327
|
-
`package:${packageId}${
|
|
291
|
+
`package:${packageId}${installedPackage.manifestPath ? `:${toPosixPath(installedPackage.manifestPath)}` : ""}`
|
|
328
292
|
)
|
|
329
293
|
);
|
|
330
294
|
}
|
|
@@ -71,18 +71,13 @@ test("discoverShellOutletTargetsFromApp includes installed package placement out
|
|
|
71
71
|
);
|
|
72
72
|
await writeFileInApp(
|
|
73
73
|
appRoot,
|
|
74
|
-
".
|
|
74
|
+
"package.json",
|
|
75
75
|
`${JSON.stringify(
|
|
76
76
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
source: {
|
|
82
|
-
type: "npm-installed-package",
|
|
83
|
-
descriptorPath: "node_modules/@example/users-web/package.descriptor.mjs"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
77
|
+
name: "fixture-app",
|
|
78
|
+
private: true,
|
|
79
|
+
dependencies: {
|
|
80
|
+
"@example/users-web": "1.0.0"
|
|
86
81
|
}
|
|
87
82
|
},
|
|
88
83
|
null,
|
|
@@ -91,23 +86,25 @@ test("discoverShellOutletTargetsFromApp includes installed package placement out
|
|
|
91
86
|
);
|
|
92
87
|
await writeFileInApp(
|
|
93
88
|
appRoot,
|
|
94
|
-
"node_modules/@example/users-web/package.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
"node_modules/@example/users-web/package.json",
|
|
90
|
+
`${JSON.stringify({
|
|
91
|
+
name: "@example/users-web",
|
|
92
|
+
version: "1.0.0",
|
|
93
|
+
jskit: {
|
|
94
|
+
metadata: {
|
|
95
|
+
ui: {
|
|
96
|
+
placements: {
|
|
97
|
+
outlets: [
|
|
98
|
+
{
|
|
99
|
+
target: "admin-cog:primary-menu",
|
|
100
|
+
source: "src/client/components/UsersWorkspaceToolsWidget.vue"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
104
105
|
}
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
`
|
|
106
|
+
}
|
|
107
|
+
}, null, 2)}\n`
|
|
111
108
|
);
|
|
112
109
|
|
|
113
110
|
const discovered = await discoverShellOutletTargetsFromApp({ appRoot });
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
shouldCreateGeneratedUiNavigationLink
|
|
16
16
|
} from "./generatedUiContract.js";
|
|
17
17
|
|
|
18
|
-
test("generated UI navigation role metadata is
|
|
18
|
+
test("generated UI navigation role metadata is package-ready", () => {
|
|
19
19
|
assert.deepEqual(
|
|
20
20
|
GENERATED_UI_NAVIGATION_ROLE_VALUES,
|
|
21
21
|
["primary", "secondary", "utility", "detail", "workflow", "none"]
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { pathToFileURL } from "node:url";
|
|
3
|
-
import { normalizeObject } from "../../shared/support/normalize.js";
|
|
4
|
-
import { fileExists } from "./fileSystem.js";
|
|
5
|
-
|
|
6
|
-
function resolveNodeModulesDescriptorCandidatePaths({ appRoot, packageId }) {
|
|
7
|
-
const packageDescriptorPath = path.join(packageId, "package.descriptor.mjs");
|
|
8
|
-
const candidatePaths = [];
|
|
9
|
-
let currentRoot = path.resolve(appRoot);
|
|
10
|
-
|
|
11
|
-
while (true) {
|
|
12
|
-
const nodeModulesRoot =
|
|
13
|
-
path.basename(currentRoot) === "node_modules" ? currentRoot : path.join(currentRoot, "node_modules");
|
|
14
|
-
candidatePaths.push(path.join(nodeModulesRoot, packageDescriptorPath));
|
|
15
|
-
|
|
16
|
-
const parentRoot = path.dirname(currentRoot);
|
|
17
|
-
if (parentRoot === currentRoot) {
|
|
18
|
-
break;
|
|
19
|
-
}
|
|
20
|
-
currentRoot = parentRoot;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return candidatePaths;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function resolveDescriptorCandidatePaths({ appRoot, packageId, installedPackageState }) {
|
|
27
|
-
const normalizedAppRoot = String(appRoot || "").trim();
|
|
28
|
-
if (!normalizedAppRoot) {
|
|
29
|
-
throw new TypeError("resolveDescriptorCandidatePaths requires appRoot.");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const normalizedPackageId = String(packageId || "").trim();
|
|
33
|
-
if (!normalizedPackageId) {
|
|
34
|
-
throw new TypeError("resolveDescriptorCandidatePaths requires packageId.");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const source = normalizeObject(installedPackageState?.source);
|
|
38
|
-
const descriptorPathFromSource = String(source.descriptorPath || "").trim();
|
|
39
|
-
const packagePathFromSource = String(source.packagePath || "").trim();
|
|
40
|
-
const jskitRoot = path.join(normalizedAppRoot, "node_modules", "@jskit-ai", "jskit-cli");
|
|
41
|
-
|
|
42
|
-
const candidatePaths = resolveNodeModulesDescriptorCandidatePaths({
|
|
43
|
-
appRoot: normalizedAppRoot,
|
|
44
|
-
packageId: normalizedPackageId
|
|
45
|
-
});
|
|
46
|
-
if (packagePathFromSource) {
|
|
47
|
-
candidatePaths.push(path.resolve(normalizedAppRoot, packagePathFromSource, "package.descriptor.mjs"));
|
|
48
|
-
}
|
|
49
|
-
if (descriptorPathFromSource) {
|
|
50
|
-
candidatePaths.push(path.resolve(normalizedAppRoot, descriptorPathFromSource));
|
|
51
|
-
candidatePaths.push(path.resolve(jskitRoot, descriptorPathFromSource));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const uniqueCandidatePaths = [];
|
|
55
|
-
const seenPaths = new Set();
|
|
56
|
-
for (const candidatePath of candidatePaths) {
|
|
57
|
-
const normalizedCandidatePath = String(candidatePath || "").trim();
|
|
58
|
-
if (!normalizedCandidatePath || seenPaths.has(normalizedCandidatePath)) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
seenPaths.add(normalizedCandidatePath);
|
|
62
|
-
uniqueCandidatePaths.push(normalizedCandidatePath);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return uniqueCandidatePaths;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function resolveDescriptorPathForInstalledPackage({ appRoot, packageId, installedPackageState, required = false }) {
|
|
69
|
-
const candidatePaths = resolveDescriptorCandidatePaths({
|
|
70
|
-
appRoot,
|
|
71
|
-
packageId,
|
|
72
|
-
installedPackageState
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
for (const candidatePath of candidatePaths) {
|
|
76
|
-
if (await fileExists(candidatePath)) {
|
|
77
|
-
return candidatePath;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (required === true) {
|
|
82
|
-
throw new Error(`Unable to resolve package descriptor for ${String(packageId || "").trim()}.`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return "";
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function normalizeDescriptorPayload(descriptorModule) {
|
|
89
|
-
return normalizeObject(descriptorModule?.default);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async function loadInstalledPackageDescriptor({ appRoot, packageId, installedPackageState, required = false }) {
|
|
93
|
-
const descriptorPath = await resolveDescriptorPathForInstalledPackage({
|
|
94
|
-
appRoot,
|
|
95
|
-
packageId,
|
|
96
|
-
installedPackageState,
|
|
97
|
-
required
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
if (!descriptorPath) {
|
|
101
|
-
return Object.freeze({
|
|
102
|
-
descriptorPath: "",
|
|
103
|
-
descriptor: Object.freeze({})
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
const descriptorModule = await import(pathToFileURL(descriptorPath).href);
|
|
109
|
-
return Object.freeze({
|
|
110
|
-
descriptorPath,
|
|
111
|
-
descriptor: normalizeDescriptorPayload(descriptorModule)
|
|
112
|
-
});
|
|
113
|
-
} catch (error) {
|
|
114
|
-
if (required === true) {
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return Object.freeze({
|
|
119
|
-
descriptorPath: "",
|
|
120
|
-
descriptor: Object.freeze({})
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export { loadInstalledPackageDescriptor, resolveDescriptorPathForInstalledPackage };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { fileExists } from "../../../internal/node/fileSystem.js";
|
|
4
|
-
|
|
5
|
-
async function readLockFromApp({ appRoot, lockPath = ".jskit/lock.json" } = {}) {
|
|
6
|
-
if (!appRoot || typeof appRoot !== "string") {
|
|
7
|
-
throw new TypeError("readLockFromApp requires appRoot.");
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const absoluteLockPath = path.resolve(appRoot, String(lockPath || ".jskit/lock.json"));
|
|
11
|
-
if (!(await fileExists(absoluteLockPath))) {
|
|
12
|
-
throw new Error(`Lock file not found: ${absoluteLockPath}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const source = await readFile(absoluteLockPath, "utf8");
|
|
16
|
-
const lock = JSON.parse(source);
|
|
17
|
-
if (!lock || typeof lock !== "object") {
|
|
18
|
-
throw new TypeError(`Invalid lock file payload at ${absoluteLockPath}.`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
lock,
|
|
23
|
-
lockPath: absoluteLockPath
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { readLockFromApp };
|