gutterpress 0.10.0 → 0.10.1-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 (54) hide show
  1. package/README.md +3 -16
  2. package/dist/api/index.d.ts +10 -19
  3. package/dist/api/index.js +8 -64
  4. package/dist/{audit-cvarpa72.js → audit-7a37g51p.js} +5 -5
  5. package/dist/{build-6r502chw.js → build-kdaet3pd.js} +5 -5
  6. package/dist/checks/source/index.d.ts +1 -0
  7. package/dist/checks/source/merge-markers.d.ts +3 -0
  8. package/dist/{cli-zfcryxg8.js → cli-ak1tagkr.js} +94 -57
  9. package/dist/{cli-eq5naw4m.js → cli-df7gcyns.js} +370 -1249
  10. package/dist/{cli-149edp6b.js → cli-dx6sxj2t.js} +1 -1
  11. package/dist/{cli-cqtggsng.js → cli-mcb484g3.js} +2 -47
  12. package/dist/{cli-k1065rkg.js → cli-w692g6dx.js} +75 -29
  13. package/dist/cli.js +14 -15
  14. package/dist/{doctor-akvxbtjb.js → doctor-vajd5h45.js} +2 -2
  15. package/dist/{engine-b159tbns.js → engine-0nt35svz.js} +2 -2
  16. package/dist/{engine-ft4cr3ep.js → engine-gkcqdye5.js} +1 -1
  17. package/dist/{gutterpress-viewer-te8g5grx.js → gutterpress-viewer-tma1qwz2.js} +57 -15
  18. package/dist/{index-ge7q9xj3.js → index-6g72h2n1.js} +771 -1482
  19. package/dist/{index-ycpvr0am.js → index-b2rqw41a.js} +1 -1
  20. package/dist/{index-mdefp0y5.js → index-dtrftayr.js} +75 -27
  21. package/dist/{index-wq3r5pj7.js → index-kvgq4q3q.js} +94 -57
  22. package/dist/index.js +9 -65
  23. package/dist/lib/git-fs.d.ts +43 -0
  24. package/dist/lib/host-policy.d.ts +14 -2
  25. package/dist/lib/remote-auth/clone.d.ts +0 -21
  26. package/dist/lib/remote-auth/converge-merge.d.ts +24 -7
  27. package/dist/lib/remote-auth/generic-auth.d.ts +0 -22
  28. package/dist/lib/remote-auth/git-http.d.ts +1 -1
  29. package/dist/lib/remote-auth/github-auth.d.ts +2 -22
  30. package/dist/lib/remote-auth/operation-log.d.ts +4 -9
  31. package/dist/lib/remote-auth/sync-messages.d.ts +35 -12
  32. package/dist/lib/remote-auth/sync-types.d.ts +30 -101
  33. package/dist/lib/remote-auth/sync.d.ts +19 -21
  34. package/dist/lib/remote-auth/token-store.d.ts +0 -10
  35. package/dist/lib/remote-auth/transport.d.ts +42 -40
  36. package/dist/lib/source-provider.d.ts +12 -0
  37. package/dist/{lint-p2sw53d9.js → lint-p6a4bkvh.js} +5 -5
  38. package/dist/{new-hvq0x91q.js → new-4cdzfbsj.js} +5 -5
  39. package/dist/{plugin-pssmk0dx.js → plugin-a89tqspy.js} +5 -5
  40. package/dist/{preflight-4j00yd0g.js → preflight-r4y3f8f9.js} +5 -5
  41. package/dist/{preview-d4s6gk6p.js → preview-k8n2kew7.js} +5 -5
  42. package/dist/{publish-tkc26en7.js → publish-jnhjp2vd.js} +5 -5
  43. package/dist/{source-provider-3tcj6qg2.js → source-provider-2j5x2hyw.js} +1 -1
  44. package/dist/{source-provider-vanafrt9.js → source-provider-kn41jmbs.js} +1 -1
  45. package/dist/{validate-w9vfefrw.js → validate-prnybpkx.js} +5 -5
  46. package/package.json +1 -1
  47. package/dist/lib/app-heartbeat.d.ts +0 -102
  48. package/dist/lib/remote-auth/image-clash.d.ts +0 -17
  49. package/dist/lib/remote-auth/recovery/classify.d.ts +0 -97
  50. package/dist/lib/remote-auth/recovery/inspect.d.ts +0 -75
  51. package/dist/lib/remote-auth/recovery/locks.d.ts +0 -20
  52. package/dist/lib/remote-auth/recovery/repair.d.ts +0 -29
  53. package/dist/lib/remote-auth/recovery/types.d.ts +0 -39
  54. package/dist/repair-2va4w12t.js +0 -137
@@ -608,7 +608,7 @@ var preview_shell_default = "./preview-shell-c5mfa3q0.js";
608
608
  var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
609
609
 
610
610
  // src/assets/engine/gutterpress-viewer.js
