@elementspanel/epanel-plugin-config 1.0.5 → 1.0.6
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/daemon/backend/index.cjs +329 -113
- package/package.json +18 -4
- package/panel/backend/index.cjs +331 -117
package/daemon/backend/index.cjs
CHANGED
|
@@ -1103,6 +1103,39 @@ async function loadPluginModule(entry, directory, revision) {
|
|
|
1103
1103
|
|
|
1104
1104
|
"use strict";
|
|
1105
1105
|
|
|
1106
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
1107
|
+
if (k2 === undefined) k2 = k;
|
|
1108
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
1109
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
1110
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
1111
|
+
}
|
|
1112
|
+
Object.defineProperty(o, k2, desc);
|
|
1113
|
+
}) : (function(o, m, k, k2) {
|
|
1114
|
+
if (k2 === undefined) k2 = k;
|
|
1115
|
+
o[k2] = m[k];
|
|
1116
|
+
}));
|
|
1117
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
1118
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
1119
|
+
}) : function(o, v) {
|
|
1120
|
+
o["default"] = v;
|
|
1121
|
+
});
|
|
1122
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
1123
|
+
var ownKeys = function(o) {
|
|
1124
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
1125
|
+
var ar = [];
|
|
1126
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
1127
|
+
return ar;
|
|
1128
|
+
};
|
|
1129
|
+
return ownKeys(o);
|
|
1130
|
+
};
|
|
1131
|
+
return function (mod) {
|
|
1132
|
+
if (mod && mod.__esModule) return mod;
|
|
1133
|
+
var result = {};
|
|
1134
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
1135
|
+
__setModuleDefault(result, mod);
|
|
1136
|
+
return result;
|
|
1137
|
+
};
|
|
1138
|
+
})();
|
|
1106
1139
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
1107
1140
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
1108
1141
|
};
|
|
@@ -1121,6 +1154,8 @@ const path_1 = __importDefault(__webpack_require__("path"));
|
|
|
1121
1154
|
const module_1 = __webpack_require__("module");
|
|
1122
1155
|
const plugin_manifest_1 = __webpack_require__("../common/src/plugin_manifest.ts");
|
|
1123
1156
|
const plugin_contract_1 = __webpack_require__("../common/src/plugin_contract.ts");
|
|
1157
|
+
// @ts-ignore Shared by the source runtime and the published npm launcher.
|
|
1158
|
+
const npmPlugins = __importStar(__webpack_require__("../../scripts/runtime/npm-plugins.cjs"));
|
|
1124
1159
|
const PLUGIN_ID = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
1125
1160
|
const PACKAGE_NAME = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
|
|
1126
1161
|
const VERSION = /^[a-zA-Z0-9][a-zA-Z0-9._+-]{0,63}$/;
|
|
@@ -1163,9 +1198,18 @@ function currentProjectRoot(packageRoot = currentPackageRoot()) {
|
|
|
1163
1198
|
}
|
|
1164
1199
|
function npmPluginRoots(options = {}) {
|
|
1165
1200
|
const packageRoot = path_1.default.resolve(options.packageRoot ?? currentPackageRoot());
|
|
1201
|
+
const projectRoot = path_1.default.resolve(options.projectRoot ?? currentProjectRoot(packageRoot));
|
|
1202
|
+
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1203
|
+
const side = options.side ||
|
|
1204
|
+
stringValue(objectValue(host?.elementspanel)?.side) ||
|
|
1205
|
+
path_1.default.basename(packageRoot);
|
|
1166
1206
|
return {
|
|
1167
1207
|
packageRoot,
|
|
1168
|
-
projectRoot
|
|
1208
|
+
projectRoot,
|
|
1209
|
+
dependencyRoot: path_1.default.dirname(npmPlugins.projectManifestFile(packageRoot, side, {
|
|
1210
|
+
projectRoot,
|
|
1211
|
+
runtimeDirectory: process.env.EPANEL_RUNTIME_ROOT
|
|
1212
|
+
}))
|
|
1169
1213
|
};
|
|
1170
1214
|
}
|
|
1171
1215
|
function projectManifestFile(projectRoot) {
|
|
@@ -1193,15 +1237,10 @@ function pluginRecord(pluginId, name, source, packageRoot, directory, folder, ve
|
|
|
1193
1237
|
function readPackageEntry(packageRoot, name) {
|
|
1194
1238
|
// Read package boundaries directly: Node caches require.resolve() paths even
|
|
1195
1239
|
// after npm moves an installation between nested and hoisted node_modules.
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
.map((directory) => path_1.default.join(directory, name, "package.json"))
|
|
1201
|
-
.find((filename) => fs_extra_1.default.existsSync(filename));
|
|
1202
|
-
if (manifestPath)
|
|
1203
|
-
break;
|
|
1204
|
-
}
|
|
1240
|
+
const localRequire = (0, module_1.createRequire)(path_1.default.join(packageRoot, "package.json"));
|
|
1241
|
+
let manifestPath = (localRequire.resolve.paths(name) || [])
|
|
1242
|
+
.map((directory) => path_1.default.join(directory, name, "package.json"))
|
|
1243
|
+
.find((filename) => fs_extra_1.default.existsSync(filename));
|
|
1205
1244
|
if (!manifestPath)
|
|
1206
1245
|
throw new Error(`Missing npm plugin package: ${name}.`);
|
|
1207
1246
|
manifestPath = fs_extra_1.default.realpathSync(manifestPath);
|
|
@@ -1248,83 +1287,26 @@ function recordFromPackage(pluginId, name, source, packageRoot, metadata, side)
|
|
|
1248
1287
|
/**
|
|
1249
1288
|
* Every npm plugin the runtime can load for a side, built-in and project-installed.
|
|
1250
1289
|
*
|
|
1251
|
-
* Built-in package names
|
|
1252
|
-
*
|
|
1253
|
-
* A project package that does not describe the requested side is skipped instead of failing, which
|
|
1254
|
-
* is what lets a two-sided project share one dependency list between sides.
|
|
1290
|
+
* Built-in package names reserve their plugin ids. The side manifest selects
|
|
1291
|
+
* the installed versions; a package without that side is skipped.
|
|
1255
1292
|
*/
|
|
1256
1293
|
function listNpmPlugins(side, options = {}) {
|
|
1257
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1258
|
-
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1259
|
-
if (!host)
|
|
1260
|
-
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
1261
|
-
const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot)
|
|
1262
|
-
? null
|
|
1263
|
-
: readProjectManifest(projectRoot);
|
|
1264
|
-
const hostMappings = mappingsOf(host);
|
|
1265
|
-
const projectMappings = { ...mappingsOf(project) };
|
|
1266
|
-
for (const name of Object.keys(dependenciesOf(project))) {
|
|
1267
|
-
if (!PACKAGE_NAME.test(name) || Object.values(projectMappings).includes(name))
|
|
1268
|
-
continue;
|
|
1269
|
-
try {
|
|
1270
|
-
const entry = readPackageEntry(projectRoot, name);
|
|
1271
|
-
const id = stringValue(objectValue(entry.metadata.elementspanel)?.id);
|
|
1272
|
-
if (PLUGIN_ID.test(id) && projectMappings[id] === undefined)
|
|
1273
|
-
projectMappings[id] = name;
|
|
1274
|
-
}
|
|
1275
|
-
catch {
|
|
1276
|
-
/* npm may still be writing the package. */
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
const mappings = new Map();
|
|
1280
|
-
for (const [pluginId, name] of Object.entries(projectMappings)) {
|
|
1281
|
-
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1282
|
-
continue;
|
|
1283
|
-
mappings.set(pluginId, { name, source: "project" });
|
|
1284
|
-
}
|
|
1285
|
-
for (const [pluginId, name] of Object.entries(hostMappings)) {
|
|
1286
|
-
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1287
|
-
continue;
|
|
1288
|
-
if (dependenciesOf(host)[name] === undefined)
|
|
1289
|
-
continue;
|
|
1290
|
-
mappings.set(pluginId, {
|
|
1291
|
-
name,
|
|
1292
|
-
source: dependenciesOf(project)[name] === undefined ? "bundled" : "project"
|
|
1293
|
-
});
|
|
1294
|
-
}
|
|
1295
|
-
const hostDependencies = dependenciesOf(host);
|
|
1296
|
-
const projectDependencies = dependenciesOf(project);
|
|
1297
|
-
const folders = new Set();
|
|
1294
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots({ ...options, side });
|
|
1298
1295
|
const records = [];
|
|
1299
|
-
for (const
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
entry = readPackageEntry(mapping.source === "project" ? projectRoot : packageRoot, mapping.name);
|
|
1309
|
-
}
|
|
1310
|
-
catch (error) {
|
|
1311
|
-
if (options.skipInvalid)
|
|
1312
|
-
continue;
|
|
1313
|
-
throw error;
|
|
1314
|
-
}
|
|
1315
|
-
const record = recordFromPackage(pluginId, mapping.name, mapping.source, entry.root, entry.metadata, side);
|
|
1296
|
+
for (const item of npmPlugins.resolveNpmPlugins(packageRoot, side, {
|
|
1297
|
+
projectRoot,
|
|
1298
|
+
runtimeDirectory: dependencyRoot,
|
|
1299
|
+
skipInvalid: options.skipInvalid
|
|
1300
|
+
})) {
|
|
1301
|
+
const metadata = readJson(path_1.default.join(item.packageRoot, "package.json"));
|
|
1302
|
+
if (!metadata)
|
|
1303
|
+
continue;
|
|
1304
|
+
const record = recordFromPackage(item.id, item.name, item.source, item.packageRoot, metadata, side);
|
|
1316
1305
|
if (!record) {
|
|
1317
|
-
if (options.skipInvalid || mapping.source === "project")
|
|
1318
|
-
continue;
|
|
1319
|
-
throw new Error(`Invalid ${side ?? "plugin"} entry in npm plugin ${mapping.name}.`);
|
|
1320
|
-
}
|
|
1321
|
-
const folder = record.folder;
|
|
1322
|
-
if (folders.has(folder)) {
|
|
1323
1306
|
if (options.skipInvalid)
|
|
1324
1307
|
continue;
|
|
1325
|
-
throw new Error(`
|
|
1308
|
+
throw new Error(`Invalid ${side ?? "plugin"} entry in npm plugin ${item.name}.`);
|
|
1326
1309
|
}
|
|
1327
|
-
folders.add(folder);
|
|
1328
1310
|
records.push(record);
|
|
1329
1311
|
}
|
|
1330
1312
|
return records;
|
|
@@ -1421,10 +1403,9 @@ async function acquireProjectLock(projectRoot) {
|
|
|
1421
1403
|
}
|
|
1422
1404
|
}
|
|
1423
1405
|
}
|
|
1424
|
-
function npmPluginOperationPending() {
|
|
1425
|
-
const {
|
|
1426
|
-
return
|
|
1427
|
-
[packageRoot, projectRoot].some((root) => fs_extra_1.default.existsSync(path_1.default.join(root, LOCK_NAME))));
|
|
1406
|
+
function npmPluginOperationPending(side) {
|
|
1407
|
+
const { dependencyRoot } = npmPluginRoots({ side });
|
|
1408
|
+
return operations.size > 0 || fs_extra_1.default.existsSync(path_1.default.join(dependencyRoot, LOCK_NAME));
|
|
1428
1409
|
}
|
|
1429
1410
|
function withProjectLock(projectRoot, operation) {
|
|
1430
1411
|
const key = process.platform === "win32" ? projectRoot.toLowerCase() : projectRoot;
|
|
@@ -1459,18 +1440,15 @@ async function installNpmPlugin(options) {
|
|
|
1459
1440
|
throw new Error(`Invalid plugin id: ${options.pluginId}`);
|
|
1460
1441
|
if (!VERSION.test(version))
|
|
1461
1442
|
throw new Error(`Invalid plugin version: ${version}`);
|
|
1462
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1463
|
-
return withProjectLock(
|
|
1443
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots(options);
|
|
1444
|
+
return withProjectLock(dependencyRoot, async () => {
|
|
1464
1445
|
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1465
1446
|
if (!host)
|
|
1466
1447
|
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
1467
|
-
const hostId = Object.entries(mappingsOf(host)).find(([, value]) => value === name
|
|
1468
|
-
const targetRoot =
|
|
1469
|
-
? packageRoot
|
|
1470
|
-
: projectRoot;
|
|
1448
|
+
const hostId = Object.entries(mappingsOf(host)).find(([, value]) => value === name)?.[0];
|
|
1449
|
+
const targetRoot = dependencyRoot;
|
|
1471
1450
|
if (options.pluginId &&
|
|
1472
1451
|
mappingsOf(host)[options.pluginId] &&
|
|
1473
|
-
dependenciesOf(host)[String(mappingsOf(host)[options.pluginId])] !== undefined &&
|
|
1474
1452
|
mappingsOf(host)[options.pluginId] !== name)
|
|
1475
1453
|
throw new Error(`BUNDLED:${options.pluginId}`);
|
|
1476
1454
|
const original = readProjectManifest(targetRoot);
|
|
@@ -1499,24 +1477,33 @@ async function installNpmPlugin(options) {
|
|
|
1499
1477
|
"--save-exact",
|
|
1500
1478
|
"--no-fund",
|
|
1501
1479
|
"--no-audit",
|
|
1502
|
-
"--ignore-scripts"
|
|
1480
|
+
"--ignore-scripts",
|
|
1481
|
+
"--workspaces=false"
|
|
1503
1482
|
], targetRoot);
|
|
1504
1483
|
const entry = readPackageEntry(targetRoot, name);
|
|
1505
1484
|
const pluginId = options.pluginId || stringValue(objectValue(entry.metadata.elementspanel)?.id);
|
|
1506
1485
|
if (!PLUGIN_ID.test(pluginId))
|
|
1507
1486
|
throw new Error(`Invalid plugin id in ${name}.`);
|
|
1508
|
-
if (mappingsOf(host)[pluginId] &&
|
|
1509
|
-
dependenciesOf(host)[String(mappingsOf(host)[pluginId])] !== undefined &&
|
|
1510
|
-
mappingsOf(host)[pluginId] !== name)
|
|
1487
|
+
if (mappingsOf(host)[pluginId] && mappingsOf(host)[pluginId] !== name)
|
|
1511
1488
|
throw new Error(`Plugin id ${pluginId} belongs to a bundled dependency.`);
|
|
1512
1489
|
if (hostId && pluginId !== hostId)
|
|
1513
1490
|
throw new Error(`The package ${name} changed its plugin id from ${hostId} to ${pluginId}.`);
|
|
1514
1491
|
const mapped = mappingsOf(readProjectManifest(targetRoot))[pluginId];
|
|
1515
1492
|
if (mapped !== undefined && mapped !== name)
|
|
1516
1493
|
throw new Error(`Plugin id ${pluginId} is already installed as ${String(mapped)}.`);
|
|
1517
|
-
const record = recordFromPackage(pluginId, name,
|
|
1494
|
+
const record = recordFromPackage(pluginId, name, hostId ? "bundled" : "project", entry.root, entry.metadata, side);
|
|
1518
1495
|
if (!record)
|
|
1519
1496
|
throw new Error(`The package ${name} does not provide a ${side} plugin named ${pluginId}.`);
|
|
1497
|
+
if (side === "panel") {
|
|
1498
|
+
const expected = objectValue(objectValue(entry.metadata.elementspanel)?.panel)
|
|
1499
|
+
?.frontendAssets;
|
|
1500
|
+
const available = objectValue(host.elementspanel)?.frontendAssets;
|
|
1501
|
+
if ((hostId || expected !== undefined) &&
|
|
1502
|
+
(!Array.isArray(expected) ||
|
|
1503
|
+
!Array.isArray(available) ||
|
|
1504
|
+
expected.some((file) => typeof file !== "string" || !available.includes(file))))
|
|
1505
|
+
throw new Error(`Frontend assets in ${name} do not match this panel. Update the panel or install a matching plugin version.`);
|
|
1506
|
+
}
|
|
1520
1507
|
if (/^[0-9]/.test(version) && record.version !== version)
|
|
1521
1508
|
throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
|
|
1522
1509
|
if (!process.env.EPANEL_PACKAGE_ROOT &&
|
|
@@ -1560,7 +1547,8 @@ async function installNpmPlugin(options) {
|
|
|
1560
1547
|
"--save",
|
|
1561
1548
|
"--no-fund",
|
|
1562
1549
|
"--no-audit",
|
|
1563
|
-
"--ignore-scripts"
|
|
1550
|
+
"--ignore-scripts",
|
|
1551
|
+
"--workspaces=false"
|
|
1564
1552
|
]
|
|
1565
1553
|
: [
|
|
1566
1554
|
"--prefix",
|
|
@@ -1569,7 +1557,8 @@ async function installNpmPlugin(options) {
|
|
|
1569
1557
|
name,
|
|
1570
1558
|
"--no-fund",
|
|
1571
1559
|
"--no-audit",
|
|
1572
|
-
"--ignore-scripts"
|
|
1560
|
+
"--ignore-scripts",
|
|
1561
|
+
"--workspaces=false"
|
|
1573
1562
|
], targetRoot);
|
|
1574
1563
|
}
|
|
1575
1564
|
catch (rollback) {
|
|
@@ -1593,22 +1582,29 @@ async function uninstallNpmPlugin(pluginId, options = {}) {
|
|
|
1593
1582
|
throw new Error(`Invalid plugin id: ${pluginId}`);
|
|
1594
1583
|
if (isEssentialNpmPlugin(pluginId))
|
|
1595
1584
|
throw new Error(`The essential plugin "${pluginId}" cannot be uninstalled.`);
|
|
1596
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1597
|
-
return withProjectLock(
|
|
1598
|
-
const
|
|
1599
|
-
const bundledName = mappingsOf(host)[pluginId];
|
|
1600
|
-
const targetRoot = typeof bundledName === "string" &&
|
|
1601
|
-
dependenciesOf(host)[bundledName] !== undefined &&
|
|
1602
|
-
dependenciesOf(readProjectManifest(projectRoot))[bundledName] === undefined
|
|
1603
|
-
? packageRoot
|
|
1604
|
-
: projectRoot;
|
|
1585
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots(options);
|
|
1586
|
+
return withProjectLock(dependencyRoot, async () => {
|
|
1587
|
+
const targetRoot = dependencyRoot;
|
|
1605
1588
|
const manifest = readProjectManifest(targetRoot);
|
|
1606
1589
|
const name = mappingsOf(manifest)[pluginId] ??
|
|
1607
|
-
listNpmPlugins(
|
|
1590
|
+
listNpmPlugins(options.side, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId)?.name;
|
|
1608
1591
|
if (typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1609
1592
|
return null;
|
|
1610
|
-
const record = listNpmPlugins(
|
|
1611
|
-
|
|
1593
|
+
const record = listNpmPlugins(options.side, {
|
|
1594
|
+
packageRoot,
|
|
1595
|
+
projectRoot,
|
|
1596
|
+
skipInvalid: true
|
|
1597
|
+
}).find((item) => item.pluginId === pluginId);
|
|
1598
|
+
await runNpm([
|
|
1599
|
+
"--prefix",
|
|
1600
|
+
targetRoot,
|
|
1601
|
+
"uninstall",
|
|
1602
|
+
name,
|
|
1603
|
+
"--no-fund",
|
|
1604
|
+
"--no-audit",
|
|
1605
|
+
"--ignore-scripts",
|
|
1606
|
+
"--workspaces=false"
|
|
1607
|
+
], targetRoot);
|
|
1612
1608
|
const updated = readProjectManifest(targetRoot);
|
|
1613
1609
|
const plugins = { ...mappingsOf(updated) };
|
|
1614
1610
|
delete plugins[pluginId];
|
|
@@ -1782,11 +1778,11 @@ const plugin_npm_1 = __webpack_require__("../common/src/plugin_npm.ts");
|
|
|
1782
1778
|
/** Poll package boundaries, allowing npm to finish replacing files before reconciliation. */
|
|
1783
1779
|
function watchNpmPlugins(ctx, side, reload, changed) {
|
|
1784
1780
|
const stamp = () => {
|
|
1785
|
-
const { packageRoot,
|
|
1781
|
+
const { packageRoot, dependencyRoot } = (0, plugin_npm_1.npmPluginRoots)({ side });
|
|
1786
1782
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(packageRoot, "package.json")))
|
|
1787
1783
|
return "";
|
|
1788
1784
|
const files = [];
|
|
1789
|
-
for (const root of [packageRoot,
|
|
1785
|
+
for (const root of [packageRoot, dependencyRoot])
|
|
1790
1786
|
for (const name of [
|
|
1791
1787
|
"package.json",
|
|
1792
1788
|
"package-lock.json",
|
|
@@ -1810,7 +1806,7 @@ function watchNpmPlugins(ctx, side, reload, changed) {
|
|
|
1810
1806
|
let candidate = applied;
|
|
1811
1807
|
let busy = false;
|
|
1812
1808
|
ctx.setInterval(() => {
|
|
1813
|
-
if (busy || (0, plugin_npm_1.npmPluginOperationPending)())
|
|
1809
|
+
if (busy || (0, plugin_npm_1.npmPluginOperationPending)(side))
|
|
1814
1810
|
return;
|
|
1815
1811
|
try {
|
|
1816
1812
|
const next = stamp();
|
|
@@ -2759,6 +2755,226 @@ module.exports = require("path");
|
|
|
2759
2755
|
"use strict";
|
|
2760
2756
|
module.exports = require("process");
|
|
2761
2757
|
|
|
2758
|
+
/***/ },
|
|
2759
|
+
|
|
2760
|
+
/***/ "../../scripts/runtime/npm-plugins.cjs"
|
|
2761
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
2762
|
+
|
|
2763
|
+
const fs = __webpack_require__("node:fs");
|
|
2764
|
+
const path = __webpack_require__("node:path");
|
|
2765
|
+
const { createRequire } = __webpack_require__("node:module");
|
|
2766
|
+
|
|
2767
|
+
const readJson = (filename) => JSON.parse(fs.readFileSync(filename, "utf8"));
|
|
2768
|
+
const readOptional = (filename) => {
|
|
2769
|
+
try {
|
|
2770
|
+
return readJson(filename);
|
|
2771
|
+
} catch (error) {
|
|
2772
|
+
if (error.code === "ENOENT") return null;
|
|
2773
|
+
throw error;
|
|
2774
|
+
}
|
|
2775
|
+
};
|
|
2776
|
+
const validId = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
2777
|
+
const validName = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
|
|
2778
|
+
|
|
2779
|
+
function packageManifest(root, name) {
|
|
2780
|
+
const localRequire = createRequire(path.join(root, "package.json"));
|
|
2781
|
+
const filename = (localRequire.resolve.paths(name) || [])
|
|
2782
|
+
.map((directory) => path.join(directory, name, "package.json"))
|
|
2783
|
+
.find((candidate) => fs.existsSync(candidate));
|
|
2784
|
+
if (!filename) throw new Error(`Missing npm package: ${name}`);
|
|
2785
|
+
return fs.realpathSync(filename);
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
function within(root, filename) {
|
|
2789
|
+
const relative = path.relative(root, filename);
|
|
2790
|
+
return (
|
|
2791
|
+
relative === "" ||
|
|
2792
|
+
(relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
|
|
2793
|
+
);
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
function projectRoot(packageRoot) {
|
|
2797
|
+
if (process.env.EPANEL_PROJECT_ROOT) return path.resolve(process.env.EPANEL_PROJECT_ROOT);
|
|
2798
|
+
const parent = path.resolve(packageRoot, "..");
|
|
2799
|
+
if (path.basename(parent) === "core") return path.dirname(parent);
|
|
2800
|
+
// An installed runtime sits at <project>/node_modules/@scope/<side>; the
|
|
2801
|
+
// project itself is three levels above the package. A development checkout
|
|
2802
|
+
// sits below core/ and is handled above.
|
|
2803
|
+
const scope = parent;
|
|
2804
|
+
const nodeModules = path.dirname(scope);
|
|
2805
|
+
if (path.basename(nodeModules) === "node_modules" && path.basename(scope).startsWith("@")) {
|
|
2806
|
+
return path.dirname(nodeModules);
|
|
2807
|
+
}
|
|
2808
|
+
return parent;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
function projectManifestFile(packageRoot, side, options = {}) {
|
|
2812
|
+
const selectedSide =
|
|
2813
|
+
side ||
|
|
2814
|
+
readJson(path.join(packageRoot, "package.json")).elementspanel?.side ||
|
|
2815
|
+
path.basename(packageRoot);
|
|
2816
|
+
if (!["panel", "daemon"].includes(selectedSide)) throw new Error("Missing runtime side.");
|
|
2817
|
+
const directory =
|
|
2818
|
+
options.runtimeDirectory ||
|
|
2819
|
+
(!options.projectRoot && process.env.EPANEL_RUNTIME_ROOT) ||
|
|
2820
|
+
path.join(options.projectRoot || projectRoot(packageRoot), selectedSide);
|
|
2821
|
+
return path.join(path.resolve(directory), "package.json");
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
function mappingOf(manifest) {
|
|
2825
|
+
const plugins = manifest?.elementspanel?.plugins;
|
|
2826
|
+
return plugins && typeof plugins === "object" && !Array.isArray(plugins) ? plugins : {};
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
function dependenciesOf(manifest) {
|
|
2830
|
+
const dependencies = manifest?.dependencies;
|
|
2831
|
+
return dependencies && typeof dependencies === "object" ? dependencies : {};
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
/**
|
|
2835
|
+
* Resolve plugins declared in the side's package.json, including hoisted npm
|
|
2836
|
+
* installations. The host catalogue reserves built-in ids without owning their
|
|
2837
|
+
* versions. Other explicitly mapped plugins remain dormant until enabled.
|
|
2838
|
+
* Runtime startup passes skipInvalid so an optional package being removed does
|
|
2839
|
+
* not stop the host; the caller separately validates the small set of core
|
|
2840
|
+
* plugins.
|
|
2841
|
+
*/
|
|
2842
|
+
function resolveNpmPlugins(packageRoot, side, options = {}) {
|
|
2843
|
+
const skipInvalid = options.skipInvalid === true;
|
|
2844
|
+
const host = readJson(path.join(packageRoot, "package.json"));
|
|
2845
|
+
const selectedSide = side || host.elementspanel?.side || path.basename(packageRoot);
|
|
2846
|
+
const projectFile = projectManifestFile(packageRoot, selectedSide, options);
|
|
2847
|
+
const project = readOptional(projectFile);
|
|
2848
|
+
const dependencyRoot = path.dirname(projectFile);
|
|
2849
|
+
|
|
2850
|
+
// The side manifest owns every dependency; the host only reserves identities.
|
|
2851
|
+
const configured = new Map();
|
|
2852
|
+
for (const [id, name] of Object.entries(mappingOf(project)))
|
|
2853
|
+
configured.set(id, { name, source: "project" });
|
|
2854
|
+
for (const name of Object.keys(dependenciesOf(project))) {
|
|
2855
|
+
if (!validName.test(name) || [...configured.values()].some((item) => item.name === name))
|
|
2856
|
+
continue;
|
|
2857
|
+
try {
|
|
2858
|
+
const metadata = readJson(packageManifest(dependencyRoot, name));
|
|
2859
|
+
const id = metadata.elementspanel?.id;
|
|
2860
|
+
if (validId.test(id) && !configured.has(id))
|
|
2861
|
+
configured.set(id, { name, source: "project", automatic: true });
|
|
2862
|
+
} catch {
|
|
2863
|
+
/* Ignore incomplete npm installations until the next scan. */
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
for (const [id, name] of Object.entries(mappingOf(host))) {
|
|
2867
|
+
if (dependenciesOf(project)[name] !== undefined)
|
|
2868
|
+
configured.set(id, {
|
|
2869
|
+
name,
|
|
2870
|
+
source: "bundled",
|
|
2871
|
+
automatic: true
|
|
2872
|
+
});
|
|
2873
|
+
else if (configured.has(id)) {
|
|
2874
|
+
if (!skipInvalid) throw new Error(`Plugin id ${id} belongs to built-in package ${name}.`);
|
|
2875
|
+
configured.delete(id);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
const projectDependencies = dependenciesOf(project);
|
|
2880
|
+
const folders = new Set();
|
|
2881
|
+
const records = [];
|
|
2882
|
+
|
|
2883
|
+
for (const [id, mapping] of configured) {
|
|
2884
|
+
const name = mapping.name;
|
|
2885
|
+
if (
|
|
2886
|
+
!validId.test(id) ||
|
|
2887
|
+
typeof name !== "string" ||
|
|
2888
|
+
!validName.test(name) ||
|
|
2889
|
+
projectDependencies[name] === undefined
|
|
2890
|
+
) {
|
|
2891
|
+
if (skipInvalid) continue;
|
|
2892
|
+
throw new Error(`Invalid npm plugin dependency: ${id}.`);
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
let manifestPath;
|
|
2896
|
+
let failure;
|
|
2897
|
+
try {
|
|
2898
|
+
manifestPath = packageManifest(dependencyRoot, name);
|
|
2899
|
+
} catch (error) {
|
|
2900
|
+
failure = error;
|
|
2901
|
+
}
|
|
2902
|
+
if (!manifestPath) {
|
|
2903
|
+
if (skipInvalid) continue;
|
|
2904
|
+
throw new Error(`Missing npm plugin ${name}. Run npm install in ${dependencyRoot}.`, {
|
|
2905
|
+
cause: failure
|
|
2906
|
+
});
|
|
2907
|
+
}
|
|
2908
|
+
let metadata;
|
|
2909
|
+
try {
|
|
2910
|
+
metadata = readJson(manifestPath);
|
|
2911
|
+
} catch (error) {
|
|
2912
|
+
if (skipInvalid) continue;
|
|
2913
|
+
throw error;
|
|
2914
|
+
}
|
|
2915
|
+
const definition = metadata.elementspanel?.[selectedSide];
|
|
2916
|
+
// A project dependency may only ship one side; the other side simply does
|
|
2917
|
+
// not see it. A built-in plugin declared by the runtime must carry this side.
|
|
2918
|
+
if (!definition) {
|
|
2919
|
+
if (mapping.source === "project" || skipInvalid) continue;
|
|
2920
|
+
throw new Error(`Invalid ${selectedSide} entry in npm plugin ${name}.`);
|
|
2921
|
+
}
|
|
2922
|
+
const pluginRoot = path.dirname(manifestPath);
|
|
2923
|
+
if (
|
|
2924
|
+
typeof definition.directory !== "string" ||
|
|
2925
|
+
typeof definition.folder !== "string" ||
|
|
2926
|
+
!validId.test(definition.folder) ||
|
|
2927
|
+
path.isAbsolute(definition.directory)
|
|
2928
|
+
) {
|
|
2929
|
+
if (skipInvalid) continue;
|
|
2930
|
+
throw new Error(`Npm plugin entry escapes its package: ${name}.`);
|
|
2931
|
+
}
|
|
2932
|
+
const directory = path.resolve(pluginRoot, definition.directory);
|
|
2933
|
+
if (directory === pluginRoot || !within(pluginRoot, directory)) {
|
|
2934
|
+
if (skipInvalid) continue;
|
|
2935
|
+
throw new Error(`Npm plugin entry escapes its package: ${name}.`);
|
|
2936
|
+
}
|
|
2937
|
+
let entries;
|
|
2938
|
+
try {
|
|
2939
|
+
entries = readJson(path.join(directory, "plugin.json"));
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
if (skipInvalid) continue;
|
|
2942
|
+
throw error;
|
|
2943
|
+
}
|
|
2944
|
+
if (
|
|
2945
|
+
metadata.elementspanel?.id !== id ||
|
|
2946
|
+
typeof metadata.version !== "string" ||
|
|
2947
|
+
!metadata.version.trim() ||
|
|
2948
|
+
!entries ||
|
|
2949
|
+
typeof entries !== "object" ||
|
|
2950
|
+
Array.isArray(entries)
|
|
2951
|
+
) {
|
|
2952
|
+
if (skipInvalid) continue;
|
|
2953
|
+
throw new Error(`Invalid npm plugin identity or version in package.json: ${name}.`);
|
|
2954
|
+
}
|
|
2955
|
+
if (folders.has(definition.folder)) {
|
|
2956
|
+
if (skipInvalid) continue;
|
|
2957
|
+
throw new Error(`Duplicate npm plugin asset directory: ${definition.folder}.`);
|
|
2958
|
+
}
|
|
2959
|
+
folders.add(definition.folder);
|
|
2960
|
+
records.push({
|
|
2961
|
+
id,
|
|
2962
|
+
name,
|
|
2963
|
+
version: metadata.version,
|
|
2964
|
+
source: mapping.source,
|
|
2965
|
+
defaultEnabled: mapping.automatic === true || mapping.source !== "project",
|
|
2966
|
+
packageRoot: pluginRoot,
|
|
2967
|
+
directory,
|
|
2968
|
+
folder: definition.folder,
|
|
2969
|
+
dependencies: Object.keys(metadata.dependencies || {})
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
return records;
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2975
|
+
module.exports = { resolveNpmPlugins, projectManifestFile };
|
|
2976
|
+
|
|
2977
|
+
|
|
2762
2978
|
/***/ },
|
|
2763
2979
|
|
|
2764
2980
|
/***/ "../../scripts/workspace-layout.cjs"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementspanel/epanel-plugin-config",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Panel plugin configuration.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Csituka_D <694428809@qq.com> (https://github.com/JessDaodao)",
|
|
@@ -39,7 +39,21 @@
|
|
|
39
39
|
"frontend/assets/style-0-_panel-plugin-build-entry_config-112f7940.css"
|
|
40
40
|
],
|
|
41
41
|
"directory": "panel",
|
|
42
|
-
"folder": "config"
|
|
42
|
+
"folder": "config",
|
|
43
|
+
"frontendAssets": [
|
|
44
|
+
"assets/_elements-sdk_cordis-e3bebc89.js",
|
|
45
|
+
"assets/_elements-sdk_cosmokit-e4842f5c.js",
|
|
46
|
+
"assets/_plugin-vue_export-helper-c27b6911.js",
|
|
47
|
+
"assets/context-f49cfcce.js",
|
|
48
|
+
"assets/htmlparser2-bcb8f9db.js",
|
|
49
|
+
"assets/i18n-66e8c48a.js",
|
|
50
|
+
"assets/lodash-001e4f93.js",
|
|
51
|
+
"assets/router-ffe15376.js",
|
|
52
|
+
"assets/useAppStateStore-e16e4edd.js",
|
|
53
|
+
"assets/useDefineApi-5b6599dc.js",
|
|
54
|
+
"assets/useScreen-7eb281ed.js",
|
|
55
|
+
"assets/vue-828bfe55.js"
|
|
56
|
+
]
|
|
43
57
|
},
|
|
44
58
|
"daemon": {
|
|
45
59
|
"priority": 10000,
|
|
@@ -50,8 +64,8 @@
|
|
|
50
64
|
}
|
|
51
65
|
},
|
|
52
66
|
"peerDependencies": {
|
|
53
|
-
"@elementspanel/panel": "^1.0.
|
|
54
|
-
"@elementspanel/daemon": "^1.0.
|
|
67
|
+
"@elementspanel/panel": "^1.0.0",
|
|
68
|
+
"@elementspanel/daemon": "^1.0.0"
|
|
55
69
|
},
|
|
56
70
|
"peerDependenciesMeta": {
|
|
57
71
|
"@elementspanel/panel": {
|
package/panel/backend/index.cjs
CHANGED
|
@@ -4155,6 +4155,39 @@ async function loadPluginModule(entry, directory, revision) {
|
|
|
4155
4155
|
|
|
4156
4156
|
"use strict";
|
|
4157
4157
|
|
|
4158
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4159
|
+
if (k2 === undefined) k2 = k;
|
|
4160
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
4161
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
4162
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
4163
|
+
}
|
|
4164
|
+
Object.defineProperty(o, k2, desc);
|
|
4165
|
+
}) : (function(o, m, k, k2) {
|
|
4166
|
+
if (k2 === undefined) k2 = k;
|
|
4167
|
+
o[k2] = m[k];
|
|
4168
|
+
}));
|
|
4169
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
4170
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
4171
|
+
}) : function(o, v) {
|
|
4172
|
+
o["default"] = v;
|
|
4173
|
+
});
|
|
4174
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
4175
|
+
var ownKeys = function(o) {
|
|
4176
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
4177
|
+
var ar = [];
|
|
4178
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
4179
|
+
return ar;
|
|
4180
|
+
};
|
|
4181
|
+
return ownKeys(o);
|
|
4182
|
+
};
|
|
4183
|
+
return function (mod) {
|
|
4184
|
+
if (mod && mod.__esModule) return mod;
|
|
4185
|
+
var result = {};
|
|
4186
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
4187
|
+
__setModuleDefault(result, mod);
|
|
4188
|
+
return result;
|
|
4189
|
+
};
|
|
4190
|
+
})();
|
|
4158
4191
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4159
4192
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4160
4193
|
};
|
|
@@ -4174,6 +4207,8 @@ const path_1 = __importDefault(__webpack_require__("path"));
|
|
|
4174
4207
|
const module_1 = __webpack_require__("module");
|
|
4175
4208
|
const plugin_manifest_1 = __webpack_require__("../common/src/plugin_manifest.ts");
|
|
4176
4209
|
const plugin_contract_1 = __webpack_require__("../common/src/plugin_contract.ts");
|
|
4210
|
+
// @ts-ignore Shared by the source runtime and the published npm launcher.
|
|
4211
|
+
const npmPlugins = __importStar(__webpack_require__("../../scripts/runtime/npm-plugins.cjs"));
|
|
4177
4212
|
const PLUGIN_ID = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
4178
4213
|
const PACKAGE_NAME = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
|
|
4179
4214
|
const VERSION = /^[a-zA-Z0-9][a-zA-Z0-9._+-]{0,63}$/;
|
|
@@ -4215,11 +4250,20 @@ function currentProjectRoot(packageRoot = currentPackageRoot()) {
|
|
|
4215
4250
|
return scope;
|
|
4216
4251
|
}
|
|
4217
4252
|
function npmPluginRoots(options = {}) {
|
|
4218
|
-
var _a, _b;
|
|
4253
|
+
var _a, _b, _c;
|
|
4219
4254
|
const packageRoot = path_1.default.resolve((_a = options.packageRoot) !== null && _a !== void 0 ? _a : currentPackageRoot());
|
|
4255
|
+
const projectRoot = path_1.default.resolve((_b = options.projectRoot) !== null && _b !== void 0 ? _b : currentProjectRoot(packageRoot));
|
|
4256
|
+
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
4257
|
+
const side = options.side ||
|
|
4258
|
+
stringValue((_c = objectValue(host === null || host === void 0 ? void 0 : host.elementspanel)) === null || _c === void 0 ? void 0 : _c.side) ||
|
|
4259
|
+
path_1.default.basename(packageRoot);
|
|
4220
4260
|
return {
|
|
4221
4261
|
packageRoot,
|
|
4222
|
-
projectRoot
|
|
4262
|
+
projectRoot,
|
|
4263
|
+
dependencyRoot: path_1.default.dirname(npmPlugins.projectManifestFile(packageRoot, side, {
|
|
4264
|
+
projectRoot,
|
|
4265
|
+
runtimeDirectory: process.env.EPANEL_RUNTIME_ROOT
|
|
4266
|
+
}))
|
|
4223
4267
|
};
|
|
4224
4268
|
}
|
|
4225
4269
|
function projectManifestFile(projectRoot) {
|
|
@@ -4250,15 +4294,10 @@ function pluginRecord(pluginId, name, source, packageRoot, directory, folder, ve
|
|
|
4250
4294
|
function readPackageEntry(packageRoot, name) {
|
|
4251
4295
|
// Read package boundaries directly: Node caches require.resolve() paths even
|
|
4252
4296
|
// after npm moves an installation between nested and hoisted node_modules.
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
.map((directory) => path_1.default.join(directory, name, "package.json"))
|
|
4258
|
-
.find((filename) => fs_extra_1.default.existsSync(filename));
|
|
4259
|
-
if (manifestPath)
|
|
4260
|
-
break;
|
|
4261
|
-
}
|
|
4297
|
+
const localRequire = (0, module_1.createRequire)(path_1.default.join(packageRoot, "package.json"));
|
|
4298
|
+
let manifestPath = (localRequire.resolve.paths(name) || [])
|
|
4299
|
+
.map((directory) => path_1.default.join(directory, name, "package.json"))
|
|
4300
|
+
.find((filename) => fs_extra_1.default.existsSync(filename));
|
|
4262
4301
|
if (!manifestPath)
|
|
4263
4302
|
throw new Error(`Missing npm plugin package: ${name}.`);
|
|
4264
4303
|
manifestPath = fs_extra_1.default.realpathSync(manifestPath);
|
|
@@ -4306,84 +4345,26 @@ function recordFromPackage(pluginId, name, source, packageRoot, metadata, side)
|
|
|
4306
4345
|
/**
|
|
4307
4346
|
* Every npm plugin the runtime can load for a side, built-in and project-installed.
|
|
4308
4347
|
*
|
|
4309
|
-
* Built-in package names
|
|
4310
|
-
*
|
|
4311
|
-
* A project package that does not describe the requested side is skipped instead of failing, which
|
|
4312
|
-
* is what lets a two-sided project share one dependency list between sides.
|
|
4348
|
+
* Built-in package names reserve their plugin ids. The side manifest selects
|
|
4349
|
+
* the installed versions; a package without that side is skipped.
|
|
4313
4350
|
*/
|
|
4314
4351
|
function listNpmPlugins(side, options = {}) {
|
|
4315
|
-
|
|
4316
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
4317
|
-
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
4318
|
-
if (!host)
|
|
4319
|
-
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
4320
|
-
const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot)
|
|
4321
|
-
? null
|
|
4322
|
-
: readProjectManifest(projectRoot);
|
|
4323
|
-
const hostMappings = mappingsOf(host);
|
|
4324
|
-
const projectMappings = { ...mappingsOf(project) };
|
|
4325
|
-
for (const name of Object.keys(dependenciesOf(project))) {
|
|
4326
|
-
if (!PACKAGE_NAME.test(name) || Object.values(projectMappings).includes(name))
|
|
4327
|
-
continue;
|
|
4328
|
-
try {
|
|
4329
|
-
const entry = readPackageEntry(projectRoot, name);
|
|
4330
|
-
const id = stringValue((_a = objectValue(entry.metadata.elementspanel)) === null || _a === void 0 ? void 0 : _a.id);
|
|
4331
|
-
if (PLUGIN_ID.test(id) && projectMappings[id] === undefined)
|
|
4332
|
-
projectMappings[id] = name;
|
|
4333
|
-
}
|
|
4334
|
-
catch (_c) {
|
|
4335
|
-
/* npm may still be writing the package. */
|
|
4336
|
-
}
|
|
4337
|
-
}
|
|
4338
|
-
const mappings = new Map();
|
|
4339
|
-
for (const [pluginId, name] of Object.entries(projectMappings)) {
|
|
4340
|
-
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
4341
|
-
continue;
|
|
4342
|
-
mappings.set(pluginId, { name, source: "project" });
|
|
4343
|
-
}
|
|
4344
|
-
for (const [pluginId, name] of Object.entries(hostMappings)) {
|
|
4345
|
-
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
4346
|
-
continue;
|
|
4347
|
-
if (dependenciesOf(host)[name] === undefined)
|
|
4348
|
-
continue;
|
|
4349
|
-
mappings.set(pluginId, {
|
|
4350
|
-
name,
|
|
4351
|
-
source: dependenciesOf(project)[name] === undefined ? "bundled" : "project"
|
|
4352
|
-
});
|
|
4353
|
-
}
|
|
4354
|
-
const hostDependencies = dependenciesOf(host);
|
|
4355
|
-
const projectDependencies = dependenciesOf(project);
|
|
4356
|
-
const folders = new Set();
|
|
4352
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots({ ...options, side });
|
|
4357
4353
|
const records = [];
|
|
4358
|
-
for (const
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
entry = readPackageEntry(mapping.source === "project" ? projectRoot : packageRoot, mapping.name);
|
|
4368
|
-
}
|
|
4369
|
-
catch (error) {
|
|
4370
|
-
if (options.skipInvalid)
|
|
4371
|
-
continue;
|
|
4372
|
-
throw error;
|
|
4373
|
-
}
|
|
4374
|
-
const record = recordFromPackage(pluginId, mapping.name, mapping.source, entry.root, entry.metadata, side);
|
|
4354
|
+
for (const item of npmPlugins.resolveNpmPlugins(packageRoot, side, {
|
|
4355
|
+
projectRoot,
|
|
4356
|
+
runtimeDirectory: dependencyRoot,
|
|
4357
|
+
skipInvalid: options.skipInvalid
|
|
4358
|
+
})) {
|
|
4359
|
+
const metadata = readJson(path_1.default.join(item.packageRoot, "package.json"));
|
|
4360
|
+
if (!metadata)
|
|
4361
|
+
continue;
|
|
4362
|
+
const record = recordFromPackage(item.id, item.name, item.source, item.packageRoot, metadata, side);
|
|
4375
4363
|
if (!record) {
|
|
4376
|
-
if (options.skipInvalid || mapping.source === "project")
|
|
4377
|
-
continue;
|
|
4378
|
-
throw new Error(`Invalid ${side !== null && side !== void 0 ? side : "plugin"} entry in npm plugin ${mapping.name}.`);
|
|
4379
|
-
}
|
|
4380
|
-
const folder = record.folder;
|
|
4381
|
-
if (folders.has(folder)) {
|
|
4382
4364
|
if (options.skipInvalid)
|
|
4383
4365
|
continue;
|
|
4384
|
-
throw new Error(`
|
|
4366
|
+
throw new Error(`Invalid ${side !== null && side !== void 0 ? side : "plugin"} entry in npm plugin ${item.name}.`);
|
|
4385
4367
|
}
|
|
4386
|
-
folders.add(folder);
|
|
4387
4368
|
records.push(record);
|
|
4388
4369
|
}
|
|
4389
4370
|
return records;
|
|
@@ -4482,10 +4463,9 @@ async function acquireProjectLock(projectRoot) {
|
|
|
4482
4463
|
}
|
|
4483
4464
|
}
|
|
4484
4465
|
}
|
|
4485
|
-
function npmPluginOperationPending() {
|
|
4486
|
-
const {
|
|
4487
|
-
return
|
|
4488
|
-
[packageRoot, projectRoot].some((root) => fs_extra_1.default.existsSync(path_1.default.join(root, LOCK_NAME))));
|
|
4466
|
+
function npmPluginOperationPending(side) {
|
|
4467
|
+
const { dependencyRoot } = npmPluginRoots({ side });
|
|
4468
|
+
return operations.size > 0 || fs_extra_1.default.existsSync(path_1.default.join(dependencyRoot, LOCK_NAME));
|
|
4489
4469
|
}
|
|
4490
4470
|
function withProjectLock(projectRoot, operation) {
|
|
4491
4471
|
var _a;
|
|
@@ -4521,19 +4501,16 @@ async function installNpmPlugin(options) {
|
|
|
4521
4501
|
throw new Error(`Invalid plugin id: ${options.pluginId}`);
|
|
4522
4502
|
if (!VERSION.test(version))
|
|
4523
4503
|
throw new Error(`Invalid plugin version: ${version}`);
|
|
4524
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
4525
|
-
return withProjectLock(
|
|
4526
|
-
var _a, _b;
|
|
4504
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots(options);
|
|
4505
|
+
return withProjectLock(dependencyRoot, async () => {
|
|
4506
|
+
var _a, _b, _c, _d, _e;
|
|
4527
4507
|
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
4528
4508
|
if (!host)
|
|
4529
4509
|
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
4530
|
-
const hostId = (_a = Object.entries(mappingsOf(host)).find(([, value]) => value === name
|
|
4531
|
-
const targetRoot =
|
|
4532
|
-
? packageRoot
|
|
4533
|
-
: projectRoot;
|
|
4510
|
+
const hostId = (_a = Object.entries(mappingsOf(host)).find(([, value]) => value === name)) === null || _a === void 0 ? void 0 : _a[0];
|
|
4511
|
+
const targetRoot = dependencyRoot;
|
|
4534
4512
|
if (options.pluginId &&
|
|
4535
4513
|
mappingsOf(host)[options.pluginId] &&
|
|
4536
|
-
dependenciesOf(host)[String(mappingsOf(host)[options.pluginId])] !== undefined &&
|
|
4537
4514
|
mappingsOf(host)[options.pluginId] !== name)
|
|
4538
4515
|
throw new Error(`BUNDLED:${options.pluginId}`);
|
|
4539
4516
|
const original = readProjectManifest(targetRoot);
|
|
@@ -4543,7 +4520,7 @@ async function installNpmPlugin(options) {
|
|
|
4543
4520
|
try {
|
|
4544
4521
|
previousVersion = readPackageEntry(targetRoot, name).metadata.version || previous;
|
|
4545
4522
|
}
|
|
4546
|
-
catch (
|
|
4523
|
+
catch (_f) {
|
|
4547
4524
|
/* Keep the declared spec if the previous package is incomplete. */
|
|
4548
4525
|
}
|
|
4549
4526
|
}
|
|
@@ -4562,24 +4539,32 @@ async function installNpmPlugin(options) {
|
|
|
4562
4539
|
"--save-exact",
|
|
4563
4540
|
"--no-fund",
|
|
4564
4541
|
"--no-audit",
|
|
4565
|
-
"--ignore-scripts"
|
|
4542
|
+
"--ignore-scripts",
|
|
4543
|
+
"--workspaces=false"
|
|
4566
4544
|
], targetRoot);
|
|
4567
4545
|
const entry = readPackageEntry(targetRoot, name);
|
|
4568
4546
|
const pluginId = options.pluginId || stringValue((_b = objectValue(entry.metadata.elementspanel)) === null || _b === void 0 ? void 0 : _b.id);
|
|
4569
4547
|
if (!PLUGIN_ID.test(pluginId))
|
|
4570
4548
|
throw new Error(`Invalid plugin id in ${name}.`);
|
|
4571
|
-
if (mappingsOf(host)[pluginId] &&
|
|
4572
|
-
dependenciesOf(host)[String(mappingsOf(host)[pluginId])] !== undefined &&
|
|
4573
|
-
mappingsOf(host)[pluginId] !== name)
|
|
4549
|
+
if (mappingsOf(host)[pluginId] && mappingsOf(host)[pluginId] !== name)
|
|
4574
4550
|
throw new Error(`Plugin id ${pluginId} belongs to a bundled dependency.`);
|
|
4575
4551
|
if (hostId && pluginId !== hostId)
|
|
4576
4552
|
throw new Error(`The package ${name} changed its plugin id from ${hostId} to ${pluginId}.`);
|
|
4577
4553
|
const mapped = mappingsOf(readProjectManifest(targetRoot))[pluginId];
|
|
4578
4554
|
if (mapped !== undefined && mapped !== name)
|
|
4579
4555
|
throw new Error(`Plugin id ${pluginId} is already installed as ${String(mapped)}.`);
|
|
4580
|
-
const record = recordFromPackage(pluginId, name,
|
|
4556
|
+
const record = recordFromPackage(pluginId, name, hostId ? "bundled" : "project", entry.root, entry.metadata, side);
|
|
4581
4557
|
if (!record)
|
|
4582
4558
|
throw new Error(`The package ${name} does not provide a ${side} plugin named ${pluginId}.`);
|
|
4559
|
+
if (side === "panel") {
|
|
4560
|
+
const expected = (_d = objectValue((_c = objectValue(entry.metadata.elementspanel)) === null || _c === void 0 ? void 0 : _c.panel)) === null || _d === void 0 ? void 0 : _d.frontendAssets;
|
|
4561
|
+
const available = (_e = objectValue(host.elementspanel)) === null || _e === void 0 ? void 0 : _e.frontendAssets;
|
|
4562
|
+
if ((hostId || expected !== undefined) &&
|
|
4563
|
+
(!Array.isArray(expected) ||
|
|
4564
|
+
!Array.isArray(available) ||
|
|
4565
|
+
expected.some((file) => typeof file !== "string" || !available.includes(file))))
|
|
4566
|
+
throw new Error(`Frontend assets in ${name} do not match this panel. Update the panel or install a matching plugin version.`);
|
|
4567
|
+
}
|
|
4583
4568
|
if (/^[0-9]/.test(version) && record.version !== version)
|
|
4584
4569
|
throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
|
|
4585
4570
|
if (!process.env.EPANEL_PACKAGE_ROOT &&
|
|
@@ -4623,7 +4608,8 @@ async function installNpmPlugin(options) {
|
|
|
4623
4608
|
"--save",
|
|
4624
4609
|
"--no-fund",
|
|
4625
4610
|
"--no-audit",
|
|
4626
|
-
"--ignore-scripts"
|
|
4611
|
+
"--ignore-scripts",
|
|
4612
|
+
"--workspaces=false"
|
|
4627
4613
|
]
|
|
4628
4614
|
: [
|
|
4629
4615
|
"--prefix",
|
|
@@ -4632,7 +4618,8 @@ async function installNpmPlugin(options) {
|
|
|
4632
4618
|
name,
|
|
4633
4619
|
"--no-fund",
|
|
4634
4620
|
"--no-audit",
|
|
4635
|
-
"--ignore-scripts"
|
|
4621
|
+
"--ignore-scripts",
|
|
4622
|
+
"--workspaces=false"
|
|
4636
4623
|
], targetRoot);
|
|
4637
4624
|
}
|
|
4638
4625
|
catch (rollback) {
|
|
@@ -4656,22 +4643,29 @@ async function uninstallNpmPlugin(pluginId, options = {}) {
|
|
|
4656
4643
|
throw new Error(`Invalid plugin id: ${pluginId}`);
|
|
4657
4644
|
if (isEssentialNpmPlugin(pluginId))
|
|
4658
4645
|
throw new Error(`The essential plugin "${pluginId}" cannot be uninstalled.`);
|
|
4659
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
4660
|
-
return withProjectLock(
|
|
4646
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots(options);
|
|
4647
|
+
return withProjectLock(dependencyRoot, async () => {
|
|
4661
4648
|
var _a, _b;
|
|
4662
|
-
const
|
|
4663
|
-
const bundledName = mappingsOf(host)[pluginId];
|
|
4664
|
-
const targetRoot = typeof bundledName === "string" &&
|
|
4665
|
-
dependenciesOf(host)[bundledName] !== undefined &&
|
|
4666
|
-
dependenciesOf(readProjectManifest(projectRoot))[bundledName] === undefined
|
|
4667
|
-
? packageRoot
|
|
4668
|
-
: projectRoot;
|
|
4649
|
+
const targetRoot = dependencyRoot;
|
|
4669
4650
|
const manifest = readProjectManifest(targetRoot);
|
|
4670
|
-
const name = (_a = mappingsOf(manifest)[pluginId]) !== null && _a !== void 0 ? _a : (_b = listNpmPlugins(
|
|
4651
|
+
const name = (_a = mappingsOf(manifest)[pluginId]) !== null && _a !== void 0 ? _a : (_b = listNpmPlugins(options.side, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId)) === null || _b === void 0 ? void 0 : _b.name;
|
|
4671
4652
|
if (typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
4672
4653
|
return null;
|
|
4673
|
-
const record = listNpmPlugins(
|
|
4674
|
-
|
|
4654
|
+
const record = listNpmPlugins(options.side, {
|
|
4655
|
+
packageRoot,
|
|
4656
|
+
projectRoot,
|
|
4657
|
+
skipInvalid: true
|
|
4658
|
+
}).find((item) => item.pluginId === pluginId);
|
|
4659
|
+
await runNpm([
|
|
4660
|
+
"--prefix",
|
|
4661
|
+
targetRoot,
|
|
4662
|
+
"uninstall",
|
|
4663
|
+
name,
|
|
4664
|
+
"--no-fund",
|
|
4665
|
+
"--no-audit",
|
|
4666
|
+
"--ignore-scripts",
|
|
4667
|
+
"--workspaces=false"
|
|
4668
|
+
], targetRoot);
|
|
4675
4669
|
const updated = readProjectManifest(targetRoot);
|
|
4676
4670
|
const plugins = { ...mappingsOf(updated) };
|
|
4677
4671
|
delete plugins[pluginId];
|
|
@@ -4845,11 +4839,11 @@ const plugin_npm_1 = __webpack_require__("../common/src/plugin_npm.ts");
|
|
|
4845
4839
|
/** Poll package boundaries, allowing npm to finish replacing files before reconciliation. */
|
|
4846
4840
|
function watchNpmPlugins(ctx, side, reload, changed) {
|
|
4847
4841
|
const stamp = () => {
|
|
4848
|
-
const { packageRoot,
|
|
4842
|
+
const { packageRoot, dependencyRoot } = (0, plugin_npm_1.npmPluginRoots)({ side });
|
|
4849
4843
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(packageRoot, "package.json")))
|
|
4850
4844
|
return "";
|
|
4851
4845
|
const files = [];
|
|
4852
|
-
for (const root of [packageRoot,
|
|
4846
|
+
for (const root of [packageRoot, dependencyRoot])
|
|
4853
4847
|
for (const name of [
|
|
4854
4848
|
"package.json",
|
|
4855
4849
|
"package-lock.json",
|
|
@@ -4873,7 +4867,7 @@ function watchNpmPlugins(ctx, side, reload, changed) {
|
|
|
4873
4867
|
let candidate = applied;
|
|
4874
4868
|
let busy = false;
|
|
4875
4869
|
ctx.setInterval(() => {
|
|
4876
|
-
if (busy || (0, plugin_npm_1.npmPluginOperationPending)())
|
|
4870
|
+
if (busy || (0, plugin_npm_1.npmPluginOperationPending)(side))
|
|
4877
4871
|
return;
|
|
4878
4872
|
try {
|
|
4879
4873
|
const next = stamp();
|
|
@@ -5832,6 +5826,226 @@ module.exports = require("stream");
|
|
|
5832
5826
|
"use strict";
|
|
5833
5827
|
module.exports = require("string_decoder");
|
|
5834
5828
|
|
|
5829
|
+
/***/ },
|
|
5830
|
+
|
|
5831
|
+
/***/ "../../scripts/runtime/npm-plugins.cjs"
|
|
5832
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
5833
|
+
|
|
5834
|
+
const fs = __webpack_require__("node:fs");
|
|
5835
|
+
const path = __webpack_require__("node:path");
|
|
5836
|
+
const { createRequire } = __webpack_require__("node:module");
|
|
5837
|
+
|
|
5838
|
+
const readJson = (filename) => JSON.parse(fs.readFileSync(filename, "utf8"));
|
|
5839
|
+
const readOptional = (filename) => {
|
|
5840
|
+
try {
|
|
5841
|
+
return readJson(filename);
|
|
5842
|
+
} catch (error) {
|
|
5843
|
+
if (error.code === "ENOENT") return null;
|
|
5844
|
+
throw error;
|
|
5845
|
+
}
|
|
5846
|
+
};
|
|
5847
|
+
const validId = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
5848
|
+
const validName = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
|
|
5849
|
+
|
|
5850
|
+
function packageManifest(root, name) {
|
|
5851
|
+
const localRequire = createRequire(path.join(root, "package.json"));
|
|
5852
|
+
const filename = (localRequire.resolve.paths(name) || [])
|
|
5853
|
+
.map((directory) => path.join(directory, name, "package.json"))
|
|
5854
|
+
.find((candidate) => fs.existsSync(candidate));
|
|
5855
|
+
if (!filename) throw new Error(`Missing npm package: ${name}`);
|
|
5856
|
+
return fs.realpathSync(filename);
|
|
5857
|
+
}
|
|
5858
|
+
|
|
5859
|
+
function within(root, filename) {
|
|
5860
|
+
const relative = path.relative(root, filename);
|
|
5861
|
+
return (
|
|
5862
|
+
relative === "" ||
|
|
5863
|
+
(relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
|
|
5864
|
+
);
|
|
5865
|
+
}
|
|
5866
|
+
|
|
5867
|
+
function projectRoot(packageRoot) {
|
|
5868
|
+
if (process.env.EPANEL_PROJECT_ROOT) return path.resolve(process.env.EPANEL_PROJECT_ROOT);
|
|
5869
|
+
const parent = path.resolve(packageRoot, "..");
|
|
5870
|
+
if (path.basename(parent) === "core") return path.dirname(parent);
|
|
5871
|
+
// An installed runtime sits at <project>/node_modules/@scope/<side>; the
|
|
5872
|
+
// project itself is three levels above the package. A development checkout
|
|
5873
|
+
// sits below core/ and is handled above.
|
|
5874
|
+
const scope = parent;
|
|
5875
|
+
const nodeModules = path.dirname(scope);
|
|
5876
|
+
if (path.basename(nodeModules) === "node_modules" && path.basename(scope).startsWith("@")) {
|
|
5877
|
+
return path.dirname(nodeModules);
|
|
5878
|
+
}
|
|
5879
|
+
return parent;
|
|
5880
|
+
}
|
|
5881
|
+
|
|
5882
|
+
function projectManifestFile(packageRoot, side, options = {}) {
|
|
5883
|
+
const selectedSide =
|
|
5884
|
+
side ||
|
|
5885
|
+
readJson(path.join(packageRoot, "package.json")).elementspanel?.side ||
|
|
5886
|
+
path.basename(packageRoot);
|
|
5887
|
+
if (!["panel", "daemon"].includes(selectedSide)) throw new Error("Missing runtime side.");
|
|
5888
|
+
const directory =
|
|
5889
|
+
options.runtimeDirectory ||
|
|
5890
|
+
(!options.projectRoot && process.env.EPANEL_RUNTIME_ROOT) ||
|
|
5891
|
+
path.join(options.projectRoot || projectRoot(packageRoot), selectedSide);
|
|
5892
|
+
return path.join(path.resolve(directory), "package.json");
|
|
5893
|
+
}
|
|
5894
|
+
|
|
5895
|
+
function mappingOf(manifest) {
|
|
5896
|
+
const plugins = manifest?.elementspanel?.plugins;
|
|
5897
|
+
return plugins && typeof plugins === "object" && !Array.isArray(plugins) ? plugins : {};
|
|
5898
|
+
}
|
|
5899
|
+
|
|
5900
|
+
function dependenciesOf(manifest) {
|
|
5901
|
+
const dependencies = manifest?.dependencies;
|
|
5902
|
+
return dependencies && typeof dependencies === "object" ? dependencies : {};
|
|
5903
|
+
}
|
|
5904
|
+
|
|
5905
|
+
/**
|
|
5906
|
+
* Resolve plugins declared in the side's package.json, including hoisted npm
|
|
5907
|
+
* installations. The host catalogue reserves built-in ids without owning their
|
|
5908
|
+
* versions. Other explicitly mapped plugins remain dormant until enabled.
|
|
5909
|
+
* Runtime startup passes skipInvalid so an optional package being removed does
|
|
5910
|
+
* not stop the host; the caller separately validates the small set of core
|
|
5911
|
+
* plugins.
|
|
5912
|
+
*/
|
|
5913
|
+
function resolveNpmPlugins(packageRoot, side, options = {}) {
|
|
5914
|
+
const skipInvalid = options.skipInvalid === true;
|
|
5915
|
+
const host = readJson(path.join(packageRoot, "package.json"));
|
|
5916
|
+
const selectedSide = side || host.elementspanel?.side || path.basename(packageRoot);
|
|
5917
|
+
const projectFile = projectManifestFile(packageRoot, selectedSide, options);
|
|
5918
|
+
const project = readOptional(projectFile);
|
|
5919
|
+
const dependencyRoot = path.dirname(projectFile);
|
|
5920
|
+
|
|
5921
|
+
// The side manifest owns every dependency; the host only reserves identities.
|
|
5922
|
+
const configured = new Map();
|
|
5923
|
+
for (const [id, name] of Object.entries(mappingOf(project)))
|
|
5924
|
+
configured.set(id, { name, source: "project" });
|
|
5925
|
+
for (const name of Object.keys(dependenciesOf(project))) {
|
|
5926
|
+
if (!validName.test(name) || [...configured.values()].some((item) => item.name === name))
|
|
5927
|
+
continue;
|
|
5928
|
+
try {
|
|
5929
|
+
const metadata = readJson(packageManifest(dependencyRoot, name));
|
|
5930
|
+
const id = metadata.elementspanel?.id;
|
|
5931
|
+
if (validId.test(id) && !configured.has(id))
|
|
5932
|
+
configured.set(id, { name, source: "project", automatic: true });
|
|
5933
|
+
} catch {
|
|
5934
|
+
/* Ignore incomplete npm installations until the next scan. */
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
for (const [id, name] of Object.entries(mappingOf(host))) {
|
|
5938
|
+
if (dependenciesOf(project)[name] !== undefined)
|
|
5939
|
+
configured.set(id, {
|
|
5940
|
+
name,
|
|
5941
|
+
source: "bundled",
|
|
5942
|
+
automatic: true
|
|
5943
|
+
});
|
|
5944
|
+
else if (configured.has(id)) {
|
|
5945
|
+
if (!skipInvalid) throw new Error(`Plugin id ${id} belongs to built-in package ${name}.`);
|
|
5946
|
+
configured.delete(id);
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
|
|
5950
|
+
const projectDependencies = dependenciesOf(project);
|
|
5951
|
+
const folders = new Set();
|
|
5952
|
+
const records = [];
|
|
5953
|
+
|
|
5954
|
+
for (const [id, mapping] of configured) {
|
|
5955
|
+
const name = mapping.name;
|
|
5956
|
+
if (
|
|
5957
|
+
!validId.test(id) ||
|
|
5958
|
+
typeof name !== "string" ||
|
|
5959
|
+
!validName.test(name) ||
|
|
5960
|
+
projectDependencies[name] === undefined
|
|
5961
|
+
) {
|
|
5962
|
+
if (skipInvalid) continue;
|
|
5963
|
+
throw new Error(`Invalid npm plugin dependency: ${id}.`);
|
|
5964
|
+
}
|
|
5965
|
+
|
|
5966
|
+
let manifestPath;
|
|
5967
|
+
let failure;
|
|
5968
|
+
try {
|
|
5969
|
+
manifestPath = packageManifest(dependencyRoot, name);
|
|
5970
|
+
} catch (error) {
|
|
5971
|
+
failure = error;
|
|
5972
|
+
}
|
|
5973
|
+
if (!manifestPath) {
|
|
5974
|
+
if (skipInvalid) continue;
|
|
5975
|
+
throw new Error(`Missing npm plugin ${name}. Run npm install in ${dependencyRoot}.`, {
|
|
5976
|
+
cause: failure
|
|
5977
|
+
});
|
|
5978
|
+
}
|
|
5979
|
+
let metadata;
|
|
5980
|
+
try {
|
|
5981
|
+
metadata = readJson(manifestPath);
|
|
5982
|
+
} catch (error) {
|
|
5983
|
+
if (skipInvalid) continue;
|
|
5984
|
+
throw error;
|
|
5985
|
+
}
|
|
5986
|
+
const definition = metadata.elementspanel?.[selectedSide];
|
|
5987
|
+
// A project dependency may only ship one side; the other side simply does
|
|
5988
|
+
// not see it. A built-in plugin declared by the runtime must carry this side.
|
|
5989
|
+
if (!definition) {
|
|
5990
|
+
if (mapping.source === "project" || skipInvalid) continue;
|
|
5991
|
+
throw new Error(`Invalid ${selectedSide} entry in npm plugin ${name}.`);
|
|
5992
|
+
}
|
|
5993
|
+
const pluginRoot = path.dirname(manifestPath);
|
|
5994
|
+
if (
|
|
5995
|
+
typeof definition.directory !== "string" ||
|
|
5996
|
+
typeof definition.folder !== "string" ||
|
|
5997
|
+
!validId.test(definition.folder) ||
|
|
5998
|
+
path.isAbsolute(definition.directory)
|
|
5999
|
+
) {
|
|
6000
|
+
if (skipInvalid) continue;
|
|
6001
|
+
throw new Error(`Npm plugin entry escapes its package: ${name}.`);
|
|
6002
|
+
}
|
|
6003
|
+
const directory = path.resolve(pluginRoot, definition.directory);
|
|
6004
|
+
if (directory === pluginRoot || !within(pluginRoot, directory)) {
|
|
6005
|
+
if (skipInvalid) continue;
|
|
6006
|
+
throw new Error(`Npm plugin entry escapes its package: ${name}.`);
|
|
6007
|
+
}
|
|
6008
|
+
let entries;
|
|
6009
|
+
try {
|
|
6010
|
+
entries = readJson(path.join(directory, "plugin.json"));
|
|
6011
|
+
} catch (error) {
|
|
6012
|
+
if (skipInvalid) continue;
|
|
6013
|
+
throw error;
|
|
6014
|
+
}
|
|
6015
|
+
if (
|
|
6016
|
+
metadata.elementspanel?.id !== id ||
|
|
6017
|
+
typeof metadata.version !== "string" ||
|
|
6018
|
+
!metadata.version.trim() ||
|
|
6019
|
+
!entries ||
|
|
6020
|
+
typeof entries !== "object" ||
|
|
6021
|
+
Array.isArray(entries)
|
|
6022
|
+
) {
|
|
6023
|
+
if (skipInvalid) continue;
|
|
6024
|
+
throw new Error(`Invalid npm plugin identity or version in package.json: ${name}.`);
|
|
6025
|
+
}
|
|
6026
|
+
if (folders.has(definition.folder)) {
|
|
6027
|
+
if (skipInvalid) continue;
|
|
6028
|
+
throw new Error(`Duplicate npm plugin asset directory: ${definition.folder}.`);
|
|
6029
|
+
}
|
|
6030
|
+
folders.add(definition.folder);
|
|
6031
|
+
records.push({
|
|
6032
|
+
id,
|
|
6033
|
+
name,
|
|
6034
|
+
version: metadata.version,
|
|
6035
|
+
source: mapping.source,
|
|
6036
|
+
defaultEnabled: mapping.automatic === true || mapping.source !== "project",
|
|
6037
|
+
packageRoot: pluginRoot,
|
|
6038
|
+
directory,
|
|
6039
|
+
folder: definition.folder,
|
|
6040
|
+
dependencies: Object.keys(metadata.dependencies || {})
|
|
6041
|
+
});
|
|
6042
|
+
}
|
|
6043
|
+
return records;
|
|
6044
|
+
}
|
|
6045
|
+
|
|
6046
|
+
module.exports = { resolveNpmPlugins, projectManifestFile };
|
|
6047
|
+
|
|
6048
|
+
|
|
5835
6049
|
/***/ },
|
|
5836
6050
|
|
|
5837
6051
|
/***/ "../../scripts/workspace-layout.cjs"
|