gutterpress 0.11.23-alpha.7 → 0.11.23-beta.1

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 +2 -0
  2. package/dist/{README-syg2hn83.md → README-8rct3axy.md} +2 -2
  3. package/dist/api/index.d.ts +3 -3
  4. package/dist/api/index.js +7 -5
  5. package/dist/{build-w572wq10.js → build-dg8a566j.js} +8 -7
  6. package/dist/{cli-eatdqx3z.js → cli-1fy1pm9d.js} +1 -1
  7. package/dist/cli-65gy8ask.js +82 -0
  8. package/dist/{cli-3cvq3n1c.js → cli-989eg8jz.js} +186 -83
  9. package/dist/{cli-6pv84kf3.js → cli-e31jshz6.js} +6 -84
  10. package/dist/{cli-58fsk6d7.js → cli-k087gj0p.js} +66 -34
  11. package/dist/{cli-5ba6bm6z.js → cli-s1zt779w.js} +1 -1
  12. package/dist/{cli-wyg7qstd.js → cli-ttj95aex.js} +3 -3
  13. package/dist/{cli-mmgtqnmr.js → cli-vhav8g82.js} +1 -1
  14. package/dist/cli.js +12 -12
  15. package/dist/{doctor-2f3zqmza.js → doctor-g4a42tcz.js} +3 -3
  16. package/dist/engine/shared/page-vars.d.ts +32 -0
  17. package/dist/{engine-4rabsgwq.js → engine-jvkcahr1.js} +2 -1
  18. package/dist/{engine-wm4fggac.js → engine-wgkaqjsc.js} +3 -3
  19. package/dist/{ext-0cgky8n3.js → ext-w9d5ftcg.js} +8 -7
  20. package/dist/{extension-restore-vghc58vx.js → extension-restore-5x4mj79d.js} +3 -3
  21. package/dist/{extension-restore-e7je32pr.js → extension-restore-as0g38p1.js} +5 -4
  22. package/dist/{gutterpress-viewer-mafsby5k.js → gutterpress-viewer-ze691rrd.js} +52 -13
  23. package/dist/{index-2vxzxyyj.js → index-798jt0qc.js} +9 -9
  24. package/dist/{index-fp7xwvpr.js → index-a4j3xcfp.js} +3 -3
  25. package/dist/{index-nfysshcc.js → index-c6y0p7jy.js} +249 -139
  26. package/dist/{index-wm4x7xbf.js → index-fk2kpf2t.js} +58 -26
  27. package/dist/{index-hphcn7th.js → index-rj5vrhz6.js} +5 -85
  28. package/dist/index-tayzfr9c.js +99 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.js +233 -6
  31. package/dist/lib/book-css.d.ts +56 -0
  32. package/dist/lib/markdown/assemble.d.ts +58 -0
  33. package/dist/lib/publish/google-drive.d.ts +12 -4
  34. package/dist/lib/publish/manifest-publish.d.ts +6 -0
  35. package/dist/lib/publish/providers/gdrive-folder.d.ts +30 -0
  36. package/dist/lib/publish/run-publish.d.ts +6 -1
  37. package/dist/lib/publish/types.d.ts +52 -5
  38. package/dist/lib/remote-auth/converge-merge.d.ts +3 -3
  39. package/dist/lib/remote-auth/sync-messages.d.ts +2 -2
  40. package/dist/lib/root-tokens.d.ts +76 -0
  41. package/dist/lib/version-changes.d.ts +12 -12
  42. package/dist/{manifest-79zsgkpn.yaml → manifest-0vwaskj2.yaml} +1 -1
  43. package/dist/{manifest-2kc56wvw.yaml → manifest-aya31jwt.yaml} +1 -1
  44. package/dist/{manifest-41ddzm13.yaml → manifest-mffah3hr.yaml} +1 -1
  45. package/dist/{manifest-sqzm4681.yaml → manifest-wbcv8cbp.yaml} +2 -2
  46. package/dist/{manifest.schema-93sd7zje.json → manifest.schema-0jgj0jt1.json} +1 -1
  47. package/dist/{new-88rkrv71.js → new-jtk028rf.js} +8 -7
  48. package/dist/{page-rules-ytj9p04v.css → page-rules-vnja6grt.css} +2 -2
  49. package/dist/{plugins-3aj0wc5h.js → plugins-bcbe7xs8.js} +1 -1
  50. package/dist/{plugins-sprxsz5d.js → plugins-zsm6wv79.js} +3 -3
  51. package/dist/{preflight-11dg1qkk.js → preflight-cs6mj1d6.js} +8 -7
  52. package/dist/{preview-nftp782j.js → preview-d1j1g4qf.js} +8 -7
  53. package/dist/{publish-6tgxfck9.js → publish-7yw4jyrt.js} +24 -8
  54. package/dist/render.js +65 -24
  55. package/dist/schema/manifest.types.d.ts +2 -1
  56. package/dist/{tokens-n82t4k9h.css → tokens-a7grv940.css} +4 -5
  57. package/dist/{validate-pktqrye5.js → validate-rkcdnzhw.js} +8 -7
  58. package/package.json +1 -1
  59. package/dist/index-46ycxe6r.js +0 -18
@@ -10,20 +10,13 @@ import {
10
10
  UsageError,
11
11
  addExtension,
12
12
  applyDefaultPdfStrictChecks,
13
- cssLength,
14
13
  ensureProjectGitignore,
15
14
  extensionConfigFor,
16
- formatPageSize,
17
- isNonNegativePoints,
18
- isPositivePoints,
19
- judgeRect,
20
15
  listProjectExtensions,
21
16
  loadManifest,
22
17
  loadManifestDoc,
23
18
  loadManifestWithPath,
24
19
  npmRegistryUrl,
25
- pageBoxes,
26
- printAreaMeta,
27
20
  publishTargetFor,
28
21
  readEntryCss,
29
22
  resolveConfig,
@@ -31,13 +24,12 @@ import {
31
24
  resolvePort,
32
25
  resolveTargets,
33
26
  restoreForCommand,
34
- round3,
35
27
  scalarString,
36
28
  uniqueExtensionId,
37
29
  validatePageMargin,
38
30
  withFetchTimeout,
39
31
  writeManifestDoc
40
- } from "./index-hphcn7th.js";
32
+ } from "./index-rj5vrhz6.js";
41
33
  import {
42
34
  EXTENSION_MANIFEST_FILENAME,
43
35
  GUTTERPRESS_CSS,
@@ -73,7 +65,7 @@ import {
73
65
  setLogLevel,
74
66
  slugify,
75
67
  warn
76
- } from "./index-fp7xwvpr.js";
68
+ } from "./index-a4j3xcfp.js";
77
69
  import {
78
70
  blackTextToGray
79
71
  } from "./index-ht1bcqdd.js";