611
- var gutterpress_viewer_default = "./gutterpress-viewer-te8g5grx.js";
611
+ var gutterpress_viewer_default = "./gutterpress-viewer-tma1qwz2.js";
612
612
 
613
613
  // src/assets/engine/gutterpress-agent.js
614
614
  var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
@@ -4,8 +4,59 @@ import {
4
4
  findEnclosingRepoDir
5
5
  } from "./index-v5mp7a6q.js";
6
6
 
7
+ // src/lib/git-fs.ts
8
+ import * as nodeFs from "node:fs";
9
+ var MUTABLE_GIT_METADATA = /(?:^|[\\/])\.git[\\/](?:index|HEAD|packed-refs|refs[\\/].+)$/;
10
+ function needsAtomicWrite(file) {
11
+ return typeof file === "string" && MUTABLE_GIT_METADATA.test(file);
12
+ }
13
+ var tempCounter = 0;
14
+ function tempPathFor(file) {
15
+ return `${file}.gp${process.pid.toString(36)}-${(tempCounter++).toString(36)}.tmp`;
16
+ }
17
+ function writeFile2(file, data, options, callback) {
18
+ const cb = typeof options === "function" ? options : callback;
19
+ const opts = typeof options === "function" ? undefined : options;
20
+ if (!needsAtomicWrite(file)) {
21
+ nodeFs.writeFile(file, data, opts, cb);
22
+ return;
23
+ }
24
+ const temp = tempPathFor(file);
25
+ const failed = (err) => nodeFs.unlink(temp, () => cb(err));
26
+ nodeFs.writeFile(temp, data, opts, (writeErr) => {
27
+ if (writeErr)
28
+ return failed(writeErr);
29
+ nodeFs.rename(temp, file, (renameErr) => {
30
+ if (renameErr)
31
+ return failed(renameErr);
32
+ cb(null);
33
+ });
34
+ });
35
+ }
36
+ async function writeFilePromise(file, data, options) {
37
+ if (!needsAtomicWrite(file)) {
38
+ return nodeFs.promises.writeFile(file, data, options);
39
+ }
40
+ const temp = tempPathFor(file);
41
+ try {
42
+ await nodeFs.promises.writeFile(temp, data, options);
43
+ await nodeFs.promises.rename(temp, file);
44
+ } catch (err) {
45
+ await nodeFs.promises.unlink(temp).catch(() => {});
46
+ throw err;
47
+ }
48
+ }
49
+ var promises2 = {
50
+ ...nodeFs.promises,
51
+ writeFile: writeFilePromise
52
+ };
53
+ var gitFs = {
54
+ ...nodeFs,
55
+ writeFile: writeFile2,
56
+ promises: promises2
57
+ };
58
+
7
59
  // src/lib/source-provider.ts
8
- import * as fs from "node:fs";
9
60
  import path2 from "node:path";
10
61
  import git from "isomorphic-git";
11
62
 
@@ -63,9 +114,6 @@ function formatData(data) {
63
114
  }
64
115
  return parts.length > 0 ? " " + parts.join(" ") : "";
65
116
  }
66
- function shortOid(oid) {
67
- return oid.length >= 7 ? oid.slice(0, 7) : oid;
68
- }
69
117
 
70
118
  // src/lib/source-provider.ts
