@powerhousedao/registry 6.2.3-dev.36 → 6.2.3-dev.38
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/dist/cli.d.mts +2 -0
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +91 -48
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.d.mts
CHANGED
|
@@ -22,6 +22,7 @@ export declare const registryCommand: Partial<import("cmd-ts/dist/cjs/argparser.
|
|
|
22
22
|
workers: number;
|
|
23
23
|
uplink: string | undefined;
|
|
24
24
|
uplinkMaxage: string | undefined;
|
|
25
|
+
trustProxy: string | undefined;
|
|
25
26
|
webEnabled: boolean;
|
|
26
27
|
publicUrl: string | undefined;
|
|
27
28
|
authRenown: boolean;
|
|
@@ -51,6 +52,7 @@ export declare const registryCommand: Partial<import("cmd-ts/dist/cjs/argparser.
|
|
|
51
52
|
workers: number;
|
|
52
53
|
uplink: string | undefined;
|
|
53
54
|
uplinkMaxage: string | undefined;
|
|
55
|
+
trustProxy: string | undefined;
|
|
54
56
|
webEnabled: boolean;
|
|
55
57
|
publicUrl: string | undefined;
|
|
56
58
|
authRenown: boolean;
|
package/dist/cli.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.mts","names":[],"sources":["../cli.ts"],"mappings":";qBA2Ia,iBAAe,+CAAA
|
|
1
|
+
{"version":3,"file":"cli.d.mts","names":[],"sources":["../cli.ts"],"mappings":";qBA2Ia,iBAAe,+CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2I1B,6CAAA,iDAAA,mDAAA;qBAEW,eAAa,+CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyCxB,6CAAA,iDAAA,mDAAA;qBAEW,gBAAc,+CAAA;;;;;;;;;;;;IAkBzB,6CAAA,iDAAA,mDAAA;qBAEW,6BAA2B,+CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAatC,6CAAA,iDAAA,mDAAA"}
|
package/dist/cli.mjs
CHANGED
|
@@ -1919,13 +1919,19 @@ function createS3ArtifactStore(config) {
|
|
|
1919
1919
|
},
|
|
1920
1920
|
async putFile(key, file, contentType) {
|
|
1921
1921
|
const { size } = await fs.promises.stat(file);
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1922
|
+
const body = fs.createReadStream(file);
|
|
1923
|
+
body.on("error", () => void 0);
|
|
1924
|
+
try {
|
|
1925
|
+
await s3.send(new PutObjectCommand({
|
|
1926
|
+
Bucket: config.bucket,
|
|
1927
|
+
Key: root + key,
|
|
1928
|
+
Body: body,
|
|
1929
|
+
ContentLength: size,
|
|
1930
|
+
ContentType: contentType
|
|
1931
|
+
}));
|
|
1932
|
+
} finally {
|
|
1933
|
+
body.destroy();
|
|
1934
|
+
}
|
|
1929
1935
|
},
|
|
1930
1936
|
async get(key) {
|
|
1931
1937
|
try {
|
|
@@ -2826,9 +2832,16 @@ function inside(root, relative) {
|
|
|
2826
2832
|
}
|
|
2827
2833
|
async function inBatches(items, size, fn) {
|
|
2828
2834
|
let cursor = 0;
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2835
|
+
let failed = false;
|
|
2836
|
+
const rejected = (await Promise.allSettled(Array.from({ length: Math.min(size, items.length) }, async () => {
|
|
2837
|
+
while (!failed && cursor < items.length) try {
|
|
2838
|
+
await fn(items[cursor++]);
|
|
2839
|
+
} catch (err) {
|
|
2840
|
+
failed = true;
|
|
2841
|
+
throw err;
|
|
2842
|
+
}
|
|
2843
|
+
}))).find((lane) => lane.status === "rejected");
|
|
2844
|
+
if (rejected) throw rejected.reason;
|
|
2832
2845
|
}
|
|
2833
2846
|
async function packDir(dir) {
|
|
2834
2847
|
const files = listFiles(dir);
|
|
@@ -2933,6 +2946,12 @@ async function indexedRevision(db, pkg) {
|
|
|
2933
2946
|
}
|
|
2934
2947
|
return (await db.query("SELECT rev FROM verdaccio_manifests WHERE name = $1", [pkg])).rows[0]?.rev ?? null;
|
|
2935
2948
|
}
|
|
2949
|
+
async function publishedHere(db, pkg) {
|
|
2950
|
+
if (!(await db.query("SELECT to_regclass('verdaccio_packages') IS NOT NULL AS exists")).rows[0]?.exists) return null;
|
|
2951
|
+
return (await db.query(`SELECT EXISTS (SELECT 1 FROM verdaccio_packages WHERE name = $1)
|
|
2952
|
+
OR EXISTS (SELECT 1 FROM registry_package_owners WHERE package_name = $1)
|
|
2953
|
+
AS published`, [pkg])).rows[0]?.published === true;
|
|
2954
|
+
}
|
|
2936
2955
|
async function upsertPackage(tx, pkg, packument, local, manifestRev) {
|
|
2937
2956
|
const versions = Object.keys(packument.versions ?? {}).sort(compareSemver);
|
|
2938
2957
|
const times = {};
|
|
@@ -3017,7 +3036,7 @@ function publisherOf$1(job) {
|
|
|
3017
3036
|
async function processVersion(ctx, job, finish) {
|
|
3018
3037
|
const pkg = job.package;
|
|
3019
3038
|
const version = job.version;
|
|
3020
|
-
const local = job.payload.local === true;
|
|
3039
|
+
const local = await publishedHere(ctx.db, pkg) ?? job.payload.local === true;
|
|
3021
3040
|
const manifestRev = await indexedRevision(ctx.db, pkg);
|
|
3022
3041
|
const packument = await fetchPackument(ctx.registryUrl, pkg);
|
|
3023
3042
|
if (!packument?.versions?.[version]) {
|
|
@@ -3102,15 +3121,22 @@ async function syncPackage(ctx, job, finish) {
|
|
|
3102
3121
|
const known = await ctx.db.query("SELECT version FROM registry_versions WHERE package = $1", [pkg]);
|
|
3103
3122
|
const listed = new Set(Object.keys(packument?.versions ?? {}));
|
|
3104
3123
|
const removed = known.rows.map((r) => r.version).filter((v) => !listed.has(v));
|
|
3124
|
+
const published = await publishedHere(ctx.db, pkg);
|
|
3125
|
+
const local = published ?? job.payload.local === true;
|
|
3126
|
+
if (!packument && published) throw new Error(`metadata for published ${pkg} returned 404`);
|
|
3105
3127
|
await ctx.db.transaction(async (tx) => {
|
|
3106
3128
|
await removeVersionRows(tx, pkg, removed);
|
|
3107
3129
|
if (!packument) await tx.query("DELETE FROM registry_packages WHERE name = $1", [pkg]);
|
|
3108
3130
|
else {
|
|
3109
|
-
await upsertPackage(tx, pkg, packument,
|
|
3131
|
+
await upsertPackage(tx, pkg, packument, local, manifestRev);
|
|
3110
3132
|
await recomputeLatest(tx, pkg);
|
|
3111
|
-
if (
|
|
3133
|
+
if (local) {
|
|
3112
3134
|
const have = new Set(known.rows.map((r) => r.version));
|
|
3113
|
-
|
|
3135
|
+
const tagged = new Set(Object.values(packument["dist-tags"] ?? {}));
|
|
3136
|
+
for (const version of tagged) {
|
|
3137
|
+
if (!listed.has(version)) continue;
|
|
3138
|
+
if (!have.has(version)) await enqueue(tx, "process", pkg, version, { local: true }, job.priority);
|
|
3139
|
+
}
|
|
3114
3140
|
}
|
|
3115
3141
|
}
|
|
3116
3142
|
await finish(tx);
|
|
@@ -4761,7 +4787,10 @@ function buildVerdaccioConfig(config) {
|
|
|
4761
4787
|
primary_color: "#38C780",
|
|
4762
4788
|
darkMode: true
|
|
4763
4789
|
},
|
|
4764
|
-
server: {
|
|
4790
|
+
server: {
|
|
4791
|
+
keepAliveTimeout: 60,
|
|
4792
|
+
...config.trustProxy !== void 0 && { trustProxy: config.trustProxy }
|
|
4793
|
+
},
|
|
4765
4794
|
log: {
|
|
4766
4795
|
type: "stdout",
|
|
4767
4796
|
format: "pretty",
|
|
@@ -4799,8 +4828,10 @@ async function enqueueSweep(db) {
|
|
|
4799
4828
|
return names.rows.length;
|
|
4800
4829
|
}
|
|
4801
4830
|
async function hasManifestIndex(db) {
|
|
4802
|
-
return (await db.query(
|
|
4831
|
+
return (await db.query(`SELECT to_regclass('verdaccio_manifests') IS NOT NULL
|
|
4832
|
+
AND to_regclass('verdaccio_packages') IS NOT NULL AS exists`)).rows[0]?.exists === true;
|
|
4803
4833
|
}
|
|
4834
|
+
const PUBLISHED = "EXISTS (SELECT 1 FROM verdaccio_packages l WHERE l.name = m.name)";
|
|
4804
4835
|
const UNPUBLISHED = `
|
|
4805
4836
|
SELECT p.name FROM registry_packages p
|
|
4806
4837
|
WHERE p.local AND p.updated_at < now() - interval '30 seconds'
|
|
@@ -4809,7 +4840,7 @@ const QUICK_CHANGED = `
|
|
|
4809
4840
|
SELECT m.name
|
|
4810
4841
|
FROM verdaccio_manifests m
|
|
4811
4842
|
LEFT JOIN registry_packages p ON p.name = m.name
|
|
4812
|
-
WHERE m.updated_at < now() - interval '30 seconds'
|
|
4843
|
+
WHERE m.updated_at < now() - interval '30 seconds' AND ${PUBLISHED}
|
|
4813
4844
|
AND (p.name IS NULL OR p.manifest_rev IS DISTINCT FROM m.rev)
|
|
4814
4845
|
UNION ${UNPUBLISHED}
|
|
4815
4846
|
LIMIT 1000`;
|
|
@@ -4822,11 +4853,11 @@ const QUICK_MISSING = `
|
|
|
4822
4853
|
AND j.version = r.version)
|
|
4823
4854
|
LIMIT 1000`;
|
|
4824
4855
|
const FULL_MISSING = `
|
|
4825
|
-
SELECT m.name, v.version
|
|
4856
|
+
SELECT DISTINCT m.name, v.version
|
|
4826
4857
|
FROM verdaccio_manifests m
|
|
4827
|
-
CROSS JOIN LATERAL
|
|
4858
|
+
CROSS JOIN LATERAL jsonb_each_text(m.dist_tags) AS v(tag, version)
|
|
4828
4859
|
LEFT JOIN registry_versions r ON r.package = m.name AND r.version = v.version
|
|
4829
|
-
WHERE m.updated_at < now() - interval '30 seconds'
|
|
4860
|
+
WHERE m.updated_at < now() - interval '30 seconds' AND ${PUBLISHED}
|
|
4830
4861
|
AND (r.package IS NULL
|
|
4831
4862
|
OR (r.status = 'pending' AND r.updated_at < now() - interval '5 minutes'
|
|
4832
4863
|
AND NOT EXISTS (SELECT 1 FROM registry_jobs j
|
|
@@ -4837,8 +4868,8 @@ const FULL_CHANGED = `
|
|
|
4837
4868
|
SELECT m.name
|
|
4838
4869
|
FROM verdaccio_manifests m
|
|
4839
4870
|
LEFT JOIN registry_packages p ON p.name = m.name
|
|
4840
|
-
WHERE m.updated_at < now() - interval '30 seconds'
|
|
4841
|
-
AND (p.name IS NULL OR p.dist_tags <> m.dist_tags
|
|
4871
|
+
WHERE m.updated_at < now() - interval '30 seconds' AND ${PUBLISHED}
|
|
4872
|
+
AND (p.name IS NULL OR NOT p.local OR p.dist_tags <> m.dist_tags
|
|
4842
4873
|
OR EXISTS (SELECT 1 FROM registry_versions r
|
|
4843
4874
|
WHERE r.package = m.name AND NOT m.versions ? r.version))
|
|
4844
4875
|
UNION ${UNPUBLISHED}
|
|
@@ -4853,12 +4884,32 @@ async function reconcile(db, options = {}) {
|
|
|
4853
4884
|
if (queued > 0) await wakeWorkers(db);
|
|
4854
4885
|
return queued;
|
|
4855
4886
|
}
|
|
4887
|
+
async function pruneCachedPackages(q, published) {
|
|
4888
|
+
if (!(await q.query("SELECT to_regclass('registry_jobs') IS NOT NULL AS exists")).rows[0]?.exists) return [];
|
|
4889
|
+
const pruned = (await q.query(`DELETE FROM verdaccio_packages p
|
|
4890
|
+
WHERE p.name <> ALL($1::text[])
|
|
4891
|
+
AND NOT EXISTS (SELECT 1 FROM registry_package_owners o
|
|
4892
|
+
WHERE o.package_name = p.name)
|
|
4893
|
+
AND NOT EXISTS (SELECT 1 FROM registry_packages r
|
|
4894
|
+
WHERE r.name = p.name AND r.listed_manifest IS NOT NULL)
|
|
4895
|
+
RETURNING p.name`, [published])).rows.map((row) => row.name);
|
|
4896
|
+
if (pruned.length) {
|
|
4897
|
+
await q.query("DELETE FROM registry_jobs WHERE package = ANY($1) AND locked_by IS NULL", [pruned]);
|
|
4898
|
+
await q.query("DELETE FROM registry_versions WHERE package = ANY($1)", [pruned]);
|
|
4899
|
+
await q.query("DELETE FROM registry_packages WHERE name = ANY($1)", [pruned]);
|
|
4900
|
+
}
|
|
4901
|
+
return pruned;
|
|
4902
|
+
}
|
|
4856
4903
|
function publisherOf(job) {
|
|
4857
4904
|
const by = job.payload.publishedBy;
|
|
4858
4905
|
return by?.address ? by : void 0;
|
|
4859
4906
|
}
|
|
4860
4907
|
async function runJob(ctx, job, options) {
|
|
4861
4908
|
const finish = (tx) => complete(tx, job);
|
|
4909
|
+
if (job.priority === 10 && await publishedHere(ctx.db, job.package) === false) {
|
|
4910
|
+
await ctx.db.transaction(finish);
|
|
4911
|
+
return;
|
|
4912
|
+
}
|
|
4862
4913
|
if (job.kind === "process") {
|
|
4863
4914
|
if (await processVersion(ctx, job, finish) && job.payload.notify === true) await options.webhooks?.notifyPublish({
|
|
4864
4915
|
packageName: job.package,
|
|
@@ -4942,7 +4993,7 @@ async function startWorker(ctx, options) {
|
|
|
4942
4993
|
};
|
|
4943
4994
|
const loops = Array.from({ length: Math.max(1, options.concurrency) }, () => loop());
|
|
4944
4995
|
let sweeper;
|
|
4945
|
-
let lastFull =
|
|
4996
|
+
let lastFull = Date.now() - SWEEP_INTERVAL_MS + RECONCILE_INTERVAL_MS;
|
|
4946
4997
|
const sweep = async () => {
|
|
4947
4998
|
try {
|
|
4948
4999
|
const full = Date.now() - lastFull >= SWEEP_INTERVAL_MS;
|
|
@@ -5057,8 +5108,11 @@ async function seedVerdaccioSecret(databaseUrl, secret) {
|
|
|
5057
5108
|
const MIB = 1048576;
|
|
5058
5109
|
const DRAIN_DELAY_MS = 5e3;
|
|
5059
5110
|
const DRAIN_TIMEOUT_MS = 2e4;
|
|
5111
|
+
function parseTrustProxy(value) {
|
|
5112
|
+
return /^\d+$/.test(value) ? Number(value) : value;
|
|
5113
|
+
}
|
|
5060
5114
|
async function runRegistry(args) {
|
|
5061
|
-
const { port, storageDir, cdnCacheDir, uplink, uplinkMaxage, webEnabled, webhooks, publicUrl, authRenown, renownUrl, verdaccioSecret, localPackages, databaseUrl, pluginsDir, authStore } = args;
|
|
5115
|
+
const { port, storageDir, cdnCacheDir, uplink, uplinkMaxage, trustProxy, webEnabled, webhooks, publicUrl, authRenown, renownUrl, verdaccioSecret, localPackages, databaseUrl, pluginsDir, authStore } = args;
|
|
5062
5116
|
const storagePath = await resolveDir(storageDir);
|
|
5063
5117
|
const cdnCachePath = await resolveDir(cdnCacheDir);
|
|
5064
5118
|
const s3 = s3From(args);
|
|
@@ -5084,6 +5138,7 @@ async function runRegistry(args) {
|
|
|
5084
5138
|
uplink,
|
|
5085
5139
|
uplinkMaxage,
|
|
5086
5140
|
webEnabled,
|
|
5141
|
+
...trustProxy ? { trustProxy: parseTrustProxy(trustProxy) } : {},
|
|
5087
5142
|
...localPackagePatterns?.length ? { localPackagePatterns } : {},
|
|
5088
5143
|
...renownEnabled && publicUrl ? { renown: {
|
|
5089
5144
|
publicUrl,
|
|
@@ -5271,27 +5326,6 @@ async function runMigrate(databaseUrl, options) {
|
|
|
5271
5326
|
await db.close();
|
|
5272
5327
|
}
|
|
5273
5328
|
}
|
|
5274
|
-
async function storedPackageNames(s3, config) {
|
|
5275
|
-
const prefix = config.keyPrefix ?? "";
|
|
5276
|
-
const names = /* @__PURE__ */ new Set();
|
|
5277
|
-
let token;
|
|
5278
|
-
do {
|
|
5279
|
-
const page = await s3.send(new ListObjectsV2Command({
|
|
5280
|
-
Bucket: config.bucket,
|
|
5281
|
-
Prefix: prefix,
|
|
5282
|
-
ContinuationToken: token
|
|
5283
|
-
}));
|
|
5284
|
-
for (const { Key } of page.Contents ?? []) {
|
|
5285
|
-
const rel = Key?.slice(prefix.length) ?? "";
|
|
5286
|
-
if (!rel.endsWith("/package.json") || rel.startsWith("artifacts/")) continue;
|
|
5287
|
-
const name = rel.slice(0, -13);
|
|
5288
|
-
const depth = name.split("/").length;
|
|
5289
|
-
if (name.startsWith("@") ? depth === 2 : depth === 1) names.add(name);
|
|
5290
|
-
}
|
|
5291
|
-
token = page.IsTruncated ? page.NextContinuationToken : void 0;
|
|
5292
|
-
} while (token);
|
|
5293
|
-
return names;
|
|
5294
|
-
}
|
|
5295
5329
|
async function readStoredManifest(s3, config, name) {
|
|
5296
5330
|
try {
|
|
5297
5331
|
const res = await s3.send(new GetObjectCommand({
|
|
@@ -5327,9 +5361,9 @@ async function runImportVerdaccioState(args) {
|
|
|
5327
5361
|
const name = err.name;
|
|
5328
5362
|
if (name !== "NoSuchKey" && name !== "NotFound") throw err;
|
|
5329
5363
|
}
|
|
5330
|
-
const names =
|
|
5331
|
-
for (const name of legacy.list ?? []) names.add(name);
|
|
5364
|
+
const names = new Set(legacy.list ?? []);
|
|
5332
5365
|
const pool = new pg.Pool({ connectionString: args.databaseUrl });
|
|
5366
|
+
let pruned = [];
|
|
5333
5367
|
try {
|
|
5334
5368
|
const store = new S3DatabasePostgres(pool, pluginLogger);
|
|
5335
5369
|
await store.init();
|
|
@@ -5338,6 +5372,7 @@ async function runImportVerdaccioState(args) {
|
|
|
5338
5372
|
if (manifest) await store.record(name, manifest);
|
|
5339
5373
|
}
|
|
5340
5374
|
for (const name of names) await pool.query("INSERT INTO verdaccio_packages (name) VALUES ($1) ON CONFLICT (name) DO NOTHING", [name]);
|
|
5375
|
+
pruned = await pruneCachedPackages(pool, [...names]);
|
|
5341
5376
|
for (const token of legacy.tokens ?? []) await pool.query(`INSERT INTO verdaccio_tokens ("user", key, token) VALUES ($1, $2, $3)
|
|
5342
5377
|
ON CONFLICT ("user", key) DO NOTHING`, [
|
|
5343
5378
|
token.user,
|
|
@@ -5349,7 +5384,7 @@ async function runImportVerdaccioState(args) {
|
|
|
5349
5384
|
} finally {
|
|
5350
5385
|
await pool.end();
|
|
5351
5386
|
}
|
|
5352
|
-
console.log(`[registry] imported ${names.size} package name(s), ${legacy.tokens?.length ?? 0} token(s)${legacy.secret ? " and the secret" : ""}`);
|
|
5387
|
+
console.log(`[registry] imported ${names.size} package name(s), ${legacy.tokens?.length ?? 0} token(s)${legacy.secret ? " and the secret" : ""}; pruned ${pruned.length} cached package(s)`);
|
|
5353
5388
|
}
|
|
5354
5389
|
//#endregion
|
|
5355
5390
|
//#region cli.ts
|
|
@@ -5500,6 +5535,13 @@ const registryCommand = command({
|
|
|
5500
5535
|
defaultValue: () => process.env.PH_REGISTRY_UPLINK_MAXAGE,
|
|
5501
5536
|
defaultValueIsSerializable: true
|
|
5502
5537
|
}),
|
|
5538
|
+
trustProxy: option({
|
|
5539
|
+
long: "trust-proxy",
|
|
5540
|
+
type: optional(string),
|
|
5541
|
+
description: "Express `trust proxy` (e.g. 2 proxy hops), so rate limits key on client IPs; env PH_REGISTRY_TRUST_PROXY",
|
|
5542
|
+
defaultValue: () => process.env.PH_REGISTRY_TRUST_PROXY,
|
|
5543
|
+
defaultValueIsSerializable: true
|
|
5544
|
+
}),
|
|
5503
5545
|
webEnabled: flag({
|
|
5504
5546
|
long: "web-enabled",
|
|
5505
5547
|
defaultValue: () => process.env.REGISTRY_WEB !== "false",
|
|
@@ -5546,6 +5588,7 @@ const registryCommand = command({
|
|
|
5546
5588
|
databaseUrl: redact(args.databaseUrl),
|
|
5547
5589
|
listenDatabaseUrl: redact(args.listenDatabaseUrl),
|
|
5548
5590
|
verdaccioSecret: redact(args.verdaccioSecret),
|
|
5591
|
+
s3AccessKeyId: redact(args.s3AccessKeyId),
|
|
5549
5592
|
s3SecretAccessKey: redact(args.s3SecretAccessKey)
|
|
5550
5593
|
});
|
|
5551
5594
|
try {
|