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.
Files changed (59) hide show
  1. package/README.md +24 -46
  2. package/dist/api/index.d.ts +1 -1
  3. package/dist/api/index.js +10 -6
  4. package/dist/{build-dfpvvhys.js → build-npxq1tvm.js} +7 -6
  5. package/dist/cdp-jg95s674.js +15 -0
  6. package/dist/cdp-smdx6mr3.js +16 -0
  7. package/dist/{cli-d8rdk1y7.js → cli-30j93gzt.js} +11 -335
  8. package/dist/{cli-pfczdbyd.js → cli-5qr3z0qa.js} +10 -404
  9. package/dist/{cli-c41yr7he.js → cli-7fkhgtfn.js} +3 -1
  10. package/dist/{cli-k2hwrp7s.js → cli-97bdz5k0.js} +1 -4
  11. package/dist/cli-kkzka31p.js +261 -0
  12. package/dist/{cli-p679pvce.js → cli-vbzkkcbv.js} +2 -2
  13. package/dist/{cli-4xksazfr.js → cli-z8ye91f0.js} +283 -1142
  14. package/dist/cli.js +12 -14
  15. package/dist/{doctor-hheax5yc.js → doctor-ykr6gtpv.js} +3 -3
  16. package/dist/engine/shared/cdp.d.ts +23 -19
  17. package/dist/engine-3gwctsty.js +24 -0
  18. package/dist/engine-mwshptgf.js +25 -0
  19. package/dist/{ext-q5024j6v.js → ext-bna9nr3v.js} +7 -6
  20. package/dist/{index-1a4rx87v.js → index-322fxk25.js} +344 -1130
  21. package/dist/{index-kqftehgy.js → index-dzp0hc2c.js} +4 -2
  22. package/dist/{index-fnhak0nh.js → index-qf7y4d85.js} +10 -404
  23. package/dist/index-r4wvy5v3.js +267 -0
  24. package/dist/{index-t43k5rq1.js → index-rzm1phg0.js} +23 -356
  25. package/dist/index.d.ts +0 -1
  26. package/dist/index.js +12 -87
  27. package/dist/lib/build-error.d.ts +4 -5
  28. package/dist/lib/build-preflight.d.ts +1 -35
  29. package/dist/lib/build-runner.d.ts +27 -44
  30. package/dist/lib/chromium.d.ts +5 -1
  31. package/dist/lib/engine.d.ts +3 -18
  32. package/dist/lib/extension-manager.d.ts +2 -2
  33. package/dist/lib/extension-manifest.d.ts +1 -1
  34. package/dist/lib/markdown/assemble.d.ts +2 -9
  35. package/dist/lib/markdown/index.d.ts +2 -4
  36. package/dist/lib/markdown/plugins.d.ts +0 -3
  37. package/dist/lib/npm-plugin-installer.d.ts +6 -1
  38. package/dist/lib/plugin-vendor.d.ts +10 -78
  39. package/dist/lib/source-provider.d.ts +1 -1
  40. package/dist/lib/validation-exec.d.ts +5 -6
  41. package/dist/{new-6xm4tdxb.js → new-0hv3nwqj.js} +9 -8
  42. package/dist/{preflight-ezt8rvg3.js → preflight-pk0k25fm.js} +7 -6
  43. package/dist/preview/file-watcher.d.ts +4 -43
  44. package/dist/preview/http-server.d.ts +1 -3
  45. package/dist/{preview-hehs46dd.js → preview-8b1fn59h.js} +7 -6
  46. package/dist/{preview-shell-gqnc5xxe.js → preview-shell-tqndvhbx.js} +5 -7
  47. package/dist/{publish-ha505ejq.js → publish-ba5h76tz.js} +7 -6
  48. package/dist/render.d.ts +1 -1
  49. package/dist/render.js +1 -9
  50. package/dist/{source-provider-ta09wegv.js → source-provider-pzmz0br9.js} +1 -1
  51. package/dist/{source-provider-7c2ww3bz.js → source-provider-qbthnmqw.js} +1 -1
  52. package/dist/{validate-je56vdbj.js → validate-4rq2r5b3.js} +7 -6
  53. package/package.json +1 -4
  54. package/dist/audit-v9594a72.js +0 -69
  55. package/dist/engine-qtfrfbpk.js +0 -41
  56. package/dist/engine-trte2tg2.js +0 -40
  57. package/dist/lib/browser-pool.d.ts +0 -35
  58. package/dist/lib/lint-runner.d.ts +0 -29
  59. package/dist/lint-tbywt66a.js +0 -68
@@ -13,22 +13,20 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-p679pvce.js";
16
+ } from "./cli-vbzkkcbv.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-k2hwrp7s.js";
21
+ } from "./cli-97bdz5k0.js";
22
22
  import {
23
23
  MARGIN_BOX_IGNORED_PROPERTIES,
24
- RENDER_TIMEOUT_MS,
25
- REQUIRED_MILESTONE,
26
- closeBrowser,
27
24
  getAssetPath,
28
- getAssetsDir,
29
- getBrowser,
30
- prewarmBrowser
31
- } from "./cli-d8rdk1y7.js";
25
+ getAssetsDir
26
+ } from "./cli-30j93gzt.js";
27
+ import {
28
+ BuildError
29
+ } from "./cli-46ycxe6r.js";
32
30
  import {
33
31
  INSTALL_HINTS,
34
32
  execCapture,
@@ -36,32 +34,24 @@ import {
36
34
  requireChromiumExecutable,
37
35
  resolveChromiumExecutable,
38
36
  spawnCapture
39
- } from "./cli-c41yr7he.js";
40
- import {
41
- BuildError
42
- } from "./cli-46ycxe6r.js";
37
+ } from "./cli-7fkhgtfn.js";
43
38
  import {
44
39
  PLUGINS_DIR,
45
40
  VENDORED_NPM_DIR,
46
- VENDOR_RECEIPT_FILE,
47
- VENDOR_RECEIPT_VERSION,
48
41
  assertWindowsSafeRelativePath,
49
- computeVendorTreeDigest,
50
42
  hasUncommittedChanges,
51
43
  isExactNpmVersion,
52
44
  isValidNpmPackageName,
53
45
  listWorkdirChanges,
54
- npmRegistryUrl,
55
- packageEntryFormat,
56
46
  packageResolutionTargets,
57
47
  parseNpmPluginSpec,
58
48
  resolvePackageEntry,
59
49
  resolveVendoredPluginInstallRoot,
50
+ safePackageTarget,
60
51
  vendoredNpmPluginPackageDir,
61
52
  vendoredNpmPluginRoot,
62
- verifyVendoredPlugin,
63
53
  windowsPathKey
64
- } from "./cli-pfczdbyd.js";
54
+ } from "./cli-5qr3z0qa.js";
65
55
  import {
66
56
  detectProjectSource,
67
57
  repoSubPath
@@ -2797,7 +2787,7 @@ async function inlineShapeUrls(html, baseDir) {
2797
2787
  }
2798
2788
 
2799
2789
  // src/checks/source/local-ref-parser.ts
2800
- import { readFile as readFile11 } from "node:fs/promises";
2790
+ import { readFile as readFile10 } from "node:fs/promises";
2801
2791
 
2802
2792
  // src/lib/markdown/renderer.ts
2803
2793
  import MarkdownIt from "markdown-it";
@@ -4616,16 +4606,11 @@ function layerSlug(name) {
4616
4606
  }
4617
4607
 
4618
4608
  // src/lib/markdown/plugins.ts
4619
- import { createHash as createHash2 } from "node:crypto";
4620
- import { existsSync as existsSync6, lstatSync, realpathSync, rmSync, statSync as statSync2, unlinkSync } from "node:fs";
4621
- import { cp, link, mkdir, mkdtemp, readFile as readFile10, rm, unlink, writeFile } from "node:fs/promises";
4622
- import { tmpdir } from "node:os";
4623
- import { resolve as resolve4, join, dirname as dirname2, basename, extname, relative, isAbsolute } from "node:path";
4624
- import { fileURLToPath, pathToFileURL } from "node:url";
4625
- import Module, { builtinModules, createRequire } from "node:module";
4626
- import { parse as parseJavaScript } from "acorn";
4627
- import { parse as parseModuleImports } from "es-module-lexer/js";
4628
- import { imports as resolvePackageImports } from "resolve.exports";
4609
+ import { existsSync as existsSync6, readFileSync, statSync as statSync2, unlinkSync } from "node:fs";
4610
+ import { link, unlink } from "node:fs/promises";
4611
+ import { isBuiltin } from "node:module";
4612
+ import { resolve as resolve4, join, dirname as dirname2, basename, extname, isAbsolute, relative, sep } from "node:path";
4613
+ import { pathToFileURL } from "node:url";
4629
4614
 
4630
4615
  // src/lib/style-declarations.ts
4631
4616
  import { existsSync as existsSync5 } from "node:fs";
@@ -4737,513 +4722,97 @@ function resolveExtension(dir, meta, subject) {
4737
4722
  };
4738
4723
  }
4739
4724
  // src/lib/markdown/plugins.ts