71
119
  var noopLogger = {
@@ -86,7 +134,7 @@ var repoQueues = new Map;
86
134
  function repoLockKey(projectDir) {
87
135
  const resolved = path2.resolve(projectDir);
88
136
  try {
89
- return fs.realpathSync(resolved);
137
+ return gitFs.realpathSync(resolved);
90
138
  } catch {
91
139
  return resolved;
92
140
  }
@@ -117,10 +165,10 @@ function gitAuthor(name, email) {
117
165
  }
118
166
  async function readGitAuthor(dir) {
119
167
  const [name, email] = await Promise.all([
120
- git.getConfig({ fs, dir, path: "user.name" }).catch(() => {
168
+ git.getConfig({ fs: gitFs, dir, path: "user.name" }).catch(() => {
121
169
  return;
122
170
  }),
123
- git.getConfig({ fs, dir, path: "user.email" }).catch(() => {
171
+ git.getConfig({ fs: gitFs, dir, path: "user.email" }).catch(() => {
124
172
  return;
125
173
  })
126
174
  ]);
@@ -137,14 +185,14 @@ async function listWorkdirChanges(dir, cache = {}) {
137
185
  const adds = [];
138
186
  const removes = [];
139
187
  await git.walk({
140
- fs,
188
+ fs: gitFs,
141
189
  dir,
142
190
  cache,
143
191
  trees: [git.WORKDIR(), git.STAGE()],
144
192
  map: async (filepath, [workdir, stage]) => {
145
193
  if (filepath === ".")
146
194
  return;
147
- if (!stage && workdir && await git.isIgnored({ fs, dir, filepath })) {
195
+ if (!stage && workdir && (filepath.startsWith(".git-damaged") || await git.isIgnored({ fs: gitFs, dir, filepath }))) {
148
196
  return null;
149
197
  }
150
198
  const [wType, sType] = await Promise.all([
@@ -168,7 +216,7 @@ async function listWorkdirChanges(dir, cache = {}) {
168
216
  if (workdirOid !== stageOid) {
169
217
  adds.push(filepath);
170
218
  } else {
171
- const fileBytes = await fs.promises.readFile(path2.join(dir, filepath));
219
+ const fileBytes = await gitFs.promises.readFile(path2.join(dir, filepath));
172
220
  const { oid: actualOid } = await git.hashBlob({ object: fileBytes });
173
221
  if (actualOid !== stageOid)
174
222
  adds.push(filepath);
@@ -181,10 +229,10 @@ async function listWorkdirChanges(dir, cache = {}) {
181
229
  }
182
230
  async function stageChanges(dir, changes, cache) {
183
231
  if (changes.adds.length > 0) {
184
- await git.add({ fs, dir, cache, filepath: changes.adds });
232
+ await git.add({ fs: gitFs, dir, cache, filepath: changes.adds });
185
233
  }
186
234
  for (const filepath of changes.removes) {
187
- await git.remove({ fs, dir, cache, filepath });
235
+ await git.remove({ fs: gitFs, dir, cache, filepath });
188
236
  }
189
237
  }
190
238
  async function hasPendingChanges(dir, cache = {}) {
@@ -199,13 +247,13 @@ async function hasUncommittedChanges(dir, cache = {}) {
199
247
  async function stageMatchesHead(dir, cache) {
200
248
  let headOid;
201
249
  try {
202
- headOid = await git.resolveRef({ fs, dir, ref: "HEAD" });
250
+ headOid = await git.resolveRef({ fs: gitFs, dir, ref: "HEAD" });
203
251
  } catch {
204
252
  return false;
205
253
  }
206
254
  let differs = false;
207
255
  await git.walk({
208
- fs,
256
+ fs: gitFs,
209
257
  dir,
210
258
  cache,
211
259
  trees: [git.TREE({ ref: headOid }), git.STAGE()],
@@ -247,10 +295,10 @@ class LocalFolderSourceProvider {
247
295
  }
248
296
  return withRepoLock(dir, async () => {
249
297
  const cache = {};
250
- await git.init({ fs, dir, defaultBranch: DEFAULT_BRANCH });
298
+ await git.init({ fs: gitFs, dir, defaultBranch: DEFAULT_BRANCH });
251
299
  await stageChanges(dir, await listWorkdirChanges(dir, cache), cache);
252
300
  await git.commit({
253
- fs,
301
+ fs: gitFs,
254
302
  dir,
255
303
  cache,
256
304
  message: options.initialMessage?.trim() || "Created project",
@@ -319,7 +367,7 @@ class LocalGitSourceProvider {
319
367
  let commits;
320
368
  try {
321
369
  commits = await git.log({
322
- fs,
370
+ fs: gitFs,
323
371
  dir,
324
372
  cache: {},
325
373
  depth: limit + 2,
@@ -356,7 +404,7 @@ class LocalGitSourceProvider {
356
404
  }
357
405
  async restoreUnlocked(options) {
358
406
  await git.checkout({
359
- fs,
407
+ fs: gitFs,
360
408
  dir: this.dir,
361
409
  cache: {},
362
410
  ref: options.id,
@@ -368,9 +416,9 @@ class LocalGitSourceProvider {
368
416
  async function snapshotWorkingTreeUnlocked(options) {
369
417
  const dir = options.repoRoot ?? options.projectDir;
370
418
  const logger = options.logFile ? createFileLogger(options.logFile, "snapshot") : noopLogger;
371
- const cache = {};
419
+ const cache = options.cache ?? {};
372
420
  const stagingMarker = snapshotStagingMarkerPath(dir);
373
- const staleStaging = fs.existsSync(stagingMarker);
421
+ const staleStaging = gitFs.existsSync(stagingMarker);
374
422
  const changes = await listWorkdirChanges(dir, cache);
375
423
  const workdirClean = changes.adds.length === 0 && changes.removes.length === 0;
376
424
  if (workdirClean && !staleStaging) {
@@ -379,8 +427,8 @@ async function snapshotWorkingTreeUnlocked(options) {
379
427
  }
380
428
  if (workdirClean && staleStaging && await stageMatchesHead(dir, cache)) {
381
429
  logger.debug("snapshot", "stale marker outlived a completed commit — clearing, not recommitting");
382
- fs.rmSync(stagingMarker, { force: true });
383
- const [head2] = await git.log({ fs, dir, cache, depth: 1 });
430
+ gitFs.rmSync(stagingMarker, { force: true });
431
+ const [head2] = await git.log({ fs: gitFs, dir, cache, depth: 1 });
384
432
  return {
385
433
  id: head2.oid,
386
434
  message: head2.commit.message.trim(),
@@ -393,18 +441,18 @@ async function snapshotWorkingTreeUnlocked(options) {
393
441
  removes: changes.removes.length,
394
442
  ...staleStaging ? { recoveredStaleStaging: true } : {}
395
443
  });
396
- fs.writeFileSync(stagingMarker, "");
444
+ gitFs.writeFileSync(stagingMarker, "");
397
445
  await stageChanges(dir, changes, cache);
398
446
  const author = await resolveGitAuthor(dir, options.authorName, options.authorEmail);
399
447
  const id = await git.commit({
400
- fs,
448
+ fs: gitFs,
401
449
  dir,
402
450
  cache,
403
451
  message: options.message,
404
452
  author
405
453
  });
406
- fs.rmSync(stagingMarker, { force: true });
407
- const [head] = await git.log({ fs, dir, cache, depth: 1 });
454
+ gitFs.rmSync(stagingMarker, { force: true });
455
+ const [head] = await git.log({ fs: gitFs, dir, cache, depth: 1 });
408
456
  return {
409
457
  id,
410
458
  message: options.message,
@@ -461,4 +509,4 @@ async function restoreVersionWithBackup(options) {
461
509
  });
462
510
  }
463
511
 
464
- export { resolveLogger, shortOid, gitScopeFor, HISTORY_PAGE_LIMIT, withRepoLock, __repoLockQueueSizeForTests, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup };
512
+ export { gitFs, resolveLogger, gitScopeFor, HISTORY_PAGE_LIMIT, withRepoLock, __repoLockQueueSizeForTests, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup };
@@ -4,7 +4,7 @@ import {
4
4
  launchChromium,
5
5
  marginBoxAlign,
6
6
  marginBoxRectPt
7
- } from "./index-ycpvr0am.js";
7
+ } from "./index-b2rqw41a.js";
8
8
 
9
9
  // src/engine/compiler/build.ts
10
10
  import { readFile } from "node:fs/promises";
@@ -1282,6 +1282,62 @@ var DESC_JS = `(el) => {
1282
1282
  const src = el.tagName === "IMG" ? " src=" + (el.getAttribute("src") || "").slice(-40) : "";
1283
1283
  return el.tagName.toLowerCase() + cls + src;
1284
1284
  }`;
1285
+ var ABS_CONTAINING_BLOCK_JS = `(cs) => {
1286
+ if (cs.position !== "static") return true;
1287
+ for (const prop of [
1288
+ "transform", "translate", "rotate", "scale", "perspective",
1289
+ "filter", "backdropFilter",
1290
+ ]) {
1291
+ const value = cs[prop];
1292
+ if (value && value !== "none") return true;
1293
+ }
1294
+ if (/\\b(layout|paint|strict|content)\\b/.test(cs.contain)) return true;
1295
+ if (cs.containerType && cs.containerType !== "normal") return true;
1296
+ return /\\b(transform|translate|rotate|scale|perspective|filter)\\b/.test(cs.willChange);
1297
+ }`;
1298
+ var CLIP_EDGES_JS = `((establishesAbsContainingBlock) => {
1299
+ const open = () => ({ left: -Infinity, right: Infinity, top: -Infinity, bottom: Infinity });
1300
+ const rootStyle = getComputedStyle(document.documentElement);
1301
+ const propagates = (a, rootOverflow) =>
1302
+ a === document.documentElement ||
1303
+ (a === document.body && rootOverflow === "visible");
1304
+ return (el) => {
1305
+ const edges = open();
1306
+ const chain = [];
1307
+ const elStyle = getComputedStyle(el);
1308
+ const fixed = elStyle.position === "fixed";
1309
+ let binds = !fixed && elStyle.position !== "absolute";
1310
+ for (let a = el.parentElement; a; a = a.parentElement) {
1311
+ const cs = getComputedStyle(a);
1312
+ if (!fixed && !binds && establishesAbsContainingBlock(cs)) binds = true;
1313
+ const own = open();
1314
+ const clipsX =
1315
+ binds && cs.overflowX !== "visible" && !propagates(a, rootStyle.overflowX);
1316
+ const clipsY =
1317
+ binds && cs.overflowY !== "visible" && !propagates(a, rootStyle.overflowY);
1318
+ if (clipsX || clipsY) {
1319
+ const r = a.getBoundingClientRect();
1320
+ const clipMargin = parseFloat(cs.overflowClipMargin) || 0;
1321
+ if (clipsX) {
1322
+ const grow = cs.overflowX === "clip" ? clipMargin : 0;
1323
+ own.left = r.left + parseFloat(cs.borderLeftWidth) - grow;
1324
+ own.right = r.right - parseFloat(cs.borderRightWidth) + grow;
1325
+ edges.left = Math.max(edges.left, own.left);
1326
+ edges.right = Math.min(edges.right, own.right);
1327
+ }
1328
+ if (clipsY) {
1329
+ const grow = cs.overflowY === "clip" ? clipMargin : 0;
1330
+ own.top = r.top + parseFloat(cs.borderTopWidth) - grow;
1331
+ own.bottom = r.bottom - parseFloat(cs.borderBottomWidth) + grow;
1332
+ edges.top = Math.max(edges.top, own.top);
1333
+ edges.bottom = Math.min(edges.bottom, own.bottom);
1334
+ }
1335
+ }
1336
+ chain.push({ ancestor: a, style: cs, edges: own });
1337
+ }
1338
+ return { edges, chain };
1339
+ };
1340
+ })(${ABS_CONTAINING_BLOCK_JS})`;
1285
1341
  function pagePseudoContexts(model) {
1286
1342
  const used = new Set(pseudoVariants(model));
1287
1343
  const standard = new Set(["left", "right", "recto", "verso", "first", "blank"]);
@@ -1762,25 +1818,11 @@ ${mapCss}`;
1762
1818
  return reasons;
1763
1819
  };
1764
1820
 
1765
- // Does this box establish the containing block for an absolutely
1766
- // positioned descendant? Overflow clipping binds an abspos
1767
- // .gp-pin only from its containing block outward MEASURED: a
1768
- // pin whose box lay entirely outside a STATIC overflow:hidden
1769
- // (and overflow:clip) wrapper printed complete and still behind
1770
- // the page text; the wrapper's clip never touched it.
1771
- const establishesAbsContainingBlock = (cs) => {
1772
- if (cs.position !== "static") return true;
1773
- for (const prop of [
1774
- "transform", "translate", "rotate", "scale", "perspective",
1775
- "filter", "backdropFilter",
1776
- ]) {
1777
- const value = cs[prop];
1778
- if (value && value !== "none") return true;
1779
- }
1780
- if (/\\b(layout|paint|strict|content)\\b/.test(cs.contain)) return true;
1781
- if (cs.containerType && cs.containerType !== "normal") return true;
1782
- return /\\b(transform|translate|rotate|scale|perspective|filter)\\b/.test(cs.willChange);
1783
- };
1821
+ // Which ancestors clip a .gp-behind, and where their edges fall —
1822
+ // the same measured rule the pre-print width check clamps against
1823
+ // (see CLIP_EDGES_JS). This pass walks its \`chain\` so it can name
1824
+ // the ancestor doing the cutting.
1825
+ const clipEdges = ${CLIP_EDGES_JS};
1784
1826
 
1785
1827
  for (const el of document.querySelectorAll("*")) {
1786
1828
  const cs = getComputedStyle(el);
@@ -1823,47 +1865,25 @@ ${mapCss}`;
1823
1865
  const boundary = el.closest(".page, .spread");
1824
1866
  if (boundary) {
1825
1867
  const elRect = el.getBoundingClientRect();
1826
- // Clip binding: an in-flow .gp-behind is bound by every
1827
- // ancestor's overflow, but an abspos one only from its
1828
- // containing block outward — static wrappers in between
1829
- // never clip it (measured; see the pass comment above).
1830
- let clipBinds = cs.position !== "absolute" && cs.position !== "fixed";
1831
- for (let ancestor = el.parentElement; ancestor; ancestor = ancestor.parentElement) {
1832
- const ancestorStyle = getComputedStyle(ancestor);
1833
- if (!clipBinds && establishesAbsContainingBlock(ancestorStyle)) clipBinds = true;
1868
+ for (const link of clipEdges(el).chain) {
1869
+ const ancestor = link.ancestor;
1870
+ const ancestorStyle = link.style;
1834
1871
  const reasons = stackingReasons(ancestor, ancestorStyle);
1835
1872
  // Clipping never reorders layers — it can only CUT the
1836
1873
  // art (measured, pass comment above): warn only where the
1837
- // border box crosses a binding ancestor's clip edge on an
1838
- // axis whose overflow is not \`visible\`. The clip edge is
1839
- // the padding box, grown by overflow-clip-margin where
1840
- // that axis's value is \`clip\` (px values only; keyword
1841
- // forms parse NaN -> 0, i.e. the ungrown padding box).
1842
- // 1px epsilon: the measured cut lands exactly at the
1843
- // edge, and sub-pixel layout rounding is not an overhang.
1874
+ // border box crosses THIS ancestor's own clip edges, which
1875
+ // are ±Infinity on any axis it does not bind. 1px epsilon:
1876
+ // the measured cut lands exactly at the edge, and sub-pixel
1877
+ // layout rounding is not an overhang.
1844
1878
  const cuts = [];
1845
- if (clipBinds && (ancestorStyle.overflowX !== "visible" || ancestorStyle.overflowY !== "visible")) {
1846
- const r = ancestor.getBoundingClientRect();
1847
- const clipMargin = parseFloat(ancestorStyle.overflowClipMargin) || 0;
1848
- if (ancestorStyle.overflowX !== "visible") {
1849
- const grow = ancestorStyle.overflowX === "clip" ? clipMargin : 0;
1850
- const left = r.left + parseFloat(ancestorStyle.borderLeftWidth) - grow;
1851
- const right = r.right - parseFloat(ancestorStyle.borderRightWidth) + grow;
1852
- if (elRect.left < left - 1)
1853
- cuts.push(Math.round(left - elRect.left) + "px past its left clip edge");
1854
- if (elRect.right > right + 1)
1855
- cuts.push(Math.round(elRect.right - right) + "px past its right clip edge");
1856
- }
1857
- if (ancestorStyle.overflowY !== "visible") {
1858
- const grow = ancestorStyle.overflowY === "clip" ? clipMargin : 0;
1859
- const top = r.top + parseFloat(ancestorStyle.borderTopWidth) - grow;
1860
- const bottom = r.bottom - parseFloat(ancestorStyle.borderBottomWidth) + grow;
1861
- if (elRect.top < top - 1)
1862
- cuts.push(Math.round(top - elRect.top) + "px past its top clip edge");
1863
- if (elRect.bottom > bottom + 1)
1864
- cuts.push(Math.round(elRect.bottom - bottom) + "px past its bottom clip edge");
1865
- }
1866
- }
1879
+ if (elRect.left < link.edges.left - 1)
1880
+ cuts.push(Math.round(link.edges.left - elRect.left) + "px past its left clip edge");
1881
+ if (elRect.right > link.edges.right + 1)
1882
+ cuts.push(Math.round(elRect.right - link.edges.right) + "px past its right clip edge");
1883
+ if (elRect.top < link.edges.top - 1)
1884
+ cuts.push(Math.round(link.edges.top - elRect.top) + "px past its top clip edge");
1885
+ if (elRect.bottom > link.edges.bottom + 1)
1886
+ cuts.push(Math.round(elRect.bottom - link.edges.bottom) + "px past its bottom clip edge");
1867
1887
  if ((reasons.length || cuts.length) && !seenLayerTraps.has(ancestor)) {
1868
1888
  seenLayerTraps.add(ancestor);
1869
1889
  const effects = [];
@@ -1968,6 +1988,20 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
1968
1988
  const boxes = JSON.parse(await page.evaluate(`(() => {
1969
1989
  const LIMIT = ${limitPx} + 1;
1970
1990
  const desc = ${DESC_JS};
1991
+ // Shrink-to-fit only reacts to overflow that ESCAPES: a clipping or
1992
+ // scrolling ancestor contains its subtree's overflow, so the
1993
+ // document's own width never grows and the book prints at 1.0x.
1994
+ // MEASURED (Chrome 151, a marker word read off \`pdftotext -bbox\`
1995
+ // against an unshrunk control): a 900px box inside a 300px
1996
+ // \`overflow: hidden\` shell printed unshrunk, as did the same box
1997
+ // under clip/auto/scroll — and a real 208-page book whose two
1998
+ // "offenders" both sat under \`overflow-x: clip\` printed
1999
+ // coordinate-identical with them restored. WHICH ancestors clip, and
2000
+ // where their edges fall, is CLIP_EDGES_JS's measured rule — shared
2001
+ // with the layer-containment audit, which measures overhang past the
2002
+ // same edges. Only the x edges matter here: shrink-to-fit is a width
2003
+ // response.
2004
+ const clipEdges = ${CLIP_EDGES_JS};
1971
2005
  const out = [];
1972
2006
  for (const el of document.querySelectorAll("*")) {
1973
2007
  const r = el.getBoundingClientRect();
@@ -1977,6 +2011,9 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
1977
2011
  // width) — both trigger the same whole-document shrink-to-fit,
1978
2012
  // measured: a left bleed alone cost 16%.
1979
2013
  if (right <= LIMIT && r.width <= LIMIT && r.left >= -1) continue;
2014
+ // ...but only where it actually escapes its clipping ancestors.
2015
+ const clip = clipEdges(el).edges;
2016
+ if (Math.min(right, clip.right) <= LIMIT && Math.max(r.left, clip.left) >= -1) continue;
1980
2017
  let deepest = true;
1981
2018
  for (const c of el.children) {
1982
2019
  if (c.getBoundingClientRect().width >= r.width - 1) { deepest = false; break; }
package/dist/index.js CHANGED
@@ -1,16 +1,15 @@
1
1
  import {
2
- APP_HEARTBEAT_FRESH_MS,
3
2
  AUTO_SNAPSHOT_DEFAULT_MINUTES,
4
3
  AUTO_SNAPSHOT_MAX_MINUTES,
5
4
  AUTO_SNAPSHOT_MIN_MINUTES,
6
5
  AUTO_SYNC_DEFAULT_MINUTES,
7
6
  AUTO_SYNC_MAX_MINUTES,
8
7
  AUTO_SYNC_MIN_MINUTES,
8
+ AUTO_SYNC_PUSH_INTERVAL_MINUTES,
9
9
  BUILT_IN_TEMPLATE_IDS,
10
10
  BUILT_IN_THEME_IDS,
11
11
  FileTokenStore,
12
12
  GITHUB_HOST,
13
- GenericTokenAuthProvider,
14
13
  GitHubAuthProvider,
15
14
  MANIFEST_FILENAMES,
16
15
  PLUGINS_DIR,
@@ -18,9 +17,7 @@ import {
18
17
  PRESET_IDS,
19
18
  PublishSelectionsStore,
20
19
  RECOMMENDED_PLUGINS,
21
- RepoNeedsRecoveryError,
22
20
  SNIPPETS_DIR,
23
- STALE_LOCK_MIN_AGE_MS,
24
21
  SYNC_SNAPSHOT_MESSAGE,
25
22
  TARGETS,
26
23
  TARGET_IDS,
@@ -28,14 +25,11 @@ import {
28
25
  addLocalPlugin,
29
26
  addNpmPlugin,
30
27
  adoptFolder,
31
- appHeartbeatPath,
32
28
  applyTheme,
33
29
  autoSnapshotDelayMs,
34
30
  autoSyncDelayMs,
35
- buildPreflightDiagnostics,
36
31
  checkCss,
37
32
  checkToolAvailability,
38
- classifyFromHealth,
39
33
  cloneRepository,
40
34
  connectGenericHost,
41
35
  connectPublishProvider,
@@ -55,20 +49,13 @@ import {
55
49
  getPreviousTheme,
56
50
  getSystemDiagnostics,
57
51
  hasProjectManifest,
58
- heartbeatTtlMs,
59
52
  importTemplateFromFolder,
60
53
  importThemeFromFile,
61
54
  importThemeFromFolder,
62
55
  importThemeFromUrl,
63
56
  inspectImage,
64
- inspectRepo,
65
- isAppHeartbeatFresh,
66
57
  isGitInternalPath,
67
- isLikelyRepoCorruption,
68
- isRepoNeedsRecoveryError,
69
58
  isSshRemoteUrl,
70
- isUnbornRepo,
71
- keepImageVersion,
72
59
  knownForgeTokenUrl,
73
60
  listBuiltInTemplates,
74
61
  listBuiltInThemes,
@@ -85,29 +72,17 @@ import {
85
72
  loadManifest,
86
73
  loadManifestWithPath,
87
74
  log,
88
- migrateUrlCredential,
89
- normalizeForgeHost,
90
75
  openPath,
91
76
  parseRemoteOrigin,
92
- preflightStructuralReason,
93
- provenancePath,
94
77
  publishConnectionStatus,
95
78
  publishCredentialKey,
96
79
  publishProviderFor,
97
80
  publishTargetFor,
98
- pullChanges,
99
- pushChanges,
100
- readAppHeartbeat,
101
- readImageVersion,
102
81
  readManifestFields,
103
- readProjectProvenance,
104
82
  readPublishSettings,
105
83
  readSnippet,
106
84
  readThemeCss,
107
- redactCredential,
108
- removeAppHeartbeat,
109
85
  removeProjectTheme,
110
- repairRepo,
111
86
  reportMissingTools,
112
87
  resolveActiveStyles,
113
88
  resolveBuiltInTheme,
@@ -137,18 +112,16 @@ import {
137
112
  substituteVariables,
138
113
  syncProject,
139
114
  testRemoteAccess,
140
- validateProjectPlugins,
141
- verifyRepoReadable,
142
- writeAppHeartbeat
143
- } from "./index-ge7q9xj3.js";
115
+ validateProjectPlugins
116
+ } from "./index-6g72h2n1.js";
144
117
  import {
145
118
  BUILD_DIAGNOSTIC_CODES
146
- } from "./index-wq3r5pj7.js";
119
+ } from "./index-kvgq4q3q.js";
147
120
  import {
148
121
  BuildError,
149
122
  DEFAULT_PRINT_OPTS,
150
123
  readyProbeExpr
151
- } from "./index-ycpvr0am.js";
124
+ } from "./index-b2rqw41a.js";
152
125
  import {
153
126
  AUTO_SNAPSHOT_MESSAGE,
154
127
  HISTORY_PAGE_LIMIT,
@@ -156,9 +129,8 @@ import {
156
129
  isNoChangesError,
157
130
  providerFor,
158
131
  resolveLogger,
159
- restoreVersionWithBackup,
160
- shortOid
161
- } from "./index-mdefp0y5.js";
132
+ restoreVersionWithBackup
133
+ } from "./index-dtrftayr.js";
162
134
  import {
163
135
  capabilitiesFor,
164
136
  detectProjectSource,
@@ -168,8 +140,6 @@ import {
168
140
  } from "./index-v5mp7a6q.js";
169
141
  import"./index-37x76zdn.js";
170
142
  export {
171
- writeAppHeartbeat,
172
- verifyRepoReadable,
173
143
  validateProjectPlugins,
174
144
  testRemoteAccess,
175
145
  syncProject,
@@ -177,7 +147,6 @@ export {
177
147
  startPreviewServer,
178
148
  splitOutPath,
179
149
  slugifyProjectName,
180
- shortOid,
181
150
  setPublishProviderConfig,
182
151
  setPluginEnabled,
183
152
  setManifestFields,
@@ -205,31 +174,19 @@ export {
205
174
  reportMissingTools,
206
175
  repoSubPath,
207
176
  repoRootForSource,
208
- repairRepo,
209
177
  removeProjectTheme,
210
- removeAppHeartbeat,
211
- redactCredential,
212
178
  readyProbeExpr,
213
179
  readThemeCss,
214
180
  readSnippet,
215
181
  readPublishSettings,
216
- readProjectProvenance,
217
182
  readManifestFields,
218
- readImageVersion,
219
- readAppHeartbeat,
220
- pushChanges,
221
- pullChanges,
222
183
  publishTargetFor,
223
184
  publishProviderFor,
224
185
  publishCredentialKey,
225
186
  publishConnectionStatus,
226
187
  providerFor,
227
- provenancePath,
228
- preflightStructuralReason,
229
188
  parseRemoteOrigin,
230
189
  openPath,
231
- normalizeForgeHost,
232
- migrateUrlCredential,
233
190
  log,
234
191
  loadManifestWithPath,
235
192
  loadManifest,
@@ -246,21 +203,14 @@ export {
246
203
  listBuiltInThemes,
247
204
  listBuiltInTemplates,
248
205
  knownForgeTokenUrl,
249
- keepImageVersion,
250
- isUnbornRepo,
251
206
  isSshRemoteUrl,
252
- isRepoNeedsRecoveryError,
253
207
  isNoChangesError,
254
- isLikelyRepoCorruption,
255
208
  isGitInternalPath,
256
- isAppHeartbeatFresh,
257
- inspectRepo,
258
209
  inspectImage,
259
210
  importThemeFromUrl,
260
211
  importThemeFromFolder,
261
212
  importThemeFromFile,
262
213
  importTemplateFromFolder,
263
- heartbeatTtlMs,
264
214
  hasProjectManifest,
265
215
  getSystemDiagnostics,
266
216
  getPreviousTheme,
@@ -282,15 +232,12 @@ export {
282
232
  connectPublishProvider,
283
233
  connectGenericHost,
284
234
  cloneRepository,
285
- classifyFromHealth,
286
235
  checkToolAvailability,
287
236
  checkCss,
288
237
  capabilitiesFor,
289
- buildPreflightDiagnostics,
290
238
  autoSyncDelayMs,
291
239
  autoSnapshotDelayMs,
292
240
  applyTheme,
293
- appHeartbeatPath,
294
241
  adoptFolder,
295
242
  addNpmPlugin,
296
243
  addLocalPlugin,
@@ -298,9 +245,7 @@ export {
298
245
  TARGET_IDS,
299
246
  TARGETS,
300
247
  SYNC_SNAPSHOT_MESSAGE,
301
- STALE_LOCK_MIN_AGE_MS,
302
248
  SNIPPETS_DIR,
303
- RepoNeedsRecoveryError,
304
249
  RESTORE_BACKUP_MESSAGE,
305
250
  RECOMMENDED_PLUGINS,
306
251
  PublishSelectionsStore,
@@ -310,7 +255,6 @@ export {
310
255
  MANIFEST_FILENAMES,
311
256
  HISTORY_PAGE_LIMIT,
312
257
  GitHubAuthProvider,
313
- GenericTokenAuthProvider,
314
258
  GITHUB_HOST,
315
259
  FileTokenStore,
316
260
  DEFAULT_PRINT_OPTS,
@@ -318,12 +262,12 @@ export {
318
262
  BUILT_IN_THEME_IDS,
319
263
  BUILT_IN_TEMPLATE_IDS,
320
264
  BUILD_DIAGNOSTIC_CODES,
265
+ AUTO_SYNC_PUSH_INTERVAL_MINUTES,
321
266
  AUTO_SYNC_MIN_MINUTES,
322
267
  AUTO_SYNC_MAX_MINUTES,
323
268
  AUTO_SYNC_DEFAULT_MINUTES,
324
269
  AUTO_SNAPSHOT_MIN_MINUTES,
325
270
  AUTO_SNAPSHOT_MESSAGE,
326
271
  AUTO_SNAPSHOT_MAX_MINUTES,
327
- AUTO_SNAPSHOT_DEFAULT_MINUTES,
328
- APP_HEARTBEAT_FRESH_MS
272
+ AUTO_SNAPSHOT_DEFAULT_MINUTES
329
273
  };