@beyondwork/docx-react-component 1.0.129 → 1.0.130

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 (102) hide show
  1. package/dist/api/public-types.cjs +595 -18
  2. package/dist/api/public-types.d.cts +1 -1
  3. package/dist/api/public-types.d.ts +1 -1
  4. package/dist/api/public-types.js +4 -4
  5. package/dist/api/v3.cjs +1164 -332
  6. package/dist/api/v3.d.cts +2 -2
  7. package/dist/api/v3.d.ts +2 -2
  8. package/dist/api/v3.js +13 -13
  9. package/dist/{chunk-OTQIW2TC.js → chunk-35RHOE6I.js} +105 -4
  10. package/dist/{chunk-PGKUJZXV.js → chunk-3YCQM2RV.js} +6 -6
  11. package/dist/{chunk-JJGVE5J7.js → chunk-4YCWECLZ.js} +1 -1
  12. package/dist/{chunk-EZKJXIPH.js → chunk-6TBLDBCL.js} +1 -1
  13. package/dist/{chunk-SKPTKQHF.js → chunk-7G5GR3VV.js} +122 -23
  14. package/dist/{chunk-HUIHBBAQ.js → chunk-A3GSNB4G.js} +17 -6
  15. package/dist/{chunk-5DGKFNQT.js → chunk-A66ZVUAT.js} +150 -1
  16. package/dist/{chunk-YIYM4ZAP.js → chunk-CI2TD3T4.js} +1 -1
  17. package/dist/{chunk-63FYIGCT.js → chunk-DGA7M77X.js} +2 -2
  18. package/dist/{chunk-EB6M3GE6.js → chunk-FM4K4XFJ.js} +100 -97
  19. package/dist/{chunk-VNLDQJ47.js → chunk-HYHCRMR7.js} +1 -1
  20. package/dist/{chunk-DJU2W4E4.js → chunk-KNHMXKC6.js} +2 -2
  21. package/dist/{chunk-Q3QYGKFE.js → chunk-M7YRJX6V.js} +10 -21
  22. package/dist/{chunk-KFCQYZXR.js → chunk-OVLZQ6FZ.js} +61 -0
  23. package/dist/{chunk-W34X3KBR.js → chunk-PHMWH23E.js} +1 -1
  24. package/dist/{chunk-DDN2AIGE.js → chunk-Q7Y57KOK.js} +2 -2
  25. package/dist/{chunk-LJH64PV3.js → chunk-QXKQPUOM.js} +3 -3
  26. package/dist/{chunk-CX42VC67.js → chunk-SYQWQ6FE.js} +1 -1
  27. package/dist/{chunk-5DSHUYSY.js → chunk-T5YYFDZB.js} +1 -1
  28. package/dist/{chunk-RMRTQGW3.js → chunk-THVM6EP5.js} +371 -13
  29. package/dist/{chunk-XMHSGPLN.js → chunk-VRKK2CSZ.js} +111 -90
  30. package/dist/{chunk-OL2UEHRP.js → chunk-WUDSNHWF.js} +1 -1
  31. package/dist/{chunk-XQCAMKIQ.js → chunk-WZDKNF37.js} +250 -106
  32. package/dist/{chunk-PRAZBHNF.js → chunk-YLL7MF5C.js} +15 -15
  33. package/dist/{chunk-YZDZ4FGR.js → chunk-ZVC23LKV.js} +1 -1
  34. package/dist/compare.cjs +100 -97
  35. package/dist/compare.js +3 -3
  36. package/dist/core/commands/formatting-commands.d.cts +1 -1
  37. package/dist/core/commands/formatting-commands.d.ts +1 -1
  38. package/dist/core/commands/image-commands.cjs +16 -5
  39. package/dist/core/commands/image-commands.d.cts +1 -1
  40. package/dist/core/commands/image-commands.d.ts +1 -1
  41. package/dist/core/commands/image-commands.js +5 -5
  42. package/dist/core/commands/section-layout-commands.d.cts +1 -1
  43. package/dist/core/commands/section-layout-commands.d.ts +1 -1
  44. package/dist/core/commands/style-commands.d.cts +1 -1
  45. package/dist/core/commands/style-commands.d.ts +1 -1
  46. package/dist/core/commands/table-structure-commands.cjs +16 -5
  47. package/dist/core/commands/table-structure-commands.d.cts +1 -1
  48. package/dist/core/commands/table-structure-commands.d.ts +1 -1
  49. package/dist/core/commands/table-structure-commands.js +4 -4
  50. package/dist/core/commands/text-commands.cjs +16 -5
  51. package/dist/core/commands/text-commands.d.cts +1 -1
  52. package/dist/core/commands/text-commands.d.ts +1 -1
  53. package/dist/core/commands/text-commands.js +5 -5
  54. package/dist/core/selection/mapping.d.cts +1 -1
  55. package/dist/core/selection/mapping.d.ts +1 -1
  56. package/dist/core/state/editor-state.d.cts +1 -1
  57. package/dist/core/state/editor-state.d.ts +1 -1
  58. package/dist/index.cjs +1280 -347
  59. package/dist/index.d.cts +4 -4
  60. package/dist/index.d.ts +4 -4
  61. package/dist/index.js +24 -24
  62. package/dist/io/docx-session.cjs +216 -203
  63. package/dist/io/docx-session.d.cts +3 -3
  64. package/dist/io/docx-session.d.ts +3 -3
  65. package/dist/io/docx-session.js +6 -6
  66. package/dist/legal.cjs +9 -20
  67. package/dist/legal.js +3 -3
  68. package/dist/{loader-4qsw4eIU.d.ts → loader-B-aL5HGD.d.ts} +2 -2
  69. package/dist/{loader-B8TKhmQi.d.cts → loader-DiY_ZgKl.d.cts} +2 -2
  70. package/dist/{measurement-backend-canvas-Q3MJMEYX.js → measurement-backend-canvas-F7ZYDACK.js} +1 -1
  71. package/dist/{public-types-p9b8rfy8.d.ts → public-types-DyqnxxO9.d.ts} +124 -1
  72. package/dist/{public-types-B5CRoR6f.d.cts → public-types-gvubspUI.d.cts} +124 -1
  73. package/dist/public-types.cjs +595 -18
  74. package/dist/public-types.d.cts +1 -1
  75. package/dist/public-types.d.ts +1 -1
  76. package/dist/public-types.js +4 -4
  77. package/dist/runtime/collab.d.cts +2 -2
  78. package/dist/runtime/collab.d.ts +2 -2
  79. package/dist/runtime/document-runtime.cjs +908 -129
  80. package/dist/runtime/document-runtime.d.cts +1 -1
  81. package/dist/runtime/document-runtime.d.ts +1 -1
  82. package/dist/runtime/document-runtime.js +17 -17
  83. package/dist/{session-BnGIjaex.d.cts → session-BUN6B-Vj.d.cts} +2 -2
  84. package/dist/{session-vEYKf-w3.d.ts → session-CDB0hohT.d.ts} +2 -2
  85. package/dist/session.cjs +216 -203
  86. package/dist/session.d.cts +4 -4
  87. package/dist/session.d.ts +4 -4
  88. package/dist/session.js +7 -7
  89. package/dist/tailwind.cjs +595 -18
  90. package/dist/tailwind.d.cts +1 -1
  91. package/dist/tailwind.d.ts +1 -1
  92. package/dist/tailwind.js +8 -8
  93. package/dist/{types-BLuvZ6cQ.d.cts → types-C4bz3kDU.d.cts} +1 -1
  94. package/dist/{types-Dutlyj0T.d.ts → types-VWH6CRvG.d.ts} +1 -1
  95. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +2 -2
  96. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +2 -2
  97. package/dist/ui-tailwind/editor-surface/search-plugin.js +5 -5
  98. package/dist/ui-tailwind.cjs +595 -18
  99. package/dist/ui-tailwind.d.cts +2 -2
  100. package/dist/ui-tailwind.d.ts +2 -2
  101. package/dist/ui-tailwind.js +8 -8
  102. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -31,6 +31,43 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
33
  // src/runtime/layout/resolved-formatting-state.ts