4740
- var moduleInternals = Module;
4741
- var vendorCjsTrees = new Map;
4742
- var latestVendorCjsTree = new Map;
4743
- var isolatedVendorTrees = new Map;
4744
- var nodeBuiltins = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));
4745
- var needsNativeCjsResolver = !process.versions.bun;
4746
- var cjsResolverInstalled = false;
4747
- var isolatedVendorBase;
4748
- var isolatedVendorBasePath = null;
4749
- var vendorSnapshotHook;
4750
- function pathContains(root, candidate) {
4751
- const value = relative(root, candidate);
4752
- return value === "" || !value.startsWith("..") && !isAbsolute(value);
4753
- }
4754
- function barePackageRequest(request) {
4755
- if (!request || request.startsWith(".") || request.startsWith("/") || request.startsWith("#") || isAbsolute(request) || /^[a-zA-Z][a-zA-Z+.-]*:/.test(request)) {
4756
- return null;
4757
- }
4758
- const parts = request.split("/");
4759
- if (request.startsWith("@")) {
4760
- if (parts.length < 2)
4761
- return null;
4762
- return { name: `${parts[0]}/${parts[1]}`, subpath: parts.slice(2).join("/") };
4763
- }
4764
- return { name: parts[0], subpath: parts.slice(1).join("/") };
4765
- }
4766
- function resolveVerifiedTarget(pkg, resolution) {
4767
- const target = resolution.target.startsWith("./") ? resolution.target.slice(2) : resolution.target;
4768
- if (!target || target.includes("\\") || target.includes("*") || target.includes("?") || target.includes("#")) {
4769
- return null;
4770
- }
4771
- try {
4772
- assertWindowsSafeRelativePath(target);
4773
- } catch {
4774
- return null;
4775
- }
4776
- if (target.normalize("NFKC").split("/").some((part) => part.toLowerCase() === "node_modules")) {
4777
- return null;
4778
- }
4779
- const base = resolve4(pkg.packageDir, ...target.split("/"));
4780
- if (!pathContains(pkg.packageDir, base))
4781
- return null;
4782
- const candidates = resolution.exact ? [base] : [
4783
- base,
4784
- `${base}.js`,
4785
- `${base}.cjs`,
4786
- `${base}.mjs`,
4787
- `${base}.json`,
4788
- join(base, "index.js"),
4789
- join(base, "index.cjs"),
4790
- join(base, "index.mjs"),
4791
- join(base, "index.json")
4792
- ];
4793
- for (const candidate of candidates) {
4794
- try {
4795
- const info2 = lstatSync(candidate);
4796
- const extension = extname(candidate);
4797
- if (info2.isFile() && !info2.isSymbolicLink() && (!extension || [".js", ".cjs", ".mjs", ".json"].includes(extension))) {
4798
- return candidate;
4799
- }
4800
- } catch {}
4801
- }
4802
- return null;
4803
- }
4804
- function resolveVerifiedRequest(pkg, subpath, condition) {
4805
- for (const resolution of packageResolutionTargets(pkg.manifest, subpath, condition)) {
4806
- const resolved = resolveVerifiedTarget(pkg, resolution);
4807
- if (resolved)
4808
- return resolved;
4809
- }
4810
- return null;
4811
- }
4812
- function resolveApprovedPackageRequest(owner, request, condition, tree, depth = 0) {
4813
- if (depth > 8)
4814
- return null;
4815
- if (nodeBuiltins.has(request)) {
4816
- return request.startsWith("node:") ? request : `node:${request}`;
4817
- }
4818
- if (request.startsWith("#")) {
4819
- let targets;
4725
+ var vendoredRootsOpened = new Set;
4726
+ var bunVendoredResolverInstalled = false;
4727
+ function isInsideDir(candidate, root) {
4728
+ return candidate === root || candidate.startsWith(root.endsWith(sep) ? root : root + sep);
4729
+ }
4730
+ function resolveBareSpecifierSync(specifier, fromDir, stopRoot, condition) {
4731
+ const parts = specifier.split("/");
4732
+ const name = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
4733
+ const subpath = specifier.slice(name.length).replace(/^\//, "");
4734
+ for (let dir = fromDir;isInsideDir(dir, stopRoot); dir = dirname2(dir)) {
4735
+ const packageDir = join(dir, "node_modules", ...name.split("/"));
4736
+ const packageJson = join(packageDir, "package.json");
4737
+ if (!existsSync6(packageJson)) {
4738
+ if (dir === stopRoot)
4739
+ break;
4740
+ continue;
4741
+ }
4742
+ let manifest;
4820
4743
  try {
4821
- targets = resolvePackageImports(owner.manifest, request, {
4822
- require: condition === "require"
4823
- }) ?? [];
4744
+ manifest = JSON.parse(readFileSync(packageJson, "utf8"));
4824
4745
  } catch {
4825
4746
  return null;
4826
4747
  }
4827
- for (const target2 of targets) {
4828
- if (target2.startsWith("./")) {
4829
- const resolved = resolveVerifiedTarget(owner, { target: target2, exact: true });
4830
- if (resolved)
4831
- return resolved;
4832
- } else {
4833
- const resolved = resolveApprovedPackageRequest(owner, target2, condition, tree, depth + 1);
4834
- if (resolved)
4835
- return resolved;
4748
+ for (const target of packageResolutionTargets(manifest, subpath, condition)) {
4749
+ const rel = safePackageTarget(target.target);
4750
+ if (!rel)
4751
+ continue;
4752
+ const base = resolve4(packageDir, ...rel.split("/"));
4753
+ if (!isInsideDir(base, packageDir))
4754
+ continue;
4755
+ const candidates = target.exact ? [base] : [base, `${base}.mjs`, `${base}.js`, `${base}.cjs`, `${base}.json`, join(base, "index.mjs"), join(base, "index.js"), join(base, "index.cjs")];
4756
+ for (const candidate of candidates) {
4757
+ try {
4758
+ if (statSync2(candidate).isFile())
4759
+ return candidate;
4760
+ } catch {}
4836
4761
  }
4837
4762
  }
4838
4763
  return null;
4839
4764
  }
4840
- const parsed = barePackageRequest(request);
4841
- if (!parsed)
4842
- return null;
4843
- const targetPath = parsed.name === owner.name ? owner.path : owner.dependencies[parsed.name];
4844
- const target = targetPath ? tree.byPath.get(targetPath) : undefined;
4845
- if (!target)
4846
- return null;
4847
- if (parsed.subpath)
4848
- return resolveVerifiedRequest(target, parsed.subpath, condition);
4849
- return condition === "require" ? target.requireEntryPath ?? null : target.entryPath ?? null;
4850
- }
4851
- function unresolvedVendorRequest(request, parent) {
4852
- const error2 = new Error(`Cannot resolve undeclared or unexported package request "${request}" from ${parent}.`);
4853
- error2.code = "MODULE_NOT_FOUND";
4854
- return error2;
4765
+ return null;
4855
4766
  }
4856
- function ensureVendorCjsResolver() {
4857
- if (!needsNativeCjsResolver || cjsResolverInstalled)
4767
+ function installBunVendoredResolver() {
4768
+ if (bunVendoredResolverInstalled)
4858
4769
  return;
4859
- cjsResolverInstalled = true;
4860
- const original = moduleInternals._resolveFilename;
4861
- moduleInternals._resolveFilename = function resolveVendorRequest(request, parent, isMain, options) {
4862
- if (parent?.filename && (request.startsWith("#") || barePackageRequest(request))) {
4863
- for (const tree of vendorCjsTrees.values()) {
4864
- const owner = tree.packages.find((pkg) => pathContains(pkg.packageDir, parent.filename));
4865
- if (!owner)
4866
- continue;
4867
- const resolved = resolveApprovedPackageRequest(owner, request, "require", tree);
4868
- if (resolved)
4869
- return resolved;
4870
- if (!nodeBuiltins.has(request)) {
4871
- throw unresolvedVendorRequest(request, parent.filename);
4872
- }
4873
- }
4874
- }
4875
- return Reflect.apply(original, this, [request, parent, isMain, options]);
4876
- };
4877
- }
4878
- async function getIsolatedVendorBase() {
4879
- isolatedVendorBase ??= mkdtemp(join(tmpdir(), "gutterpress-plugin-loads-"));
4880
- const base = await isolatedVendorBase;
4881
- isolatedVendorBasePath = base;
4882
- ensureExitCleanupRegistered();
4883
- return base;
4884
- }
4885
- function isolatedPackageCopyFilter(packageDir, candidate) {
4886
- const candidateRelative = relative(packageDir, candidate);
4887
- if (!candidateRelative)
4888
- return true;
4889
- const parts = candidateRelative.split(/[\\/]/);
4890
- const nodeModulesAt = parts.findIndex((part) => part.normalize("NFKC").toLowerCase() === "node_modules");
4891
- if (nodeModulesAt < 0)
4892
- return true;
4893
- if (nodeModulesAt === 0 && parts[0] === "node_modules")
4894
- return false;
4895
- throw new Error(`Package contains bundled node_modules content: ${candidateRelative}`);
4896
- }
4897
- function rewrittenSpecifier(owner, specifier, condition, tree) {
4898
- if (!specifier.startsWith("#") && !barePackageRequest(specifier) && !nodeBuiltins.has(specifier)) {
4899
- return null;
4900
- }
4901
- const resolved = resolveApprovedPackageRequest(owner, specifier, condition, tree);
4902
- if (!resolved) {
4903
- throw new Error(`Package request "${specifier}" from ${owner.name} is not a receipt-approved dependency.`);
4904
- }
4905
- if (resolved.startsWith("node:"))
4906
- return { replacement: resolved };
4907
- return {
4908
- replacement: condition === "require" ? resolved : pathToFileURL(resolved).href,
4909
- targetPath: resolved
4910
- };
4911
- }
4912
- function localModuleTarget(absolute, specifier, condition) {
4913
- if (!specifier.startsWith(".") && !specifier.startsWith("file:") && !isAbsolute(specifier)) {
4914
- return null;
4915
- }
4916
- try {
4917
- if (condition === "require" && !specifier.startsWith("file:")) {
4918
- return createRequire(absolute).resolve(specifier);
4919
- }
4920
- const url = specifier.startsWith("file:") ? new URL(specifier) : isAbsolute(specifier) ? pathToFileURL(specifier) : new URL(specifier, pathToFileURL(absolute));
4921
- const target = fileURLToPath(url);
4922
- return lstatSync(target).isFile() ? target : null;
4923
- } catch {
4924
- return null;
4925
- }
4926
- }
4927
- function packageOwningFile(tree, file) {
4928
- return tree.packages.find((pkg) => pathContains(pkg.packageDir, file));
4929
- }
4930
- function addReachableTarget(targets, target, specifier, absolute, tree) {
4931
- if (!target)
4770
+ bunVendoredResolverInstalled = true;
4771
+ const bun = globalThis.Bun;
4772
+ if (typeof bun?.plugin !== "function")
4932
4773
  return;
4933
- if (!packageOwningFile(tree, target)) {
4934
- throw new Error(`Module "${specifier}" from ${absolute} resolves outside the verified package tree.`);
4935
- }
4936
- targets.add(target);
4937
- }
4938
- function visitSyntax(node, visitor) {
4939
- visitor(node);
4940
- for (const [key, value] of Object.entries(node)) {
4941
- if (["type", "start", "end", "loc", "range"].includes(key) || !value)
4942
- continue;
4943
- if (Array.isArray(value)) {
4944
- for (const item of value) {
4945
- if (item && typeof item === "object" && typeof item.type === "string") {
4946
- visitSyntax(item, visitor);
4774
+ bun.plugin({
4775
+ name: "gutterpress-vendored-plugins",
4776
+ setup(build) {
4777
+ build.onResolve({ filter: /^[^./]/ }, (args) => {
4778
+ if (!args.importer || isAbsolute(args.path) || /^[a-z]+:/i.test(args.path) || isBuiltin(args.path)) {
4779
+ return;
4947
4780
  }
4948
- }
4949
- } else if (typeof value === "object" && typeof value.type === "string") {
4950
- visitSyntax(value, visitor);
4951
- }
4952
- }
4953
- }
4954
- function memberName(node) {
4955
- if (node.type !== "MemberExpression")
4956
- return null;
4957
- const property = node.property;
4958
- if (!property)
4959
- return null;
4960
- if (property.type === "Identifier")
4961
- return property.name;
4962
- if (property.type === "Literal" && typeof property.value === "string")
4963
- return property.value;
4964
- return null;
4965
- }
4966
- function isReceiptBoundRequireCall(node) {
4967
- if (node.type !== "CallExpression")
4968
- return false;
4969
- const callee = node.callee;
4970
- if (!callee)
4971
- return false;
4972
- if (callee.type === "Identifier" && callee.name === "require")
4973
- return true;
4974
- if (callee.type !== "MemberExpression")
4975
- return false;
4976
- const object2 = callee.object;
4977
- const property = memberName(callee);
4978
- return Boolean(object2 && (object2.type === "Identifier" && object2.name === "module" && property === "require" || object2.type === "Identifier" && object2.name === "require" && property === "resolve"));
4979
- }
4980
- function rewriteCommonJsRequires(source, absolute, pkg, tree) {
4981
- const ast = parseJavaScript(source, {
4982
- ecmaVersion: "latest",
4983
- sourceType: "script",
4984
- allowHashBang: true,
4985
- allowReturnOutsideFunction: true
4986
- });
4987
- const replacements = [];
4988
- const targets = new Set;
4989
- visitSyntax(ast, (node) => {
4990
- if (!isReceiptBoundRequireCall(node))
4991
- return;
4992
- const args = node.arguments;
4993
- const argument = args?.[0];
4994
- if (!argument || argument.type !== "Literal" || typeof argument.value !== "string") {
4995
- throw new Error(`Dynamic require in ${pkg.name}/${relative(pkg.packageDir, absolute)} must use a string literal.`);
4996
- }
4997
- const rewritten = rewrittenSpecifier(pkg, argument.value, "require", tree);
4998
- if (rewritten) {
4999
- replacements.push({
5000
- start: argument.start,
5001
- end: argument.end,
5002
- value: JSON.stringify(rewritten.replacement)
5003
- });
5004
- addReachableTarget(targets, rewritten.targetPath, argument.value, absolute, tree);
5005
- } else {
5006
- const target = localModuleTarget(absolute, argument.value, "require");
5007
- if (!target) {
5008
- throw new Error(`CommonJS module "${argument.value}" from ${pkg.name}/${relative(pkg.packageDir, absolute)} could not be resolved.`);
5009
- }
5010
- addReachableTarget(targets, target, argument.value, absolute, tree);
5011
- }
5012
- });
5013
- return { replacements, targets };
5014
- }
5015
- async function rewriteReachableModuleImports(entryPath, tree) {
5016
- const pending = [entryPath];
5017
- const visited = new Set;
5018
- while (pending.length > 0) {
5019
- const absolute = pending.pop();
5020
- if (visited.has(absolute))
5021
- continue;
5022
- visited.add(absolute);
5023
- const extension = extname(absolute);
5024
- if (![".js", ".mjs", ".cjs"].includes(extension))
5025
- continue;
5026
- const pkg = packageOwningFile(tree, absolute);
5027
- if (!pkg)
5028
- throw new Error(`Reachable plugin module is outside the verified package tree: ${absolute}`);
5029
- const source = await readFile10(absolute, "utf8");
5030
- const [imports] = parseModuleImports(source, absolute);
5031
- const replacements = [];
5032
- const targets = new Set;
5033
- for (const imported of imports) {
5034
- if (imported.d === -2)
5035
- continue;
5036
- if (imported.n === undefined) {
5037
- throw new Error(`Dynamic import in ${pkg.name}/${relative(pkg.packageDir, absolute)} must use a string literal.`);
5038
- }
5039
- const rewritten2 = rewrittenSpecifier(pkg, imported.n, "import", tree);
5040
- if (rewritten2) {
5041
- addReachableTarget(targets, rewritten2.targetPath, imported.n, absolute, tree);
5042
- if (imported.d === -1) {
5043
- const quote = source[imported.s - 1];
5044
- if (quote !== '"' && quote !== "'" || source[imported.e] !== quote) {
5045
- throw new Error(`Could not safely rewrite an import in ${absolute}.`);
4781
+ let root;
4782
+ for (const opened of vendoredRootsOpened) {
4783
+ if (isInsideDir(args.importer, opened)) {
4784
+ root = opened;
4785
+ break;
5046
4786
  }
5047
- replacements.push({
5048
- start: imported.s - 1,
5049
- end: imported.e + 1,
5050
- value: JSON.stringify(rewritten2.replacement)
5051
- });
5052
- } else {
5053
- replacements.push({
5054
- start: imported.s,
5055
- end: imported.e,
5056
- value: JSON.stringify(rewritten2.replacement)
5057
- });
5058
4787
  }
5059
- } else {
5060
- const target = localModuleTarget(absolute, imported.n, "import");
5061
- if (target) {
5062
- addReachableTarget(targets, target, imported.n, absolute, tree);
5063
- } else if (imported.n.startsWith(".") || imported.n.startsWith("file:") || isAbsolute(imported.n)) {
5064
- throw new Error(`ESM module "${imported.n}" from ${pkg.name}/${relative(pkg.packageDir, absolute)} could not be resolved.`);
5065
- }
5066
- }
5067
- }
5068
- if (extension === ".cjs" || extension === ".js" && pkg.manifest.type !== "module") {
5069
- const commonJs = rewriteCommonJsRequires(source, absolute, pkg, tree);
5070
- replacements.push(...commonJs.replacements);
5071
- for (const target of commonJs.targets)
5072
- targets.add(target);
5073
- }
5074
- replacements.sort((a, b) => b.start - a.start);
5075
- let rewritten = source;
5076
- for (const replacement of replacements) {
5077
- rewritten = rewritten.slice(0, replacement.start) + replacement.value + rewritten.slice(replacement.end);
5078
- }
5079
- if (replacements.length > 0)
5080
- await writeFile(absolute, rewritten, "utf8");
5081
- pending.push(...targets);
5082
- }
5083
- }
5084
- function remapPackageEntry(source, destination, entry) {
5085
- if (!entry)
5086
- return;
5087
- const entryRelative = relative(source.packageDir, entry);
5088
- if (!pathContains(source.packageDir, entry) || !entryRelative) {
5089
- throw new Error(`Verified entry for ${source.name} is outside its package.`);
5090
- }
5091
- return resolve4(destination, entryRelative);
5092
- }
5093
- async function createIsolatedVendorTree(verified, address) {
5094
- const base = await getIsolatedVendorBase();
5095
- const loadRoot = join(base, address);
5096
- await mkdir(loadRoot);
5097
- try {
5098
- const packageMap = new Map;
5099
- const sorted = [...verified.packages].sort((a, b) => a.path.localeCompare(b.path));
5100
- for (let index = 0;index < sorted.length; index++) {
5101
- const source = sorted[index];
5102
- const destination = join(loadRoot, "packages", String(index), "package");
5103
- await mkdir(dirname2(destination), { recursive: true });
5104
- await cp(source.packageDir, destination, {
5105
- recursive: true,
5106
- filter: (candidate) => isolatedPackageCopyFilter(source.packageDir, candidate)
5107
- });
5108
- packageMap.set(source.path, {
5109
- ...source,
5110
- packageDir: destination,
5111
- entryPath: remapPackageEntry(source, destination, source.entryPath),
5112
- requireEntryPath: remapPackageEntry(source, destination, source.requireEntryPath)
4788
+ if (!root)
4789
+ return;
4790
+ const resolved = resolveBareSpecifierSync(args.path, dirname2(args.importer), root, args.kind === "require-call" || args.kind === "require-resolve" ? "require" : "import");
4791
+ return resolved ? { path: resolved } : undefined;
5113
4792
  });
5114
4793
  }
5115
- const packages = [...packageMap.values()];
5116
- const tree = {
5117
- sourceRoot: verified.installRoot,
5118
- packages,
5119
- byPath: new Map(packages.map((pkg) => [pkg.path, pkg]))
5120
- };
5121
- const rootPackage = packageMap.get(verified.receipt.root.packagePath);
5122
- if (!rootPackage)
5123
- throw new Error("Verified root package is missing from the isolated tree.");
5124
- const sourceRoot = verified.packages.find((pkg) => pkg.path === verified.receipt.root.packagePath);
5125
- const entryPath = remapPackageEntry(sourceRoot, rootPackage.packageDir, verified.entryPath);
5126
- if (!entryPath)
5127
- throw new Error("Verified plugin entry is missing from the isolated tree.");
5128
- await rewriteReachableModuleImports(entryPath, tree);
5129
- return { loadRoot, entryPath, packages };
5130
- } catch (error2) {
5131
- await rm(loadRoot, { recursive: true, force: true }).catch(() => {});
5132
- throw error2;
5133
- }
5134
- }
5135
- async function isolateVendoredPlugin(verified) {
5136
- const address = createHash2("sha256").update(verified.receipt.tree.digest).update("\x00").update(JSON.stringify(verified.receipt)).digest("hex");
5137
- let pending = isolatedVendorTrees.get(address);
5138
- if (!pending) {
5139
- pending = createIsolatedVendorTree(verified, address).catch((error2) => {
5140
- isolatedVendorTrees.delete(address);
5141
- throw error2;
5142
- });
5143
- isolatedVendorTrees.set(address, pending);
5144
- }
5145
- const isolated = await pending;
5146
- return {
5147
- ...verified,
5148
- loadRoot: isolated.loadRoot,
5149
- entryPath: isolated.entryPath,
5150
- packages: isolated.packages
5151
- };
5152
- }
5153
- async function snapshotAndIsolateVendoredPlugin(baseDir, packageName, version) {
5154
- const sourceRoot = await resolveVendoredPluginInstallRoot(baseDir, packageName, version);
5155
- if (!sourceRoot)
5156
- return null;
5157
- const base = await getIsolatedVendorBase();
5158
- const container = await mkdtemp(join(base, "snapshot-"));
5159
- const snapshotProject = join(container, "project");
5160
- const snapshotRoot = vendoredNpmPluginRoot(snapshotProject, packageName, version);
5161
- try {
5162
- await mkdir(dirname2(snapshotRoot), { recursive: true });
5163
- await cp(sourceRoot, snapshotRoot, {
5164
- recursive: true,
5165
- dereference: false,
5166
- verbatimSymlinks: true
5167
- });
5168
- await vendorSnapshotHook?.(sourceRoot, snapshotRoot);
5169
- const verifiedSnapshot = await verifyVendoredPlugin(snapshotProject, packageName, version);
5170
- if (!verifiedSnapshot)
5171
- return null;
5172
- const isolated = await isolateVendoredPlugin(verifiedSnapshot);
5173
- return { ...isolated, installRoot: sourceRoot };
5174
- } finally {
5175
- await rm(container, { recursive: true, force: true }).catch(() => {});
5176
- }
5177
- }
5178
- function registerVendorCjsTree(verified) {
5179
- ensureVendorCjsResolver();
5180
- const key = `${verified.installRoot}\x00${verified.loadRoot}`;
5181
- const previousKey = latestVendorCjsTree.get(verified.installRoot);
5182
- if (vendorCjsTrees.has(key)) {
5183
- latestVendorCjsTree.set(verified.installRoot, key);
5184
- return () => {};
5185
- }
5186
- const packages = [...verified.packages].sort((a, b) => b.packageDir.length - a.packageDir.length);
5187
- vendorCjsTrees.set(key, {
5188
- sourceRoot: verified.installRoot,
5189
- ...previousKey ? { previousKey } : {},
5190
- packages,
5191
- byPath: new Map(packages.map((pkg) => [pkg.path, pkg]))
5192
4794
  });
5193
- latestVendorCjsTree.set(verified.installRoot, key);
5194
- return () => {
5195
- vendorCjsTrees.delete(key);
5196
- if (latestVendorCjsTree.get(verified.installRoot) === key) {
5197
- if (previousKey)
5198
- latestVendorCjsTree.set(verified.installRoot, previousKey);
5199
- else
5200
- latestVendorCjsTree.delete(verified.installRoot);
5201
- }
5202
- };
5203
- }
5204
- function clearVendoredPluginResolver(baseDir, packageName, version) {
5205
- let projectDir = baseDir;
5206
- try {
5207
- projectDir = realpathSync(baseDir);
5208
- } catch {}
5209
- const sourceRoot = vendoredNpmPluginRoot(projectDir, packageName, version);
5210
- const key = latestVendorCjsTree.get(sourceRoot);
5211
- if (!key)
5212
- return;
5213
- const tree = vendorCjsTrees.get(key);
5214
- vendorCjsTrees.delete(key);
5215
- if (tree?.previousKey)
5216
- latestVendorCjsTree.set(sourceRoot, tree.previousKey);
5217
- else
5218
- latestVendorCjsTree.delete(sourceRoot);
5219
4795
  }
5220
4796
  async function loadNpmPackage(packageName, baseDir, version) {
5221
4797
  if (version && isValidNpmPackageName(packageName) && isExactNpmVersion(version)) {
5222
- const verified = await snapshotAndIsolateVendoredPlugin(baseDir, packageName, version);
5223
- if (verified) {
5224
- const restoreRegistration = registerVendorCjsTree(verified);
4798
+ const installRoot = await resolveVendoredPluginInstallRoot(baseDir, packageName, version);
4799
+ if (installRoot) {
4800
+ const packageDir = vendoredNpmPluginPackageDir(installRoot, packageName);
4801
+ let entry;
5225
4802
  try {
5226
- const moduleDir = dirname2(verified.entryPath);
5227
- const packageDir = verified.packages.find((pkg) => pkg.path === verified.receipt.root.packagePath)?.packageDir ?? null;
5228
- const entryPath = verified.entryPath;
5229
- if (verified.format === "commonjs") {
5230
- return {
5231
- module: createRequire(verified.entryPath)(verified.entryPath),
5232
- moduleDir,
5233
- packageDir,
5234
- entryPath
5235
- };
5236
- }
5237
- return {
5238
- module: await import(pathToFileURL(verified.entryPath).href),
5239
- moduleDir,
5240
- packageDir,
5241
- entryPath
5242
- };
5243
- } catch (error2) {
5244
- restoreRegistration();
5245
- throw error2;
4803
+ entry = await resolvePackageEntry(packageDir);
4804
+ } catch (cause) {
4805
+ throw new Error(`the downloaded copy of ${packageName}@${version} under plugins/npm/ is incomplete ` + `(${cause instanceof Error ? cause.message : String(cause)}). ` + `Reinstall it with \`gutterpress ext add ${packageName}@${version}\`.`, { cause });
5246
4806
  }
4807
+ const entryPath = join(packageDir, ...entry.split("/"));
4808
+ vendoredRootsOpened.add(installRoot);
4809
+ installBunVendoredResolver();
4810
+ return {
4811
+ module: await import(pathToFileURL(entryPath).href),
4812
+ moduleDir: dirname2(entryPath),
4813
+ packageDir,
4814
+ entryPath
4815
+ };
5247
4816
  }
5248
4817
  }
5249
4818
  try {
@@ -5325,11 +4894,6 @@ function ensureExitCleanupRegistered() {
5325
4894
  unlinkSync(shadowPath);
5326
4895
  } catch {}
5327
4896
  }
5328
- if (isolatedVendorBasePath) {
5329
- try {
5330
- rmSync(isolatedVendorBasePath, { recursive: true, force: true });
5331
- } catch {}
5332
- }
5333
4897
  });
5334
4898
  }
5335
4899
  function shadowPathFor(pluginPath, mtimeMs) {
@@ -5605,7 +5169,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
5605
5169
  for (const file of files) {
5606
5170
  let refs;
5607
5171
  try {
5608
- refs = collectRenderedLocalRefs(await readFile11(file, "utf8"));
5172
+ refs = collectRenderedLocalRefs(await readFile10(file, "utf8"));
5609
5173
  } catch {
5610
5174
  results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
5611
5175
  continue;
@@ -5672,10 +5236,10 @@ import os from "node:os";
5672
5236
  import fsp from "node:fs/promises";
5673
5237
 
5674
5238
  // src/lib/missing-asset-placeholder.ts
5675
- import { createHash as createHash3 } from "node:crypto";
5239
+ import { createHash as createHash2 } from "node:crypto";
5676
5240
  import { deflateSync } from "node:zlib";
5677
5241
  function placeholderOutputPath(missingOutputPath) {
5678
- const hash = createHash3("sha256").update(missingOutputPath).digest("hex").slice(0, 16);
5242
+ const hash = createHash2("sha256").update(missingOutputPath).digest("hex").slice(0, 16);
5679
5243
  return `assets/gutterpress-missing/${hash}.png`;
5680
5244
  }
5681
5245
  function decodeHtmlAttribute(value) {
@@ -5956,7 +5520,7 @@ var check21 = {
5956
5520
  registerCheck(check21);
5957
5521
 
5958
5522
  // src/checks/source/accessibility-alt-text.ts
5959
- import { readFile as readFile12 } from "node:fs/promises";
5523
+ import { readFile as readFile11 } from "node:fs/promises";
5960
5524
  var check22 = {
5961
5525
  id: "source.accessibility.alt-text",
5962
5526
  name: "Image Alt Text",
@@ -5970,7 +5534,7 @@ var check22 = {
5970
5534
  const results = [];
5971
5535
  for (const file of files) {
5972
5536
  try {
5973
- const content = await readFile12(file, "utf8");
5537
+ const content = await readFile11(file, "utf8");
5974
5538
  const lines = content.split(`
5975
5539
  `);
5976
5540
  let inFence = false;
@@ -6014,7 +5578,7 @@ function extractImageAlts(line) {
6014
5578
  registerCheck(check22);
6015
5579
 
6016
5580
  // src/checks/source/accessibility-heading-order.ts
6017
- import { readFile as readFile13 } from "node:fs/promises";
5581
+ import { readFile as readFile12 } from "node:fs/promises";
6018
5582
  var check23 = {
6019
5583
  id: "source.accessibility.heading-order",
6020
5584
  name: "Heading Order",
@@ -6028,7 +5592,7 @@ var check23 = {
6028
5592
  const results = [];
6029
5593
  for (const file of files) {
6030
5594
  try {
6031
- const content = await readFile13(file, "utf8");
5595
+ const content = await readFile12(file, "utf8");
6032
5596
  const lines = content.split(`
6033
5597
  `);
6034
5598
  let inFence = false;
@@ -6064,7 +5628,7 @@ var check23 = {
6064
5628
  registerCheck(check23);
6065
5629
 
6066
5630
  // src/checks/source/layout-markers.ts
6067
- import { readFile as readFile14 } from "node:fs/promises";
5631
+ import { readFile as readFile13 } from "node:fs/promises";
6068
5632
  var check24 = {
6069
5633
  id: "source.markdown.layout-markers",
6070
5634
  name: "Layout Markers",
@@ -6082,7 +5646,7 @@ var check24 = {
6082
5646
  const md = createMarkdownRenderer(plugins);
6083
5647
  for (const file of files) {
6084
5648
  try {
6085
- const content = await readFile14(file, "utf8");
5649
+ const content = await readFile13(file, "utf8");
6086
5650
  const env = {};
6087
5651
  md.render(content, env);
6088
5652
  for (const w of env.layoutWarnings ?? []) {
@@ -6104,7 +5668,7 @@ var check24 = {
6104
5668
  registerCheck(check24);
6105
5669
 
6106
5670
  // src/checks/source/merge-markers.ts
6107
- import { readFile as readFile15 } from "node:fs/promises";
5671
+ import { readFile as readFile14 } from "node:fs/promises";
6108
5672
  import path5 from "node:path";
6109
5673
 
6110
5674
  // src/checks/asset/extensions.ts
@@ -6146,7 +5710,7 @@ var check25 = {
6146
5710
  for (const file of textFiles) {
6147
5711
  let content;
6148
5712
  try {
6149
- content = await readFile15(file, "utf8");
5713
+ content = await readFile14(file, "utf8");
6150
5714
  } catch {
6151
5715
  results.push(inspectionFailed(check25.id, `Could not read source file: ${file}`, { file }));
6152
5716
  continue;
@@ -6209,7 +5773,7 @@ registerCheck(check25);
6209
5773
  import { stat as stat3 } from "node:fs/promises";
6210
5774
 
6211
5775
  // src/lib/image-inspect.ts
6212
- import { stat as stat2, readFile as readFile16 } from "node:fs/promises";
5776
+ import { stat as stat2, readFile as readFile15 } from "node:fs/promises";
6213
5777
  var DEFAULT_DPI = 72;
6214
5778
  var cache = new Map;
6215
5779
  async function inspectImage(path6) {
@@ -6224,7 +5788,7 @@ async function inspectImage(path6) {
6224
5788
  return hit.info;
6225
5789
  let info2 = null;
6226
5790
  try {
6227
- const buf = await readFile16(path6);
5791
+ const buf = await readFile15(path6);
6228
5792
  info2 = parseImage(buf);
6229
5793
  } catch {
6230
5794
  info2 = null;
@@ -6784,7 +6348,7 @@ var check33 = {
6784
6348
  registerCheck(check33);
6785
6349
 
6786
6350
  // src/checks/heuristic/section-density.ts
6787
- import { readFile as readFile17 } from "node:fs/promises";
6351
+ import { readFile as readFile16 } from "node:fs/promises";
6788
6352
  var check34 = {
6789
6353
  id: "heuristic.chunking.section-density",
6790
6354
  name: "Section Density",
@@ -6801,7 +6365,7 @@ var check34 = {
6801
6365
  const results = [];
6802
6366
  for (const file of files) {
6803
6367
  try {
6804
- const content = await readFile17(file, "utf8");
6368
+ const content = await readFile16(file, "utf8");
6805
6369
  const lines = content.split(`
6806
6370
  `);
6807
6371
  let currentSectionStart = 0;
@@ -6998,7 +6562,7 @@ function artifactName(title, format) {
6998
6562
  var BOOK_HTML_FILENAME = "book.html";
6999
6563
 
7000
6564
  // src/lib/markdown/index.ts
7001
- import { readdir as readdir2, readFile as readFile18, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
6565
+ import { readdir as readdir2, readFile as readFile17, writeFile, mkdir } from "node:fs/promises";
7002
6566
 
7003
6567
  // src/lib/remote-auth/sync-messages.ts
7004
6568
  function isOnlineSibling(filepath) {
@@ -7050,16 +6614,8 @@ async function assembleBookHtml(opts) {
7050
6614
  }
7051
6615
  for (const ref of env.imageRefs ?? [])
7052
6616
  imageRefs.add(ref);
7053
- if (opts.wrapChapters) {
7054
- const safe = chapterId.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
7055
- bodyContent += `<div class="gutterpress-chapter" data-chapter-src="${safe}">
7056
- ${rendered}
7057
- </div>
7058
- `;
7059
- } else {
7060
- bodyContent += rendered + `
6617
+ bodyContent += rendered + `
7061
6618
  `;
7062
- }
7063
6619
  }
7064
6620
  if (opts.onImageRefs) {
7065
6621
  for (const ref of collectHtmlImageRefs(bodyContent))
@@ -7144,20 +6700,19 @@ ${css.trim()}
7144
6700
  }
7145
6701
  return assembleBookHtml({
7146
6702
  files,
7147
- readText: (relPath) => readFile18(join2(inputDir, canonicalChapterId(relPath)), "utf-8"),
6703
+ readText: (relPath) => readFile17(join2(inputDir, canonicalChapterId(relPath)), "utf-8"),
7148
6704
  projectCss: inlined.css,
7149
6705
  preloadImages: cssAssetCopies.map((c) => c.to),
7150
6706
  title: opts.title,
7151
6707
  plugins: opts.plugins,
7152
6708
  pluginCss,
7153
- wrapChapters: opts.wrapChapters,
7154
6709
  annotateSourceChapters: opts.annotateSourceChapters,
7155
6710
  onChapterWarnings: opts.onChapterWarnings,
7156
6711
  onImageRefs: opts.onImageRefs
7157
6712
  });
7158
6713
  }
7159
6714
  async function renderChaptersToFile(inputDir, outDir, opts = {}) {
7160
- await mkdir2(outDir, { recursive: true });
6715
+ await mkdir(outDir, { recursive: true });
7161
6716
  const html = await renderChapters(inputDir, {
7162
6717
  title: opts.title,
7163
6718
  styles: opts.styles,
@@ -7170,12 +6725,12 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
7170
6725
  onStyleWarnings: opts.onStyleWarnings
7171
6726
  });
7172
6727
  const outFile = join2(outDir, BOOK_HTML_FILENAME);
7173
- await writeFile2(outFile, html);
6728
+ await writeFile(outFile, html);
7174
6729
  return outFile;
7175
6730
  }
7176
6731
 
7177
6732
  // src/lib/markdownlint-fix.ts
7178
- import { readFile as readFile19, writeFile as writeFile3 } from "node:fs/promises";
6733
+ import { readFile as readFile18, writeFile as writeFile2 } from "node:fs/promises";
7179
6734
  import { applyFixes } from "markdownlint";
7180
6735
  import { lint as lint2 } from "markdownlint/sync";
7181
6736
  async function uncommittedAmong(inputDir, files) {
@@ -7215,7 +6770,7 @@ async function applyMarkdownlintFixes(ctx) {
7215
6770
  for (const [file, violations] of Object.entries(results)) {
7216
6771
  if (!Array.isArray(violations) || violations.length === 0)
7217
6772
  continue;
7218
- const before = await readFile19(file, "utf8");
6773
+ const before = await readFile18(file, "utf8");
7219
6774
  const after = applyFixes(before, violations);
7220
6775
  if (after !== before)
7221
6776
  pending.push({ file, content: after });
@@ -7226,7 +6781,7 @@ async function applyMarkdownlintFixes(ctx) {
7226
6781
  }
7227
6782
  const dirty = await uncommittedAmong(ctx.inputDir, pending.map((p) => p.file));
7228
6783
  for (const { file, content } of pending) {
7229
- await writeFile3(file, content, "utf8");
6784
+ await writeFile2(file, content, "utf8");
7230
6785
  }
7231
6786
  log.warn(`--fix: rewrote ${pending.length} file(s):`);
7232
6787
  for (const { file } of pending)
@@ -7719,8 +7274,8 @@ import { randomBytes } from "node:crypto";
7719
7274
 
7720
7275
  // src/lib/build-fingerprint.ts
7721
7276
  import * as fs from "node:fs";
7722
- import { mkdir as mkdir3, readFile as readFile20, writeFile as writeFile4 } from "node:fs/promises";
7723
- import { createHash as createHash4 } from "node:crypto";
7277
+ import { mkdir as mkdir2, readFile as readFile19, writeFile as writeFile3 } from "node:fs/promises";
7278
+ import { createHash as createHash3 } from "node:crypto";
7724
7279
  import path7 from "node:path";
7725
7280
  import git from "isomorphic-git";
7726
7281
  var FINGERPRINT_FILENAME = "build-fingerprint.json";
@@ -7806,10 +7361,10 @@ async function getEngineBundleHash() {
7806
7361
  getAssetPath("engine/gutterpress-agent.js")
7807
7362
  ]);
7808
7363
  const [viewerBytes, agentBytes] = await Promise.all([
7809
- readFile20(viewerPath),
7810
- readFile20(agentPath)
7364
+ readFile19(viewerPath),
7365
+ readFile19(agentPath)
7811
7366
  ]);
7812
- const hash = createHash4("sha256");
7367
+ const hash = createHash3("sha256");
7813
7368
  hash.update(viewerBytes);
7814
7369
  hash.update(agentBytes);
7815
7370
  return hash.digest("hex").slice(0, 12);
@@ -7829,7 +7384,6 @@ async function getToolVersions() {
7829
7384
  gutterpress: PACKAGE_META.version,
7830
7385
  bun: process.versions.bun ?? null,
7831
7386
  node: process.versions.node,
7832
- "puppeteer-core": PACKAGE_META.dependencies["puppeteer-core"] ?? null,
7833
7387
  engineBundle: engineBundleHash,
7834
7388
  ghostscript: gsVersion,
7835
7389
  qpdf: qpdfVersion,
@@ -7877,8 +7431,8 @@ async function writeBuildFingerprint(input) {
7877
7431
  sourceRevision,
7878
7432
  tools
7879
7433
  };
7880
- await mkdir3(outputDir, { recursive: true });
7881
- await writeFile4(outPath, stableJsonStringify(payload), "utf8");
7434
+ await mkdir2(outputDir, { recursive: true });
7435
+ await writeFile3(outPath, stableJsonStringify(payload), "utf8");
7882
7436
  return outPath;
7883
7437
  }
7884
7438
 
@@ -7887,12 +7441,9 @@ var INSTALL_HINTS2 = {
7887
7441
  gs: INSTALL_HINTS.gs.body,
7888
7442
  qpdf: INSTALL_HINTS.qpdf.body
7889
7443
  };
7890
- function rendersInPooledChromium(format, opts) {
7891
- return format !== "html" && !opts.engineBrowser;
7892
- }
7893
7444
  async function preflightBuildTools(format, opts, config) {
7894
7445
  const missing = [];
7895
- if (rendersInPooledChromium(format, opts) && !await resolveChromiumExecutable()) {
7446
+ if (format !== "html" && !opts.engineBrowser && !await resolveChromiumExecutable()) {
7896
7447
  await requireChromiumExecutable();
7897
7448
  }
7898
7449
  if (format === "pdfx" && !await resolveGhostscript()) {
@@ -7916,24 +7467,6 @@ ${list}
7916
7467
 
7917
7468
  Install the missing tools and re-run, or set GHOSTSCRIPT_PATH, CHROMIUM_PATH, or system PATH so gutterpress can find them. See the User Guide Chapter 7 (System Setup) at examples/gutterpress-user-guide/07-system-setup.md for the full per-feature matrix.`, 2);
7918
7469
  }
7919
- async function verifyNativeChromiumMilestone() {
7920
- let version;
7921
- try {
7922
- const browser = await getBrowser(RENDER_TIMEOUT_MS);
7923
- version = await browser.version();
7924
- } catch (err) {
7925
- throw new BuildError(`Could not launch a Chromium browser for the PDF build: ` + `${err instanceof Error ? err.message : String(err)}`, 2);
7926
- }
7927
- const milestone = Number(/Chrome\/(\d+)/.exec(version)?.[1] ?? 0);
7928
- if (milestone < REQUIRED_MILESTONE) {
7929
- await closeBrowser();
7930
- throw new BuildError(`The Gutterpress native engine requires Chromium ${REQUIRED_MILESTONE}+; found ${version}.
7931
-
7932
- ` + `Install a newer Chrome, Chromium, or Edge, or point CHROMIUM_PATH ` + `(or PUPPETEER_EXECUTABLE_PATH) at a ${REQUIRED_MILESTONE}+ binary.
7933
-
7934
- ` + `Note: this applies to the CLI's own Chromium only — the desktop app ` + `renders PDFs with its own bundled browser and needs no ` + `separate install.`, 2);
7935
- }
7936
- }
7937
7470
  function computeGates(format, opts, config) {
7938
7471
  if (format === "html") {
7939
7472
  if (opts.skipLint || opts.skipPreValidate || opts.skipPostValidate) {
@@ -8182,7 +7715,9 @@ class HtmlOutput {
8182
7715
  }
8183
7716
 
8184
7717
  class PdfOutput {
8185
- async finish(ctx, htmlFile) {
7718
+ async finish(ctx, htmlFile, browser) {
7719
+ if (!browser)
7720
+ throw new BuildError("PDF build reached the render stage without a browser");
8186
7721
  const { workDir, outDir, inputDir, config, opts, format, manifestDir, gates } = ctx;
8187
7722
  const pdfxMode = format === "pdfx" ? opts.pdfxFlavor ?? config.pdfx.flavor : undefined;
8188
7723
  const pdfName = artifactName(config.title, pdfxMode ? "pdfx" : "pdf");
@@ -8193,13 +7728,13 @@ class PdfOutput {
8193
7728
  const rawPdf = pdfxMode ? path8.join(stage, "raw.pdf") : path8.resolve(pdfFile);
8194
7729
  await fsp2.mkdir(path8.dirname(path8.resolve(pdfFile)), { recursive: true });
8195
7730
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
8196
- const { buildNativePdf } = await import("./engine-qtfrfbpk.js");
7731
+ const { buildNativePdf } = await import("./engine-mwshptgf.js");
8197
7732
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
8198
7733
  title: config.title,
8199
7734
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
8200
7735
  signature: config.print.signature,
8201
7736
  allowShrink: opts.allowShrink
8202
- }, opts.engineBrowser);
7737
+ }, browser);
8203
7738
  for (const d of engineDiagnostics)
8204
7739
  log.warn(d.message);
8205
7740
  if (!pdfxMode) {
@@ -8266,20 +7801,26 @@ async function runBuild(opts) {
8266
7801
  if (ctx.format !== "html") {
8267
7802
  await preflightBuildTools(ctx.format, opts, ctx.config);
8268
7803
  }
8269
- if (rendersInPooledChromium(ctx.format, opts))
8270
- prewarmBrowser(RENDER_TIMEOUT_MS);
7804
+ const launch = opts.engineBrowser ?? (async () => (await import("./cdp-smdx6mr3.js")).launchChromium());
7805
+ const browserPromise = ctx.format === "html" ? null : launch();
7806
+ browserPromise?.catch(() => {});
8271
7807
  try {
8272
7808
  await fsp2.mkdir(ctx.workDir, { recursive: true });
8273
7809
  await runQualityGates(ctx);
8274
- if (rendersInPooledChromium(ctx.format, opts)) {
8275
- await verifyNativeChromiumMilestone();
7810
+ let browser;
7811
+ if (browserPromise) {
7812
+ try {
7813
+ browser = await browserPromise;
7814
+ } catch (err) {
7815
+ throw new BuildError(`Could not launch a Chromium browser for the PDF build: ${err instanceof Error ? err.message : String(err)}`, 2);
7816
+ }
8276
7817
  }
8277
7818
  const htmlFile = await renderBook(ctx);
8278
7819
  const strategy = ctx.format === "html" ? new HtmlOutput : new PdfOutput;
8279
- return await strategy.finish(ctx, htmlFile);
7820
+ return await strategy.finish(ctx, htmlFile, browser);
8280
7821
  } finally {
8281
- if (!opts.keepBrowserAlive)
8282
- await closeBrowser();
7822
+ if (browserPromise)
7823
+ await browserPromise.then((b) => b.close(), () => {});
8283
7824
  await fsp2.rm(ctx.workDir, { recursive: true, force: true });
8284
7825
  }
8285
7826
  }
@@ -8314,9 +7855,9 @@ function openPath(filePath) {
8314
7855
 
8315
7856
  // src/preview/lifecycle.ts
8316
7857
  import path10 from "path";
8317
- import { tmpdir as tmpdir2 } from "os";
7858
+ import { tmpdir } from "os";
8318
7859
  import { randomBytes as randomBytes2 } from "crypto";
8319
- import { readdir as readdir3, readFile as readFile21, writeFile as writeFile5 } from "node:fs/promises";
7860
+ import { readdir as readdir3, readFile as readFile20, writeFile as writeFile4 } from "node:fs/promises";
8320
7861
 
8321
7862
  // src/utils/file-utils.ts
8322
7863
  import { promises as fs3 } from "fs";
@@ -8331,7 +7872,7 @@ async function fileExists(filePath) {
8331
7872
  async function remove(targetPath) {
8332
7873
  await fs3.rm(targetPath, { recursive: true, force: true });
8333
7874
  }
8334
- async function mkdir4(dirPath) {
7875
+ async function mkdir3(dirPath) {
8335
7876
  await fs3.mkdir(dirPath, { recursive: true });
8336
7877
  }
8337
7878
 
@@ -8355,9 +7896,6 @@ var EMPTY_BOOK_HTML = `<!doctype html>
8355
7896
  </body>
8356
7897
  </html>
8357
7898
  `;
8358
- function incrementalPreviewEnabled() {
8359
- return process.env.GUTTERPRESS_PREVIEW_INCREMENTAL !== "0";
8360
- }
8361
7899
  async function renderPreviewBook(inputPath, config, opts) {
8362
7900
  const { plugins, pluginStyles } = await loadPluginsWithCss(config.extensions, inputPath, (ref, err) => warn(`Skipping plugin "${ref}" in preview — ${err.message}`));
8363
7901
  return renderChapters(inputPath, {
@@ -8366,7 +7904,6 @@ async function renderPreviewBook(inputPath, config, opts) {
8366
7904
  files: opts.files,
8367
7905
  plugins,
8368
7906
  pluginStyles,
8369
- wrapChapters: opts.wrapChapters,
8370
7907
  annotateSourceChapters: true,
8371
7908
  ...opts.onCssAssets ? { onCssAssets: opts.onCssAssets } : {},
8372
7909
  onChapterWarnings: (file, warnings) => {
@@ -8376,17 +7913,12 @@ async function renderPreviewBook(inputPath, config, opts) {
8376
7913
  }
8377
7914
  });
8378
7915
  }
8379
- function injectPreviewScripts(html, pageIsolateChapters) {
7916
+ function injectPreviewScripts(html) {
8380
7917
  const scripts = ` <script src="/engine/gutterpress-viewer.js"></script>
8381
7918
  ` + `<script src="/preview/scripts/preview-interface.js"></script>
8382
7919
  ` + `<script src="/preview/scripts/preview-bridge.js"></script>
8383
7920
  `;
8384
- let output = /<\/head>/i.test(html) ? html.replace(/<\/head>/i, scripts + "</head>") : html + scripts;
8385
- if (pageIsolateChapters && /<\/head>/i.test(output)) {
8386
- output = output.replace(/<\/head>/i, `<style>.gutterpress-chapter{break-before:page}</style>
8387
- </head>`);
8388
- }
8389
- return output;
7921
+ return /<\/head>/i.test(html) ? html.replace(/<\/head>/i, scripts + "</head>") : html + scripts;
8390
7922
  }
8391
7923
  async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
8392
7924
  if (!inputPath) {
@@ -8397,7 +7929,6 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
8397
7929
  const nextAssets = new Map;
8398
7930
  const html = await renderPreviewBook(inputPath, config, {
8399
7931
  files: config.source?.files ?? null,
8400
- wrapChapters: false,
8401
7932
  onCssAssets: (copies) => {
8402
7933
  for (const copy of copies)
8403
7934
  nextAssets.set(copy.to, copy.from);
@@ -8406,39 +7937,7 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
8406
7937
  cssAssets.clear();
8407
7938
  for (const [to, from] of nextAssets)
8408
7939
  cssAssets.set(to, from);
8409
- await fsp3.writeFile(path9.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html, false), "utf-8");
8410
- }
8411
- async function renderChapterPreviewHtml(inputPath, file, config) {
8412
- const html = await renderPreviewBook(inputPath, config, {
8413
- files: [canonicalChapterId(file)],
8414
- wrapChapters: true
8415
- });
8416
- return injectPreviewScripts(html, true);
8417
- }
8418
- function describeChanges(changes, inputResolved) {
8419
- const files = [];
8420
- for (const [changedPath, event] of changes) {
8421
- const relative2 = path9.relative(inputResolved, path9.resolve(changedPath));
8422
- if (relative2 === "" || relative2 === ".." || relative2.startsWith(`..${path9.sep}`) || path9.isAbsolute(relative2))
8423
- continue;
8424
- files.push({
8425
- relativePath: canonicalChapterId(relative2),
8426
- ext: path9.extname(changedPath).toLowerCase(),
8427
- event
8428
- });
8429
- }
8430
- return files;
8431
- }
8432
- function decideBroadcast(files, changeCount, incremental) {
8433
- const only = files.length === 1 ? files[0] : null;
8434
- if (incremental && changeCount === 1 && only?.ext === ".md" && only.event !== "unlink" && only.event !== "unlinkDir") {
8435
- return {
8436
- kind: "chapter-splice",
8437
- chapterId: canonicalChapterId(only.relativePath),
8438
- relativePath: only.relativePath
8439
- };
8440
- }
8441
- return { kind: "full-reload" };
7940
+ await fsp3.writeFile(path9.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
8442
7941
  }
8443
7942
  function isDotPathUnderRoot(candidatePath, root) {
8444
7943
  const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "");
@@ -8754,14 +8253,8 @@ function createFileWatcher(state) {
8754
8253
  await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets);
8755
8254
  if (closed)
8756
8255
  return;
8757
- const decision = decideBroadcast(describeChanges(changes, inputResolved), changes.length, incrementalPreviewEnabled());
8758
- if (decision.kind === "chapter-splice") {
8759
- state.previewServer?.broadcastContentUpdate(decision.chapterId);
8760
- info(`Chapter updated: ${decision.relativePath}`);
8761
- } else {
8762
- state.previewServer?.broadcastReload();
8763
- info(changes.length > 1 ? `Preview updated (${changes.length} files changed — full reload)` : "Preview updated");
8764
- }
8256
+ state.previewServer?.broadcastReload();
8257
+ info(changes.length > 1 ? `Preview updated (${changes.length} files changed)` : "Preview updated");
8765
8258
  } catch (err) {
8766
8259
  error("Failed to regenerate preview:", err);
8767
8260
  } finally {
@@ -8819,7 +8312,7 @@ async function stopFileWatcher(state) {
8819
8312
  }
8820
8313
 
8821
8314
  // src/preview/lifecycle.ts
8822
- var TEMP_DIR_BASE = path10.join(tmpdir2(), "gutterpress-preview");
8315
+ var TEMP_DIR_BASE = path10.join(tmpdir(), "gutterpress-preview");
8823
8316
  var PID_FILE_NAME = ".gutterpress.pid";
8824
8317
  function isProcessAlive(pid) {
8825
8318
  if (!Number.isFinite(pid) || pid <= 0)
@@ -8842,7 +8335,7 @@ async function cleanupOrphanTempDirs() {
8842
8335
  const dir = path10.join(TEMP_DIR_BASE, entry);
8843
8336
  const pidFile = path10.join(dir, PID_FILE_NAME);
8844
8337
  try {
8845
- const raw = await readFile21(pidFile, "utf8");
8338
+ const raw = await readFile20(pidFile, "utf8");
8846
8339
  const pid = parseInt(raw.trim(), 10);
8847
8340
  if (!isProcessAlive(pid)) {
8848
8341
  debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
@@ -8855,9 +8348,9 @@ async function initializePreviewDirectories() {
8855
8348
  await cleanupOrphanTempDirs();
8856
8349
  const tempDirSuffix = randomBytes2(8).toString("hex");
8857
8350
  const tempDir = path10.join(TEMP_DIR_BASE, tempDirSuffix);
8858
- await mkdir4(tempDir);
8351
+ await mkdir3(tempDir);
8859
8352
  debug(`Created temporary directory: ${tempDir}`);
8860
- await writeFile5(path10.join(tempDir, PID_FILE_NAME), `${process.pid}
8353
+ await writeFile4(path10.join(tempDir, PID_FILE_NAME), `${process.pid}
8861
8354
  `, "utf8");
8862
8355
  return tempDir;
8863
8356
  }
@@ -8947,8 +8440,8 @@ function createServerState(inputPath, tempDir, config, options) {
8947
8440
  // src/preview/http-server.ts
8948
8441
  import http from "node:http";
8949
8442
  import net from "node:net";
8950
- import { createHash as createHash5, randomUUID } from "node:crypto";
8951
- import { readFile as readFile22, stat as stat4 } from "node:fs/promises";
8443
+ import { createHash as createHash4, randomUUID } from "node:crypto";
8444
+ import { readFile as readFile21, stat as stat4 } from "node:fs/promises";
8952
8445
  import path12 from "path";
8953
8446
  import { WebSocket, WebSocketServer } from "ws";
8954
8447
 
@@ -9003,169 +8496,6 @@ function resolveStaticPath(urlPathname, root) {
9003
8496
 
9004
8497
  // src/preview/http-server.ts
9005
8498
  var HMR_PATH = "/__gutterpress-hmr";
9006
- function hmrClientSnippet(initialRevision, instanceId) {
9007
- return `
9008
- <script>
9009
- (function () {
9010
- // When loaded by the preview SHELL (iframe double-buffer), the shell loads us
9011
- // with ?gutterpressshell=1 and owns HMR (it swaps frames + syncs scroll), so we stay
9012
- // inert. We must NOT bail merely because we're framed — other hosts (the
9013
- // Electron desktop's SPA) embed book.html directly and rely on this HMR client
9014
- // for scroll-anchor and reload.
9015
- if (/[?&]gutterpressshell=1/.test(location.search)) return;
9016
- var ANCHOR_KEY = 'gutterpress-scroll-anchor';
9017
- var appliedRevision = ${initialRevision};
9018
- var appliedInstance = ${JSON.stringify(instanceId)};
9019
- var readyToAcknowledge = false;
9020
- var reloadRequested = false;
9021
-
9022
- // Find the element nearest the top of the viewport that carries a source
9023
- // line (markdown-it-source-map emits data-source-line on block elements).
9024
- // We anchor on SOURCE position, not pixels, because page breaks move when
9025
- // content re-paginates.
9026
- function captureAnchor() {
9027
- var els = document.querySelectorAll('[data-source-line]');
9028
- var best = null, bestTop = -Infinity;
9029
- for (var i = 0; i < els.length; i++) {
9030
- var r = els[i].getBoundingClientRect();
9031
- if (r.bottom < 0 || r.height === 0) continue;
9032
- if (r.top <= 80 && r.top > bestTop) { bestTop = r.top; best = els[i]; }
9033
- }
9034
- if (!best) {
9035
- for (var j = 0; j < els.length; j++) {
9036
- var rr = els[j].getBoundingClientRect();
9037
- if (rr.bottom > 0 && rr.height > 0) { best = els[j]; break; }
9038
- }
9039
- }
9040
- if (!best) return null;
9041
- var chapter = best.closest && best.closest('[data-chapter-src]');
9042
- return {
9043
- chapter: chapter ? chapter.getAttribute('data-chapter-src') : null,
9044
- line: best.getAttribute('data-source-line'),
9045
- offset: best.getBoundingClientRect().top
9046
- };
9047
- }
9048
-
9049
- // After a content reload, put the same source line back at the same viewport
9050
- // offset so the author keeps their place (no jump to the top).
9051
- function restoreAnchor() {
9052
- var raw;
9053
- try { raw = sessionStorage.getItem(ANCHOR_KEY); } catch (_) { return; }
9054
- if (!raw) return;
9055
- try { sessionStorage.removeItem(ANCHOR_KEY); } catch (_) {}
9056
- var a; try { a = JSON.parse(raw); } catch (_) { return; }
9057
- var tries = 0;
9058
- (function attempt() {
9059
- var blocks = document.querySelectorAll('[data-source-line]');
9060
- var el = null;
9061
- for (var i = 0; i < blocks.length; i++) {
9062
- var chapter = blocks[i].closest && blocks[i].closest('[data-chapter-src]');
9063
- var chapterId = chapter ? chapter.getAttribute('data-chapter-src') : null;
9064
- if ((!a.chapter || chapterId === a.chapter) &&
9065
- blocks[i].getAttribute('data-source-line') === String(a.line)) {
9066
- el = blocks[i];
9067
- break;
9068
- }
9069
- }
9070
- if (el) {
9071
- window.scrollBy({
9072
- top: el.getBoundingClientRect().top - a.offset,
9073
- behavior: 'instant'
9074
- });
9075
- if (window.previewAPI && typeof window.previewAPI.refresh === 'function') {
9076
- window.previewAPI.refresh();
9077
- }
9078
- return;
9079
- }
9080
- if (tries++ < 240) setTimeout(attempt, 25); // wait for pagination
9081
- })();
9082
- }
9083
- var restored = false;
9084
- function restoreOnce() { if (restored) return; restored = true; restoreAnchor(); }
9085
- function finishInitialRender() {
9086
- restoreOnce();
9087
- readyToAcknowledge = true;
9088
- acknowledge();
9089
- }
9090
- // CRITICAL ordering: when the pagination engine is present it restructures
9091
- // the DOM after load, so restoring the scroll anchor early would target
9092
- // pre-pagination geometry. The Gutterpress engine viewer fires
9093
- // 'gp:layout' when its pagination completes — wait for it. In static
9094
- // mode (no engine) the content is final immediately, so restore right
9095
- // after load.
9096
- var hasEngine = !!document.querySelector('script[src*="/engine/gutterpress-viewer.js"]');
9097
- window.addEventListener('gp:layout', finishInitialRender, { once: true });
9098
- if (!hasEngine) {
9099
- if (document.readyState === 'loading') {
9100
- document.addEventListener('DOMContentLoaded', function () { setTimeout(finishInitialRender, 50); });
9101
- } else {
9102
- setTimeout(finishInitialRender, 50);
9103
- }
9104
- }
9105
- var ws = null;
9106
- var reconnectTimer = null;
9107
- var reconnectDelay = 250;
9108
- var stopped = false;
9109
-
9110
- function acknowledge() {
9111
- if (!readyToAcknowledge || !ws || ws.readyState !== 1) return;
9112
- try {
9113
- ws.send(JSON.stringify({
9114
- type: 'reload-applied',
9115
- instance: appliedInstance,
9116
- revision: appliedRevision
9117
- }));
9118
- } catch (_) {}
9119
- }
9120
-
9121
- function connect() {
9122
- if (stopped) return;
9123
- ws = new WebSocket(location.origin.replace(/^http/, 'ws') + '${HMR_PATH}');
9124
- ws.onopen = function () {
9125
- reconnectDelay = 250;
9126
- acknowledge();
9127
- };
9128
- ws.onmessage = function (e) {
9129
- var msg;
9130
- try { msg = JSON.parse(e.data); } catch (_) { return; }
9131
- if (
9132
- msg.type !== 'reload-state' &&
9133
- msg.type !== 'full-reload' &&
9134
- msg.type !== 'content-update'
9135
- ) return;
9136
- var instance = typeof msg.instance === 'string' ? msg.instance : null;
9137
- var revision = Number(msg.revision);
9138
- if (!instance || !Number.isSafeInteger(revision) || revision < 0) return;
9139
- if (instance === appliedInstance && revision <= appliedRevision) {
9140
- acknowledge();
9141
- return;
9142
- }
9143
- if (reloadRequested) return;
9144
- reloadRequested = true;
9145
- try { var a = captureAnchor(); if (a) sessionStorage.setItem(ANCHOR_KEY, JSON.stringify(a)); } catch (_) {}
9146
- location.reload();
9147
- };
9148
- ws.onclose = function () {
9149
- ws = null;
9150
- if (stopped || reconnectTimer !== null) return;
9151
- reconnectTimer = setTimeout(function () {
9152
- reconnectTimer = null;
9153
- connect();
9154
- }, reconnectDelay);
9155
- reconnectDelay = Math.min(reconnectDelay * 2, 5000);
9156
- };
9157
- ws.onerror = function () { try { ws.close(); } catch (_) {} };
9158
- }
9159
-
9160
- window.addEventListener('beforeunload', function () {
9161
- stopped = true;
9162
- if (reconnectTimer !== null) clearTimeout(reconnectTimer);
9163
- });
9164
- connect();
9165
- })();
9166
- </script>
9167
- `;
9168
- }
9169
8499
  function shellHtml(initialRevision, instanceId) {
9170
8500
  return `<!doctype html>
9171
8501
  <html lang="en"><head><meta charset="utf-8"><title>gutterpress preview</title>
@@ -9218,14 +8548,7 @@ async function findAvailablePort(startPort, host = "127.0.0.1") {
9218
8548
  }
9219
8549
  throw new BuildError(`Could not find an available port on ${host} from ${firstPort} to ${port - 1}; all are already in use. ` + "Stop another preview server or pass --port with an available port.", undefined, { cause: lastBusyError });
9220
8550
  }
9221
- function injectHmrClient(html, revision, instanceId) {
9222
- const snippet = hmrClientSnippet(revision, instanceId);
9223
- const closingBody = html.lastIndexOf("</body>");
9224
- if (closingBody === -1)
9225
- return html + snippet;
9226
- return html.slice(0, closingBody) + snippet + html.slice(closingBody);
9227
- }
9228
- async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders = {}, hmrRevision = 0, hmrInstance = "") {
8551
+ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders = {}) {
9229
8552
  let filePath = absPath;
9230
8553
  try {
9231
8554
  const s = await stat4(filePath);
@@ -9238,7 +8561,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
9238
8561
  }
9239
8562
  let data;
9240
8563
  try {
9241
- data = await readFile22(filePath);
8564
+ data = await readFile21(filePath);
9242
8565
  } catch {
9243
8566
  res.writeHead(404);
9244
8567
  res.end("Not Found");
@@ -9246,9 +8569,8 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
9246
8569
  }
9247
8570
  const isHtml = filePath.endsWith(".html") || filePath.endsWith(".htm");
9248
8571
  if (isHtml) {
9249
- const withHmr = injectHmrClient(data.toString("utf-8"), hmrRevision, hmrInstance);
9250
8572
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
9251
- res.end(withHmr);
8573
+ res.end(data);
9252
8574
  return;
9253
8575
  }
9254
8576
  const ct = STATIC_MIME[path12.extname(filePath).toLowerCase()] ?? "application/octet-stream";
@@ -9288,12 +8610,12 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
9288
8610
  let data;
9289
8611
  if (!validator || validator.stamp !== stamp) {
9290
8612
  try {
9291
- data = await readFile22(absPath);
8613
+ data = await readFile21(absPath);
9292
8614
  } catch {
9293
8615
  await serveStatic(absPath, res);
9294
8616
  return;
9295
8617
  }
9296
- const digest = createHash5("sha256").update(data).digest("base64url");
8618
+ const digest = createHash4("sha256").update(data).digest("base64url");
9297
8619
  validator = { stamp, etag: `"gutterpress-file-${digest}"` };
9298
8620
  validators.set(absPath, validator);
9299
8621
  }
@@ -9323,16 +8645,11 @@ async function createPreviewServer(state, port) {
9323
8645
  const projectAssetValidators = new Map;
9324
8646
  let reloadRevision = 0;
9325
8647
  const clients = new Map;
9326
- function sendRevision(ws, type, file) {
8648
+ function sendRevision(ws, type) {
9327
8649
  if (ws.readyState !== WebSocket.OPEN)
9328
8650
  return;
9329
8651
  try {
9330
- ws.send(JSON.stringify({
9331
- type,
9332
- instance: instanceId,
9333
- revision: reloadRevision,
9334
- ...file ? { file } : {}
9335
- }));
8652
+ ws.send(JSON.stringify({ type, instance: instanceId, revision: reloadRevision }));
9336
8653
  } catch {}
9337
8654
  }
9338
8655
  function waitForAcknowledgement(ws) {
@@ -9422,34 +8739,6 @@ async function createPreviewServer(state, port) {
9422
8739
  res.end("Not Found");
9423
8740
  return;
9424
8741
  }
9425
- if (url.pathname === "/__chapter" && req.method === "GET") {
9426
- const rawFile = url.searchParams.get("file");
9427
- const file = rawFile ? canonicalChapterId(rawFile) : "";
9428
- const revision = Number(url.searchParams.get("revision"));
9429
- const configuredFiles = state.config.source?.files;
9430
- if (!file || !state.currentInputPath || !incrementalPreviewEnabled() || !Number.isSafeInteger(revision) || revision !== reloadRevision || path12.extname(file).toLowerCase() !== ".md" || hasDotSegment(file) || !resolveWithinRoot(file, state.currentInputPath) || Array.isArray(configuredFiles) && configuredFiles.length > 0 && !configuredFiles.some((configured) => canonicalChapterId(configured) === file)) {
9431
- res.writeHead(400);
9432
- res.end("Bad Request");
9433
- return;
9434
- }
9435
- try {
9436
- const html = await renderChapterPreviewHtml(state.currentInputPath, file, state.config);
9437
- if (revision !== reloadRevision) {
9438
- res.writeHead(409);
9439
- res.end("Superseded");
9440
- return;
9441
- }
9442
- res.writeHead(200, {
9443
- "Content-Type": "text/html; charset=utf-8",
9444
- "Cache-Control": "no-store"
9445
- });
9446
- res.end(html);
9447
- } catch (error2) {
9448
- res.writeHead(500);
9449
- res.end(error2 instanceof Error ? error2.message : String(error2));
9450
- }
9451
- return;
9452
- }
9453
8742
  if (matchesEmbedded(url.pathname)) {
9454
8743
  if (req.headers["if-none-match"] === EMBEDDED_ETAG) {
9455
8744
  res.writeHead(304, { ETag: EMBEDDED_ETAG, "Cache-Control": EMBEDDED_CACHE_CONTROL });
@@ -9466,12 +8755,12 @@ async function createPreviewServer(state, port) {
9466
8755
  }
9467
8756
  return;
9468
8757
  }
9469
- if (url.pathname === "/" && incrementalPreviewEnabled()) {
8758
+ if (url.pathname === "/") {
9470
8759
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
9471
8760
  res.end(shellHtml(reloadRevision, instanceId));
9472
8761
  return;
9473
8762
  }
9474
- const pathname = url.pathname === "/" ? "/book.html" : url.pathname;
8763
+ const pathname = url.pathname;
9475
8764
  const cssAssetSource = state.cssAssets.get(pathname.replace(/^\/+/, ""));
9476
8765
  if (cssAssetSource) {
9477
8766
  await serveRevalidatedStatic(req, cssAssetSource, res, projectAssetValidators).catch((err) => {
@@ -9495,7 +8784,7 @@ async function createPreviewServer(state, port) {
9495
8784
  res.end("Not Found");
9496
8785
  return;
9497
8786
  }
9498
- const serve = servingProjectRoot ? serveRevalidatedStatic(req, absPath, res, projectAssetValidators) : serveStatic(absPath, res, "no-store", {}, reloadRevision, instanceId);
8787
+ const serve = servingProjectRoot ? serveRevalidatedStatic(req, absPath, res, projectAssetValidators) : serveStatic(absPath, res);
9499
8788
  await serve.catch((err) => {
9500
8789
  if (!res.headersSent) {
9501
8790
  res.writeHead(500);
@@ -9523,22 +8812,6 @@ async function createPreviewServer(state, port) {
9523
8812
  openPath(serverUrl).catch(() => {});
9524
8813
  }
9525
8814
  let stopped = false;
9526
- const broadcastUpdate = (type, file) => {
9527
- if (stopped)
9528
- return;
9529
- reloadRevision++;
9530
- for (const [ws] of clients) {
9531
- sendRevision(ws, type, file);
9532
- waitForAcknowledgement(ws);
9533
- }
9534
- };
9535
- const updateInFlight = () => {
9536
- for (const client of clients.values()) {
9537
- if (client.acknowledgedRevision < reloadRevision)
9538
- return true;
9539
- }
9540
- return false;
9541
- };
9542
8815
  return {
9543
8816
  port: boundPort,
9544
8817
  async close() {
@@ -9560,13 +8833,13 @@ async function createPreviewServer(state, port) {
9560
8833
  });
9561
8834
  },
9562
8835
  broadcastReload() {
9563
- broadcastUpdate("full-reload");
9564
- },
9565
- broadcastContentUpdate(file) {
9566
- if (updateInFlight())
9567
- broadcastUpdate("full-reload");
9568
- else
9569
- broadcastUpdate("content-update", canonicalChapterId(file));
8836
+ if (stopped)
8837
+ return;
8838
+ reloadRevision++;
8839
+ for (const [ws] of clients) {
8840
+ sendRevision(ws, "full-reload");
8841
+ waitForAcknowledgement(ws);
8842
+ }
9570
8843
  }
9571
8844
  };
9572
8845
  }
@@ -9627,14 +8900,14 @@ async function startPreviewServer(options) {
9627
8900
  }
9628
8901
 
9629
8902
  // src/lib/project-scaffold.ts
9630
- import { access, copyFile, cp as cp2, mkdir as mkdir6, readdir as readdir4, readFile as readFile24, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
8903
+ import { access, copyFile, cp, mkdir as mkdir5, readdir as readdir4, readFile as readFile23, stat as stat5, writeFile as writeFile5 } from "node:fs/promises";
9631
8904
  import { constants as FS, existsSync as existsSync11 } from "node:fs";
9632
8905
  import path14 from "node:path";
9633
8906
 
9634
8907
  // src/lib/manifest-doc.ts
9635
8908
  import { existsSync as existsSync10 } from "node:fs";
9636
8909
  import { randomUUID as randomUUID2 } from "node:crypto";
9637
- import { mkdir as mkdir5, open, readFile as readFile23, rename, rm as rm2 } from "node:fs/promises";
8910
+ import { mkdir as mkdir4, open, readFile as readFile22, rename, rm } from "node:fs/promises";
9638
8911
  import path13 from "node:path";
9639
8912
  import { parseDocument, isSeq, YAMLSeq } from "yaml";
9640
8913
  function resolveManifestPath(projectDir) {
@@ -9645,7 +8918,7 @@ async function loadManifestDoc(projectDir) {
9645
8918
  const file = resolveManifestPath(projectDir);
9646
8919
  let text = "";
9647
8920
  try {
9648
- text = await readFile23(file, "utf8");
8921
+ text = await readFile22(file, "utf8");
9649
8922
  } catch (error2) {
9650
8923
  if (error2.code !== "ENOENT")
9651
8924
  throw error2;
@@ -9654,7 +8927,7 @@ async function loadManifestDoc(projectDir) {
9654
8927
  }
9655
8928
  async function writeManifestDoc(file, doc) {
9656
8929
  const dir = path13.dirname(file);
9657
- await mkdir5(dir, { recursive: true });
8930
+ await mkdir4(dir, { recursive: true });
9658
8931
  const temporary = path13.join(dir, `.${path13.basename(file)}.tmp-${process.pid}-${randomUUID2()}`);
9659
8932
  try {
9660
8933
  const handle = await open(temporary, "wx", 438);
@@ -9671,7 +8944,7 @@ async function writeManifestDoc(file, doc) {
9671
8944
  await directory.close();
9672
8945
  }
9673
8946
  } finally {
9674
- await rm2(temporary, { force: true });
8947
+ await rm(temporary, { force: true });
9675
8948
  }
9676
8949
  }
9677
8950
  function ensureSeq(doc, key) {
@@ -9780,23 +9053,23 @@ async function scaffoldProject(options) {
9780
9053
  const preset = customTemplateDir && options.preset === undefined ? undefined : requirePreset(options.preset, options.customPage);
9781
9054
  const targets = preset ? resolveScaffoldTargets(options.targets, preset) : undefined;
9782
9055
  try {
9783
- await mkdir6(projectDir, { recursive: true });
9056
+ await mkdir5(projectDir, { recursive: true });
9784
9057
  if (customTemplateDir) {
9785
9058
  const entries = await readdir4(customTemplateDir, { withFileTypes: true });
9786
9059
  for (const entry of entries) {
9787
9060
  if (entry.name === ".gutterpress-template.json")
9788
9061
  continue;
9789
- await cp2(path14.join(customTemplateDir, entry.name), path14.join(projectDir, entry.name), { recursive: true });
9062
+ await cp(path14.join(customTemplateDir, entry.name), path14.join(projectDir, entry.name), { recursive: true });
9790
9063
  }
9791
- await mkdir6(path14.join(projectDir, "assets"), { recursive: true });
9064
+ await mkdir5(path14.join(projectDir, "assets"), { recursive: true });
9792
9065
  } else {
9793
9066
  const tplManifest = await getAssetPath(`templates/${template}/manifest.yaml`);
9794
9067
  const tplChapter = await getAssetPath(`templates/${template}/chapter-01.md`);
9795
- await mkdir6(path14.join(projectDir, "assets"), { recursive: true });
9068
+ await mkdir5(path14.join(projectDir, "assets"), { recursive: true });
9796
9069
  await copyFile(tplManifest, path14.join(projectDir, MANIFEST_FILENAMES[0]));
9797
9070
  await copyFile(tplChapter, path14.join(projectDir, "chapter-01.md"));
9798
- await mkdir6(path14.join(projectDir, "styles"), { recursive: true });
9799
- await writeFile6(path14.join(projectDir, "styles", "book.css"), starterOverridesCss(), "utf8");
9071
+ await mkdir5(path14.join(projectDir, "styles"), { recursive: true });
9072
+ await writeFile5(path14.join(projectDir, "styles", "book.css"), starterOverridesCss(), "utf8");
9800
9073
  }
9801
9074
  } catch (e) {
9802
9075
  throw new CreateProjectErrorImpl("scaffold-io", `Could not create the book files: ${e instanceof Error ? e.message : String(e)}`);
@@ -9843,7 +9116,7 @@ async function scaffoldProject(options) {
9843
9116
  let versionHistoryError;
9844
9117
  if (requested === "local-git") {
9845
9118
  try {
9846
- const { providerFor } = await import("./source-provider-ta09wegv.js");
9119
+ const { providerFor } = await import("./source-provider-pzmz0br9.js");
9847
9120
  const provider = providerFor({ type: "local-folder", path: projectDir });
9848
9121
  await provider.initVersionHistory({
9849
9122
  projectDir,
@@ -9873,10 +9146,10 @@ async function ensureGitignoreHasDist(projectDir) {
9873
9146
  const gitignorePath = path14.join(projectDir, ".gitignore");
9874
9147
  let existing = null;
9875
9148
  try {
9876
- existing = await readFile24(gitignorePath, "utf8");
9149
+ existing = await readFile23(gitignorePath, "utf8");
9877
9150
  } catch {}
9878
9151
  if (existing === null) {
9879
- await writeFile6(gitignorePath, `dist/
9152
+ await writeFile5(gitignorePath, `dist/
9880
9153
  `, "utf8");
9881
9154
  return;
9882
9155
  }
@@ -9886,14 +9159,14 @@ async function ensureGitignoreHasDist(projectDir) {
9886
9159
  return;
9887
9160
  const needsLeadingNewline = existing.length > 0 && !existing.endsWith(`
9888
9161
  `);
9889
- await writeFile6(gitignorePath, existing + (needsLeadingNewline ? `
9162
+ await writeFile5(gitignorePath, existing + (needsLeadingNewline ? `
9890
9163
  ` : "") + `dist/
9891
9164
  `, "utf8");
9892
9165
  }
9893
9166
  async function firstSourceFile(manifestPath) {
9894
9167
  let text;
9895
9168
  try {
9896
- text = await readFile24(manifestPath, "utf8");
9169
+ text = await readFile23(manifestPath, "utf8");
9897
9170
  } catch {
9898
9171
  return;
9899
9172
  }
@@ -9905,15 +9178,15 @@ async function firstSourceFile(manifestPath) {
9905
9178
  return m ? m[1].trim() : undefined;
9906
9179
  }
9907
9180
  async function fillTemplateFile(filePath, substitutions) {
9908
- let text = await readFile24(filePath, "utf8");
9181
+ let text = await readFile23(filePath, "utf8");
9909
9182
  for (const [token, value] of Object.entries(substitutions)) {
9910
9183
  text = text.split(token).join(value);
9911
9184
  }
9912
- await writeFile6(filePath, text, "utf8");
9185
+ await writeFile5(filePath, text, "utf8");
9913
9186
  }
9914
9187
 
9915
9188
  // src/lib/extension-scaffold.ts
9916
- import { access as access2, mkdir as mkdir7, readFile as readFile25, writeFile as writeFile7 } from "node:fs/promises";
9189
+ import { access as access2, mkdir as mkdir6, readFile as readFile24, writeFile as writeFile6 } from "node:fs/promises";
9917
9190
  import { constants as FS2 } from "node:fs";
9918
9191
  import path15 from "node:path";
9919
9192
  var EXTENSION_KINDS = ["plugin", "theme"];
@@ -10025,14 +9298,14 @@ async function scaffoldExtension(options) {
10025
9298
  const entries = TEMPLATE_FILES[kind];
10026
9299
  const written = [];
10027
9300
  try {
10028
- await mkdir7(extensionDir, { recursive: true });
9301
+ await mkdir6(extensionDir, { recursive: true });
10029
9302
  for (const [assetName, relDest] of entries) {
10030
9303
  const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
10031
9304
  const dest = path15.join(extensionDir, relDest);
10032
- await mkdir7(path15.dirname(dest), { recursive: true });
10033
- const text = await readFile25(src, "utf8");
9305
+ await mkdir6(path15.dirname(dest), { recursive: true });
9306
+ const text = await readFile24(src, "utf8");
10034
9307
  const table = relDest.endsWith(".json") ? jsonSafe : plain;
10035
- await writeFile7(dest, substitute(text, table), "utf8");
9308
+ await writeFile6(dest, substitute(text, table), "utf8");
10036
9309
  written.push(relDest);
10037
9310
  }
10038
9311
  } catch (e) {
@@ -10074,23 +9347,23 @@ var SKIP_ENTRIES = new Set([
10074
9347
  ]);
10075
9348
 
10076
9349
  // src/lib/extension-manager.ts
10077
- import { cp as cp3, mkdir as mkdir9, readFile as readFile27, rm as rm4, stat as stat6 } from "node:fs/promises";
9350
+ import { cp as cp2, mkdir as mkdir8, readFile as readFile26, rm as rm3, stat as stat6 } from "node:fs/promises";
10078
9351
  import { existsSync as existsSync12 } from "node:fs";
10079
9352
  import path17 from "node:path";
10080
9353
  import { isSeq as isSeq3, isMap as isMap2, isScalar as isScalar2, YAMLMap, Scalar } from "yaml";
10081
9354
 
10082
9355
  // src/lib/npm-plugin-installer.ts
10083
- import { createHash as createHash6, randomUUID as randomUUID3, timingSafeEqual } from "node:crypto";
9356
+ import { createHash as createHash5, randomUUID as randomUUID3, timingSafeEqual } from "node:crypto";
10084
9357
  import { createReadStream } from "node:fs";
10085
9358
  import {
10086
9359
  lstat,
10087
- mkdir as mkdir8,
10088
- mkdtemp as mkdtemp2,
9360
+ mkdir as mkdir7,
9361
+ mkdtemp,
10089
9362
  open as open2,
10090
- readFile as readFile26,
9363
+ readFile as readFile25,
10091
9364
  realpath,
10092
9365
  rename as rename2,
10093
- rm as rm3
9366
+ rm as rm2
10094
9367
  } from "node:fs/promises";
10095
9368
  import path16 from "node:path";
10096
9369
  import { Transform } from "node:stream";
@@ -10131,6 +9404,25 @@ async function withFetchTimeout(options, run) {
10131
9404
  }
10132
9405
  }
10133
9406
 
9407
+ // src/lib/npm-registry.ts
9408
+ var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
9409
+ var ENV_OVERRIDE = "GUTTERPRESS_NPM_REGISTRY";
9410
+ function npmRegistryUrl() {
9411
+ const configured = process.env[ENV_OVERRIDE]?.trim();
9412
+ if (!configured)
9413
+ return DEFAULT_NPM_REGISTRY;
9414
+ let scheme;
9415
+ try {
9416
+ scheme = new URL(configured).protocol;
9417
+ } catch {
9418
+ throw new Error(`Invalid ${ENV_OVERRIDE} URL "${configured}".`);
9419
+ }
9420
+ if (scheme !== "http:" && scheme !== "https:") {
9421
+ throw new Error(`${ENV_OVERRIDE} must be an http(s) URL — got "${scheme}".`);
9422
+ }
9423
+ return configured.replace(/\/+$/, "");
9424
+ }
9425
+
10134
9426
  // src/lib/npm-plugin-installer.ts
10135
9427
  var DEFAULT_LIMITS = {
10136
9428
  metadataBytes: 15 * 1024 * 1024,
@@ -10345,7 +9637,7 @@ async function selectPackage(ctx, name, selector) {
10345
9637
  }
10346
9638
  async function downloadTarball(ctx, pkg, archivePath) {
10347
9639
  const file = await open2(archivePath, "wx");
10348
- const hash = createHash6(pkg.integrity.algorithm);
9640
+ const hash = createHash5(pkg.integrity.algorithm);
10349
9641
  try {
10350
9642
  await withFetchTimeout({
10351
9643
  timeoutMs: TARBALL_TIMEOUT_MS,
@@ -10406,7 +9698,7 @@ async function extractTarball(ctx, archivePath, packageDir, packageName) {
10406
9698
  "OldGnuLongPath",
10407
9699
  "OldExtendedHeader"
10408
9700
  ]);
10409
- await mkdir8(packageDir, { recursive: true });
9701
+ await mkdir7(packageDir, { recursive: true });
10410
9702
  const unpack = extract({
10411
9703
  cwd: packageDir,
10412
9704
  strip: 1,
@@ -10485,7 +9777,7 @@ async function readInstalledManifest(packageDir, selected) {
10485
9777
  const info2 = await lstat(packageJsonPath);
10486
9778
  if (!info2.isFile() || info2.isSymbolicLink())
10487
9779
  throw new Error("not a regular file");
10488
- manifest = object2(JSON.parse(await readFile26(packageJsonPath, "utf8")));
9780
+ manifest = object2(JSON.parse(await readFile25(packageJsonPath, "utf8")));
10489
9781
  } catch (error2) {
10490
9782
  throw new SecurityInstallError(`Downloaded ${selected.name}@${selected.version} has no valid package.json (${error2 instanceof Error ? error2.message : String(error2)}).`);
10491
9783
  }
@@ -10494,16 +9786,6 @@ async function readInstalledManifest(packageDir, selected) {
10494
9786
  }
10495
9787
  return manifest;
10496
9788
  }
10497
- async function optionalPackageEntry(packageDir, manifest, condition) {
10498
- try {
10499
- return await resolvePackageEntry(packageDir, manifest, condition);
10500
- } catch (error2) {
10501
- if (error2 instanceof Error && error2.message.includes("no contained JavaScript entry point")) {
10502
- return;
10503
- }
10504
- throw error2;
10505
- }
10506
- }
10507
9789
  function platformAllowed(rule, current) {
10508
9790
  let values;
10509
9791
  if (typeof rule === "string") {
@@ -10528,11 +9810,9 @@ function relativePackagePath(parentPackagePath, name) {
10528
9810
  }
10529
9811
  async function installPackage(ctx, name, selector, parentPackagePath, ancestors, depth, optional) {
10530
9812
  const recordStart = ctx.records.length;
10531
- const skippedStart = ctx.skipped.length;
10532
9813
  const warningsBefore = new Set(ctx.warnings);
10533
9814
  const discardOptionalSubtree = () => {
10534
9815
  ctx.records.splice(recordStart);
10535
- ctx.skipped.splice(skippedStart);
10536
9816
  ctx.warnings = warningsBefore;
10537
9817
  };
10538
9818
  if (depth > ctx.limits.dependencyDepth) {
@@ -10558,39 +9838,35 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
10558
9838
  const packageDir = path16.join(ctx.stageRoot, ...relativePath.split("/"));
10559
9839
  const archivePath = path16.join(ctx.downloadsDir, `${ctx.archiveCounter++}.tgz`);
10560
9840
  try {
10561
- await mkdir8(path16.dirname(packageDir), { recursive: true });
9841
+ await mkdir7(path16.dirname(packageDir), { recursive: true });
10562
9842
  await downloadTarball(ctx, selected, archivePath);
10563
9843
  await extractTarball(ctx, archivePath, packageDir, selected.name);
10564
9844
  const manifest = await readInstalledManifest(packageDir, selected);
10565
9845
  if (!platformAllowed(manifest.os, process.platform) || !platformAllowed(manifest.cpu, process.arch)) {
10566
9846
  const reason = `${name}@${selected.version} does not support ${process.platform}/${process.arch}`;
10567
9847
  if (optional) {
10568
- await rm3(packageDir, { recursive: true, force: true });
9848
+ await rm2(packageDir, { recursive: true, force: true });
10569
9849
  return { skipped: reason };
10570
9850
  }
10571
9851
  throw new PackageUnavailableError(reason);
10572
9852
  }
10573
- const importEntry = await optionalPackageEntry(packageDir, manifest, "import");
10574
- const requireEntry = await optionalPackageEntry(packageDir, manifest, "require");
10575
- if (parentPackagePath === null && !importEntry && !requireEntry) {
10576
- throw new SecurityInstallError(`${name}@${selected.version} has no JavaScript plugin entry.`);
9853
+ if (parentPackagePath === null) {
9854
+ try {
9855
+ await resolvePackageEntry(packageDir, manifest);
9856
+ } catch (cause) {
9857
+ throw new SecurityInstallError(`${name}@${selected.version} has no JavaScript plugin entry.`, { cause });
9858
+ }
10577
9859
  }
10578
9860
  const record = {
10579
9861
  path: relativePath,
10580
9862
  name,
10581
9863
  version: selected.version,
10582
- tarball: selected.tarball,
10583
- integrity: selected.integrity.label,
10584
- legacySha1: selected.integrity.legacySha1,
10585
- ...importEntry ? { entry: `${relativePath}/${importEntry}` } : {},
10586
- ...requireEntry ? { requireEntry: `${relativePath}/${requireEntry}` } : {},
10587
- dependencies: {},
10588
9864
  packageDir,
10589
9865
  manifest
10590
9866
  };
10591
9867
  ctx.records.push(record);
10592
9868
  if (selected.integrity.legacySha1) {
10593
- ctx.warnings.add(`${name}@${selected.version} is an old npm release with only SHA-1 registry integrity. It was accepted for compatibility and recorded as legacy SHA-1 in the vendor receipt.`);
9869
+ ctx.warnings.add(`${name}@${selected.version} is an old npm release with only SHA-1 registry integrity. It was accepted for compatibility.`);
10594
9870
  }
10595
9871
  const dependencies = stringMap(manifest.dependencies);
10596
9872
  const optionalDependencies = stringMap(manifest.optionalDependencies);
@@ -10610,38 +9886,21 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
10610
9886
  const child = await installPackage(ctx, dependency, range, relativePath, nextAncestors, depth + 1, false);
10611
9887
  if (!child.path)
10612
9888
  throw new Error(`Required dependency ${dependency} was unexpectedly skipped.`);
10613
- record.dependencies[dependency] = child.path;
10614
9889
  }
10615
9890
  const optionalEntries = Object.entries(optionalDependencies).sort(([a], [b]) => a.localeCompare(b));
10616
9891
  for (const [dependency, range] of optionalEntries) {
10617
- const child = await installPackage(ctx, dependency, range, relativePath, nextAncestors, depth + 1, true);
10618
- if (child.path)
10619
- record.dependencies[dependency] = child.path;
10620
- else if (child.skipped) {
10621
- ctx.skipped.push({ from: relativePath, name: dependency, selector: range, kind: "optional", reason: child.skipped });
10622
- }
10623
- }
10624
- for (const [dependency, range] of Object.entries(peerDependencies)) {
10625
- if (object2(peerMeta[dependency])?.optional === true) {
10626
- ctx.skipped.push({
10627
- from: relativePath,
10628
- name: dependency,
10629
- selector: range,
10630
- kind: "optional-peer",
10631
- reason: "Optional peer dependencies are not auto-installed."
10632
- });
10633
- }
9892
+ await installPackage(ctx, dependency, range, relativePath, nextAncestors, depth + 1, true);
10634
9893
  }
10635
9894
  return { path: relativePath };
10636
9895
  } catch (error2) {
10637
- await rm3(packageDir, { recursive: true, force: true });
9896
+ await rm2(packageDir, { recursive: true, force: true });
10638
9897
  if (optional && isOptionalAvailabilityError(error2)) {
10639
9898
  discardOptionalSubtree();
10640
9899
  return { skipped: error2 instanceof Error ? error2.message : String(error2) };
10641
9900
  }
10642
9901
  throw error2;
10643
9902
  } finally {
10644
- await rm3(archivePath, { force: true });
9903
+ await rm2(archivePath, { force: true });
10645
9904
  }
10646
9905
  }
10647
9906
  async function ensureDirectory(pathname) {
@@ -10653,14 +9912,14 @@ async function ensureDirectory(pathname) {
10653
9912
  } catch (error2) {
10654
9913
  if (error2.code !== "ENOENT")
10655
9914
  throw error2;
10656
- await mkdir8(pathname);
9915
+ await mkdir7(pathname);
10657
9916
  }
10658
9917
  }
10659
9918
  async function prepareVendorParent(projectDir, name) {
10660
9919
  const plugins = path16.join(projectDir, PLUGINS_DIR);
10661
9920
  const npm = path16.join(plugins, VENDORED_NPM_DIR);
10662
9921
  const packageParent = path16.dirname(vendoredNpmPluginRoot(projectDir, name, "0.0.0"));
10663
- await mkdir8(projectDir, { recursive: true });
9922
+ await mkdir7(projectDir, { recursive: true });
10664
9923
  await ensureDirectory(plugins);
10665
9924
  await ensureDirectory(npm);
10666
9925
  await ensureDirectory(packageParent);
@@ -10673,29 +9932,16 @@ async function prepareVendorParent(projectDir, name) {
10673
9932
  }
10674
9933
  return realNpm;
10675
9934
  }
10676
- function publicReceipt(record) {
10677
- return {
10678
- path: record.path,
10679
- name: record.name,
10680
- version: record.version,
10681
- tarball: record.tarball,
10682
- integrity: record.integrity,
10683
- legacySha1: record.legacySha1,
10684
- ...record.entry ? { entry: record.entry } : {},
10685
- ...record.requireEntry ? { requireEntry: record.requireEntry } : {},
10686
- dependencies: record.dependencies
10687
- };
10688
- }
10689
9935
  async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
10690
9936
  const requestedProjectDir = path16.resolve(projectDirInput);
10691
- await mkdir8(requestedProjectDir, { recursive: true });
9937
+ await mkdir7(requestedProjectDir, { recursive: true });
10692
9938
  const projectDir = await realpath(requestedProjectDir);
10693
9939
  const requested = parseNpmPluginSpec(packageSpec);
10694
9940
  const npmRoot = await prepareVendorParent(projectDir, requested.name);
10695
- const container = await mkdtemp2(path16.join(npmRoot, ".install-"));
9941
+ const container = await mkdtemp(path16.join(npmRoot, ".install-"));
10696
9942
  const stageRoot = path16.join(container, "root");
10697
9943
  const downloadsDir = path16.join(container, "downloads");
10698
- await Promise.all([mkdir8(stageRoot), mkdir8(downloadsDir)]);
9944
+ await Promise.all([mkdir7(stageRoot), mkdir7(downloadsDir)]);
10699
9945
  const ctx = {
10700
9946
  fetch: options.fetch ?? globalThis.fetch,
10701
9947
  signal: options.signal,
@@ -10704,7 +9950,6 @@ async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
10704
9950
  downloadsDir,
10705
9951
  packuments: new Map,
10706
9952
  records: [],
10707
- skipped: [],
10708
9953
  warnings: new Set,
10709
9954
  totalNetworkBytes: 0,
10710
9955
  totalUnpackedBytes: 0,
@@ -10720,34 +9965,6 @@ async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
10720
9965
  const rootRecord = ctx.records.find((record) => record.path === rootResult.path);
10721
9966
  if (!rootRecord)
10722
9967
  throw new Error("Root plugin package is missing from the dependency graph.");
10723
- const importEntry = rootRecord.entry ?? rootRecord.requireEntry;
10724
- if (!importEntry)
10725
- throw new Error("Root plugin package has no recorded JavaScript entry.");
10726
- const importFormat = packageEntryFormat(rootRecord.manifest, importEntry);
10727
- const entry = importFormat === "commonjs" ? rootRecord.requireEntry ?? importEntry : importEntry;
10728
- const format = packageEntryFormat(rootRecord.manifest, entry);
10729
- const tree = await computeVendorTreeDigest(stageRoot);
10730
- const receipt = {
10731
- schemaVersion: VENDOR_RECEIPT_VERSION,
10732
- root: {
10733
- name: rootRecord.name,
10734
- version: rootRecord.version,
10735
- packagePath: rootRecord.path,
10736
- entry,
10737
- format
10738
- },
10739
- packages: ctx.records.map(publicReceipt).sort((a, b) => a.path.localeCompare(b.path)),
10740
- skipped: ctx.skipped,
10741
- tree: { algorithm: "sha256", ...tree }
10742
- };
10743
- const receiptFile = await open2(path16.join(stageRoot, VENDOR_RECEIPT_FILE), "wx");
10744
- try {
10745
- await receiptFile.writeFile(`${JSON.stringify(receipt, null, 2)}
10746
- `, "utf8");
10747
- await receiptFile.sync();
10748
- } finally {
10749
- await receiptFile.close();
10750
- }
10751
9968
  finalRoot = vendoredNpmPluginRoot(projectDir, rootRecord.name, rootRecord.version);
10752
9969
  const realFinalParent = await realpath(path16.dirname(finalRoot));
10753
9970
  if (!isContained(projectDir, realFinalParent)) {
@@ -10781,16 +9998,16 @@ async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
10781
9998
  warnings: [...ctx.warnings]
10782
9999
  };
10783
10000
  } finally {
10784
- await rm3(container, { recursive: true, force: true }).catch(() => {});
10001
+ await rm2(container, { recursive: true, force: true }).catch(() => {});
10785
10002
  }
10786
10003
  }
10787
10004
  async function finalizeNpmPluginInstall(installed) {
10788
10005
  if (installed.backupRoot) {
10789
- await rm3(installed.backupRoot, { recursive: true, force: true });
10006
+ await rm2(installed.backupRoot, { recursive: true, force: true });
10790
10007
  }
10791
10008
  }
10792
10009
  async function rollbackNpmPluginInstall(installed) {
10793
- await rm3(installed.installRoot, { recursive: true, force: true });
10010
+ await rm2(installed.installRoot, { recursive: true, force: true });
10794
10011
  if (installed.backupRoot)
10795
10012
  await rename2(installed.backupRoot, installed.installRoot);
10796
10013
  }
@@ -11066,11 +10283,10 @@ async function removeExtension(projectDir, use) {
11066
10283
  return;
11067
10284
  }
11068
10285
  if (parsed.kind === "npm" && parsed.version) {
11069
- await rm4(vendoredNpmPluginRoot(projectDir, parsed.name, parsed.version), {
10286
+ await rm3(vendoredNpmPluginRoot(projectDir, parsed.name, parsed.version), {
11070
10287
  recursive: true,
11071
10288
  force: true
11072
10289
  });
11073
- clearVendoredPluginResolver(projectDir, parsed.name, parsed.version);
11074
10290
  }
11075
10291
  });
11076
10292
  }
@@ -11152,7 +10368,6 @@ async function addExtensionUnlocked(projectDir, specifier, options) {
11152
10368
  } catch (cause) {
11153
10369
  try {
11154
10370
  await rollbackNpmPluginInstall(installed);
11155
- clearVendoredPluginResolver(projectDir, installed.name, installed.version);
11156
10371
  } catch (rollbackError) {
11157
10372
  throw new Error(`Extension install failed and its previous vendor tree could not be restored: ` + `${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`, { cause });
11158
10373
  }
@@ -11181,8 +10396,8 @@ async function addBuiltInStyleSet(projectDir, id) {
11181
10396
  const dest = path17.join(projectDir, EXTENSIONS_DIR, id);
11182
10397
  if (!existsSync12(dest)) {
11183
10398
  const src = path17.join(await getAssetsDir(), "themes", id);
11184
- await mkdir9(path17.dirname(dest), { recursive: true });
11185
- await cp3(src, dest, { recursive: true });
10399
+ await mkdir8(path17.dirname(dest), { recursive: true });
10400
+ await cp2(src, dest, { recursive: true });
11186
10401
  }
11187
10402
  return addExtensionUnlocked(projectDir, `./${EXTENSIONS_DIR}/${id}`, {});
11188
10403
  });
@@ -11190,8 +10405,8 @@ async function addBuiltInStyleSet(projectDir, id) {
11190
10405
 
11191
10406
  // src/lib/extension-import.ts
11192
10407
  import { existsSync as existsSync13 } from "node:fs";
11193
- import { cp as cp4, mkdir as mkdir10, mkdtemp as mkdtemp3, readFile as readFile28, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
11194
- import { tmpdir as tmpdir3 } from "node:os";
10408
+ import { cp as cp3, mkdir as mkdir9, mkdtemp as mkdtemp2, readFile as readFile27, rm as rm4, writeFile as writeFile7 } from "node:fs/promises";
10409
+ import { tmpdir as tmpdir2 } from "node:os";
11195
10410
  import path18 from "node:path";
11196
10411
  import { unzipSync } from "fflate";
11197
10412
  var MAX_THEME_ARCHIVE_BYTES = 25 * 1024 * 1024;
@@ -11263,7 +10478,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11263
10478
  if (!existsSync13(cssPath)) {
11264
10479
  throw new Error("A theme must contain a theme.css file.");
11265
10480
  }
11266
- const css = await readFile28(cssPath, "utf8");
10481
+ const css = await readFile27(cssPath, "utf8");
11267
10482
  const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
11268
10483
  if (reject) {
11269
10484
  throw new Error(`theme.css could not be parsed — ${reject.message}`);
@@ -11291,7 +10506,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11291
10506
  for (let i = 0;i < extraSheets.length; i++) {
11292
10507
  const rel = extraSheets[i];
11293
10508
  const sheetPath = extraSheetPaths[i];
11294
- const sheetCss = await readFile28(sheetPath, "utf8");
10509
+ const sheetCss = await readFile27(sheetPath, "utf8");
11295
10510
  const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
11296
10511
  if (sheetReject) {
11297
10512
  throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
@@ -11311,8 +10526,8 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11311
10526
  }
11312
10527
  const id = await uniqueExtensionId(projectDir, meta.name?.trim() || fallbackName);
11313
10528
  const dest = path18.join(projectDir, EXTENSIONS_DIR, id);
11314
- await mkdir10(path18.dirname(dest), { recursive: true });
11315
- await cp4(sourceDir, dest, { recursive: true });
10529
+ await mkdir9(path18.dirname(dest), { recursive: true });
10530
+ await cp3(sourceDir, dest, { recursive: true });
11316
10531
  await completeLandedManifest(dest, id, meta, metaExists);
11317
10532
  const entry = await addExtension(projectDir, `./${EXTENSIONS_DIR}/${id}`);
11318
10533
  return { entry, warnings };
@@ -11324,14 +10539,14 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
11324
10539
  let pkg = {};
11325
10540
  if (metaExists) {
11326
10541
  try {
11327
- const parsed = JSON.parse(await readFile28(file, "utf8"));
10542
+ const parsed = JSON.parse(await readFile27(file, "utf8"));
11328
10543
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
11329
10544
  pkg = parsed;
11330
10545
  }
11331
10546
  } catch {}
11332
10547
  }
11333
10548
  const gutterpress = pkg.gutterpress && typeof pkg.gutterpress === "object" && !Array.isArray(pkg.gutterpress) ? pkg.gutterpress : {};
11334
- await writeFile8(file, JSON.stringify({
10549
+ await writeFile7(file, JSON.stringify({
11335
10550
  ...pkg,
11336
10551
  name: typeof pkg.name === "string" && pkg.name.trim() ? pkg.name : id,
11337
10552
  gutterpress: { ...gutterpress, styles: ["theme.css"] }
@@ -11378,7 +10593,7 @@ async function importExtensionFromZip(projectDir, archive) {
11378
10593
  throw new Error("No theme.css found in the package. A theme needs a theme.css at the package root or inside a single folder.");
11379
10594
  }
11380
10595
  const prefix = root === "" ? "" : `${root}/`;
11381
- const tmp = await mkdtemp3(path18.join(tmpdir3(), "gutterpress-theme-"));
10596
+ const tmp = await mkdtemp2(path18.join(tmpdir2(), "gutterpress-theme-"));
11382
10597
  try {
11383
10598
  const relPaths = [];
11384
10599
  for (const [name, data] of Object.entries(files)) {
@@ -11395,12 +10610,12 @@ async function importExtensionFromZip(projectDir, archive) {
11395
10610
  throw new Error(`The package contains an unsafe path and was rejected: ${name}`);
11396
10611
  }
11397
10612
  relPaths.push(rel);
11398
- await mkdir10(path18.dirname(dest), { recursive: true });
11399
- await writeFile8(dest, data);
10613
+ await mkdir9(path18.dirname(dest), { recursive: true });
10614
+ await writeFile7(dest, data);
11400
10615
  }
11401
10616
  return await finalizeExtensionImport(projectDir, tmp, relPaths, root || "imported-look");
11402
10617
  } finally {
11403
- await rm5(tmp, { recursive: true, force: true });
10618
+ await rm4(tmp, { recursive: true, force: true });
11404
10619
  }
11405
10620
  }
11406
10621
  async function importExtensionFromCssText(projectDir, css, name) {
@@ -11409,10 +10624,10 @@ async function importExtensionFromCssText(projectDir, css, name) {
11409
10624
  throw new Error(`The CSS could not be parsed — ${reject.message}`);
11410
10625
  }
11411
10626
  const displayName = name.trim() || "Imported theme";
11412
- const tmp = await mkdtemp3(path18.join(tmpdir3(), "gutterpress-theme-"));
10627
+ const tmp = await mkdtemp2(path18.join(tmpdir2(), "gutterpress-theme-"));
11413
10628
  try {
11414
- await writeFile8(path18.join(tmp, "theme.css"), css, "utf8");
11415
- await writeFile8(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
10629
+ await writeFile7(path18.join(tmp, "theme.css"), css, "utf8");
10630
+ await writeFile7(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
11416
10631
  const result = await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], displayName);
11417
10632
  result.warnings.unshift({
11418
10633
  code: "no-theme-json",
@@ -11420,17 +10635,17 @@ async function importExtensionFromCssText(projectDir, css, name) {
11420
10635
  });
11421
10636
  return result;
11422
10637
  } finally {
11423
- await rm5(tmp, { recursive: true, force: true });
10638
+ await rm4(tmp, { recursive: true, force: true });
11424
10639
  }
11425
10640
  }
11426
10641
  async function importExtensionFromFile(projectDir, filePath) {
11427
10642
  const ext = path18.extname(filePath).toLowerCase();
11428
10643
  if (ext === ".zip") {
11429
- const buf = await readFile28(filePath);
10644
+ const buf = await readFile27(filePath);
11430
10645
  return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
11431
10646
  }
11432
10647
  if (ext === ".css") {
11433
- const css = await readFile28(filePath, "utf8");
10648
+ const css = await readFile27(filePath, "utf8");
11434
10649
  return importExtensionFromCssText(projectDir, css, prettify(path18.basename(filePath, ".css")));
11435
10650
  }
11436
10651
  throw new Error("Choose a .zip extension package or a .css stylesheet.");
@@ -11493,9 +10708,9 @@ async function importExtensionFromUrl(projectDir, url) {
11493
10708
  if (!css.trim())
11494
10709
  throw new Error(`Fetched CSS from ${trimmed} was empty.`);
11495
10710
  assertLooksLikeCss(css, trimmed);
11496
- const tmp = await mkdtemp3(path18.join(tmpdir3(), "gutterpress-ext-"));
10711
+ const tmp = await mkdtemp2(path18.join(tmpdir2(), "gutterpress-ext-"));
11497
10712
  try {
11498
- await writeFile8(path18.join(tmp, "theme.css"), css, "utf8");
10713
+ await writeFile7(path18.join(tmp, "theme.css"), css, "utf8");
11499
10714
  const gp = meta.gutterpress && typeof meta.gutterpress === "object" && !Array.isArray(meta.gutterpress) ? meta.gutterpress : {};
11500
10715
  const finalMeta = {
11501
10716
  name: typeof meta.name === "string" && meta.name || slugify(baseName, "look"),
@@ -11507,10 +10722,10 @@ async function importExtensionFromUrl(projectDir, url) {
11507
10722
  preview: typeof gp.preview === "string" ? gp.preview : null
11508
10723
  }
11509
10724
  };
11510
- await writeFile8(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
10725
+ await writeFile7(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
11511
10726
  return await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], baseName);
11512
10727
  } finally {
11513
- await rm5(tmp, { recursive: true, force: true });
10728
+ await rm4(tmp, { recursive: true, force: true });
11514
10729
  }
11515
10730
  }
11516
10731
 
@@ -12133,11 +11348,11 @@ ${tail}` : ""}`);
12133
11348
  };
12134
11349
 
12135
11350
  // src/lib/publish/providers/guided.ts
12136
- import { copyFile as copyFile2, mkdir as mkdir11, writeFile as writeFile9 } from "node:fs/promises";
11351
+ import { copyFile as copyFile2, mkdir as mkdir10, writeFile as writeFile8 } from "node:fs/promises";
12137
11352
  import path19 from "node:path";
12138
11353
  async function stageGuidedPackage(req, providerId, listingLines) {
12139
11354
  const packageDir = path19.join(path19.dirname(req.artifact.path), "publish", providerId);
12140
- await mkdir11(packageDir, { recursive: true });
11355
+ await mkdir10(packageDir, { recursive: true });
12141
11356
  await copyFile2(req.artifact.path, path19.join(packageDir, path19.basename(req.artifact.path)));
12142
11357
  const { title, authors } = req.project;
12143
11358
  const sheet = [
@@ -12151,7 +11366,7 @@ async function stageGuidedPackage(req, providerId, listingLines) {
12151
11366
  ""
12152
11367
  ].join(`
12153
11368
  `);
12154
- await writeFile9(path19.join(packageDir, "LISTING.md"), sheet, "utf8");
11369
+ await writeFile8(path19.join(packageDir, "LISTING.md"), sheet, "utf8");
12155
11370
  return packageDir;
12156
11371
  }
12157
11372
 
@@ -12214,8 +11429,8 @@ var drivethrurpgProvider = {
12214
11429
  };
12215
11430
 
12216
11431
  // src/lib/publish/providers/gdrive.ts
12217
- import { mkdtemp as mkdtemp4, readFile as readFile29, readdir as readdir5, rm as rm6, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
12218
- import { tmpdir as tmpdir4 } from "node:os";
11432
+ import { mkdtemp as mkdtemp3, readFile as readFile28, readdir as readdir5, rm as rm5, stat as stat7, writeFile as writeFile9 } from "node:fs/promises";
11433
+ import { tmpdir as tmpdir3 } from "node:os";
12219
11434
  import path20 from "node:path";
12220
11435
  import { Zip, ZipDeflate } from "fflate";
12221
11436
 
@@ -12606,12 +11821,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
12606
11821
  await collectZipEntries(root, full, out, onWarn);
12607
11822
  } else if (entry.isFile()) {
12608
11823
  const rel = path20.relative(root, full).split(path20.sep).join("/");
12609
- out[rel] = await readFile29(full);
11824
+ out[rel] = await readFile28(full);
12610
11825
  } else if (entry.isSymbolicLink()) {
12611
11826
  const resolved = await stat7(full).catch(() => null);
12612
11827
  if (resolved?.isFile()) {
12613
11828
  const rel = path20.relative(root, full).split(path20.sep).join("/");
12614
- out[rel] = await readFile29(full);
11829
+ out[rel] = await readFile28(full);
12615
11830
  } else if (resolved?.isDirectory()) {
12616
11831
  await collectZipEntries(root, full, out, onWarn);
12617
11832
  } else {
@@ -12622,11 +11837,11 @@ async function collectZipEntries(root, dir, out, onWarn) {
12622
11837
  }
12623
11838
  }
12624
11839
  }
12625
- async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile10) {
11840
+ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile9) {
12626
11841
  const entries = {};
12627
11842
  await collectZipEntries(exportDir, exportDir, entries, onWarn);
12628
11843
  const fileName = `${bookSlug(title)}-website.zip`;
12629
- const tmpRoot = await mkdtemp4(path20.join(tmpdir4(), "gutterpress-gdrive-"));
11844
+ const tmpRoot = await mkdtemp3(path20.join(tmpdir3(), "gutterpress-gdrive-"));
12630
11845
  try {
12631
11846
  const filePath = path20.join(tmpRoot, fileName);
12632
11847
  const zipped = await zipEntriesNonBlocking(entries, { level: 6 });
@@ -12635,10 +11850,10 @@ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeF
12635
11850
  filePath,
12636
11851
  fileName,
12637
11852
  mimeType: "application/zip",
12638
- cleanup: () => rm6(tmpRoot, { recursive: true, force: true })
11853
+ cleanup: () => rm5(tmpRoot, { recursive: true, force: true })
12639
11854
  };
12640
11855
  } catch (e) {
12641
- await rm6(tmpRoot, { recursive: true, force: true }).catch(() => {});
11856
+ await rm5(tmpRoot, { recursive: true, force: true }).catch(() => {});
12642
11857
  throw e;
12643
11858
  }
12644
11859
  }
@@ -12726,7 +11941,7 @@ var gdriveProvider = {
12726
11941
  };
12727
11942
 
12728
11943
  // src/lib/publish/butler.ts
12729
- import { chmod, mkdir as mkdir12, stat as stat8, writeFile as writeFile11 } from "node:fs/promises";
11944
+ import { chmod, mkdir as mkdir11, stat as stat8, writeFile as writeFile10 } from "node:fs/promises";
12730
11945
  import path21 from "node:path";
12731
11946
  import { unzipSync as unzipSync2 } from "fflate";
12732
11947
  var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
@@ -12787,13 +12002,13 @@ async function ensureButler(deps) {
12787
12002
  return new Uint8Array(await response.arrayBuffer());
12788
12003
  });
12789
12004
  const files = unzipSync2(archive);
12790
- await mkdir12(cacheDir, { recursive: true });
12005
+ await mkdir11(cacheDir, { recursive: true });
12791
12006
  let foundBinary = false;
12792
12007
  for (const [name, data] of Object.entries(files)) {
12793
12008
  if (name.endsWith("/"))
12794
12009
  continue;
12795
12010
  const target = path21.join(cacheDir, path21.basename(name));
12796
- await writeFile11(target, data);
12011
+ await writeFile10(target, data);
12797
12012
  if (path21.basename(name) === butlerBinaryName()) {
12798
12013
  await chmod(target, 493).catch(() => {});
12799
12014
  foundBinary = true;
@@ -12990,7 +12205,7 @@ var kdpProvider = {
12990
12205
  };
12991
12206
 
12992
12207
  // src/lib/publish/providers/local-folder.ts
12993
- import { cp as cp5, mkdir as mkdir13, stat as stat9 } from "node:fs/promises";
12208
+ import { cp as cp4, mkdir as mkdir12, stat as stat9 } from "node:fs/promises";
12994
12209
  import path22 from "node:path";
12995
12210
  var LOCAL_PUBLISH_DEFAULT_DIR = "dist";
12996
12211
  var info7 = {
@@ -13028,10 +12243,10 @@ var localFolderProvider = {
13028
12243
  },
13029
12244
  async upload(req) {
13030
12245
  const dir = localPublishDir(req);
13031
- await mkdir13(dir, { recursive: true });
12246
+ await mkdir12(dir, { recursive: true });
13032
12247
  const dest = req.artifact.format === "html" ? dir : path22.join(dir, path22.basename(req.artifact.path));
13033
12248
  if (path22.resolve(dest) !== path22.resolve(req.artifact.path)) {
13034
- await cp5(req.artifact.path, dest, { recursive: true });
12249
+ await cp4(req.artifact.path, dest, { recursive: true });
13035
12250
  }
13036
12251
  return { kind: "published", detail: `Saved to ${dest}` };
13037
12252
  }
@@ -13595,7 +12810,7 @@ import git7 from "isomorphic-git";
13595
12810
  // src/lib/remote-auth/scorched-earth.ts
13596
12811
  import git8 from "isomorphic-git";
13597
12812
  // src/lib/publish/selections.ts
13598
- import { chmod as chmod2, mkdir as mkdir14, readFile as readFile30, writeFile as writeFile12 } from "node:fs/promises";
12813
+ import { chmod as chmod2, mkdir as mkdir13, readFile as readFile29, writeFile as writeFile11 } from "node:fs/promises";
13599
12814
  import path24 from "node:path";
13600
12815
  class PublishSelectionsStore {
13601
12816
  filePath;
@@ -13605,7 +12820,7 @@ class PublishSelectionsStore {
13605
12820
  }
13606
12821
  async read() {
13607
12822
  try {
13608
- const raw = await readFile30(this.filePath, "utf8");
12823
+ const raw = await readFile29(this.filePath, "utf8");
13609
12824
  const parsed = JSON.parse(raw);
13610
12825
  if (parsed && typeof parsed === "object") {
13611
12826
  return {
@@ -13618,8 +12833,8 @@ class PublishSelectionsStore {
13618
12833
  return { version: 1, global: {}, projects: {} };
13619
12834
  }
13620
12835
  async write(data) {
13621
- await mkdir14(path24.dirname(this.filePath), { recursive: true });
13622
- await writeFile12(this.filePath, JSON.stringify(data, null, 2), {
12836
+ await mkdir13(path24.dirname(this.filePath), { recursive: true });
12837
+ await writeFile11(this.filePath, JSON.stringify(data, null, 2), {
13623
12838
  encoding: "utf8",
13624
12839
  mode: 384
13625
12840
  });
@@ -13684,78 +12899,4 @@ function normalizeProjectKey(projectDir) {
13684
12899
  }
13685
12900
  // src/lib/publish/manifest-publish.ts
13686
12901
  import { isMap as isMap4 } from "yaml";
13687
- // src/lib/lint-runner.ts
13688
- import { resolve as resolve8 } from "node:path";
13689
- import { readFile as readFile31 } from "node:fs/promises";
13690
- async function runLint(opts = {}) {
13691
- const { glob } = await import("glob");
13692
- const { manifest, manifestDir } = await loadManifestWithPath(opts.manifest, {
13693
- explicit: opts.manifest !== undefined
13694
- });
13695
- const resolved = resolveConfig({}, manifest);
13696
- let files;
13697
- if (opts.files) {
13698
- files = await glob([opts.files], { nodir: true, ignore: ["**/*.min.css"] });
13699
- } else {
13700
- const relStyles = await resolveActiveStyles(manifestDir, resolved.styles);
13701
- const projectFiles = relStyles.map((rel) => resolve8(manifestDir, rel));
13702
- let pluginStylePaths = opts.pluginStylePaths;
13703
- if (pluginStylePaths === undefined) {
13704
- ({ pluginStylePaths } = await loadPluginsWithCss(resolved.extensions, manifestDir, (ref, err) => log.warn(`Skipping plugin "${ref}" for lint — ${err.message}`)));
13705
- }
13706
- files = [...projectFiles, ...pluginStylePaths].filter((f) => !f.endsWith(".min.css"));
13707
- }
13708
- if (files.length === 0) {
13709
- log.warn("No CSS files found to lint");
13710
- return { ok: true, riskyCount: 0, containmentCount: 0, filesLinted: 0 };
13711
- }
13712
- log.info(`Linting ${files.length} CSS file(s)`);
13713
- let errorCount = 0;
13714
- let riskyCount = 0;
13715
- let containmentCount = 0;
13716
- let linted = 0;
13717
- for (const file of files) {
13718
- let css;
13719
- try {
13720
- css = await readFile31(file, "utf8");
13721
- } catch (err) {
13722
- log.error(` ${file}`);
13723
- log.error(` cannot read stylesheet: ${err instanceof Error ? err.message : String(err)}`);
13724
- errorCount++;
13725
- continue;
13726
- }
13727
- linted++;
13728
- const warnings = checkCss(css, file);
13729
- const errors = warnings.filter((w) => w.severity === "error");
13730
- const risky = warnings.filter((w) => w.rule === ruleRiskyProps);
13731
- const containment = warnings.filter((w) => w.rule === rulePageContainment);
13732
- riskyCount += risky.length;
13733
- containmentCount += containment.length;
13734
- if (errors.length > 0) {
13735
- log.error(` ${file}`);
13736
- for (const w of errors) {
13737
- log.error(` ${w.line}:${w.column} ${w.message} (${w.rule})`);
13738
- }
13739
- errorCount += errors.length;
13740
- }
13741
- const nonErrorWarnings = [...risky, ...containment].sort((a, b) => a.line - b.line);
13742
- if (nonErrorWarnings.length > 0) {
13743
- log.warn(` ${file}`);
13744
- for (const w of nonErrorWarnings) {
13745
- log.warn(` ${w.line}:${w.column} ${w.message} (${w.rule})`);
13746
- }
13747
- }
13748
- }
13749
- if (errorCount > 0) {
13750
- log.error("CSS lint errors found");
13751
- return { ok: false, riskyCount, containmentCount, filesLinted: linted };
13752
- }
13753
- const totalWarnings = riskyCount + containmentCount;
13754
- if (totalWarnings > 0) {
13755
- log.warn(`${totalWarnings} print-safety warning(s): ${riskyCount} risky effect(s), ${containmentCount} page-containment`);
13756
- } else {
13757
- log.success("CSS lint passed");
13758
- }
13759
- return { ok: true, riskyCount, containmentCount, filesLinted: linted };
13760
- }
13761
- export { isPathSpecifier, parseExtensionSpecifier, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, MANIFEST_FILENAMES, loadManifestWithPath, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, scaffoldProject, EXTENSION_KINDS, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, BUILT_IN_STYLE_SET_IDS, listProjectExtensions, setExtensionEnabled, removeExtension, addExtension, addBuiltInStyleSet, importExtensionFromFile, importExtensionFromUrl, searchNpmExtensions, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listPublishProviders, publishProviderFor, resolvePublishFormat, runPublish, connectPublishProvider, disconnectPublishCredential, runLint };
12902
+ export { isPathSpecifier, parseExtensionSpecifier, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, loadManifestWithPath, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, scaffoldProject, EXTENSION_KINDS, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, BUILT_IN_STYLE_SET_IDS, listProjectExtensions, setExtensionEnabled, removeExtension, addExtension, addBuiltInStyleSet, importExtensionFromFile, importExtensionFromUrl, searchNpmExtensions, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listPublishProviders, publishProviderFor, resolvePublishFormat, runPublish, connectPublishProvider, disconnectPublishCredential };