gutterpress 0.11.10-alpha.2 → 0.11.10-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -46
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +10 -6
- package/dist/{build-dfpvvhys.js → build-npxq1tvm.js} +7 -6
- package/dist/cdp-jg95s674.js +15 -0
- package/dist/cdp-smdx6mr3.js +16 -0
- package/dist/{cli-d8rdk1y7.js → cli-30j93gzt.js} +11 -335
- package/dist/{cli-pfczdbyd.js → cli-5qr3z0qa.js} +10 -404
- package/dist/{cli-c41yr7he.js → cli-7fkhgtfn.js} +3 -1
- package/dist/{cli-k2hwrp7s.js → cli-97bdz5k0.js} +1 -4
- package/dist/cli-kkzka31p.js +261 -0
- package/dist/{cli-p679pvce.js → cli-vbzkkcbv.js} +2 -2
- package/dist/{cli-4xksazfr.js → cli-z8ye91f0.js} +283 -1142
- package/dist/cli.js +12 -14
- package/dist/{doctor-hheax5yc.js → doctor-ykr6gtpv.js} +3 -3
- package/dist/engine/shared/cdp.d.ts +23 -19
- package/dist/engine-3gwctsty.js +24 -0
- package/dist/engine-mwshptgf.js +25 -0
- package/dist/{ext-q5024j6v.js → ext-bna9nr3v.js} +7 -6
- package/dist/{index-1a4rx87v.js → index-322fxk25.js} +344 -1130
- package/dist/{index-kqftehgy.js → index-dzp0hc2c.js} +4 -2
- package/dist/{index-fnhak0nh.js → index-qf7y4d85.js} +10 -404
- package/dist/index-r4wvy5v3.js +267 -0
- package/dist/{index-t43k5rq1.js → index-rzm1phg0.js} +23 -356
- package/dist/index.d.ts +0 -1
- package/dist/index.js +12 -87
- package/dist/lib/build-error.d.ts +4 -5
- package/dist/lib/build-preflight.d.ts +1 -35
- package/dist/lib/build-runner.d.ts +27 -44
- package/dist/lib/chromium.d.ts +5 -1
- package/dist/lib/engine.d.ts +3 -18
- package/dist/lib/extension-manager.d.ts +2 -2
- package/dist/lib/extension-manifest.d.ts +1 -1
- package/dist/lib/markdown/assemble.d.ts +2 -9
- package/dist/lib/markdown/index.d.ts +2 -4
- package/dist/lib/markdown/plugins.d.ts +0 -3
- package/dist/lib/npm-plugin-installer.d.ts +6 -1
- package/dist/lib/plugin-vendor.d.ts +10 -78
- package/dist/lib/source-provider.d.ts +1 -1
- package/dist/lib/validation-exec.d.ts +5 -6
- package/dist/{new-6xm4tdxb.js → new-0hv3nwqj.js} +9 -8
- package/dist/{preflight-ezt8rvg3.js → preflight-pk0k25fm.js} +7 -6
- package/dist/preview/file-watcher.d.ts +4 -43
- package/dist/preview/http-server.d.ts +1 -3
- package/dist/{preview-hehs46dd.js → preview-8b1fn59h.js} +7 -6
- package/dist/{preview-shell-gqnc5xxe.js → preview-shell-tqndvhbx.js} +5 -7
- package/dist/{publish-ha505ejq.js → publish-ba5h76tz.js} +7 -6
- package/dist/render.d.ts +1 -1
- package/dist/render.js +1 -9
- package/dist/{source-provider-ta09wegv.js → source-provider-pzmz0br9.js} +1 -1
- package/dist/{source-provider-7c2ww3bz.js → source-provider-qbthnmqw.js} +1 -1
- package/dist/{validate-je56vdbj.js → validate-4rq2r5b3.js} +7 -6
- package/package.json +1 -4
- package/dist/audit-v9594a72.js +0 -69
- package/dist/engine-qtfrfbpk.js +0 -41
- package/dist/engine-trte2tg2.js +0 -40
- package/dist/lib/browser-pool.d.ts +0 -35
- package/dist/lib/lint-runner.d.ts +0 -29
- package/dist/lint-tbywt66a.js +0 -68
|
@@ -148,42 +148,14 @@ function formatData(data, clean) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// src/lib/plugin-vendor.ts
|
|
151
|
-
import {
|
|
152
|
-
import { createReadStream } from "node:fs";
|
|
153
|
-
import { lstat, readFile, readdir, realpath } from "node:fs/promises";
|
|
151
|
+
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
154
152
|
import path2 from "node:path";
|
|
155
153
|
import { exports as resolveExports } from "resolve.exports";
|
|
156
|
-
import { satisfies, validRange } from "semver";
|
|
157
|
-
|
|
158
|
-
// src/lib/npm-registry.ts
|
|
159
|
-
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
160
|
-
var ENV_OVERRIDE = "GUTTERPRESS_NPM_REGISTRY";
|
|
161
|
-
function npmRegistryUrl() {
|
|
162
|
-
const configured = process.env[ENV_OVERRIDE]?.trim();
|
|
163
|
-
if (!configured)
|
|
164
|
-
return DEFAULT_NPM_REGISTRY;
|
|
165
|
-
let scheme;
|
|
166
|
-
try {
|
|
167
|
-
scheme = new URL(configured).protocol;
|
|
168
|
-
} catch {
|
|
169
|
-
throw new Error(`Invalid ${ENV_OVERRIDE} URL "${configured}".`);
|
|
170
|
-
}
|
|
171
|
-
if (scheme !== "http:" && scheme !== "https:") {
|
|
172
|
-
throw new Error(`${ENV_OVERRIDE} must be an http(s) URL — got "${scheme}".`);
|
|
173
|
-
}
|
|
174
|
-
return configured.replace(/\/+$/, "");
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// src/lib/plugin-vendor.ts
|
|
178
154
|
var PLUGINS_DIR = "plugins";
|
|
179
155
|
var VENDORED_NPM_DIR = "npm";
|
|
180
|
-
var VENDOR_RECEIPT_FILE = ".gutterpress-install.json";
|
|
181
|
-
var VENDOR_RECEIPT_VERSION = 2;
|
|
182
156
|
var NPM_SEGMENT = /^[a-z0-9][a-z0-9._~-]*$/;
|
|
183
157
|
var EXACT_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
184
158
|
var WINDOWS_RESERVED = /^(con|prn|aux|nul|clock\$|conin\$|conout\$|com[1-9¹²³]|lpt[1-9¹²³])(?:\..*)?$/i;
|
|
185
|
-
var MAX_VERIFIED_FILES = 50000;
|
|
186
|
-
var MAX_VERIFIED_BYTES = 512 * 1024 * 1024;
|
|
187
159
|
function isValidNpmPackageName(name) {
|
|
188
160
|
if (!name || name.length > 214 || name !== name.toLowerCase())
|
|
189
161
|
return false;
|
|
@@ -236,10 +208,6 @@ function vendoredNpmPluginPackageDir(installRoot, name) {
|
|
|
236
208
|
function toPosixPath(value) {
|
|
237
209
|
return value.split(path2.sep).join("/");
|
|
238
210
|
}
|
|
239
|
-
function packageEntryFormat(manifest, relativeEntry) {
|
|
240
|
-
const extension = path2.posix.extname(relativeEntry);
|
|
241
|
-
return extension === ".cjs" || extension === ".json" || extension !== ".mjs" && manifest.type !== "module" ? "commonjs" : "module";
|
|
242
|
-
}
|
|
243
211
|
function assertWindowsSafeRelativePath(relative) {
|
|
244
212
|
if (!relative || relative.includes("\\") || relative.startsWith("/") || /^[a-zA-Z]:/.test(relative)) {
|
|
245
213
|
throw new Error(`Unsafe package path: ${relative || "(empty)"}`);
|
|
@@ -258,12 +226,6 @@ function assertWindowsSafeRelativePath(relative) {
|
|
|
258
226
|
function windowsPathKey(relative) {
|
|
259
227
|
return relative.normalize("NFKC").toLowerCase();
|
|
260
228
|
}
|
|
261
|
-
function safeReceiptPath(relative, label) {
|
|
262
|
-
if (typeof relative !== "string")
|
|
263
|
-
throw new Error(`${label} must be a string.`);
|
|
264
|
-
assertWindowsSafeRelativePath(relative);
|
|
265
|
-
return relative;
|
|
266
|
-
}
|
|
267
229
|
function isContained(root, candidate) {
|
|
268
230
|
const relative = path2.relative(root, candidate);
|
|
269
231
|
return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
|
|
@@ -271,38 +233,6 @@ function isContained(root, candidate) {
|
|
|
271
233
|
function object(value) {
|
|
272
234
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
273
235
|
}
|
|
274
|
-
function stringMap(value) {
|
|
275
|
-
const map = object(value);
|
|
276
|
-
if (!map)
|
|
277
|
-
return {};
|
|
278
|
-
const result = {};
|
|
279
|
-
for (const [name, selector] of Object.entries(map)) {
|
|
280
|
-
if (typeof selector === "string" && selector.trim())
|
|
281
|
-
result[name] = selector.trim();
|
|
282
|
-
}
|
|
283
|
-
return result;
|
|
284
|
-
}
|
|
285
|
-
function dependencyDeclarations(manifest) {
|
|
286
|
-
const required = stringMap(manifest.dependencies);
|
|
287
|
-
const optional = stringMap(manifest.optionalDependencies);
|
|
288
|
-
for (const name of Object.keys(optional))
|
|
289
|
-
delete required[name];
|
|
290
|
-
const peers = stringMap(manifest.peerDependencies);
|
|
291
|
-
const peerMeta = object(manifest.peerDependenciesMeta) ?? {};
|
|
292
|
-
const optionalPeers = {};
|
|
293
|
-
for (const [name, selector] of Object.entries(peers)) {
|
|
294
|
-
if (name in required || name in optional)
|
|
295
|
-
continue;
|
|
296
|
-
if (object(peerMeta[name])?.optional === true)
|
|
297
|
-
optionalPeers[name] = selector;
|
|
298
|
-
else
|
|
299
|
-
required[name] = selector;
|
|
300
|
-
}
|
|
301
|
-
return { required, optional, optionalPeers };
|
|
302
|
-
}
|
|
303
|
-
function unsupportedRegistrySelector(selector) {
|
|
304
|
-
return /^(?:file:|git\+|https?:|ssh:|github:|workspace:|link:|npm:)/i.test(selector);
|
|
305
|
-
}
|
|
306
236
|
async function readPackageJson(packageDir) {
|
|
307
237
|
const packageJsonPath = path2.join(packageDir, "package.json");
|
|
308
238
|
const info = await lstat(packageJsonPath);
|
|
@@ -314,26 +244,6 @@ async function readPackageJson(packageDir) {
|
|
|
314
244
|
throw new Error(`Package metadata is not an object: ${packageJsonPath}`);
|
|
315
245
|
return parsed;
|
|
316
246
|
}
|
|
317
|
-
async function verifyReceiptEntry(installRoot, packagePath, entry, label) {
|
|
318
|
-
if (entry === undefined)
|
|
319
|
-
return;
|
|
320
|
-
const relative = safeReceiptPath(entry, label);
|
|
321
|
-
if (!relative.startsWith(`${packagePath}/`)) {
|
|
322
|
-
throw new Error(`${label} is outside its package.`);
|
|
323
|
-
}
|
|
324
|
-
const packageDir = path2.resolve(installRoot, ...packagePath.split("/"));
|
|
325
|
-
const entryPath = path2.resolve(installRoot, ...relative.split("/"));
|
|
326
|
-
const [realPackageDir, realEntry] = await Promise.all([
|
|
327
|
-
realpath(packageDir),
|
|
328
|
-
realpath(entryPath)
|
|
329
|
-
]);
|
|
330
|
-
if (!isContained(realPackageDir, realEntry))
|
|
331
|
-
throw new Error(`${label} escapes its package.`);
|
|
332
|
-
const info = await lstat(realEntry);
|
|
333
|
-
if (!info.isFile() || info.isSymbolicLink())
|
|
334
|
-
throw new Error(`${label} is not a regular file.`);
|
|
335
|
-
return realEntry;
|
|
336
|
-
}
|
|
337
247
|
function packageResolutionTargets(manifest, subpath, condition) {
|
|
338
248
|
if (manifest.exports !== undefined) {
|
|
339
249
|
try {
|
|
@@ -401,112 +311,16 @@ async function resolveEntryCandidate(packageDir, resolution) {
|
|
|
401
311
|
}
|
|
402
312
|
return null;
|
|
403
313
|
}
|
|
404
|
-
async function resolvePackageEntry(packageDir, packageJson
|
|
314
|
+
async function resolvePackageEntry(packageDir, packageJson) {
|
|
405
315
|
const manifest = packageJson ?? await readPackageJson(packageDir);
|
|
406
|
-
for (const
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
throw new Error("Package has no contained JavaScript entry point for ESM import.");
|
|
412
|
-
}
|
|
413
|
-
async function listTreeEntries(root) {
|
|
414
|
-
const out = [];
|
|
415
|
-
async function visit(dir) {
|
|
416
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
417
|
-
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
418
|
-
for (const entry of entries) {
|
|
419
|
-
const absolute = path2.join(dir, entry.name);
|
|
420
|
-
const relative = toPosixPath(path2.relative(root, absolute));
|
|
421
|
-
if (relative === VENDOR_RECEIPT_FILE)
|
|
422
|
-
continue;
|
|
423
|
-
if (entry.isSymbolicLink())
|
|
424
|
-
throw new Error(`Vendor tree contains a symbolic link: ${relative}`);
|
|
425
|
-
if (entry.isDirectory()) {
|
|
426
|
-
out.push({ relative, directory: true });
|
|
427
|
-
await visit(absolute);
|
|
428
|
-
} else if (entry.isFile())
|
|
429
|
-
out.push({ relative, directory: false });
|
|
430
|
-
else
|
|
431
|
-
throw new Error(`Vendor tree contains an unsupported filesystem entry: ${relative}`);
|
|
316
|
+
for (const condition of ["import", "require"]) {
|
|
317
|
+
for (const target of packageResolutionTargets(manifest, "", condition)) {
|
|
318
|
+
const resolved = await resolveEntryCandidate(packageDir, target);
|
|
319
|
+
if (resolved)
|
|
320
|
+
return resolved;
|
|
432
321
|
}
|
|
433
322
|
}
|
|
434
|
-
|
|
435
|
-
return out;
|
|
436
|
-
}
|
|
437
|
-
async function computeVendorTreeDigest(root) {
|
|
438
|
-
const entries = await listTreeEntries(root);
|
|
439
|
-
const files = entries.filter((entry) => !entry.directory);
|
|
440
|
-
if (files.length > MAX_VERIFIED_FILES) {
|
|
441
|
-
throw new Error(`Vendor tree contains more than ${MAX_VERIFIED_FILES} files.`);
|
|
442
|
-
}
|
|
443
|
-
const seen = new Set;
|
|
444
|
-
const hash = createHash("sha256");
|
|
445
|
-
let bytes = 0;
|
|
446
|
-
for (const entry of entries) {
|
|
447
|
-
const { relative } = entry;
|
|
448
|
-
assertWindowsSafeRelativePath(relative);
|
|
449
|
-
const key = windowsPathKey(relative);
|
|
450
|
-
if (seen.has(key))
|
|
451
|
-
throw new Error(`Vendor tree has a Windows-colliding path: ${relative}`);
|
|
452
|
-
seen.add(key);
|
|
453
|
-
if (entry.directory)
|
|
454
|
-
continue;
|
|
455
|
-
const absolute = path2.join(root, ...relative.split("/"));
|
|
456
|
-
const info = await lstat(absolute);
|
|
457
|
-
if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) {
|
|
458
|
-
throw new Error(`Vendor tree file is not an independent regular file: ${relative}`);
|
|
459
|
-
}
|
|
460
|
-
bytes += info.size;
|
|
461
|
-
if (bytes > MAX_VERIFIED_BYTES) {
|
|
462
|
-
throw new Error(`Vendor tree exceeds ${Math.round(MAX_VERIFIED_BYTES / 1024 / 1024)}MB.`);
|
|
463
|
-
}
|
|
464
|
-
hash.update(`${Buffer.byteLength(relative)}:${relative}:${info.size}\x00`);
|
|
465
|
-
for await (const chunk of createReadStream(absolute))
|
|
466
|
-
hash.update(chunk);
|
|
467
|
-
}
|
|
468
|
-
return { digest: hash.digest("hex"), files: files.length, bytes };
|
|
469
|
-
}
|
|
470
|
-
async function assertVendorPackageOwnership(root, packagePaths) {
|
|
471
|
-
const packages = packagePaths.map((relative) => ({
|
|
472
|
-
relative,
|
|
473
|
-
key: windowsPathKey(relative),
|
|
474
|
-
parts: relative.split("/").length
|
|
475
|
-
})).sort((a, b) => b.key.length - a.key.length);
|
|
476
|
-
for (const entry of await listTreeEntries(root)) {
|
|
477
|
-
const actualParts = entry.relative.split("/");
|
|
478
|
-
for (const part of actualParts) {
|
|
479
|
-
if (part.normalize("NFKC").toLowerCase() === "node_modules" && part !== "node_modules") {
|
|
480
|
-
throw new Error(`Vendor tree contains a non-canonical node_modules path: ${entry.relative}`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
const key = windowsPathKey(entry.relative);
|
|
484
|
-
const structural = packages.some((pkg) => pkg.key === key || pkg.key.startsWith(`${key}/`));
|
|
485
|
-
if (entry.directory && structural)
|
|
486
|
-
continue;
|
|
487
|
-
const owner = packages.find((pkg) => key.startsWith(`${pkg.key}/`));
|
|
488
|
-
if (!owner)
|
|
489
|
-
throw new Error(`Vendor tree path is not owned by a receipt package: ${entry.relative}`);
|
|
490
|
-
const packageRelative = actualParts.slice(owner.parts);
|
|
491
|
-
const nodeModulesAt = packageRelative.findIndex((part) => part.normalize("NFKC").toLowerCase() === "node_modules");
|
|
492
|
-
if (nodeModulesAt < 0)
|
|
493
|
-
continue;
|
|
494
|
-
const generatedEmptyDirectory = entry.directory && nodeModulesAt === 0 && (packageRelative.length === 1 || packageRelative.length === 2 && packageRelative[1].startsWith("@"));
|
|
495
|
-
if (!generatedEmptyDirectory) {
|
|
496
|
-
throw new Error(`Package contains bundled node_modules content: ${entry.relative}`);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
async function recomputeReceiptEntry(packageDir, packagePath, manifest, condition) {
|
|
501
|
-
try {
|
|
502
|
-
const entry = await resolvePackageEntry(packageDir, manifest, condition);
|
|
503
|
-
return `${packagePath}/${entry}`;
|
|
504
|
-
} catch (error) {
|
|
505
|
-
if (error instanceof Error && error.message.includes("no contained JavaScript entry point")) {
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
throw error;
|
|
509
|
-
}
|
|
323
|
+
throw new Error("Package has no contained JavaScript entry point.");
|
|
510
324
|
}
|
|
511
325
|
async function resolveVendoredPluginInstallRoot(projectDir, expectedName, expectedVersion) {
|
|
512
326
|
const requestedProjectRoot = path2.resolve(projectDir);
|
|
@@ -531,214 +345,6 @@ async function resolveVendoredPluginInstallRoot(projectDir, expectedName, expect
|
|
|
531
345
|
}
|
|
532
346
|
return installRoot;
|
|
533
347
|
}
|
|
534
|
-
function reconcileReceiptGraph(receipt, packages, manifests) {
|
|
535
|
-
if (!Array.isArray(receipt.skipped))
|
|
536
|
-
throw new Error("Vendor receipt skipped list is invalid.");
|
|
537
|
-
const declarations = new Map;
|
|
538
|
-
for (const [packagePath, manifest] of manifests) {
|
|
539
|
-
declarations.set(packagePath, dependencyDeclarations(manifest));
|
|
540
|
-
}
|
|
541
|
-
const skippedByEdge = new Map;
|
|
542
|
-
for (const skipped of receipt.skipped) {
|
|
543
|
-
if (!packages.has(skipped.from) || !isValidNpmPackageName(skipped.name) || typeof skipped.selector !== "string" || !["optional", "optional-peer"].includes(skipped.kind) || typeof skipped.reason !== "string") {
|
|
544
|
-
throw new Error("Vendor receipt contains an invalid skipped dependency.");
|
|
545
|
-
}
|
|
546
|
-
const declared = declarations.get(skipped.from);
|
|
547
|
-
const expectedSelector = skipped.kind === "optional" ? declared.optional[skipped.name] : declared.optionalPeers[skipped.name];
|
|
548
|
-
if (expectedSelector !== skipped.selector) {
|
|
549
|
-
throw new Error(`Skipped dependency is not declared as ${skipped.kind}: ${skipped.name}`);
|
|
550
|
-
}
|
|
551
|
-
const key = `${skipped.from}\x00${skipped.name}`;
|
|
552
|
-
if (skippedByEdge.has(key))
|
|
553
|
-
throw new Error(`Duplicate skipped dependency: ${skipped.name}`);
|
|
554
|
-
skippedByEdge.set(key, skipped);
|
|
555
|
-
}
|
|
556
|
-
for (const pkg of receipt.packages) {
|
|
557
|
-
if (!object(pkg.dependencies))
|
|
558
|
-
throw new Error(`Invalid dependency map for ${pkg.name}.`);
|
|
559
|
-
const declared = declarations.get(pkg.path);
|
|
560
|
-
for (const [dependency, target] of Object.entries(pkg.dependencies)) {
|
|
561
|
-
const targetPackage = packages.get(target);
|
|
562
|
-
if (!isValidNpmPackageName(dependency) || !targetPackage || targetPackage.name !== dependency) {
|
|
563
|
-
throw new Error(`Broken dependency edge ${pkg.name} -> ${dependency}.`);
|
|
564
|
-
}
|
|
565
|
-
const selector = declared.required[dependency] ?? declared.optional[dependency];
|
|
566
|
-
if (!selector)
|
|
567
|
-
throw new Error(`Undeclared dependency edge ${pkg.name} -> ${dependency}.`);
|
|
568
|
-
if (unsupportedRegistrySelector(selector)) {
|
|
569
|
-
throw new Error(`Unsupported selector on dependency edge ${pkg.name} -> ${dependency}.`);
|
|
570
|
-
}
|
|
571
|
-
const range = validRange(selector);
|
|
572
|
-
if (range && !satisfies(targetPackage.version, range)) {
|
|
573
|
-
throw new Error(`Dependency edge ${pkg.name} -> ${dependency}@${targetPackage.version} does not satisfy ${selector}.`);
|
|
574
|
-
}
|
|
575
|
-
if (skippedByEdge.has(`${pkg.path}\x00${dependency}`)) {
|
|
576
|
-
throw new Error(`Dependency is both installed and skipped: ${pkg.name} -> ${dependency}.`);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
for (const dependency of Object.keys(declared.required)) {
|
|
580
|
-
if (!(dependency in pkg.dependencies)) {
|
|
581
|
-
throw new Error(`Missing required dependency edge ${pkg.name} -> ${dependency}.`);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
for (const dependency of Object.keys(declared.optional)) {
|
|
585
|
-
if (!(dependency in pkg.dependencies) && !skippedByEdge.has(`${pkg.path}\x00${dependency}`)) {
|
|
586
|
-
throw new Error(`Optional dependency is neither installed nor skipped: ${pkg.name} -> ${dependency}.`);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
for (const dependency of Object.keys(declared.optionalPeers)) {
|
|
590
|
-
if (!skippedByEdge.has(`${pkg.path}\x00${dependency}`)) {
|
|
591
|
-
throw new Error(`Optional peer dependency is not recorded as skipped: ${pkg.name} -> ${dependency}.`);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
async function verifyVendoredPlugin(projectDir, expectedName, expectedVersion) {
|
|
597
|
-
try {
|
|
598
|
-
const installRoot = await resolveVendoredPluginInstallRoot(projectDir, expectedName, expectedVersion);
|
|
599
|
-
if (!installRoot)
|
|
600
|
-
return null;
|
|
601
|
-
const receiptPath = path2.join(installRoot, VENDOR_RECEIPT_FILE);
|
|
602
|
-
let raw;
|
|
603
|
-
try {
|
|
604
|
-
const info = await lstat(receiptPath);
|
|
605
|
-
if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1 || info.size > 1024 * 1024) {
|
|
606
|
-
throw new Error("Vendor receipt is not a small regular file.");
|
|
607
|
-
}
|
|
608
|
-
raw = await readFile(receiptPath, "utf8");
|
|
609
|
-
} catch (error) {
|
|
610
|
-
if (error.code === "ENOENT")
|
|
611
|
-
return null;
|
|
612
|
-
throw error;
|
|
613
|
-
}
|
|
614
|
-
const receipt = JSON.parse(raw);
|
|
615
|
-
if (receipt.schemaVersion !== VENDOR_RECEIPT_VERSION) {
|
|
616
|
-
throw new Error(`Unsupported vendor receipt schema ${String(receipt.schemaVersion)}.`);
|
|
617
|
-
}
|
|
618
|
-
if (receipt.root?.name !== expectedName || receipt.root?.version !== expectedVersion) {
|
|
619
|
-
throw new Error("Vendor receipt identity does not match the manifest entry.");
|
|
620
|
-
}
|
|
621
|
-
if (!Array.isArray(receipt.packages) || receipt.packages.length === 0) {
|
|
622
|
-
throw new Error("Vendor receipt has no package graph.");
|
|
623
|
-
}
|
|
624
|
-
const tree = await computeVendorTreeDigest(installRoot);
|
|
625
|
-
if (receipt.tree?.algorithm !== "sha256" || receipt.tree.digest !== tree.digest || receipt.tree.files !== tree.files || receipt.tree.bytes !== tree.bytes) {
|
|
626
|
-
throw new Error("Vendor tree hash does not match its receipt.");
|
|
627
|
-
}
|
|
628
|
-
const packages = new Map;
|
|
629
|
-
const manifests = new Map;
|
|
630
|
-
const verifiedPackages = [];
|
|
631
|
-
const pathKeys = new Set;
|
|
632
|
-
for (const pkg of receipt.packages) {
|
|
633
|
-
const relative = safeReceiptPath(pkg.path, "Package receipt path");
|
|
634
|
-
const key = windowsPathKey(relative);
|
|
635
|
-
if (pathKeys.has(key))
|
|
636
|
-
throw new Error(`Duplicate package receipt path: ${relative}`);
|
|
637
|
-
pathKeys.add(key);
|
|
638
|
-
if (!isValidNpmPackageName(pkg.name) || !isExactNpmVersion(pkg.version)) {
|
|
639
|
-
throw new Error(`Invalid package identity in receipt: ${pkg.name}@${pkg.version}`);
|
|
640
|
-
}
|
|
641
|
-
const expectedSuffix = `node_modules/${pkg.name}`;
|
|
642
|
-
if (relative !== expectedSuffix && !relative.endsWith(`/${expectedSuffix}`)) {
|
|
643
|
-
throw new Error(`Package receipt path does not match ${pkg.name}: ${relative}`);
|
|
644
|
-
}
|
|
645
|
-
if (typeof pkg.integrity !== "string" || !/^(?:sha512|sha384|sha256|sha1)-(?:hex-)?[A-Za-z0-9+/=]+$/.test(pkg.integrity) || typeof pkg.legacySha1 !== "boolean" || pkg.legacySha1 !== pkg.integrity.startsWith("sha1-")) {
|
|
646
|
-
throw new Error(`Package receipt is missing provenance: ${pkg.name}@${pkg.version}`);
|
|
647
|
-
}
|
|
648
|
-
const tarball = new URL(pkg.tarball);
|
|
649
|
-
if (tarball.origin !== new URL(npmRegistryUrl()).origin || tarball.username || tarball.password) {
|
|
650
|
-
throw new Error(`Package receipt has an invalid tarball URL: ${pkg.name}@${pkg.version}`);
|
|
651
|
-
}
|
|
652
|
-
const packageDir = path2.resolve(installRoot, ...relative.split("/"));
|
|
653
|
-
if (!isContained(installRoot, packageDir))
|
|
654
|
-
throw new Error(`Package escapes vendor root: ${relative}`);
|
|
655
|
-
const realPackageDir2 = await realpath(packageDir);
|
|
656
|
-
if (!isContained(installRoot, realPackageDir2)) {
|
|
657
|
-
throw new Error(`Package resolves outside the vendor root: ${relative}`);
|
|
658
|
-
}
|
|
659
|
-
const manifest = await readPackageJson(packageDir);
|
|
660
|
-
if (manifest.name !== pkg.name || manifest.version !== pkg.version) {
|
|
661
|
-
throw new Error(`Installed package identity changed: ${pkg.name}@${pkg.version}`);
|
|
662
|
-
}
|
|
663
|
-
const [expectedEntry, expectedRequireEntry] = await Promise.all([
|
|
664
|
-
recomputeReceiptEntry(packageDir, relative, manifest, "import"),
|
|
665
|
-
recomputeReceiptEntry(packageDir, relative, manifest, "require")
|
|
666
|
-
]);
|
|
667
|
-
if (pkg.entry !== expectedEntry || pkg.requireEntry !== expectedRequireEntry) {
|
|
668
|
-
throw new Error(`Recorded package entries do not match package.json: ${pkg.name}@${pkg.version}`);
|
|
669
|
-
}
|
|
670
|
-
packages.set(relative, pkg);
|
|
671
|
-
manifests.set(relative, manifest);
|
|
672
|
-
verifiedPackages.push({
|
|
673
|
-
path: relative,
|
|
674
|
-
name: pkg.name,
|
|
675
|
-
packageDir: realPackageDir2,
|
|
676
|
-
manifest,
|
|
677
|
-
entryPath: await verifyReceiptEntry(installRoot, relative, pkg.entry, "Package import entry"),
|
|
678
|
-
requireEntryPath: await verifyReceiptEntry(installRoot, relative, pkg.requireEntry, "Package require entry"),
|
|
679
|
-
dependencies: pkg.dependencies
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
await assertVendorPackageOwnership(installRoot, receipt.packages.map((pkg) => pkg.path));
|
|
683
|
-
reconcileReceiptGraph(receipt, packages, manifests);
|
|
684
|
-
const rootPackagePath = safeReceiptPath(receipt.root.packagePath, "Root package path");
|
|
685
|
-
const rootPackage = packages.get(rootPackagePath);
|
|
686
|
-
if (!rootPackage || rootPackage.name !== expectedName || rootPackage.version !== expectedVersion) {
|
|
687
|
-
throw new Error("Vendor receipt root package is missing.");
|
|
688
|
-
}
|
|
689
|
-
const reachablePackages = new Set([rootPackagePath]);
|
|
690
|
-
const pendingPackages = [rootPackagePath];
|
|
691
|
-
while (pendingPackages.length > 0) {
|
|
692
|
-
const current = packages.get(pendingPackages.pop());
|
|
693
|
-
for (const target of Object.values(current.dependencies)) {
|
|
694
|
-
if (reachablePackages.has(target))
|
|
695
|
-
continue;
|
|
696
|
-
reachablePackages.add(target);
|
|
697
|
-
pendingPackages.push(target);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
if (reachablePackages.size !== receipt.packages.length) {
|
|
701
|
-
throw new Error("Vendor receipt contains a package that is not reachable from its root.");
|
|
702
|
-
}
|
|
703
|
-
const rootManifest = manifests.get(rootPackagePath);
|
|
704
|
-
if (receipt.root.format !== "module" && receipt.root.format !== "commonjs") {
|
|
705
|
-
throw new Error("Vendor receipt root format is invalid.");
|
|
706
|
-
}
|
|
707
|
-
const entryRelative = safeReceiptPath(receipt.root.entry, "Plugin entry path");
|
|
708
|
-
if (!entryRelative.startsWith(`${rootPackagePath}/`)) {
|
|
709
|
-
throw new Error("Plugin entry is outside its package.");
|
|
710
|
-
}
|
|
711
|
-
const expectedRootEntry = receipt.root.format === "commonjs" ? rootPackage.requireEntry ?? rootPackage.entry : rootPackage.entry;
|
|
712
|
-
if (entryRelative !== expectedRootEntry) {
|
|
713
|
-
throw new Error("Plugin entry does not match the package graph entry.");
|
|
714
|
-
}
|
|
715
|
-
if (packageEntryFormat(rootManifest, entryRelative) !== receipt.root.format) {
|
|
716
|
-
throw new Error("Plugin entry format does not match its package metadata.");
|
|
717
|
-
}
|
|
718
|
-
const entryPath = path2.resolve(installRoot, ...entryRelative.split("/"));
|
|
719
|
-
const rootPackageDir = path2.resolve(installRoot, ...rootPackagePath.split("/"));
|
|
720
|
-
const [realPackageDir, realEntry] = await Promise.all([
|
|
721
|
-
realpath(rootPackageDir),
|
|
722
|
-
realpath(entryPath)
|
|
723
|
-
]);
|
|
724
|
-
if (!isContained(installRoot, realEntry) || !isContained(realPackageDir, realEntry)) {
|
|
725
|
-
throw new Error("Plugin entry resolves outside the verified vendor tree.");
|
|
726
|
-
}
|
|
727
|
-
const entryInfo = await lstat(realEntry);
|
|
728
|
-
if (!entryInfo.isFile() || entryInfo.isSymbolicLink()) {
|
|
729
|
-
throw new Error("Plugin entry is not a regular file.");
|
|
730
|
-
}
|
|
731
|
-
return {
|
|
732
|
-
installRoot,
|
|
733
|
-
entryPath: realEntry,
|
|
734
|
-
format: receipt.root.format,
|
|
735
|
-
packages: verifiedPackages,
|
|
736
|
-
receipt
|
|
737
|
-
};
|
|
738
|
-
} catch (error) {
|
|
739
|
-
throw new Error(`Vendored plugin "${expectedName}@${expectedVersion}" failed verification: ` + `${error instanceof Error ? error.message : String(error)} Reinstall it before building.`, { cause: error });
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
348
|
|
|
743
349
|
// src/lib/source-provider.ts
|
|
744
350
|
var noopLogger = {
|
|
@@ -1103,7 +709,7 @@ async function countUnversionedChanges(projectDir) {
|
|
|
1103
709
|
const appWritten = `${bookPrefix}${PLUGINS_DIR}/${VENDORED_NPM_DIR}/`;
|
|
1104
710
|
return withRepoLock(dir, async () => {
|
|
1105
711
|
const { adds, removes } = await listWorkdirChanges(dir);
|
|
1106
|
-
const mine = new Set([...adds, ...removes].filter((f) => f.startsWith(bookPrefix) && !f.startsWith(appWritten)
|
|
712
|
+
const mine = new Set([...adds, ...removes].filter((f) => f.startsWith(bookPrefix) && !f.startsWith(appWritten)));
|
|
1107
713
|
return { changedFiles: mine.size, stale: gitFs.existsSync(snapshotStagingMarkerPath(dir)) };
|
|
1108
714
|
});
|
|
1109
715
|
}
|
|
@@ -1279,4 +885,4 @@ async function switchBranch(options) {
|
|
|
1279
885
|
});
|
|
1280
886
|
}
|
|
1281
887
|
|
|
1282
|
-
export {
|
|
888
|
+
export { PLUGINS_DIR, VENDORED_NPM_DIR, isValidNpmPackageName, parseNpmPluginSpec, isExactNpmVersion, vendoredNpmPluginRoot, vendoredNpmPluginPackageDir, assertWindowsSafeRelativePath, windowsPathKey, packageResolutionTargets, safePackageTarget, resolvePackageEntry, resolveVendoredPluginInstallRoot, gitScopeFor, HISTORY_PAGE_LIMIT, withRepoLock, whenGitIdle, __repoLockQueueSizeForTests, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, countUnversionedChanges, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup, SWITCH_BRANCH_SNAPSHOT_MESSAGE, listLocalBranches, switchBranch };
|
|
@@ -137,6 +137,9 @@ async function findTool(tool) {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// src/lib/chromium.ts
|
|
141
|
+
import { existsSync } from "node:fs";
|
|
142
|
+
|
|
140
143
|
// src/lib/install-hints.ts
|
|
141
144
|
var INSTALL_HINTS = {
|
|
142
145
|
chromium: {
|
|
@@ -165,7 +168,6 @@ ${hint.body}`;
|
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
// src/lib/chromium.ts
|
|
168
|
-
import { existsSync } from "node:fs";
|
|
169
171
|
var SYSTEM_PATHS = [
|
|
170
172
|
process.env.CHROMIUM_PATH,
|
|
171
173
|
process.env.PUPPETEER_EXECUTABLE_PATH,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "gutterpress",
|
|
7
|
-
version: "0.11.10-alpha.
|
|
7
|
+
version: "0.11.10-alpha.6",
|
|
8
8
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
9
9
|
author: "itlackey",
|
|
10
10
|
license: "MPL-2.0",
|
|
@@ -64,11 +64,9 @@ var package_default = {
|
|
|
64
64
|
node: ">=22.0.0"
|
|
65
65
|
},
|
|
66
66
|
dependencies: {
|
|
67
|
-
acorn: "8.16.0",
|
|
68
67
|
chokidar: "^5.0.0",
|
|
69
68
|
citty: "^0.2.0",
|
|
70
69
|
diff3: "0.0.3",
|
|
71
|
-
"es-module-lexer": "2.0.0",
|
|
72
70
|
fflate: "0.8.3",
|
|
73
71
|
glob: "^13.0.0",
|
|
74
72
|
htmlhint: "^1.9.2",
|
|
@@ -85,7 +83,6 @@ var package_default = {
|
|
|
85
83
|
markdownlint: "^0.40.0",
|
|
86
84
|
"pdf-lib": "^1.17.1",
|
|
87
85
|
postcss: "^8.5.18",
|
|
88
|
-
"puppeteer-core": "^25.0.4",
|
|
89
86
|
"resolve.exports": "2.0.3",
|
|
90
87
|
semver: "7.8.0",
|
|
91
88
|
tar: "7.5.20",
|