@@ -84,10 +76,18 @@ import {
84
76
  getAssetPath,
85
77
  lastPageMode,
86
78
  resolvePage
87
- } from "./index-2vxzxyyj.js";
79
+ } from "./index-798jt0qc.js";
88
80
  import {
89
- BuildError
90
- } from "./index-46ycxe6r.js";
81
+ BuildError,
82
+ cssLength,
83
+ formatPageSize,
84
+ isNonNegativePoints,
85
+ isPositivePoints,
86
+ judgeRect,
87
+ pageBoxes,
88
+ printAreaMeta,
89
+ round3
90
+ } from "./index-tayzfr9c.js";
91
91
  import {
92
92
  countLinkAnnotations,
93
93
  getImageResolutions,
@@ -166,8 +166,8 @@ var MSG_OFFLINE = "Your changes are saved on this computer. Gutterpress couldn't
166
166
  var MSG_AUTH = "The online copy didn't accept the saved sign-in. Sign in again and try again.";
167
167
  var MSG_INSECURE_TRANSPORT = "This book's online copy is at an address that isn't secure, so the saved sign-in wasn't sent — sign-ins are never sent over an insecure address. Switch the address to a secure one (starting with https), or to a local loopback address for a server on this computer, to back up.";
168
168
  var MSG_BUSY = "The online copy is changing very quickly right now. Your work is saved on this computer — try again in a moment.";
169
- var MSG_HISTORY_UNREADABLE = `This book's versions can't be read, so backing up can't continue. Your writing is safe — every file is still here on this computer. Use "Repair the online copy" (in Book setup → Online copy) to get versions and backing up working again.`;
170
- var MSG_UNRELATED = `This book and the online copy have no versions in common, so they can't be combined. Either the online copy's address points at a different book, or this book's own versions were lost and started over. Your writing is safe — every file is still here on this computer. Check the online copy's address; if it is correct, use "Repair the online copy" (in Book setup → Online copy).`;
169
+ var MSG_HISTORY_UNREADABLE = `This book's versions can't be read, so backing up can't continue. Your writing is safe — every file is still here on this computer. Use "Repair the online copy" in Book setup to get versions and backing up working again.`;
170
+ var MSG_UNRELATED = `This book and the online copy have no versions in common, so they can't be combined. Either the online copy's address points at a different book, or this book's own versions were lost and started over. Your writing is safe — every file is still here on this computer. Check the online copy's address; if it is correct, use "Repair the online copy" in Book setup.`;
171
171
  var MSG_NO_REMOTE = "This book doesn't have an online copy yet.";
172
172
  var MSG_SSH_REMOTE = "This book's online copy uses an SSH address (git@…), which Gutterpress can't back up to. Switch it to the web (HTTPS) address to back up from here.";
173
173
  var MSG_NO_BRANCH = "This book isn't on a named revision, so it can't be backed up right now.";
@@ -202,6 +202,7 @@ function canonicalChapterId(p) {
202
202
  }
203
203
 
204
204
  // src/lib/markdown/assemble.ts
205
+ import postcss from "postcss";
205
206
  function pageGeometryCss(page) {
206
207
  if (!page || !isPositivePoints(page.width) || !isPositivePoints(page.height))
207
208
  return null;
@@ -222,6 +223,65 @@ function defaultPageMarginCss(page) {
222
223
  @page { margin: ${cssLength(DEFAULT_PAGE_MARGIN_PT)}; }
223
224
  }`;
224
225
  }
226
+ function liftPageRules(css) {
227
+ if (!/@page\b/i.test(css))
228
+ return { layered: css, pages: "" };
229
+ let root;
230
+ try {
231
+ root = postcss.parse(css);
232
+ } catch {
233
+ return { layered: css, pages: "" };
234
+ }
235
+ const found = [];
236
+ root.walkAtRules(/^page$/i, (rule) => {
237
+ found.push(rule);
238
+ });
239
+ const pages = found.map((rule) => {
240
+ let lifted = rule.clone();
241
+ for (let p = rule.parent;p instanceof postcss.AtRule || p instanceof postcss.Rule; p = p.parent) {
242
+ if (p instanceof postcss.AtRule && p.name.toLowerCase() === "layer")
243
+ continue;
244
+ lifted = p.clone({ nodes: [] }).append(lifted);
245
+ }
246
+ rule.remove();
247
+ return lifted.toString();
248
+ });
249
+ return { layered: root.toString(), pages: pages.join(`
250
+ `) };
251
+ }
252
+ var CORE_MARKERS = liftPageRules(`${MARKER_CSS.trim()}
253
+ ${TWO_VERSIONS_CSS.trim()}`);
254
+ var CORE_VOCAB = liftPageRules(GUTTERPRESS_CSS.trim());
255
+ function assembleCssChunks(opts) {
256
+ const core = (css) => css ? [{ origin: { kind: "core" }, css }] : [];
257
+ const headed = (title, chunks = []) => chunks.map((chunk, i) => i === 0 ? { ...chunk, css: `/* ${title} */
258
+ ${chunk.css.trim()}` } : chunk);
259
+ const pageGeometry = pageGeometryCss(opts.printArea);
260
+ const defaultMargin = defaultPageMarginCss(opts.printArea);
261
+ return [
262
+ ...core("@layer gp.marker, gp.vocab;"),
263
+ ...core(`/* gutterpress markers */
264
+ @layer gp.marker {
265
+ ${CORE_MARKERS.layered.trim()}
266
+ }`),
267
+ ...core(CORE_MARKERS.pages && `/* gutterpress markers: page rules */
268
+ ${CORE_MARKERS.pages}`),
269
+ ...core(`/* gutterpress */
270
+ @layer gp.vocab {
271
+ ${CORE_VOCAB.layered.trim()}
272
+ }`),
273
+ ...core(CORE_VOCAB.pages && `/* gutterpress: page rules */
274
+ ${CORE_VOCAB.pages}`),
275
+ ...core(defaultMargin && `/* page margins (default) */
276
+ ${defaultMargin}`),
277
+ ...headed("extension css", opts.extensions),
278
+ ...core(`/* column alignment */
279
+ ${TABLE_ALIGN_CSS.trim()}`),
280
+ ...headed("project css", opts.book),
281
+ ...core(pageGeometry && `/* page geometry (manifest) */
282
+ ${pageGeometry}`)
283
+ ];
284
+ }
225
285
  async function assembleBookHtml(opts) {
226
286
  const title = opts.title ?? "Document";
227
287
  const projectCss = opts.projectCss ?? "";
@@ -260,30 +320,11 @@ async function assembleBookHtml(opts) {
260
320
  imageRefs.add(ref);
261
321
  opts.onImageRefs([...imageRefs]);
262
322
  }
263
- const pageGeometry = pageGeometryCss(opts.printArea);
264
- const defaultMargin = defaultPageMarginCss(opts.printArea);
265
- const inlineCss = [
266
- "@layer gp.marker, gp.vocab;",
267
- `/* gutterpress markers */
268
- @layer gp.marker {
269
- ${MARKER_CSS.trim()}
270
- ${TWO_VERSIONS_CSS.trim()}
271
- }`,
272
- `/* gutterpress */
273
- @layer gp.vocab {
274
- ${GUTTERPRESS_CSS.trim()}
275
- }`,
276
- defaultMargin ? `/* page margins (default) */
277
- ${defaultMargin}` : null,
278
- pluginCss ? `/* extension css */
279
- ${pluginCss.trim()}` : null,
280
- `/* column alignment */
281
- ${TABLE_ALIGN_CSS.trim()}`,
282
- projectCss ? `/* project css */
283
- ${projectCss.trim()}` : null,
284
- pageGeometry ? `/* page geometry (manifest) */
285
- ${pageGeometry}` : null
286
- ].filter(Boolean).join(`
323
+ const inlineCss = assembleCssChunks({
324
+ printArea: opts.printArea,
325
+ extensions: pluginCss ? [{ origin: { kind: "extension" }, css: pluginCss }] : [],
326
+ book: projectCss ? [{ origin: { kind: "book" }, css: projectCss }] : []
327
+ }).map((chunk) => chunk.css).join(`
287
328
 
288
329
  `);
289
330
  const preloadTags = (opts.preloadImages ?? []).map((href) => `
@@ -396,7 +437,7 @@ async function listProjectStyles(projectDir, opts = {}) {
396
437
  import { createHash } from "node:crypto";
397
438
  import { readFile } from "node:fs/promises";
398
439
  import path2 from "node:path";
399
- import postcss from "postcss";
440
+ import postcss2 from "postcss";
400
441
  var FONT_EXTS = new Set([".woff2", ".woff", ".ttf", ".otf"]);
401
442
  var HASHED_ASSET_DIR = "assets";
402
443
  var MIME_BY_EXT = {
@@ -496,15 +537,15 @@ function wrapImportConditions(node, imported) {
496
537
  const layer = media.match(/\blayer\(([^)]*)\)|\blayer\b/i);
497
538
  if (layer) {
498
539
  media = media.replace(layer[0], "").trim();
499
- inner = postcss.atRule({ name: "layer", params: (layer[1] ?? "").trim(), nodes: [inner] });
540
+ inner = postcss2.atRule({ name: "layer", params: (layer[1] ?? "").trim(), nodes: [inner] });
500
541
  }
501
542
  const supports = media.match(/\bsupports\(([\s\S]*)\)/i);
502
543
  if (supports) {
503
544
  media = media.replace(supports[0], "").trim();
504
- inner = postcss.atRule({ name: "supports", params: (supports[1] ?? "").trim(), nodes: [inner] });
545
+ inner = postcss2.atRule({ name: "supports", params: (supports[1] ?? "").trim(), nodes: [inner] });
505
546
  }
506
547
  if (media) {
507
- inner = postcss.atRule({ name: "media", params: media, nodes: [inner] });
548
+ inner = postcss2.atRule({ name: "media", params: media, nodes: [inner] });
508
549
  }
509
550
  return inner;
510
551
  }
@@ -526,7 +567,7 @@ async function inlineOne(cssPath, copies, warnings, seen) {
526
567
  const cssDir = path2.dirname(abs);
527
568
  let root;
528
569
  try {
529
- root = postcss.parse(source.toString("utf-8"), { from: abs });
570
+ root = postcss2.parse(source.toString("utf-8"), { from: abs });
530
571
  } catch (err) {
531
572
  throw new BuildError(`Could not parse CSS: ${abs}
532
573
  ${err instanceof Error ? err.message : String(err)}`, 1);
@@ -566,7 +607,7 @@ async function inlineOne(cssPath, copies, warnings, seen) {
566
607
  for (const { node, target } of imports) {
567
608
  const importedAbs = path2.resolve(cssDir, stripUrlSuffix(decodeRef(target)));
568
609
  const inlined = await inlineOne(importedAbs, copies, warnings, seen);
569
- node.replaceWith(wrapImportConditions(node, postcss.parse(inlined, { from: importedAbs })));
610
+ node.replaceWith(wrapImportConditions(node, postcss2.parse(inlined, { from: importedAbs })));
570
611
  }
571
612
  return root.toString();
572
613
  }
@@ -608,7 +649,7 @@ async function collectStyleDependencies(projectDir, stylePaths) {
608
649
  }
609
650
  let root;
610
651
  try {
611
- root = postcss.parse(source, { from: abs });
652
+ root = postcss2.parse(source, { from: abs });
612
653
  } catch {
613
654
  return;
614
655
  }
@@ -705,6 +746,7 @@ async function resolveActiveMarkdownFiles(inputDir, configuredFiles) {
705
746
  async function renderChapters(inputDir, opts = {}) {
706
747
  const styles = await resolveActiveStyles(inputDir, opts.styles);
707
748
  const inlined = await inlineStyles(inputDir, styles);
749
+ const book = liftPageRules(inlined.css);
708
750
  const blocks = [];
709
751
  const layers = [];
710
752
  const styleWarnings = [];
@@ -719,10 +761,13 @@ async function renderChapters(inputDir, opts = {}) {
719
761
  if (!css)
720
762
  continue;
721
763
  layers.push(group.layer);
764
+ const { layered, pages } = liftPageRules(css);
722
765
  blocks.push(`/* ${group.name} */
723
766
  @layer ${group.layer} {
724
- ${css.trim()}
725
- }`);
767
+ ${layered.trim()}
768
+ }` + (pages ? `
769
+ /* ${group.name}: page rules */
770
+ ${pages}` : ""));
726
771
  }
727
772
  styleWarnings.push(...inlined.warnings);
728
773
  if (styleWarnings.length > 0)
@@ -740,7 +785,8 @@ ${css.trim()}
740
785
  return assembleBookHtml({
741
786
  files,
742
787
  readText: (relPath) => readFile2(join(inputDir, canonicalChapterId(relPath)), "utf-8"),
743
- projectCss: inlined.css,
788
+ projectCss: book.pages ? `${book.layered.trim()}
789
+ ${book.pages}` : inlined.css,
744
790
  preloadImages: cssAssetCopies.map((c) => c.to),
745
791
  title: opts.title,
746
792
  language: opts.language,
@@ -2737,7 +2783,7 @@ registerCheck(check19);
2737
2783
  import { readFile as readFile11 } from "node:fs/promises";
2738
2784
 
2739
2785
  // src/lib/printsafe.ts
2740
- import postcss2 from "postcss";
2786
+ import postcss3 from "postcss";
2741
2787
 
2742
2788
  // src/lib/lint-rules.ts
2743
2789
  function ruleLevel(rules, id) {
@@ -3029,7 +3075,7 @@ function filterFindings(findings, css, rules) {
3029
3075
  function checkCssRaw(css, from) {
3030
3076
  let root;
3031
3077
  try {
3032
- root = postcss2.parse(css, from ? { from } : undefined);
3078
+ root = postcss3.parse(css, from ? { from } : undefined);
3033
3079
  } catch (err) {
3034
3080
  const e = err;
3035
3081
  return [
@@ -3063,7 +3109,7 @@ function checkCssRaw(css, from) {
3063
3109
  warnings.push({
3064
3110
  rule: rulePageSizeInStylesheet,
3065
3111
  severity: "warning",
3066
- message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — Setup > Book in the app), which is written after every stylesheet. Remove this declaration; to print at another size, change the manifest.`,
3112
+ message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — set them in Book setup), which is written after every stylesheet. Remove this declaration; to print at another size, change the manifest.`,
3067
3113
  ...nodeLoc(decl)
3068
3114
  });
3069
3115
  return;
@@ -3199,7 +3245,7 @@ registerCheck(check20);
3199
3245
 
3200
3246
  // src/checks/source/css-ownership.ts
3201
3247
  import { readFile as readFile12 } from "node:fs/promises";
3202
- import postcss3 from "postcss";
3248
+ import postcss4 from "postcss";
3203
3249
  import { parse as parseYaml2 } from "yaml";
3204
3250
  var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
3205
3251
  async function loadContract(configPath) {
@@ -3356,7 +3402,7 @@ var check21 = {
3356
3402
  }
3357
3403
  let root;
3358
3404
  try {
3359
- root = postcss3.parse(css, { from: absFile });
3405
+ root = postcss4.parse(css, { from: absFile });
3360
3406
  } catch {
3361
3407
  continue;
3362
3408
  }
@@ -3851,7 +3897,7 @@ registerCheck(check25);
3851
3897
  import { readFile as readFile15 } from "node:fs/promises";
3852
3898
 
3853
3899
  // src/lib/unknown-classes.ts
3854
- import postcss4 from "postcss";
3900
+ import postcss5 from "postcss";
3855
3901
  var EMITTED = new Set([
3856
3902
  "chapter",
3857
3903
  "spread",
@@ -3899,7 +3945,7 @@ function addSelectorClasses(selector, into) {
3899
3945
  }
3900
3946
  function addCssClasses(css, into) {
3901
3947
  try {
3902
- postcss4.parse(css).walk((node) => {
3948
+ postcss5.parse(css).walk((node) => {
3903
3949
  if (node.type === "rule")
3904
3950
  addSelectorClasses(node.selector, into);
3905
3951
  else if (node.type === "atrule") {
@@ -4097,7 +4143,7 @@ registerCheck(check27);
4097
4143
  import { readFile as readFile17 } from "node:fs/promises";
4098
4144
 
4099
4145
  // src/checks/source/character-table.ts
4100
- var CHARACTER_PATTERN = new RegExp("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u00A0\\u00AD\\u00B4\\u02BC" + "\\u061C\\u2000-\\u2015\\u2018\\u201B-\\u201D\\u201F\\u2022\\u2026" + "\\u2028-\\u202F\\u2032\\u2033\\u205F\\u2060\\u2066-\\u2069\\u2190\\u2192" + "\\u2194\\u21D2\\u2212\\u25AA\\u25E6\\u2605\\u2713\\u2714\\u2717\\u3000" + "\\uE000-\\uF8FF\\uFEFF\\uFF02\\uFF07\\uFFFD]" + "|\\p{Emoji_Presentation}|\\p{Extended_Pictographic}(?=\\uFE0F)" + "|(?<=[\\p{L}\\p{N}])\\u2019|\\u2019(?![\\p{L}\\p{N}])", "gu");
4146
+ var CHARACTER_PATTERN = new RegExp("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u00A0\\u00AD\\u00B4\\u02BC" + "\\u061C\\u2000-\\u2015\\u2018\\u201B-\\u201D\\u201F\\u2022\\u2026" + "\\u2028-\\u202F\\u2032\\u2033\\u205F\\u2060\\u2066-\\u2069\\u2190\\u2192" + "\\u2194\\u21D2\\u25AA\\u25E6\\u2605\\u2713\\u2714\\u2717\\u3000" + "\\uE000-\\uF8FF\\uFEFF\\uFF02\\uFF07\\uFFFD]" + "|\\p{Emoji_Presentation}|\\p{Extended_Pictographic}(?=\\uFE0F)" + "|(?<=[\\p{L}\\p{N}])\\u2019|\\u2019(?![\\p{L}\\p{N}])", "gu");
4101
4147
  var NAMED = {
4102
4148
  8212: ["Em dash", "typographer", "---"],
4103
4149
  8211: ["En dash", "typographer", "--"],
@@ -4118,7 +4164,6 @@ var NAMED = {
4118
4164
  8209: ["Non-breaking hyphen", "lookalike", "-"],
4119
4165
  8210: ["Figure dash", "lookalike", "-"],
4120
4166
  8213: ["Horizontal bar", "lookalike", "---"],
4121
- 8722: ["Minus sign", "lookalike", "-"],
4122
4167
  8226: ["Bullet", "symbol", "&bull;"],
4123
4168
  9702: ["White bullet", "symbol", "&#x25E6;"],
4124
4169
  9642: ["Small square", "symbol", "&squf;"],
@@ -5532,7 +5577,7 @@ class PdfOutput {
5532
5577
  const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
5533
5578
  await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
5534
5579
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
5535
- const { buildNativePdf } = await import("./engine-wm4fggac.js");
5580
+ const { buildNativePdf } = await import("./engine-wgkaqjsc.js");
5536
5581
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
5537
5582
  title: config.title,
5538
5583
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -7216,10 +7261,10 @@ function starterOverridesCss() {
7216
7261
  return `/**
7217
7262
  * Your book's own styles. Rules here win over your look's.
7218
7263
  *
7219
- * In the app you rarely need this file: Setup > Look chooses a look and
7220
- * changes its fonts and colors (those changes are saved here as :root
7221
- * custom properties), Setup > Advanced lists every setting, and Setup > Book
7222
- * sets the page size and margins (in the manifest).
7264
+ * In the app you rarely need this file: Book setup chooses a look, changes
7265
+ * its fonts and colors (those changes are saved here as :root custom
7266
+ * properties), lists every setting, and sets the page size and margins (in
7267
+ * the manifest).
7223
7268
  *
7224
7269
  * To change the look from the command line: gutterpress ext remove <old>
7225
7270
  * <book>, then gutterpress ext add <look> <book>.
@@ -8621,7 +8666,7 @@ async function setActiveStyles(projectDir, paths) {
8621
8666
  import path19 from "node:path";
8622
8667
  import { mkdir as mkdir10, readFile as readFile30, writeFile as writeFile12 } from "node:fs/promises";
8623
8668
  import git3 from "isomorphic-git";
8624
- import postcss5 from "postcss";
8669
+ import postcss6 from "postcss";
8625
8670
 
8626
8671
  // src/lib/remote-auth/transport.ts
8627
8672
  import git2 from "isomorphic-git";
@@ -9087,7 +9132,7 @@ function paragraphs(text) {
9087
9132
  }
9088
9133
  function cssRules(text) {
9089
9134
  try {
9090
- return postcss5.parse(text).nodes.map((node) => node.toString().trim()).filter((rule) => rule.length > 0);
9135
+ return postcss6.parse(text).nodes.map((node) => node.toString().trim()).filter((rule) => rule.length > 0);
9091
9136
  } catch {
9092
9137
  return textLines(text);
9093
9138
  }
@@ -9108,13 +9153,10 @@ function changeHint(filepath, before, after) {
9108
9153
  }
9109
9154
  return count > 0 ? `${plural(count, unit)} changed` : "changed";
9110
9155
  }
9111
- async function firstParent(dir, cache2, oid) {
9112
- const { commit } = await git3.readCommit({ fs: gitFs, dir, cache: cache2, oid });
9113
- return commit.parent[0] ?? null;
9114
- }
9115
- async function listVersionChanges(dir, oid, options = {}) {
9116
- const cache2 = options.cache ?? {};
9117
- const parent = await firstParent(dir, cache2, oid);
9156
+ async function listVersionChanges(projectDir, oid) {
9157
+ const dir = await repoDirFor(projectDir);
9158
+ const cache2 = {};
9159
+ const parent = (await git3.readCommit({ fs: gitFs, dir, cache: cache2, oid })).commit.parent[0] ?? null;
9118
9160
  const found = [];
9119
9161
  await git3.walk({
9120
9162
  fs: gitFs,
@@ -9185,30 +9227,41 @@ async function trackingTip(dir) {
9185
9227
  }
9186
9228
  return resolveOrNull(dir, `refs/remotes/${remote.remote}/${branch}`);
9187
9229
  }
9188
- async function isAncestor(dir, cache2, oid, ancestor) {
9189
- if (oid === ancestor)
9190
- return true;
9191
- try {
9192
- return await git3.isDescendent({ fs: gitFs, dir, cache: cache2, oid, ancestor });
9193
- } catch {
9194
- return false;
9195
- }
9196
- }
9197
9230
  async function describeVersions(projectDir, entries) {
9198
9231
  const dir = await repoDirFor(projectDir);
9199
- const cache2 = {};
9200
9232
  const tip = await trackingTip(dir);
9233
+ if (!tip)
9234
+ return entries.map((entry) => ({ ...entry, backedUp: null }));
9235
+ const cache2 = {};
9236
+ const shallow = await readFile30(path19.join(dir, ".git", "shallow"), "utf8").catch(() => "");
9237
+ const reached = new Set([tip]);
9238
+ const queued = new Set;
9239
+ const queue = [tip];
9201
9240
  const out = [];
9202
9241
  let olderAreBackedUp = false;
9203
9242
  for (const entry of entries) {
9204
- const { files, more } = await listVersionChanges(dir, entry.id, { cache: cache2 });
9205
- let backedUp = null;
9206
- if (tip) {
9207
- backedUp = olderAreBackedUp || await isAncestor(dir, cache2, tip, entry.id);
9208
- if (backedUp)
9209
- olderAreBackedUp = true;
9243
+ try {
9244
+ while (!olderAreBackedUp && !reached.has(entry.id) && queue.length > 0) {
9245
+ const oid = queue.shift();
9246
+ const { commit } = await git3.readCommit({ fs: gitFs, dir, cache: cache2, oid });
9247
+ for (const parent of commit.parent)
9248
+ reached.add(parent);
9249
+ if (shallow.includes(oid))
9250
+ continue;
9251
+ for (const parent of commit.parent) {
9252
+ if (queued.has(parent))
9253
+ continue;
9254
+ queued.add(parent);
9255
+ queue.push(parent);
9256
+ }
9257
+ }
9258
+ } catch {
9259
+ queue.length = 0;
9210
9260
  }
9211
- out.push({ ...entry, changes: files, moreChanges: more, backedUp });
9261
+ const backedUp = olderAreBackedUp || reached.has(entry.id);
9262
+ if (backedUp)
9263
+ olderAreBackedUp = true;
9264
+ out.push({ ...entry, backedUp });
9212
9265
  }
9213
9266
  return out;
9214
9267
  }
@@ -9258,12 +9311,8 @@ async function listOnlineVersions(options) {
9258
9311
  const local = await resolveOrNull(dir, branch);
9259
9312
  if (!tip || !local)
9260
9313
  return { entries: [] };
9261
- const entries = [];
9262
- for (const entry of await commitsAhead(dir, tip, local, cache2)) {
9263
- const { files, more } = await listVersionChanges(dir, entry.id, { cache: cache2 });
9264
- entries.push({ ...entry, changes: files, moreChanges: more, backedUp: true });
9265
- }
9266
- return { entries };
9314
+ const entries = await commitsAhead(dir, tip, local, cache2);
9315
+ return { entries: entries.map((entry) => ({ ...entry, backedUp: true })) };
9267
9316
  } catch (e) {
9268
9317
  const message = e?.message ?? "";
9269
9318
  if (message === MSG_NO_REMOTE || message === MSG_SSH_REMOTE)
@@ -9953,9 +10002,9 @@ function isMergeConflictError(e) {
9953
10002
  function isCheckoutConflict(e) {
9954
10003
  return e?.code === "CheckoutConflictError";
9955
10004
  }
9956
- var CONVERGE_PREPARE_MESSAGE = "Getting your changes ready to combine with the online version";
9957
- var CONVERGE_RESTORE_MESSAGE = "Kept both versions of the files that can't be combined";
9958
- var CONVERGE_MERGE_MESSAGE = "Combined your changes with the online version";
10005
+ var CONVERGE_PREPARE_MESSAGE = "Getting your changes ready to combine with the online copy's changes";
10006
+ var CONVERGE_RESTORE_MESSAGE = "Kept both takes of the files that can't be combined";
10007
+ var CONVERGE_MERGE_MESSAGE = "Combined your changes with the online copy's";
9959
10008
  var MARKER_UNSAFE_EXT = /\.svg$/i;
9960
10009
  var OUR_LABEL = YOUR_VERSION_LABEL;
9961
10010
  var THEIR_LABEL = ONLINE_VERSION_LABEL;
@@ -10485,8 +10534,8 @@ var API_BASE3 = "https://api.github.com";
10485
10534
  var REQUEST_TIMEOUT_MS4 = 15000;
10486
10535
  var MAX_NAME_LENGTH = 100;
10487
10536
  var MSG = {
10488
- notConnected: "Connect your GitHub account first (Settings > Accounts), then set up the online copy.",
10489
- auth: "GitHub didn't accept the saved sign-in. Sign in to GitHub again in Settings > Accounts and try again.",
10537
+ notConnected: "Connect your GitHub account first, then set up the online copy.",
10538
+ auth: "GitHub didn't accept the saved sign-in. Sign in to GitHub again and try again.",
10490
10539
  offline: "Gutterpress couldn't reach GitHub. Check your internet connection and try again. Nothing was changed.",
10491
10540
  noHistory: "Turn on version history for this book first. The online copy holds the versions Gutterpress keeps on this computer.",
10492
10541
  alreadyHasRemote: "This book already has an online copy.",
@@ -11659,13 +11708,13 @@ async function createFolder(fetchImpl, accessToken, name) {
11659
11708
  throw await driveFailure(res, `Couldn't create the Google Drive folder "${name}"`);
11660
11709
  return await res.json();
11661
11710
  }
11662
- async function findFolderByName(fetchImpl, accessToken, name) {
11711
+ async function findFoldersByName(fetchImpl, accessToken, name, limit = 1) {
11663
11712
  const q = `name='${escapeDriveQueryValue(name)}' and mimeType='${FOLDER_MIME}' and trashed=false`;
11664
11713
  const params = new URLSearchParams({
11665
11714
  q,
11666
11715
  fields: "files(id,name)",
11667
11716
  orderBy: "modifiedTime desc",
11668
- pageSize: "1"
11717
+ pageSize: String(limit)
11669
11718
  });
11670
11719
  const res = await driveFetch(fetchImpl, `${DRIVE_API_BASE}/files?${params.toString()}`, {
11671
11720
  method: "GET",
@@ -11674,10 +11723,10 @@ async function findFolderByName(fetchImpl, accessToken, name) {
11674
11723
  if (!res.ok)
11675
11724
  throw await driveFailure(res, `Couldn't look up the Google Drive folder "${name}"`);
11676
11725
  const body = await res.json();
11677
- return body.files?.[0] ?? null;
11726
+ return body.files ?? [];
11678
11727
  }
11679
11728
  async function ensureFolder(fetchImpl, accessToken, name) {
11680
- const found = await findFolderByName(fetchImpl, accessToken, name);
11729
+ const [found] = await findFoldersByName(fetchImpl, accessToken, name);
11681
11730
  if (found)
11682
11731
  return found;
11683
11732
  return createFolder(fetchImpl, accessToken, name);
@@ -11810,8 +11859,80 @@ async function resumableUpload(fetchImpl, accessToken, opts) {
11810
11859
  }
11811
11860
  }
11812
11861
 
11813
- // src/lib/publish/providers/gdrive.ts
11862
+ // src/lib/publish/providers/gdrive-folder.ts
11814
11863
  var DEFAULT_FOLDER_NAME = "Gutterpress";
11864
+ var NO_OWN_FOLDER = { myFolderId: "", myFolder: "", myFolderFor: "", myFolderAccount: "" };
11865
+ function readConfig(req) {
11866
+ const text = (key) => {
11867
+ const value = req.config[key];
11868
+ return (typeof value === "string" ? value.trim() : "") || undefined;
11869
+ };
11870
+ return {
11871
+ folder: text("folder"),
11872
+ folderId: text("folderId"),
11873
+ myFolderId: text("myFolderId"),
11874
+ myFolder: text("myFolder"),
11875
+ myFolderFor: text("myFolderFor"),
11876
+ myFolderAccount: text("myFolderAccount"),
11877
+ account: req.deps.credentialAccount?.trim() ?? ""
11878
+ };
11879
+ }
11880
+ async function resolveFolder(req, accessToken) {
11881
+ const fetchImpl = req.deps.fetch ?? globalThis.fetch;
11882
+ const cfg = readConfig(req);
11883
+ let found = [];
11884
+ if (cfg.folderId) {
11885
+ const folder = await getFolderById(fetchImpl, accessToken, cfg.folderId);
11886
+ if (folder)
11887
+ found = [folder];
11888
+ } else if (cfg.folder) {
11889
+ found = await findFoldersByName(fetchImpl, accessToken, cfg.folder, 2);
11890
+ }
11891
+ const first = found[0];
11892
+ const book = { title: cfg.folder || cfg.folderId || "", reachable: !cfg.folderId || !!first };
11893
+ if (cfg.myFolderId) {
11894
+ const bookKey = cfg.folderId || cfg.folder;
11895
+ if (bookKey && cfg.myFolderFor === bookKey && (cfg.myFolderAccount ?? "") === cfg.account) {
11896
+ const mine = await getFolderById(fetchImpl, accessToken, cfg.myFolderId);
11897
+ return mine ? { state: "mine", destination: toDestination(mine), book } : { state: "unreachable", book, mine: cfg.myFolder || cfg.myFolderId };
11898
+ }
11899
+ if (book.reachable) {
11900
+ await req.deps.selections?.setSettings(req.project.projectDir, "gdrive", NO_OWN_FOLDER);
11901
+ }
11902
+ }
11903
+ if (cfg.folderId) {
11904
+ return first ? { state: "book", destination: toDestination(first) } : { state: "unreachable", book };
11905
+ }
11906
+ if (cfg.folder) {
11907
+ return {
11908
+ state: "by-name",
11909
+ name: cfg.folder,
11910
+ ...first ? { destination: toDestination(first) } : {},
11911
+ several: found.length > 1
11912
+ };
11913
+ }
11914
+ return { state: "unset" };
11915
+ }
11916
+ async function uploadFolder(where, fetchImpl, accessToken) {
11917
+ switch (where.state) {
11918
+ case "unreachable":
11919
+ throw new Error(where.mine ? `Your own Drive folder "${where.mine}" for this book can't be reached any more: it was trashed or deleted, or belongs to another Google account. Choose a folder you can reach on the Google Drive step (it is saved for you only).` : `This book publishes to the Drive folder "${where.book.title}", which this Google account can't reach: it isn't shared with Gutterpress under this account, or it was trashed or deleted. The book keeps its folder for everyone else. To publish to a folder you can reach, choose one for yourself on the Google Drive step in the desktop app (saved for you only), or pass --folder-id <id> or --folder <name> to "gutterpress publish" for one run.`);
11920
+ case "unset":
11921
+ return toDestination(await ensureFolder(fetchImpl, accessToken, DEFAULT_FOLDER_NAME));
11922
+ case "by-name":
11923
+ return where.destination ?? toDestination(await createFolder(fetchImpl, accessToken, where.name));
11924
+ default:
11925
+ return where.destination;
11926
+ }
11927
+ }
11928
+ function folderUrl(id) {
11929
+ return `https://drive.google.com/drive/folders/${id}`;
11930
+ }
11931
+ function toDestination(folder) {
11932
+ return { id: folder.id, title: folder.name, url: folderUrl(folder.id) };
11933
+ }
11934
+
11935
+ // src/lib/publish/providers/gdrive.ts
11815
11936
  var NOT_CONNECTED_MESSAGE = "Google Drive isn't connected. Run `gutterpress publish --provider gdrive --connect` (or set GDRIVE_REFRESH_TOKEN) first.";
11816
11937
  var info5 = {
11817
11938
  id: "gdrive",
@@ -11830,13 +11951,6 @@ var info5 = {
11830
11951
  },
11831
11952
  destinations: { label: "Folder", canCreate: true }
11832
11953
  };
11833
- function readConfig(req) {
11834
- const cfg = req.config;
11835
- return {
11836
- folder: cfg.folder?.trim() || undefined,
11837
- folderId: cfg.folderId?.trim() || undefined
11838
- };
11839
- }
11840
11954
  function formatBytes(bytes) {
11841
11955
  if (bytes < 1024 * 1024)
11842
11956
  return `${(bytes / 1024).toFixed(0)} KB`;
@@ -11858,22 +11972,6 @@ async function getAccessToken(req) {
11858
11972
  const accessToken = await mintAccessToken(resolved, req.deps.fetch ?? globalThis.fetch);
11859
11973
  return { accessToken, source: resolved.source };
11860
11974
  }
11861
- async function resolveFolder(fetchImpl, accessToken, cfg) {
11862
- if (cfg.folderId) {
11863
- const folder = await getFolderById(fetchImpl, accessToken, cfg.folderId);
11864
- if (!folder) {
11865
- throw new Error(`The Drive folder recorded in publish.gdrive.folderId ("${cfg.folderId}") can't be found — it may have been trashed or the id copied wrong. Pick the folder again.`);
11866
- }
11867
- return folder;
11868
- }
11869
- return ensureFolder(fetchImpl, accessToken, cfg.folder || DEFAULT_FOLDER_NAME);
11870
- }
11871
- function folderUrl(id) {
11872
- return `https://drive.google.com/drive/folders/${id}`;
11873
- }
11874
- function toDestination(folder) {
11875
- return { id: folder.id, title: folder.name, url: folderUrl(folder.id) };
11876
- }
11877
11975
  var ZIP_CHUNK_BYTES = 64 * 1024;
11878
11976
  function yieldToEventLoop() {
11879
11977
  return new Promise((resolve6) => setImmediate(resolve6));
@@ -12000,9 +12098,12 @@ var gdriveProvider = {
12000
12098
  const folder = await createFolder(req.deps.fetch ?? globalThis.fetch, accessToken, name);
12001
12099
  return toDestination(folder);
12002
12100
  },
12101
+ async destinationStatus(req) {
12102
+ const { accessToken } = await getAccessToken(req);
12103
+ return resolveFolder(req, accessToken);
12104
+ },
12003
12105
  async upload(req) {
12004
12106
  const fetchImpl = req.deps.fetch ?? globalThis.fetch;
12005
- const cfg = readConfig(req);
12006
12107
  const { accessToken } = await getAccessToken(req);
12007
12108
  const isHtml = req.artifact.format === "html";
12008
12109
  const source = isHtml ? await zipHtmlExport(req.artifact.path, req.project.title, (msg) => req.deps.onProgress?.(msg)) : {
@@ -12020,10 +12121,11 @@ var gdriveProvider = {
12020
12121
  }
12021
12122
  }
12022
12123
  req.deps.onProgress?.("Resolving the Drive folder…");
12023
- const folder = await resolveFolder(fetchImpl, accessToken, cfg);
12124
+ const where = await resolveFolder(req, accessToken);
12125
+ const folder = await uploadFolder(where, fetchImpl, accessToken);
12024
12126
  const fileName = source.fileName;
12025
12127
  const existing = await findFileInFolder(fetchImpl, accessToken, folder.id, fileName);
12026
- req.deps.onProgress?.(existing ? `Updating "${fileName}" in "${folder.name}"…` : `Uploading "${fileName}" to "${folder.name}"…`);
12128
+ req.deps.onProgress?.(existing ? `Updating "${fileName}" in "${folder.title}"…` : `Uploading "${fileName}" to "${folder.title}"…`);
12027
12129
  let lastReported = -1;
12028
12130
  const file = await resumableUpload(fetchImpl, accessToken, {
12029
12131
  ...existing ? { fileId: existing.id } : {},
@@ -12043,11 +12145,11 @@ var gdriveProvider = {
12043
12145
  return {
12044
12146
  kind: "published",
12045
12147
  url: file.webViewLink,
12046
- detail: `Uploaded "${fileName}" to the "${folder.name}" folder in your Google Drive${existing ? " (updated the existing file)" : ""}.`,
12148
+ detail: `Uploaded "${fileName}" to the "${folder.title}" folder in your Google Drive${existing ? " (updated the existing file)" : ""}.` + (where.state === "by-name" && where.several ? ` Several of your folders are named "${where.name}"; this is the most recently changed one: ${folder.url}` : ""),
12047
12149
  followUp: [
12048
12150
  "To share it, open it in Drive and use the Share button — Gutterpress never changes who can see your files.",
12049
12151
  isHtml ? "Google Drive stores files, not live websites — download and unzip it to view the export, or publish it as a real site with the Azure Static Web Apps provider." : undefined,
12050
- cfg.folderId ? undefined : `Tip (CLI): record the folder id in the manifest (publish.gdrive.folderId: "${folder.id}") so renaming the folder in Drive can never break publishing.`
12152
+ where.state === "unset" ? `Tip (CLI): record the folder id in the manifest (publish.gdrive.folderId: "${folder.id}") so renaming the folder in Drive can never break publishing.` : undefined
12051
12153
  ].filter((s) => !!s)
12052
12154
  };
12053
12155
  } finally {
@@ -12659,7 +12761,7 @@ async function resolvePublishProvider(id, book) {
12659
12761
  const ext = await bookExtensions(book);
12660
12762
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
12661
12763
  if (npmEntry) {
12662
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-vghc58vx.js");
12764
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-5x4mj79d.js");
12663
12765
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
12664
12766
  }
12665
12767
  const publishers = await discover(ext);
@@ -12697,7 +12799,7 @@ function infoFor(p) {
12697
12799
  }
12698
12800
  function pluginProvider(p) {
12699
12801
  let loading;
12700
- const load = () => loading ??= import("./plugins-3aj0wc5h.js").then((m) => m.loadPublishFunction(p));
12802
+ const load = () => loading ??= import("./plugins-bcbe7xs8.js").then((m) => m.loadPublishFunction(p));
12701
12803
  return {
12702
12804
  info: infoFor(p),
12703
12805
  async authenticate() {
@@ -12766,7 +12868,8 @@ async function requestFor(provider, options, deps) {
12766
12868
  const publishSettings = manifest.publish ?? {};
12767
12869
  const providerConfig = {
12768
12870
  ...publishSettings[provider.info.id] ?? {},
12769
- ...(await deps.selections?.settings(options.projectDir))?.[provider.info.id] ?? {}
12871
+ ...(await deps.selections?.settings(options.projectDir))?.[provider.info.id] ?? {},
12872
+ ...options.settings
12770
12873
  };
12771
12874
  const bookAccount = typeof providerConfig.credential === "string" ? providerConfig.credential.trim() : "";
12772
12875
  const effectiveAccount = bookAccount || deps.credentialAccount;
@@ -13145,19 +13248,26 @@ async function savePublishSettings(projectDir, providerId, values, selections) {
13145
13248
  if (inside !== null) {
13146
13249
  shared[key] = inside;
13147
13250
  mine[key] = "";
13148
- } else if (isDir || key === "credential") {
13251
+ } else if (isDir || key === "credential" || providerId === "gdrive" && key.startsWith("myFolder")) {
13149
13252
  mine[key] = isDir && text ? path31.resolve(projectDir, text) : text;
13150
13253
  shared[key] = "";
13151
13254
  } else {
13152
13255
  shared[key] = value;
13153
13256
  }
13154
13257
  }
13258
+ const inManifest = (await readPublishSettings(projectDir))[providerId] ?? {};
13259
+ if ("myFolderId" in mine) {
13260
+ const own = !!mine.myFolderId;
13261
+ const account = mine.credential ?? (await selections.settings(projectDir))[providerId]?.credential;
13262
+ mine.myFolder = own ? mine.myFolder ?? "" : "";
13263
+ mine.myFolderFor = own ? String(inManifest.folderId || inManifest.folder || "") : "";
13264
+ mine.myFolderAccount = own ? account ?? String(inManifest.credential ?? "") : "";
13265
+ }
13155
13266
  if (Object.keys(mine).length > 0)
13156
13267
  await selections.setSettings(projectDir, providerId, mine);
13157
- const inManifest = (await readPublishSettings(projectDir))[providerId] ?? {};
13158
13268
  const changes = Object.fromEntries(Object.entries(shared).filter(([key, value]) => value !== "" || (key in inManifest)));
13159
13269
  if (Object.keys(changes).length > 0)
13160
13270
  await setPublishProviderConfig(projectDir, providerId, changes);
13161
13271
  return readPublishSettings(projectDir, selections);
13162
13272
  }
13163
- export { SYNC_SNAPSHOT_MESSAGE, resolveActiveStyles, listProjectStyles, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, readPageSetup, setPageSetup, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, saveSnippet, deleteSnippet, listMergedSnippets, listMarkerComponents, listLocationVariants, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, VERSION_CHANGES_SHOWN, describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, syncProject, refreshRemoteCopies, checkRemoteUpdates, isValidRepositoryName, setUpOnlineBackup, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, renameRevision, deleteRevision, REPAIR_SNAPSHOT_MESSAGE, repairOnlineBackup, scorchedEarth, listPublishProviders, publishProviderFor, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig, savePublishSettings };
13273
+ export { SYNC_SNAPSHOT_MESSAGE, assembleCssChunks, relDisplay, resolveActiveStyles, listProjectStyles, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, readPageSetup, setPageSetup, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, saveSnippet, deleteSnippet, listMergedSnippets, listMarkerComponents, listLocationVariants, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, VERSION_CHANGES_SHOWN, listVersionChanges, describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, syncProject, refreshRemoteCopies, checkRemoteUpdates, isValidRepositoryName, setUpOnlineBackup, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, renameRevision, deleteRevision, REPAIR_SNAPSHOT_MESSAGE, repairOnlineBackup, scorchedEarth, listPublishProviders, publishProviderFor, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig, savePublishSettings };