@elementspanel/epanel-plugin-config 1.0.4 → 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 +374 -113
- package/package.json +19 -5
- package/panel/backend/index.cjs +377 -117
- package/panel/frontend/assets/{style-0-_panel-plugin-build-entry_config-9641f087.css → style-0-_panel-plugin-build-entry_config-112f7940.css} +1 -1
- package/panel/frontend/panel-plugin-config-d3d27421.js +1 -0
- package/panel/plugin.json +1 -1
- package/panel/frontend/panel-plugin-config-440a77c3.js +0 -1
package/daemon/backend/index.cjs
CHANGED
|
@@ -240,6 +240,7 @@ Object.defineProperty(exports, "arrayUnique", ({ enumerable: true, get: function
|
|
|
240
240
|
__exportStar(__webpack_require__("../common/src/plugin_contract.ts"), exports);
|
|
241
241
|
__exportStar(__webpack_require__("../common/src/plugin_overrides.ts"), exports);
|
|
242
242
|
__exportStar(__webpack_require__("../common/src/plugin_lifecycle.ts"), exports);
|
|
243
|
+
__exportStar(__webpack_require__("../common/src/process_restart.ts"), exports);
|
|
243
244
|
__exportStar(__webpack_require__("../common/src/plugin_revision.ts"), exports);
|
|
244
245
|
__exportStar(__webpack_require__("../common/src/plugin_modules.ts"), exports);
|
|
245
246
|
__exportStar(__webpack_require__("../common/src/plugin_watch.ts"), exports);
|
|
@@ -1102,6 +1103,39 @@ async function loadPluginModule(entry, directory, revision) {
|
|
|
1102
1103
|
|
|
1103
1104
|
"use strict";
|
|
1104
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
|
+
})();
|
|
1105
1139
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
1106
1140
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
1107
1141
|
};
|
|
@@ -1120,6 +1154,8 @@ const path_1 = __importDefault(__webpack_require__("path"));
|
|
|
1120
1154
|
const module_1 = __webpack_require__("module");
|
|
1121
1155
|
const plugin_manifest_1 = __webpack_require__("../common/src/plugin_manifest.ts");
|
|
1122
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"));
|
|
1123
1159
|
const PLUGIN_ID = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
1124
1160
|
const PACKAGE_NAME = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
|
|
1125
1161
|
const VERSION = /^[a-zA-Z0-9][a-zA-Z0-9._+-]{0,63}$/;
|
|
@@ -1162,9 +1198,18 @@ function currentProjectRoot(packageRoot = currentPackageRoot()) {
|
|
|
1162
1198
|
}
|
|
1163
1199
|
function npmPluginRoots(options = {}) {
|
|
1164
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);
|
|
1165
1206
|
return {
|
|
1166
1207
|
packageRoot,
|
|
1167
|
-
projectRoot
|
|
1208
|
+
projectRoot,
|
|
1209
|
+
dependencyRoot: path_1.default.dirname(npmPlugins.projectManifestFile(packageRoot, side, {
|
|
1210
|
+
projectRoot,
|
|
1211
|
+
runtimeDirectory: process.env.EPANEL_RUNTIME_ROOT
|
|
1212
|
+
}))
|
|
1168
1213
|
};
|
|
1169
1214
|
}
|
|
1170
1215
|
function projectManifestFile(projectRoot) {
|
|
@@ -1192,15 +1237,10 @@ function pluginRecord(pluginId, name, source, packageRoot, directory, folder, ve
|
|
|
1192
1237
|
function readPackageEntry(packageRoot, name) {
|
|
1193
1238
|
// Read package boundaries directly: Node caches require.resolve() paths even
|
|
1194
1239
|
// after npm moves an installation between nested and hoisted node_modules.
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
.map((directory) => path_1.default.join(directory, name, "package.json"))
|
|
1200
|
-
.find((filename) => fs_extra_1.default.existsSync(filename));
|
|
1201
|
-
if (manifestPath)
|
|
1202
|
-
break;
|
|
1203
|
-
}
|
|
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));
|
|
1204
1244
|
if (!manifestPath)
|
|
1205
1245
|
throw new Error(`Missing npm plugin package: ${name}.`);
|
|
1206
1246
|
manifestPath = fs_extra_1.default.realpathSync(manifestPath);
|
|
@@ -1247,83 +1287,26 @@ function recordFromPackage(pluginId, name, source, packageRoot, metadata, side)
|
|
|
1247
1287
|
/**
|
|
1248
1288
|
* Every npm plugin the runtime can load for a side, built-in and project-installed.
|
|
1249
1289
|
*
|
|
1250
|
-
* Built-in package names
|
|
1251
|
-
*
|
|
1252
|
-
* A project package that does not describe the requested side is skipped instead of failing, which
|
|
1253
|
-
* 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.
|
|
1254
1292
|
*/
|
|
1255
1293
|
function listNpmPlugins(side, options = {}) {
|
|
1256
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1257
|
-
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1258
|
-
if (!host)
|
|
1259
|
-
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
1260
|
-
const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot)
|
|
1261
|
-
? null
|
|
1262
|
-
: readProjectManifest(projectRoot);
|
|
1263
|
-
const hostMappings = mappingsOf(host);
|
|
1264
|
-
const projectMappings = { ...mappingsOf(project) };
|
|
1265
|
-
for (const name of Object.keys(dependenciesOf(project))) {
|
|
1266
|
-
if (!PACKAGE_NAME.test(name) || Object.values(projectMappings).includes(name))
|
|
1267
|
-
continue;
|
|
1268
|
-
try {
|
|
1269
|
-
const entry = readPackageEntry(projectRoot, name);
|
|
1270
|
-
const id = stringValue(objectValue(entry.metadata.elementspanel)?.id);
|
|
1271
|
-
if (PLUGIN_ID.test(id) && projectMappings[id] === undefined)
|
|
1272
|
-
projectMappings[id] = name;
|
|
1273
|
-
}
|
|
1274
|
-
catch {
|
|
1275
|
-
/* npm may still be writing the package. */
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
const mappings = new Map();
|
|
1279
|
-
for (const [pluginId, name] of Object.entries(projectMappings)) {
|
|
1280
|
-
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1281
|
-
continue;
|
|
1282
|
-
mappings.set(pluginId, { name, source: "project" });
|
|
1283
|
-
}
|
|
1284
|
-
for (const [pluginId, name] of Object.entries(hostMappings)) {
|
|
1285
|
-
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1286
|
-
continue;
|
|
1287
|
-
if (dependenciesOf(host)[name] === undefined)
|
|
1288
|
-
continue;
|
|
1289
|
-
mappings.set(pluginId, {
|
|
1290
|
-
name,
|
|
1291
|
-
source: dependenciesOf(project)[name] === undefined ? "bundled" : "project"
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
const hostDependencies = dependenciesOf(host);
|
|
1295
|
-
const projectDependencies = dependenciesOf(project);
|
|
1296
|
-
const folders = new Set();
|
|
1294
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots({ ...options, side });
|
|
1297
1295
|
const records = [];
|
|
1298
|
-
for (const
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
entry = readPackageEntry(mapping.source === "project" ? projectRoot : packageRoot, mapping.name);
|
|
1308
|
-
}
|
|
1309
|
-
catch (error) {
|
|
1310
|
-
if (options.skipInvalid)
|
|
1311
|
-
continue;
|
|
1312
|
-
throw error;
|
|
1313
|
-
}
|
|
1314
|
-
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);
|
|
1315
1305
|
if (!record) {
|
|
1316
|
-
if (options.skipInvalid || mapping.source === "project")
|
|
1317
|
-
continue;
|
|
1318
|
-
throw new Error(`Invalid ${side ?? "plugin"} entry in npm plugin ${mapping.name}.`);
|
|
1319
|
-
}
|
|
1320
|
-
const folder = record.folder;
|
|
1321
|
-
if (folders.has(folder)) {
|
|
1322
1306
|
if (options.skipInvalid)
|
|
1323
1307
|
continue;
|
|
1324
|
-
throw new Error(`
|
|
1308
|
+
throw new Error(`Invalid ${side ?? "plugin"} entry in npm plugin ${item.name}.`);
|
|
1325
1309
|
}
|
|
1326
|
-
folders.add(folder);
|
|
1327
1310
|
records.push(record);
|
|
1328
1311
|
}
|
|
1329
1312
|
return records;
|
|
@@ -1420,10 +1403,9 @@ async function acquireProjectLock(projectRoot) {
|
|
|
1420
1403
|
}
|
|
1421
1404
|
}
|
|
1422
1405
|
}
|
|
1423
|
-
function npmPluginOperationPending() {
|
|
1424
|
-
const {
|
|
1425
|
-
return
|
|
1426
|
-
[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));
|
|
1427
1409
|
}
|
|
1428
1410
|
function withProjectLock(projectRoot, operation) {
|
|
1429
1411
|
const key = process.platform === "win32" ? projectRoot.toLowerCase() : projectRoot;
|
|
@@ -1458,18 +1440,15 @@ async function installNpmPlugin(options) {
|
|
|
1458
1440
|
throw new Error(`Invalid plugin id: ${options.pluginId}`);
|
|
1459
1441
|
if (!VERSION.test(version))
|
|
1460
1442
|
throw new Error(`Invalid plugin version: ${version}`);
|
|
1461
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1462
|
-
return withProjectLock(
|
|
1443
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots(options);
|
|
1444
|
+
return withProjectLock(dependencyRoot, async () => {
|
|
1463
1445
|
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1464
1446
|
if (!host)
|
|
1465
1447
|
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
1466
|
-
const hostId = Object.entries(mappingsOf(host)).find(([, value]) => value === name
|
|
1467
|
-
const targetRoot =
|
|
1468
|
-
? packageRoot
|
|
1469
|
-
: projectRoot;
|
|
1448
|
+
const hostId = Object.entries(mappingsOf(host)).find(([, value]) => value === name)?.[0];
|
|
1449
|
+
const targetRoot = dependencyRoot;
|
|
1470
1450
|
if (options.pluginId &&
|
|
1471
1451
|
mappingsOf(host)[options.pluginId] &&
|
|
1472
|
-
dependenciesOf(host)[String(mappingsOf(host)[options.pluginId])] !== undefined &&
|
|
1473
1452
|
mappingsOf(host)[options.pluginId] !== name)
|
|
1474
1453
|
throw new Error(`BUNDLED:${options.pluginId}`);
|
|
1475
1454
|
const original = readProjectManifest(targetRoot);
|
|
@@ -1498,24 +1477,33 @@ async function installNpmPlugin(options) {
|
|
|
1498
1477
|
"--save-exact",
|
|
1499
1478
|
"--no-fund",
|
|
1500
1479
|
"--no-audit",
|
|
1501
|
-
"--ignore-scripts"
|
|
1480
|
+
"--ignore-scripts",
|
|
1481
|
+
"--workspaces=false"
|
|
1502
1482
|
], targetRoot);
|
|
1503
1483
|
const entry = readPackageEntry(targetRoot, name);
|
|
1504
1484
|
const pluginId = options.pluginId || stringValue(objectValue(entry.metadata.elementspanel)?.id);
|
|
1505
1485
|
if (!PLUGIN_ID.test(pluginId))
|
|
1506
1486
|
throw new Error(`Invalid plugin id in ${name}.`);
|
|
1507
|
-
if (mappingsOf(host)[pluginId] &&
|
|
1508
|
-
dependenciesOf(host)[String(mappingsOf(host)[pluginId])] !== undefined &&
|
|
1509
|
-
mappingsOf(host)[pluginId] !== name)
|
|
1487
|
+
if (mappingsOf(host)[pluginId] && mappingsOf(host)[pluginId] !== name)
|
|
1510
1488
|
throw new Error(`Plugin id ${pluginId} belongs to a bundled dependency.`);
|
|
1511
1489
|
if (hostId && pluginId !== hostId)
|
|
1512
1490
|
throw new Error(`The package ${name} changed its plugin id from ${hostId} to ${pluginId}.`);
|
|
1513
1491
|
const mapped = mappingsOf(readProjectManifest(targetRoot))[pluginId];
|
|
1514
1492
|
if (mapped !== undefined && mapped !== name)
|
|
1515
1493
|
throw new Error(`Plugin id ${pluginId} is already installed as ${String(mapped)}.`);
|
|
1516
|
-
const record = recordFromPackage(pluginId, name,
|
|
1494
|
+
const record = recordFromPackage(pluginId, name, hostId ? "bundled" : "project", entry.root, entry.metadata, side);
|
|
1517
1495
|
if (!record)
|
|
1518
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
|
+
}
|
|
1519
1507
|
if (/^[0-9]/.test(version) && record.version !== version)
|
|
1520
1508
|
throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
|
|
1521
1509
|
if (!process.env.EPANEL_PACKAGE_ROOT &&
|
|
@@ -1559,7 +1547,8 @@ async function installNpmPlugin(options) {
|
|
|
1559
1547
|
"--save",
|
|
1560
1548
|
"--no-fund",
|
|
1561
1549
|
"--no-audit",
|
|
1562
|
-
"--ignore-scripts"
|
|
1550
|
+
"--ignore-scripts",
|
|
1551
|
+
"--workspaces=false"
|
|
1563
1552
|
]
|
|
1564
1553
|
: [
|
|
1565
1554
|
"--prefix",
|
|
@@ -1568,7 +1557,8 @@ async function installNpmPlugin(options) {
|
|
|
1568
1557
|
name,
|
|
1569
1558
|
"--no-fund",
|
|
1570
1559
|
"--no-audit",
|
|
1571
|
-
"--ignore-scripts"
|
|
1560
|
+
"--ignore-scripts",
|
|
1561
|
+
"--workspaces=false"
|
|
1572
1562
|
], targetRoot);
|
|
1573
1563
|
}
|
|
1574
1564
|
catch (rollback) {
|
|
@@ -1592,22 +1582,29 @@ async function uninstallNpmPlugin(pluginId, options = {}) {
|
|
|
1592
1582
|
throw new Error(`Invalid plugin id: ${pluginId}`);
|
|
1593
1583
|
if (isEssentialNpmPlugin(pluginId))
|
|
1594
1584
|
throw new Error(`The essential plugin "${pluginId}" cannot be uninstalled.`);
|
|
1595
|
-
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1596
|
-
return withProjectLock(
|
|
1597
|
-
const
|
|
1598
|
-
const bundledName = mappingsOf(host)[pluginId];
|
|
1599
|
-
const targetRoot = typeof bundledName === "string" &&
|
|
1600
|
-
dependenciesOf(host)[bundledName] !== undefined &&
|
|
1601
|
-
dependenciesOf(readProjectManifest(projectRoot))[bundledName] === undefined
|
|
1602
|
-
? packageRoot
|
|
1603
|
-
: projectRoot;
|
|
1585
|
+
const { packageRoot, projectRoot, dependencyRoot } = npmPluginRoots(options);
|
|
1586
|
+
return withProjectLock(dependencyRoot, async () => {
|
|
1587
|
+
const targetRoot = dependencyRoot;
|
|
1604
1588
|
const manifest = readProjectManifest(targetRoot);
|
|
1605
1589
|
const name = mappingsOf(manifest)[pluginId] ??
|
|
1606
|
-
listNpmPlugins(
|
|
1590
|
+
listNpmPlugins(options.side, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId)?.name;
|
|
1607
1591
|
if (typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1608
1592
|
return null;
|
|
1609
|
-
const record = listNpmPlugins(
|
|
1610
|
-
|
|
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);
|
|
1611
1608
|
const updated = readProjectManifest(targetRoot);
|
|
1612
1609
|
const plugins = { ...mappingsOf(updated) };
|
|
1613
1610
|
delete plugins[pluginId];
|
|
@@ -1781,11 +1778,11 @@ const plugin_npm_1 = __webpack_require__("../common/src/plugin_npm.ts");
|
|
|
1781
1778
|
/** Poll package boundaries, allowing npm to finish replacing files before reconciliation. */
|
|
1782
1779
|
function watchNpmPlugins(ctx, side, reload, changed) {
|
|
1783
1780
|
const stamp = () => {
|
|
1784
|
-
const { packageRoot,
|
|
1781
|
+
const { packageRoot, dependencyRoot } = (0, plugin_npm_1.npmPluginRoots)({ side });
|
|
1785
1782
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(packageRoot, "package.json")))
|
|
1786
1783
|
return "";
|
|
1787
1784
|
const files = [];
|
|
1788
|
-
for (const root of [packageRoot,
|
|
1785
|
+
for (const root of [packageRoot, dependencyRoot])
|
|
1789
1786
|
for (const name of [
|
|
1790
1787
|
"package.json",
|
|
1791
1788
|
"package-lock.json",
|
|
@@ -1809,7 +1806,7 @@ function watchNpmPlugins(ctx, side, reload, changed) {
|
|
|
1809
1806
|
let candidate = applied;
|
|
1810
1807
|
let busy = false;
|
|
1811
1808
|
ctx.setInterval(() => {
|
|
1812
|
-
if (busy || (0, plugin_npm_1.npmPluginOperationPending)())
|
|
1809
|
+
if (busy || (0, plugin_npm_1.npmPluginOperationPending)(side))
|
|
1813
1810
|
return;
|
|
1814
1811
|
try {
|
|
1815
1812
|
const next = stamp();
|
|
@@ -1840,6 +1837,50 @@ function watchNpmPlugins(ctx, side, reload, changed) {
|
|
|
1840
1837
|
}
|
|
1841
1838
|
|
|
1842
1839
|
|
|
1840
|
+
/***/ },
|
|
1841
|
+
|
|
1842
|
+
/***/ "../common/src/process_restart.ts"
|
|
1843
|
+
(__unused_webpack_module, exports) {
|
|
1844
|
+
|
|
1845
|
+
"use strict";
|
|
1846
|
+
|
|
1847
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
1848
|
+
exports.isProcessRestartPending = isProcessRestartPending;
|
|
1849
|
+
exports.requestProcessRestart = requestProcessRestart;
|
|
1850
|
+
const RESTART = Symbol.for("elementspanel.process.restart");
|
|
1851
|
+
function isProcessRestartPending(ctx) {
|
|
1852
|
+
return ctx.root[RESTART]?.pending === true;
|
|
1853
|
+
}
|
|
1854
|
+
/** The CLI retains instance processes and starts a fresh worker after this one exits. */
|
|
1855
|
+
function requestProcessRestart(ctx, settle, ready = async () => { }) {
|
|
1856
|
+
if (isProcessRestartPending(ctx))
|
|
1857
|
+
return true;
|
|
1858
|
+
if (process.env.EPANEL_SUPERVISED !== "1" || !process.connected || !process.send)
|
|
1859
|
+
return false;
|
|
1860
|
+
const state = { pending: true };
|
|
1861
|
+
ctx.root[RESTART] = state;
|
|
1862
|
+
const retainProcesses = () => new Promise((resolve, reject) => process.send({ type: "elementspanel:prepare-restart" }, (error) => error ? reject(error) : resolve()));
|
|
1863
|
+
setImmediate(() => {
|
|
1864
|
+
void (async () => {
|
|
1865
|
+
await ready();
|
|
1866
|
+
// Detach output consumers before cleanup so output and exits during the
|
|
1867
|
+
// restart are retained for the next daemon generation.
|
|
1868
|
+
await retainProcesses();
|
|
1869
|
+
await ctx.parallel("process/restarting");
|
|
1870
|
+
// A pending start can finish while restart hooks are awaiting it.
|
|
1871
|
+
await retainProcesses();
|
|
1872
|
+
await ctx.stop();
|
|
1873
|
+
await settle();
|
|
1874
|
+
process.send({ type: "elementspanel:restart" }, (error) => process.exit(error ? 1 : 0));
|
|
1875
|
+
})().catch((error) => {
|
|
1876
|
+
ctx.logger.error("Failed to restart the process:", error);
|
|
1877
|
+
process.exit(1);
|
|
1878
|
+
});
|
|
1879
|
+
});
|
|
1880
|
+
return true;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
|
|
1843
1884
|
/***/ },
|
|
1844
1885
|
|
|
1845
1886
|
/***/ "../common/src/process_tools.ts"
|
|
@@ -2714,6 +2755,226 @@ module.exports = require("path");
|
|
|
2714
2755
|
"use strict";
|
|
2715
2756
|
module.exports = require("process");
|
|
2716
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
|
+
|
|
2717
2978
|
/***/ },
|
|
2718
2979
|
|
|
2719
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)",
|
|
@@ -36,10 +36,24 @@
|
|
|
36
36
|
],
|
|
37
37
|
"description": "Panel plugin configuration.",
|
|
38
38
|
"styles": [
|
|
39
|
-
"frontend/assets/style-0-_panel-plugin-build-entry_config-
|
|
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": {
|