34
+ function createLayoutReadyFormattingSnapshot(formatting, runs = /* @__PURE__ */ new Map()) {
35
+ const snapshot = {
36
+ version: 1,
37
+ paragraph: {
38
+ spacingBefore: formatting.spacingBefore,
39
+ spacingAfter: formatting.spacingAfter,
40
+ lineHeight: formatting.lineHeight,
41
+ lineRule: formatting.lineRule,
42
+ indentLeft: formatting.indentLeft,
43
+ indentRight: formatting.indentRight,
44
+ firstLineIndent: formatting.firstLineIndent,
45
+ hangingIndent: formatting.hangingIndent,
46
+ fontSizeHalfPoints: formatting.fontSizeHalfPoints,
47
+ averageCharWidthTwips: formatting.averageCharWidthTwips,
48
+ tabStops: formatting.tabStops.map((tab) => ({ ...tab })),
49
+ defaultTabInterval: formatting.defaultTabInterval,
50
+ keepNext: formatting.keepNext,
51
+ keepLines: formatting.keepLines,
52
+ pageBreakBefore: formatting.pageBreakBefore,
53
+ widowControl: formatting.widowControl,
54
+ contextualSpacing: formatting.contextualSpacing,
55
+ ...formatting.numberingMarkerBox ? { numberingMarkerBox: { ...formatting.numberingMarkerBox } } : {}
56
+ },
57
+ runs: Array.from(runs.entries()).map(([runId, run]) => ({
58
+ runId,
59
+ ...run.fontFamily ? { fontFamily: run.fontFamily } : {},
60
+ ...typeof run.fontSizeHalfPoints === "number" ? { fontSizeHalfPoints: run.fontSizeHalfPoints } : {},
61
+ bold: Boolean(run.bold),
62
+ italic: Boolean(run.italic),
63
+ verticalAlign: run.verticalAlign ?? "baseline"
64
+ })).sort((a, b) => a.runId.localeCompare(b.runId))
65
+ };
66
+ return {
67
+ ...snapshot,
68
+ hash: hashStable(snapshot)
69
+ };
70
+ }
34
71
  function resolveBlockFormatting(block, defaultTabInterval = 720, themeFonts) {
35
72
  if (block.kind !== "paragraph") {
36
73
  return null;
@@ -273,6 +310,29 @@ function buildRunFormattingMap(block) {
273
310
  }
274
311
  return runs;
275
312
  }
313
+ function hashStable(value) {
314
+ return fnv1a(stableStringify(value)).toString(36);
315
+ }
316
+ function stableStringify(value) {
317
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
318
+ if (Array.isArray(value)) {
319
+ return `[${value.map((item) => stableStringify(item)).join(",")}]`;
320
+ }
321
+ if (value instanceof Map) {
322
+ return stableStringify(Array.from(value.entries()));
323
+ }
324
+ const object = value;
325
+ const keys = Object.keys(object).filter((key) => object[key] !== void 0 && typeof object[key] !== "function").sort();
326
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
327
+ }
328
+ function fnv1a(input) {
329
+ let hash = 2166136261;
330
+ for (let i = 0; i < input.length; i += 1) {
331
+ hash ^= input.charCodeAt(i);
332
+ hash = Math.imul(hash, 16777619);
333
+ }
334
+ return hash >>> 0;
335
+ }
276
336
  var FONT_AVG_CHAR_WIDTH, DEFAULT_FONT_AVG_CHAR_WIDTH, DEFAULT_FONT_SIZE_HALF_POINTS, DEFAULT_LINE_HEIGHT_FACTOR, TWIPS_PER_POINT;
277
337
  var init_resolved_formatting_state = __esm({
278
338
  "src/runtime/layout/resolved-formatting-state.ts"() {
@@ -2877,7 +2937,7 @@ function toStableJsonValue(value) {
2877
2937
  }
2878
2938
  return result;
2879
2939
  }
2880
- function stableStringify(value) {
2940
+ function stableStringify2(value) {
2881
2941
  return JSON.stringify(toStableJsonValue(value));
2882
2942
  }
2883
2943
 
@@ -3041,7 +3101,7 @@ function migrateReviewRecordAnchor(record) {
3041
3101
  return record;
3042
3102
  }
3043
3103
  function createCanonicalDocumentSignature(document2) {
3044
- return stableStringify(document2);
3104
+ return stableStringify2(document2);
3045
3105
  }
3046
3106
  function assertCanonicalDocument(value) {
3047
3107
  const issues = validateCanonicalDocument(value);
@@ -6296,6 +6356,7 @@ function collectCanonicalLayoutInputs(doc) {
6296
6356
  const blockContexts = collectStoryBlockContexts(doc);
6297
6357
  return {
6298
6358
  stories: collectCanonicalStoryIdentities(doc),
6359
+ layoutIdentities: collectLayoutInputIdentities(doc, blockContexts),
6299
6360
  fieldRegions: collectCanonicalFieldRegionIdentities(doc),
6300
6361
  numbering: collectCanonicalNumberingLayoutInputs(doc, blockContexts),
6301
6362
  tables: collectCanonicalTableLayoutInputs(blockContexts),
@@ -6304,6 +6365,116 @@ function collectCanonicalLayoutInputs(doc) {
6304
6365
  editableTargets: collectEditableTargetRefs(doc)
6305
6366
  };
6306
6367
  }
6368
+ function collectLayoutInputIdentities(doc, contexts = collectStoryBlockContexts(doc)) {
6369
+ const identities = [];
6370
+ const editableTargets = collectEditableTargetRefs(doc);
6371
+ const editableByStoryBlock = new Map(
6372
+ editableTargets.map((target) => [`${target.storyKey}:${target.blockPath}`, target])
6373
+ );
6374
+ for (const context of contexts) {
6375
+ walkBlocks(context.blocks, context.storyKey, context.basePath, {
6376
+ paragraph(paragraph, blockPath) {
6377
+ const styleNumbering = paragraph.numbering === void 0 && paragraph.styleId !== void 0 ? resolveParagraphStyleNumbering(doc, paragraph.styleId) : void 0;
6378
+ const numbering = paragraph.numbering ?? styleNumbering;
6379
+ const editableTargetRef = editableByStoryBlock.get(`${context.storyKey}:${blockPath}`);
6380
+ identities.push(
6381
+ createLayoutInputIdentity({
6382
+ storyKey: context.storyKey,
6383
+ blockPath,
6384
+ block: paragraph,
6385
+ ...editableTargetRef !== void 0 ? { editableTargetRef } : {},
6386
+ ...numbering !== void 0 ? {
6387
+ list: {
6388
+ numberingInstanceId: numbering.numberingInstanceId,
6389
+ level: numbering.level ?? 0,
6390
+ ...paragraph.numbering?.sourceRef !== void 0 ? { markerSourceRef: paragraph.numbering.sourceRef } : {}
6391
+ }
6392
+ } : {}
6393
+ })
6394
+ );
6395
+ },
6396
+ table(table, blockPath) {
6397
+ identities.push(
6398
+ createLayoutInputIdentity({
6399
+ storyKey: context.storyKey,
6400
+ blockPath,
6401
+ block: table,
6402
+ table: { tableBlockPath: blockPath }
6403
+ })
6404
+ );
6405
+ },
6406
+ inline(inline, blockPath, inlinePath) {
6407
+ const objectId = objectIdForInline(inline);
6408
+ if (!objectId) return;
6409
+ const sourceRef = sourceRefForInline(inline);
6410
+ identities.push({
6411
+ storyKey: context.storyKey,
6412
+ blockPath,
6413
+ blockId: `${context.storyKey}:${inlinePath}`,
6414
+ ...sourceRef !== void 0 ? { sourceRef } : {},
6415
+ object: {
6416
+ objectId,
6417
+ ...sourceRef !== void 0 ? { anchorSourceRef: sourceRef } : {}
6418
+ }
6419
+ });
6420
+ }
6421
+ });
6422
+ }
6423
+ return identities;
6424
+ }
6425
+ function createLayoutInputIdentity(input) {
6426
+ const sourceRef = sourceRefForBlock(input.block);
6427
+ const blockId = input.block.type === "paragraph" && input.block.wordExtensionIds?.paraId ? `para:${input.block.wordExtensionIds.paraId}` : sourceRef?.sourceId !== void 0 ? `source:${sourceRef.sourceId}` : `${input.storyKey}:${input.blockPath}`;
6428
+ return {
6429
+ storyKey: input.storyKey,
6430
+ blockPath: input.blockPath,
6431
+ blockId,
6432
+ ...sourceRef !== void 0 ? { sourceRef } : {},
6433
+ ...input.editableTargetRef !== void 0 ? { editableTargetRef: input.editableTargetRef } : {},
6434
+ ...input.table !== void 0 ? { table: input.table } : {},
6435
+ ...input.list !== void 0 ? { list: input.list } : {}
6436
+ };
6437
+ }
6438
+ function sourceRefForBlock(block) {
6439
+ return "sourceRef" in block ? block.sourceRef : void 0;
6440
+ }
6441
+ function sourceRefForInline(inline) {
6442
+ return "sourceRef" in inline ? inline.sourceRef : void 0;
6443
+ }
6444
+ function objectIdForInline(inline) {
6445
+ switch (inline.type) {
6446
+ case "image":
6447
+ return inline.mediaId;
6448
+ case "drawing_frame":
6449
+ return objectIdForDrawingContent(inline.content) ?? inline.sourceRef?.sourceId;
6450
+ case "shape":
6451
+ case "vml_shape":
6452
+ case "wordart":
6453
+ return inline.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(inline.rawXml).slice(0, 16)}`;
6454
+ case "chart_preview":
6455
+ case "smartart_preview":
6456
+ return inline.previewMediaId ?? `raw:${sha256TextHex(inline.rawXml).slice(0, 16)}`;
6457
+ case "ole_embed":
6458
+ return inline.relationshipId ?? inline.id ?? inline.sourceRef?.sourceId;
6459
+ case "opaque_inline":
6460
+ return inline.fragmentId;
6461
+ default:
6462
+ return void 0;
6463
+ }
6464
+ }
6465
+ function objectIdForDrawingContent(content) {
6466
+ switch (content.type) {
6467
+ case "picture":
6468
+ return content.mediaId ?? content.packagePartName ?? content.blipRef;
6469
+ case "chart_preview":
6470
+ case "smartart_preview":
6471
+ return content.previewMediaId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
6472
+ case "shape":
6473
+ return content.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
6474
+ case "opaque":
6475
+ return content.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
6476
+ }
6477
+ }
6307
6478
  function collectEditableTargetRefs(doc, cache) {
6308
6479
  const targets = [];
6309
6480
  for (const context of collectStoryBlockContexts(doc)) {
@@ -8452,6 +8623,16 @@ function collectCanonicalNumberingLayoutInputs(doc, contexts = collectStoryBlock
8452
8623
  const instance = doc.numbering.instances[numbering.numberingInstanceId];
8453
8624
  const abstractDefinition = instance?.abstractNumberingId === void 0 ? void 0 : doc.numbering.abstractDefinitions[instance.abstractNumberingId];
8454
8625
  inputs.push({
8626
+ identity: createLayoutInputIdentity({
8627
+ storyKey: context.storyKey,
8628
+ blockPath,
8629
+ block: paragraph,
8630
+ list: {
8631
+ numberingInstanceId: numbering.numberingInstanceId,
8632
+ level: numbering.level ?? 0,
8633
+ ...paragraph.numbering?.sourceRef !== void 0 ? { markerSourceRef: paragraph.numbering.sourceRef } : {}
8634
+ }
8635
+ }),
8455
8636
  numberingKey: `${context.storyKey}:${blockPath}:numbering`,
8456
8637
  storyKey: context.storyKey,
8457
8638
  blockPath,
@@ -8753,6 +8934,12 @@ function projectTableLayoutInput(table, storyKey2, blockPath) {
8753
8934
  (row2, rowIndex) => projectTableRowLayoutInput(row2, tableKey, rowIndex)
8754
8935
  );
8755
8936
  return {
8937
+ identity: createLayoutInputIdentity({
8938
+ storyKey: storyKey2,
8939
+ blockPath,
8940
+ block: table,
8941
+ table: { tableBlockPath: blockPath }
8942
+ }),
8756
8943
  tableKey,
8757
8944
  storyKey: storyKey2,
8758
8945
  blockPath,
@@ -8840,6 +9027,16 @@ function projectDrawingFrameAnchor(node, storyKey2, blockPath, inlinePath) {
8840
9027
  const objectKey = `${storyKey2}:${inlinePath}`;
8841
9028
  const textBoxBody = projectTextBoxBodyLayoutInput(content, objectKey, sourceRef, `${inlinePath}/txbx`);
8842
9029
  return {
9030
+ identity: {
9031
+ storyKey: storyKey2,
9032
+ blockPath,
9033
+ blockId: objectKey,
9034
+ ...sourceRef !== void 0 ? { sourceRef } : {},
9035
+ object: {
9036
+ objectId: objectKey,
9037
+ ...sourceRef !== void 0 ? { anchorSourceRef: sourceRef } : {}
9038
+ }
9039
+ },
8843
9040
  objectKey,
8844
9041
  storyKey: storyKey2,
8845
9042
  blockPath,
@@ -8961,8 +9158,19 @@ function projectTextBoxRunLayoutInput(inline, paragraphKey, inlineIndex) {
8961
9158
  }
8962
9159
  function projectLegacyImageAnchor(doc, node, storyKey2, blockPath, inlinePath) {
8963
9160
  const media = doc.media.items[node.mediaId];
9161
+ const objectKey = `${storyKey2}:${inlinePath}`;
8964
9162
  return {
8965
- objectKey: `${storyKey2}:${inlinePath}`,
9163
+ identity: {
9164
+ storyKey: storyKey2,
9165
+ blockPath,
9166
+ blockId: objectKey,
9167
+ ...node.sourceRef !== void 0 ? { sourceRef: node.sourceRef } : {},
9168
+ object: {
9169
+ objectId: objectKey,
9170
+ ...node.sourceRef !== void 0 ? { anchorSourceRef: node.sourceRef } : {}
9171
+ }
9172
+ },
9173
+ objectKey,
8966
9174
  storyKey: storyKey2,
8967
9175
  blockPath,
8968
9176
  inlinePath,
@@ -11213,7 +11421,7 @@ function buildEffectiveLayoutFormatting(input) {
11213
11421
  };
11214
11422
  }
11215
11423
  function createStructuralHash(value) {
11216
- const stable = stableStringify2(value);
11424
+ const stable = stableStringify3(value);
11217
11425
  let hash = 2166136261;
11218
11426
  for (let i = 0; i < stable.length; i += 1) {
11219
11427
  hash ^= stable.charCodeAt(i);
@@ -11221,16 +11429,16 @@ function createStructuralHash(value) {
11221
11429
  }
11222
11430
  return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, "0")}`;
11223
11431
  }
11224
- function stableStringify2(value) {
11432
+ function stableStringify3(value) {
11225
11433
  if (value === null || typeof value !== "object") {
11226
11434
  return JSON.stringify(value);
11227
11435
  }
11228
11436
  if (Array.isArray(value)) {
11229
- return `[${value.map((entry) => stableStringify2(entry)).join(",")}]`;
11437
+ return `[${value.map((entry) => stableStringify3(entry)).join(",")}]`;
11230
11438
  }
11231
11439
  const record = value;
11232
11440
  const keys = Object.keys(record).filter((key) => record[key] !== void 0).sort();
11233
- return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify2(record[key])}`).join(",")}}`;
11441
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify3(record[key])}`).join(",")}}`;
11234
11442
  }
11235
11443
 
11236
11444
  // src/runtime/formatting/formatting-context.ts
@@ -11821,6 +12029,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
11821
12029
  ...options.authorColorPalette ? { authorColorPalette: options.authorColorPalette } : {}
11822
12030
  });
11823
12031
  const editableTargetsByBlockPath = options.editableTargetsByBlockPath ?? indexEditableTargetsByBlockPath(document2);
12032
+ const layoutIdentitiesByBlockPath = options.layoutIdentitiesByBlockPath;
11824
12033
  const activeStoryBlockPathBase = getActiveStoryBlockPathBase(document2, activeStory);
11825
12034
  chartModelStore.beginBuildPass(document2);
11826
12035
  const unsupportedNumberingFormatsSeen = options.emitFormattingTelemetry ? /* @__PURE__ */ new Set() : null;
@@ -11844,6 +12053,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
11844
12053
  activeStory.kind !== "main",
11845
12054
  !isInViewport,
11846
12055
  editableTargetsByBlockPath,
12056
+ layoutIdentitiesByBlockPath,
11847
12057
  `${activeStoryBlockPathBase}/block[${index}]`
11848
12058
  );
11849
12059
  if (isInViewport) {
@@ -11910,7 +12120,7 @@ function isIndexInAnyRange(index, ranges) {
11910
12120
  }
11911
12121
  return false;
11912
12122
  }
11913
- function createSurfaceBlock(block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath) {
12123
+ function createSurfaceBlock(block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, blockPath) {
11914
12124
  if (block.type === "opaque_block") {
11915
12125
  const fragment = getOpaqueFragment(document2.preservation, block.fragmentId);
11916
12126
  const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
@@ -11947,6 +12157,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
11947
12157
  promoteSecondaryStoryTextBoxes,
11948
12158
  cullBuild,
11949
12159
  editableTargetsByBlockPath,
12160
+ layoutIdentitiesByBlockPath,
11950
12161
  blockPath
11951
12162
  );
11952
12163
  }
@@ -11987,6 +12198,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
11987
12198
  promoteSecondaryStoryTextBoxes,
11988
12199
  cullBuild,
11989
12200
  editableTargetsByBlockPath,
12201
+ layoutIdentitiesByBlockPath,
11990
12202
  blockPath
11991
12203
  );
11992
12204
  }
@@ -12069,10 +12281,11 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
12069
12281
  cullBuild,
12070
12282
  editableTargetsByBlockPath,
12071
12283
  blockPath,
12072
- blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0
12284
+ blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0,
12285
+ blockPath !== void 0 ? layoutIdentitiesByBlockPath?.get(blockPath) : void 0
12073
12286
  );
12074
12287
  }
12075
- function createTableBlock(tableIndex, table, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, tablePath) {
12288
+ function createTableBlock(tableIndex, table, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, tablePath) {
12076
12289
  const lockedFragmentIds = [];
12077
12290
  let innerCursor = cursor;
12078
12291
  if (cullBuild) {
@@ -12089,6 +12302,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
12089
12302
  promoteSecondaryStoryTextBoxes,
12090
12303
  true,
12091
12304
  editableTargetsByBlockPath,
12305
+ layoutIdentitiesByBlockPath,
12092
12306
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
12093
12307
  );
12094
12308
  lockedFragmentIds.push(...result.lockedFragmentIds);
@@ -12104,6 +12318,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
12104
12318
  to: innerCursor,
12105
12319
  styleId: table.styleId,
12106
12320
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
12321
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
12107
12322
  gridColumns: table.gridColumns,
12108
12323
  rows: []
12109
12324
  },
@@ -12141,6 +12356,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
12141
12356
  promoteSecondaryStoryTextBoxes,
12142
12357
  cullBuild,
12143
12358
  editableTargetsByBlockPath,
12359
+ layoutIdentitiesByBlockPath,
12144
12360
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
12145
12361
  );
12146
12362
  cellContent.push(result.block);
@@ -12229,6 +12445,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
12229
12445
  to: innerCursor,
12230
12446
  styleId: table.styleId,
12231
12447
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
12448
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
12232
12449
  gridColumns: table.gridColumns,
12233
12450
  ...gridColumnsRelative ? { gridColumnsRelative } : {},
12234
12451
  ...resolvedTable.table?.alignment ? { alignment: resolvedTable.table.alignment } : {},
@@ -12416,7 +12633,7 @@ function resolveCellBorderStyles(borders, tableBorders, position) {
12416
12633
  if (left) result.borderLeft = left;
12417
12634
  return result;
12418
12635
  }
12419
- function createSdtBlock(sdtIndex, block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, sdtPath) {
12636
+ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, sdtPath) {
12420
12637
  const children = [];
12421
12638
  const lockedFragmentIds = [];
12422
12639
  let innerCursor = cursor;
@@ -12433,6 +12650,7 @@ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formatting
12433
12650
  promoteSecondaryStoryTextBoxes,
12434
12651
  cullBuild,
12435
12652
  editableTargetsByBlockPath,
12653
+ layoutIdentitiesByBlockPath,
12436
12654
  sdtPath !== void 0 ? `${sdtPath}/block[${childIndex}]` : void 0
12437
12655
  );
12438
12656
  children.push(result.block);
@@ -12475,7 +12693,7 @@ function getRecursableSdtBlockedReasonCode(block) {
12475
12693
  ].filter(Boolean).join(" ").toLowerCase();
12476
12694
  return searchText.includes("table of contents") || /\btoc\b/u.test(searchText) ? "workflow_preserve_only" : null;
