gutterpress 0.11.23-alpha.2 → 0.11.23-alpha.3

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 (55) hide show
  1. package/README.md +6 -7
  2. package/dist/{README-8ef336pp.md → README-8db7btxb.md} +13 -19
  3. package/dist/api/index.d.ts +1 -1
  4. package/dist/api/index.js +4 -4
  5. package/dist/{build-encgnv0c.js → build-m78jcpf7.js} +7 -7
  6. package/dist/{cli-xq6djqbj.js → cli-1h17ktsg.js} +84 -113
  7. package/dist/{cli-kh8v4vvw.js → cli-5jzyw06s.js} +1 -1
  8. package/dist/{cli-sdmv4bba.js → cli-h4x81x97.js} +112 -8
  9. package/dist/{cli-evg8sbht.js → cli-n2tsxqpn.js} +1 -1
  10. package/dist/{cli-aqh6brew.js → cli-s6djx4ma.js} +1 -1
  11. package/dist/{cli-pwwfxdgb.js → cli-t8be9yeb.js} +9 -20
  12. package/dist/{cli-pz4bn98t.js → cli-xsrffqzt.js} +19 -13
  13. package/dist/cli.js +12 -12
  14. package/dist/{doctor-5gtpgpd1.js → doctor-j71jqce3.js} +3 -3
  15. package/dist/engine/shared/gcpm-extract.d.ts +8 -0
  16. package/dist/engine/shared/print-area.d.ts +16 -4
  17. package/dist/{engine-tn13gk0b.js → engine-1r6q80tq.js} +2 -2
  18. package/dist/{engine-mc5br8g8.js → engine-m4y10shc.js} +1 -1
  19. package/dist/{ext-wn2a5afq.js → ext-fq2hg9va.js} +7 -7
  20. package/dist/{extension-restore-s3x1618g.js → extension-restore-9dh7c4tp.js} +2 -2
  21. package/dist/{extension-restore-g8jnmmzq.js → extension-restore-tmxtzkm0.js} +4 -4
  22. package/dist/{gutterpress-viewer-701vf4qp.js → gutterpress-viewer-mafsby5k.js} +9 -2
  23. package/dist/{index-2bjcghze.js → index-0wee4408.js} +9 -20
  24. package/dist/{index-x3ema2w3.js → index-7pck1q9c.js} +124 -17
  25. package/dist/{index-0skhjx3e.js → index-nedd07bk.js} +19 -13
  26. package/dist/{index-4x6y8krm.js → index-nvmf22rt.js} +1 -1
  27. package/dist/{index-j5z86r4a.js → index-prqvz3xm.js} +213 -276
  28. package/dist/index.js +5 -5
  29. package/dist/lib/extension-manager.d.ts +8 -7
  30. package/dist/lib/extension-manifest.d.ts +1 -13
  31. package/dist/lib/manifest.d.ts +15 -1
  32. package/dist/lib/markdown/assemble.d.ts +4 -3
  33. package/dist/lib/page-size.d.ts +34 -27
  34. package/dist/lib/printsafe.d.ts +1 -0
  35. package/dist/lib/project-templates.d.ts +9 -0
  36. package/dist/manifest-8afhrk30.yaml +19 -0
  37. package/dist/manifest-d4f9q79e.yaml +23 -0
  38. package/dist/{manifest-eagfhba6.yaml → manifest-gf13sjp8.yaml} +10 -2
  39. package/dist/manifest-my7mdv8j.yaml +23 -0
  40. package/dist/{manifest.schema-t7nx2stg.json → manifest.schema-650pe0d1.json} +15 -3
  41. package/dist/{new-mhs46pw3.js → new-s4zcaepg.js} +7 -7
  42. package/dist/{package-aenwjew3.json → package-awwkt7sa.json} +0 -1
  43. package/dist/{page-rules-nsj3aw42.css → page-rules-fj09xct5.css} +12 -40
  44. package/dist/{plugin.test.js-xgxrd8hf.tpl → plugin.test.js-gxzqqfdh.tpl} +0 -1
  45. package/dist/{plugins-1sxe0dkz.js → plugins-4vaf27n9.js} +3 -3
  46. package/dist/{plugins-2cek4mz1.js → plugins-80emnf31.js} +1 -1
  47. package/dist/{preflight-3k2b1x8e.js → preflight-c7w1xdn3.js} +7 -7
  48. package/dist/{preview-6p9v6rht.js → preview-mzytcwyk.js} +7 -7
  49. package/dist/{publish-qgsngy8s.js → publish-fez14ad4.js} +7 -7
  50. package/dist/render.js +24 -561
  51. package/dist/schema/manifest.types.d.ts +22 -0
  52. package/dist/{tokens-7984461t.css → tokens-ye64p899.css} +5 -12
  53. package/dist/{validate-0v7xw6wa.js → validate-p2chr6hr.js} +7 -7
  54. package/package.json +1 -1
  55. package/dist/manifest-n1gh3qw5.yaml +0 -9
@@ -2,6 +2,7 @@ import {
2
2
  DEBOUNCE,
3
3
  FriendlyHttpError,
4
4
  MANIFEST_FILENAMES,
5
+ MARGIN_EDGES,
5
6
  PRESETS,
6
7
  PRESET_IDS,
7
8
  TARGETS,
@@ -9,25 +10,34 @@ import {
9
10
  UsageError,
10
11
  addExtension,
11
12
  applyDefaultPdfStrictChecks,
13
+ cssLength,
12
14
  ensureProjectGitignore,
13
- ensureSeq,
14
15
  extensionConfigFor,
16
+ formatPageSize,
17
+ isNonNegativePoints,
18
+ isPositivePoints,
19
+ judgeRect,
15
20
  listProjectExtensions,
16
21
  loadManifest,
17
22
  loadManifestDoc,
18
23
  loadManifestWithPath,
19
24
  npmRegistryUrl,
25
+ pageBoxes,
26
+ printAreaMeta,
20
27
  publishTargetFor,
28
+ readEntryCss,
21
29
  resolveConfig,
22
30
  resolveConfigForTarget,
23
31
  resolvePort,
24
32
  resolveTargets,
25
33
  restoreForCommand,
34
+ round3,
26
35
  scalarString,
27
36
  uniqueExtensionId,
37
+ validatePageMargin,
28
38
  withFetchTimeout,
29
39
  writeManifestDoc
30
- } from "./index-x3ema2w3.js";
40
+ } from "./index-7pck1q9c.js";
31
41
  import {
32
42
  EXTENSION_MANIFEST_FILENAME,
33
43
  GUTTERPRESS_CSS,
@@ -63,18 +73,18 @@ import {
63
73
  setLogLevel,
64
74
  slugify,
65
75
  warn
66
- } from "./index-2bjcghze.js";
76
+ } from "./index-0wee4408.js";
67
77
  import {
68
78
  blackTextToGray
69
79
  } from "./index-ht1bcqdd.js";
70
80
  import {
81
+ DEFAULT_PAGE_MARGIN_PT,
71
82
  MARGIN_BOX_IGNORED_PROPERTIES,
72
83
  extract,
73
84
  getAssetPath,
74
85
  lastPageMode,
75
- parseSize,
76
86
  resolvePage
77
- } from "./index-0skhjx3e.js";
87
+ } from "./index-nedd07bk.js";
78
88
  import {
79
89
  BuildError
80
90
  } from "./index-46ycxe6r.js";
@@ -185,95 +195,26 @@ function canonicalChapterId(p) {
185
195
  return s;
186
196
  }
187
197
 
