@elementspanel/epanel-plugin-config 1.0.0 → 1.0.1
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 +595 -87
- package/daemon/plugin.json +1 -4
- package/package.json +13 -1
- package/panel/backend/index.cjs +619 -92
- package/panel/frontend/assets/{style-0-_panel-plugin-build-entry_config-4aa69b22.css → style-0-_panel-plugin-build-entry_config-6c3cbd56.css} +1 -1
- package/panel/frontend/panel-plugin-config-1f7cc416.js +1 -0
- package/panel/plugin.json +2 -11
- package/panel/frontend/panel-plugin-config-cb428381.js +0 -1
package/daemon/backend/index.cjs
CHANGED
|
@@ -109,7 +109,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
109
109
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
110
110
|
};
|
|
111
111
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
112
|
-
exports.StorageSubsystem = exports.MCServerStatus = exports.InstanceStreamListener = exports.GlobalVariable = exports.normalizeDockerPlatform = exports.normalizeDockerOS = exports.normalizeDockerArchitecture = exports.removeTrail = exports.uninstallNpmPlugin = exports.npmPluginRoots = exports.listNpmPlugins = exports.installNpmPlugin = exports.currentProjectRoot = exports.currentPackageRoot = exports.sortPlugins = exports.resolvePluginEntry = exports.readPluginManifest = exports.createFrontendPluginMetadata = exports.discoverPluginsFromRoots = exports.discoverPlugins = exports.arrayUnique = exports.toText = exports.toNumber = exports.toBoolean = exports.supposeValue = exports.isEmpty = exports.configureEntityParams = exports.systemInfo = exports.QueryWrapper = exports.QueryMapWrapper = exports.MySqlSource = exports.LocalFileSource = exports.killProcess = exports.ProcessWrapper = void 0;
|
|
112
|
+
exports.StorageSubsystem = exports.MCServerStatus = exports.InstanceStreamListener = exports.GlobalVariable = exports.normalizeDockerPlatform = exports.normalizeDockerOS = exports.normalizeDockerArchitecture = exports.removeTrail = exports.uninstallNpmPlugin = exports.isEssentialNpmPlugin = exports.npmPluginOperationPending = exports.npmPluginRoots = exports.listNpmPlugins = exports.installNpmPlugin = exports.currentProjectRoot = exports.currentPackageRoot = exports.sortPlugins = exports.resolvePluginEntry = exports.readPluginManifest = exports.createFrontendPluginMetadata = exports.discoverPluginsFromRoots = exports.discoverPlugins = exports.arrayUnique = exports.toText = exports.toNumber = exports.toBoolean = exports.supposeValue = exports.isEmpty = exports.configureEntityParams = exports.systemInfo = exports.QueryWrapper = exports.QueryMapWrapper = exports.MySqlSource = exports.LocalFileSource = exports.killProcess = exports.ProcessWrapper = void 0;
|
|
113
113
|
const global_variable_1 = __importDefault(__webpack_require__("../common/src/global_variable.ts"));
|
|
114
114
|
exports.GlobalVariable = global_variable_1.default;
|
|
115
115
|
const instance_stream_1 = __importDefault(__webpack_require__("../common/src/instance_stream.ts"));
|
|
@@ -141,6 +141,8 @@ __exportStar(__webpack_require__("../common/src/plugin_contract.ts"), exports);
|
|
|
141
141
|
__exportStar(__webpack_require__("../common/src/plugin_overrides.ts"), exports);
|
|
142
142
|
__exportStar(__webpack_require__("../common/src/plugin_lifecycle.ts"), exports);
|
|
143
143
|
__exportStar(__webpack_require__("../common/src/plugin_revision.ts"), exports);
|
|
144
|
+
__exportStar(__webpack_require__("../common/src/plugin_modules.ts"), exports);
|
|
145
|
+
__exportStar(__webpack_require__("../common/src/plugin_watch.ts"), exports);
|
|
144
146
|
__exportStar(__webpack_require__("../common/src/runtime_paths.ts"), exports);
|
|
145
147
|
var plugin_manifest_1 = __webpack_require__("../common/src/plugin_manifest.ts");
|
|
146
148
|
Object.defineProperty(exports, "discoverPlugins", ({ enumerable: true, get: function () { return plugin_manifest_1.discoverPlugins; } }));
|
|
@@ -155,6 +157,8 @@ Object.defineProperty(exports, "currentProjectRoot", ({ enumerable: true, get: f
|
|
|
155
157
|
Object.defineProperty(exports, "installNpmPlugin", ({ enumerable: true, get: function () { return plugin_npm_1.installNpmPlugin; } }));
|
|
156
158
|
Object.defineProperty(exports, "listNpmPlugins", ({ enumerable: true, get: function () { return plugin_npm_1.listNpmPlugins; } }));
|
|
157
159
|
Object.defineProperty(exports, "npmPluginRoots", ({ enumerable: true, get: function () { return plugin_npm_1.npmPluginRoots; } }));
|
|
160
|
+
Object.defineProperty(exports, "npmPluginOperationPending", ({ enumerable: true, get: function () { return plugin_npm_1.npmPluginOperationPending; } }));
|
|
161
|
+
Object.defineProperty(exports, "isEssentialNpmPlugin", ({ enumerable: true, get: function () { return plugin_npm_1.isEssentialNpmPlugin; } }));
|
|
158
162
|
Object.defineProperty(exports, "uninstallNpmPlugin", ({ enumerable: true, get: function () { return plugin_npm_1.uninstallNpmPlugin; } }));
|
|
159
163
|
var string_utils_1 = __webpack_require__("../common/src/string_utils.ts");
|
|
160
164
|
Object.defineProperty(exports, "removeTrail", ({ enumerable: true, get: function () { return string_utils_1.removeTrail; } }));
|
|
@@ -622,7 +626,45 @@ function createFrontendPluginMetadata(manifest, extras = {}) {
|
|
|
622
626
|
};
|
|
623
627
|
}
|
|
624
628
|
const MANIFEST_FILES = ["plugin.json", "manifest.json", "package.json"];
|
|
625
|
-
|
|
629
|
+
const ENTRY_FIELDS = ["backend", "frontend", "panel", "daemon", "main", "entry", "ui"];
|
|
630
|
+
function objectValue(value) {
|
|
631
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
632
|
+
? value
|
|
633
|
+
: {};
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Source plugins keep package.json beside plugin.json. Published npm plugins
|
|
637
|
+
* keep it at the package root, with runtime metadata under elementspanel.<side>.
|
|
638
|
+
* Stop at the first package boundary so a host's metadata cannot reach a plugin.
|
|
639
|
+
*/
|
|
640
|
+
function readPackageMetadata(directory, id) {
|
|
641
|
+
const pluginDirectory = node_path_1.default.resolve(directory);
|
|
642
|
+
let current = pluginDirectory;
|
|
643
|
+
while (true) {
|
|
644
|
+
const filename = node_path_1.default.join(current, "package.json");
|
|
645
|
+
if (node_fs_1.default.existsSync(filename)) {
|
|
646
|
+
const { elementspanel, ...metadata } = objectValue(JSON.parse(node_fs_1.default.readFileSync(filename, "utf8")));
|
|
647
|
+
const { id: packageId, panel, daemon, ...shared } = objectValue(elementspanel);
|
|
648
|
+
const definition = [panel, daemon]
|
|
649
|
+
.map(objectValue)
|
|
650
|
+
.find((side) => typeof side.directory === "string" &&
|
|
651
|
+
node_path_1.default.resolve(current, side.directory) === pluginDirectory);
|
|
652
|
+
if (current !== pluginDirectory && (packageId !== id || !definition))
|
|
653
|
+
return {};
|
|
654
|
+
const { directory: _directory, folder: _folder, ...sideMetadata } = definition ?? {};
|
|
655
|
+
const result = { ...metadata, ...shared, ...sideMetadata };
|
|
656
|
+
// npm's main/entry fields do not define a side's execution entry.
|
|
657
|
+
for (const field of ["dual", ...ENTRY_FIELDS])
|
|
658
|
+
delete result[field];
|
|
659
|
+
return result;
|
|
660
|
+
}
|
|
661
|
+
const parent = node_path_1.default.dirname(current);
|
|
662
|
+
if (parent === current)
|
|
663
|
+
return {};
|
|
664
|
+
current = parent;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/** Merges package metadata with a plugin's identity and entries. Legacy manifests still load. */
|
|
626
668
|
function readPluginManifest(directory, onWarning, fallbackId = node_path_1.default.basename(directory)) {
|
|
627
669
|
for (const file of MANIFEST_FILES) {
|
|
628
670
|
const filePath = node_path_1.default.join(directory, file);
|
|
@@ -635,7 +677,18 @@ function readPluginManifest(directory, onWarning, fallbackId = node_path_1.defau
|
|
|
635
677
|
const id = typeof value.id === "string" ? value.id : fallbackId;
|
|
636
678
|
if (!id.trim())
|
|
637
679
|
return null;
|
|
638
|
-
|
|
680
|
+
const manifest = {
|
|
681
|
+
...value,
|
|
682
|
+
...readPackageMetadata(directory, id.trim()),
|
|
683
|
+
id: id.trim()
|
|
684
|
+
};
|
|
685
|
+
// Identity and execution paths always belong to plugin.json. Package
|
|
686
|
+
// metadata wins for descriptions, priority, configuration and dependencies.
|
|
687
|
+
for (const field of ["version", "dual", ...ENTRY_FIELDS]) {
|
|
688
|
+
if (value[field] !== undefined)
|
|
689
|
+
manifest[field] = value[field];
|
|
690
|
+
}
|
|
691
|
+
return manifest;
|
|
639
692
|
}
|
|
640
693
|
catch (error) {
|
|
641
694
|
onWarning?.(`Failed to read plugin manifest: ${filePath}`, error);
|
|
@@ -733,6 +786,13 @@ function discoverPluginsFromRoots(roots, options) {
|
|
|
733
786
|
discovered.push({
|
|
734
787
|
...plugin,
|
|
735
788
|
manifest,
|
|
789
|
+
...(root.packageRoot
|
|
790
|
+
? {
|
|
791
|
+
packageRoot: root.packageRoot,
|
|
792
|
+
packageName: root.packageName,
|
|
793
|
+
npmSource: root.npmSource
|
|
794
|
+
}
|
|
795
|
+
: {}),
|
|
736
796
|
...(root.folder ? { folder: root.folder } : {})
|
|
737
797
|
});
|
|
738
798
|
}
|
|
@@ -746,6 +806,177 @@ function sortPlugins(plugins) {
|
|
|
746
806
|
}
|
|
747
807
|
|
|
748
808
|
|
|
809
|
+
/***/ },
|
|
810
|
+
|
|
811
|
+
/***/ "../common/src/plugin_modules.ts"
|
|
812
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
816
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
817
|
+
};
|
|
818
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
819
|
+
exports.pluginBackendRevision = pluginBackendRevision;
|
|
820
|
+
exports.forgetPluginModules = forgetPluginModules;
|
|
821
|
+
exports.loadPluginModule = loadPluginModule;
|
|
822
|
+
const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
|
|
823
|
+
const node_path_1 = __importDefault(__webpack_require__("node:path"));
|
|
824
|
+
const node_url_1 = __webpack_require__("node:url");
|
|
825
|
+
const node_crypto_1 = __webpack_require__("node:crypto");
|
|
826
|
+
const node_module_1 = __webpack_require__("node:module");
|
|
827
|
+
const plugin_revision_1 = __webpack_require__("../common/src/plugin_revision.ts");
|
|
828
|
+
const REVISION = "epanelPluginRevision";
|
|
829
|
+
const graphs = new Map();
|
|
830
|
+
const previousRoots = new Map();
|
|
831
|
+
let hooksInstalled = false;
|
|
832
|
+
const sharedModules = new Set([
|
|
833
|
+
"cordis",
|
|
834
|
+
"@cordisjs/core",
|
|
835
|
+
"@cordisjs/logger",
|
|
836
|
+
"@cordisjs/timer",
|
|
837
|
+
"@cordisjs/schema",
|
|
838
|
+
"cosmokit",
|
|
839
|
+
"schemastery",
|
|
840
|
+
"reggol"
|
|
841
|
+
]);
|
|
842
|
+
function dependencyRoots(directory) {
|
|
843
|
+
const visited = new Set([directory]);
|
|
844
|
+
const walk = (root) => {
|
|
845
|
+
const filename = node_path_1.default.join(root, "package.json");
|
|
846
|
+
if (!node_fs_1.default.existsSync(filename))
|
|
847
|
+
return;
|
|
848
|
+
const metadata = JSON.parse(node_fs_1.default.readFileSync(filename, "utf8"));
|
|
849
|
+
const localRequire = (0, node_module_1.createRequire)(filename);
|
|
850
|
+
for (const name of Object.keys({
|
|
851
|
+
...metadata.dependencies,
|
|
852
|
+
...metadata.optionalDependencies
|
|
853
|
+
})) {
|
|
854
|
+
if (sharedModules.has(name))
|
|
855
|
+
continue;
|
|
856
|
+
const target = (localRequire.resolve.paths(name) || [])
|
|
857
|
+
.map((directory) => node_path_1.default.join(directory, name, "package.json"))
|
|
858
|
+
.find((candidate) => node_fs_1.default.existsSync(candidate));
|
|
859
|
+
if (!target)
|
|
860
|
+
continue;
|
|
861
|
+
const dependency = node_fs_1.default.realpathSync(node_path_1.default.dirname(target));
|
|
862
|
+
if (visited.has(dependency))
|
|
863
|
+
continue;
|
|
864
|
+
visited.add(dependency);
|
|
865
|
+
walk(dependency);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
walk(directory);
|
|
869
|
+
visited.delete(directory);
|
|
870
|
+
return [...visited];
|
|
871
|
+
}
|
|
872
|
+
/** Include transitive dependency versions so npm updates replace the affected graph. */
|
|
873
|
+
function pluginBackendRevision(entry, directory) {
|
|
874
|
+
const hash = (0, node_crypto_1.createHash)("sha256").update((0, plugin_revision_1.pluginDirectoryRevision)(node_path_1.default.dirname(entry)));
|
|
875
|
+
for (const root of [directory, ...dependencyRoots(directory)]) {
|
|
876
|
+
const filename = node_path_1.default.join(root, "package.json");
|
|
877
|
+
if (node_fs_1.default.existsSync(filename))
|
|
878
|
+
hash.update(root).update(node_fs_1.default.readFileSync(filename));
|
|
879
|
+
}
|
|
880
|
+
return hash.digest("hex").slice(0, 24);
|
|
881
|
+
}
|
|
882
|
+
function within(root, filename) {
|
|
883
|
+
const relative = node_path_1.default.relative(root, filename);
|
|
884
|
+
return (relative === "" ||
|
|
885
|
+
(!relative.startsWith(`..${node_path_1.default.sep}`) && relative !== ".." && !node_path_1.default.isAbsolute(relative)));
|
|
886
|
+
}
|
|
887
|
+
/** Clear the plugin's complete CJS graph, keeping shared host modules intact. */
|
|
888
|
+
function forgetPluginModules(directory) {
|
|
889
|
+
const runtimeRequire = eval("require");
|
|
890
|
+
const owned = [directory, ...(previousRoots.get(directory) || []), ...dependencyRoots(directory)];
|
|
891
|
+
previousRoots.delete(directory);
|
|
892
|
+
const belongs = (filename) => {
|
|
893
|
+
const parts = filename.split(`${node_path_1.default.sep}node_modules${node_path_1.default.sep}`);
|
|
894
|
+
if (parts.slice(1).some((part) => {
|
|
895
|
+
const name = part.startsWith("@")
|
|
896
|
+
? part.split(node_path_1.default.sep).slice(0, 2).join("/")
|
|
897
|
+
: part.split(node_path_1.default.sep)[0];
|
|
898
|
+
return sharedModules.has(name);
|
|
899
|
+
}))
|
|
900
|
+
return false;
|
|
901
|
+
return owned.some((root) => within(root, filename));
|
|
902
|
+
};
|
|
903
|
+
for (const filename of Object.keys(runtimeRequire.cache)) {
|
|
904
|
+
if (belongs(filename))
|
|
905
|
+
delete runtimeRequire.cache[filename];
|
|
906
|
+
}
|
|
907
|
+
for (const mod of Object.values(runtimeRequire.cache)) {
|
|
908
|
+
if (mod)
|
|
909
|
+
mod.children = mod.children.filter((child) => !belongs(child.filename));
|
|
910
|
+
}
|
|
911
|
+
// npm can move a dependency or change its main entry. Node's CJS resolver
|
|
912
|
+
// retains those paths separately from require.cache.
|
|
913
|
+
const pathCache = runtimeRequire("node:module")._pathCache;
|
|
914
|
+
for (const [key, filename] of Object.entries(pathCache)) {
|
|
915
|
+
if (belongs(filename) || owned.some((root) => key.includes(root)))
|
|
916
|
+
delete pathCache[key];
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
function isEsm(entry) {
|
|
920
|
+
if (entry.endsWith(".mjs"))
|
|
921
|
+
return true;
|
|
922
|
+
if (entry.endsWith(".cjs"))
|
|
923
|
+
return false;
|
|
924
|
+
let directory = node_path_1.default.dirname(entry);
|
|
925
|
+
while (true) {
|
|
926
|
+
const filename = node_path_1.default.join(directory, "package.json");
|
|
927
|
+
if (node_fs_1.default.existsSync(filename))
|
|
928
|
+
return JSON.parse(node_fs_1.default.readFileSync(filename, "utf8")).type === "module";
|
|
929
|
+
const parent = node_path_1.default.dirname(directory);
|
|
930
|
+
if (parent === directory)
|
|
931
|
+
return false;
|
|
932
|
+
directory = parent;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
/** Give an ESM entry and its local imports the same immutable revision URL. */
|
|
936
|
+
async function loadPluginModule(entry, directory, revision) {
|
|
937
|
+
const runtimeRequire = eval("require");
|
|
938
|
+
previousRoots.set(directory, dependencyRoots(directory));
|
|
939
|
+
if (!isEsm(entry)) {
|
|
940
|
+
try {
|
|
941
|
+
return runtimeRequire(entry);
|
|
942
|
+
}
|
|
943
|
+
catch (error) {
|
|
944
|
+
if (error?.code !== "ERR_REQUIRE_ESM")
|
|
945
|
+
throw error;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
graphs.set(revision, [directory, ...dependencyRoots(directory)]);
|
|
949
|
+
if (!hooksInstalled) {
|
|
950
|
+
const { registerHooks } = runtimeRequire("node:module");
|
|
951
|
+
if (typeof registerHooks !== "function")
|
|
952
|
+
throw new Error("ESM plugin updates require Node.js 22.15 or newer.");
|
|
953
|
+
registerHooks({
|
|
954
|
+
resolve(specifier, context, nextResolve) {
|
|
955
|
+
const resolved = nextResolve(specifier, context);
|
|
956
|
+
if (!context.parentURL?.startsWith("file:") || !resolved.url.startsWith("file:"))
|
|
957
|
+
return resolved;
|
|
958
|
+
const parent = new URL(context.parentURL);
|
|
959
|
+
const parentRevision = parent.searchParams.get(REVISION);
|
|
960
|
+
if (!parentRevision)
|
|
961
|
+
return resolved;
|
|
962
|
+
const roots = graphs.get(parentRevision);
|
|
963
|
+
if (!roots?.some((root) => within(root, (0, node_url_1.fileURLToPath)(parent))) ||
|
|
964
|
+
!roots.some((root) => within(root, (0, node_url_1.fileURLToPath)(resolved.url))))
|
|
965
|
+
return resolved;
|
|
966
|
+
const url = new URL(resolved.url);
|
|
967
|
+
url.searchParams.set(REVISION, parentRevision);
|
|
968
|
+
return { ...resolved, url: url.href };
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
hooksInstalled = true;
|
|
972
|
+
}
|
|
973
|
+
const url = (0, node_url_1.pathToFileURL)(entry);
|
|
974
|
+
url.searchParams.set(REVISION, revision);
|
|
975
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
976
|
+
return dynamicImport(url.href);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
|
|
749
980
|
/***/ },
|
|
750
981
|
|
|
751
982
|
/***/ "../common/src/plugin_npm.ts"
|
|
@@ -760,15 +991,19 @@ exports.currentPackageRoot = currentPackageRoot;
|
|
|
760
991
|
exports.currentProjectRoot = currentProjectRoot;
|
|
761
992
|
exports.npmPluginRoots = npmPluginRoots;
|
|
762
993
|
exports.listNpmPlugins = listNpmPlugins;
|
|
994
|
+
exports.npmPluginOperationPending = npmPluginOperationPending;
|
|
995
|
+
exports.isEssentialNpmPlugin = isEssentialNpmPlugin;
|
|
763
996
|
exports.installNpmPlugin = installNpmPlugin;
|
|
764
997
|
exports.uninstallNpmPlugin = uninstallNpmPlugin;
|
|
765
998
|
const child_process_1 = __webpack_require__("child_process");
|
|
766
999
|
const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
|
|
767
1000
|
const path_1 = __importDefault(__webpack_require__("path"));
|
|
768
1001
|
const module_1 = __webpack_require__("module");
|
|
1002
|
+
const plugin_manifest_1 = __webpack_require__("../common/src/plugin_manifest.ts");
|
|
1003
|
+
const plugin_contract_1 = __webpack_require__("../common/src/plugin_contract.ts");
|
|
769
1004
|
const PLUGIN_ID = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
770
1005
|
const PACKAGE_NAME = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
|
|
771
|
-
const VERSION = /^[
|
|
1006
|
+
const VERSION = /^[a-zA-Z0-9][a-zA-Z0-9._+-]{0,63}$/;
|
|
772
1007
|
function readJson(filename) {
|
|
773
1008
|
try {
|
|
774
1009
|
const parsed = JSON.parse(fs_extra_1.default.readFileSync(filename, "utf8"));
|
|
@@ -834,8 +1069,20 @@ function pluginRecord(pluginId, name, source, packageRoot, directory, folder, ve
|
|
|
834
1069
|
return { pluginId, name, version, sides: [], directory, folder, packageRoot, source };
|
|
835
1070
|
}
|
|
836
1071
|
function readPackageEntry(packageRoot, name) {
|
|
837
|
-
|
|
838
|
-
|
|
1072
|
+
// Read package boundaries directly: Node caches require.resolve() paths even
|
|
1073
|
+
// after npm moves an installation between nested and hoisted node_modules.
|
|
1074
|
+
let manifestPath;
|
|
1075
|
+
for (const root of [packageRoot, currentProjectRoot(packageRoot)]) {
|
|
1076
|
+
const localRequire = (0, module_1.createRequire)(path_1.default.join(root, "package.json"));
|
|
1077
|
+
manifestPath = (localRequire.resolve.paths(name) || [])
|
|
1078
|
+
.map((directory) => path_1.default.join(directory, name, "package.json"))
|
|
1079
|
+
.find((filename) => fs_extra_1.default.existsSync(filename));
|
|
1080
|
+
if (manifestPath)
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
if (!manifestPath)
|
|
1084
|
+
throw new Error(`Missing npm plugin package: ${name}.`);
|
|
1085
|
+
manifestPath = fs_extra_1.default.realpathSync(manifestPath);
|
|
839
1086
|
const metadata = readJson(manifestPath);
|
|
840
1087
|
if (!metadata)
|
|
841
1088
|
throw new Error(`Missing package metadata for ${name}.`);
|
|
@@ -849,7 +1096,10 @@ function sideDirectory(packageRoot, metadata, side) {
|
|
|
849
1096
|
return undefined;
|
|
850
1097
|
const target = path_1.default.resolve(packageRoot, directory);
|
|
851
1098
|
const relative = path_1.default.relative(packageRoot, target);
|
|
852
|
-
if (relative === "" ||
|
|
1099
|
+
if (relative === "" ||
|
|
1100
|
+
relative === ".." ||
|
|
1101
|
+
relative.startsWith(`..${path_1.default.sep}`) ||
|
|
1102
|
+
path_1.default.isAbsolute(relative))
|
|
853
1103
|
return undefined;
|
|
854
1104
|
return target;
|
|
855
1105
|
}
|
|
@@ -866,7 +1116,7 @@ function recordFromPackage(pluginId, name, source, packageRoot, metadata, side)
|
|
|
866
1116
|
return undefined;
|
|
867
1117
|
const directory = sideDirectory(packageRoot, metadata, target);
|
|
868
1118
|
const folder = stringValue(objectValue(elements[target])?.folder);
|
|
869
|
-
if (!directory || !folder)
|
|
1119
|
+
if (!directory || !PLUGIN_ID.test(folder))
|
|
870
1120
|
return undefined;
|
|
871
1121
|
return {
|
|
872
1122
|
...pluginRecord(pluginId, name, source, packageRoot, directory, folder, version),
|
|
@@ -886,9 +1136,24 @@ function listNpmPlugins(side, options = {}) {
|
|
|
886
1136
|
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
887
1137
|
if (!host)
|
|
888
1138
|
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
889
|
-
const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot)
|
|
1139
|
+
const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot)
|
|
1140
|
+
? null
|
|
1141
|
+
: readProjectManifest(projectRoot);
|
|
890
1142
|
const hostMappings = mappingsOf(host);
|
|
891
|
-
const projectMappings = mappingsOf(project);
|
|
1143
|
+
const projectMappings = { ...mappingsOf(project) };
|
|
1144
|
+
for (const name of Object.keys(dependenciesOf(project))) {
|
|
1145
|
+
if (!PACKAGE_NAME.test(name) || Object.values(projectMappings).includes(name))
|
|
1146
|
+
continue;
|
|
1147
|
+
try {
|
|
1148
|
+
const entry = readPackageEntry(projectRoot, name);
|
|
1149
|
+
const id = stringValue(objectValue(entry.metadata.elementspanel)?.id);
|
|
1150
|
+
if (PLUGIN_ID.test(id) && projectMappings[id] === undefined)
|
|
1151
|
+
projectMappings[id] = name;
|
|
1152
|
+
}
|
|
1153
|
+
catch {
|
|
1154
|
+
/* npm may still be writing the package. */
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
892
1157
|
const mappings = new Map();
|
|
893
1158
|
for (const [pluginId, name] of Object.entries(projectMappings)) {
|
|
894
1159
|
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
@@ -898,6 +1163,8 @@ function listNpmPlugins(side, options = {}) {
|
|
|
898
1163
|
for (const [pluginId, name] of Object.entries(hostMappings)) {
|
|
899
1164
|
if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
900
1165
|
continue;
|
|
1166
|
+
if (dependenciesOf(host)[name] === undefined)
|
|
1167
|
+
continue;
|
|
901
1168
|
mappings.set(pluginId, { name, source: "bundled" });
|
|
902
1169
|
}
|
|
903
1170
|
const hostDependencies = dependenciesOf(host);
|
|
@@ -913,7 +1180,7 @@ function listNpmPlugins(side, options = {}) {
|
|
|
913
1180
|
}
|
|
914
1181
|
let entry;
|
|
915
1182
|
try {
|
|
916
|
-
entry = readPackageEntry(packageRoot, mapping.name);
|
|
1183
|
+
entry = readPackageEntry(mapping.source === "project" ? projectRoot : packageRoot, mapping.name);
|
|
917
1184
|
}
|
|
918
1185
|
catch (error) {
|
|
919
1186
|
if (options.skipInvalid)
|
|
@@ -945,7 +1212,12 @@ function runNpm(args, cwd) {
|
|
|
945
1212
|
: process.platform === "win32"
|
|
946
1213
|
? {
|
|
947
1214
|
command: process.env.ComSpec || "cmd.exe",
|
|
948
|
-
args: [
|
|
1215
|
+
args: [
|
|
1216
|
+
"/d",
|
|
1217
|
+
"/s",
|
|
1218
|
+
"/c",
|
|
1219
|
+
`npm ${args.map((item) => `"${item.replace(/"/g, '""')}"`).join(" ")}`
|
|
1220
|
+
],
|
|
949
1221
|
shell: false
|
|
950
1222
|
}
|
|
951
1223
|
: { command: "npm", args, shell: false };
|
|
@@ -964,9 +1236,10 @@ function runNpm(args, cwd) {
|
|
|
964
1236
|
};
|
|
965
1237
|
child.stdout?.on("data", append);
|
|
966
1238
|
child.stderr?.on("data", append);
|
|
1239
|
+
const action = args.find((argument) => argument === "install" || argument === "uninstall") || "operation";
|
|
967
1240
|
const timer = setTimeout(() => {
|
|
968
1241
|
child.kill("SIGKILL");
|
|
969
|
-
reject(new Error(`npm ${
|
|
1242
|
+
reject(new Error(`npm ${action} timed out.`));
|
|
970
1243
|
}, 10 * 60 * 1000);
|
|
971
1244
|
timer.unref?.();
|
|
972
1245
|
child.once("error", (error) => {
|
|
@@ -977,15 +1250,69 @@ function runNpm(args, cwd) {
|
|
|
977
1250
|
clearTimeout(timer);
|
|
978
1251
|
if (code === 0)
|
|
979
1252
|
return resolve(output);
|
|
980
|
-
reject(new Error(`npm ${
|
|
1253
|
+
reject(new Error(`npm ${action} failed (${code}): ${output.trim()}`));
|
|
981
1254
|
});
|
|
982
1255
|
});
|
|
983
1256
|
}
|
|
984
|
-
const
|
|
1257
|
+
const operationsKey = Symbol.for("elementspanel.npm.operations");
|
|
1258
|
+
const shared = globalThis;
|
|
1259
|
+
const operations = (shared[operationsKey] ??= new Map());
|
|
1260
|
+
const LOCK_NAME = ".elementspanel-npm.lock";
|
|
1261
|
+
async function acquireProjectLock(projectRoot) {
|
|
1262
|
+
await fs_extra_1.default.ensureDir(projectRoot);
|
|
1263
|
+
const directory = path_1.default.join(projectRoot, LOCK_NAME);
|
|
1264
|
+
const deadline = Date.now() + 11 * 60 * 1000;
|
|
1265
|
+
while (true) {
|
|
1266
|
+
try {
|
|
1267
|
+
await fs_extra_1.default.mkdir(directory);
|
|
1268
|
+
await fs_extra_1.default.writeJson(path_1.default.join(directory, "owner.json"), { pid: process.pid });
|
|
1269
|
+
return () => fs_extra_1.default.remove(directory);
|
|
1270
|
+
}
|
|
1271
|
+
catch (error) {
|
|
1272
|
+
if (error.code !== "EEXIST")
|
|
1273
|
+
throw error;
|
|
1274
|
+
try {
|
|
1275
|
+
const owner = await fs_extra_1.default.readJson(path_1.default.join(directory, "owner.json"));
|
|
1276
|
+
try {
|
|
1277
|
+
process.kill(owner.pid, 0);
|
|
1278
|
+
}
|
|
1279
|
+
catch (failure) {
|
|
1280
|
+
if (failure.code === "ESRCH") {
|
|
1281
|
+
await fs_extra_1.default.remove(directory);
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
catch {
|
|
1287
|
+
if (Date.now() - ((await fs_extra_1.default.stat(directory).catch(() => null))?.mtimeMs ?? Date.now()) >
|
|
1288
|
+
60_000) {
|
|
1289
|
+
await fs_extra_1.default.remove(directory);
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
if (Date.now() > deadline)
|
|
1294
|
+
throw new Error("Another npm plugin operation is still running.");
|
|
1295
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
function npmPluginOperationPending() {
|
|
1300
|
+
const { packageRoot, projectRoot } = npmPluginRoots();
|
|
1301
|
+
return (operations.size > 0 ||
|
|
1302
|
+
[packageRoot, projectRoot].some((root) => fs_extra_1.default.existsSync(path_1.default.join(root, LOCK_NAME))));
|
|
1303
|
+
}
|
|
985
1304
|
function withProjectLock(projectRoot, operation) {
|
|
986
1305
|
const key = process.platform === "win32" ? projectRoot.toLowerCase() : projectRoot;
|
|
987
1306
|
const previous = operations.get(key) ?? Promise.resolve();
|
|
988
|
-
const result = previous.then(
|
|
1307
|
+
const result = previous.then(async () => {
|
|
1308
|
+
const release = await acquireProjectLock(projectRoot);
|
|
1309
|
+
try {
|
|
1310
|
+
return await operation();
|
|
1311
|
+
}
|
|
1312
|
+
finally {
|
|
1313
|
+
await release();
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
989
1316
|
const settled = result.then(() => { }, () => { });
|
|
990
1317
|
operations.set(key, settled);
|
|
991
1318
|
return result.finally(() => {
|
|
@@ -993,18 +1320,18 @@ function withProjectLock(projectRoot, operation) {
|
|
|
993
1320
|
operations.delete(key);
|
|
994
1321
|
});
|
|
995
1322
|
}
|
|
996
|
-
/**
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
*/
|
|
1323
|
+
/** Core services keep the connection and management interface available. */
|
|
1324
|
+
function isEssentialNpmPlugin(pluginId) {
|
|
1325
|
+
return ["i18n", "storage", "runtime", "server", "console", "config"].includes(pluginId);
|
|
1326
|
+
}
|
|
1327
|
+
/** npm changes dependencies and lockfiles; only append our plugin mapping afterwards. */
|
|
1002
1328
|
async function installNpmPlugin(options) {
|
|
1003
|
-
const { name,
|
|
1004
|
-
|
|
1005
|
-
throw new Error(`Invalid plugin id: ${pluginId}`);
|
|
1329
|
+
const { name, side } = options;
|
|
1330
|
+
const version = options.version || "latest";
|
|
1006
1331
|
if (!PACKAGE_NAME.test(name))
|
|
1007
1332
|
throw new Error(`Invalid npm plugin package: ${name}`);
|
|
1333
|
+
if (options.pluginId && !PLUGIN_ID.test(options.pluginId))
|
|
1334
|
+
throw new Error(`Invalid plugin id: ${options.pluginId}`);
|
|
1008
1335
|
if (!VERSION.test(version))
|
|
1009
1336
|
throw new Error(`Invalid plugin version: ${version}`);
|
|
1010
1337
|
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
@@ -1012,64 +1339,154 @@ async function installNpmPlugin(options) {
|
|
|
1012
1339
|
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1013
1340
|
if (!host)
|
|
1014
1341
|
throw new Error(`Missing runtime package metadata: ${packageRoot}`);
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1342
|
+
const hostId = Object.entries(mappingsOf(host)).find(([, value]) => value === name && dependenciesOf(host)[name] !== undefined)?.[0];
|
|
1343
|
+
const targetRoot = hostId ? packageRoot : projectRoot;
|
|
1344
|
+
if (hostId && isEssentialNpmPlugin(hostId))
|
|
1345
|
+
throw new Error(`The essential plugin "${hostId}" cannot be replaced while running.`);
|
|
1346
|
+
if (options.pluginId &&
|
|
1347
|
+
mappingsOf(host)[options.pluginId] &&
|
|
1348
|
+
dependenciesOf(host)[String(mappingsOf(host)[options.pluginId])] !== undefined &&
|
|
1349
|
+
mappingsOf(host)[options.pluginId] !== name)
|
|
1350
|
+
throw new Error(`BUNDLED:${options.pluginId}`);
|
|
1351
|
+
const original = readProjectManifest(targetRoot);
|
|
1352
|
+
const previous = dependenciesOf(original)[name];
|
|
1353
|
+
let previousVersion = previous;
|
|
1354
|
+
if (previous) {
|
|
1355
|
+
try {
|
|
1356
|
+
previousVersion = readPackageEntry(targetRoot, name).metadata.version || previous;
|
|
1357
|
+
}
|
|
1358
|
+
catch {
|
|
1359
|
+
/* Keep the declared spec if the previous package is incomplete. */
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
const backups = new Map();
|
|
1363
|
+
for (const filename of ["package.json", "package-lock.json", "npm-shrinkwrap.json"]) {
|
|
1364
|
+
const target = path_1.default.join(targetRoot, filename);
|
|
1365
|
+
backups.set(target, fs_extra_1.default.existsSync(target) ? fs_extra_1.default.readFileSync(target) : null);
|
|
1366
|
+
}
|
|
1023
1367
|
try {
|
|
1024
|
-
|
|
1368
|
+
await runNpm([
|
|
1369
|
+
"--prefix",
|
|
1370
|
+
targetRoot,
|
|
1371
|
+
"install",
|
|
1372
|
+
`${name}@${version}`,
|
|
1373
|
+
"--save",
|
|
1374
|
+
"--save-exact",
|
|
1375
|
+
"--no-fund",
|
|
1376
|
+
"--no-audit",
|
|
1377
|
+
"--ignore-scripts"
|
|
1378
|
+
], targetRoot);
|
|
1379
|
+
const entry = readPackageEntry(targetRoot, name);
|
|
1380
|
+
const pluginId = options.pluginId || stringValue(objectValue(entry.metadata.elementspanel)?.id);
|
|
1381
|
+
if (!PLUGIN_ID.test(pluginId))
|
|
1382
|
+
throw new Error(`Invalid plugin id in ${name}.`);
|
|
1383
|
+
if (mappingsOf(host)[pluginId] &&
|
|
1384
|
+
dependenciesOf(host)[String(mappingsOf(host)[pluginId])] !== undefined &&
|
|
1385
|
+
mappingsOf(host)[pluginId] !== name)
|
|
1386
|
+
throw new Error(`Plugin id ${pluginId} belongs to a bundled dependency.`);
|
|
1387
|
+
if (hostId && pluginId !== hostId)
|
|
1388
|
+
throw new Error(`The package ${name} changed its plugin id from ${hostId} to ${pluginId}.`);
|
|
1389
|
+
const mapped = mappingsOf(readProjectManifest(targetRoot))[pluginId];
|
|
1390
|
+
if (mapped !== undefined && mapped !== name)
|
|
1391
|
+
throw new Error(`Plugin id ${pluginId} is already installed as ${String(mapped)}.`);
|
|
1392
|
+
const record = recordFromPackage(pluginId, name, hostId ? "bundled" : "project", entry.root, entry.metadata, side);
|
|
1393
|
+
if (!record)
|
|
1394
|
+
throw new Error(`The package ${name} does not provide a ${side} plugin named ${pluginId}.`);
|
|
1395
|
+
if (/^[0-9]/.test(version) && record.version !== version)
|
|
1396
|
+
throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
|
|
1397
|
+
if (!process.env.EPANEL_PACKAGE_ROOT &&
|
|
1398
|
+
(0, plugin_manifest_1.discoverPlugins)(path_1.default.join(packageRoot, "plugins"), {
|
|
1399
|
+
entryFields: [],
|
|
1400
|
+
includeDisabled: true
|
|
1401
|
+
}).some((plugin) => plugin.manifest.id === pluginId))
|
|
1402
|
+
throw new Error(`Source plugin ${pluginId} cannot be replaced with an npm dependency.`);
|
|
1403
|
+
const manifest = (0, plugin_manifest_1.readPluginManifest)(record.directory);
|
|
1404
|
+
if (!manifest || manifest.id !== pluginId || manifest.version !== record.version)
|
|
1405
|
+
throw new Error(`The plugin manifest in ${name} does not match its package.`);
|
|
1406
|
+
(0, plugin_contract_1.validatePluginCompatibility)(manifest.elements);
|
|
1407
|
+
for (const field of ["backend", "frontend", "panel", "daemon", "main", "entry", "ui"]) {
|
|
1408
|
+
if (typeof manifest[field] === "string" &&
|
|
1409
|
+
!(0, plugin_manifest_1.resolvePluginEntry)(record.directory, manifest, { entryFields: [field] }))
|
|
1410
|
+
throw new Error(`Invalid ${field} entry in ${name}.`);
|
|
1411
|
+
}
|
|
1412
|
+
const others = listNpmPlugins(side, { packageRoot, projectRoot, skipInvalid: true });
|
|
1413
|
+
if (others.some((plugin) => plugin.pluginId === pluginId && plugin.name !== name))
|
|
1414
|
+
throw new Error(`Plugin id ${pluginId} is already provided by another dependency.`);
|
|
1415
|
+
const collision = others.find((plugin) => plugin.pluginId !== pluginId && plugin.folder === record.folder);
|
|
1416
|
+
if (collision)
|
|
1417
|
+
throw new Error(`Plugin asset directory ${record.folder} is already used by ${collision.name}.`);
|
|
1418
|
+
const updated = readProjectManifest(targetRoot);
|
|
1419
|
+
updated.dependencies = { ...dependenciesOf(updated), [name]: record.version };
|
|
1420
|
+
updated.elementspanel = {
|
|
1421
|
+
...objectValue(updated.elementspanel),
|
|
1422
|
+
plugins: { ...mappingsOf(updated), [pluginId]: name }
|
|
1423
|
+
};
|
|
1424
|
+
writeProjectManifest(targetRoot, updated);
|
|
1425
|
+
return record;
|
|
1025
1426
|
}
|
|
1026
1427
|
catch (error) {
|
|
1027
|
-
|
|
1428
|
+
try {
|
|
1429
|
+
await runNpm(previous
|
|
1430
|
+
? [
|
|
1431
|
+
"--prefix",
|
|
1432
|
+
targetRoot,
|
|
1433
|
+
"install",
|
|
1434
|
+
`${name}@${String(previousVersion)}`,
|
|
1435
|
+
"--save",
|
|
1436
|
+
"--no-fund",
|
|
1437
|
+
"--no-audit",
|
|
1438
|
+
"--ignore-scripts"
|
|
1439
|
+
]
|
|
1440
|
+
: [
|
|
1441
|
+
"--prefix",
|
|
1442
|
+
targetRoot,
|
|
1443
|
+
"uninstall",
|
|
1444
|
+
name,
|
|
1445
|
+
"--no-fund",
|
|
1446
|
+
"--no-audit",
|
|
1447
|
+
"--ignore-scripts"
|
|
1448
|
+
], targetRoot);
|
|
1449
|
+
}
|
|
1450
|
+
catch (rollback) {
|
|
1451
|
+
throw new Error(`${String(error)}; npm rollback failed: ${String(rollback)}`);
|
|
1452
|
+
}
|
|
1453
|
+
finally {
|
|
1454
|
+
for (const [filename, content] of backups) {
|
|
1455
|
+
if (content === null)
|
|
1456
|
+
await fs_extra_1.default.remove(filename);
|
|
1457
|
+
else
|
|
1458
|
+
await fs_extra_1.default.writeFile(filename, content);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1028
1461
|
throw error;
|
|
1029
1462
|
}
|
|
1030
|
-
const record = recordFromPackage(pluginId, name, "project", entry.root, entry.metadata, side);
|
|
1031
|
-
if (!record) {
|
|
1032
|
-
await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
|
|
1033
|
-
throw new Error(`The package ${name} does not provide a ${side} plugin named ${pluginId}.`);
|
|
1034
|
-
}
|
|
1035
|
-
if (record.version !== version) {
|
|
1036
|
-
await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
|
|
1037
|
-
throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
|
|
1038
|
-
}
|
|
1039
|
-
const manifest = readProjectManifest(projectRoot);
|
|
1040
|
-
const dependencies = { ...dependenciesOf(manifest), [name]: version };
|
|
1041
|
-
const elementspanel = { ...(objectValue(manifest.elementspanel) ?? {}) };
|
|
1042
|
-
const plugins = { ...mappingsOf(manifest), [pluginId]: name };
|
|
1043
|
-
manifest.dependencies = dependencies;
|
|
1044
|
-
manifest.elementspanel = { ...elementspanel, plugins };
|
|
1045
|
-
writeProjectManifest(projectRoot, manifest);
|
|
1046
|
-
return record;
|
|
1047
1463
|
});
|
|
1048
1464
|
}
|
|
1049
|
-
/**
|
|
1465
|
+
/** Remove the dependency from the manifest that owns it, preserving user configuration. */
|
|
1050
1466
|
async function uninstallNpmPlugin(pluginId, options = {}) {
|
|
1051
1467
|
if (!PLUGIN_ID.test(pluginId))
|
|
1052
1468
|
throw new Error(`Invalid plugin id: ${pluginId}`);
|
|
1469
|
+
if (isEssentialNpmPlugin(pluginId))
|
|
1470
|
+
throw new Error(`The essential plugin "${pluginId}" cannot be uninstalled.`);
|
|
1053
1471
|
const { packageRoot, projectRoot } = npmPluginRoots(options);
|
|
1054
1472
|
return withProjectLock(projectRoot, async () => {
|
|
1055
1473
|
const host = readJson(path_1.default.join(packageRoot, "package.json"));
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1474
|
+
const bundledName = mappingsOf(host)[pluginId];
|
|
1475
|
+
const targetRoot = typeof bundledName === "string" && dependenciesOf(host)[bundledName] !== undefined
|
|
1476
|
+
? packageRoot
|
|
1477
|
+
: projectRoot;
|
|
1478
|
+
const manifest = readProjectManifest(targetRoot);
|
|
1479
|
+
const name = mappingsOf(manifest)[pluginId] ??
|
|
1480
|
+
listNpmPlugins(undefined, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId)?.name;
|
|
1060
1481
|
if (typeof name !== "string" || !PACKAGE_NAME.test(name))
|
|
1061
1482
|
return null;
|
|
1062
1483
|
const record = listNpmPlugins(undefined, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId);
|
|
1063
|
-
await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"],
|
|
1064
|
-
const
|
|
1484
|
+
await runNpm(["--prefix", targetRoot, "uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], targetRoot);
|
|
1485
|
+
const updated = readProjectManifest(targetRoot);
|
|
1486
|
+
const plugins = { ...mappingsOf(updated) };
|
|
1065
1487
|
delete plugins[pluginId];
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
elementspanel.plugins = plugins;
|
|
1069
|
-
else
|
|
1070
|
-
delete elementspanel.plugins;
|
|
1071
|
-
manifest.elementspanel = elementspanel;
|
|
1072
|
-
writeProjectManifest(projectRoot, manifest);
|
|
1488
|
+
updated.elementspanel = { ...objectValue(updated.elementspanel), plugins };
|
|
1489
|
+
writeProjectManifest(targetRoot, updated);
|
|
1073
1490
|
return record ?? null;
|
|
1074
1491
|
});
|
|
1075
1492
|
}
|
|
@@ -1218,6 +1635,82 @@ function pluginDirectoryRevision(directory) {
|
|
|
1218
1635
|
}
|
|
1219
1636
|
|
|
1220
1637
|
|
|
1638
|
+
/***/ },
|
|
1639
|
+
|
|
1640
|
+
/***/ "../common/src/plugin_watch.ts"
|
|
1641
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
1642
|
+
|
|
1643
|
+
|
|
1644
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
1645
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
1646
|
+
};
|
|
1647
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
1648
|
+
exports.watchNpmPlugins = watchNpmPlugins;
|
|
1649
|
+
const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
|
|
1650
|
+
const node_path_1 = __importDefault(__webpack_require__("node:path"));
|
|
1651
|
+
const plugin_npm_1 = __webpack_require__("../common/src/plugin_npm.ts");
|
|
1652
|
+
/** Poll package boundaries, allowing npm to finish replacing files before reconciliation. */
|
|
1653
|
+
function watchNpmPlugins(ctx, side, reload, changed) {
|
|
1654
|
+
const stamp = () => {
|
|
1655
|
+
const { packageRoot, projectRoot } = (0, plugin_npm_1.npmPluginRoots)();
|
|
1656
|
+
if (!node_fs_1.default.existsSync(node_path_1.default.join(packageRoot, "package.json")))
|
|
1657
|
+
return "";
|
|
1658
|
+
const files = [];
|
|
1659
|
+
for (const root of [packageRoot, projectRoot])
|
|
1660
|
+
for (const name of [
|
|
1661
|
+
"package.json",
|
|
1662
|
+
"package-lock.json",
|
|
1663
|
+
"npm-shrinkwrap.json",
|
|
1664
|
+
"node_modules/.package-lock.json"
|
|
1665
|
+
])
|
|
1666
|
+
files.push(node_path_1.default.join(root, name));
|
|
1667
|
+
for (const plugin of (0, plugin_npm_1.listNpmPlugins)(side, { skipInvalid: true }))
|
|
1668
|
+
files.push(node_path_1.default.join(plugin.packageRoot, "package.json"), node_path_1.default.join(plugin.directory, "plugin.json"));
|
|
1669
|
+
return JSON.stringify(files.map((filename) => {
|
|
1670
|
+
try {
|
|
1671
|
+
const stat = node_fs_1.default.statSync(filename);
|
|
1672
|
+
return [filename, stat.size, stat.mtimeMs, stat.ctimeMs];
|
|
1673
|
+
}
|
|
1674
|
+
catch {
|
|
1675
|
+
return [filename, null];
|
|
1676
|
+
}
|
|
1677
|
+
}));
|
|
1678
|
+
};
|
|
1679
|
+
let applied = stamp();
|
|
1680
|
+
let candidate = applied;
|
|
1681
|
+
let busy = false;
|
|
1682
|
+
ctx.setInterval(() => {
|
|
1683
|
+
if (busy || (0, plugin_npm_1.npmPluginOperationPending)())
|
|
1684
|
+
return;
|
|
1685
|
+
try {
|
|
1686
|
+
const next = stamp();
|
|
1687
|
+
if (next === applied) {
|
|
1688
|
+
candidate = next;
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
if (next !== candidate) {
|
|
1692
|
+
candidate = next;
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
busy = true;
|
|
1696
|
+
void reload()
|
|
1697
|
+
.then(() => {
|
|
1698
|
+
applied = next;
|
|
1699
|
+
candidate = next;
|
|
1700
|
+
changed?.();
|
|
1701
|
+
})
|
|
1702
|
+
.catch((error) => ctx.logger.warn("Failed to synchronize npm plugins", error))
|
|
1703
|
+
.finally(() => {
|
|
1704
|
+
busy = false;
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
catch (error) {
|
|
1708
|
+
ctx.logger.warn("Failed to inspect npm plugins", error);
|
|
1709
|
+
}
|
|
1710
|
+
}, 2000);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
|
|
1221
1714
|
/***/ },
|
|
1222
1715
|
|
|
1223
1716
|
/***/ "../common/src/process_tools.ts"
|
|
@@ -1539,6 +2032,9 @@ function npmPluginRoots(side) {
|
|
|
1539
2032
|
const { resolveNpmPlugins } = runtimeRequire(resolver);
|
|
1540
2033
|
return resolveNpmPlugins(packagePath(), side, { skipInvalid: true }).map((record) => ({
|
|
1541
2034
|
directory: record.directory,
|
|
2035
|
+
packageRoot: record.packageRoot,
|
|
2036
|
+
packageName: record.name,
|
|
2037
|
+
npmSource: record.source,
|
|
1542
2038
|
...(record.folder ? { folder: record.folder } : {}),
|
|
1543
2039
|
// Built-in packages are part of the runtime's default configuration. A
|
|
1544
2040
|
// project dependency is installed but remains dormant until the user
|
|
@@ -2101,6 +2597,13 @@ module.exports = require("node:fs");
|
|
|
2101
2597
|
|
|
2102
2598
|
/***/ },
|
|
2103
2599
|
|
|
2600
|
+
/***/ "node:module"
|
|
2601
|
+
(module) {
|
|
2602
|
+
|
|
2603
|
+
module.exports = require("node:module");
|
|
2604
|
+
|
|
2605
|
+
/***/ },
|
|
2606
|
+
|
|
2104
2607
|
/***/ "node:os"
|
|
2105
2608
|
(module) {
|
|
2106
2609
|
|
|
@@ -2115,6 +2618,13 @@ module.exports = require("node:path");
|
|
|
2115
2618
|
|
|
2116
2619
|
/***/ },
|
|
2117
2620
|
|
|
2621
|
+
/***/ "node:url"
|
|
2622
|
+
(module) {
|
|
2623
|
+
|
|
2624
|
+
module.exports = require("node:url");
|
|
2625
|
+
|
|
2626
|
+
/***/ },
|
|
2627
|
+
|
|
2118
2628
|
/***/ "os"
|
|
2119
2629
|
(module) {
|
|
2120
2630
|
|
|
@@ -2139,84 +2649,84 @@ module.exports = require("process");
|
|
|
2139
2649
|
/***/ "./plugins/config/src/i18n/de_DE.json"
|
|
2140
2650
|
(module) {
|
|
2141
2651
|
|
|
2142
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Der Webserver kann nicht aus der Ferne deaktiviert werden: Das Panel würde die Verbindung verlieren, über die es diesen Daemon verwaltet. Setze enabled auf dem Host in seiner plugin.json auf false.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Eine Plugin-ID ist erforderlich.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Die Plugin-Verwaltung kann sich nicht selbst deaktivieren: Das Panel würde die Events verlieren, mit denen es diesen Daemon verwaltet. Setze enabled auf dem Host in seiner plugin.json auf false."}');
|
|
2652
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Der Webserver kann nicht aus der Ferne deaktiviert werden: Das Panel würde die Verbindung verlieren, über die es diesen Daemon verwaltet. Setze plugins.server.enabled auf dem Host in seiner data/plugin-overrides.json auf false.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Eine Plugin-ID ist erforderlich.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Die Plugin-Verwaltung kann sich nicht selbst deaktivieren: Das Panel würde die Events verlieren, mit denen es diesen Daemon verwaltet. Setze plugins.config.enabled auf dem Host in seiner data/plugin-overrides.json auf false."}');
|
|
2143
2653
|
|
|
2144
2654
|
/***/ },
|
|
2145
2655
|
|
|
2146
2656
|
/***/ "./plugins/config/src/i18n/en_US.json"
|
|
2147
2657
|
(module) {
|
|
2148
2658
|
|
|
2149
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"The web server cannot be disabled remotely: the panel would lose the connection it manages this daemon over. Set enabled to false in its plugin.json on the host instead.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"A plugin id is required.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Plugin management cannot disable itself: the panel would lose the events it administers this daemon with. Set enabled to false in its plugin.json on the host instead."}');
|
|
2659
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"The web server cannot be disabled remotely: the panel would lose the connection it manages this daemon over. Set plugins.server.enabled to false in its data/plugin-overrides.json on the host instead.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"A plugin id is required.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Plugin management cannot disable itself: the panel would lose the events it administers this daemon with. Set plugins.config.enabled to false in its data/plugin-overrides.json on the host instead."}');
|
|
2150
2660
|
|
|
2151
2661
|
/***/ },
|
|
2152
2662
|
|
|
2153
2663
|
/***/ "./plugins/config/src/i18n/es_ES.json"
|
|
2154
2664
|
(module) {
|
|
2155
2665
|
|
|
2156
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"El servidor web no puede desactivarse de forma remota: el panel perdería la conexión con la que administra este demonio. Establece enabled en false en su plugin.json en el host.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Se requiere un id de complemento.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"La gestión de complementos no puede desactivarse a sí misma: el panel perdería los eventos con los que administra este demonio. Establece enabled en false en su plugin.json en el host."}');
|
|
2666
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"El servidor web no puede desactivarse de forma remota: el panel perdería la conexión con la que administra este demonio. Establece plugins.server.enabled en false en su data/plugin-overrides.json en el host.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Se requiere un id de complemento.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"La gestión de complementos no puede desactivarse a sí misma: el panel perdería los eventos con los que administra este demonio. Establece plugins.config.enabled en false en su data/plugin-overrides.json en el host."}');
|
|
2157
2667
|
|
|
2158
2668
|
/***/ },
|
|
2159
2669
|
|
|
2160
2670
|
/***/ "./plugins/config/src/i18n/fr_FR.json"
|
|
2161
2671
|
(module) {
|
|
2162
2672
|
|
|
2163
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Le serveur web ne peut pas être désactivé à distance : le panneau perdrait la connexion par laquelle il administre ce démon. Définissez enabled à false dans son plugin.json sur l hôte.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Un identifiant d extension est requis.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Le gestionnaire d extensions ne peut pas se désactiver lui-même : le panneau perdrait les événements par lesquels il administre ce démon. Définissez enabled à false dans son plugin.json sur l hôte."}');
|
|
2673
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Le serveur web ne peut pas être désactivé à distance : le panneau perdrait la connexion par laquelle il administre ce démon. Définissez plugins.server.enabled à false dans son data/plugin-overrides.json sur l hôte.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Un identifiant d extension est requis.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Le gestionnaire d extensions ne peut pas se désactiver lui-même : le panneau perdrait les événements par lesquels il administre ce démon. Définissez plugins.config.enabled à false dans son data/plugin-overrides.json sur l hôte."}');
|
|
2164
2674
|
|
|
2165
2675
|
/***/ },
|
|
2166
2676
|
|
|
2167
2677
|
/***/ "./plugins/config/src/i18n/ja_JP.json"
|
|
2168
2678
|
(module) {
|
|
2169
2679
|
|
|
2170
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web サーバーはリモートから無効にできません。パネルがこのデーモンを管理している接続を失います。ホスト上で plugin.json の enabled を false に設定してください。","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"プラグイン ID を指定してください。","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"プラグイン管理は自身を無効にできません。パネルがこのデーモンを管理しているイベントを失います。ホスト上で plugin.json の enabled を false に設定してください。"}');
|
|
2680
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web サーバーはリモートから無効にできません。パネルがこのデーモンを管理している接続を失います。ホスト上で data/plugin-overrides.json の plugins.server.enabled を false に設定してください。","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"プラグイン ID を指定してください。","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"プラグイン管理は自身を無効にできません。パネルがこのデーモンを管理しているイベントを失います。ホスト上で data/plugin-overrides.json の plugins.config.enabled を false に設定してください。"}');
|
|
2171
2681
|
|
|
2172
2682
|
/***/ },
|
|
2173
2683
|
|
|
2174
2684
|
/***/ "./plugins/config/src/i18n/ko_KR.json"
|
|
2175
2685
|
(module) {
|
|
2176
2686
|
|
|
2177
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"웹 서버는 원격으로 비활성화할 수 없습니다. 패널이 이 데몬을 관리하는 연결을 잃게 됩니다. 호스트에서 plugin.json의 enabled 를 false 로 설정하세요.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"플러그인 ID가 필요합니다.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"플러그인 관리는 자신을 비활성화할 수 없습니다. 패널이 이 데몬을 관리하는 이벤트를 잃게 됩니다. 호스트에서 plugin.json의 enabled 를 false 로 설정하세요."}');
|
|
2687
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"웹 서버는 원격으로 비활성화할 수 없습니다. 패널이 이 데몬을 관리하는 연결을 잃게 됩니다. 호스트에서 data/plugin-overrides.json의 plugins.server.enabled 를 false 로 설정하세요.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"플러그인 ID가 필요합니다.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"플러그인 관리는 자신을 비활성화할 수 없습니다. 패널이 이 데몬을 관리하는 이벤트를 잃게 됩니다. 호스트에서 data/plugin-overrides.json의 plugins.config.enabled 를 false 로 설정하세요."}');
|
|
2178
2688
|
|
|
2179
2689
|
/***/ },
|
|
2180
2690
|
|
|
2181
2691
|
/***/ "./plugins/config/src/i18n/pt_BR.json"
|
|
2182
2692
|
(module) {
|
|
2183
2693
|
|
|
2184
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"O servidor web não pode ser desativado remotamente: o painel perderia a conexão pela qual administra este daemon. Defina enabled como false no plugin.json dele no host.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"É necessário informar o id do plugin.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"O gerenciador de plugins não pode desativar a si mesmo: o painel perderia os eventos pelos quais administra este daemon. Defina enabled como false no plugin.json dele no host."}');
|
|
2694
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"O servidor web não pode ser desativado remotamente: o painel perderia a conexão pela qual administra este daemon. Defina plugins.server.enabled como false no data/plugin-overrides.json dele no host.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"É necessário informar o id do plugin.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"O gerenciador de plugins não pode desativar a si mesmo: o painel perderia os eventos pelos quais administra este daemon. Defina plugins.config.enabled como false no data/plugin-overrides.json dele no host."}');
|
|
2185
2695
|
|
|
2186
2696
|
/***/ },
|
|
2187
2697
|
|
|
2188
2698
|
/***/ "./plugins/config/src/i18n/ru_RU.json"
|
|
2189
2699
|
(module) {
|
|
2190
2700
|
|
|
2191
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Веб-сервер нельзя отключить удалённо: панель потеряет соединение, через которое управляет этим демоном. Укажите enabled: false в его plugin.json на хосте.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Требуется идентификатор плагина.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Менеджер плагинов не может отключить сам себя: панель потеряет события, через которые управляет этим демоном. Укажите enabled: false в его plugin.json на хосте."}');
|
|
2701
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Веб-сервер нельзя отключить удалённо: панель потеряет соединение, через которое управляет этим демоном. Укажите plugins.server.enabled: false в его data/plugin-overrides.json на хосте.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Требуется идентификатор плагина.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Менеджер плагинов не может отключить сам себя: панель потеряет события, через которые управляет этим демоном. Укажите plugins.config.enabled: false в его data/plugin-overrides.json на хосте."}');
|
|
2192
2702
|
|
|
2193
2703
|
/***/ },
|
|
2194
2704
|
|
|
2195
2705
|
/***/ "./plugins/config/src/i18n/th_TH.json"
|
|
2196
2706
|
(module) {
|
|
2197
2707
|
|
|
2198
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"ไม่สามารถปิดใช้งานเว็บเซิร์ฟเวอร์จากระยะไกลได้ แผงควบคุมจะเสียการเชื่อมต่อที่ใช้จัดการดีมอนนี้ กรุณาตั้ง enabled เป็น false ใน plugin.json ของมันบนเครื่องโฮสต์","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"ต้องระบุรหัสปลั๊กอิน","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"ตัวจัดการปลั๊กอินปิดใช้งานตัวเองไม่ได้ แผงควบคุมจะเสียอีเวนต์ที่ใช้จัดการดีมอนนี้ กรุณาตั้ง enabled เป็น false ใน plugin.json ของมันบนเครื่องโฮสต์"}');
|
|
2708
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"ไม่สามารถปิดใช้งานเว็บเซิร์ฟเวอร์จากระยะไกลได้ แผงควบคุมจะเสียการเชื่อมต่อที่ใช้จัดการดีมอนนี้ กรุณาตั้ง plugins.server.enabled เป็น false ใน data/plugin-overrides.json ของมันบนเครื่องโฮสต์","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"ต้องระบุรหัสปลั๊กอิน","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"ตัวจัดการปลั๊กอินปิดใช้งานตัวเองไม่ได้ แผงควบคุมจะเสียอีเวนต์ที่ใช้จัดการดีมอนนี้ กรุณาตั้ง plugins.config.enabled เป็น false ใน data/plugin-overrides.json ของมันบนเครื่องโฮสต์"}');
|
|
2199
2709
|
|
|
2200
2710
|
/***/ },
|
|
2201
2711
|
|
|
2202
2712
|
/***/ "./plugins/config/src/i18n/tr_TR.json"
|
|
2203
2713
|
(module) {
|
|
2204
2714
|
|
|
2205
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web sunucusu uzaktan devre dışı bırakılamaz: panel bu daemon u yönettiği bağlantıyı kaybeder. Bunun yerine ana makinede plugin.json dosyasında enabled değerini false yapın.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Bir eklenti kimliği gerekli.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Eklenti yöneticisi kendisini devre dışı bırakamaz: panel bu daemon u yönettiği olayları kaybeder. Bunun yerine ana makinede plugin.json dosyasında enabled değerini false yapın."}');
|
|
2715
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web sunucusu uzaktan devre dışı bırakılamaz: panel bu daemon u yönettiği bağlantıyı kaybeder. Bunun yerine ana makinede data/plugin-overrides.json dosyasında plugins.server.enabled değerini false yapın.","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"Bir eklenti kimliği gerekli.","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"Eklenti yöneticisi kendisini devre dışı bırakamaz: panel bu daemon u yönettiği olayları kaybeder. Bunun yerine ana makinede data/plugin-overrides.json dosyasında plugins.config.enabled değerini false yapın."}');
|
|
2206
2716
|
|
|
2207
2717
|
/***/ },
|
|
2208
2718
|
|
|
2209
2719
|
/***/ "./plugins/config/src/i18n/zh_CN.json"
|
|
2210
2720
|
(module) {
|
|
2211
2721
|
|
|
2212
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web 服务器不能远程禁用:面板会失去用来管理这个守护进程的连接。请在宿主机上把它的 plugin.json 里的 enabled 设为 false。","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"必须提供插件 ID。","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"插件管理无法禁用自己:面板会失去用来管理这个守护进程的事件。请在宿主机上把它的 plugin.json 里的 enabled 设为 false。"}');
|
|
2722
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web 服务器不能远程禁用:面板会失去用来管理这个守护进程的连接。请在宿主机上把它的 data/plugin-overrides.json 里的 plugins.server.enabled 设为 false。","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"必须提供插件 ID。","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"插件管理无法禁用自己:面板会失去用来管理这个守护进程的事件。请在宿主机上把它的 data/plugin-overrides.json 里的 plugins.config.enabled 设为 false。"}');
|
|
2213
2723
|
|
|
2214
2724
|
/***/ },
|
|
2215
2725
|
|
|
2216
2726
|
/***/ "./plugins/config/src/i18n/zh_TW.json"
|
|
2217
2727
|
(module) {
|
|
2218
2728
|
|
|
2219
|
-
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web 伺服器不能遠端停用:面板會失去用來管理這個守護行程的連線。請在主機上把它的 plugin.json 裡的 enabled 設為 false。","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"必須提供外掛 ID。","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"外掛管理無法停用自己:面板會失去用來管理這個守護行程的事件。請在主機上把它的 plugin.json 裡的 enabled 設為 false。"}');
|
|
2729
|
+
module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_DAEMON_PLUGIN_ESSENTIAL_DISABLE":"Web 伺服器不能遠端停用:面板會失去用來管理這個守護行程的連線。請在主機上把它的 data/plugin-overrides.json 裡的 plugins.server.enabled 設為 false。","TXT_CODE_DAEMON_PLUGIN_ID_REQUIRED":"必須提供外掛 ID。","TXT_CODE_DAEMON_PLUGIN_SELF_DISABLE":"外掛管理無法停用自己:面板會失去用來管理這個守護行程的事件。請在主機上把它的 data/plugin-overrides.json 裡的 plugins.config.enabled 設為 false。"}');
|
|
2220
2730
|
|
|
2221
2731
|
/***/ }
|
|
2222
2732
|
|
|
@@ -2376,11 +2886,10 @@ function apply(ctx) {
|
|
|
2376
2886
|
ctx.protocol.on("plugin/npm/install", async (routerCtx, data) => {
|
|
2377
2887
|
try {
|
|
2378
2888
|
const payload = (data ?? {});
|
|
2379
|
-
const record = await
|
|
2889
|
+
const record = await ctx.plugins.install({
|
|
2380
2890
|
name: String(payload.name ?? ""),
|
|
2381
|
-
pluginId: String(payload.pluginId
|
|
2382
|
-
version: String(payload.version
|
|
2383
|
-
side: "daemon"
|
|
2891
|
+
pluginId: payload.pluginId ? String(payload.pluginId) : undefined,
|
|
2892
|
+
version: payload.version ? String(payload.version) : undefined
|
|
2384
2893
|
});
|
|
2385
2894
|
ctx.protocol.response(routerCtx, record);
|
|
2386
2895
|
}
|
|
@@ -2391,16 +2900,15 @@ function apply(ctx) {
|
|
|
2391
2900
|
ctx.protocol.on("plugin/npm/uninstall", async (routerCtx, data) => {
|
|
2392
2901
|
try {
|
|
2393
2902
|
const pluginId = String(data?.pluginId ?? "");
|
|
2394
|
-
|
|
2395
|
-
ctx.protocol.response(routerCtx, { removed, pluginId });
|
|
2903
|
+
await ctx.plugins.remove(pluginId);
|
|
2904
|
+
ctx.protocol.response(routerCtx, { removed: true, pluginId });
|
|
2396
2905
|
}
|
|
2397
2906
|
catch (error) {
|
|
2398
2907
|
ctx.protocol.responseError(routerCtx, error);
|
|
2399
2908
|
}
|
|
2400
2909
|
});
|
|
2401
|
-
//
|
|
2402
|
-
//
|
|
2403
|
-
// from a newly loaded plugin are bound to a fresh socket.
|
|
2910
|
+
// Reconcile dependencies and make their current handlers available on
|
|
2911
|
+
// existing authenticated sockets.
|
|
2404
2912
|
ctx.protocol.on("plugin/reload", async (routerCtx) => {
|
|
2405
2913
|
try {
|
|
2406
2914
|
await ctx.plugins.reload();
|