12477
12695
  }
12478
- function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget) {
12696
+ function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget, layoutIdentity) {
12479
12697
  const themeResolver = formattingContext.theme;
12480
12698
  const effectiveNumbering = formattingContext.resolveEffectiveParagraphNumbering(paragraph);
12481
12699
  let resolvedNumbering = null;
@@ -12498,6 +12716,7 @@ function createParagraphBlock(paragraphIndex, paragraph, document2, start, forma
12498
12716
  from: start,
12499
12717
  to: start,
12500
12718
  ...editableTarget !== void 0 ? { editableTarget } : {},
12719
+ ...layoutIdentity !== void 0 ? { layoutIdentity } : {},
12501
12720
  ...paragraph.styleId ? { styleId: paragraph.styleId } : {},
12502
12721
  ...effectiveNumbering ? { numbering: effectiveNumbering } : {},
12503
12722
  ...resolvedNumbering ? {
@@ -19588,13 +19807,331 @@ async function createCanvasProvider(fontLoader) {
19588
19807
  }
19589
19808
  }
19590
19809
 
19810
+ // src/runtime/layout/persistent-layout-measurement-cache.ts
19811
+ init_resolved_formatting_state();
19812
+ var DEFAULT_MAX_ENTRIES = 1e4;
19813
+ var DEFAULT_MAX_ESTIMATED_BYTES = 50 * 1024 * 1024;
19814
+ function createPersistentLayoutMeasurementCache(options = {}) {
19815
+ const maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_MAX_ENTRIES);
19816
+ const maxEstimatedBytes = Math.max(
19817
+ 1024,
19818
+ options.maxEstimatedBytes ?? DEFAULT_MAX_ESTIMATED_BYTES
19819
+ );
19820
+ const entries = /* @__PURE__ */ new Map();
19821
+ const counters = {
19822
+ hits: 0,
19823
+ misses: 0,
19824
+ sets: 0,
19825
+ evictions: 0,
19826
+ clears: 0,
19827
+ estimatedBytes: 0,
19828
+ invalidatedByReason: {}
19829
+ };
19830
+ function evictOldest() {
19831
+ const oldest = entries.keys().next();
19832
+ if (oldest.done) return;
19833
+ const entry = entries.get(oldest.value);
19834
+ if (entry) {
19835
+ counters.estimatedBytes -= entry.estimatedBytes;
19836
+ }
19837
+ entries.delete(oldest.value);
19838
+ counters.evictions += 1;
19839
+ }
19840
+ return {
19841
+ get(key) {
19842
+ const cacheKey2 = serializeCacheKey(key);
19843
+ const entry = entries.get(cacheKey2);
19844
+ if (!entry) {
19845
+ counters.misses += 1;
19846
+ return void 0;
19847
+ }
19848
+ entries.delete(cacheKey2);
19849
+ entries.set(cacheKey2, entry);
19850
+ counters.hits += 1;
19851
+ return entry.value;
19852
+ },
19853
+ set(key, value) {
19854
+ const cacheKey2 = serializeCacheKey(key);
19855
+ const previous = entries.get(cacheKey2);
19856
+ if (previous) {
19857
+ counters.estimatedBytes -= previous.estimatedBytes;
19858
+ entries.delete(cacheKey2);
19859
+ }
19860
+ const estimatedBytes = estimateBytes(key, value);
19861
+ entries.set(cacheKey2, { key, value, estimatedBytes });
19862
+ counters.estimatedBytes += estimatedBytes;
19863
+ counters.sets += 1;
19864
+ while (entries.size > maxEntries || counters.estimatedBytes > maxEstimatedBytes) {
19865
+ evictOldest();
19866
+ }
19867
+ },
19868
+ invalidate(reason, predicate) {
19869
+ if (!predicate) {
19870
+ const removed2 = entries.size;
19871
+ counters.estimatedBytes = 0;
19872
+ entries.clear();
19873
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed2;
19874
+ return;
19875
+ }
19876
+ let removed = 0;
19877
+ for (const [cacheKey2, entry] of entries) {
19878
+ if (!predicate(entry.key)) continue;
19879
+ counters.estimatedBytes -= entry.estimatedBytes;
19880
+ entries.delete(cacheKey2);
19881
+ removed += 1;
19882
+ }
19883
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed;
19884
+ },
19885
+ clear(reason) {
19886
+ const removed = entries.size;
19887
+ counters.estimatedBytes = 0;
19888
+ entries.clear();
19889
+ counters.clears += 1;
19890
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed;
19891
+ },
19892
+ stats() {
19893
+ return {
19894
+ hits: counters.hits,
19895
+ misses: counters.misses,
19896
+ sets: counters.sets,
19897
+ evictions: counters.evictions,
19898
+ clears: counters.clears,
19899
+ size: entries.size,
19900
+ estimatedBytes: Math.max(0, counters.estimatedBytes),
19901
+ invalidatedByReason: { ...counters.invalidatedByReason }
19902
+ };
19903
+ }
19904
+ };
19905
+ }
19906
+ function createCachedLayoutMeasurementProvider(delegate, options = {}) {
19907
+ const cache = options.cache ?? createPersistentLayoutMeasurementCache(options);
19908
+ function emitCounter(type, key) {
19909
+ const telemetryBus = options.telemetryBus;
19910
+ if (!telemetryBus?.isEnabled("layout")) return;
19911
+ telemetryBus.emitLazy("layout", () => ({
19912
+ type,
19913
+ payload: key ? {
19914
+ measurementKind: key.measurementKind,
19915
+ blockId: key.blockId,
19916
+ backendVersion: key.backendVersion
19917
+ } : void 0
19918
+ }));
19919
+ }
19920
+ return {
19921
+ get fidelity() {
19922
+ return delegate.fidelity;
19923
+ },
19924
+ measurementCache: cache,
19925
+ measurementCacheStats() {
19926
+ return cache.stats();
19927
+ },
19928
+ whenReady() {
19929
+ return delegate.whenReady();
19930
+ },
19931
+ measureLineFragments(input) {
19932
+ const key = buildLineFragmentsKey(input, delegate, options);
19933
+ const cached = cache.get(key);
19934
+ if (cached) {
19935
+ emitCounter("pageRender.measurement.hit", key);
19936
+ return cloneMeasuredLineFragments(cached);
19937
+ }
19938
+ emitCounter("pageRender.measurement.miss", key);
19939
+ const measured = delegate.measureLineFragments(input);
19940
+ cache.set(key, cloneMeasuredLineFragments(measured));
19941
+ return measured;
19942
+ },
19943
+ measureInlineObject(input) {
19944
+ const key = buildInlineObjectKey(input, delegate, options);
19945
+ const cached = cache.get(key);
19946
+ if (cached) {
19947
+ emitCounter("pageRender.measurement.hit", key);
19948
+ return { ...cached };
19949
+ }
19950
+ emitCounter("pageRender.measurement.miss", key);
19951
+ const measured = delegate.measureInlineObject(input);
19952
+ cache.set(key, { ...measured });
19953
+ return measured;
19954
+ },
19955
+ measureTableBlock(input) {
19956
+ const key = buildTableBlockKey(input, delegate, options);
19957
+ const cached = cache.get(key);
19958
+ if (cached) {
19959
+ emitCounter("pageRender.measurement.hit", key);
19960
+ return cloneMeasuredTableBlock(cached);
19961
+ }
19962
+ emitCounter("pageRender.measurement.miss", key);
19963
+ const measured = delegate.measureTableBlock(input);
19964
+ cache.set(key, cloneMeasuredTableBlock(measured));
19965
+ return measured;
19966
+ },
19967
+ invalidateCache() {
19968
+ delegate.invalidateCache();
19969
+ cache.clear("provider.invalidateCache");
19970
+ emitCounter("pageRender.measurement.invalidated.provider.invalidateCache");
19971
+ }
19972
+ };
19973
+ }
19974
+ function isCachedLayoutMeasurementProvider(provider) {
19975
+ return typeof provider.measurementCacheStats === "function";
19976
+ }
19977
+ function buildLineFragmentsKey(input, delegate, options) {
19978
+ const block = input.block;
19979
+ const identity = measurementIdentityForBlock(block);
19980
+ return {
19981
+ measurementKind: "line-fragments",
19982
+ blockId: identity.blockId,
19983
+ blockPath: identity.blockPath,
19984
+ contentHash: hashStable2({
19985
+ kind: block.kind,
19986
+ identity: identity.identityHash,
19987
+ segments: block.segments,
19988
+ numbering: block.numbering,
19989
+ numberingPrefix: block.numberingPrefix,
19990
+ numberingSuffix: block.numberingSuffix,
19991
+ resolvedNumbering: block.resolvedNumbering
19992
+ }),
19993
+ formattingHash: createLayoutReadyFormattingSnapshot(
19994
+ input.formatting,
19995
+ input.runs
19996
+ ).hash,
19997
+ constraintsHash: hashStable2({ columnWidth: input.columnWidth }),
19998
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
19999
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
20000
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
20001
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
20002
+ };
20003
+ }
20004
+ function buildInlineObjectKey(input, delegate, options) {
20005
+ return {
20006
+ measurementKind: "inline-object",
20007
+ blockId: "inline-object",
20008
+ blockPath: "inline-object",
20009
+ contentHash: hashStable2({ display: input.display }),
20010
+ formattingHash: "format:none",
20011
+ constraintsHash: hashStable2({
20012
+ widthTwips: input.widthTwips,
20013
+ heightTwips: input.heightTwips
20014
+ }),
20015
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
20016
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
20017
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
20018
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
20019
+ };
20020
+ }
20021
+ function buildTableBlockKey(input, delegate, options) {
20022
+ const block = input.block;
20023
+ const identity = measurementIdentityForBlock(block);
20024
+ return {
20025
+ measurementKind: "table-block",
20026
+ blockId: identity.blockId,
20027
+ blockPath: identity.blockPath,
20028
+ contentHash: hashStable2({
20029
+ kind: block.kind,
20030
+ identity: identity.identityHash,
20031
+ rows: block.rows,
20032
+ gridColumns: block.gridColumns,
20033
+ gridColumnsRelative: block.gridColumnsRelative,
20034
+ tableResolved: block.tableResolved,
20035
+ tblLook: block.tblLook
20036
+ }),
20037
+ formattingHash: hashStable2({
20038
+ styleId: block.styleId,
20039
+ alignment: block.alignment
20040
+ }),
20041
+ constraintsHash: hashStable2({ columnWidth: input.columnWidth }),
20042
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
20043
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
20044
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
20045
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
20046
+ };
20047
+ }
20048
+ function measurementIdentityForBlock(block) {
20049
+ const identity = block.layoutIdentity;
20050
+ if (!identity) {
20051
+ return {
20052
+ blockId: block.blockId,
20053
+ blockPath: blockPathForBlock(block),
20054
+ identityHash: "identity:legacy"
20055
+ };
20056
+ }
20057
+ return {
20058
+ blockId: identity.blockId,
20059
+ blockPath: identity.blockPath,
20060
+ identityHash: hashStable2({
20061
+ storyKey: identity.storyKey,
20062
+ blockId: identity.blockId,
20063
+ blockPath: identity.blockPath,
20064
+ sourceRef: identity.sourceRef,
20065
+ table: identity.table,
20066
+ list: identity.list,
20067
+ field: identity.field,
20068
+ object: identity.object
20069
+ })
20070
+ };
20071
+ }
20072
+ function blockPathForBlock(block) {
20073
+ return `${block.from}:${block.to}`;
20074
+ }
20075
+ function resolveOptionValue(option, fallback) {
20076
+ if (typeof option === "function") return option();
20077
+ return option ?? fallback;
20078
+ }
20079
+ function serializeCacheKey(key) {
20080
+ return stableStringify4(key);
20081
+ }
20082
+ function estimateBytes(key, value) {
20083
+ return stableStringify4(key).length + stableStringify4(value).length;
20084
+ }
20085
+ function cloneMeasuredLineFragments(value) {
20086
+ return {
20087
+ lineCount: value.lineCount,
20088
+ maxLineWidth: value.maxLineWidth,
20089
+ lineHeights: [...value.lineHeights]
20090
+ };
20091
+ }
20092
+ function cloneMeasuredTableBlock(value) {
20093
+ return {
20094
+ totalHeightTwips: value.totalHeightTwips,
20095
+ rowHeights: [...value.rowHeights]
20096
+ };
20097
+ }
20098
+ function hashStable2(value) {
20099
+ return fnv1a2(stableStringify4(value)).toString(36);
20100
+ }
20101
+ function stableStringify4(value) {
20102
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
20103
+ if (Array.isArray(value)) {
20104
+ return `[${value.map((item) => stableStringify4(item)).join(",")}]`;
20105
+ }
20106
+ if (value instanceof Map) {
20107
+ return stableStringify4(Array.from(value.entries()));
20108
+ }
20109
+ const object = value;
20110
+ const keys = Object.keys(object).filter((key) => object[key] !== void 0 && typeof object[key] !== "function").sort();
20111
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify4(object[key])}`).join(",")}}`;
20112
+ }
20113
+ function fnv1a2(input) {
20114
+ let hash = 2166136261;
20115
+ for (let i = 0; i < input.length; i += 1) {
20116
+ hash ^= input.charCodeAt(i);
20117
+ hash = Math.imul(hash, 16777619);
20118
+ }
20119
+ return hash >>> 0;
20120
+ }
20121
+
19591
20122
  // src/runtime/layout/layout-engine-version.ts
19592
- var LAYOUT_ENGINE_VERSION = 89;
20123
+ var LAYOUT_ENGINE_VERSION = 93;
19593
20124
  var LAYCACHE_SCHEMA_VERSION = 12;
19594
20125
 
19595
20126
  // src/runtime/layout/layout-engine-instance.ts
19596
20127
  var FULL_VIEWPORT_WINDOW_KEY = "full";
19597
20128
  var DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER = 1;