188
- // src/engine/shared/print-area.ts
189
- function isPositivePoints(value) {
190
- return typeof value === "number" && Number.isFinite(value) && value > 0;
191
- }
192
- var round3 = (n) => Math.round(n * 1000) / 1000;
193
- function cssLength(pt) {
194
- const inches = round3(pt / 72);
195
- return Math.abs(inches * 72 - pt) < 0.000001 ? `${inches}in` : `${round3(pt)}pt`;
196
- }
197
- function formatPageSize(page) {
198
- return `${cssLength(page.width)} ${cssLength(page.height)}`;
199
- }
200
- function printAreaMeta(page) {
201
- const area = JSON.stringify({
202
- width: page.width,
203
- height: page.height,
204
- bleed: page.bleed ?? 0,
205
- safe: page.safe ?? 0,
206
- artSafe: page.artSafe,
207
- gutter: page.gutter,
208
- preset: page.preset,
209
- spec: page.spec
210
- });
211
- return `<meta name="gp-print-area" content='${area.replace(/&/g, "&amp;").replace(/'/g, "&#39;")}'>`;
212
- }
213
- function pageBoxes(area, side, scale = 1) {
214
- const w = area.width * scale;
215
- const h = area.height * scale;
216
- const b = Math.max(0, area.bleed) * scale;
217
- const s = Math.max(0, area.safe) * scale;
218
- const a = Math.max(0, area.artSafe) * scale;
219
- const g = Math.max(0, area.gutter) * scale;
220
- const [textLeft, textRight] = side === "verso" ? [s, g] : [g, s];
221
- const [artLeft, artRight] = side === "verso" ? [a, g] : [g, a];
222
- const trim = { x: side === "verso" ? b : 0, y: b, w: Math.max(0, w - b), h: Math.max(0, h - 2 * b) };
223
- return {
224
- sheet: { x: 0, y: 0, w, h },
225
- trim,
226
- safe: {
227
- x: trim.x + textLeft,
228
- y: trim.y + s,
229
- w: Math.max(0, trim.w - textLeft - textRight),
230
- h: Math.max(0, trim.h - 2 * s)
231
- },
232
- safeArt: {
233
- x: trim.x + artLeft,
234
- y: trim.y + a,
235
- w: Math.max(0, trim.w - artLeft - artRight),
236
- h: Math.max(0, trim.h - 2 * a)
237
- },
238
- bleed: b
239
- };
240
- }
241
- var SEVERITY = { inside: 0, unsafe: 1, bleed: 2, "off-page": 3 };
242
- function judgeRect(r, boxes, rule, tol = 0) {
243
- const { sheet, trim } = boxes;
244
- const safe = rule === "art" ? boxes.safeArt : boxes.safe;
245
- const sides = [
246
- ["left", -r.x, -safe.x, -trim.x, -sheet.x],
247
- ["right", r.x + r.w, safe.x + safe.w, trim.x + trim.w, sheet.x + sheet.w],
248
- ["top", -r.y, -safe.y, -trim.y, -sheet.y],
249
- ["bottom", r.y + r.h, safe.y + safe.h, trim.y + trim.h, sheet.y + sheet.h]
250
- ];
251
- let worst = { kind: "inside", gap: 0, need: 0, edge: null };
252
- let beyond = 0;
253
- for (const [edge, ink, limit, trimEdge, sheetEdge] of sides) {
254
- const past = ink - limit;
255
- if (past <= tol || rule === "art" && ink >= sheetEdge - tol)
256
- continue;
257
- const kind = ink > sheetEdge + tol ? "off-page" : ink > trimEdge + tol ? "bleed" : "unsafe";
258
- if (SEVERITY[kind] > SEVERITY[worst.kind] || kind === worst.kind && past > beyond) {
259
- worst = { kind, gap: trimEdge - ink, need: trimEdge - limit, edge };
260
- beyond = past;
261
- }
262
- }
263
- return worst;
264
- }
265
-
266
198
  // src/lib/markdown/assemble.ts
267
- function defaultPageSizeCss(css, page) {
199
+ function pageGeometryCss(page) {
268
200
  if (!page || !isPositivePoints(page.width) || !isPositivePoints(page.height))
269
201
  return null;
270
- try {
271
- if (resolvePage(extract(css)).decls.size !== undefined)
272
- return null;
273
- } catch {
202
+ const size = `size: ${formatPageSize(page)};`;
203
+ const m = page.margin;
204
+ if (!m)
205
+ return `@page { ${size} }`;
206
+ const [top, bottom, inside, outside] = [m.top, m.bottom, m.inside, m.outside].map(cssLength);
207
+ const recto = `margin: ${top} ${outside} ${bottom} ${inside};`;
208
+ const verso = `margin: ${top} ${inside} ${bottom} ${outside};`;
209
+ return [`@page { ${size} ${recto} }`, `@page :left { ${verso} }`, `@page :right { ${recto} }`].join(`
210
+ `);
211
+ }
212
+ function defaultPageMarginCss(page) {
213
+ if (!page || page.margin)
274
214
  return null;
275
- }
276
- return `@page { size: ${formatPageSize(page)}; }`;
215
+ return `@layer gp.vocab {
216
+ @page { margin: ${cssLength(DEFAULT_PAGE_MARGIN_PT)}; }
217
+ }`;
277
218
  }
278
219
  async function assembleBookHtml(opts) {
279
220
  const title = opts.title ?? "Document";
@@ -313,8 +254,8 @@ async function assembleBookHtml(opts) {
313
254
  imageRefs.add(ref);
314
255
  opts.onImageRefs([...imageRefs]);
315
256
  }
316
- const pageSize = defaultPageSizeCss(`${pluginCss}
317
- ${projectCss}`, opts.printArea);
257
+ const pageGeometry = pageGeometryCss(opts.printArea);
258
+ const defaultMargin = defaultPageMarginCss(opts.printArea);
318
259
  const inlineCss = [
319
260
  "@layer gp.marker, gp.vocab;",
320
261
  `/* gutterpress markers */
@@ -326,14 +267,16 @@ ${TWO_VERSIONS_CSS.trim()}
326
267
  @layer gp.vocab {
327
268
  ${GUTTERPRESS_CSS.trim()}
328
269
  }`,
329
- pageSize ? `/* page size (manifest) */
330
- ${pageSize}` : null,
270
+ defaultMargin ? `/* page margins (default) */
271
+ ${defaultMargin}` : null,
331
272
  pluginCss ? `/* extension css */
332
273
  ${pluginCss.trim()}` : null,
333
274
  `/* column alignment */
334
275
  ${TABLE_ALIGN_CSS.trim()}`,
335
276
  projectCss ? `/* project css */
336
- ${projectCss.trim()}` : null
277
+ ${projectCss.trim()}` : null,
278
+ pageGeometry ? `/* page geometry (manifest) */
279
+ ${pageGeometry}` : null
337
280
  ].filter(Boolean).join(`
338
281
 
339
282
  `);
@@ -2833,6 +2776,7 @@ var ruleRiskyProps = "printsafe/no-risky-print-effects";
2833
2776
  var ruleSyntax = "printsafe/syntax-error";
2834
2777
  var rulePageContainment = "printsafe/page-containment";
2835
2778
  var rulePreviewCannotFollow = "printsafe/preview-cannot-follow";
2779
+ var rulePageSizeInStylesheet = "printsafe/page-size-in-stylesheet";
2836
2780
  function extractUrls(value) {
2837
2781
  const urls = [];
2838
2782
  const re = /url\(\s*(['"]?)(.*?)\1\s*\)/gi;
@@ -2881,6 +2825,12 @@ function isInPageBox(decl) {
2881
2825
  const page = decl.parent;
2882
2826
  return !!page && page.type === "atrule" && page.name.toLowerCase() === "page";
2883
2827
  }
2828
+ function isInBookPageRule(decl) {
2829
+ if (!isInPageBox(decl))
2830
+ return false;
2831
+ const params = decl.parent.params.trim();
2832
+ return params === "" || /^(:[a-z-]+\s*)+$/i.test(params);
2833
+ }
2884
2834
  function isDroppedPageGradient(decl) {
2885
2835
  const prop = decl.prop.toLowerCase();
2886
2836
  if (prop !== "background" && prop !== "background-image")
@@ -3120,6 +3070,15 @@ function checkCssRaw(css, from) {
3120
3070
  root.walkAtRules((at) => reportRemoteUrls(at.params || "", at));
3121
3071
  root.walkDecls((decl) => {
3122
3072
  const prop = decl.prop.toLowerCase();
3073
+ if (prop === "size" && isInBookPageRule(decl)) {
3074
+ warnings.push({
3075
+ rule: rulePageSizeInStylesheet,
3076
+ severity: "warning",
3077
+ message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — Setup > Details in the app), which is written after every stylesheet. Remove this declaration; to print at another size, change the manifest.`,
3078
+ ...nodeLoc(decl)
3079
+ });
3080
+ return;
3081
+ }
3123
3082
  if (isInertValue(prop, decl.value))
