zyrk 0.5.2 → 0.5.4
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/README.md +10 -0
- package/VERSION +1 -1
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +9 -0
- package/dist/cli/parse.d.ts.map +1 -1
- package/dist/cli/parse.js +2 -0
- package/dist/cli/progress.d.ts +10 -0
- package/dist/cli/progress.d.ts.map +1 -0
- package/dist/cli/progress.js +52 -0
- package/dist/install/budgets.d.ts +7 -0
- package/dist/install/budgets.d.ts.map +1 -0
- package/dist/install/budgets.js +25 -0
- package/dist/install/import-npm.d.ts.map +1 -1
- package/dist/install/import-npm.js +23 -7
- package/dist/install/lock.d.ts.map +1 -1
- package/dist/install/lock.js +17 -3
- package/dist/install/run.d.ts +10 -0
- package/dist/install/run.d.ts.map +1 -1
- package/dist/install/run.js +30 -0
- package/dist/install/workspace-install.d.ts.map +1 -1
- package/dist/install/workspace-install.js +19 -1
- package/dist/resolve/spec.d.ts.map +1 -1
- package/dist/resolve/spec.js +8 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -362,3 +362,13 @@ version-qualified selectors, self rules (`.`), and `$direct` references. Direct
|
|
|
362
362
|
dependency overrides must match the declared specification. Workspace member
|
|
363
363
|
overrides are ignored, matching npm root-only policy. Override rule order is
|
|
364
364
|
recorded in the manifest fingerprint; frozen installs reject policy drift.
|
|
365
|
+
|
|
366
|
+
`zyrk help` and `zyrk --help` both show help successfully. Installs report
|
|
367
|
+
preparation, resolution, verified source counts, realization, approved builds,
|
|
368
|
+
and project linking on stderr. Interactive terminals show an activity spinner;
|
|
369
|
+
redirected output contains plain phase messages. `--json` disables progress.
|
|
370
|
+
|
|
371
|
+
Install resolution has a five-minute deadline; each archive extraction has a
|
|
372
|
+
two-minute deadline. Set `ZYRK_RESOLVE_TIMEOUT_MS` or `ZYRK_EXTRACT_TIMEOUT_MS`
|
|
373
|
+
to an integer from `1` to `900000` milliseconds to adjust these timeouts.
|
|
374
|
+
Graph, archive-entry, and byte limits still apply.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v0.5.
|
|
1
|
+
v0.5.4
|
package/dist/cli/main.d.ts
CHANGED
package/dist/cli/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAe,SAAS,EAAe,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,OAAO,EAAoB,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAM3C,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhF,eAAO,MAAM,uBAAuB,IAAI,CAAC;AA2DzC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAwBhD;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA6EF;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,GACnD,SAAS,CAgDX;AAmBD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3D,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;CACxC,CAAC;AAEF,gFAAgF;AAChF,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA4ZpE"}
|
package/dist/cli/main.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createInstallProgress } from "./progress.js";
|
|
1
2
|
import { runMaintenanceCommand } from "../commands/maintenance.js";
|
|
2
3
|
import { runDeployCommand } from "../commands/deploy.js";
|
|
3
4
|
import { runPatchCommand } from "../commands/patch.js";
|
|
@@ -379,6 +380,7 @@ export async function runCli(options) {
|
|
|
379
380
|
(parsed.command === "install" || parsed.command === "i")) {
|
|
380
381
|
if (isGlobalInstallRequest(parsed.command, parsed.commandArgs, options.env))
|
|
381
382
|
return emit(fail(globalInstallError(parsed.command), parsed));
|
|
383
|
+
const progress = createInstallProgress(options.stderr, parsed.json);
|
|
382
384
|
try {
|
|
383
385
|
if (parsed.commandArgs.includes("--help") ||
|
|
384
386
|
parsed.commandArgs.includes("-h")) {
|
|
@@ -413,6 +415,7 @@ export async function runCli(options) {
|
|
|
413
415
|
else
|
|
414
416
|
specs.push(token);
|
|
415
417
|
}
|
|
418
|
+
progress.update({ phase: "planning" });
|
|
416
419
|
const cwd = options.cwd ?? process.cwd();
|
|
417
420
|
const tools = options.tools
|
|
418
421
|
? await options.tools()
|
|
@@ -429,12 +432,14 @@ export async function runCli(options) {
|
|
|
429
432
|
}),
|
|
430
433
|
};
|
|
431
434
|
const result = await installProject({
|
|
435
|
+
onProgress: progress.update,
|
|
432
436
|
...flags,
|
|
433
437
|
env: options.env,
|
|
434
438
|
specs,
|
|
435
439
|
projectDir: cwd,
|
|
436
440
|
...tools,
|
|
437
441
|
});
|
|
442
|
+
progress.close();
|
|
438
443
|
if (parsed.json)
|
|
439
444
|
return emit({
|
|
440
445
|
exitCode: 0,
|
|
@@ -451,8 +456,12 @@ export async function runCli(options) {
|
|
|
451
456
|
});
|
|
452
457
|
}
|
|
453
458
|
catch (error) {
|
|
459
|
+
progress.close();
|
|
454
460
|
return emit(fail(toZyrkError(error, "zyrk install failed."), parsed));
|
|
455
461
|
}
|
|
462
|
+
finally {
|
|
463
|
+
progress.close();
|
|
464
|
+
}
|
|
456
465
|
}
|
|
457
466
|
if (!parsed.help &&
|
|
458
467
|
!parsed.version &&
|
package/dist/cli/parse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/cli/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,6EAA6E;IAC7E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/cli/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,6EAA6E;IAC7E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAmD7D;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAOT"}
|
package/dist/cli/parse.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { InstallProgress } from "../install/run.ts";
|
|
2
|
+
/** Presentation only: never writes to stdout or exposes package URLs or paths. */
|
|
3
|
+
export declare function createInstallProgress(stream: {
|
|
4
|
+
write(chunk: string): unknown;
|
|
5
|
+
isTTY?: boolean;
|
|
6
|
+
}, quiet: boolean): {
|
|
7
|
+
update(event: InstallProgress): void;
|
|
8
|
+
close(): void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/cli/progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAWzD,kFAAkF;AAClF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE;IAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,EAC1D,KAAK,EAAE,OAAO,GACb;IAAE,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAAC,KAAK,IAAI,IAAI,CAAA;CAAE,CAuCzD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const labels = {
|
|
2
|
+
planning: "Preparing installation",
|
|
3
|
+
resolving: "Resolving dependencies",
|
|
4
|
+
fetching: "Verifying package sources",
|
|
5
|
+
realizing: "Preparing shared realizations",
|
|
6
|
+
building: "Preparing approved private builds",
|
|
7
|
+
linking: "Linking project dependencies",
|
|
8
|
+
};
|
|
9
|
+
/** Presentation only: never writes to stdout or exposes package URLs or paths. */
|
|
10
|
+
export function createInstallProgress(stream, quiet) {
|
|
11
|
+
let timer;
|
|
12
|
+
let current = "", last = "", frame = 0, closed = false;
|
|
13
|
+
const write = (text) => {
|
|
14
|
+
try {
|
|
15
|
+
stream.write(text);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
/* A display failure cannot alter installation. */
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const render = () => write(`\r\u001b[2K${["|", "/", "-", "\\"][frame++ % 4]} ${current}`);
|
|
22
|
+
return {
|
|
23
|
+
update(event) {
|
|
24
|
+
if (quiet || closed)
|
|
25
|
+
return;
|
|
26
|
+
current =
|
|
27
|
+
labels[event.phase] +
|
|
28
|
+
(event.total === undefined
|
|
29
|
+
? ""
|
|
30
|
+
: ` (${event.completed ?? 0}/${event.total})`);
|
|
31
|
+
if (stream.isTTY) {
|
|
32
|
+
render();
|
|
33
|
+
if (!timer) {
|
|
34
|
+
timer = setInterval(render, 100);
|
|
35
|
+
timer.unref();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (current !== last)
|
|
39
|
+
write(`zyrk: ${current}\n`);
|
|
40
|
+
last = current;
|
|
41
|
+
},
|
|
42
|
+
close() {
|
|
43
|
+
if (closed)
|
|
44
|
+
return;
|
|
45
|
+
closed = true;
|
|
46
|
+
if (timer)
|
|
47
|
+
clearInterval(timer);
|
|
48
|
+
if (!quiet && stream.isTTY && current)
|
|
49
|
+
write("\r\u001b[2K");
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolverLimits } from "../resolve/resolver.ts";
|
|
2
|
+
import type { ExtractionLimits } from "../extract/tarball.ts";
|
|
3
|
+
export declare function installBudgets(env: NodeJS.ProcessEnv): {
|
|
4
|
+
resolveBudget: Partial<ResolverLimits>;
|
|
5
|
+
extractBudget: Partial<ExtractionLimits>;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=budgets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budgets.d.ts","sourceRoot":"","sources":["../../src/install/budgets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAwB9D,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG;IACtD,aAAa,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC1C,CASA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Public, bounded install timeout configuration. Node and byte limits stay intact. */
|
|
2
|
+
import { ZyrkError } from "../errors.js";
|
|
3
|
+
function timeout(env, key, fallback) {
|
|
4
|
+
const raw = env[key];
|
|
5
|
+
if (raw === undefined)
|
|
6
|
+
return fallback;
|
|
7
|
+
if (!/^[0-9]+$/.test(raw) ||
|
|
8
|
+
!Number.isSafeInteger(Number(raw)) ||
|
|
9
|
+
Number(raw) < 1 ||
|
|
10
|
+
Number(raw) > 900000)
|
|
11
|
+
throw new ZyrkError("ZYRK_POLICY_DENIED", `Cannot configure install: ${key} must be an integer from 1 to 900000.`, {
|
|
12
|
+
remedy: `Set ${key} to a timeout in milliseconds from 1 to 900000, or unset it to use the default.`,
|
|
13
|
+
});
|
|
14
|
+
return Number(raw);
|
|
15
|
+
}
|
|
16
|
+
export function installBudgets(env) {
|
|
17
|
+
return {
|
|
18
|
+
resolveBudget: {
|
|
19
|
+
deadlineMs: timeout(env, "ZYRK_RESOLVE_TIMEOUT_MS", 300000),
|
|
20
|
+
},
|
|
21
|
+
extractBudget: {
|
|
22
|
+
maxDurationMs: timeout(env, "ZYRK_EXTRACT_TIMEOUT_MS", 120000),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,EAC3C,SAAS,GAAE,cAAwC,GAClD,cAAc,
|
|
1
|
+
{"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,EAC3C,SAAS,GAAE,cAAwC,GAClD,cAAc,CAyMhB"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRootOverrides, } from "../resolve/overrides.js";
|
|
3
3
|
import { validateLockDoc } from "../lockfile/read.js";
|
|
4
4
|
import { canonicalStrongSri } from "../util/integrity.js";
|
|
5
|
-
import { valid, satisfies } from "semver";
|
|
5
|
+
import { valid, validRange, satisfies } from "semver";
|
|
6
6
|
import { parseRequirement } from "../resolve/spec.js";
|
|
7
7
|
import { sourceIdOf, sha512Hex } from "../util/hash.js";
|
|
8
8
|
import { cleanUrl, lockMismatch, packageName } from "./lock.js";
|
|
@@ -76,12 +76,28 @@ export function importNpmLock(doc, requirements, origin, overrides = createRootO
|
|
|
76
76
|
peerBindings: [],
|
|
77
77
|
};
|
|
78
78
|
if (entry.engines !== undefined) {
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
if (Array.isArray(entry.engines)) {
|
|
80
|
+
// Old npm manifests used ["node >= 0.2.0"] instead of an engine map.
|
|
81
|
+
const engines = {};
|
|
82
|
+
for (const value of entry.engines) {
|
|
83
|
+
const match = typeof value === "string"
|
|
84
|
+
? /^([a-z][a-z0-9._-]*)\s+(.+)$/.exec(value)
|
|
85
|
+
: null;
|
|
86
|
+
if (!match ||
|
|
87
|
+
Object.hasOwn(engines, match[1]) ||
|
|
88
|
+
validRange(match[2]) === null)
|
|
89
|
+
throw lockMismatch("invalid npm engine constraint");
|
|
90
|
+
engines[match[1]] = match[2];
|
|
91
|
+
}
|
|
92
|
+
node.engines = engines;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
if (typeof entry.engines !== "object" ||
|
|
96
|
+
entry.engines === null ||
|
|
97
|
+
Object.values(entry.engines).some((value) => typeof value !== "string"))
|
|
98
|
+
throw lockMismatch("invalid npm engine constraint");
|
|
99
|
+
node.engines = entry.engines;
|
|
100
|
+
}
|
|
85
101
|
}
|
|
86
102
|
if (typeof entry.bin === "object" &&
|
|
87
103
|
entry.bin !== null &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/install/lock.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMjD;AACD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa/C;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CASnD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc,CA6M3D;
|
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/install/lock.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMjD;AACD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa/C;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CASnD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc,CA6M3D;AAUD,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAK,GAAG,IAAI,CAM3E"}
|
package/dist/install/lock.js
CHANGED
|
@@ -201,10 +201,20 @@ export function lockedGraph(doc) {
|
|
|
201
201
|
}
|
|
202
202
|
return { nodes, roots };
|
|
203
203
|
}
|
|
204
|
+
// npm publishes this canonical GitHub sponsorship link in funding metadata.
|
|
205
|
+
// Keep source/archive URL validation query-free, and allow no other query here.
|
|
206
|
+
function githubFundingUrl(value) {
|
|
207
|
+
return /^https:\/\/github\.com\/[A-Za-z0-9_-]+\/[A-Za-z0-9_.-]+\?sponsor=1$/.test(value);
|
|
208
|
+
}
|
|
204
209
|
/** Preserved metadata is subject to the same portability boundary as new data. */
|
|
205
210
|
export function assertPortableLockMetadata(value, field = "") {
|
|
211
|
+
visitPortableLockMetadata(value, field, field === "funding" ? "entry" : undefined);
|
|
212
|
+
}
|
|
213
|
+
function visitPortableLockMetadata(value, field, funding) {
|
|
206
214
|
if (typeof value === "string") {
|
|
207
|
-
if (/^(?:https?:|file:|git\+|ssh:)/i.test(value) &&
|
|
215
|
+
if (/^(?:https?:|file:|git\+|ssh:)/i.test(value) &&
|
|
216
|
+
!cleanUrl(value) &&
|
|
217
|
+
!(funding && githubFundingUrl(value)))
|
|
208
218
|
throw lockMismatch("portable metadata contains an unsafe URL");
|
|
209
219
|
if (value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value))
|
|
210
220
|
throw lockMismatch("portable metadata contains a local path");
|
|
@@ -212,7 +222,7 @@ export function assertPortableLockMetadata(value, field = "") {
|
|
|
212
222
|
}
|
|
213
223
|
if (Array.isArray(value)) {
|
|
214
224
|
for (const item of value)
|
|
215
|
-
|
|
225
|
+
visitPortableLockMetadata(item, field, funding === "entry" ? "entry" : undefined);
|
|
216
226
|
return;
|
|
217
227
|
}
|
|
218
228
|
if (value && typeof value === "object")
|
|
@@ -234,6 +244,10 @@ export function assertPortableLockMetadata(value, field = "") {
|
|
|
234
244
|
".",
|
|
235
245
|
].includes(field))
|
|
236
246
|
throw lockMismatch("portable metadata contains a credential field");
|
|
237
|
-
|
|
247
|
+
visitPortableLockMetadata(item, key, key === "funding"
|
|
248
|
+
? "entry"
|
|
249
|
+
: funding === "entry" && key === "url"
|
|
250
|
+
? "url"
|
|
251
|
+
: undefined);
|
|
238
252
|
}
|
|
239
253
|
}
|
package/dist/install/run.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { type BuildCandidate } from "./private.ts";
|
|
2
2
|
import { RegistryClient } from "../fetch/registry.ts";
|
|
3
|
+
import type { ResolverLimits } from "../resolve/resolver.ts";
|
|
4
|
+
import type { ExtractionLimits } from "../extract/tarball.ts";
|
|
3
5
|
import { Store } from "../store/layout.ts";
|
|
6
|
+
export type InstallProgress = {
|
|
7
|
+
phase: "planning" | "resolving" | "fetching" | "realizing" | "building" | "linking";
|
|
8
|
+
completed?: number;
|
|
9
|
+
total?: number;
|
|
10
|
+
};
|
|
4
11
|
export type InstallOptions = {
|
|
12
|
+
onProgress?: (event: InstallProgress) => void;
|
|
5
13
|
projectDir: string;
|
|
6
14
|
store: Store;
|
|
7
15
|
registry: RegistryClient;
|
|
@@ -26,6 +34,8 @@ export type InstallOptions = {
|
|
|
26
34
|
approveBuilds?: readonly string[];
|
|
27
35
|
rebuild?: boolean;
|
|
28
36
|
repair?: boolean;
|
|
37
|
+
resolveBudget?: Partial<ResolverLimits>;
|
|
38
|
+
extractBudget?: Partial<ExtractionLimits>;
|
|
29
39
|
fetchBudget?: {
|
|
30
40
|
maxArchiveBytes?: number;
|
|
31
41
|
maxExpandedBytes?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAYtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAYtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAgC3C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EACD,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,SAAS,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1C,WAAW,CAAC,EAAE;QACZ,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EACL,OAAO,GACP,uBAAuB,GACvB,eAAe,GACf,SAAS,GACT,cAAc,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AA4GF,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAs0BxB"}
|
package/dist/install/run.js
CHANGED
|
@@ -15,6 +15,7 @@ import npa from "npm-package-arg";
|
|
|
15
15
|
import { satisfies } from "semver";
|
|
16
16
|
import { ZyrkError } from "../errors.js";
|
|
17
17
|
import { RegistryClient } from "../fetch/registry.js";
|
|
18
|
+
import { installBudgets } from "./budgets.js";
|
|
18
19
|
import { extractTarball } from "../extract/tarball.js";
|
|
19
20
|
import { commitExtractedSource } from "../store/source.js";
|
|
20
21
|
import { Store } from "../store/layout.js";
|
|
@@ -93,6 +94,13 @@ function scriptPolicy(manifest) {
|
|
|
93
94
|
return object(manifest.zyrk) ? manifest.zyrk.scripts : undefined;
|
|
94
95
|
}
|
|
95
96
|
export async function installProject(options) {
|
|
97
|
+
options.onProgress?.({ phase: "planning" });
|
|
98
|
+
const budgets = installBudgets(options.env ?? process.env);
|
|
99
|
+
options = {
|
|
100
|
+
...options,
|
|
101
|
+
resolveBudget: { ...budgets.resolveBudget, ...options.resolveBudget },
|
|
102
|
+
extractBudget: { ...budgets.extractBudget, ...options.extractBudget },
|
|
103
|
+
};
|
|
96
104
|
if (await findWorkspaceRoot(options.projectDir)) {
|
|
97
105
|
const { installWorkspaceProject } = await import("./workspace-install.js");
|
|
98
106
|
return installWorkspaceProject(options);
|
|
@@ -248,8 +256,10 @@ export async function installProject(options) {
|
|
|
248
256
|
throw error("ZYRK_OFFLINE_MISSING", "Offline installation requires an existing compatible zyrk lockfile.");
|
|
249
257
|
const prior = existing?.zyrk ? lockedGraph(existing) : undefined;
|
|
250
258
|
const fresh = new Set(specs.map((spec) => npa(spec).name));
|
|
259
|
+
options.onProgress?.({ phase: "resolving" });
|
|
251
260
|
resolved = await resolveRequirements({
|
|
252
261
|
overrides,
|
|
262
|
+
limits: options.resolveBudget,
|
|
253
263
|
provider: {
|
|
254
264
|
origin: options.registry.origin,
|
|
255
265
|
originFor: (name) => options.registry.originFor(name),
|
|
@@ -460,10 +470,21 @@ export async function installProject(options) {
|
|
|
460
470
|
})
|
|
461
471
|
: undefined;
|
|
462
472
|
const unique = new Map(activeNodes.map((n) => [n.sourceId, n]));
|
|
473
|
+
let completedSources = 0;
|
|
474
|
+
options.onProgress?.({
|
|
475
|
+
phase: "fetching",
|
|
476
|
+
completed: 0,
|
|
477
|
+
total: unique.size,
|
|
478
|
+
});
|
|
463
479
|
for (const node of unique.values()) {
|
|
464
480
|
operation.operation.checkpoint();
|
|
465
481
|
if (await pathExists(sourceManifestPath(options.store, node.sourceId))) {
|
|
466
482
|
await readSourceManifest(options.store, node.sourceId);
|
|
483
|
+
options.onProgress?.({
|
|
484
|
+
phase: "fetching",
|
|
485
|
+
completed: ++completedSources,
|
|
486
|
+
total: unique.size,
|
|
487
|
+
});
|
|
467
488
|
continue;
|
|
468
489
|
}
|
|
469
490
|
if (options.offline)
|
|
@@ -480,6 +501,7 @@ export async function installProject(options) {
|
|
|
480
501
|
label: `${node.name}@${node.version}`,
|
|
481
502
|
});
|
|
482
503
|
const extracted = await extractTarball({
|
|
504
|
+
limits: options.extractBudget,
|
|
483
505
|
signal: operation.operation.signal,
|
|
484
506
|
onExpandedBytes: operation.operation.consumeExpandedBytes,
|
|
485
507
|
tarballPath: tarball,
|
|
@@ -497,6 +519,11 @@ export async function installProject(options) {
|
|
|
497
519
|
if (source.sourceId !== node.sourceId)
|
|
498
520
|
throw lockMismatch("download identity disagrees with the locked source");
|
|
499
521
|
await rm(tarball, { force: true });
|
|
522
|
+
options.onProgress?.({
|
|
523
|
+
phase: "fetching",
|
|
524
|
+
completed: ++completedSources,
|
|
525
|
+
total: unique.size,
|
|
526
|
+
});
|
|
500
527
|
}
|
|
501
528
|
for (const node of unique.values())
|
|
502
529
|
assertSupportedSourcePayload(node, await readSourceManifest(options.store, node.sourceId));
|
|
@@ -509,6 +536,7 @@ export async function installProject(options) {
|
|
|
509
536
|
warnings,
|
|
510
537
|
};
|
|
511
538
|
const graph = createGraphDoc(activeNodes.map((n) => ({ ...n, deps: n.edges })));
|
|
539
|
+
options.onProgress?.({ phase: "realizing" });
|
|
512
540
|
const sharedRealized = await realizeGraph({
|
|
513
541
|
store: options.store,
|
|
514
542
|
graph,
|
|
@@ -581,6 +609,7 @@ export async function installProject(options) {
|
|
|
581
609
|
});
|
|
582
610
|
privateGraph = true;
|
|
583
611
|
}
|
|
612
|
+
options.onProgress?.({ phase: "building" });
|
|
584
613
|
await buildPrivate({
|
|
585
614
|
project,
|
|
586
615
|
generationId,
|
|
@@ -667,6 +696,7 @@ export async function installProject(options) {
|
|
|
667
696
|
roots: selectedRoots.map((r) => r.target),
|
|
668
697
|
readiness,
|
|
669
698
|
});
|
|
699
|
+
options.onProgress?.({ phase: "linking" });
|
|
670
700
|
const published = await installProjection(project, entries, {
|
|
671
701
|
generationId,
|
|
672
702
|
lockHeld: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyH9D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyH9D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CA+qBxB"}
|
|
@@ -161,6 +161,7 @@ export async function installWorkspaceProject(options) {
|
|
|
161
161
|
if (!graph) {
|
|
162
162
|
if (options.frozen || options.offline)
|
|
163
163
|
throw lockMismatch("offline/frozen workspace install needs a compatible lock");
|
|
164
|
+
options.onProgress?.({ phase: "resolving" });
|
|
164
165
|
graph = await resolveWorkspaceGraph(project, {
|
|
165
166
|
origin: options.registry.origin,
|
|
166
167
|
originFor: (name) => options.registry.originFor(name),
|
|
@@ -170,6 +171,7 @@ export async function installWorkspaceProject(options) {
|
|
|
170
171
|
}, {
|
|
171
172
|
...(existing ? { previous: existing.graph } : {}),
|
|
172
173
|
fresh: mutation.fresh,
|
|
174
|
+
...options.resolveBudget,
|
|
173
175
|
});
|
|
174
176
|
}
|
|
175
177
|
assertWorkspacePlatform(graph);
|
|
@@ -261,7 +263,14 @@ export async function installWorkspaceProject(options) {
|
|
|
261
263
|
offline: options.offline === true,
|
|
262
264
|
})
|
|
263
265
|
: undefined;
|
|
264
|
-
|
|
266
|
+
const uniqueSources = new Map(nodes.map((n) => [n.sourceId, n]));
|
|
267
|
+
let completedSources = 0;
|
|
268
|
+
options.onProgress?.({
|
|
269
|
+
phase: "fetching",
|
|
270
|
+
completed: 0,
|
|
271
|
+
total: uniqueSources.size,
|
|
272
|
+
});
|
|
273
|
+
for (const node of uniqueSources.values()) {
|
|
265
274
|
operation.operation.checkpoint();
|
|
266
275
|
if (!(await pathExists(sourceManifestPath(options.store, node.sourceId)))) {
|
|
267
276
|
if (options.offline)
|
|
@@ -279,6 +288,7 @@ export async function installWorkspaceProject(options) {
|
|
|
279
288
|
onBytes: operation.operation.consumeArchiveBytes,
|
|
280
289
|
});
|
|
281
290
|
const extraction = await extractTarball({
|
|
291
|
+
limits: options.extractBudget,
|
|
282
292
|
tarballPath: archive,
|
|
283
293
|
destDir: path.join(txn.dir, node.sourceId),
|
|
284
294
|
signal: operation.operation.signal,
|
|
@@ -298,6 +308,11 @@ export async function installWorkspaceProject(options) {
|
|
|
298
308
|
await rm(archive, { force: true });
|
|
299
309
|
}
|
|
300
310
|
assertSupportedSourcePayload(node, await readSourceManifest(options.store, node.sourceId));
|
|
311
|
+
options.onProgress?.({
|
|
312
|
+
phase: "fetching",
|
|
313
|
+
completed: ++completedSources,
|
|
314
|
+
total: uniqueSources.size,
|
|
315
|
+
});
|
|
301
316
|
}
|
|
302
317
|
if (options.fetchOnly)
|
|
303
318
|
return {
|
|
@@ -306,6 +321,7 @@ export async function installWorkspaceProject(options) {
|
|
|
306
321
|
reused: 0,
|
|
307
322
|
warnings,
|
|
308
323
|
};
|
|
324
|
+
options.onProgress?.({ phase: "realizing" });
|
|
309
325
|
const shared = await realizeGraph({
|
|
310
326
|
store: options.store,
|
|
311
327
|
graph: pureGraph,
|
|
@@ -443,6 +459,7 @@ export async function installWorkspaceProject(options) {
|
|
|
443
459
|
});
|
|
444
460
|
// Approved writes need a coherent fully private registry closure.
|
|
445
461
|
await allocatePrivate(new Set(nodes.map((n) => n.key)));
|
|
462
|
+
options.onProgress?.({ phase: "building" });
|
|
446
463
|
await buildPrivate({
|
|
447
464
|
project: root,
|
|
448
465
|
generationId,
|
|
@@ -498,6 +515,7 @@ export async function installWorkspaceProject(options) {
|
|
|
498
515
|
bins[name] = actual;
|
|
499
516
|
}
|
|
500
517
|
}
|
|
518
|
+
options.onProgress?.({ phase: "linking" });
|
|
501
519
|
await installProjection(holder, node.edges.map((e) => ({
|
|
502
520
|
name: e.name,
|
|
503
521
|
linkTarget: realized.packageDirByKey.get(e.target),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/resolve/spec.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/resolve/spec.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,eAAe,CAAC;IACtB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;CACvC,CAAC;AAcF;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,iBAAiB,CA6FnB"}
|
package/dist/resolve/spec.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* explicitly — they are never handed to a tool that might run scripts.
|
|
8
8
|
*/
|
|
9
9
|
import npa from "npm-package-arg";
|
|
10
|
+
import { SemVer } from "semver";
|
|
10
11
|
import { ZyrkError } from "../errors.js";
|
|
11
12
|
function unsupported(what, spec) {
|
|
12
13
|
return new ZyrkError("ZYRK_RESOLUTION_FAILED", `unsupported dependency protocol in "${spec}" (${what})`, {
|
|
@@ -46,7 +47,13 @@ export function parseRequirement(edgeName, spec) {
|
|
|
46
47
|
edgeName,
|
|
47
48
|
realName: parsed.name,
|
|
48
49
|
kind: "exact",
|
|
49
|
-
|
|
50
|
+
// npm accepts = and v prefixes for exact versions. SemVer.format()
|
|
51
|
+
// omits build metadata, so append it explicitly for registry lookup.
|
|
52
|
+
targetSpec: (() => {
|
|
53
|
+
const version = new SemVer(parsed.fetchSpec.replace(/^[=v\s]+/, ""));
|
|
54
|
+
return (version.version +
|
|
55
|
+
(version.build.length ? `+${version.build.join(".")}` : ""));
|
|
56
|
+
})(),
|
|
50
57
|
targetKind: "exact",
|
|
51
58
|
};
|
|
52
59
|
}
|