20129
+ function indexLayoutIdentitiesByBlockPath(identities) {
20130
+ return new Map(identities.map((identity) => [identity.blockPath, identity]));
20131
+ }
20132
+ function indexEditableTargetsByBlockPath2(targets) {
20133
+ return new Map(targets.map((target) => [target.blockPath, target]));
20134
+ }
19598
20135
  function normalizeViewportPageWindow(window2) {
19599
20136
  if (!window2) return void 0;
19600
20137
  const buffer = Number.isFinite(window2.bufferPages) ? Math.max(0, Math.floor(window2.bufferPages ?? 0)) : DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER;
@@ -19790,8 +20327,22 @@ function recordFullRebuildReason(reasonKind) {
19790
20327
  probe.invalidationCounts[totalKey] = (probe.invalidationCounts[totalKey] ?? 0) + 1;
19791
20328
  probe.invalidationCounts[byReasonKey] = (probe.invalidationCounts[byReasonKey] ?? 0) + 1;
19792
20329
  }
20330
+ function wrapMeasurementProvider(provider, measurementCache, telemetryBus) {
20331
+ if (!measurementCache || isCachedLayoutMeasurementProvider(provider)) {
20332
+ return provider;
20333
+ }
20334
+ const cacheOptions = measurementCache === true ? {} : measurementCache;
20335
+ return createCachedLayoutMeasurementProvider(provider, {
20336
+ ...cacheOptions,
20337
+ ...telemetryBus ? { telemetryBus } : {}
20338
+ });
20339
+ }
19793
20340
  function createLayoutEngine(options = {}) {
19794
- let measurementProvider = options.measurementProvider ?? createEmpiricalMeasurementProvider();
20341
+ let measurementProvider = wrapMeasurementProvider(
20342
+ options.measurementProvider ?? createEmpiricalMeasurementProvider(),
20343
+ options.measurementCache,
20344
+ options.telemetryBus
20345
+ );
19795
20346
  const autoUpgradeToCanvas = options.autoUpgradeToCanvasBackend !== false;
19796
20347
  const telemetryBus = options.telemetryBus;
19797
20348
  const dirtyFieldFamilies = /* @__PURE__ */ new Set();
@@ -19891,13 +20442,20 @@ function createLayoutEngine(options = {}) {
19891
20442
  const pageCountBeforeRecompute = previousPageCount;
19892
20443
  const document2 = input.document;
19893
20444
  const viewportWindow = normalizeViewportPageWindow(input.viewportPageWindow);
20445
+ const layoutInputs = collectCanonicalLayoutInputs(document2);
20446
+ const layoutIdentitiesByBlockPath = indexLayoutIdentitiesByBlockPath(
20447
+ layoutInputs.layoutIdentities
20448
+ );
20449
+ const editableTargetsByBlockPath = indexEditableTargetsByBlockPath2(
20450
+ layoutInputs.editableTargets
20451
+ );
19894
20452
  const mainSurface = createEditorSurfaceSnapshot(
19895
20453
  document2,
19896
20454
  createSelectionSnapshot(0, 0),
19897
- MAIN_STORY_TARGET
20455
+ MAIN_STORY_TARGET,
20456
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
19898
20457
  );
19899
20458
  const sections = buildResolvedSections(document2);
19900
- const layoutInputs = collectCanonicalLayoutInputs(document2);
19901
20459
  const fieldRegions = layoutInputs.fieldRegions;
19902
20460
  const pageStack = buildPageStackWithSplits(
19903
20461
  document2,
@@ -20009,10 +20567,18 @@ function createLayoutEngine(options = {}) {
20009
20567
  const firstDirty = range.firstPageIndex;
20010
20568
  if (firstDirty < 0 || firstDirty >= priorGraph.pages.length) return null;
20011
20569
  const document2 = input.document;
20570
+ const layoutInputs = collectCanonicalLayoutInputs(document2);
20571
+ const layoutIdentitiesByBlockPath = indexLayoutIdentitiesByBlockPath(
20572
+ layoutInputs.layoutIdentities
20573
+ );
20574
+ const editableTargetsByBlockPath = indexEditableTargetsByBlockPath2(
20575
+ layoutInputs.editableTargets
20576
+ );
20012
20577
  const mainSurface = createEditorSurfaceSnapshot(
20013
20578
  document2,
20014
20579
  createSelectionSnapshot(0, 0),
20015
- MAIN_STORY_TARGET
20580
+ MAIN_STORY_TARGET,
20581
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
20016
20582
  );
20017
20583
  const sections = buildResolvedSections(document2);
20018
20584
  const dirtyPage = priorGraph.pages[firstDirty];
@@ -20041,7 +20607,6 @@ function createLayoutEngine(options = {}) {
20041
20607
  const freshSnapshotsToRebuild = freshSnapshots.slice(0, convergenceIndex);
20042
20608
  const convergedTailStart = convergenceIndex < freshSnapshots.length ? firstDirty + convergenceIndex : void 0;
20043
20609
  const freshStories = resolvePageStories(freshSnapshotsToRebuild);
20044
- const layoutInputs = collectCanonicalLayoutInputs(document2);
20045
20610
  const fieldRegions = layoutInputs.fieldRegions;
20046
20611
  const freshBodyFragmentsByPageIndex = projectSurfaceBlocksToPageFragments(
20047
20612
  mainSurface,
@@ -20173,7 +20738,11 @@ function createLayoutEngine(options = {}) {
20173
20738
  try {
20174
20739
  const mod = await Promise.resolve().then(() => (init_measurement_backend_canvas(), measurement_backend_canvas_exports));
20175
20740
  const canvasProvider = mod.createCanvasBackend();
20176
- measurementProvider = canvasProvider;
20741
+ measurementProvider = wrapMeasurementProvider(
20742
+ canvasProvider,
20743
+ options.measurementCache,
20744
+ telemetryBus
20745
+ );
20177
20746
  cachedKey = null;
20178
20747
  cachedGraph = null;
20179
20748
  cachedFormatting = null;
@@ -20258,7 +20827,11 @@ function createLayoutEngine(options = {}) {
20258
20827
  },
20259
20828
  swapMeasurementProvider(provider) {
20260
20829
  const previousFidelity = measurementProvider.fidelity;
20261
- measurementProvider = provider;
20830
+ measurementProvider = wrapMeasurementProvider(
20831
+ provider,
20832
+ options.measurementCache,
20833
+ telemetryBus
20834
+ );
20262
20835
  if (previousFidelity !== provider.fidelity) {
20263
20836
  cachedKey = null;
20264
20837
  cachedGraph = null;
@@ -20287,6 +20860,10 @@ function createLayoutEngine(options = {}) {
20287
20860
  cachedFormatting = null;
20288
20861
  cachedMapper = null;
20289
20862
  },
20863
+ getMeasurementCacheStats() {
20864
+ if (!isCachedLayoutMeasurementProvider(measurementProvider)) return null;
20865
+ return measurementProvider.measurementCacheStats();
20866
+ },
20290
20867
  /**
20291
20868
  * L7 Phase 2.5 — seed the cached graph from a prerender envelope.
20292
20869
  * Populates both `cachedGraph` and `cachedKey` (keyed on the provided
@@ -41770,6 +42347,76 @@ function diffRenderFrames(prev, next) {
41770
42347
  }
41771
42348
  return { addedPages, removedPages, unchangedPages, changedPages };
41772
42349
  }
42350
+ function createPagePatchPlan(prev, next, diff = diffRenderFrames(prev, next), options = {}) {
42351
+ const prevByIndex = indexPagesByIndex(prev?.pages ?? []);
42352
+ const nextByIndex = indexPagesByIndex(next.pages);
42353
+ const addedPages = diff.addedPages.map(
42354
+ (pageIndex) => pageIdForIndex(nextByIndex, pageIndex)
42355
+ );
42356
+ const removedPages = diff.removedPages.map(
42357
+ (pageIndex) => pageIdForIndex(prevByIndex, pageIndex)
42358
+ );
42359
+ const unchangedPages = diff.unchangedPages.map(
42360
+ (pageIndex) => pageIdForIndex(nextByIndex, pageIndex)
42361
+ );
42362
+ const changedPages = diff.changedPages.map(
42363
+ (entry) => createPagePatchEntry(entry, pageIdForIndex(nextByIndex, entry.pageIndex), options)
42364
+ );
42365
+ return {
42366
+ layoutRevision: options.layoutRevision ?? next.revision,
42367
+ geometryRevision: options.geometryRevision ?? next.revision,
42368
+ addedPages,
42369
+ removedPages,
42370
+ unchangedPages,
42371
+ changedPages,
42372
+ mountChanges: resolveMountChanges({
42373
+ addedPages,
42374
+ removedPages,
42375
+ mountedPageIds: options.mountedPageIds,
42376
+ requestedMountPageIds: options.requestedMountPageIds
42377
+ })
42378
+ };
42379
+ }
42380
+ function createPagePatchEntry(entry, pageId, options) {
42381
+ const regionChanges = entry.regions.map((region) => region.kind);
42382
+ const fragmentChanges = uniqueStrings(
42383
+ entry.regions.flatMap((region) => region.changedBlockIds)
42384
+ );
42385
+ const overlayLaneChanges = !entry.pageFrameChanged && entry.regions.length === 0 ? ["chrome-reservations"] : [];
42386
+ return {
42387
+ pageId,
42388
+ pageIndex: entry.pageIndex,
42389
+ frameChanged: entry.pageFrameChanged === true,
42390
+ regionChanges,
42391
+ fragmentChanges,
42392
+ lineBoxChanges: fragmentChanges,
42393
+ overlayLaneChanges,
42394
+ reason: options.reason ?? (overlayLaneChanges.length > 0 ? "overlay" : "layout")
42395
+ };
42396
+ }
42397
+ function resolveMountChanges(input) {
42398
+ if (!input.mountedPageIds || !input.requestedMountPageIds) {
42399
+ return {
42400
+ mountPageIds: input.addedPages,
42401
+ unmountPageIds: input.removedPages
42402
+ };
42403
+ }
42404
+ const mounted = new Set(input.mountedPageIds);
42405
+ const requested = new Set(input.requestedMountPageIds);
42406
+ return {
42407
+ mountPageIds: input.requestedMountPageIds.filter((pageId) => !mounted.has(pageId)),
42408
+ unmountPageIds: input.mountedPageIds.filter((pageId) => !requested.has(pageId))
42409
+ };
42410
+ }
42411
+ function indexPagesByIndex(pages) {
42412
+ return new Map(pages.map((page) => [page.page.pageIndex, page]));
42413
+ }
42414
+ function pageIdForIndex(pages, pageIndex) {
42415
+ return pages.get(pageIndex)?.page.pageId ?? `page:${pageIndex}`;
42416
+ }
42417
+ function uniqueStrings(values) {
42418
+ return [...new Set(values)];
42419
+ }
41773
42420
  function diffPage(prev, next, prevIndex, nextIndex) {
41774
42421
  const changed = [];
41775
42422
  const bodyChanges = diffRegion(prev.regions.body, next.regions.body, prevIndex, nextIndex);
@@ -41990,10 +42637,12 @@ function createRenderKernel(input) {
41990
42637
  emit2({ kind: "frame_built", revision: frame.revision, reason: "full" });
41991
42638
  const diffT0 = typeof performance !== "undefined" ? performance.now() : 0;
41992
42639
  const diff = diffRenderFrames(lastEmittedFrame, frame);
42640
+ const patchPlan = createPagePatchPlan(lastEmittedFrame, frame, diff);
42641
+ recordPagePatchPlanTelemetry(patchPlan);
41993
42642
  if (diffT0 > 0) {
41994
42643
  recordPerfSample("render.frame_diff", performance.now() - diffT0);
41995
42644
  }
41996
- emit2({ kind: "frame_diff", revision: frame.revision, diff });
42645
+ emit2({ kind: "frame_diff", revision: frame.revision, diff, patchPlan });
41997
42646
  lastEmittedFrame = frame;
41998
42647
  }
41999
42648
  return frame;
@@ -42016,6 +42665,35 @@ function createRenderKernel(input) {
42016
42665
  }
42017
42666
  };
42018
42667
  }
42668
+ function recordPagePatchPlanTelemetry(plan) {
42669
+ incrementInvalidationCounter(
42670
+ "pageRender.patch.addedPages",
42671
+ plan.addedPages.length
42672
+ );
42673
+ incrementInvalidationCounter(
42674
+ "pageRender.patch.removedPages",
42675
+ plan.removedPages.length
42676
+ );
42677
+ incrementInvalidationCounter(
42678
+ "pageRender.patch.unchangedPages",
42679
+ plan.unchangedPages.length
42680
+ );
42681
+ incrementInvalidationCounter(
42682
+ "pageRender.patch.changedFragments",
42683
+ plan.changedPages.reduce(
42684
+ (total, page) => total + page.fragmentChanges.length,
42685
+ 0
42686
+ )
42687
+ );
42688
+ incrementInvalidationCounter(
42689
+ "pageRender.patch.mountedPages",
42690
+ plan.mountChanges.mountPageIds.length
42691
+ );
42692
+ incrementInvalidationCounter(
42693
+ "pageRender.patch.unmountedPages",
42694
+ plan.mountChanges.unmountPageIds.length
42695
+ );
42696
+ }
42019
42697
  function buildPage(page, topPx, zoom, activeStory, facet) {
42020
42698
  const layout = page.layout;
42021
42699
  const widthPx = layout.pageWidth * zoom.pxPerTwip;
@@ -45147,26 +45825,35 @@ function buildParagraphPropertiesXml(paragraph) {
45147
45825
  if (frameXml) children.push(frameXml);
45148
45826
  }
45149
45827
  pushOnOffParagraphProperty(children, "widowControl", paragraph.widowControl);
45150
- if (paragraph.outlineLevel !== void 0) {
45151
- children.push(`<w:outlineLvl w:val="${paragraph.outlineLevel}"/>`);
45152
- }
45153
45828
  if (paragraph.numbering) {
45154
45829
  children.push(serializeParagraphNumberingProperties(paragraph.numbering));
45155
45830
  }
45831
+ pushOnOffParagraphProperty(children, "suppressLineNumbers", paragraph.suppressLineNumbers);
45832
+ if (paragraph.borders) {
45833
+ const bordersXml = serializeParagraphBorders(paragraph.borders);
45834
+ if (bordersXml) children.push(bordersXml);
45835
+ }
45836
+ if (paragraph.shading) {
45837
+ const shadingXml = serializeParagraphShading(paragraph.shading);
45838
+ if (shadingXml) children.push(shadingXml);
45839
+ }
45840
+ if (paragraph.tabStops && paragraph.tabStops.length > 0) {
45841
+ const tabsXml = paragraph.tabStops.map((tab) => {
45842
+ const leaderAttr = tab.leader ? ` w:leader="${escapeXmlAttribute2(tab.leader)}"` : "";
45843
+ return `<w:tab w:val="${escapeXmlAttribute2(tab.align)}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
45844
+ }).join("");
45845
+ children.push(`<w:tabs>${tabsXml}</w:tabs>`);
45846
+ }
45847
+ pushOnOffParagraphProperty(children, "bidi", paragraph.bidi);
45156
45848
  if (paragraph.spacing) {
45157
45849
  const s = paragraph.spacing;
45158
45850
  const attrs = [];
45159
45851
  if (s.before !== void 0) attrs.push(`w:before="${twip(s.before)}"`);
45160
45852
  if (s.after !== void 0) attrs.push(`w:after="${twip(s.after)}"`);
45161
45853
  if (s.line !== void 0) attrs.push(`w:line="${twip(s.line)}"`);
45162
- if (s.lineRule !== void 0) attrs.push(`w:lineRule="${s.lineRule}"`);
45854
+ if (s.lineRule !== void 0) attrs.push(`w:lineRule="${escapeXmlAttribute2(s.lineRule)}"`);
45163
45855
  if (attrs.length > 0) children.push(`<w:spacing ${attrs.join(" ")}/>`);
45164
45856
  }
45165
- if (paragraph.contextualSpacing === true) {
45166
- children.push("<w:contextualSpacing/>");
45167
- } else if (paragraph.contextualSpacing === false) {
45168
- children.push(`<w:contextualSpacing w:val="false"/>`);
45169
- }
45170
45857
  if (paragraph.indentation) {
45171
45858
  const ind = paragraph.indentation;
45172
45859
  const attrs = [];
@@ -45176,33 +45863,20 @@ function buildParagraphPropertiesXml(paragraph) {
45176
45863
  if (ind.hanging !== void 0) attrs.push(`w:hanging="${twip(ind.hanging)}"`);
45177
45864
  if (attrs.length > 0) children.push(`<w:ind ${attrs.join(" ")}/>`);
45178
45865
  }
45179
- if (paragraph.alignment) {
45180
- children.push(`<w:jc w:val="${paragraph.alignment}"/>`);
45866
+ if (paragraph.contextualSpacing === true) {
45867
+ children.push("<w:contextualSpacing/>");
45868
+ } else if (paragraph.contextualSpacing === false) {
45869
+ children.push(`<w:contextualSpacing w:val="false"/>`);
45181
45870
  }
45182
- if (paragraph.borders) {
45183
- const bordersXml = serializeParagraphBorders(paragraph.borders);
45184
- if (bordersXml) {
45185
- children.push(bordersXml);
45186
- }
45871
+ if (paragraph.alignment) {
45872
+ children.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
45187
45873
  }
45188
- if (paragraph.shading) {
45189
- const shadingXml = serializeParagraphShading(paragraph.shading);
45190
- if (shadingXml) {
45191
- children.push(shadingXml);
45192
- }
45874
+ if (paragraph.outlineLevel !== void 0) {
45875
+ children.push(`<w:outlineLvl w:val="${paragraph.outlineLevel}"/>`);
45193
45876
  }
45194
- pushOnOffParagraphProperty(children, "bidi", paragraph.bidi);
45195
- pushOnOffParagraphProperty(children, "suppressLineNumbers", paragraph.suppressLineNumbers);
45196
45877
  if (paragraph.cnfStyle) {
45197
45878
  children.push(`<w:cnfStyle w:val="${escapeXmlAttribute2(paragraph.cnfStyle)}"/>`);
45198
45879
  }
45199
- if (paragraph.tabStops && paragraph.tabStops.length > 0) {
45200
- const tabsXml = paragraph.tabStops.map((tab) => {
45201
- const leaderAttr = tab.leader ? ` w:leader="${tab.leader}"` : "";
45202
- return `<w:tab w:val="${tab.align}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
45203
- }).join("");
45204
- children.push(`<w:tabs>${tabsXml}</w:tabs>`);
45205
- }
45206
45880
  if (children.length === 0) return "";
45207
45881
  return `<w:pPr>${children.join("")}</w:pPr>`;
45208
45882
  }
@@ -45767,79 +46441,86 @@ function serializeRunProperties(marks) {
45767
46441
  if (!marks || marks.length === 0) {
45768
46442
  return "";
45769
46443
  }
46444
+ const orderedTypes = [
46445
+ "fontFamily",
46446
+ "bold",
46447
+ "italic",
46448
+ "allCaps",
46449
+ "smallCaps",
46450
+ "strikethrough",
46451
+ "doubleStrikethrough",
46452
+ "shadow",
46453
+ "emboss",
46454
+ "imprint",
46455
+ "vanish",
46456
+ "textColor",
46457
+ "charSpacing",
46458
+ "kerning",
46459
+ "position",
46460
+ "fontSize",
46461
+ "highlight",
46462
+ "underline",
46463
+ "backgroundColor",
46464
+ "lang",
46465
+ "textFill"
46466
+ ];
45770
46467
  const markParts = [];
45771
- for (const mark of marks) {
45772
- switch (mark.type) {
45773
- case "bold":
45774
- markParts.push("<w:b/>");
45775
- break;
45776
- case "italic":
45777
- markParts.push("<w:i/>");
45778
- break;
45779
- case "underline":
45780
- markParts.push(`<w:u w:val="single"/>`);
45781
- break;
45782
- case "strikethrough":
45783
- markParts.push("<w:strike/>");
45784
- break;
45785
- case "doubleStrikethrough":
45786
- markParts.push("<w:dstrike/>");
45787
- break;
45788
- case "vanish":
45789
- markParts.push("<w:vanish/>");
45790
- break;
45791
- case "lang":
45792
- markParts.push(`<w:lang w:val="${escapeXmlAttribute2(mark.val)}"/>`);
45793
- break;
45794
- case "highlight":
45795
- markParts.push(`<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`);
45796
- break;
45797
- case "backgroundColor":
45798
- markParts.push(
45799
- `<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`
45800
- );
45801
- break;
45802
- case "charSpacing":
45803
- markParts.push(`<w:spacing w:val="${mark.val}"/>`);
45804
- break;
45805
- case "kerning":
45806
- markParts.push(`<w:kern w:val="${mark.val}"/>`);
45807
- break;
45808
- case "emboss":
45809
- markParts.push("<w:emboss/>");
45810
- break;
45811
- case "imprint":
45812
- markParts.push("<w:imprint/>");
45813
- break;
45814
- case "shadow":
45815
- markParts.push("<w:shadow/>");
45816
- break;
45817
- case "position":
45818
- markParts.push(`<w:position w:val="${mark.val}"/>`);
45819
- break;
45820
- case "textFill":
45821
- markParts.push(mark.xml);
45822
- break;
45823
- case "fontFamily":
45824
- markParts.push(`<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`);
45825
- break;
45826
- case "fontSize":
45827
- markParts.push(`<w:sz w:val="${mark.val}"/>`);
45828
- break;
45829
- case "textColor":
45830
- markParts.push(`<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`);
45831
- break;
45832
- case "smallCaps":
45833
- markParts.push("<w:smallCaps/>");
45834
- break;
45835
- case "allCaps":
45836
- markParts.push("<w:caps/>");
45837
- break;
46468
+ for (const type of orderedTypes) {
46469
+ for (const mark of marks) {
46470
+ if (mark.type !== type) continue;
46471
+ const xml = serializeRunPropertyMark(mark);
46472
+ if (xml) markParts.push(xml);
45838
46473
  }
45839
46474
  }
45840
46475
  const children = markParts.join("");
45841
46476
  return children.length > 0 ? `<w:rPr>${children}</w:rPr>` : "";
45842
46477
  }
46478
+ function serializeRunPropertyMark(mark) {
46479
+ switch (mark.type) {
46480
+ case "bold":
46481
+ return "<w:b/>";
46482
+ case "italic":
46483
+ return "<w:i/>";
46484
+ case "underline":
46485
+ return `<w:u w:val="single"/>`;
46486
+ case "strikethrough":
46487
+ return "<w:strike/>";
46488
+ case "doubleStrikethrough":
46489
+ return "<w:dstrike/>";
46490
+ case "vanish":
46491
+ return "<w:vanish/>";
46492
+ case "lang":
46493
+ return `<w:lang w:val="${escapeXmlAttribute2(mark.val)}"/>`;
46494
+ case "highlight":
46495
+ return `<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`;
46496
+ case "backgroundColor":
46497
+ return `<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`;
46498
+ case "charSpacing":
46499
+ return `<w:spacing w:val="${mark.val}"/>`;
46500
+ case "kerning":
46501
+ return `<w:kern w:val="${mark.val}"/>`;
46502
+ case "emboss":
46503
+ return "<w:emboss/>";
46504
+ case "imprint":
46505
+ return "<w:imprint/>";
46506
+ case "shadow":
46507
+ return "<w:shadow/>";
46508
+ case "position":
46509
+ return `<w:position w:val="${mark.val}"/>`;
46510
+ case "textFill":
46511
+ return mark.xml;
46512
+ case "fontFamily":
46513
+ return `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`;
46514
+ case "fontSize":
46515
+ return `<w:sz w:val="${mark.val}"/>`;
46516
+ case "textColor":
46517
+ return `<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`;
46518
+ case "smallCaps":
46519
+ return "<w:smallCaps/>";
46520
+ case "allCaps":
46521
+ return "<w:caps/>";
46522
+ }
46523
+ }
45843
46524
  function requiresPreservedSpace(text) {
45844
46525
  return /^\s/.test(text) || /\s$/.test(text) || text.includes(" ");
45845
46526
  }
@@ -50462,6 +51143,19 @@ function paragraphHasBookmarkId(paragraph, bookmarkId) {
50462
51143
  function commandActionHandleForAddress(commandFamily, address) {
50463
51144
  return address ? `scope-command:${commandFamily}:${address.addressKey}` : void 0;
50464
51145
  }
51146
+ function layoutIdentityIndexes(document2) {
51147
+ const byTargetKey = /* @__PURE__ */ new Map();
51148
+ const byStoryBlockPath = /* @__PURE__ */ new Map();
51149
+ for (const identity of collectLayoutInputIdentities(document2)) {
51150
+ byStoryBlockPath.set(`${identity.storyKey}:${identity.blockPath}`, identity);
51151
+ const targetKey = identity.editableTargetRef?.targetKey;
51152
+ if (targetKey) byTargetKey.set(targetKey, identity);
51153
+ }
51154
+ return { byTargetKey, byStoryBlockPath };
51155
+ }
51156
+ function layoutIdentityForTarget(target, indexes) {
51157
+ return indexes.byTargetKey.get(target.targetKey) ?? indexes.byStoryBlockPath.get(`${target.storyKey}:${target.blockPath}`);
51158
+ }
50465
51159
  function withCommandAction(evidence, target, canonicalAddress = target.canonicalAddress) {
50466
51160
  if (evidence.status !== "supported" || !canonicalAddress) return evidence;
50467
51161
  return {
@@ -50473,6 +51167,24 @@ function withCommandAction(evidence, target, canonicalAddress = target.canonical
50473
51167
  function commandAddressForTarget(target, scopeKind) {
50474
51168
  return scopeKind === "list-item" && target.listAddress !== void 0 ? target.listAddress : target.canonicalAddress;
50475
51169
  }
51170
+ function freezeCommandIntents(intents) {
51171
+ return Object.freeze([...new Set(intents)]);
51172
+ }
51173
+ function relatedListActionHandlesForTarget(target, primaryAddress) {
51174
+ if (target.commandFamily !== "text-leaf" || target.listAddress === void 0 || !LIST_TEXT_TARGET_KINDS2.has(target.kind) || target.listAddress.addressKey === primaryAddress?.addressKey) {
51175
+ return void 0;
51176
+ }
51177
+ const actionHandle = commandActionHandleForAddress(target.commandFamily, target.listAddress);
51178
+ if (!actionHandle) return void 0;
51179
+ return Object.freeze([
51180
+ {
51181
+ actionHandle,
51182
+ canonicalAddress: target.listAddress,
51183
+ intents: freezeCommandIntents(["list-text-edit", "list-structure-action"]),
51184
+ reason: "l07:list-address-target-supported"
51185
+ }
51186
+ ]);
51187
+ }
50476
51188
  function runtimeTextCommandEvidence(target, workflowBlockers) {
50477
51189
  const shapeIssues = validateEditableTargetRef(target);
50478
51190
  if (shapeIssues.length > 0) {
@@ -50572,13 +51284,16 @@ function runtimeCommandEvidence(target, workflowBlockers, textCommand, scopeKind
50572
51284
  };
50573
51285
  }
50574
51286
  if (target.commandFamily === "text-leaf") {
51287
+ const canonicalAddress = commandAddressForTarget(target, scopeKind);
51288
+ const relatedActionHandles = relatedListActionHandlesForTarget(target, canonicalAddress);
50575
51289
  return withCommandAction({
50576
51290
  status: textCommand.status,
50577
51291
  commandFamily: target.commandFamily,
50578
51292
  intents: commandIntentsForTarget(target, scopeKind),
50579
51293
  reason: textCommand.reason,
51294
+ ...relatedActionHandles !== void 0 ? { relatedActionHandles } : {},
50580
51295
  ...textCommand.blockers ? { blockers: textCommand.blockers } : {}
50581
- }, target, commandAddressForTarget(target, scopeKind));
51296
+ }, target, canonicalAddress);
50582
51297
  }
50583
51298
  if (target.commandFamily === "comment-revision") {
50584
51299
  const isOpen = target.review?.status === "open";
@@ -50903,19 +51618,21 @@ function commandIntentsForTarget(target, scopeKind) {
50903
51618
  if (target.kind === "hyperlink-text") {
50904
51619
  return Object.freeze(["text-leaf-edit", "hyperlink-display-text-edit"]);
50905
51620
  }
50906
- if (target.table?.operationScope === "text") {
50907
- return Object.freeze([
50908
- "text-leaf-edit",
50909
- "table-text-paste",
50910
- "table-text-drop",
50911
- "table-structured-fragment-paste",
50912
- "table-structured-fragment-drop"
50913
- ]);
50914
- }
50915
- if (scopeKind === "list-item" && LIST_TEXT_TARGET_KINDS2.has(target.kind)) {
50916
- return Object.freeze(["text-leaf-edit", "list-text-edit", "list-structure-action"]);
51621
+ {
51622
+ const intents = ["text-leaf-edit"];
51623
+ if (target.table?.operationScope === "text") {
51624
+ intents.push(
51625
+ "table-text-paste",
51626
+ "table-text-drop",
51627
+ "table-structured-fragment-paste",
51628
+ "table-structured-fragment-drop"
51629
+ );
51630
+ }
51631
+ if ((scopeKind === "list-item" || target.listAddress !== void 0) && LIST_TEXT_TARGET_KINDS2.has(target.kind)) {
51632
+ intents.push("list-text-edit", "list-structure-action");
51633
+ }
51634
+ return freezeCommandIntents(intents);
50917
51635
  }
50918
- return Object.freeze(["text-leaf-edit"]);
50919
51636
  case "field":
50920
51637
  return Object.freeze(
50921
51638
  target.field?.fieldFamily === "TOC" ? ["toc-refresh", "field-update"] : ["field-update"]
@@ -51062,7 +51779,7 @@ function readbackForTarget(document2, target, runtimeTextCommand) {
51062
51779
  source: "canonical-text-leaf"
51063
51780
  };
51064
51781
  }
51065
- function projectTarget(document2, target, relation, workflowBlockers, scopeKind) {
51782
+ function projectTarget(document2, target, relation, workflowBlockers, scopeKind, layoutIdentity) {
51066
51783
  const runtimeTextCommand = runtimeTextCommandEvidence(target, workflowBlockers);
51067
51784
  const readback = readbackForTarget(document2, target, runtimeTextCommand);
51068
51785
  return {
@@ -51083,6 +51800,7 @@ function projectTarget(document2, target, relation, workflowBlockers, scopeKind)
51083
51800
  ...target.table ? { table: target.table } : {},
51084
51801
  ...target.editableOwner ? { editableOwner: target.editableOwner } : {},
51085
51802
  ...target.canonicalAddress ? { canonicalAddress: target.canonicalAddress } : {},
51803
+ ...layoutIdentity ? { layoutIdentity } : {},
51086
51804
  staleCheck: target.staleCheck,
51087
51805
  posture: target.posture,
51088
51806
  ...workflowBlockers.length > 0 ? { workflowBlockers: Object.freeze([...workflowBlockers]) } : {},
@@ -51098,7 +51816,7 @@ function deriveScopeEditableTargetEvidence(document2, scope, entry, options = {}
51098
51816
  facts.push(projectWorkflowBlockerFact(fact));
51099
51817
  factsByTargetKey.set(fact.targetKey, facts);
51100
51818
  }
51101
- const entries = collectEditableTargetRefs(document2, options.editableTargetCache).map((target) => {
51819
+ const relatedTargets = collectEditableTargetRefs(document2, options.editableTargetCache).map((target) => {
51102
51820
  const relation = relationForTarget(target, scope, entry);
51103
51821
  if (!relation) return null;
51104
51822
  const workflowBlockers = Object.freeze(
@@ -51106,8 +51824,19 @@ function deriveScopeEditableTargetEvidence(document2, scope, entry, options = {}
51106
51824
  (left, right) => left.source.localeCompare(right.source) || left.blocker.localeCompare(right.blocker) || left.refusalId.localeCompare(right.refusalId)
51107
51825
  )
51108
51826
  );
51109
- return projectTarget(document2, target, relation, workflowBlockers, scope.kind);
51110
- }).filter((target) => target !== null).sort((a, b) => a.targetKey.localeCompare(b.targetKey));
51827
+ return { target, relation, workflowBlockers };
51828
+ }).filter((target) => target !== null);
51829
+ const layoutIndexes = relatedTargets.length > 0 ? layoutIdentityIndexes(document2) : void 0;
51830
+ const entries = relatedTargets.map(
51831
+ ({ target, relation, workflowBlockers }) => projectTarget(
51832
+ document2,
51833
+ target,
51834
+ relation,
51835
+ workflowBlockers,
51836
+ scope.kind,
51837
+ layoutIndexes ? layoutIdentityForTarget(target, layoutIndexes) : void 0
51838
+ )
51839
+ ).sort((a, b) => a.targetKey.localeCompare(b.targetKey));
51111
51840
  const blockers = /* @__PURE__ */ new Set();
51112
51841
  let supportedTextTargetCount = 0;
51113
51842
  for (const target of entries) {
@@ -51171,15 +51900,65 @@ function projectEntry2(entry) {
51171
51900
  ...entry.posture.preserveOnly ? { preserveOnly: true } : {}
51172
51901
  };
51173
51902
  }
51903
+ function familyKindFor(entry) {
51904
+ return entry.objectKind ?? "unknown";
51905
+ }
51906
+ function familyStatusFor(entries) {
51907
+ if (entries.some((entry) => entry.runtimeCommand.status === "supported")) {
51908
+ return "supported";
51909
+ }
51910
+ if (entries.length > 0 && entries.every(
51911
+ (entry) => entry.preserveOnly === true || entry.commandFamily === "preserve-only-refusal"
51912
+ )) {
51913
+ return "preserve-only";
51914
+ }
51915
+ return "blocked";
51916
+ }
51917
+ function summarizeFamily(objectKind, entries) {
51918
+ const sortedEntries = [...entries].sort(
51919
+ (left, right) => left.targetKey.localeCompare(right.targetKey)
51920
+ );
51921
+ const preserveOnly = sortedEntries.some((entry) => entry.preserveOnly === true);
51922
+ return {
51923
+ objectKind,
51924
+ status: familyStatusFor(sortedEntries),
51925
+ count: sortedEntries.length,
51926
+ targetKeys: unique2(sortedEntries.map((entry) => entry.targetKey)),
51927
+ relations: unique2(sortedEntries.map((entry) => entry.relation)),
51928
+ commandFamilies: unique2(sortedEntries.map((entry) => entry.commandFamily)),
51929
+ runtimeIntents: unique2(
51930
+ sortedEntries.flatMap((entry) => [...entry.runtimeCommand.intents])
51931
+ ),
51932
+ blockers: unique2(sortedEntries.flatMap((entry) => [...entry.blockers])),
51933
+ ...preserveOnly ? { preserveOnly: true } : {}
51934
+ };
51935
+ }
51936
+ function summarizeFamilies(entries) {
51937
+ const byFamily = /* @__PURE__ */ new Map();
51938
+ for (const entry of entries) {
51939
+ const objectKind = familyKindFor(entry);
51940
+ const bucket = byFamily.get(objectKind);
51941
+ if (bucket) {
51942
+ bucket.push(entry);
51943
+ continue;
51944
+ }
51945
+ byFamily.set(objectKind, [entry]);
51946
+ }
51947
+ return Object.freeze(
51948
+ [...byFamily.entries()].map(([objectKind, familyEntries]) => summarizeFamily(objectKind, familyEntries)).sort((left, right) => left.objectKind.localeCompare(right.objectKind))
51949
+ );
51950
+ }
51174
51951
  function deriveScopeObjectEvidence(editableTargets) {
51175
51952
  const entries = Object.freeze(
51176
51953
  [...editableTargets?.entries ?? []].filter(isObjectTarget).map(projectEntry2).sort((left, right) => left.targetKey.localeCompare(right.targetKey))
51177
51954
  );
51178
51955
  const blockers = unique2(entries.flatMap((entry) => [...entry.blockers]));
51956
+ const families = summarizeFamilies(entries);
51179
51957
  return {
51180
51958
  status: entries.length > 0 ? "present" : "none",
51181
51959
  count: entries.length,
51182
51960
  blockers,
51961
+ families,
51183
51962
  entries
51184
51963
  };
51185
51964
  }
@@ -59962,8 +60741,7 @@ async function collectEditorStateForSerialize(args) {
59962
60741
  // src/io/ooxml/parse-bookmark-references.ts
59963
60742
  var HYPERLINK_ANCHOR_RE = /<(?:\w+:)?hyperlink\b[^>]*\bw:anchor\s*=\s*"([^"]*)"/gi;
59964
60743
  var INSTR_TEXT_RE = /<(?:\w+:)?instrText\b[^>]*>([\s\S]*?)<\/(?:\w+:)?instrText>/gi;
59965
- var FLD_SIMPLE_INSTR_DOUBLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*"([^"]*)"/gi;
59966
- var FLD_SIMPLE_INSTR_SINGLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*'([^']*)'/gi;
60744
+ var FLD_SIMPLE_INSTR_RE = /<(?:\w+:)?fldSimple\b[^>]*\bw:instr\s*=\s*(["'])([\s\S]*?)\1/gi;
59967
60745
  var TOC_FIELD_RE = /\bTOC\b/;
59968
60746
  var REFLIKE_FIELD_RE = /\b(?:HYPERLINK|REF|PAGEREF|NOTEREF)\s+([A-Za-z0-9_:.\-]+)/g;
59969
60747
  var DATA_BINDING_RE = /<(?:\w+:)?dataBinding\b/i;
@@ -59982,21 +60760,14 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
59982
60760
  }
59983
60761
  INSTR_TEXT_RE.lastIndex = 0;
59984
60762
  while ((m = INSTR_TEXT_RE.exec(documentXml)) !== null) {
59985
- const instrText = m[1] ?? "";
59986
- scanFieldInstruction(instrText, retained, () => {
59987
- retainAllToc = true;
60763
+ retainInstructionReferences(m[1] ?? "", retained, (value) => {
60764
+ retainAllToc = retainAllToc || value;
59988
60765
  });
59989
60766
  }
59990
- FLD_SIMPLE_INSTR_DOUBLE_RE.lastIndex = 0;
59991
- while ((m = FLD_SIMPLE_INSTR_DOUBLE_RE.exec(documentXml)) !== null) {
59992
- scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
59993
- retainAllToc = true;
59994
- });
59995
- }
59996
- FLD_SIMPLE_INSTR_SINGLE_RE.lastIndex = 0;
59997
- while ((m = FLD_SIMPLE_INSTR_SINGLE_RE.exec(documentXml)) !== null) {
59998
- scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
59999
- retainAllToc = true;
60767
+ FLD_SIMPLE_INSTR_RE.lastIndex = 0;
60768
+ while ((m = FLD_SIMPLE_INSTR_RE.exec(documentXml)) !== null) {
60769
+ retainInstructionReferences(m[2] ?? "", retained, (value) => {
60770
+ retainAllToc = retainAllToc || value;
60000
60771
  });
60001
60772
  }
60002
60773
  retainRevisionBoundedBookmarks(documentXml, retained);
@@ -60006,17 +60777,14 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
60006
60777
  retainAll
60007
60778
  };
60008
60779
  }
60009
- function scanFieldInstruction(instrText, retained, retainToc) {
60010
- if (TOC_FIELD_RE.test(instrText)) retainToc();
60780
+ function retainInstructionReferences(instrText, retained, setRetainAllToc) {
60781
+ if (TOC_FIELD_RE.test(instrText)) setRetainAllToc(true);
60011
60782
  REFLIKE_FIELD_RE.lastIndex = 0;
60012
60783
  let r;
60013
60784
  while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
60014
60785
  if (r[1]) retained.add(r[1]);
60015
60786
  }
60016
60787
  }
60017
- function decodeXmlAttribute(value) {
60018
- return value.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
60019
- }
60020
60788
  function retainRevisionBoundedBookmarks(documentXml, retained) {
60021
60789
  const starts = /* @__PURE__ */ new Map();
60022
60790
  BOOKMARK_START_RE.lastIndex = 0;
@@ -76123,11 +76891,11 @@ function computeBaseDocFingerprint(envelope) {
76123
76891
  fieldRegistry: envelope.fieldRegistry,
76124
76892
  fontTable: envelope.fontTable
76125
76893
  };
76126
- const serialized = stableStringify3(subset);
76894
+ const serialized = stableStringify5(subset);
76127
76895
  const bytes = new TextEncoder().encode(serialized);
76128
76896
  return sha256Hex3(bytes);
76129
76897
  }
76130
- function stableStringify3(value) {
76898
+ function stableStringify5(value) {
76131
76899
  if (value === null) return "null";
76132
76900
  if (value === void 0) return "null";
76133
76901
  const t = typeof value;
@@ -76137,7 +76905,7 @@ function stableStringify3(value) {
76137
76905
  if (Array.isArray(value)) {
76138
76906
  const parts = [];
76139
76907
  for (const item of value) {
76140
- parts.push(item === void 0 ? "null" : stableStringify3(item));
76908
+ parts.push(item === void 0 ? "null" : stableStringify5(item));
76141
76909
  }
76142
76910
  return "[" + parts.join(",") + "]";
76143
76911
  }
@@ -76152,7 +76920,7 @@ function stableStringify3(value) {
76152
76920
  keys.sort();
76153
76921
  const parts = [];
76154
76922
  for (const key of keys) {
76155
- parts.push(JSON.stringify(key) + ":" + stableStringify3(obj[key]));
76923
+ parts.push(JSON.stringify(key) + ":" + stableStringify5(obj[key]));
76156
76924
  }
76157
76925
  return "{" + parts.join(",") + "}";
76158
76926
  }
@@ -81484,6 +82252,13 @@ function buildParagraphPropertiesXml2(paragraph) {
81484
82252
  const frameXml = buildFrameXml(paragraph.frameProperties);
81485
82253
  if (frameXml) parts.push(frameXml);
81486
82254
  }
82255
+ if (paragraph.tabStops && paragraph.tabStops.length > 0) {
82256
+ const tabsXml = paragraph.tabStops.map((tab) => {
82257
+ const leaderAttr = tab.leader ? ` w:leader="${escapeXmlAttribute2(tab.leader)}"` : "";
82258
+ return `<w:tab w:val="${escapeXmlAttribute2(tab.align)}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
82259
+ }).join("");
82260
+ parts.push(`<w:tabs>${tabsXml}</w:tabs>`);
82261
+ }
81487
82262
  if (paragraph.spacing) {
81488
82263
  const s = paragraph.spacing;
81489
82264
  const attrs = [];
@@ -81505,13 +82280,6 @@ function buildParagraphPropertiesXml2(paragraph) {
81505
82280
  if (paragraph.alignment) {
81506
82281
  parts.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
81507
82282
  }
81508
- if (paragraph.tabStops && paragraph.tabStops.length > 0) {
81509
- const tabsXml = paragraph.tabStops.map((tab) => {
81510
- const leaderAttr = tab.leader ? ` w:leader="${escapeXmlAttribute2(tab.leader)}"` : "";
81511
- return `<w:tab w:val="${tab.align}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
81512
- }).join("");
81513
- parts.push(`<w:tabs>${tabsXml}</w:tabs>`);
81514
- }
81515
82283
  return parts.length > 0 ? `<w:pPr>${parts.join("")}</w:pPr>` : "";
81516
82284
  }
81517
82285
  function serializeInlineNode2(node) {
@@ -81580,51 +82348,60 @@ function buildRunPropertiesXml2(marks) {
81580
82348
  if (!marks || marks.length === 0) {
81581
82349
  return "";
81582
82350
  }
82351
+ const orderedTypes = [
82352
+ "fontFamily",
82353
+ "bold",
82354
+ "italic",
82355
+ "allCaps",
82356
+ "smallCaps",
82357
+ "strikethrough",
82358
+ "doubleStrikethrough",
82359
+ "textColor",
82360
+ "fontSize",
82361
+ "highlight",
82362
+ "underline",
82363
+ "backgroundColor"
82364
+ ];
81583
82365
  const parts = [];
81584
- for (const mark of marks) {
81585
- switch (mark.type) {
81586
- case "bold":
81587
- parts.push("<w:b/>");
81588
- break;
81589
- case "italic":
81590
- parts.push("<w:i/>");
81591
- break;
81592
- case "underline":
81593
- parts.push('<w:u w:val="single"/>');
81594
- break;
81595
- case "strikethrough":
81596
- parts.push("<w:strike/>");
81597
- break;
81598
- case "doubleStrikethrough":
81599
- parts.push("<w:dstrike/>");
81600
- break;
81601
- case "fontFamily":
81602
- parts.push(`<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`);
81603
- break;
81604
- case "fontSize":
81605
- parts.push(`<w:sz w:val="${twip(mark.val)}"/>`);
81606
- break;
81607
- case "textColor":
81608
- parts.push(`<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`);
81609
- break;
81610
- case "highlight":
81611
- parts.push(`<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`);
81612
- break;
81613
- case "backgroundColor":
81614
- parts.push(`<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`);
81615
- break;
81616
- case "smallCaps":
81617
- parts.push("<w:smallCaps/>");
81618
- break;
81619
- case "allCaps":
81620
- parts.push("<w:caps/>");
81621
- break;
81622
- default:
81623
- break;
82366
+ for (const type of orderedTypes) {
82367
+ for (const mark of marks) {
82368
+ if (mark.type !== type) continue;
82369
+ const xml = serializeRunPropertyMark2(mark);
82370
+ if (xml) parts.push(xml);
81624
82371
  }
81625
82372
  }
81626
82373
  return parts.length > 0 ? `<w:rPr>${parts.join("")}</w:rPr>` : "";
81627
82374
  }
82375
+ function serializeRunPropertyMark2(mark) {
82376
+ switch (mark.type) {
82377
+ case "bold":
82378
+ return "<w:b/>";
82379
+ case "italic":
82380
+ return "<w:i/>";
82381
+ case "underline":
82382
+ return `<w:u w:val="single"/>`;
82383
+ case "strikethrough":
82384
+ return "<w:strike/>";
82385
+ case "doubleStrikethrough":
82386
+ return "<w:dstrike/>";
82387
+ case "fontFamily":
82388
+ return `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`;
82389
+ case "fontSize":
82390
+ return `<w:sz w:val="${twip(mark.val)}"/>`;
82391
+ case "textColor":
82392
+ return `<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`;
82393
+ case "highlight":
82394
+ return `<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`;
82395
+ case "backgroundColor":
82396
+ return `<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`;
82397
+ case "smallCaps":
82398
+ return "<w:smallCaps/>";
82399
+ case "allCaps":
82400
+ return "<w:caps/>";
82401
+ default:
82402
+ return "";
82403
+ }
82404
+ }
81628
82405
  function requiresPreservedSpace3(text) {
81629
82406
  return text.length > 0 && (text[0] === " " || text[text.length - 1] === " " || text.includes(" "));
81630
82407
  }
@@ -81798,9 +82575,6 @@ function buildParagraphPropertiesXml3(paragraph) {
81798
82575
  const frameXml = buildFrameXml(paragraph.frameProperties);
81799
82576
  if (frameXml) parts.push(frameXml);
81800
82577
  }
81801
- if (paragraph.alignment) {
81802
- parts.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
81803
- }
81804
82578
  if (paragraph.spacing) {
81805
82579
  const attrs = [];
81806
82580
  if (paragraph.spacing.before !== void 0) attrs.push(`w:before="${twip(paragraph.spacing.before)}"`);
@@ -81821,6 +82595,9 @@ function buildParagraphPropertiesXml3(paragraph) {
81821
82595
  parts.push(`<w:ind ${attrs.join(" ")}/>`);
81822
82596
  }
81823
82597
  }
82598
+ if (paragraph.alignment) {
82599
+ parts.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
82600
+ }
81824
82601
  return parts.length > 0 ? `<w:pPr>${parts.join("")}</w:pPr>` : "";
81825
82602
  }
81826
82603
  function serializeInlineNode3(node) {
@@ -81881,47 +82658,59 @@ function buildRunPropertiesXml3(marks) {
81881
82658
  if (!marks || marks.length === 0) {
81882
82659
  return "";
81883
82660
  }
81884
- const parts = [];
82661
+ const orderedTypes = [
82662
+ "fontFamily",
82663
+ "bold",
82664
+ "italic",
82665
+ "allCaps",
82666
+ "smallCaps",
82667
+ "strikethrough",
82668
+ "doubleStrikethrough",
82669
+ "textColor",
82670
+ "fontSize",
82671
+ "underline"
82672
+ ];
82673
+ const supportedTypes = new Set(orderedTypes);
81885
82674
  for (const mark of marks) {
81886
- switch (mark.type) {
81887
- case "bold":
81888
- parts.push("<w:b/>");
81889
- break;
81890
- case "italic":
81891
- parts.push("<w:i/>");
81892
- break;
81893
- case "underline":
81894
- parts.push('<w:u w:val="single"/>');
81895
- break;
81896
- case "strikethrough":
81897
- parts.push("<w:strike/>");
81898
- break;
81899
- case "doubleStrikethrough":
81900
- parts.push("<w:dstrike/>");
81901
- break;
81902
- case "fontFamily":
81903
- parts.push(
81904
- `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`
81905
- );
81906
- break;
81907
- case "fontSize":
81908
- parts.push(`<w:sz w:val="${twip(mark.val)}"/>`);
81909
- break;
81910
- case "textColor":
81911
- parts.push(`<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`);
81912
- break;
81913
- case "smallCaps":
81914
- parts.push("<w:smallCaps/>");
81915
- break;
81916
- case "allCaps":
81917
- parts.push("<w:caps/>");
81918
- break;
81919
- default:
81920
- throw new Error(`Cannot safely serialize ${mark.type} marks in note sub-parts.`);
82675
+ if (!supportedTypes.has(mark.type)) {
82676
+ throw new Error(`Cannot safely serialize ${mark.type} marks in note sub-parts.`);
82677
+ }
82678
+ }
82679
+ const parts = [];
82680
+ for (const type of orderedTypes) {
82681
+ for (const mark of marks) {
82682
+ if (mark.type !== type) continue;
82683
+ parts.push(serializeRunPropertyMark3(mark));
81921
82684
  }
81922
82685
  }
81923
82686
  return parts.length > 0 ? `<w:rPr>${parts.join("")}</w:rPr>` : "";
81924
82687
  }
82688
+ function serializeRunPropertyMark3(mark) {
82689
+ switch (mark.type) {
82690
+ case "bold":
82691
+ return "<w:b/>";
82692
+ case "italic":
82693
+ return "<w:i/>";
82694
+ case "underline":
82695
+ return `<w:u w:val="single"/>`;
82696
+ case "strikethrough":
82697
+ return "<w:strike/>";
82698
+ case "doubleStrikethrough":
82699
+ return "<w:dstrike/>";
82700
+ case "fontFamily":
82701
+ return `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`;
82702
+ case "fontSize":
82703
+ return `<w:sz w:val="${twip(mark.val)}"/>`;
82704
+ case "textColor":
82705
+ return `<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`;
82706
+ case "smallCaps":
82707
+ return "<w:smallCaps/>";
82708
+ case "allCaps":
82709
+ return "<w:caps/>";
82710
+ default:
82711
+ throw new Error(`Cannot safely serialize ${mark.type} marks in note sub-parts.`);
82712
+ }
82713
+ }
81925
82714
  function compareNoteIds2(left, right) {
81926
82715
  return Number.parseInt(left.noteId, 10) - Number.parseInt(right.noteId, 10);
81927
82716
  }
@@ -89521,11 +90310,11 @@ function extractFilename2(target) {
89521
90310
  }
89522
90311
  function mintManifestId(partPath, relationshipId, size) {
89523
90312
  const material = `${partPath}${relationshipId}${size}`;
89524
- const a = fnv1a(material, 2166136261);
89525
- const b = fnv1a(material, 461845907);
90313
+ const a = fnv1a3(material, 2166136261);
90314
+ const b = fnv1a3(material, 461845907);
89526
90315
  return `emb:${toHex8(a)}${toHex8(b)}`;
89527
90316
  }
89528
- function fnv1a(input, seed) {
90317
+ function fnv1a3(input, seed) {
89529
90318
  let hash = seed >>> 0;
89530
90319
  for (let i = 0; i < input.length; i++) {
89531
90320
  hash ^= input.charCodeAt(i);
@@ -129770,7 +130559,7 @@ var listOperationMetadata = actionMethodMetadata(
129770
130559
  "listOperation",
129771
130560
  "mutate",
129772
130561
  "actions-list-operation",
129773
- "Apply list toggle, indent, outdent, restart, or continue-numbering commands to paragraph-like scope handles.",
130562
+ "Apply list toggle, indent, outdent, restart, or continue-numbering commands through opaque list action handles or command-safe list scope targets.",
129774
130563
  {
129775
130564
  uiVisible: true,
129776
130565
  expectsUxResponse: "inline-change",
@@ -131505,25 +132294,16 @@ function checkPlanStepCapability(runtime, step, before) {
131505
132294
  return null;
131506
132295
  }
131507
132296
  if (step.kind === "listOperation") {
131508
- const resolved = resolveScopeExactTarget(runtime, step.target, step.kind);
132297
+ const resolved = resolveListOperationTarget(runtime, step.target);
131509
132298
  if (!resolved.ok) return resolved.blockerDetails[0] ?? null;
131510
- const scope = resolved.target.scope;
131511
- if (scope.kind !== "list-item" && scope.kind !== "paragraph" && scope.kind !== "heading") {
131512
- return blocker(
131513
- `actions:list-operation:target-kind-unsupported:${scope.kind}`,
131514
- "unsupported",
131515
- "List operations require a paragraph-like scope handle.",
131516
- "Use ai.actions.locateAll or ai.listScopes to select a paragraph, heading, or list-item handle."
131517
- );
131518
- }
131519
- if (paragraphIndexFromHandle(scope.handle) === null) {
131520
- return blockerWithOwner(
131521
- `actions:list-operation:paragraph-index-unresolved:${scope.handle.scopeId}`,
131522
- "blocked",
131523
- "The list operation target did not resolve to a current paragraph index.",
131524
- "Refresh the scope handle and retry; route persistent failures to L08 scope resolution.",
131525
- "L08 semantic scope compiler"
131526
- );
132299
+ const command = runtimeListCommandForOperation(step.operation);
132300
+ const preview = createListsFamily(runtime).previewCommand({
132301
+ ...resolved.input,
132302
+ command,
132303
+ ...step.operation.kind === "restart-numbering" && step.operation.startAt !== void 0 ? { startAt: step.operation.startAt } : {}
132304
+ });
132305
+ if (preview.blockers.length > 0) {
132306
+ return listBlockerDetails("actions:list-operation:preflight", preview.blockers)[0] ?? null;
131527
132307
  }
131528
132308
  return null;
131529
132309
  }
@@ -131680,70 +132460,253 @@ function applyModeledCommand(runtime, targetInput, kind, commandInput, reference
131680
132460
  };
131681
132461
  }
131682
132462
  function applyListOperation(runtime, input) {
131683
- const resolvedScope = resolveScopeExactTarget(runtime, input.target, "listOperation");
131684
- if (!resolvedScope.ok) return blockedApplyFromResolution(resolvedScope);
132463
+ const resolvedTarget = resolveListOperationTarget(runtime, input.target);
132464
+ if (!resolvedTarget.ok) return blockedApplyFromResolution(resolvedTarget);
132465
+ const command = runtimeListCommandForOperation(input.operation);
132466
+ const result = createListsFamily(runtime).applyCommand({
132467
+ ...resolvedTarget.input,
132468
+ command,
132469
+ ...input.operation.kind === "restart-numbering" && input.operation.startAt !== void 0 ? { startAt: input.operation.startAt } : {}
132470
+ });
132471
+ if (!result.applied) {
132472
+ const details = result.blockers.length > 0 ? listBlockerDetails("actions:list-operation", result.blockers) : [
132473
+ blockerWithOwner(
132474
+ `actions:list-operation:runtime-noop:${resolvedTarget.before?.addressKey ?? "unknown"}`,
132475
+ "blocked",
132476
+ "The runtime list command produced no document change for the selected list target.",
132477
+ "Refresh the list action handle and retry; route persistent failures with before/after readback to L07 runtime list commands.",
132478
+ "L07 runtime list commands"
132479
+ )
132480
+ ];
132481
+ return {
132482
+ status: details.some((detail) => detail.category === "unsupported") ? "unsupported" : "blocked",
132483
+ applied: false,
132484
+ changed: false,
132485
+ target: summarizeListTarget(resolvedTarget, result.before ?? resolvedTarget.before),
132486
+ blockers: Object.freeze(details.map((detail) => detail.code)),
132487
+ blockerDetails: Object.freeze(details),
132488
+ listReadback: listOperationReadback(result, resolvedTarget.before)
132489
+ };
132490
+ }
132491
+ const compiledAfter = resolvedTarget.scopeHandle ? createScopeCompilerService(runtime).compileScopeById(resolvedTarget.scopeHandle.scopeId) : null;
132492
+ const target = compiledAfter ? summarizeTarget({ kind: "scope", scope: compiledAfter.scope, handle: compiledAfter.scope.handle }) : summarizeListTarget(resolvedTarget, result.after ?? result.before ?? resolvedTarget.before);
132493
+ return {
132494
+ status: "applied",
132495
+ applied: true,
132496
+ changed: result.applied,
132497
+ target,
132498
+ commandReference: {
132499
+ command: commandReferenceForListCommand(result.command),
132500
+ actorId: input.actorId ?? "v3-ai-api",
132501
+ origin: input.origin ?? "agent",
132502
+ emittedAtUtc: currentAuditTimestamp(runtime)
132503
+ },
132504
+ listReadback: listOperationReadback(result, resolvedTarget.before)
132505
+ };
132506
+ }
132507
+ function resolveListOperationTarget(runtime, targetInput) {
132508
+ const lists = createListsFamily(runtime);
132509
+ if ("actionHandle" in targetInput) {
132510
+ const addressKey = listAddressKeyFromActionHandle(targetInput.actionHandle);
132511
+ if (!addressKey) {
132512
+ const detail = blockerWithOwner(
132513
+ `actions:list-operation:action-handle-malformed:${targetInput.actionHandle}`,
132514
+ "unsupported",
132515
+ "List operations require an opaque list action handle from runtime.lists or list editable-target evidence.",
132516
+ "Call runtime.lists.list or refresh the scope bundle and retry with a list-action:* or scope-command:text-leaf:* list handle.",
132517
+ "L07 runtime list commands and L08 semantic scopes"
132518
+ );
132519
+ return {
132520
+ ok: false,
132521
+ blockers: Object.freeze([detail.code]),
132522
+ blockerDetails: Object.freeze([detail])
132523
+ };
132524
+ }
132525
+ const before2 = lists.get({ addressKey });
132526
+ if (!before2) {
132527
+ const detail = blockerWithOwner(
132528
+ `actions:list-operation:action-handle-not-found:${targetInput.actionHandle}`,
132529
+ "unresolved-target",
132530
+ "No current list target matches the supplied opaque action handle.",
132531
+ "Refresh runtime.lists.list or the scope bundle, then retry with the current list action handle.",
132532
+ "L07 runtime list commands"
132533
+ );
132534
+ return {
132535
+ ok: false,
132536
+ blockers: Object.freeze([detail.code]),
132537
+ blockerDetails: Object.freeze([detail])
132538
+ };
132539
+ }
132540
+ return { ok: true, input: { addressKey }, before: before2 };
132541
+ }
132542
+ const resolvedScope = resolveScopeExactTarget(runtime, targetInput, "listOperation");
132543
+ if (!resolvedScope.ok) return resolvedScope;
131685
132544
  const scope = resolvedScope.target.scope;
131686
132545
  if (scope.kind !== "list-item" && scope.kind !== "paragraph" && scope.kind !== "heading") {
131687
- return blockedApply(
132546
+ const detail = blocker(
131688
132547
  `actions:list-operation:target-kind-unsupported:${scope.kind}`,
131689
132548
  "unsupported",
131690
- "List operations require a paragraph-like scope handle.",
131691
- "Use ai.actions.locateAll or ai.listScopes to select a paragraph, heading, or list-item handle."
132549
+ "List operations require a list item or command-safe paragraph-like scope target.",
132550
+ "Use ai.actions.locateAll, ai.listScopes, or runtime.lists.list to select a current list item target."
131692
132551
  );
132552
+ return {
132553
+ ok: false,
132554
+ blockers: Object.freeze([detail.code]),
132555
+ blockerDetails: Object.freeze([detail])
132556
+ };
131693
132557
  }
131694
- const paragraphIndex = paragraphIndexFromHandle(scope.handle);
131695
- if (paragraphIndex === null) {
131696
- return blockedApply(
131697
- `actions:list-operation:paragraph-index-unresolved:${scope.handle.scopeId}`,
132558
+ const bundle = createScopeCompilerService(runtime).compileBundleById(
132559
+ scope.handle.scopeId,
132560
+ currentAuditTimestamp(runtime)
132561
+ );
132562
+ const entries = bundle?.evidence.editableTargets?.entries ?? [];
132563
+ const listEntry = entries.find(
132564
+ (entry) => entry.commandFamily === "text-leaf" && entry.runtimeCommand.status === "supported" && entry.runtimeCommand.intents.includes("list-structure-action") && entry.runtimeCommand.canonicalAddress?.operationScope === "list-text" && entry.runtimeCommand.canonicalAddress.addressKind === "list-item-text"
132565
+ );
132566
+ if (!listEntry) {
132567
+ const detail = blockerWithOwner(
132568
+ `actions:list-operation:list-target-missing:${scope.handle.scopeId}`,
131698
132569
  "blocked",
131699
- "The list operation target did not resolve to a current paragraph index.",
131700
- "Refresh the scope handle and retry; route persistent failures to L08 scope resolution.",
131701
- [
131702
- blockerWithOwner(
131703
- `actions:list-operation:paragraph-index-unresolved:${scope.handle.scopeId}`,
131704
- "blocked",
131705
- "The list operation target did not resolve to a current paragraph index.",
131706
- "Refresh the scope handle and retry; route persistent failures to L08 scope resolution.",
131707
- "L08 semantic scope compiler"
131708
- )
131709
- ]
132570
+ "The selected scope does not expose a command-safe list structure target.",
132571
+ "Refresh the scope bundle and route missing list editable-target evidence to L08/L07; do not derive a paragraph index from the scope handle.",
132572
+ "L08 semantic scopes and L07 runtime list commands"
131710
132573
  );
132574
+ return {
132575
+ ok: false,
132576
+ blockers: Object.freeze([detail.code]),
132577
+ blockerDetails: Object.freeze([detail])
132578
+ };
131711
132579
  }
131712
- const command = listCommandForOperation(input.operation, paragraphIndex, actionOrigin(runtime, input));
131713
- const before = runtime.getCanonicalDocument();
131714
- runtime.dispatch(command);
131715
- const changed = runtime.getCanonicalDocument() !== before;
131716
- if (!changed) {
131717
- return blockedApply(
131718
- `actions:list-operation:runtime-noop:${scope.handle.scopeId}`,
132580
+ const currentTarget = collectEditableTargetRefs(runtime.getCanonicalDocument()).find(
132581
+ (target) => target.targetKey === listEntry.targetKey || target.listAddress?.addressKey === listEntry.runtimeCommand.canonicalAddress?.addressKey
132582
+ );
132583
+ if (!currentTarget) {
132584
+ const detail = blockerWithOwner(
132585
+ `actions:list-operation:list-target-not-current:${scope.handle.scopeId}`,
132586
+ "unresolved-target",
132587
+ "The list editable target evidence is stale in the current document.",
132588
+ "Refresh the scope bundle and retry with the current opaque list target.",
132589
+ "L08 semantic scopes and L07 runtime list commands"
132590
+ );
132591
+ return {
132592
+ ok: false,
132593
+ blockers: Object.freeze([detail.code]),
132594
+ blockerDetails: Object.freeze([detail])
132595
+ };
132596
+ }
132597
+ const before = lists.get({ editableTarget: currentTarget });
132598
+ if (!before) {
132599
+ const detail = blockerWithOwner(
132600
+ `actions:list-operation:list-readback-missing:${scope.handle.scopeId}`,
131719
132601
  "blocked",
131720
- "The list runtime command produced no document change for the selected scope.",
131721
- "Select a list-compatible paragraph and retry, or route to L03/L07 list command support with the scope handle.",
131722
- [
131723
- blockerWithOwner(
131724
- `actions:list-operation:runtime-noop:${scope.handle.scopeId}`,
131725
- "blocked",
131726
- "The list runtime command produced no document change for the selected scope.",
131727
- "Select a list-compatible paragraph and retry, or route to L03/L07 list command support with the scope handle.",
131728
- "L03 numbering/list semantics and L07 runtime list commands"
131729
- )
131730
- ]
132602
+ "The list target was present in scope evidence but runtime.lists could not produce readback.",
132603
+ "Route the target with editable-target evidence to L07 runtime list readback.",
132604
+ "L07 runtime list commands"
131731
132605
  );
132606
+ return {
132607
+ ok: false,
132608
+ blockers: Object.freeze([detail.code]),
132609
+ blockerDetails: Object.freeze([detail])
132610
+ };
131732
132611
  }
131733
- const compiledAfter = createScopeCompilerService(runtime).compileScopeById(scope.handle.scopeId);
131734
132612
  return {
131735
- status: "applied",
131736
- applied: true,
131737
- changed: true,
131738
- target: compiledAfter ? summarizeTarget({ kind: "scope", scope: compiledAfter.scope, handle: compiledAfter.scope.handle }) : summarizeTarget(resolvedScope.target),
131739
- commandReference: {
131740
- command: command.type,
131741
- actorId: input.actorId ?? "v3-ai-api",
131742
- origin: input.origin ?? "agent",
131743
- emittedAtUtc: command.origin?.timestamp ?? currentAuditTimestamp(runtime)
131744
- }
132613
+ ok: true,
132614
+ input: { editableTarget: currentTarget },
132615
+ before,
132616
+ scopeHandle: scope.handle
131745
132617
  };
131746
132618
  }
132619
+ function listAddressKeyFromActionHandle(actionHandle) {
132620
+ const listPrefix = "list-action:";
132621
+ if (actionHandle.startsWith(listPrefix)) return actionHandle.slice(listPrefix.length) || null;
132622
+ const scopeCommandPrefix = "scope-command:text-leaf:";
132623
+ if (actionHandle.startsWith(scopeCommandPrefix)) {
132624
+ return actionHandle.slice(scopeCommandPrefix.length) || null;
132625
+ }
132626
+ return null;
132627
+ }
132628
+ function runtimeListCommandForOperation(operation) {
132629
+ switch (operation.kind) {
132630
+ case "toggle":
132631
+ return operation.listKind === "numbered" ? "toggle-numbered" : "toggle-bulleted";
132632
+ case "indent":
132633
+ return "indent";
132634
+ case "outdent":
132635
+ return "outdent";
132636
+ case "restart-numbering":
132637
+ return "restart-numbering";
132638
+ case "continue-numbering":
132639
+ return "continue-numbering";
132640
+ }
132641
+ }
132642
+ function commandReferenceForListCommand(command) {
132643
+ switch (command) {
132644
+ case "toggle-numbered":
132645
+ case "toggle-bulleted":
132646
+ return "list.toggle";
132647
+ case "indent":
132648
+ return "list.indent";
132649
+ case "outdent":
132650
+ return "list.outdent";
132651
+ case "restart-numbering":
132652
+ return "list.restart-numbering";
132653
+ case "continue-numbering":
132654
+ return "list.continue-numbering";
132655
+ default:
132656
+ return "list.toggle";
132657
+ }
132658
+ }
132659
+ function listOperationReadback(result, fallbackBefore) {
132660
+ const before = sanitizeListReadback(result.before ?? fallbackBefore);
132661
+ const after = sanitizeListReadback(result.after);
132662
+ return {
132663
+ ...before ? { before } : {},
132664
+ ...after ? { after } : {}
132665
+ };
132666
+ }
132667
+ function sanitizeListReadback(readback) {
132668
+ if (!readback) return void 0;
132669
+ return {
132670
+ actionHandle: readback.actionHandle,
132671
+ kind: readback.kind,
132672
+ storyKey: readback.storyKey,
132673
+ addressKey: readback.addressKey,
132674
+ numberingInstanceId: readback.numberingInstanceId,
132675
+ ...readback.abstractNumberingId ? { abstractNumberingId: readback.abstractNumberingId } : {},
132676
+ level: readback.level,
132677
+ ...readback.listKind ? { listKind: readback.listKind } : {},
132678
+ editability: readback.editability,
132679
+ blockers: readback.blockers,
132680
+ supportedCommands: readback.supportedCommands,
132681
+ unsupportedCommands: readback.unsupportedCommands,
132682
+ staleDiscriminators: readback.staleDiscriminators
132683
+ };
132684
+ }
132685
+ function summarizeListTarget(target, readback) {
132686
+ const current = readback ?? target.before;
132687
+ return {
132688
+ kind: "list-item",
132689
+ ...target.scopeHandle ? { handle: target.scopeHandle } : {},
132690
+ ...current?.actionHandle ? { actionHandle: current.actionHandle } : {},
132691
+ canRewriteText: current?.editability === "editable" && (current.blockers.length ?? 0) === 0,
132692
+ canInsertAdjacentText: false,
132693
+ canFlag: Boolean(target.scopeHandle),
132694
+ canMark: Boolean(target.scopeHandle)
132695
+ };
132696
+ }
132697
+ function listBlockerDetails(prefix, blockers) {
132698
+ return Object.freeze(
132699
+ blockers.map(
132700
+ (entry) => blockerWithOwner(
132701
+ `${prefix}:${entry.code}:${entry.addressKey ?? entry.targetKey ?? "unknown"}`,
132702
+ entry.code === "list-command-unsupported" ? "unsupported" : "blocked",
132703
+ entry.message,
132704
+ "Refresh the opaque list target/readback and route persistent blockers to the owning runtime list layer.",
132705
+ entry.ownerLayer === "L07" ? "L07 runtime list commands" : entry.ownerLayer
132706
+ )
132707
+ )
132708
+ );
132709
+ }
131747
132710
  function projectTableApplyResult(result) {
131748
132711
  return {
131749
132712
  status: result.applied ? "applied" : "blocked",
@@ -131871,36 +132834,6 @@ function tableSelectionStepHasDescriptor(operation) {
131871
132834
  operation && "selectionDescriptor" in operation && operation.selectionDescriptor
131872
132835
  );
131873
132836
  }
131874
- function listCommandForOperation(operation, paragraphIndex, origin) {
131875
- switch (operation.kind) {
131876
- case "toggle":
131877
- return {
131878
- type: "list.toggle",
131879
- kind: operation.listKind,
131880
- paragraphIndexes: [paragraphIndex],
131881
- origin
131882
- };
131883
- case "indent":
131884
- return { type: "list.indent", paragraphIndexes: [paragraphIndex], origin };
131885
- case "outdent":
131886
- return { type: "list.outdent", paragraphIndexes: [paragraphIndex], origin };
131887
- case "restart-numbering":
131888
- return {
131889
- type: "list.restart-numbering",
131890
- paragraphIndex,
131891
- ...operation.startAt !== void 0 ? { startAt: operation.startAt } : {},
131892
- origin
131893
- };
131894
- case "continue-numbering":
131895
- return { type: "list.continue-numbering", paragraphIndex, origin };
131896
- }
131897
- }
131898
- function paragraphIndexFromHandle(handle) {
131899
- const raw = handle.semanticPath[handle.semanticPath.length - 1];
131900
- if (raw === void 0) return null;
131901
- const index = Number(raw);
131902
- return Number.isSafeInteger(index) && index >= 0 ? index : null;
131903
- }
131904
132837
  function actionOrigin(runtime, input) {
131905
132838
  return { source: "api", timestamp: currentAuditTimestamp(runtime) };
131906
132839
  }
@@ -137638,7 +138571,7 @@ function normalizeForHashing(doc) {
137638
138571
  };
137639
138572
  }
137640
138573
  async function computeCanonicalDocumentHash(doc) {
137641
- return sha256Hex5(stableStringify(normalizeForHashing(doc)));
138574
+ return sha256Hex5(stableStringify2(normalizeForHashing(doc)));
137642
138575
  }
137643
138576
 
137644
138577
  // src/runtime/prerender/font-fingerprint.ts