3124
3083
  return;
3125
3084
  if (marginBoxIgnoredProperties.has(prop) && isInPageMarginBox(decl)) {
@@ -5669,7 +5628,7 @@ class PdfOutput {
5669
5628
  const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
5670
5629
  await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
5671
5630
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
5672
- const { buildNativePdf } = await import("./engine-tn13gk0b.js");
5631
+ const { buildNativePdf } = await import("./engine-1r6q80tq.js");
5673
5632
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
5674
5633
  title: config.title,
5675
5634
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -7206,20 +7165,18 @@ async function getSystemDiagnostics() {
7206
7165
  };
7207
7166
  }
7208
7167
  // src/lib/project-scaffold.ts
7209
- import { access, copyFile, cp, mkdir as mkdir6, readdir as readdir6, readFile as readFile25, stat as stat4, writeFile as writeFile8 } from "node:fs/promises";
7168
+ import { access, copyFile, cp, mkdir as mkdir5, readdir as readdir6, readFile as readFile25, stat as stat4, writeFile as writeFile7 } from "node:fs/promises";
7210
7169
  import { constants as FS, existsSync as existsSync9 } from "node:fs";
7211
7170
  import path14 from "node:path";
7212
7171
 
7213
7172
  // src/lib/page-size.ts
7214
7173
  import { existsSync as existsSync8 } from "node:fs";
7215
- import { mkdir as mkdir5, readFile as readFile24, writeFile as writeFile7 } from "node:fs/promises";
7174
+ import { readFile as readFile24 } from "node:fs/promises";
7216
7175
  import path13 from "node:path";
7217
- import postcss5 from "postcss";
7218
- import { isMap, Scalar } from "yaml";
7176
+ import { isMap } from "yaml";
7219
7177
  function writePageBounds(doc, page) {
7220
7178
  const tolerance = page.tolerance ?? numberAt(doc, ["page", "tolerance"]);
7221
- if (!isMap(doc.get("page", true)))
7222
- doc.set("page", doc.createNode({}));
7179
+ ensurePageMap(doc);
7223
7180
  doc.setIn(["page", "width"], page.width);
7224
7181
  doc.setIn(["page", "height"], page.height);
7225
7182
  if (tolerance !== undefined)
@@ -7236,6 +7193,17 @@ function deletePageBounds(doc) {
7236
7193
  if (block.items.length === 0)
7237
7194
  doc.delete("page");
7238
7195
  }
7196
+ function writePageMargin(doc, margin) {
7197
+ ensurePageMap(doc);
7198
+ if (!isMap(doc.getIn(["page", "margin"], true)))
7199
+ doc.setIn(["page", "margin"], doc.createNode({}));
7200
+ for (const edge of MARGIN_EDGES)
7201
+ doc.setIn(["page", "margin", edge], margin[edge]);
7202
+ }
7203
+ function ensurePageMap(doc) {
7204
+ if (!isMap(doc.get("page", true)))
7205
+ doc.set("page", doc.createNode({}));
7206
+ }
7239
7207
  function numberAt(doc, keyPath) {
7240
7208
  const v = doc.getIn(keyPath);
7241
7209
  return isPositivePoints(v) ? v : undefined;
@@ -7254,132 +7222,95 @@ function pageSizeForChoice(choice) {
7254
7222
  const base = PRESETS[choice.preset].page;
7255
7223
  return { width: base.width, height: base.height };
7256
7224
  }
7257
- var SAME_SIZE_PT = 0.5;
7258
- function sameSize(a, b) {
7259
- return Math.abs(a.width - b.width) < SAME_SIZE_PT && Math.abs(a.height - b.height) < SAME_SIZE_PT;
7260
- }
7261
- function plainPageRules(root) {
7262
- const rules = [];
7263
- root.walkAtRules("page", (rule) => {
7264
- if (rule.params.trim() === "")
7265
- rules.push(rule);
7266
- });
7267
- return rules;
7268
- }
7269
- function sizeDeclsOf(rule) {
7270
- const decls = [];
7271
- rule.each((node) => {
7272
- if (node.type === "decl" && node.prop.toLowerCase() === "size")
7273
- decls.push(node);
7274
- });
7275
- return decls;
7276
- }
7277
- function readPageSizeFromCss(css) {
7278
- let root;
7279
- try {
7280
- root = postcss5.parse(css);
7281
- } catch {
7282
- return null;
7283
- }
7284
- const decls = plainPageRules(root).flatMap(sizeDeclsOf);
7285
- const last = decls[decls.length - 1];
7286
- return last ? parseSize(last.value) ?? null : null;
7287
- }
7288
- function setPageSizeInCss(css, page) {
7289
- const root = postcss5.parse(css);
7290
- const decls = plainPageRules(root).flatMap(sizeDeclsOf);
7291
- const last = decls[decls.length - 1];
7292
- const value = formatPageSize(page);
7293
- if (last) {
7294
- const current = parseSize(last.value);
7295
- if (current && sameSize(current, page))
7296
- return css;
7297
- last.value = value;
7298
- return root.toString();
7299
- }
7300
- const rule = `@page {
7301
- size: ${value};
7302
- }
7303
- `;
7304
- if (css.trim() === "")
7305
- return css + rule;
7306
- return `${css}${css.endsWith(`
7307
- `) ? "" : `
7308
- `}
7309
- ${rule}`;
7310
- }
7311
- async function ownStylesheets(projectDir) {
7312
- const rels = await resolveActiveStyles(projectDir).catch(() => []);
7313
- return rels.map((rel) => path13.resolve(projectDir, rel)).filter((abs) => {
7314
- const inside = path13.relative(projectDir, abs);
7315
- return !inside.startsWith("..") && !path13.isAbsolute(inside) && existsSync8(abs);
7316
- });
7317
- }
7318
- var relDisplay2 = (projectDir, abs) => path13.relative(projectDir, abs).split(path13.sep).join("/");
7319
- async function findCssSize(projectDir, sheets) {
7320
- let found = null;
7321
- for (const file of sheets) {
7322
- const size2 = readPageSizeFromCss(await readFile24(file, "utf8"));
7323
- if (size2)
7324
- found = { file, size: size2 };
7325
- }
7326
- return found;
7327
- }
7328
- async function readPageSetup(projectDir) {
7329
- const { doc } = await loadManifestDoc(projectDir);
7225
+ function manifestGeometry(doc) {
7330
7226
  const declared = doc.get("preset");
7331
7227
  const preset = declared === undefined || declared === null ? "dtrpg" : PRESET_IDS.includes(String(declared)) ? declared : null;
7332
7228
  const base = preset ? PRESETS[preset].page : null;
7333
7229
  const width = numberAt(doc, ["page", "width"]) ?? base?.width;
7334
7230
  const height = numberAt(doc, ["page", "height"]) ?? base?.height;
7335
7231
  const tolerance = numberAt(doc, ["page", "tolerance"]) ?? base?.tolerance ?? 0.5;
7336
- const found = await findCssSize(projectDir, await ownStylesheets(projectDir));
7337
- return {
7338
- preset,
7339
- bounds: width !== undefined && height !== undefined ? { width, height, tolerance } : null,
7340
- css: found ? { ...found.size, file: relDisplay2(projectDir, found.file) } : null
7232
+ const bounds = width !== undefined && height !== undefined ? { width, height, tolerance } : null;
7233
+ const at = (edge) => doc.getIn(["page", "margin", edge]);
7234
+ const margins = MARGIN_EDGES.every((edge) => isNonNegativePoints(at(edge))) ? { top: at("top"), bottom: at("bottom"), inside: at("inside"), outside: at("outside") } : undefined;
7235
+ return { preset, bounds, ...margins ? { margins } : {} };
7236
+ }
7237
+ async function stylesheetMargins(projectDir, manifestStyles) {
7238
+ const d = DEFAULT_PAGE_MARGIN_PT;
7239
+ const fallback = {
7240
+ margins: { top: d, bottom: d, inside: d, outside: d },
7241
+ marginsFrom: "default"
7341
7242
  };
7342
- }
7343
- async function setPageSetup(projectDir, choice) {
7344
- const size2 = pageSizeForChoice(choice);
7345
- const sheets = await ownStylesheets(projectDir);
7346
- const found = await findCssSize(projectDir, sheets);
7347
- const newSheet = path13.join(projectDir, "styles", "book.css");
7348
- const target = found?.file ?? sheets[sheets.length - 1] ?? newSheet;
7349
- const before = existsSync8(target) ? await readFile24(target, "utf8") : "";
7350
- let after;
7243
+ const [entries, rels] = await Promise.all([
7244
+ listProjectExtensions(projectDir).catch(() => []),
7245
+ resolveActiveStyles(projectDir, manifestStyles).catch(() => [])
7246
+ ]);
7247
+ const sheets = rels.map((rel) => path13.resolve(projectDir, rel)).filter((abs) => existsSync8(abs));
7248
+ const parts = await Promise.all([
7249
+ ...entries.filter((e) => e.enabled && e.carries.styles).map((e) => readEntryCss(e).catch(() => "")),
7250
+ ...sheets.map((file) => readFile24(file, "utf8").catch(() => ""))
7251
+ ]);
7351
7252
  try {
7352
- after = setPageSizeInCss(before, size2);
7353
- } catch (e) {
7354
- throw new UsageError(`Could not update the page size: ${relDisplay2(projectDir, target)} has a CSS error ` + `(${e instanceof Error ? e.message : String(e)}). Fix it, then try again.`);
7253
+ const page = resolvePage(extract(parts.join(`
7254
+
7255
+ `)), { pseudos: ["right"] });
7256
+ const declared = Object.keys(page.decls).some((prop) => prop === "margin" || prop.startsWith("margin-"));
7257
+ if (!declared)
7258
+ return fallback;
7259
+ const m = page.geometry.margin;
7260
+ return {
7261
+ margins: { top: round3(m.top), bottom: round3(m.bottom), inside: round3(m.left), outside: round3(m.right) },
7262
+ marginsFrom: "stylesheet"
7263
+ };
7264
+ } catch {
7265
+ return fallback;
7355
7266
  }
7267
+ }
7268
+ async function setupOf(projectDir, doc) {
7269
+ const { margins, ...geometry } = manifestGeometry(doc);
7270
+ if (margins)
7271
+ return { ...geometry, margins, marginsFrom: "manifest" };
7272
+ const styles = doc.toJS()?.styles;
7273
+ return { ...geometry, ...await stylesheetMargins(projectDir, Array.isArray(styles) ? styles : undefined) };
7274
+ }
7275
+ async function readPageSetup(projectDir) {
7276
+ const { doc } = await loadManifestDoc(projectDir);
7277
+ return setupOf(projectDir, doc);
7278
+ }
7279
+ async function setPageSetup(projectDir, change) {
7356
7280
  const { doc, file } = await loadManifestDoc(projectDir);
7357
- doc.set("preset", choice.preset);
7358
- if (choice.preset === "custom")
7359
- writePageBounds(doc, size2);
7360
- else
7361
- deletePageBounds(doc);
7362
- if (target === newSheet && !sheets.includes(newSheet)) {
7363
- ensureSeq(doc, "styles").add(new Scalar("styles/book.css"));
7281
+ const size2 = change.size ? pageSizeForChoice(change.size) : null;
7282
+ let margins;
7283
+ if (change.margins !== undefined) {
7284
+ const against = size2 ?? manifestGeometry(doc).bounds;
7285
+ if (!against)
7286
+ throw new UsageError("Choose a page size before setting margins: the manifest records none.");
7287
+ margins = validatePageMargin(change.margins, against);
7288
+ }
7289
+ if (change.size && size2) {
7290
+ doc.set("preset", change.size.preset);
7291
+ if (change.size.preset === "custom")
7292
+ writePageBounds(doc, size2);
7293
+ else
7294
+ deletePageBounds(doc);
7364
7295
  }
7296
+ if (margins)
7297
+ writePageMargin(doc, margins);
7365
7298
  await writeManifestDoc(file, doc);
7366
- if (after !== before || !existsSync8(target)) {
7367
- await mkdir5(path13.dirname(target), { recursive: true });
7368
- await writeFile7(target, after, "utf8");
7369
- }
7370
- return readPageSetup(projectDir);
7299
+ return setupOf(projectDir, doc);
7371
7300
  }
7372
7301
 
7373
7302
  // src/lib/project-scaffold.ts
7374
7303
  function starterOverridesCss() {
7375
7304
  return `/**
7376
- * Your book's own styles.
7305
+ * Your book's own styles. Rules here win over your look's.
7377
7306
  *
7378
- * This file loads AFTER every extension, so any rule you add here overrides
7379
- * a look's defaults. A new book has no look until its template or you add
7380
- * one:
7381
- * gutterpress ext add academic <book> (a built-in look)
7382
- * gutterpress ext add <package> <book> (a look from npm)
7307
+ * In the app you rarely need this file: Setup > Looks & features adds a
7308
+ * look, Setup > Design changes its fonts, colors and sizes (those changes
7309
+ * are saved here as :root custom properties), and Setup > Details sets the
7310
+ * page size and margins (in the manifest).
7311
+ *
7312
+ * To change the look from the command line: gutterpress ext remove <old>
7313
+ * <book>, then gutterpress ext add <look> <book>.
7383
7314
  */
7384
7315
  `;
7385
7316
  }
@@ -7462,7 +7393,7 @@ async function scaffoldProject(options) {
7462
7393
  const preset = options.preset === undefined ? undefined : requirePreset(options.preset, options.customPage);
7463
7394
  const targets = preset ? resolveScaffoldTargets(options.targets, preset) : undefined;
7464
7395
  try {
7465
- await mkdir6(projectDir, { recursive: true });
7396
+ await mkdir5(projectDir, { recursive: true });
7466
7397
  if (customTemplateDir) {
7467
7398
  const entries = await readdir6(customTemplateDir, { withFileTypes: true });
7468
7399
  for (const entry of entries) {
@@ -7470,15 +7401,15 @@ async function scaffoldProject(options) {
7470
7401
  continue;
7471
7402
  await cp(path14.join(customTemplateDir, entry.name), path14.join(projectDir, entry.name), { recursive: true });
7472
7403
  }
7473
- await mkdir6(path14.join(projectDir, "assets"), { recursive: true });
7404
+ await mkdir5(path14.join(projectDir, "assets"), { recursive: true });
7474
7405
  } else {
7475
7406
  const tplManifest = await getAssetPath(`templates/${template}/manifest.yaml`);
7476
7407
  const tplChapter = await getAssetPath(`templates/${template}/chapter-01.md`);
7477
- await mkdir6(path14.join(projectDir, "assets"), { recursive: true });
7408
+ await mkdir5(path14.join(projectDir, "assets"), { recursive: true });
7478
7409
  await copyFile(tplManifest, path14.join(projectDir, MANIFEST_FILENAMES[0]));
7479
7410
  await copyFile(tplChapter, path14.join(projectDir, "chapter-01.md"));
7480
- await mkdir6(path14.join(projectDir, "styles"), { recursive: true });
7481
- await writeFile8(path14.join(projectDir, "styles", "book.css"), starterOverridesCss(), "utf8");
7411
+ await mkdir5(path14.join(projectDir, "styles"), { recursive: true });
7412
+ await writeFile7(path14.join(projectDir, "styles", "book.css"), starterOverridesCss(), "utf8");
7482
7413
  }
7483
7414
  } catch (e) {
7484
7415
  throw new CreateProjectErrorImpl("scaffold-io", `Could not create the book files: ${e instanceof Error ? e.message : String(e)}`);
@@ -7502,6 +7433,8 @@ async function scaffoldProject(options) {
7502
7433
  if (preset) {
7503
7434
  doc.set("preset", preset);
7504
7435
  doc.set("targets", doc.createNode(targets ?? []));
7436
+ if (preset !== "custom")
7437
+ deletePageBounds(doc);
7505
7438
  }
7506
7439
  if (options.customPage)
7507
7440
  writePageBounds(doc, options.customPage);
@@ -7579,10 +7512,10 @@ async function adoptFolder(options) {
7579
7512
  await fillTemplateFile(path14.join(dir, "chapter-01.md"), { "{{TITLE}}": title }).catch(() => {});
7580
7513
  mdFiles = ["chapter-01.md"];
7581
7514
  }
7582
- await mkdir6(path14.join(dir, "styles"), { recursive: true });
7515
+ await mkdir5(path14.join(dir, "styles"), { recursive: true });
7583
7516
  const bookCssPath = path14.join(dir, "styles", "book.css");
7584
7517
  if (!existsSync9(bookCssPath)) {
7585
- await writeFile8(bookCssPath, starterOverridesCss(), "utf8");
7518
+ await writeFile7(bookCssPath, starterOverridesCss(), "utf8");
7586
7519
  }
7587
7520
  const filesYaml = mdFiles.map((f) => ` - "${escapeYamlScalar(f)}"`).join(`
7588
7521
  `);
@@ -7598,8 +7531,8 @@ ${filesYaml}
7598
7531
  styles:
7599
7532
  - styles/book.css
7600
7533
  `;
7601
- await writeFile8(path14.join(dir, MANIFEST_FILENAMES[0]), manifest, "utf8");
7602
- await mkdir6(path14.join(dir, "assets"), { recursive: true });
7534
+ await writeFile7(path14.join(dir, MANIFEST_FILENAMES[0]), manifest, "utf8");
7535
+ await mkdir5(path14.join(dir, "assets"), { recursive: true });
7603
7536
  await ensureProjectGitignore(dir);
7604
7537
  } catch (e) {
7605
7538
  if (e instanceof CreateProjectErrorImpl)
@@ -7653,10 +7586,10 @@ async function fillTemplateFile(filePath, substitutions) {
7653
7586
  for (const [token, value] of Object.entries(substitutions)) {
7654
7587
  text = text.split(token).join(value);
7655
7588
  }
7656
- await writeFile8(filePath, text, "utf8");
7589
+ await writeFile7(filePath, text, "utf8");
7657
7590
  }
7658
7591
  // src/lib/extension-scaffold.ts
7659
- import { access as access2, mkdir as mkdir7, readFile as readFile26, writeFile as writeFile9 } from "node:fs/promises";
7592
+ import { access as access2, mkdir as mkdir6, readFile as readFile26, writeFile as writeFile8 } from "node:fs/promises";
7660
7593
  import { constants as FS2 } from "node:fs";
7661
7594
  import path15 from "node:path";
7662
7595
  var EXTENSION_KINDS = ["plugin", "look"];
@@ -7768,14 +7701,14 @@ async function scaffoldExtension(options) {
7768
7701
  const entries = TEMPLATE_FILES[kind];
7769
7702
  const written = [];
7770
7703
  try {
7771
- await mkdir7(extensionDir, { recursive: true });
7704
+ await mkdir6(extensionDir, { recursive: true });
7772
7705
  for (const [assetName, relDest] of entries) {
7773
7706
  const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
7774
7707
  const dest = path15.join(extensionDir, relDest);
7775
- await mkdir7(path15.dirname(dest), { recursive: true });
7708
+ await mkdir6(path15.dirname(dest), { recursive: true });
7776
7709
  const text = await readFile26(src, "utf8");
7777
7710
  const table = relDest.endsWith(".json") ? jsonSafe : plain;
7778
- await writeFile9(dest, substitute(text, table), "utf8");
7711
+ await writeFile8(dest, substitute(text, table), "utf8");
7779
7712
  written.push(relDest);
7780
7713
  }
7781
7714
  } catch (e) {
@@ -7799,7 +7732,7 @@ function substitute(text, table) {
7799
7732
  return out;
7800
7733
  }
7801
7734
  // src/lib/project-templates.ts
7802
- import { cp as cp2, mkdir as mkdir8, readFile as readFile27, readdir as readdir7, stat as stat5, writeFile as writeFile10 } from "node:fs/promises";
7735
+ import { cp as cp2, mkdir as mkdir7, readFile as readFile27, readdir as readdir7, stat as stat5, writeFile as writeFile9 } from "node:fs/promises";
7803
7736
  import { constants as FS3, existsSync as existsSync10 } from "node:fs";
7804
7737
  import { access as access3 } from "node:fs/promises";
7805
7738
  import path16 from "node:path";
@@ -7822,6 +7755,10 @@ async function readTemplateChoices(manifestPath) {
7822
7755
  if (isSeq(targets)) {
7823
7756
  out.targets = targets.items.map((i) => scalarString(i)).filter((s) => s !== null);
7824
7757
  }
7758
+ const width = numberAt(doc, ["page", "width"]);
7759
+ const height = numberAt(doc, ["page", "height"]);
7760
+ if (width !== undefined && height !== undefined)
7761
+ out.page = { width, height };
7825
7762
  return out;
7826
7763
  } catch {
7827
7764
  return {};
@@ -7830,19 +7767,19 @@ async function readTemplateChoices(manifestPath) {
7830
7767
  var BUILT_IN_META = {
7831
7768
  book: {
7832
7769
  label: "Book",
7833
- description: "A clean starting point for a novel, memoir, or any long-form book."
7770
+ description: "A clean starting point for a novel, memoir, or any long-form book. Uses the Clean book look."
7834
7771
  },
7835
7772
  zine: {
7836
7773
  label: "Zine",
7837
- description: "A short, personal zine made to be printed, folded, and shared."
7774
+ description: "A short, personal zine made to be printed, folded, and shared. Uses the Zine look."
7838
7775
  },
7839
7776
  technical: {
7840
7777
  label: "Technical document",
7841
- description: "A manual or guide with steps, reference tables, and code examples."
7778
+ description: "A manual or guide with steps, reference tables, and code examples. Uses the Technical doc look."
7842
7779
  },
7843
7780
  paper: {
7844
7781
  label: "Academic paper",
7845
- description: "A journal-style article with LaTeX math, numbered equations, figures, tables, notes and references."
7782
+ description: "A journal-style article with LaTeX math, numbered equations, figures, tables, notes and references. Uses the Academic look."
7846
7783
  }
7847
7784
  };
7848
7785
  async function listBuiltInTemplates() {
@@ -7939,7 +7876,7 @@ async function reconcileSharedRefs(templateDir, sourceProjectDir, mode) {
7939
7876
  const vendorDir = pickVendorDir(templateDir, base);
7940
7877
  await Promise.all(externalFiles.filter((abs) => existsSync10(abs)).map(async (abs) => {
7941
7878
  const dest = path16.join(templateDir, vendorDir, path16.relative(base, abs));
7942
- await mkdir8(path16.dirname(dest), { recursive: true });
7879
+ await mkdir7(path16.dirname(dest), { recursive: true });
7943
7880
  await cp2(abs, dest, { recursive: true });
7944
7881
  }));
7945
7882
  const bookLocal = (value) => toPosixPath(path16.join(vendorDir, path16.relative(base, path16.resolve(sourceProjectDir, value))));
@@ -7972,7 +7909,7 @@ async function saveProjectAsTemplate(options) {
7972
7909
  if (exists) {
7973
7910
  throw new Error(`A template named "${name}" already exists. Choose a different name.`);
7974
7911
  }
7975
- await mkdir8(dir, { recursive: true });
7912
+ await mkdir7(dir, { recursive: true });
7976
7913
  const entries = await readdir7(projectDir, { withFileTypes: true });
7977
7914
  for (const entry of entries) {
7978
7915
  if (SKIP_ENTRIES.has(entry.name))
@@ -7985,7 +7922,7 @@ async function saveProjectAsTemplate(options) {
7985
7922
  const shared = manifestName ? await reconcileSharedRefs(dir, projectDir, options.sharedRefs ?? "vendor") : { vendoredRefs: [], excludedRefs: [] };
7986
7923
  if (manifestName)
7987
7924
  await retokeniseManifest(path16.join(dir, manifestName));
7988
- await writeFile10(path16.join(dir, TEMPLATE_META_FILE), JSON.stringify({ label: name }, null, 2), "utf8");
7925
+ await writeFile9(path16.join(dir, TEMPLATE_META_FILE), JSON.stringify({ label: name }, null, 2), "utf8");
7989
7926
  return {
7990
7927
  id,
7991
7928
  label: name,
@@ -8003,7 +7940,7 @@ async function retokeniseManifest(manifestPath) {
8003
7940
  return;
8004
7941
  }
8005
7942
  text = text.replace(/^title:\s*.*$/m, 'title: "{{TITLE}}"').replace(/^(authors:[^\n]*\n[ \t]*-[ \t]*).*$/m, '$1"{{AUTHOR}}"');
8006
- await writeFile10(manifestPath, text, "utf8");
7943
+ await writeFile9(manifestPath, text, "utf8");
8007
7944
  }
8008
7945
  async function listCustomTemplates(templatesRoot) {
8009
7946
  let entries;
@@ -8045,7 +7982,7 @@ async function importTemplateFromFolder(options) {
8045
7982
  return saveProjectAsTemplate({ projectDir: sourceDir, name, templatesRoot });
8046
7983
  }
8047
7984
  // src/lib/snippets.ts
8048
- import { readdir as readdir8, readFile as readFile28, writeFile as writeFile11, mkdir as mkdir9, rm } from "node:fs/promises";
7985
+ import { readdir as readdir8, readFile as readFile28, writeFile as writeFile10, mkdir as mkdir8, rm } from "node:fs/promises";
8049
7986
  import path17 from "node:path";
8050
7987
  var SNIPPETS_DIR = "snippets";
8051
7988
  var LEVEL_RANK = { project: 0, extension: 1, core: 2 };
@@ -8110,8 +8047,8 @@ async function saveSnippet(projectDir, name, body) {
8110
8047
  throw new Error(`Could not derive a filename from "${name}".`);
8111
8048
  const fileName = `${stem}.md`;
8112
8049
  const dir = path17.join(projectDir, SNIPPETS_DIR);
8113
- await mkdir9(dir, { recursive: true });
8114
- await writeFile11(resolveSnippetPath(projectDir, fileName), body, "utf8");
8050
+ await mkdir8(dir, { recursive: true });
8051
+ await writeFile10(resolveSnippetPath(projectDir, fileName), body, "utf8");
8115
8052
  return { name, fileName, variables: extractVariables(body), body, source: { kind: "project" } };
8116
8053
  }
8117
8054
  async function deleteSnippet(projectDir, fileName) {
@@ -8244,7 +8181,7 @@ async function listLocationVariants(projectDir) {
8244
8181
  }
8245
8182
  // src/lib/extension-import.ts
8246
8183
  import { existsSync as existsSync11 } from "node:fs";
8247
- import { cp as cp3, mkdir as mkdir10, mkdtemp, readFile as readFile29, rm as rm2, writeFile as writeFile12 } from "node:fs/promises";
8184
+ import { cp as cp3, mkdir as mkdir9, mkdtemp, readFile as readFile29, rm as rm2, writeFile as writeFile11 } from "node:fs/promises";
8248
8185
  import { tmpdir as tmpdir2 } from "node:os";
8249
8186
  import path18 from "node:path";
8250
8187
  import { unzipSync } from "fflate";
@@ -8365,7 +8302,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
8365
8302
  }
8366
8303
  const id = await uniqueExtensionId(projectDir, meta.name?.trim() || fallbackName);
8367
8304
  const dest = path18.join(projectDir, EXTENSIONS_DIR, id);
8368
- await mkdir10(path18.dirname(dest), { recursive: true });
8305
+ await mkdir9(path18.dirname(dest), { recursive: true });
8369
8306
  await cp3(sourceDir, dest, { recursive: true });
8370
8307
  await completeLandedManifest(dest, id, meta, metaExists);
8371
8308
  const entry = await addExtension(projectDir, `./${EXTENSIONS_DIR}/${id}`);
@@ -8385,7 +8322,7 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
8385
8322
  } catch {}
8386
8323
  }
8387
8324
  const gutterpress = pkg.gutterpress && typeof pkg.gutterpress === "object" && !Array.isArray(pkg.gutterpress) ? pkg.gutterpress : {};
8388
- await writeFile12(file, JSON.stringify({
8325
+ await writeFile11(file, JSON.stringify({
8389
8326
  ...pkg,
8390
8327
  name: typeof pkg.name === "string" && pkg.name.trim() ? pkg.name : id,
8391
8328
  gutterpress: { ...gutterpress, styles: ["theme.css"] }
@@ -8449,8 +8386,8 @@ async function importExtensionFromZip(projectDir, archive) {
8449
8386
  throw new Error(`The package contains an unsafe path and was rejected: ${name}`);
8450
8387
  }
8451
8388
  relPaths.push(rel);
8452
- await mkdir10(path18.dirname(dest), { recursive: true });
8453
- await writeFile12(dest, data);
8389
+ await mkdir9(path18.dirname(dest), { recursive: true });
8390
+ await writeFile11(dest, data);
8454
8391
  }
8455
8392
  return await finalizeExtensionImport(projectDir, tmp, relPaths, root || "imported-look");
8456
8393
  } finally {
@@ -8465,8 +8402,8 @@ async function importExtensionFromCssText(projectDir, css, name) {
8465
8402
  const displayName = name.trim() || "Imported theme";
8466
8403
  const tmp = await mkdtemp(path18.join(tmpdir2(), "gutterpress-theme-"));
8467
8404
  try {
8468
- await writeFile12(path18.join(tmp, "theme.css"), css, "utf8");
8469
- await writeFile12(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
8405
+ await writeFile11(path18.join(tmp, "theme.css"), css, "utf8");
8406
+ await writeFile11(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
8470
8407
  const result = await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], displayName);
8471
8408
  result.warnings.unshift({
8472
8409
  code: "no-theme-json",
@@ -8549,7 +8486,7 @@ async function importExtensionFromUrl(projectDir, url) {
8549
8486
  assertLooksLikeCss(css, trimmed);
8550
8487
  const tmp = await mkdtemp(path18.join(tmpdir2(), "gutterpress-ext-"));
8551
8488
  try {
8552
- await writeFile12(path18.join(tmp, "theme.css"), css, "utf8");
8489
+ await writeFile11(path18.join(tmp, "theme.css"), css, "utf8");
8553
8490
  const gp = meta.gutterpress && typeof meta.gutterpress === "object" && !Array.isArray(meta.gutterpress) ? meta.gutterpress : {};
8554
8491
  const finalMeta = {
8555
8492
  name: typeof meta.name === "string" && meta.name || slugify(baseName, "look"),
@@ -8561,7 +8498,7 @@ async function importExtensionFromUrl(projectDir, url) {
8561
8498
  preview: typeof gp.preview === "string" ? gp.preview : null
8562
8499
  }
8563
8500
  };
8564
- await writeFile12(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
8501
+ await writeFile11(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
8565
8502
  return await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], baseName);
8566
8503
  } finally {
8567
8504
  await rm2(tmp, { recursive: true, force: true });
@@ -8682,7 +8619,7 @@ async function searchNpmExtensions(query, options = {}) {
8682
8619
  return { matches, total: pages.reduce((sum, page) => sum + page.total, 0) };
8683
8620
  }
8684
8621
  // src/lib/manifest-config.ts
8685
- import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar as Scalar2 } from "yaml";
8622
+ import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar } from "yaml";
8686
8623
  function hasKey(obj, key) {
8687
8624
  return Object.prototype.hasOwnProperty.call(obj, key);
8688
8625
  }
@@ -8765,7 +8702,7 @@ async function setActiveStyles(projectDir, paths) {
8765
8702
  } else {
8766
8703
  const seq = new YAMLSeq(doc.schema);
8767
8704
  for (const p of paths)
8768
- seq.add(new Scalar2(p));
8705
+ seq.add(new Scalar(p));
8769
8706
  doc.set("styles", seq);
8770
8707
  }
8771
8708
  await writeManifestDoc(file, doc);
@@ -8773,9 +8710,9 @@ async function setActiveStyles(projectDir, paths) {
8773
8710
  }
8774
8711
  // src/lib/version-changes.ts
8775
8712
  import path19 from "node:path";
8776
- import { mkdir as mkdir11, readFile as readFile30, writeFile as writeFile13 } from "node:fs/promises";
8713
+ import { mkdir as mkdir10, readFile as readFile30, writeFile as writeFile12 } from "node:fs/promises";
8777
8714
  import git3 from "isomorphic-git";
8778
- import postcss6 from "postcss";
8715
+ import postcss5 from "postcss";
8779
8716
 
8780
8717
  // src/lib/remote-auth/transport.ts
8781
8718
  import git2 from "isomorphic-git";
@@ -9228,7 +9165,7 @@ function paragraphs(text) {
9228
9165
  }
9229
9166
  function cssRules(text) {
9230
9167
  try {
9231
- return postcss6.parse(text).nodes.map((node) => node.toString().trim()).filter((rule) => rule.length > 0);
9168
+ return postcss5.parse(text).nodes.map((node) => node.toString().trim()).filter((rule) => rule.length > 0);
9232
9169
  } catch {
9233
9170
  return textLines(text);
9234
9171
  }
@@ -9467,8 +9404,8 @@ async function exportVersionTree(projectDir, id, destDir) {
9467
9404
  if (!content)
9468
9405
  return null;
9469
9406
  const abs = path19.join(destDir, filepath);
9470
- await mkdir11(path19.dirname(abs), { recursive: true });
9471
- await writeFile13(abs, content);
9407
+ await mkdir10(path19.dirname(abs), { recursive: true });
9408
+ await writeFile12(abs, content);
9472
9409
  return null;
9473
9410
  }
9474
9411
  });
@@ -10084,7 +10021,7 @@ import git5 from "isomorphic-git";
10084
10021
  import { randomUUID as randomUUID2 } from "node:crypto";
10085
10022
 
10086
10023
  // src/lib/remote-auth/converge-merge.ts
10087
- import { mkdir as mkdir12, unlink as unlink2, writeFile as writeFile14 } from "node:fs/promises";
10024
+ import { mkdir as mkdir11, unlink as unlink2, writeFile as writeFile13 } from "node:fs/promises";
10088
10025
  import path20 from "node:path";
10089
10026
  import git4 from "isomorphic-git";
10090
10027
  import diff3Merge from "diff3";
@@ -10134,8 +10071,8 @@ async function readBlob(dir, cache2, oid, filepath) {
10134
10071
  }
10135
10072
  async function writeTreeFile(dir, filepath, content) {
10136
10073
  const abs = path20.join(dir, filepath);
10137
- await mkdir12(path20.dirname(abs), { recursive: true });
10138
- await writeFile14(abs, content);
10074
+ await mkdir11(path20.dirname(abs), { recursive: true });
10075
+ await writeFile13(abs, content);
10139
10076
  }
10140
10077
  async function bothAddedPaths(dir, cache2, ourTip, theirTip, allowUnrelated) {
10141
10078
  const bases = await git4.findMergeBase({ fs: gitFs, dir, cache: cache2, oids: [ourTip, theirTip] });
@@ -10791,7 +10728,7 @@ async function setUpOnlineBackup(options) {
10791
10728
  }
10792
10729
  }
10793
10730
  // src/lib/remote-auth/clone.ts
10794
- import { mkdir as mkdir13, readdir as readdir9, rm as rm3 } from "node:fs/promises";
10731
+ import { mkdir as mkdir12, readdir as readdir9, rm as rm3 } from "node:fs/promises";
10795
10732
  import path21 from "node:path";
10796
10733
  import git7 from "isomorphic-git";
10797
10734
  function sanitizeCloneFolderName(name) {
@@ -10850,7 +10787,7 @@ async function cloneRepository(options) {
10850
10787
  return withRepoLock(dir, async () => {
10851
10788
  await assertCloneTarget(dir);
10852
10789
  const dirExistedBefore = gitFs.existsSync(dir);
10853
- await mkdir13(dir, { recursive: true });
10790
+ await mkdir12(dir, { recursive: true });
10854
10791
  try {
10855
10792
  await git7.clone({
10856
10793
  fs: gitFs,
@@ -11140,11 +11077,11 @@ async function diagnoseProjectRemote(projectDir, options = {}) {
11140
11077
  }
11141
11078
  // src/lib/remote-auth/repair.ts
11142
11079
  import git9 from "isomorphic-git";
11143
- import { cp as cp4, mkdir as mkdir14, rename as rename3, rm as rm4 } from "node:fs/promises";
11080
+ import { cp as cp4, mkdir as mkdir13, rename as rename3, rm as rm4 } from "node:fs/promises";
11144
11081
  import path22 from "node:path";
11145
11082
  var REPAIR_SNAPSHOT_MESSAGE = "Repaired online backup";
11146
11083
  async function moveDir(from, to) {
11147
- await mkdir14(path22.dirname(to), { recursive: true });
11084
+ await mkdir13(path22.dirname(to), { recursive: true });
11148
11085
  try {
11149
11086
  await rename3(from, to);
11150
11087
  } catch (e) {
@@ -11221,7 +11158,7 @@ async function repairOnlineBackup(options) {
11221
11158
  }
11222
11159
  // src/lib/remote-auth/scorched-earth.ts
11223
11160
  import git10 from "isomorphic-git";
11224
- import { cp as cp5, mkdir as mkdir15, readdir as readdir10, rm as rm5 } from "node:fs/promises";
11161
+ import { cp as cp5, mkdir as mkdir14, readdir as readdir10, rm as rm5 } from "node:fs/promises";
11225
11162
  import path23 from "node:path";
11226
11163
  async function emptyDir(dir) {
11227
11164
  for (const entry of await readdir10(dir)) {
@@ -11251,7 +11188,7 @@ async function scorchedEarth(options) {
11251
11188
  branch2 = undefined;
11252
11189
  }
11253
11190
  logger.info("backup", "copying folder", { to: backupDir });
11254
- await mkdir15(backupDir, { recursive: true });
11191
+ await mkdir14(backupDir, { recursive: true });
11255
11192
  await cp5(dir, backupDir, { recursive: true });
11256
11193
  logger.info("delete", "emptying folder", { dir });
11257
11194
  await emptyDir(dir);
@@ -11437,11 +11374,11 @@ ${tail}` : ""}`);
11437
11374
  };
11438
11375
 
11439
11376
  // src/lib/publish/providers/guided.ts
11440
- import { copyFile as copyFile2, mkdir as mkdir16, writeFile as writeFile15 } from "node:fs/promises";
11377
+ import { copyFile as copyFile2, mkdir as mkdir15, writeFile as writeFile14 } from "node:fs/promises";
11441
11378
  import path24 from "node:path";
11442
11379
  async function stageGuidedPackage(req, providerId, listingLines) {
11443
11380
  const packageDir = path24.join(path24.dirname(req.artifact.path), "publish", providerId);
11444
- await mkdir16(packageDir, { recursive: true });
11381
+ await mkdir15(packageDir, { recursive: true });
11445
11382
  await copyFile2(req.artifact.path, path24.join(packageDir, path24.basename(req.artifact.path)));
11446
11383
  const { title, authors } = req.project;
11447
11384
  const sheet = [
@@ -11455,7 +11392,7 @@ async function stageGuidedPackage(req, providerId, listingLines) {
11455
11392
  ""
11456
11393
  ].join(`
11457
11394
  `);
11458
- await writeFile15(path24.join(packageDir, "LISTING.md"), sheet, "utf8");
11395
+ await writeFile14(path24.join(packageDir, "LISTING.md"), sheet, "utf8");
11459
11396
  return packageDir;
11460
11397
  }
11461
11398
 
@@ -11518,7 +11455,7 @@ var drivethrurpgProvider = {
11518
11455
  };
11519
11456
 
11520
11457
  // src/lib/publish/providers/gdrive.ts
11521
- import { mkdtemp as mkdtemp2, readFile as readFile31, readdir as readdir11, rm as rm6, stat as stat7, writeFile as writeFile16 } from "node:fs/promises";
11458
+ import { mkdtemp as mkdtemp2, readFile as readFile31, readdir as readdir11, rm as rm6, stat as stat7, writeFile as writeFile15 } from "node:fs/promises";
11522
11459
  import { tmpdir as tmpdir3 } from "node:os";
11523
11460
  import path25 from "node:path";
11524
11461
  import { Zip, ZipDeflate } from "fflate";
@@ -11926,7 +11863,7 @@ async function collectZipEntries(root, dir, out, onWarn) {
11926
11863
  }
11927
11864
  }
11928
11865
  }
11929
- async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile16) {
11866
+ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile15) {
11930
11867
  const entries = {};
11931
11868
  await collectZipEntries(exportDir, exportDir, entries, onWarn);
11932
11869
  const fileName = `${bookSlug(title)}-website.zip`;
@@ -12030,7 +11967,7 @@ var gdriveProvider = {
12030
11967
  };
12031
11968
 
12032
11969
  // src/lib/publish/butler.ts
12033
- import { chmod as chmod2, mkdir as mkdir17, stat as stat8, writeFile as writeFile17 } from "node:fs/promises";
11970
+ import { chmod as chmod2, mkdir as mkdir16, stat as stat8, writeFile as writeFile16 } from "node:fs/promises";
12034
11971
  import path26 from "node:path";
12035
11972
  import { unzipSync as unzipSync2 } from "fflate";
12036
11973
  var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
@@ -12091,13 +12028,13 @@ async function ensureButler(deps) {
12091
12028
  return new Uint8Array(await response.arrayBuffer());
12092
12029
  });
12093
12030
  const files = unzipSync2(archive);
12094
- await mkdir17(cacheDir, { recursive: true });
12031
+ await mkdir16(cacheDir, { recursive: true });
12095
12032
  let foundBinary = false;
12096
12033
  for (const [name, data] of Object.entries(files)) {
12097
12034
  if (name.endsWith("/"))
12098
12035
  continue;
12099
12036
  const target = path26.join(cacheDir, path26.basename(name));
12100
- await writeFile17(target, data);
12037
+ await writeFile16(target, data);
12101
12038
  if (path26.basename(name) === butlerBinaryName()) {
12102
12039
  await chmod2(target, 493).catch(() => {});
12103
12040
  foundBinary = true;
@@ -12294,7 +12231,7 @@ var kdpProvider = {
12294
12231
  };
12295
12232
 
12296
12233
  // src/lib/publish/providers/local-folder.ts
12297
- import { cp as cp6, mkdir as mkdir18, stat as stat9 } from "node:fs/promises";
12234
+ import { cp as cp6, mkdir as mkdir17, stat as stat9 } from "node:fs/promises";
12298
12235
  import path27 from "node:path";
12299
12236
  var LOCAL_PUBLISH_DEFAULT_DIR = "dist";
12300
12237
  var info8 = {
@@ -12332,7 +12269,7 @@ var localFolderProvider = {
12332
12269
  },
12333
12270
  async upload(req) {
12334
12271
  const dir = localPublishDir(req);
12335
- await mkdir18(dir, { recursive: true });
12272
+ await mkdir17(dir, { recursive: true });
12336
12273
  const dest = req.artifact.format === "html" ? dir : path27.join(dir, path27.basename(req.artifact.path));
12337
12274
  if (path27.resolve(dest) !== path27.resolve(req.artifact.path)) {
12338
12275
  await cp6(req.artifact.path, dest, { recursive: true });
@@ -12632,7 +12569,7 @@ async function resolvePublishProvider(id, book) {
12632
12569
  const ext = await bookExtensions(book);
12633
12570
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
12634
12571
  if (npmEntry) {
12635
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-s3x1618g.js");
12572
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-9dh7c4tp.js");
12636
12573
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
12637
12574
  }
12638
12575
  const publishers = await discover(ext);
@@ -12670,7 +12607,7 @@ function infoFor(p) {
12670
12607
  }
12671
12608
  function pluginProvider(p) {
12672
12609
  let loading;
12673
- const load = () => loading ??= import("./plugins-2cek4mz1.js").then((m) => m.loadPublishFunction(p));
12610
+ const load = () => loading ??= import("./plugins-80emnf31.js").then((m) => m.loadPublishFunction(p));
12674
12611
  return {
12675
12612
  info: infoFor(p),
12676
12613
  async authenticate() {
@@ -12941,7 +12878,7 @@ async function disconnectPublishCredential(key, deps, options = {}) {
12941
12878
  }
12942
12879
  }
12943
12880
  // src/lib/publish/selections.ts
12944
- import { chmod as chmod3, mkdir as mkdir19, readFile as readFile32, writeFile as writeFile18 } from "node:fs/promises";
12881
+ import { chmod as chmod3, mkdir as mkdir18, readFile as readFile32, writeFile as writeFile17 } from "node:fs/promises";
12945
12882
  import path30 from "node:path";
12946
12883
  class PublishSelectionsStore {
12947
12884
  filePath;
@@ -12964,8 +12901,8 @@ class PublishSelectionsStore {
12964
12901
  return { version: 1, global: {}, projects: {} };
12965
12902
  }
12966
12903
  async write(data) {
12967
- await mkdir19(path30.dirname(this.filePath), { recursive: true });
12968
- await writeFile18(this.filePath, JSON.stringify(data, null, 2), {
12904
+ await mkdir18(path30.dirname(this.filePath), { recursive: true });
12905
+ await writeFile17(this.filePath, JSON.stringify(data, null, 2), {
12969
12906
  encoding: "utf8",
12970
12907
  mode: 384
12971
12908
  });