@octonodes/cli 0.2.3 → 0.2.5
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/package.json +2 -2
- package/runtime/plugin-lifecycle.cjs +271 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octonodes/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Octonode API and plugin development CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"prepack": "tsc -b"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@octonodes/sdk": "0.2.
|
|
24
|
+
"@octonodes/sdk": "0.2.5",
|
|
25
25
|
"@supabase/supabase-js": "2.107.0",
|
|
26
26
|
"esbuild": "0.28.1",
|
|
27
27
|
"tar": "7.5.22",
|
|
@@ -11541,7 +11541,7 @@ var require_plugin_publishing = __commonJS({
|
|
|
11541
11541
|
"packages/schema/dist/plugin-publishing.js"(exports2) {
|
|
11542
11542
|
"use strict";
|
|
11543
11543
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11544
|
-
exports2.PluginPublisherConnections = exports2.PluginPublisherConnection = exports2.PluginPublisherPreview = exports2.PluginPublisherConsent = exports2.PluginPublisherAutomatic = exports2.PluginPublisherRepository = exports2.PluginPublisherInput = exports2.pluginReleaseScope = exports2.PluginReleaseConfig = exports2.PluginConfigPath = void 0;
|
|
11544
|
+
exports2.PluginCloudBuild = exports2.PluginPublisherBuildDetail = exports2.PluginPublisherBuilds = exports2.PluginPublisherBuildQuery = exports2.PluginPublisherApplied = exports2.PluginPublisherApply = exports2.PluginPublisherReview = exports2.PluginPublisherReviewItem = exports2.PluginPublisherOperation = exports2.PluginPublisherConnections = exports2.PluginPublisherConnection = exports2.PluginPublisherPreview = exports2.PluginPublisherConsent = exports2.PluginPublisherAutomatic = exports2.PluginPublisherRepository = exports2.PluginPublisherInput = exports2.pluginReleaseScope = exports2.PluginReleaseConfig = exports2.PluginConfigPath = void 0;
|
|
11545
11545
|
var zod_1 = require("zod");
|
|
11546
11546
|
var plugin_version_1 = require_plugin_version();
|
|
11547
11547
|
exports2.PluginConfigPath = zod_1.z.string().max(512).refine((path) => /^(?:[a-zA-Z0-9_.-]+\/)*(?:plugin\.octonode\.(?:json|ya?ml)|octonode\.plugin\.json)$/.test(path) && !path.split("/").some((part) => [".", "..", ".git", "node_modules"].includes(part)), "Select a repository-relative octonode.plugin.json file (older plugin.octonode release files also work)");
|
|
@@ -11585,6 +11585,88 @@ var require_plugin_publishing = __commonJS({
|
|
|
11585
11585
|
lastPublishedAt: zod_1.z.number().nullable()
|
|
11586
11586
|
});
|
|
11587
11587
|
exports2.PluginPublisherConnections = zod_1.z.object({ items: zod_1.z.array(exports2.PluginPublisherConnection) });
|
|
11588
|
+
exports2.PluginPublisherOperation = zod_1.z.enum(["create", "update", "delete"]);
|
|
11589
|
+
exports2.PluginPublisherReviewItem = zod_1.z.object({
|
|
11590
|
+
configPath: exports2.PluginConfigPath,
|
|
11591
|
+
config: exports2.PluginReleaseConfig,
|
|
11592
|
+
sha256: zod_1.z.string(),
|
|
11593
|
+
connectionId: zod_1.z.string().nullable(),
|
|
11594
|
+
missing: zod_1.z.boolean()
|
|
11595
|
+
});
|
|
11596
|
+
exports2.PluginPublisherReview = zod_1.z.object({
|
|
11597
|
+
repositoryId: zod_1.z.number(),
|
|
11598
|
+
repository: zod_1.z.string(),
|
|
11599
|
+
branch: zod_1.z.string(),
|
|
11600
|
+
headSha: zod_1.z.string(),
|
|
11601
|
+
revision: zod_1.z.string(),
|
|
11602
|
+
items: zod_1.z.array(exports2.PluginPublisherReviewItem)
|
|
11603
|
+
});
|
|
11604
|
+
exports2.PluginPublisherApply = zod_1.z.object({
|
|
11605
|
+
repositoryId: zod_1.z.number().int().positive(),
|
|
11606
|
+
revision: zod_1.z.string().regex(/^[a-f0-9]{64}$/),
|
|
11607
|
+
operations: zod_1.z.array(zod_1.z.object({ configPath: exports2.PluginConfigPath, operation: exports2.PluginPublisherOperation }).strict()).min(1).max(100)
|
|
11608
|
+
}).strict();
|
|
11609
|
+
exports2.PluginPublisherApplied = zod_1.z.object({
|
|
11610
|
+
ok: zod_1.z.boolean(),
|
|
11611
|
+
sha: zod_1.z.string(),
|
|
11612
|
+
repositoryId: zod_1.z.number(),
|
|
11613
|
+
buildId: zod_1.z.number()
|
|
11614
|
+
});
|
|
11615
|
+
exports2.PluginPublisherBuildQuery = zod_1.z.object({
|
|
11616
|
+
repositoryId: zod_1.z.coerce.number().int().positive().optional(),
|
|
11617
|
+
page: zod_1.z.coerce.number().int().min(1).max(1e3).default(1),
|
|
11618
|
+
search: zod_1.z.string().max(200).default(""),
|
|
11619
|
+
status: zod_1.z.enum(["", "queued", "in_progress", "success", "failure"]).default(""),
|
|
11620
|
+
sort: zod_1.z.enum(["newest", "oldest", "name"]).default("newest")
|
|
11621
|
+
});
|
|
11622
|
+
exports2.PluginPublisherBuilds = zod_1.z.object({
|
|
11623
|
+
total: zod_1.z.number(),
|
|
11624
|
+
page: zod_1.z.number(),
|
|
11625
|
+
hasMore: zod_1.z.boolean(),
|
|
11626
|
+
items: zod_1.z.array(zod_1.z.object({
|
|
11627
|
+
id: zod_1.z.number(),
|
|
11628
|
+
repositoryId: zod_1.z.number(),
|
|
11629
|
+
number: zod_1.z.number(),
|
|
11630
|
+
attempt: zod_1.z.number(),
|
|
11631
|
+
title: zod_1.z.string(),
|
|
11632
|
+
sha: zod_1.z.string(),
|
|
11633
|
+
branch: zod_1.z.string(),
|
|
11634
|
+
status: zod_1.z.string(),
|
|
11635
|
+
conclusion: zod_1.z.string().nullable(),
|
|
11636
|
+
url: zod_1.z.string(),
|
|
11637
|
+
createdAt: zod_1.z.string(),
|
|
11638
|
+
updatedAt: zod_1.z.string()
|
|
11639
|
+
}))
|
|
11640
|
+
});
|
|
11641
|
+
exports2.PluginPublisherBuildDetail = zod_1.z.object({
|
|
11642
|
+
repository: zod_1.z.string(),
|
|
11643
|
+
sha: zod_1.z.string(),
|
|
11644
|
+
branch: zod_1.z.string(),
|
|
11645
|
+
status: zod_1.z.string(),
|
|
11646
|
+
createdAt: zod_1.z.string(),
|
|
11647
|
+
items: zod_1.z.array(zod_1.z.object({
|
|
11648
|
+
configPath: exports2.PluginConfigPath,
|
|
11649
|
+
name: zod_1.z.string(),
|
|
11650
|
+
version: zod_1.z.string(),
|
|
11651
|
+
scope: zod_1.z.enum(["user", "team", "organization", "public"]),
|
|
11652
|
+
operation: exports2.PluginPublisherOperation,
|
|
11653
|
+
status: zod_1.z.string(),
|
|
11654
|
+
url: zod_1.z.string().nullable(),
|
|
11655
|
+
error: zod_1.z.string().nullable()
|
|
11656
|
+
})),
|
|
11657
|
+
log: zod_1.z.string()
|
|
11658
|
+
});
|
|
11659
|
+
exports2.PluginCloudBuild = zod_1.z.object({
|
|
11660
|
+
id: zod_1.z.number().int().positive(),
|
|
11661
|
+
sha: zod_1.z.string().regex(/^[a-f0-9]{40}$/),
|
|
11662
|
+
active: zod_1.z.boolean(),
|
|
11663
|
+
items: zod_1.z.array(zod_1.z.object({
|
|
11664
|
+
configPath: exports2.PluginConfigPath,
|
|
11665
|
+
config: exports2.PluginReleaseConfig,
|
|
11666
|
+
operation: exports2.PluginPublisherOperation,
|
|
11667
|
+
status: zod_1.z.string()
|
|
11668
|
+
})).max(100)
|
|
11669
|
+
});
|
|
11588
11670
|
}
|
|
11589
11671
|
});
|
|
11590
11672
|
|
|
@@ -12634,6 +12716,7 @@ var PLUGIN_BUNDLE_EXCLUDES = [
|
|
|
12634
12716
|
"*.pem",
|
|
12635
12717
|
"*.key"
|
|
12636
12718
|
];
|
|
12719
|
+
var MAX_CATALOG_MANIFESTS = 512;
|
|
12637
12720
|
|
|
12638
12721
|
// packages/plugin/src/integrity.ts
|
|
12639
12722
|
function collectFiles(dir, base, files) {
|
|
@@ -12793,6 +12876,79 @@ function loadPlugin(dir, source = "user") {
|
|
|
12793
12876
|
function isPluginDir(dir) {
|
|
12794
12877
|
return import_schema2.PLUGIN_DEFINITION_FILENAMES.some((name) => (0, import_node_fs4.existsSync)((0, import_node_path4.join)(dir, name)));
|
|
12795
12878
|
}
|
|
12879
|
+
function pluginDirsIn(root) {
|
|
12880
|
+
if (!(0, import_node_fs4.existsSync)(root)) return [];
|
|
12881
|
+
const out = [];
|
|
12882
|
+
for (const name of (0, import_node_fs4.readdirSync)(root)) {
|
|
12883
|
+
if (name.startsWith(".")) continue;
|
|
12884
|
+
const dir = (0, import_node_path4.join)(root, name);
|
|
12885
|
+
try {
|
|
12886
|
+
if ((0, import_node_fs4.statSync)(dir).isDirectory() && isPluginDir(dir)) out.push(dir);
|
|
12887
|
+
} catch {
|
|
12888
|
+
}
|
|
12889
|
+
}
|
|
12890
|
+
return out;
|
|
12891
|
+
}
|
|
12892
|
+
function discoverPluginCatalog(opts = {}) {
|
|
12893
|
+
return discover(opts, true);
|
|
12894
|
+
}
|
|
12895
|
+
var catalogManifests = /* @__PURE__ */ new Map();
|
|
12896
|
+
function catalogManifest(dir) {
|
|
12897
|
+
const path = (0, import_plugin_runtime2.pluginDefinitionPath)(dir);
|
|
12898
|
+
const stat = (0, import_node_fs4.statSync)(path);
|
|
12899
|
+
const revision = `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;
|
|
12900
|
+
const cached = catalogManifests.get(path);
|
|
12901
|
+
if (cached?.revision === revision) return cached.manifest;
|
|
12902
|
+
const manifest2 = loadPluginManifest(dir);
|
|
12903
|
+
if (catalogManifests.size >= MAX_CATALOG_MANIFESTS) catalogManifests.delete(catalogManifests.keys().next().value);
|
|
12904
|
+
catalogManifests.set(path, { revision, manifest: manifest2 });
|
|
12905
|
+
return manifest2;
|
|
12906
|
+
}
|
|
12907
|
+
function discover(opts, metadataOnly) {
|
|
12908
|
+
const plugins = [];
|
|
12909
|
+
const errors = [];
|
|
12910
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12911
|
+
const scanRoot = (root, source) => {
|
|
12912
|
+
for (const dir of pluginDirsIn(root)) {
|
|
12913
|
+
try {
|
|
12914
|
+
const manifest2 = metadataOnly ? catalogManifest(dir) : loadPluginManifest(dir);
|
|
12915
|
+
if (seen.has(manifest2.id)) continue;
|
|
12916
|
+
seen.add(manifest2.id);
|
|
12917
|
+
plugins.push({ manifest: manifest2, dir, source });
|
|
12918
|
+
} catch (err) {
|
|
12919
|
+
errors.push({ dir, message: err.message });
|
|
12920
|
+
}
|
|
12921
|
+
}
|
|
12922
|
+
};
|
|
12923
|
+
scanRoot(projectPluginRoot(opts.cwd), "project");
|
|
12924
|
+
try {
|
|
12925
|
+
const lock = readLockfile(opts.cwd);
|
|
12926
|
+
for (const [id, entry] of Object.entries(lock.plugins)) {
|
|
12927
|
+
if (seen.has(id)) continue;
|
|
12928
|
+
const dir = storeEntryDir(entry.pluginId ?? id, entry.version, entry.sha256, opts.storeRoot);
|
|
12929
|
+
if (!isPluginDir(dir)) {
|
|
12930
|
+
errors.push({
|
|
12931
|
+
dir,
|
|
12932
|
+
message: `plugin "${id}"@${entry.version} is locked but missing from the store \u2014 run \`octonode install\``
|
|
12933
|
+
});
|
|
12934
|
+
continue;
|
|
12935
|
+
}
|
|
12936
|
+
try {
|
|
12937
|
+
const manifest2 = metadataOnly ? catalogManifest(dir) : loadPluginManifest(dir);
|
|
12938
|
+
if (manifest2.id !== (entry.pluginId ?? id) || manifest2.version !== entry.version || !metadataOnly && hashPluginDir(dir) !== entry.sha256)
|
|
12939
|
+
throw new Error(`Locked plugin ${id} failed identity or integrity validation; run octonode install`);
|
|
12940
|
+
seen.add(id);
|
|
12941
|
+
plugins.push({ manifest: { ...manifest2, id }, dir, source: "store" });
|
|
12942
|
+
} catch (err) {
|
|
12943
|
+
errors.push({ dir, message: err.message });
|
|
12944
|
+
}
|
|
12945
|
+
}
|
|
12946
|
+
} catch (err) {
|
|
12947
|
+
errors.push({ dir: opts.cwd ?? process.cwd(), message: err.message });
|
|
12948
|
+
}
|
|
12949
|
+
scanRoot(opts.userRoot ?? userPluginRoot(), "user");
|
|
12950
|
+
return { plugins, errors };
|
|
12951
|
+
}
|
|
12796
12952
|
|
|
12797
12953
|
// packages/plugin/src/dependencies.ts
|
|
12798
12954
|
var import_node_child_process = require("node:child_process");
|
|
@@ -13172,7 +13328,7 @@ async function run(project, command, cwd, cacheRoot) {
|
|
|
13172
13328
|
maxBuffer: 4 * 1024 * 1024
|
|
13173
13329
|
});
|
|
13174
13330
|
}
|
|
13175
|
-
async function verifyProjectDependencies(project, names) {
|
|
13331
|
+
async function verifyProjectDependencies(project, names, versions = {}) {
|
|
13176
13332
|
if (!names.length) return;
|
|
13177
13333
|
const pnp = (0, import_node_path6.join)(project.root, ".pnp.cjs");
|
|
13178
13334
|
const loader = (0, import_node_path6.join)(project.root, ".pnp.loader.mjs");
|
|
@@ -13184,14 +13340,37 @@ async function verifyProjectDependencies(project, names) {
|
|
|
13184
13340
|
"--input-type=module",
|
|
13185
13341
|
"-e",
|
|
13186
13342
|
`import { createRequire } from 'node:module';
|
|
13187
|
-
import { existsSync } from 'node:fs';
|
|
13343
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13344
|
+
import { dirname, join } from 'node:path';
|
|
13188
13345
|
import { fileURLToPath } from 'node:url';
|
|
13189
13346
|
const require = createRequire(${JSON.stringify((0, import_node_path6.join)(project.target, "package.json"))});
|
|
13347
|
+
const versions = ${JSON.stringify(versions)};
|
|
13190
13348
|
for (const name of ${JSON.stringify(names)}) {
|
|
13191
|
-
|
|
13349
|
+
let resolved;
|
|
13350
|
+
try { resolved = require.resolve(name); } catch {
|
|
13192
13351
|
const entry = import.meta.resolve(name);
|
|
13352
|
+
resolved = entry.startsWith('file:') ? fileURLToPath(entry) : undefined;
|
|
13193
13353
|
if (entry.startsWith('file:') && !existsSync(fileURLToPath(entry))) throw new Error('missing package entry: ' + name);
|
|
13194
13354
|
}
|
|
13355
|
+
const identity = name.startsWith('@') ? name.split('/').slice(0, 2).join('/') : name.split('/')[0];
|
|
13356
|
+
if (Object.hasOwn(versions, identity)) {
|
|
13357
|
+
let directory = resolved ? dirname(resolved) : '';
|
|
13358
|
+
let matched = false;
|
|
13359
|
+
while (directory) {
|
|
13360
|
+
const file = join(directory, 'package.json');
|
|
13361
|
+
if (existsSync(file)) {
|
|
13362
|
+
const pkg = JSON.parse(readFileSync(file, 'utf8'));
|
|
13363
|
+
if (pkg.name === identity) {
|
|
13364
|
+
if (pkg.version !== versions[identity]) throw new Error('installed dependency version mismatch: ' + name);
|
|
13365
|
+
matched = true; break;
|
|
13366
|
+
}
|
|
13367
|
+
}
|
|
13368
|
+
const parent = dirname(directory);
|
|
13369
|
+
if (parent === directory) break;
|
|
13370
|
+
directory = parent;
|
|
13371
|
+
}
|
|
13372
|
+
if (!matched) throw new Error('cannot verify installed package: ' + name);
|
|
13373
|
+
}
|
|
13195
13374
|
}`
|
|
13196
13375
|
],
|
|
13197
13376
|
{ cwd: project.target, env: (0, import_common.childProcessEnvironment)(), timeout: 3e4, maxBuffer: 1024 * 1024 }
|
|
@@ -13241,7 +13420,40 @@ async function reconcileDependencies(cwd, dependencies, options = {}) {
|
|
|
13241
13420
|
throw new Error("invalid npm dependency subpath");
|
|
13242
13421
|
}
|
|
13243
13422
|
}
|
|
13423
|
+
const unique = /* @__PURE__ */ new Map();
|
|
13424
|
+
for (const dependency of dependencies) {
|
|
13425
|
+
const spec = dependency.spec.startsWith(`${dependency.name}@`) ? dependency.spec.slice(dependency.name.length + 1) : dependency.spec;
|
|
13426
|
+
const previous = unique.get(dependency.name);
|
|
13427
|
+
if (previous && previous.spec !== spec) throw new Error(`Conflicting dependency requests for ${dependency.name}`);
|
|
13428
|
+
unique.set(dependency.name, {
|
|
13429
|
+
...dependency,
|
|
13430
|
+
spec,
|
|
13431
|
+
...previous?.subpaths || dependency.subpaths ? { subpaths: [.../* @__PURE__ */ new Set([...previous?.subpaths ?? [], ...dependency.subpaths ?? []])] } : {}
|
|
13432
|
+
});
|
|
13433
|
+
}
|
|
13434
|
+
dependencies = [...unique.values()];
|
|
13244
13435
|
const project = resolveDependencyProject(cwd);
|
|
13436
|
+
const declared = manifest(project.target);
|
|
13437
|
+
const existing = { ...declared.devDependencies, ...declared.optionalDependencies, ...declared.dependencies };
|
|
13438
|
+
if (options.preserveExisting) {
|
|
13439
|
+
for (const { name, spec } of dependencies)
|
|
13440
|
+
if (Object.hasOwn(existing, name) && existing[name] !== spec && !(existing[name].startsWith("file:") && spec.startsWith("file:") && (0, import_node_path6.resolve)(project.target, existing[name].slice(5)) === (0, import_node_path6.resolve)(project.target, spec.slice(5))))
|
|
13441
|
+
throw new Error(
|
|
13442
|
+
`Dependency conflict: ${name} is ${existing[name]}, plugin requires ${spec}; reconcile it explicitly first`
|
|
13443
|
+
);
|
|
13444
|
+
}
|
|
13445
|
+
const reusable = dependencies.length > 0 && !options.remove?.length && dependencies.every(
|
|
13446
|
+
({ name, spec }) => existing[name] === spec && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(spec)
|
|
13447
|
+
);
|
|
13448
|
+
const reuse = reusable && await verifyProjectDependencies(
|
|
13449
|
+
project,
|
|
13450
|
+
dependencies.flatMap(({ name, subpaths }) => subpaths ? subpaths.map((path) => name + path.slice(1)) : [name]),
|
|
13451
|
+
Object.fromEntries(dependencies.map(({ name, spec }) => [name, spec]))
|
|
13452
|
+
).then(
|
|
13453
|
+
() => true,
|
|
13454
|
+
() => false
|
|
13455
|
+
);
|
|
13456
|
+
const metadataOnly = options.metadataOnly || reuse;
|
|
13245
13457
|
const packageJson = (0, import_node_path6.join)(project.target, "package.json");
|
|
13246
13458
|
if (!dependencies.length && !(0, import_node_fs6.existsSync)(packageJson) && !options.commit) return;
|
|
13247
13459
|
const hasLock = PACKAGE_MANAGER_LOCKS[project.manager].some((file) => (0, import_node_fs6.existsSync)((0, import_node_path6.join)(project.root, file)));
|
|
@@ -13277,13 +13489,12 @@ async function reconcileDependencies(cwd, dependencies, options = {}) {
|
|
|
13277
13489
|
else (0, import_node_fs6.writeFileSync)(path, content);
|
|
13278
13490
|
}
|
|
13279
13491
|
};
|
|
13280
|
-
if (hadInstall && !hasLock && !
|
|
13492
|
+
if (hadInstall && !hasLock && !metadataOnly)
|
|
13281
13493
|
throw new Error(
|
|
13282
13494
|
"create a native lockfile before updating existing dependencies so failed installations can be recovered"
|
|
13283
13495
|
);
|
|
13284
13496
|
try {
|
|
13285
|
-
if (
|
|
13286
|
-
(0, import_node_fs6.writeFileSync)((0, import_node_path6.join)((0, import_node_path6.dirname)(journal), "metadata-only"), "1");
|
|
13497
|
+
if (metadataOnly && (0, import_node_fs6.existsSync)((0, import_node_path6.dirname)(journal))) (0, import_node_fs6.writeFileSync)((0, import_node_path6.join)((0, import_node_path6.dirname)(journal), "metadata-only"), "1");
|
|
13287
13498
|
if ((0, import_node_fs6.existsSync)((0, import_node_path6.dirname)(journal)))
|
|
13288
13499
|
(0, import_node_fs6.writeFileSync)(
|
|
13289
13500
|
journal,
|
|
@@ -13294,7 +13505,7 @@ async function reconcileDependencies(cwd, dependencies, options = {}) {
|
|
|
13294
13505
|
}))
|
|
13295
13506
|
)
|
|
13296
13507
|
);
|
|
13297
|
-
if (
|
|
13508
|
+
if (metadataOnly) {
|
|
13298
13509
|
metadataTouched = true;
|
|
13299
13510
|
options.commit?.();
|
|
13300
13511
|
(0, import_node_fs6.rmSync)(journal, { force: true });
|
|
@@ -13386,14 +13597,14 @@ async function reconcileDependencies(cwd, dependencies, options = {}) {
|
|
|
13386
13597
|
}
|
|
13387
13598
|
restoreBefore();
|
|
13388
13599
|
let recovery = "";
|
|
13389
|
-
if (!
|
|
13600
|
+
if (!metadataOnly && hadInstall && hasLock) {
|
|
13390
13601
|
try {
|
|
13391
13602
|
await run(project, installCommand(project, true), project.root, options.cacheRoot);
|
|
13392
13603
|
} catch {
|
|
13393
13604
|
recovery = "; manifests restored, but dependency recovery failed \u2014 run a frozen install before executing workflows";
|
|
13394
13605
|
}
|
|
13395
13606
|
restoreBefore();
|
|
13396
|
-
} else if (!
|
|
13607
|
+
} else if (!metadataOnly && !hadInstall) {
|
|
13397
13608
|
(0, import_node_fs6.rmSync)((0, import_node_path6.join)(project.root, "node_modules"), { recursive: true, force: true });
|
|
13398
13609
|
}
|
|
13399
13610
|
for (const [path, content] of pnpBefore) {
|
|
@@ -13698,6 +13909,19 @@ async function generatePluginPackage(cwd, selections, expectedPacker) {
|
|
|
13698
13909
|
function pluginNpmDependencies(manifest2) {
|
|
13699
13910
|
return manifest2.integration?.npmDependencies ?? (manifest2.integration?.npm ? [manifest2.integration.npm] : []);
|
|
13700
13911
|
}
|
|
13912
|
+
function assertUniqueNpmPlugins(plugins) {
|
|
13913
|
+
const owners = /* @__PURE__ */ new Map();
|
|
13914
|
+
for (const { alias, manifest: manifest2 } of plugins) {
|
|
13915
|
+
const pkg = manifest2.integration?.npm?.package.trim().toLowerCase();
|
|
13916
|
+
if (!pkg) continue;
|
|
13917
|
+
const previous = owners.get(pkg);
|
|
13918
|
+
if (previous && previous !== alias)
|
|
13919
|
+
throw new Error(
|
|
13920
|
+
`Use existing npm integration "${previous}" for ${pkg}; duplicate plugin alias "${alias}" is not allowed`
|
|
13921
|
+
);
|
|
13922
|
+
owners.set(pkg, alias);
|
|
13923
|
+
}
|
|
13924
|
+
}
|
|
13701
13925
|
|
|
13702
13926
|
// packages/plugin/src/prepared/invocation.ts
|
|
13703
13927
|
var import_common3 = __toESM(require_dist2());
|
|
@@ -13746,6 +13970,10 @@ async function reconcilePluginLock(cwd, next, options = {}) {
|
|
|
13746
13970
|
throw new Error(`Plugin identity or integrity mismatch: ${alias}`);
|
|
13747
13971
|
return { alias, directory, sha256: pin.sha256, manifest: manifest2, remote: preparedPluginPin(directory, pin) };
|
|
13748
13972
|
});
|
|
13973
|
+
assertUniqueNpmPlugins([
|
|
13974
|
+
...discoverPluginCatalog({ cwd, storeRoot: options.storeRoot }).plugins.filter((item) => item.source === "project" && !loaded.some((pin) => pin.alias === item.manifest.id)).map((item) => ({ alias: item.manifest.id, manifest: item.manifest })),
|
|
13975
|
+
...loaded
|
|
13976
|
+
]);
|
|
13749
13977
|
const libraries = loaded.filter((item) => item.manifest.library);
|
|
13750
13978
|
const generated = libraries.length ? await generatePluginPackage(project.target, libraries) : void 0;
|
|
13751
13979
|
const packageFile = (0, import_node_path10.join)(project.target, "package.json");
|
|
@@ -13842,6 +14070,9 @@ function installRoot(opts) {
|
|
|
13842
14070
|
return opts.project ? { root: projectPluginRoot(opts.cwd), source: "project" } : { root: userPluginRoot(), source: "user" };
|
|
13843
14071
|
}
|
|
13844
14072
|
async function installNodeDeps(dir, opts = {}) {
|
|
14073
|
+
return installNodeDepsUnlocked(dir, opts, false);
|
|
14074
|
+
}
|
|
14075
|
+
async function installNodeDepsUnlocked(dir, opts, locked) {
|
|
13845
14076
|
if (opts.noDeps) return {};
|
|
13846
14077
|
const dependencies = pluginNpmDependencies(loadPluginManifest(dir));
|
|
13847
14078
|
if (dependencies.length) {
|
|
@@ -13854,11 +14085,12 @@ async function installNodeDeps(dir, opts = {}) {
|
|
|
13854
14085
|
});
|
|
13855
14086
|
return {};
|
|
13856
14087
|
}
|
|
13857
|
-
await installProjectDependencies(
|
|
14088
|
+
await (locked ? reconcileDependencies : installProjectDependencies)(
|
|
13858
14089
|
opts.cwd ?? process.cwd(),
|
|
13859
14090
|
dependencies.map((npm) => ({ name: npm.package, spec: npm.spec })),
|
|
13860
14091
|
{
|
|
13861
|
-
cacheRoot: opts.cacheRoot
|
|
14092
|
+
cacheRoot: opts.cacheRoot,
|
|
14093
|
+
preserveExisting: true
|
|
13862
14094
|
}
|
|
13863
14095
|
);
|
|
13864
14096
|
return { depsInstalled: true };
|
|
@@ -13894,6 +14126,10 @@ async function installNodeDeps(dir, opts = {}) {
|
|
|
13894
14126
|
}
|
|
13895
14127
|
}
|
|
13896
14128
|
async function installPlugin(src, opts = {}) {
|
|
14129
|
+
if (opts.project) return withDependencyInstall(opts.cwd ?? process.cwd(), () => installPluginUnlocked(src, opts));
|
|
14130
|
+
return installPluginUnlocked(src, opts);
|
|
14131
|
+
}
|
|
14132
|
+
async function installPluginUnlocked(src, opts) {
|
|
13897
14133
|
if (!(0, import_node_fs11.existsSync)(src) || !(0, import_node_fs11.statSync)(src).isDirectory()) {
|
|
13898
14134
|
throw new Error(`source "${src}" is not a directory`);
|
|
13899
14135
|
}
|
|
@@ -13902,13 +14138,20 @@ async function installPlugin(src, opts = {}) {
|
|
|
13902
14138
|
}
|
|
13903
14139
|
const { manifest: manifest2 } = loadPlugin(src);
|
|
13904
14140
|
const { root, source } = installRoot(opts);
|
|
14141
|
+
const installed = discoverPluginCatalog({ cwd: opts.cwd }).plugins.filter(
|
|
14142
|
+
(item) => (opts.project ? item.source !== "user" : item.source === "user") && item.manifest.id !== manifest2.id
|
|
14143
|
+
);
|
|
14144
|
+
assertUniqueNpmPlugins([
|
|
14145
|
+
...installed.map((item) => ({ alias: item.manifest.id, manifest: item.manifest })),
|
|
14146
|
+
{ alias: manifest2.id, manifest: manifest2 }
|
|
14147
|
+
]);
|
|
13905
14148
|
const dest = (0, import_node_path11.join)(root, manifest2.id);
|
|
13906
14149
|
if ((0, import_node_fs11.existsSync)(dest)) {
|
|
13907
14150
|
if (!opts.force) {
|
|
13908
14151
|
throw new Error(`plugin "${manifest2.id}" is already installed at ${dest} (use --force to overwrite)`);
|
|
13909
14152
|
}
|
|
13910
14153
|
}
|
|
13911
|
-
const deps = pluginNpmDependencies(manifest2).length ? await
|
|
14154
|
+
const deps = pluginNpmDependencies(manifest2).length ? await installNodeDepsUnlocked(src, { ...opts, cacheOnly: opts.cacheOnly ?? !opts.project }, !!opts.project) : {};
|
|
13912
14155
|
if (deps.depsError) return { manifest: manifest2, dir: dest, source, ...deps };
|
|
13913
14156
|
if ((0, import_node_fs11.existsSync)(dest)) (0, import_node_fs11.rmSync)(dest, { recursive: true, force: true });
|
|
13914
14157
|
(0, import_node_fs11.mkdirSync)(root, { recursive: true });
|
|
@@ -13918,7 +14161,7 @@ async function installPlugin(src, opts = {}) {
|
|
|
13918
14161
|
dir: dest,
|
|
13919
14162
|
source,
|
|
13920
14163
|
...deps,
|
|
13921
|
-
...pluginNpmDependencies(manifest2).length ? {} : await
|
|
14164
|
+
...pluginNpmDependencies(manifest2).length ? {} : await installNodeDepsUnlocked(dest, opts, !!opts.project)
|
|
13922
14165
|
};
|
|
13923
14166
|
}
|
|
13924
14167
|
|
|
@@ -14264,7 +14507,20 @@ var RemoteRegistry = class {
|
|
|
14264
14507
|
}
|
|
14265
14508
|
try {
|
|
14266
14509
|
await withDependencyInstall(opts.cwd ?? process.cwd(), async () => {
|
|
14267
|
-
const
|
|
14510
|
+
const pins = readLockfile(opts.cwd).plugins;
|
|
14511
|
+
assertUniqueNpmPlugins([
|
|
14512
|
+
...discoverPluginCatalog({ cwd: opts.cwd, storeRoot: opts.storeRoot }).plugins.filter(
|
|
14513
|
+
(item) => item.source === "project" && item.manifest.id !== alias && !pins[item.manifest.id]
|
|
14514
|
+
).map((item) => ({ alias: item.manifest.id, manifest: item.manifest })),
|
|
14515
|
+
...Object.entries(pins).filter(([key]) => key !== alias).map(([key, locked]) => ({
|
|
14516
|
+
alias: key,
|
|
14517
|
+
manifest: loadPluginManifest(
|
|
14518
|
+
storeEntryDir(locked.pluginId ?? key, locked.version, locked.sha256, opts.storeRoot)
|
|
14519
|
+
)
|
|
14520
|
+
})),
|
|
14521
|
+
{ alias, manifest: entry.manifest }
|
|
14522
|
+
]);
|
|
14523
|
+
const previous = pins[alias];
|
|
14268
14524
|
if (previous && ((previous.pluginId ?? alias) !== entry.id || previous.registry !== this.baseUrl || previous.publisher !== pin.publisher))
|
|
14269
14525
|
throw new Error("Plugin alias belongs to another publisher or registry");
|
|
14270
14526
|
upsertLockEntry(opts.cwd ?? process.cwd(), alias, pin);
|