@superdoc/mcp 1.4.0-next.9 → 1.4.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1465 -589
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31330,7 +31330,7 @@ var init_host = __esm(() => {
31330
31330
  });
31331
31331
 
31332
31332
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31333
- var SDK_VERSION = "2.17.0-next.9";
31333
+ var SDK_VERSION = "2.17.1-next.1";
31334
31334
 
31335
31335
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31336
31336
  import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
@@ -96825,7 +96825,7 @@ Complete new body.`,
96825
96825
  find: {
96826
96826
  memberPath: "find",
96827
96827
  description: "Search the document for text or node matches using SDM/1 selectors. Returns discovery-grade results: for mutation targeting, use query.match instead.",
96828
- expectedResult: "Returns an SDFindResult envelope ({ total, limit, offset, items }). Each item is an SDNodeResult ({ node, address }).",
96828
+ expectedResult: "Returns an SDFindResult envelope ({ total, limit, offset, items }). Each item is an SDNodeResult ({ node, address }). Text hits contain only the matched text; use getNode or getNodeById for the full containing node. Node selectors return full node projections.",
96829
96829
  requiresDocumentContext: true,
96830
96830
  metadata: readOperation({
96831
96831
  idempotency: "idempotent",
@@ -150436,6 +150436,15 @@ function rebuildMutationSnapshot(snapshot2, state, signalsRevision, touchedStory
150436
150436
  function rebuildMutationSnapshotCanonical(snapshot2, state, signalsRevision, touchedStoryIds, lanesToRebuild, touchedParagraphIndexes, noteAnchorRefsByStory, localizedParagraphSignalsAlreadyRefreshed, sectionMutationPatches, sectionCoordinateSplicesByStory) {
150437
150437
  const shouldRebuildNoteAnchorRefs = lanesToRebuild.has("noteAnchorRefs");
150438
150438
  const shouldRebuildParagraphIndex = lanesToRebuild.has("paragraphIndex");
150439
+ const fullPartNoteAnchorRefsByStory = new Map;
150440
+ const readFullPartNoteAnchorRefs = (storyId, partUri) => {
150441
+ const donor = projectNoteAnchorRefsFromSamePartDonor(state, storyId, partUri, fullPartNoteAnchorRefsByStory);
150442
+ if (donor != null)
150443
+ return donor;
150444
+ const refs = scanNoteAnchorRefs(state, storyId, partUri);
150445
+ fullPartNoteAnchorRefsByStory.set(storyId, refs);
150446
+ return refs;
150447
+ };
150439
150448
  const paragraphSignalsWereComplete = snapshot2.completeness.paragraphIndex === "complete";
150440
150449
  const mayPromoteMainParagraphSignals = lanesToRebuild.has("sections");
150441
150450
  const paragraphSignalsAreComplete = paragraphSignalsWereComplete || shouldRebuildParagraphIndex && mayPromoteMainParagraphSignals;
@@ -150479,7 +150488,7 @@ function rebuildMutationSnapshotCanonical(snapshot2, state, signalsRevision, tou
150479
150488
  manualPageBreaks: rebaseDisjointStorySourceSignals(story.manualPageBreaks, story, storyRevision, partRevision, coordinateSplice),
150480
150489
  headings: rebaseDisjointStorySourceSignals(story.headings, story, storyRevision, partRevision, coordinateSplice),
150481
150490
  drawings: rebaseDisjointStorySourceSignals(story.drawings, story, storyRevision, partRevision, coordinateSplice),
150482
- noteAnchorRefs: shouldRebuildNoteAnchorRefs ? noteAnchorRefsByStory?.get(story.storyId) ?? scanNoteAnchorRefs(state, story.storyId, ownerPartId) : story.noteAnchorRefs,
150491
+ noteAnchorRefs: shouldRebuildNoteAnchorRefs ? noteAnchorRefsByStory?.get(story.storyId) ?? readFullPartNoteAnchorRefs(story.storyId, ownerPartId) : story.noteAnchorRefs,
150483
150492
  paragraphIndex: paragraphSignals,
150484
150493
  completeness
150485
150494
  };
@@ -150492,7 +150501,7 @@ function rebuildMutationSnapshotCanonical(snapshot2, state, signalsRevision, tou
150492
150501
  for (const storyId of touchedStoryIds) {
150493
150502
  if (seenStoryIds.has(storyId))
150494
150503
  continue;
150495
- const added = buildTouchedStorySignals(state, storyId, signalsRevision, lanesToRebuild, touchedParagraphIndexes, noteAnchorRefsByStory);
150504
+ const added = buildTouchedStorySignals(state, storyId, signalsRevision, lanesToRebuild, touchedParagraphIndexes, noteAnchorRefsByStory, readFullPartNoteAnchorRefs);
150496
150505
  if (added) {
150497
150506
  stories.push(added);
150498
150507
  seenStoryIds.add(storyId);
@@ -150806,7 +150815,7 @@ function finalSectionSemanticsAreUnchanged(section, candidate) {
150806
150815
  headerFooterRefs: section.headerFooterRefs
150807
150816
  }) === fingerprint(candidate);
150808
150817
  }
150809
- function buildTouchedStorySignals(state, storyId, signalsRevision, lanesToRebuild, touchedParagraphIndexes, noteAnchorRefsByStory) {
150818
+ function buildTouchedStorySignals(state, storyId, signalsRevision, lanesToRebuild, touchedParagraphIndexes, noteAnchorRefsByStory, readFullPartNoteAnchorRefs = (storyId2, partUri) => scanNoteAnchorRefs(state, storyId2, partUri)) {
150810
150819
  const story = state.stories.get(storyId);
150811
150820
  if (!story)
150812
150821
  return null;
@@ -150828,7 +150837,7 @@ function buildTouchedStorySignals(state, storyId, signalsRevision, lanesToRebuil
150828
150837
  manualPageBreaks: [],
150829
150838
  headings: [],
150830
150839
  drawings: [],
150831
- noteAnchorRefs: shouldRebuildNoteAnchorRefs ? noteAnchorRefsByStory?.get(storyId) ?? projectNoteAnchorRefsFromSamePartDonor(state, storyId, partUri, noteAnchorRefsByStory) ?? scanNoteAnchorRefs(state, storyId, partUri) : [],
150840
+ noteAnchorRefs: shouldRebuildNoteAnchorRefs ? noteAnchorRefsByStory?.get(storyId) ?? projectNoteAnchorRefsFromSamePartDonor(state, storyId, partUri, noteAnchorRefsByStory) ?? readFullPartNoteAnchorRefs(storyId, partUri) : [],
150832
150841
  paragraphIndex,
150833
150842
  completeness: {
150834
150843
  sections: "not-applicable",
@@ -168731,6 +168740,30 @@ function createStructuralLookupContext() {
168731
168740
  rememberCachedXmlLookup(directChildrenByXml, xml, ranges);
168732
168741
  return ranges;
168733
168742
  },
168743
+ getDirectChildrenAtRange(xml, start, end) {
168744
+ assertActive();
168745
+ const index = context.getElementRangeIndex(xml);
168746
+ const container = index.entries[firstEntryStartingAtOrAfter(index, start)];
168747
+ if (!container || container.start !== start || container.end !== end)
168748
+ return [];
168749
+ index.directChildrenByParent ?? (index.directChildrenByParent = new Map);
168750
+ const cached2 = index.directChildrenByParent.get(container);
168751
+ if (cached2)
168752
+ return cached2;
168753
+ if (!index.childrenByParent) {
168754
+ index.childrenByParent = new Map;
168755
+ for (const entry of index.entries) {
168756
+ if (!entry.parent)
168757
+ continue;
168758
+ const children = index.childrenByParent.get(entry.parent) ?? [];
168759
+ children.push(entry);
168760
+ index.childrenByParent.set(entry.parent, children);
168761
+ }
168762
+ }
168763
+ const ranges = (index.childrenByParent.get(container) ?? []).map(({ start: start2, end: end2, localName: localName2, namespaceUri }) => ({ start: start2, end: end2, localName: localName2, namespaceUri }));
168764
+ index.directChildrenByParent.set(container, ranges);
168765
+ return ranges;
168766
+ },
168734
168767
  dispose() {
168735
168768
  elementRangeIndexByXml.clear();
168736
168769
  directChildrenByXml.clear();
@@ -170201,8 +170234,8 @@ function uniqueStructuralFragments(fragments) {
170201
170234
  function classifyFullParagraphInsertion(lookupContext, partXml, paragraphStart, paragraphEnd, paragraphXml) {
170202
170235
  const parent = findImmediateParentElementAtPosition(partXml, paragraphStart, lookupContext);
170203
170236
  if (parent) {
170204
- const children = findDirectChildren(partXml.slice(parent.start, parent.end), undefined, lookupContext);
170205
- const paragraphIndex = children.findIndex((child) => parent.start + child.start === paragraphStart && parent.start + child.end === paragraphEnd);
170237
+ const children = lookupContext.getDirectChildrenAtRange(partXml, parent.start, parent.end);
170238
+ const paragraphIndex = children.findIndex((child) => child.start === paragraphStart && child.end === paragraphEnd);
170206
170239
  if (paragraphIndex > 0 && paragraphIndex < children.length - 1 && children[paragraphIndex - 1]?.localName === "tbl" && children[paragraphIndex + 1]?.localName === "tbl")
170207
170240
  return { subtype: "table-split", targetKind: "table" };
170208
170241
  }
@@ -173897,6 +173930,56 @@ function buildIsolatedTrackedRunFormattingLogicalIdWithLookupContext(lookupConte
173897
173930
  return null;
173898
173931
  return entry.id;
173899
173932
  }
173933
+ function buildIsolatedTrackedParagraphSplitLogicalId(input) {
173934
+ return withStructuralLookupContext(undefined, (lookupContext) => {
173935
+ const xml = `<w:body>${input.xml}</w:body>`;
173936
+ const raw = buildTrackedChangeCatalogFromPartXml({
173937
+ xml,
173938
+ partUri: input.partUri,
173939
+ storyId: input.storyId,
173940
+ namespaceBindings: { w: NS_W }
173941
+ });
173942
+ const structural = [...raw.structuralByKey.values()].flat();
173943
+ const mark = structural[0];
173944
+ if (structural.length !== 1 || !mark || mark.structuralKind !== "paragraph-mark-insertion" || mark.wId !== input.wordId || mark.fullParagraphInsertion === true || raw.formattingByKey.size !== 0 || raw.unsupportedByStory.size !== 0)
173945
+ return null;
173946
+ const logical = buildLogicalCatalogWithLookupContext(lookupContext, raw, input.replacementMode, new Map([[input.partUri, xml]]));
173947
+ const id = logical.structuralKeyToLogicalId.get(mark.entityKey);
173948
+ const entry = id ? logical.byId.get(id) : undefined;
173949
+ return entry?.type === "structural" && entry.subtype === "paragraph-mark-insertion" && entry.storyId === input.storyId && entry.reviewGroup == null && entry.subsumption == null ? entry.id : null;
173950
+ });
173951
+ }
173952
+ function buildBoundedTrackedParagraphRangeReceiptProjection(input) {
173953
+ return withStructuralLookupContext(undefined, (lookupContext) => {
173954
+ const xml = `<w:body>${input.xml}</w:body>`;
173955
+ const namespaceBindings = xmlFragmentAdditionalNamespaces(xml, new Map(Object.entries(input.namespaceBindings ?? {})), { w: NS_W, w14: NS_W14 });
173956
+ const parsed = collectXmlElementRanges(xml, { additionalNamespaces: namespaceBindings });
173957
+ if (parsed.errors.length || parsed.ranges.some((range) => range.tag.namespaceUri !== NS_W || /^(?:move|sectPr|sdt)/.test(range.tag.localName)))
173958
+ return null;
173959
+ const paragraphs = parsed.ranges.filter((range) => range.tag.localName === "p");
173960
+ if (paragraphs.length !== 2 || paragraphs.some((range) => !readXmlAttribute(range.tag, NS_W14, "paraId")?.value))
173961
+ return null;
173962
+ const raw = buildTrackedChangeCatalogFromPartXml({ xml, partUri: input.partUri, storyId: input.storyId, namespaceBindings });
173963
+ const structural = [...raw.structuralByKey.values()].flat();
173964
+ const mark = structural[0];
173965
+ if (structural.length !== 1 || !mark || mark.structuralKind !== "paragraph-mark-insertion" || mark.fullParagraphInsertion === true || raw.formattingByKey.size || raw.unsupportedByStory.size)
173966
+ return null;
173967
+ const logical = buildLogicalCatalogWithLookupContext(lookupContext, raw, input.replacementMode, new Map([[input.partUri, xml]]));
173968
+ const id = input.wordId === mark.wId ? logical.structuralKeyToLogicalId.get(mark.entityKey) : input.rsids?.length ? logical.rsidToLogicalId.get(input.rsids[0]) : undefined;
173969
+ const entry = id ? logical.byId.get(id) : undefined;
173970
+ if (!entry || entry.type !== "insertion" || entry.subtype !== "text-insertion" || entry.reviewGroup?.kind !== "word-inserted-paragraph-range" || entry.reviewGroup.role !== "parent" || entry.subsumption || entry.overlap || entry.movePair || entry.structuralFragments.length !== 1 || input.rsids?.some((rsid) => logical.rsidToLogicalId.get(rsid) !== id))
173971
+ return null;
173972
+ const carriers = [...entry.fragments, ...entry.structuralFragments];
173973
+ if (carriers.some((carrier) => !/^\d+$/.test(carrier.wId ?? "") || !input.authoredWordIds.has(Number(carrier.wId)) || carrier.customAttributes?.length))
173974
+ return null;
173975
+ if (parsed.ranges.some((range) => /^comment/.test(range.tag.localName) && range.start < entry.documentOrderEnd && range.end > entry.documentOrderStart))
173976
+ return null;
173977
+ const ordinary = parsed.ranges.filter((range) => range.tag.localName === "t" && range.closeStart > range.openEnd && parsed.ranges.every((parent) => !(parent.start < range.start && parent.end > range.end && /^(?:ins|del|pPr)$/.test(parent.tag.localName))));
173978
+ if (!ordinary.some((range) => range.end <= entry.documentOrderStart) || !ordinary.some((range) => range.start >= entry.documentOrderEnd))
173979
+ return null;
173980
+ return { id: entry.id, childIds: entry.reviewGroup.ownedChildIds };
173981
+ });
173982
+ }
173900
173983
  function buildIsolatedTrackedParagraphInsertionProjection(input, lookupContext) {
173901
173984
  return withStructuralLookupContext(lookupContext, (lookupContext2) => buildIsolatedTrackedParagraphInsertionProjectionWithLookupContext(lookupContext2, input));
173902
173985
  }
@@ -177061,12 +177144,7 @@ function isTableSplitParagraph(lookupContext, fragment3, partXml) {
177061
177144
  const parent = findImmediateParentElementAtPosition(partXml, fragment3.byteStart, lookupContext);
177062
177145
  if (!parent)
177063
177146
  return false;
177064
- const parentXml = partXml.slice(parent.start, parent.end);
177065
- const children = findDirectChildren(parentXml, undefined, lookupContext).map((child) => ({
177066
- ...child,
177067
- start: child.start + parent.start,
177068
- end: child.end + parent.start
177069
- }));
177147
+ const children = lookupContext.getDirectChildrenAtRange(partXml, parent.start, parent.end);
177070
177148
  const wrapperIndex = children.findIndex((child) => child.start === fragment3.byteStart && child.end === fragment3.byteEnd);
177071
177149
  if (wrapperIndex <= 0 || wrapperIndex >= children.length - 1)
177072
177150
  return false;
@@ -177109,12 +177187,7 @@ function isTableSplitTextInsertion(lookupContext, fragment3, partXml) {
177109
177187
  const parent = findImmediateParentElementAtPosition(partXml, paragraph.start, lookupContext);
177110
177188
  if (!parent)
177111
177189
  return false;
177112
- const parentXml = partXml.slice(parent.start, parent.end);
177113
- const children = findDirectChildren(parentXml, undefined, lookupContext).map((child) => ({
177114
- ...child,
177115
- start: child.start + parent.start,
177116
- end: child.end + parent.start
177117
- }));
177190
+ const children = lookupContext.getDirectChildrenAtRange(partXml, parent.start, parent.end);
177118
177191
  const paragraphIndex = children.findIndex((child) => child.localName === "p" && child.start === paragraph.start && child.end === paragraph.end);
177119
177192
  if (paragraphIndex <= 0 || paragraphIndex >= children.length - 1)
177120
177193
  return false;
@@ -178329,6 +178402,7 @@ function buildSDRenderCommitEnvelope(state, prepared, result, context = {}, opti
178329
178402
  if (trackedTextResolution != null && !trackedTextResolutionProved) {
178330
178403
  return broad("tracked-annotation-unproved");
178331
178404
  }
178405
+ const exhaustedInsertionProved = proveExhaustedTrackedInsertionForRender(prepared, context.originParagraphXml, postParagraphXml);
178332
178406
  const trackedDecisionInvalidatedChangeIds = trackedDecisionRefDelta?.kind === "invalidated" ? trackedDecisionRefDelta.changeIds : trackedTextResolutionProved ? trackedTextResolution.changeIds : null;
178333
178407
  const ownerByteDelta = postBytes.byteLength - (op.on.paragraphByteEnd - op.on.paragraphByteStart);
178334
178408
  const currentOwnerByteStart = ownerByteRange.byteStart;
@@ -178358,7 +178432,8 @@ function buildSDRenderCommitEnvelope(state, prepared, result, context = {}, opti
178358
178432
  const sliceDependencyReason = source.sourceKind === "textboxAtomReplacement" ? classifyTextboxAtomSliceDependency(prepared, postParagraphXml, context.originParagraphXml, trackedAnnotations) : trackedDecisionRefDelta ? classifyTrackedDecisionSliceDependency(postParagraphXml, context.originParagraphXml, trackedDecisionRefDelta.kind) : classifyUnprovedSliceDependency(postParagraphXml, trackedAnnotations, context.originParagraphXml, {
178359
178433
  allowTrackedWrapperDelta: source.sourceKind === "trackedChangeDecide",
178360
178434
  trackedCarrierRefinementProved,
178361
- trackedTextResolutionProved
178435
+ trackedTextResolutionProved,
178436
+ exhaustedInsertionProved
178362
178437
  });
178363
178438
  let derivedInvalidations = null;
178364
178439
  if (sliceDependencyReason) {
@@ -178378,7 +178453,8 @@ function buildSDRenderCommitEnvelope(state, prepared, result, context = {}, opti
178378
178453
  if (derivedInvalidations == null)
178379
178454
  return broad(sliceDependencyReason);
178380
178455
  }
178381
- const section = captureGoverningSectionDependency(state, op.on.storyId, bodyChild.bodyChildOrdinal);
178456
+ const directTextSourceEffect = source.sourceKind === "editText" && directEffectInput?.changeMode === "direct" ? classifyDirectVisibleTextLeafEffect(directEffectInput) : null;
178457
+ const section = captureGoverningSectionDependency(state, op.on.storyId, bodyChild.bodyChildOrdinal, directTextSourceEffect?.kind === "proved" ? "direct-visible-text" : undefined);
178382
178458
  if (!section) {
178383
178459
  const continuedTrackedInsertionChangeId = directEffectInput?.changeMode === "tracked" && trackedAnnotations?.length === 0 ? captureContinuedTrackedInsertionChangeId(prepared, directEffectInput, context.originParagraphXml, postParagraphXml, op.on.storyId) : null;
178384
178460
  const localizedBodyTextEffect = directEffectInput ? directEffectInput.changeMode === "direct" ? classifyDirectVisibleTextLeafEffect(directEffectInput) : directEffectInput.startOffset === directEffectInput.endOffset && directEffectInput.newText.length > 0 && (trackedAnnotations?.length === 1 && trackedAnnotations[0]?.kind === "insert" || continuedTrackedInsertionChangeId != null) ? classifyVisibleTextMutationEffect(directEffectInput) : null : null;
@@ -180491,6 +180567,77 @@ function captureContinuedTrackedInsertionChangeId(prepared, input, originParagra
180491
180567
  const expectedVisibleText = origin.visibleText.slice(0, localOffset) + input.newText + origin.visibleText.slice(localOffset);
180492
180568
  return post.visibleText === expectedVisibleText ? changeId : null;
180493
180569
  }
180570
+ function proveExhaustedTrackedInsertionForRender(prepared, originXml, postXml) {
180571
+ const proof = prepared.backendExtensions.storySurface?.trackedTextRefinement;
180572
+ const source = prepared.source;
180573
+ if (!proof?.removesInsertion || originXml == null || source.kind !== "editText" || source.changeMode !== "tracked" || source.newText !== "" || proof.insertedText !== "" || proof.blockId !== source.on.startBlockId || proof.sourceRange.coordinateSpace !== (source.on.coordinateSpace ?? "visible") || proof.sourceRange.startOffset !== source.on.startOffset || proof.sourceRange.endOffset !== source.on.endOffset || proof.liveTextRange.endOffset <= proof.liveTextRange.startOffset)
180574
+ return false;
180575
+ const parsed = collectXmlElementRanges(originXml, {
180576
+ fragment: true,
180577
+ additionalNamespaces: xmlFragmentAdditionalNamespaces(originXml, new Map, { w: NS_W })
180578
+ });
180579
+ if (parsed.errors.length)
180580
+ return false;
180581
+ const paragraph = parseParagraphInlineMap(originXml);
180582
+ const candidates = parsed.ranges.filter((range) => {
180583
+ if (range.tag.namespaceUri !== NS_W || range.tag.localName !== "ins")
180584
+ return false;
180585
+ const rsid = readXmlAttributeValueByLocalName(originXml.slice(range.start, range.openEnd), "rsidR");
180586
+ if (rsid?.toUpperCase() !== proof.insertionRsid.toUpperCase())
180587
+ return false;
180588
+ const pieces = paragraph.leaves().filter((piece) => piece.charStart >= range.openEnd && piece.charEnd <= range.closeStart && piece.visibleEnd > piece.visibleStart);
180589
+ return pieces.length > 0 && Math.min(...pieces.map((piece) => piece.visibleStart)) === proof.liveTextRange.startOffset && Math.max(...pieces.map((piece) => piece.visibleEnd)) === proof.liveTextRange.endOffset;
180590
+ });
180591
+ if (candidates.length !== 1)
180592
+ return false;
180593
+ const carrier = candidates[0];
180594
+ const properties = new Set([
180595
+ "rStyle",
180596
+ "rFonts",
180597
+ "b",
180598
+ "bCs",
180599
+ "i",
180600
+ "iCs",
180601
+ "caps",
180602
+ "smallCaps",
180603
+ "strike",
180604
+ "dstrike",
180605
+ "outline",
180606
+ "shadow",
180607
+ "emboss",
180608
+ "imprint",
180609
+ "noProof",
180610
+ "snapToGrid",
180611
+ "vanish",
180612
+ "webHidden",
180613
+ "color",
180614
+ "spacing",
180615
+ "w",
180616
+ "kern",
180617
+ "position",
180618
+ "sz",
180619
+ "szCs",
180620
+ "highlight",
180621
+ "u",
180622
+ "effect",
180623
+ "bdr",
180624
+ "shd",
180625
+ "fitText",
180626
+ "vertAlign",
180627
+ "rtl",
180628
+ "cs",
180629
+ "em",
180630
+ "lang",
180631
+ "eastAsianLayout",
180632
+ "specVanish",
180633
+ "oMath"
180634
+ ]);
180635
+ const descendants = parsed.ranges.filter((range) => range.start >= carrier.start && range.end <= carrier.end);
180636
+ const runProperties = descendants.filter((range) => range.tag.namespaceUri === NS_W && range.tag.localName === "rPr");
180637
+ if (descendants.some((range) => range !== carrier && (range.tag.namespaceUri !== NS_W || !(["r", "rPr", "t"].includes(range.tag.localName) || properties.has(range.tag.localName) && runProperties.some((parent) => range.start >= parent.openEnd && range.end <= parent.closeStart)))))
180638
+ return false;
180639
+ return originXml.slice(0, carrier.start) + originXml.slice(carrier.end) === postXml;
180640
+ }
180494
180641
  function trackedCarrierKeys(xml) {
180495
180642
  const keys = [];
180496
180643
  TRACKED_WRAPPER_TOKEN_RE.lastIndex = 0;
@@ -180748,7 +180895,7 @@ function classifyDeferrableSliceDependency(reason, xml, originXml, auxiliaryStor
180748
180895
  function classifyUnprovedSliceDependency(xml, trackedAnnotations, originXml, options = {}) {
180749
180896
  if (originXml == null)
180750
180897
  return "origin-slice-unavailable";
180751
- if (!options.trackedCarrierRefinementProved && !options.trackedTextResolutionProved && (TRACKED_WRAPPER_RE.test(xml) || TRACKED_WRAPPER_RE.test(originXml))) {
180898
+ if (!options.trackedCarrierRefinementProved && !options.trackedTextResolutionProved && !options.exhaustedInsertionProved && (TRACKED_WRAPPER_RE.test(xml) || TRACKED_WRAPPER_RE.test(originXml))) {
180752
180899
  if (!options.allowTrackedWrapperDelta || TRACKED_WRAPPER_RE.test(xml)) {
180753
180900
  if (trackedAnnotations == null)
180754
180901
  return "tracked-annotation-unproved";
@@ -180976,7 +181123,7 @@ function relationshipsPartUriFor(partUri) {
180976
181123
  const name = partUri.slice(slash + 1);
180977
181124
  return `${directory}/_rels/${name}.rels`;
180978
181125
  }
180979
- function captureGoverningSectionDependency(state, storyId, bodyChildOrdinal) {
181126
+ function captureGoverningSectionDependency(state, storyId, bodyChildOrdinal, sourceEdit) {
180980
181127
  const story = state.sourceSignals.snapshot?.stories.find((candidate2) => candidate2.storyId === storyId);
180981
181128
  if (story?.completeness.sections === "complete") {
180982
181129
  if (story.sections.length === 0) {
@@ -180994,7 +181141,7 @@ function captureGoverningSectionDependency(state, storyId, bodyChildOrdinal) {
180994
181141
  };
180995
181142
  }
180996
181143
  const section = findGoverningSection(story.sections, bodyChildOrdinal);
180997
- if (!section || story.sections.length === 1 && section.kind === "final-body-sectPr" && section.storyRevision !== story.storyRevision || !isNarrowSectionSupported(section, story))
181144
+ if (!section || story.sections.length === 1 && section.kind === "final-body-sectPr" && section.storyRevision !== story.storyRevision || !isNarrowSectionSupported(section, story, sourceEdit))
180998
181145
  return null;
180999
181146
  const startBodyChildOrdinal = section.appliesTo.startBodyChildOrdinal;
181000
181147
  const endBodyChildOrdinalExclusive = section.appliesTo.endBodyChildOrdinalExclusive;
@@ -181018,14 +181165,15 @@ function captureGoverningSectionDependency(state, storyId, bodyChildOrdinal) {
181018
181165
  function toggleEffectivelyOn(toggle) {
181019
181166
  return toggle.present && toggle.explicitValue !== false;
181020
181167
  }
181021
- function isNarrowSectionSupported(section, story) {
181168
+ function isNarrowSectionSupported(section, story, sourceEdit) {
181022
181169
  const pageSetup = section.pageSetup;
181170
+ const localTextSourceProved = sourceEdit === "direct-visible-text";
181023
181171
  const columnsAreEffectivelySingle = section.columns == null || (section.columns.count == null || section.columns.count === 1) && section.columns.columns.length <= 1 && section.columns.separator !== true;
181024
181172
  const columnsAreProvedNonBalanceable = section.columns != null && sectionColumnsProveBalancingInert(section.columns);
181025
181173
  const sectionType = pageSetup.type.value;
181026
181174
  const carrierMatches = section.kind === "final-body-sectPr" ? section.carrier.carrierKind === "final-body-sectPr" : section.carrier.carrierKind === "paragraph";
181027
181175
  const endnotePropertiesAreInactive = section.noteProperties.endnotePr == null || story.completeness.noteAnchorRefs === "complete" && story.noteAnchorRefs.every((reference) => reference.kind !== "endnote");
181028
- return carrierMatches && section.carrier.trackedChangeState === "none" && section.changeTracking.state === "unchanged" && section.mceAlternatives.length === 0 && (columnsAreEffectivelySingle || columnsAreProvedNonBalanceable) && section.noteProperties.footnotePr == null && endnotePropertiesAreInactive && section.lineNumbering == null && pageSetup.pageBorders == null && !toggleEffectivelyOn(pageSetup.bidi) && !toggleEffectivelyOn(pageSetup.rtlGutter) && !toggleEffectivelyOn(pageSetup.formProtection) && !pageSetup.textDirection.present && sectionType !== "evenPage" && sectionType !== "oddPage" && sectionType !== "nextColumn" && section.headerFooterRefs.every((ref3) => ref3.targetStatus === "resolved");
181176
+ return carrierMatches && section.carrier.trackedChangeState === "none" && section.changeTracking.state === "unchanged" && section.mceAlternatives.length === 0 && (localTextSourceProved || columnsAreEffectivelySingle || columnsAreProvedNonBalanceable) && (localTextSourceProved || section.noteProperties.footnotePr == null) && endnotePropertiesAreInactive && section.lineNumbering == null && pageSetup.pageBorders == null && (localTextSourceProved || !toggleEffectivelyOn(pageSetup.bidi)) && !toggleEffectivelyOn(pageSetup.rtlGutter) && !toggleEffectivelyOn(pageSetup.formProtection) && !pageSetup.textDirection.present && sectionType !== "evenPage" && sectionType !== "oddPage" && sectionType !== "nextColumn" && section.headerFooterRefs.every((ref3) => ref3.targetStatus === "resolved");
181029
181177
  }
181030
181178
  function sectionColumnsProveBalancingInert(columns) {
181031
181179
  const count = columns.count;
@@ -190533,9 +190681,11 @@ function buildCommentAnchorIndex(state, previousStoryScans, catalogOverride) {
190533
190681
  const bytes = state.packageBytes.get(story.partUri);
190534
190682
  if (!bytes)
190535
190683
  continue;
190536
- const previous = previousStoryScans.find((candidate2) => candidate2.bytes === bytes && sameStoryEnumeration(candidate2.story, story));
190537
- const storyHits = previous?.hits ?? scanStoryForAnchors(TD34.decode(bytes), story);
190538
- storyScans.push({ story: { ...story }, bytes, hits: storyHits });
190684
+ const previous = previousStoryScans.find((candidate2) => sameStoryEnumeration(candidate2.story, story));
190685
+ const xml = previous?.bytes === bytes ? previous.xml : TD34.decode(bytes);
190686
+ const scanned = previous?.bytes === bytes ? previous : scanStoryForAnchors(xml, story, previous);
190687
+ const storyHits = scanned.hits;
190688
+ storyScans.push({ story: { ...story }, bytes, xml, hits: storyHits, paragraphs: scanned.paragraphs });
190539
190689
  for (const hit of storyHits) {
190540
190690
  const list = hitsBySource.get(hit.sourceWId) ?? [];
190541
190691
  list.push(hit);
@@ -190597,7 +190747,7 @@ function enumerateStoryParts(state) {
190597
190747
  }
190598
190748
  return out;
190599
190749
  }
190600
- function scanStoryForAnchors(xml, story) {
190750
+ function scanStoryForAnchors(xml, story, previous) {
190601
190751
  const markers = [];
190602
190752
  const markerRe = /<[\w.-]+:(commentRangeStart|commentRangeEnd|commentReference)\s[^>]*?\bw:id="([^"]+)"[^>]*\/>/g;
190603
190753
  for (let m = markerRe.exec(xml);m; m = markerRe.exec(xml)) {
@@ -190611,8 +190761,8 @@ function scanStoryForAnchors(xml, story) {
190611
190761
  });
190612
190762
  }
190613
190763
  if (markers.length === 0)
190614
- return [];
190615
- const paragraphs = collectParagraphContexts(xml);
190764
+ return { hits: [], paragraphs: null };
190765
+ const paragraphs = rebaseTextOnlyParagraphContexts(xml, previous) ?? collectParagraphContexts(xml);
190616
190766
  const trackedWrapperCoverage = buildTrackedWrapperCoverage(xml);
190617
190767
  const byId = new Map;
190618
190768
  for (const mk of markers) {
@@ -190631,7 +190781,7 @@ function scanStoryForAnchors(xml, story) {
190631
190781
  const start = starts[i2];
190632
190782
  const end = ends[i2];
190633
190783
  const trackedChangeWrapper = findEnclosingTrackedWrapperKind(trackedWrapperCoverage, start.charStart, end.charEnd);
190634
- const rangeSegments = buildAnchorRangeSegments(xml, paragraphs, start, end);
190784
+ const rangeSegments = buildAnchorRangeSegments(xml, paragraphs ?? [], start, end);
190635
190785
  for (const segment of rangeSegments) {
190636
190786
  if (trackedChangeWrapper)
190637
190787
  segment.trackedChangeWrapper = trackedChangeWrapper;
@@ -190651,7 +190801,7 @@ function scanStoryForAnchors(xml, story) {
190651
190801
  hasRangeEnd: ends.length > 0
190652
190802
  });
190653
190803
  }
190654
- return out;
190804
+ return { hits: out, paragraphs };
190655
190805
  }
190656
190806
  function extractVisibleText2(xmlFragment) {
190657
190807
  let out = "";
@@ -190661,10 +190811,62 @@ function extractVisibleText2(xmlFragment) {
190661
190811
  }
190662
190812
  return out;
190663
190813
  }
190814
+ function rebaseTextOnlyParagraphContexts(xml, previous) {
190815
+ if (!previous?.paragraphs)
190816
+ return null;
190817
+ const prior = previous.xml;
190818
+ if (prior.includes("<!DOCTYPE"))
190819
+ return null;
190820
+ let start = 0;
190821
+ const commonLength = Math.min(prior.length, xml.length);
190822
+ const comparisonChunk = 4096;
190823
+ while (start + comparisonChunk <= commonLength && prior.slice(start, start + comparisonChunk) === xml.slice(start, start + comparisonChunk)) {
190824
+ start += comparisonChunk;
190825
+ }
190826
+ while (start < commonLength && prior.charCodeAt(start) === xml.charCodeAt(start))
190827
+ start += 1;
190828
+ if (start === prior.length && start === xml.length)
190829
+ return previous.paragraphs;
190830
+ let oldEnd = prior.length;
190831
+ let newEnd = xml.length;
190832
+ while (oldEnd - comparisonChunk >= start && newEnd - comparisonChunk >= start && prior.slice(oldEnd - comparisonChunk, oldEnd) === xml.slice(newEnd - comparisonChunk, newEnd)) {
190833
+ oldEnd -= comparisonChunk;
190834
+ newEnd -= comparisonChunk;
190835
+ }
190836
+ while (oldEnd > start && newEnd > start && prior.charCodeAt(oldEnd - 1) === xml.charCodeAt(newEnd - 1)) {
190837
+ oldEnd -= 1;
190838
+ newEnd -= 1;
190839
+ }
190840
+ if (/[<>]/.test(prior.slice(start, oldEnd)) || /[<>]/.test(xml.slice(start, newEnd)))
190841
+ return null;
190842
+ const nodeStart = prior.lastIndexOf("<", start - 1);
190843
+ if (nodeStart < 0)
190844
+ return null;
190845
+ for (const [open, close] of [["<!--", "-->"], ["<![CDATA[", "]]>"], ["<?", "?>"]]) {
190846
+ if (prior.lastIndexOf(open, nodeStart) > prior.lastIndexOf(close, nodeStart))
190847
+ return null;
190848
+ }
190849
+ const node2 = readXmlNodeAt(prior, nodeStart);
190850
+ if (!node2 || node2.kind !== "element" || node2.selfClosing || node2.openEnd > start || node2.closeStart < oldEnd) {
190851
+ return null;
190852
+ }
190853
+ const delta = xml.length - prior.length;
190854
+ const textEnd = prior.indexOf("<", node2.openEnd);
190855
+ if (textEnd < oldEnd || parseXmlForError(`<text>${xml.slice(node2.openEnd, textEnd + delta)}</text>`, { namespaceAware: false }) !== null)
190856
+ return null;
190857
+ const shift = (position) => position > start ? position + delta : position;
190858
+ return previous.paragraphs.map((paragraph) => ({
190859
+ paraId: paragraph.paraId,
190860
+ openStart: shift(paragraph.openStart),
190861
+ openEnd: shift(paragraph.openEnd),
190862
+ closeStart: shift(paragraph.closeStart),
190863
+ closeEnd: shift(paragraph.closeEnd)
190864
+ }));
190865
+ }
190664
190866
  function collectParagraphContexts(xml) {
190665
190867
  const scan = scanWmlParagraphSpans(xml);
190666
190868
  if (!scan.ok)
190667
- return [];
190869
+ return null;
190668
190870
  return scan.paragraphs.map((paragraph) => ({
190669
190871
  paraId: paragraph.paraId,
190670
190872
  openStart: paragraph.openStart,
@@ -190713,6 +190915,7 @@ var TD34, COMMENT_ANCHOR_INDEX_KEY = "__comment-anchor-index", ANCHOR_TAG;
190713
190915
  var init_comment_anchor_index = __esm(() => {
190714
190916
  init_lazy_indexes();
190715
190917
  init_wml_paragraph_spans();
190918
+ init_xml_sax();
190716
190919
  init_comments_catalog();
190717
190920
  init_tracked_wrapper_coverage();
190718
190921
  TD34 = new TextDecoder;
@@ -192629,7 +192832,8 @@ function compileParsedOverlapEdit(input, tokens, descendedEditableContainers) {
192629
192832
  }
192630
192833
  const paragraphContainsMoveWrapper = tokens.some((token) => token.kind === "unsupported" && token.foreignTrackedWrapper !== true && (token.trackedKind === "moveFrom" || token.trackedKind === "moveTo"));
192631
192834
  const trackedPlainCaret = (input.coordinateSpace ?? "visible") === "tracked" && tokenOwningCollapsedCaret(input, tokens)?.kind === "plain";
192632
- if ((paragraphContainsMoveWrapper || trackedPlainCaret) && input.rangeStart === input.rangeEnd && input.newText.length > 0) {
192835
+ const deletedBreakBoundary = input.collapsedInlineAffinity != null && tokens.some((token) => token.kind === "unsupported" && token.deletedManualBreak === true && token.visibleStart === input.rangeStart && token.visibleEnd === input.rangeStart);
192836
+ if ((paragraphContainsMoveWrapper || trackedPlainCaret || deletedBreakBoundary) && input.rangeStart === input.rangeEnd && input.newText.length > 0) {
192633
192837
  const defersExplicitUpstreamMoveBoundary = input.changeMode === "direct" && input.collapsedInlineAffinity === "upstream" && !tokens.some((token) => token.kind === "plain" && token.visibleEnd === input.rangeStart) && tokens.some((token) => token.kind === "unsupported" && token.foreignTrackedWrapper !== true && token.trackedKind === "moveFrom" && token.visibleStart === input.rangeStart && token.visibleEnd === input.rangeStart);
192634
192838
  if (defersExplicitUpstreamMoveBoundary) {
192635
192839
  return {
@@ -192638,7 +192842,8 @@ function compileParsedOverlapEdit(input, tokens, descendedEditableContainers) {
192638
192842
  detail: "overlap compiler: upstream move boundary is owned by the direct inline planner."
192639
192843
  };
192640
192844
  }
192641
- return compilePlainOnlyCollapsedInsertion(input, tokens, touched);
192845
+ const insertion = compilePlainOnlyCollapsedInsertion(input, tokens, touched);
192846
+ return deletedBreakBoundary && insertion.ok ? { ...insertion, requiresCollaborationSessionSync: true } : insertion;
192642
192847
  }
192643
192848
  return { ok: false, reason: "invalid-range", detail: "overlap compiler: no tracked wrappers touched." };
192644
192849
  }
@@ -194850,6 +195055,17 @@ function trackedToken(piece, spanStart, spanEnd, allowComplexDeletions, allowStr
194850
195055
  })).sort((a, b) => a.localOffset - b.localOffset);
194851
195056
  }
194852
195057
  const commentedBoundary = piece.trackedKind === "ins" && !nestedDeletions ? readCommentedInsertionBoundary(piece) : null;
195058
+ const onlyChild = piece.children.length === 1 ? piece.children[0] : undefined;
195059
+ if (piece.trackedKind === "del" && onlyChild?.kind === "control" && (onlyChild.control === "br" || onlyChild.control === "cr")) {
195060
+ const attrs = onlyChild.rawXml.replace(/^<[^\s/>]+/, "").replace(/\/?>$/, "");
195061
+ const breakType = decodeNamespacedAttr(attrs, piece.namespaceBindings, "type");
195062
+ if (breakType == null || breakType === "textWrapping") {
195063
+ return {
195064
+ ...unsupported2("text-payload-unsupported-control-char", "overlap compiler: deleted manual break"),
195065
+ deletedManualBreak: true
195066
+ };
195067
+ }
195068
+ }
194853
195069
  if (allowComplexDeletions && piece.trackedKind === "del") {
194854
195070
  const unsupportedChild = piece.children.find((child) => child.kind !== "text" && !(child.kind === "marker" && isCommentMarker2(child.markerKind)) && !(allowStructuralDeletionPassThrough && isSupportedStructuralDeletionChild(child)));
194855
195071
  if (unsupportedChild) {
@@ -195262,10 +195478,15 @@ function projectTrackedChangesForExport(state, options) {
195262
195478
  const partXmlByUri = readWordXmlParts(state, options.baseOverrides);
195263
195479
  const rawCatalog = readTrackedChangeCatalogForExport(state, options.excludedPartUris, options.baseOverrides);
195264
195480
  const sessionProvenance = collectSessionTrackedChangeProvenance(state);
195265
- const warnings = buildTrackedChangesExportWarnings(rawCatalog, partXmlByUri, options.replacementMode, options.mode === "review-preserving" ? sessionProvenance : null);
195481
+ const logicalProvenance = options.mode === "review-preserving" ? sessionProvenance : null;
195482
+ const logicalCatalog = buildLogicalCatalog(rawCatalog, options.replacementMode, partXmlByUri, undefined, {
195483
+ sessionCreatedTrackedChangeRsids: logicalProvenance?.rsids,
195484
+ sessionCreatedTrackedChangeWIds: collectOwnedSessionTrackedChangeWIds(logicalProvenance)
195485
+ });
195486
+ const warnings = buildTrackedChangesExportWarnings(logicalCatalog, partXmlByUri, logicalProvenance);
195266
195487
  const overrides = new Map;
195267
195488
  if (options.mode === "review-preserving") {
195268
- const projected = projectReviewPreservingTrackedChanges(rawCatalog, partXmlByUri, options.replacementMode, sessionProvenance);
195489
+ const projected = projectReviewPreservingTrackedChanges(logicalCatalog, partXmlByUri, sessionProvenance);
195269
195490
  for (const [partUri, xml] of projected) {
195270
195491
  const original = partXmlByUri.get(partUri);
195271
195492
  if (original !== undefined && xml !== original) {
@@ -195302,11 +195523,7 @@ function isWordXmlPart(partUri) {
195302
195523
  const normalized = partUri.startsWith("/") ? partUri.slice(1) : partUri;
195303
195524
  return normalized.startsWith("word/") && normalized.endsWith(".xml") && !normalized.includes("/_rels/");
195304
195525
  }
195305
- function buildTrackedChangesExportWarnings(rawCatalog, partXmlByUri, replacementMode, sessionProvenance) {
195306
- const logicalCatalog = buildLogicalCatalog(rawCatalog, replacementMode, partXmlByUri, undefined, {
195307
- sessionCreatedTrackedChangeRsids: sessionProvenance?.rsids,
195308
- sessionCreatedTrackedChangeWIds: collectOwnedSessionTrackedChangeWIds(sessionProvenance)
195309
- });
195526
+ function buildTrackedChangesExportWarnings(logicalCatalog, partXmlByUri, sessionProvenance) {
195310
195527
  const warnings = [];
195311
195528
  const seenCodes = new Set;
195312
195529
  const orderedChanges = [...logicalCatalog.byId.values()].sort((left, right) => left.partUri.localeCompare(right.partUri) || left.documentOrderStart - right.documentOrderStart || left.id.localeCompare(right.id));
@@ -195360,11 +195577,7 @@ function isDeleteInsertMoveApproximation(change) {
195360
195577
  const structuralApproximation = change.structuralFragments.length === 2 && change.structuralFragments.some((fragment3) => fragment3.sourceWrapperKind === "del") && change.structuralFragments.some((fragment3) => fragment3.sourceWrapperKind === "ins");
195361
195578
  return textApproximation || structuralApproximation;
195362
195579
  }
195363
- function projectReviewPreservingTrackedChanges(rawCatalog, partXmlByUri, replacementMode, sessionProvenance) {
195364
- const logicalCatalog = buildLogicalCatalog(rawCatalog, replacementMode, partXmlByUri, undefined, {
195365
- sessionCreatedTrackedChangeRsids: sessionProvenance.rsids,
195366
- sessionCreatedTrackedChangeWIds: collectOwnedSessionTrackedChangeWIds(sessionProvenance)
195367
- });
195580
+ function projectReviewPreservingTrackedChanges(logicalCatalog, partXmlByUri, sessionProvenance) {
195368
195581
  const replacementsByPart = new Map;
195369
195582
  const allocateMoveStamp = createExportMoveStampAllocator(partXmlByUri);
195370
195583
  const orderedChanges = [...logicalCatalog.byId.values()].sort((left, right) => left.partUri.localeCompare(right.partUri) || left.documentOrderStart - right.documentOrderStart || left.id.localeCompare(right.id));
@@ -197332,10 +197545,13 @@ function commitDirect(input, view) {
197332
197545
  const patchMaps = {
197333
197546
  [op.on.partUri]: { partUri: op.on.partUri, ranges: [] }
197334
197547
  };
197548
+ let noteOwnerXml;
197335
197549
  const noteSidecar = appendRemovedNoteSidecarPatches({
197336
197550
  state,
197337
197551
  ownerPartUri: op.on.partUri,
197338
- ownerXml: TD40.decode(bytes),
197552
+ get ownerXml() {
197553
+ return noteOwnerXml ?? (noteOwnerXml = TD40.decode(bytes));
197554
+ },
197339
197555
  beforeWindowXml: TD40.decode(bytes.subarray(window2.byteStart, window2.byteEnd)),
197340
197556
  afterWindowXml: TD40.decode(localized.bytes),
197341
197557
  perPart,
@@ -199688,8 +199904,13 @@ function paragraphWindowFromResolvedRange(bytes, op, searchRange) {
199688
199904
  const scanEnd = searchRange?.[1] ?? bytes.length;
199689
199905
  if (scanEnd <= start)
199690
199906
  return null;
199691
- const paragraphXmlAndTail = TD40.decode(bytes.subarray(start, scanEnd));
199692
- const paragraph = readXmlNodeAt(paragraphXmlAndTail, 0);
199907
+ const boundedEnd = Math.min(hintedEnd, scanEnd);
199908
+ let paragraphXmlAndTail = TD40.decode(bytes.subarray(start, boundedEnd));
199909
+ let paragraph = readXmlNodeAt(paragraphXmlAndTail, 0);
199910
+ if (!paragraph && boundedEnd < scanEnd) {
199911
+ paragraphXmlAndTail = TD40.decode(bytes.subarray(start, scanEnd));
199912
+ paragraph = readXmlNodeAt(paragraphXmlAndTail, 0);
199913
+ }
199693
199914
  if (!paragraph || paragraph.kind !== "element" || xmlLocalName(paragraph.qname) !== "p")
199694
199915
  return null;
199695
199916
  const actualEnd = start + TE16.encode(paragraphXmlAndTail.slice(0, paragraph.end)).length;
@@ -207203,8 +207424,50 @@ var init_hyperlink_catalog = __esm(() => {
207203
207424
  STATE_CACHE = new WeakMap;
207204
207425
  });
207205
207426
 
207427
+ // ../../../v2/editor-core/dist/document/transactions/tracked-changes/decision-xml-analysis.js
207428
+ function createDecisionXmlAnalysis() {
207429
+ const owners = new Map;
207430
+ let disposed = false;
207431
+ const read = (partUri, xml, slot) => {
207432
+ if (disposed)
207433
+ throw new Error("Decision XML analysis is disposed.");
207434
+ let owner = owners.get(partUri);
207435
+ if (!owner) {
207436
+ owner = {};
207437
+ owners.set(partUri, owner);
207438
+ }
207439
+ const same = owner[slot];
207440
+ if (same?.xml === xml)
207441
+ return same.elements;
207442
+ const other = owner[slot === "original" ? "current" : "original"];
207443
+ const snapshot2 = other?.xml === xml ? other : { xml, elements: collectXmlElementRanges(xml) };
207444
+ owner[slot] = snapshot2;
207445
+ return snapshot2.elements;
207446
+ };
207447
+ return {
207448
+ original: (partUri, xml) => read(partUri, xml, "original"),
207449
+ current: (partUri, xml) => read(partUri, xml, "current"),
207450
+ dispose() {
207451
+ owners.clear();
207452
+ disposed = true;
207453
+ }
207454
+ };
207455
+ }
207456
+ var init_decision_xml_analysis = __esm(() => {
207457
+ init_xml_sax();
207458
+ });
207459
+
207206
207460
  // ../../../v2/editor-core/dist/document/transactions/image-review-resources.js
207207
207461
  function applyImageReviewResourceCleanup(input) {
207462
+ const xmlAnalysis = input.xmlAnalysis ?? createDecisionXmlAnalysis();
207463
+ try {
207464
+ return applyImageReviewResourceCleanupWithAnalysis(input, xmlAnalysis);
207465
+ } finally {
207466
+ if (!input.xmlAnalysis)
207467
+ xmlAnalysis.dispose();
207468
+ }
207469
+ }
207470
+ function applyImageReviewResourceCleanupWithAnalysis(input, xmlAnalysis) {
207208
207471
  const fail4 = { ok: false, reason: "patch-precondition-failed" };
207209
207472
  const removedMedia = new Set;
207210
207473
  const acceptedMedia = new Set;
@@ -207219,7 +207482,8 @@ function applyImageReviewResourceCleanup(input) {
207219
207482
  const beforeXml = TD47.decode(beforeBytes);
207220
207483
  if (!beforeXml.includes("drawing") || !/<(?:[\w.-]+:)?(?:blip|hlinkClick|hlinkHover)\b/.test(beforeXml))
207221
207484
  continue;
207222
- const before = imageRelationshipUses(beforeXml);
207485
+ const beforeParsed = xmlAnalysis.original(partUri, beforeXml);
207486
+ const before = imageRelationshipUses(beforeParsed);
207223
207487
  if (!before)
207224
207488
  return fail4;
207225
207489
  if (before.length === 0)
@@ -207227,7 +207491,7 @@ function applyImageReviewResourceCleanup(input) {
207227
207491
  let afterXml = currentXml2(input, partUri);
207228
207492
  if (afterXml === null)
207229
207493
  return fail4;
207230
- let afterUses = allRelationshipUses(afterXml);
207494
+ let afterUses = allRelationshipUses(xmlAnalysis.current(partUri, afterXml));
207231
207495
  if (!afterUses)
207232
207496
  return fail4;
207233
207497
  const relsUri = relsPartUriForStory(partUri);
@@ -207241,14 +207505,14 @@ function applyImageReviewResourceCleanup(input) {
207241
207505
  return fail4;
207242
207506
  const byId = new Map(relationships.value.map((relationship) => [relationship.id, relationship]));
207243
207507
  if (input.decision === "accept") {
207244
- const allBeforeUses = allRelationshipUses(beforeXml);
207245
- const beforeRanges = collectXmlElementRanges(beforeXml).ranges;
207508
+ const allBeforeUses = allRelationshipUses(beforeParsed);
207509
+ const beforeInsertions = wordWrapperRanges(beforeParsed.ranges, new Set(["ins"]));
207246
207510
  for (const use of before) {
207247
207511
  const relationship = byId.get(use.id);
207248
207512
  if (!isImageEmbed(use) || !isEmbeddedImage(relationship))
207249
207513
  continue;
207250
207514
  const owners = allBeforeUses.filter((owner) => owner.id === use.id);
207251
- if (!owners.every((owner) => isInsideWordWrapper(owner.range, beforeRanges, new Set(["ins"]))))
207515
+ if (!owners.every((owner) => isInsideRange(owner.range, beforeInsertions)))
207252
207516
  continue;
207253
207517
  const mediaUri = resolveInternalRelationshipTarget(relsUri, relationship.target);
207254
207518
  if (mediaUri)
@@ -207277,7 +207541,7 @@ function applyImageReviewResourceCleanup(input) {
207277
207541
  return fail4;
207278
207542
  relsXml = nextRels;
207279
207543
  afterXml = rewriteUse(afterXml, newUses[0], oldId);
207280
- afterUses = allRelationshipUses(afterXml);
207544
+ afterUses = allRelationshipUses(xmlAnalysis.current(partUri, afterXml));
207281
207545
  if (!afterUses)
207282
207546
  return fail4;
207283
207547
  stageXml2(input, partUri, afterXml);
@@ -207349,11 +207613,11 @@ function applyImageReviewResourceCleanup(input) {
207349
207613
  stageXml2(input, CONTENT_TYPES, contentTypesXml);
207350
207614
  }
207351
207615
  }
207352
- if (acceptedMedia.size > 0 && !promoteAcceptedMediaContentTypes(input, acceptedMedia))
207616
+ if (acceptedMedia.size > 0 && !promoteAcceptedMediaContentTypes(input, acceptedMedia, xmlAnalysis))
207353
207617
  return fail4;
207354
207618
  return { ok: true, drawingsChanged };
207355
207619
  }
207356
- function promoteAcceptedMediaContentTypes(input, candidates) {
207620
+ function promoteAcceptedMediaContentTypes(input, candidates, xmlAnalysis) {
207357
207621
  const owners = new Map;
207358
207622
  const partUris = new Set([...input.state.parts.keys(), ...Object.keys(input.perPart)]);
207359
207623
  for (const uri of partUris) {
@@ -207393,14 +207657,15 @@ function promoteAcceptedMediaContentTypes(input, candidates) {
207393
207657
  const ownerXml = currentXml2(input, owner.partUri);
207394
207658
  if (ownerXml === null)
207395
207659
  return false;
207396
- const uses = allRelationshipUses(ownerXml);
207660
+ const parsed = xmlAnalysis.current(owner.partUri, ownerXml);
207661
+ const uses = allRelationshipUses(parsed);
207397
207662
  if (!uses)
207398
207663
  return false;
207399
207664
  const matching = uses.filter((use) => use.id === owner.id);
207400
207665
  if (matching.length !== 1 || !isImageEmbed(matching[0]))
207401
207666
  continue;
207402
- const ranges = collectXmlElementRanges(ownerXml).ranges;
207403
- if (isInsideWordWrapper(matching[0].range, ranges, new Set(["ins", "del", "moveFrom", "moveTo"])))
207667
+ const wrappers = wordWrapperRanges(parsed.ranges, new Set(["ins", "del", "moveFrom", "moveTo"]));
207668
+ if (isInsideRange(matching[0].range, wrappers))
207404
207669
  continue;
207405
207670
  const extension = mediaUri.slice(mediaUri.lastIndexOf(".") + 1).toLowerCase();
207406
207671
  const existingDefault = registry2.defaults.get(extension);
@@ -207422,8 +207687,11 @@ function promoteAcceptedMediaContentTypes(input, candidates) {
207422
207687
  function isImageEmbed(use) {
207423
207688
  return DRAWING_NAMESPACES.has(use.range.tag.namespaceUri) && use.range.tag.localName === "blip" && use.attributeName.split(":").at(-1) === "embed";
207424
207689
  }
207425
- function isInsideWordWrapper(range, ranges, names) {
207426
- return ranges.some((owner) => WORD_NAMESPACES.has(owner.tag.namespaceUri) && names.has(owner.tag.localName) && owner.start <= range.start && owner.end >= range.end);
207690
+ function wordWrapperRanges(ranges, names) {
207691
+ return ranges.filter((owner) => WORD_NAMESPACES.has(owner.tag.namespaceUri) && names.has(owner.tag.localName));
207692
+ }
207693
+ function isInsideRange(range, owners) {
207694
+ return owners.some((owner) => owner.start <= range.start && owner.end >= range.end);
207427
207695
  }
207428
207696
  function isImageOrHyperlink(type) {
207429
207697
  return [...RELATIONSHIP_NAMESPACES].some((namespace) => type === `${namespace}/image` || type === `${namespace}/hyperlink`);
@@ -207431,18 +207699,17 @@ function isImageOrHyperlink(type) {
207431
207699
  function isEmbeddedImage(relationship) {
207432
207700
  return !!relationship && relationship.targetMode !== "External" && [...RELATIONSHIP_NAMESPACES].some((namespace) => relationship.type === `${namespace}/image`);
207433
207701
  }
207434
- function allRelationshipUses(xml) {
207435
- const parsed = collectXmlElementRanges(xml);
207702
+ function allRelationshipUses(parsed) {
207436
207703
  if (parsed.errors.length > 0)
207437
207704
  return null;
207438
207705
  return parsed.ranges.flatMap((range) => range.tag.attributes.flatMap((attribute) => RELATIONSHIP_NAMESPACES.has(attribute.namespaceUri) ? [{ id: attribute.value, range, attributeName: attribute.name }] : []));
207439
207706
  }
207440
- function imageRelationshipUses(xml) {
207441
- const uses = allRelationshipUses(xml);
207707
+ function imageRelationshipUses(parsed) {
207708
+ const uses = allRelationshipUses(parsed);
207442
207709
  if (!uses)
207443
207710
  return null;
207444
- const ranges = collectXmlElementRanges(xml).ranges;
207445
- return uses.filter(({ range }) => DRAWING_NAMESPACES.has(range.tag.namespaceUri) && ["blip", "hlinkClick", "hlinkHover"].includes(range.tag.localName) && ranges.some((owner) => WORD_NAMESPACES.has(owner.tag.namespaceUri) && owner.tag.localName === "drawing" && owner.start <= range.start && owner.end >= range.end));
207711
+ const drawings = wordWrapperRanges(parsed.ranges, new Set(["drawing"]));
207712
+ return uses.filter(({ range }) => DRAWING_NAMESPACES.has(range.tag.namespaceUri) && ["blip", "hlinkClick", "hlinkHover"].includes(range.tag.localName) && isInsideRange(range, drawings));
207446
207713
  }
207447
207714
  function imageEmbedIdsInRange(uses, start, end) {
207448
207715
  return new Set(uses.filter((use) => use.range.tag.localName === "blip" && use.attributeName.split(":").at(-1) === "embed" && use.range.start >= start && use.range.end <= end).map((use) => use.id));
@@ -207503,6 +207770,7 @@ var init_image_review_resources = __esm(() => {
207503
207770
  init_hyperlink_catalog();
207504
207771
  init_patch_substrate();
207505
207772
  init_package_graph();
207773
+ init_decision_xml_analysis();
207506
207774
  TD47 = new TextDecoder;
207507
207775
  TE22 = new TextEncoder;
207508
207776
  WORD_NAMESPACES = new Set([
@@ -207809,9 +208077,16 @@ function noteFamilyProfiles(state) {
207809
208077
  });
207810
208078
  }
207811
208079
  function runTrackedChangeDecideCommit(input, lookupContext) {
207812
- return withStructuralLookupContext(lookupContext, (lookupContext2) => runTrackedChangeDecideCommitWithLookupContext(lookupContext2, input));
208080
+ return withStructuralLookupContext(lookupContext, (lookupContext2) => {
208081
+ const xmlAnalysis = createDecisionXmlAnalysis();
208082
+ try {
208083
+ return runTrackedChangeDecideCommitWithLookupContext(lookupContext2, input, xmlAnalysis);
208084
+ } finally {
208085
+ xmlAnalysis.dispose();
208086
+ }
208087
+ });
207813
208088
  }
207814
- function runTrackedChangeDecideCommitWithLookupContext(lookupContext, input) {
208089
+ function runTrackedChangeDecideCommitWithLookupContext(lookupContext, input, xmlAnalysis) {
207815
208090
  const { state, txId, op } = input;
207816
208091
  const sessionHyperlinkReview = createSessionHyperlinkReviewTracker(state);
207817
208092
  if (input.options.expectedPackageRevision && input.options.expectedPackageRevision !== state.packageRevision) {
@@ -209246,6 +209521,7 @@ function runTrackedChangeDecideCommitWithLookupContext(lookupContext, input) {
209246
209521
  if (!wholeNoteCleanup.ok)
209247
209522
  return rejected7(txId, wholeNoteCleanup.reason);
209248
209523
  const noteCleanup = applyOrphanNoteStoryCleanup({
209524
+ xmlAnalysis,
209249
209525
  state,
209250
209526
  perPart,
209251
209527
  preconditions,
@@ -209269,6 +209545,7 @@ function runTrackedChangeDecideCommitWithLookupContext(lookupContext, input) {
209269
209545
  preconditions,
209270
209546
  patchMaps,
209271
209547
  decision: op.decision,
209548
+ xmlAnalysis,
209272
209549
  logicalChanges: preDecideLogicalCatalog.byId.values()
209273
209550
  });
209274
209551
  if (!imageCleanup.ok)
@@ -210407,6 +210684,8 @@ function applyCommentCascade(args) {
210407
210684
  function collectTrackedWholeNoteStoryLifecycleRemovals(state, perPart, fragmentsByPart, decision) {
210408
210685
  const removals = new Map;
210409
210686
  for (const [partUri, fragments] of fragmentsByPart) {
210687
+ if (partUri !== NOTE_FAMILY_PROFILE.footnotes.partUri && partUri !== NOTE_FAMILY_PROFILE.endnotes.partUri)
210688
+ continue;
210410
210689
  const bytes = state.packageBytes.get(partUri);
210411
210690
  if (!bytes || fragments.length === 0)
210412
210691
  continue;
@@ -210668,8 +210947,8 @@ function applyOrphanNoteStoryCleanup(args) {
210668
210947
  return { ok: true };
210669
210948
  const originalDocumentXml = TD48.decode(originalDocumentBytes);
210670
210949
  for (const profile of noteFamilyProfiles(args.state)) {
210671
- const currentIds = noteReferenceIds(documentXml, profile.referenceLocal);
210672
- const originalIds = noteReferenceIds(originalDocumentXml, profile.referenceLocal);
210950
+ const currentIds = noteReferenceIds(args.xmlAnalysis?.current(DOCUMENT_PART_URI, documentXml) ?? collectXmlElementRanges(documentXml), profile.referenceLocal);
210951
+ const originalIds = noteReferenceIds(args.xmlAnalysis?.original(DOCUMENT_PART_URI, originalDocumentXml) ?? collectXmlElementRanges(originalDocumentXml), profile.referenceLocal);
210673
210952
  const removedIds = [...originalIds].filter((id) => !currentIds.has(id));
210674
210953
  if (removedIds.length === 0)
210675
210954
  continue;
@@ -210800,9 +211079,8 @@ function collectRemovedNoteDefinitionTrackedChangeRefs(args, partUri, entryLocal
210800
211079
  const isRemoved = (start, end) => removedRanges.some((range) => start >= range.openEnd && end <= range.closeStart);
210801
211080
  collectRemovedNoteTrackedChangeRefs(args, partUri, isRemoved);
210802
211081
  }
210803
- function noteReferenceIds(xml, local) {
211082
+ function noteReferenceIds(parsed, local) {
210804
211083
  const ids = new Set;
210805
- const parsed = collectXmlElementRanges(xml);
210806
211084
  if (parsed.errors.length > 0)
210807
211085
  return ids;
210808
211086
  for (const range of parsed.ranges) {
@@ -211862,7 +212140,7 @@ function rebaseInsertedParagraphAfterFieldEdits(fragment3, edits) {
211862
212140
  return { ...fragment3, enclosingElementEnd: paragraphEnd };
211863
212141
  }
211864
212142
  function buildIndexedStructuralReanchorPlan(lookupContext, workingXml, groups) {
211865
- if (groups.length < 2 || groups.some((group) => group.fragments.length !== 1 || group.fragments.some((fragment3) => !INDEXABLE_STRUCTURAL_KINDS.has(fragment3.structuralKind) || !isSelfClosingStructuralFragment(fragment3) && fragment3.structuralKind !== "field-insertion" && fragment3.structuralKind !== "field-deletion"))) {
212143
+ if (groups.length === 0 || groups.some((group) => group.fragments.length !== 1 || group.fragments.some((fragment3) => !INDEXABLE_STRUCTURAL_KINDS.has(fragment3.structuralKind) || !isSelfClosingStructuralFragment(fragment3) && fragment3.structuralKind !== "field-insertion" && fragment3.structuralKind !== "field-deletion"))) {
211866
212144
  return null;
211867
212145
  }
211868
212146
  const reanchorStart = performance.now();
@@ -212517,6 +212795,7 @@ var init_compile_tracked_change_decide = __esm(() => {
212517
212795
  init_comment_tracked_change_metadata();
212518
212796
  init_bibliography_review_resources();
212519
212797
  init_image_review_resources();
212798
+ init_decision_xml_analysis();
212520
212799
  init_compound_move_paragraph();
212521
212800
  init_prepared_mutation();
212522
212801
  init_patch_substrate();
@@ -214039,8 +214318,63 @@ function validateWholeFieldRangeSelection(input) {
214039
214318
  }
214040
214319
  return { ok: true };
214041
214320
  }
214321
+ function hasFieldCandidates(xml) {
214322
+ return xml.includes("fldSimple") || xml.includes("fldChar") || xml.includes("instrText");
214323
+ }
214324
+ function hasFieldByteCandidates(bytes) {
214325
+ return FIELD_CANDIDATE_SEARCHES.some(({ token, anchorOffset }) => {
214326
+ const anchor = token[anchorOffset];
214327
+ for (let at = bytes.indexOf(anchor);at >= 0; at = bytes.indexOf(anchor, at + 1)) {
214328
+ const start = at - anchorOffset;
214329
+ if (start < 0 || start + token.length > bytes.length)
214330
+ continue;
214331
+ let offset = 0;
214332
+ while (offset < token.length && bytes[start + offset] === token[offset])
214333
+ offset += 1;
214334
+ if (offset === token.length)
214335
+ return true;
214336
+ }
214337
+ return false;
214338
+ });
214339
+ }
214340
+ function emptyFieldCatalog(storyId, partUri, sourceCodeUnits) {
214341
+ let measuredUnits = typeof sourceCodeUnits === "number" ? sourceCodeUnits : undefined;
214342
+ const units = () => measuredUnits ?? (measuredUnits = typeof sourceCodeUnits === "number" ? sourceCodeUnits : sourceCodeUnits());
214343
+ return {
214344
+ storyId,
214345
+ partUri,
214346
+ fields: [],
214347
+ byFieldId: new Map,
214348
+ unmatchedComplexFieldMarkerByteOffsets: [],
214349
+ utf8OffsetIndex: {
214350
+ representation: "not-needed",
214351
+ get sourceCodeUnits() {
214352
+ return units();
214353
+ },
214354
+ checkpointStride: UTF8_OFFSET_CHECKPOINT_STRIDE,
214355
+ checkpointCount: 0,
214356
+ storageBytes: 0,
214357
+ get denseEquivalentStorageBytes() {
214358
+ return (units() + 1) * Uint32Array.BYTES_PER_ELEMENT;
214359
+ }
214360
+ },
214361
+ ownerResolution: { mode: "not-needed", packedLookupCount: 0, packedFallbackCount: 0, packedRejectionReason: null }
214362
+ };
214363
+ }
214364
+ async function screenFieldCandidatesCooperatively(xml, checkpoint) {
214365
+ const stride = 512 * 1024;
214366
+ for (let start = 0;start < xml.length; start += stride) {
214367
+ if (hasFieldCandidates(xml.slice(start, start + stride + 8)))
214368
+ return true;
214369
+ if (start + stride < xml.length && !await checkpoint())
214370
+ return null;
214371
+ }
214372
+ return false;
214373
+ }
214042
214374
  function buildFieldCatalog(input) {
214043
214375
  const xml = input.sharedXml ?? TD50.decode(input.bytes);
214376
+ if (!hasFieldCandidates(xml))
214377
+ return emptyFieldCatalog(input.storyId, input.partUri, xml.length);
214044
214378
  return buildFieldCatalogFromXml(input, xml, buildSparseFieldUtf8OffsetIndex(xml));
214045
214379
  }
214046
214380
  function buildFieldCatalogFromXml(input, xml, utf8Offsets) {
@@ -214419,7 +214753,6 @@ async function buildSparseUtf8OffsetIndexCooperatively(xml, checkpoint) {
214419
214753
  let byteOffset = 0;
214420
214754
  let checkpointIndex = 0;
214421
214755
  let nextCheckpoint = 0;
214422
- let sliceStart = performance.now();
214423
214756
  while (codeUnitIndex < xml.length) {
214424
214757
  const sliceEnd = Math.min(xml.length, codeUnitIndex + 512 * 1024);
214425
214758
  while (codeUnitIndex < sliceEnd) {
@@ -214442,11 +214775,8 @@ async function buildSparseUtf8OffsetIndexCooperatively(xml, checkpoint) {
214442
214775
  codeUnitIndex += 1;
214443
214776
  }
214444
214777
  }
214445
- if (performance.now() - sliceStart >= 8) {
214446
- if (!await checkpoint())
214447
- return null;
214448
- sliceStart = performance.now();
214449
- }
214778
+ if (codeUnitIndex < xml.length && !await checkpoint())
214779
+ return null;
214450
214780
  }
214451
214781
  if (codeUnitIndex === nextCheckpoint)
214452
214782
  checkpointOffsets[checkpointIndex] = byteOffset;
@@ -214532,18 +214862,28 @@ function getOrBuildFieldCatalogForStory(state, storyId) {
214532
214862
  if (existing && existing.partBytes === bytes) {
214533
214863
  return existing.catalog;
214534
214864
  }
214865
+ if (!hasFieldByteCandidates(bytes)) {
214866
+ const catalog2 = emptyFieldCatalog(storyId, partUri, () => TD50.decode(bytes).length);
214867
+ perStory.set(storyId, { catalog: catalog2, partBytes: bytes });
214868
+ return catalog2;
214869
+ }
214535
214870
  const shared = peekPartWmlScanFacts(state, partUri);
214536
214871
  const xml = shared?.bytes === bytes ? shared.xml : DECODED_PART_IN_FLIGHT.get(bytes)?.xml ?? TD50.decode(bytes);
214872
+ if (!hasFieldCandidates(xml)) {
214873
+ const catalog2 = emptyFieldCatalog(storyId, partUri, xml.length);
214874
+ perStory.set(storyId, { catalog: catalog2, partBytes: bytes });
214875
+ return catalog2;
214876
+ }
214537
214877
  const utf8Offsets = buildSparseFieldUtf8OffsetIndex(xml);
214538
214878
  const ownerDiagnostics = { rejectionReason: null };
214539
- const paragraphOwnerResolver = createPackedFieldParagraphOwnerResolver({
214879
+ const paragraphOwnerResolver = hasFieldCandidates(xml) ? createPackedFieldParagraphOwnerResolver({
214540
214880
  state,
214541
214881
  partUri,
214542
214882
  bytes,
214543
214883
  xml,
214544
214884
  utf8Offsets,
214545
214885
  diagnostics: ownerDiagnostics
214546
- });
214886
+ }) : null;
214547
214887
  const catalog = buildFieldCatalogFromXml({
214548
214888
  bytes,
214549
214889
  storyId,
@@ -214625,11 +214965,24 @@ async function buildFieldCatalogForStoryCooperatively(input) {
214625
214965
  try {
214626
214966
  if (!await checkpoint())
214627
214967
  return syncWinner;
214968
+ const fieldCandidates = await screenFieldCandidatesCooperatively(decoded.xml, checkpoint);
214969
+ if (fieldCandidates == null)
214970
+ return syncWinner;
214971
+ if (!fieldCandidates) {
214972
+ if (!inputsAreCurrent())
214973
+ return null;
214974
+ const winner2 = currentCatalog();
214975
+ if (winner2)
214976
+ return winner2;
214977
+ const catalog2 = emptyFieldCatalog(input.storyId, input.partUri, decoded.xml.length);
214978
+ input.perStory.set(input.storyId, { catalog: catalog2, partBytes: input.bytes });
214979
+ return catalog2;
214980
+ }
214628
214981
  const utf8Offsets = await buildSparseUtf8OffsetIndexCooperatively(decoded.xml, checkpoint);
214629
214982
  if (!utf8Offsets)
214630
214983
  return syncWinner;
214631
214984
  const ownerDiagnostics = { rejectionReason: null };
214632
- const paragraphOwnerResolver = await createPackedFieldParagraphOwnerResolverCooperatively({
214985
+ const paragraphOwnerResolver = fieldCandidates ? await createPackedFieldParagraphOwnerResolverCooperatively({
214633
214986
  state: input.state,
214634
214987
  partUri: input.partUri,
214635
214988
  bytes: input.bytes,
@@ -214637,13 +214990,13 @@ async function buildFieldCatalogForStoryCooperatively(input) {
214637
214990
  utf8Offsets,
214638
214991
  checkpoint,
214639
214992
  diagnostics: ownerDiagnostics
214640
- });
214993
+ }) : null;
214641
214994
  if (syncWinner)
214642
214995
  return syncWinner;
214643
214996
  if (!inputsAreCurrent())
214644
214997
  return null;
214645
214998
  let sharedParagraphScan;
214646
- if (!paragraphOwnerResolver) {
214999
+ if (fieldCandidates && !paragraphOwnerResolver) {
214647
215000
  const aborted2 = Symbol("field-catalog-cooperative-aborted");
214648
215001
  try {
214649
215002
  const shared = await getOrScanPartWmlSpansCooperatively(input.state, input.partUri, async () => {
@@ -214697,7 +215050,7 @@ function listFieldCatalogsForState(state) {
214697
215050
  }
214698
215051
  return out;
214699
215052
  }
214700
- var TD50, UTF8_OFFSET_CHECKPOINT_STRIDE = 256, STATE_CACHE2, STATE_IN_FLIGHT, DECODED_PART_IN_FLIGHT;
215053
+ var TD50, UTF8_OFFSET_CHECKPOINT_STRIDE = 256, FIELD_CANDIDATE_BYTES, FIELD_CANDIDATE_SEARCHES, STATE_CACHE2, STATE_IN_FLIGHT, DECODED_PART_IN_FLIGHT;
214701
215054
  var init_field_catalog = __esm(() => {
214702
215055
  init_sd_document_state();
214703
215056
  init_xml_text();
@@ -214706,6 +215059,11 @@ var init_field_catalog = __esm(() => {
214706
215059
  init_part_wml_scan_cache();
214707
215060
  init_field_paragraph_owner();
214708
215061
  TD50 = new TextDecoder;
215062
+ FIELD_CANDIDATE_BYTES = [["fldSimple", 3], ["fldChar", 3], ["instrText", 7]];
215063
+ FIELD_CANDIDATE_SEARCHES = FIELD_CANDIDATE_BYTES.map(([token, anchorOffset]) => ({
215064
+ token: new TextEncoder().encode(token),
215065
+ anchorOffset
215066
+ }));
214709
215067
  STATE_CACHE2 = new WeakMap;
214710
215068
  STATE_IN_FLIGHT = new WeakMap;
214711
215069
  DECODED_PART_IN_FLIGHT = new WeakMap;
@@ -217790,7 +218148,15 @@ function enclosingWholeParagraphRevisions(state, entry) {
217790
218148
  if (bodyChild?.localName === "p" && bodyChild.byteStart === entry.byteStart && bodyChild.byteEnd === entry.byteEnd) {
217791
218149
  return [];
217792
218150
  }
217793
- const fragments = accessTrackedChangeCatalog(state).value.structuralByPart.get(entry.partUri) ?? [];
218151
+ const bytes = state.packageBytes.get(entry.partUri);
218152
+ const catalog = bodyChild && bytes && bodyChild.byteStart <= entry.byteStart && bodyChild.byteEnd >= entry.byteEnd ? buildTrackedChangeCatalogFromPartXml({
218153
+ xml: TD53.decode(bytes.subarray(bodyChild.byteStart, bodyChild.byteEnd)),
218154
+ partUri: entry.partUri,
218155
+ storyId: entry.storyId,
218156
+ sourceByteBase: bodyChild.byteStart,
218157
+ namespaceBindings: namespaceBindingsAtPosition(bytes, bodyChild.byteStart)
218158
+ }) : accessTrackedChangeCatalog(state).value;
218159
+ const fragments = catalog.structuralByPart.get(entry.partUri) ?? [];
217794
218160
  return fragments.flatMap((fragment3) => {
217795
218161
  if (fragment3.storyId !== entry.storyId || fragment3.structuralKind !== "paragraph-insertion" && fragment3.structuralKind !== "paragraph-deletion" || fragment3.sourceByteStart == null || fragment3.sourceByteEnd == null || fragment3.sourceByteStart > entry.byteStart || fragment3.sourceByteEnd < entry.byteEnd) {
217796
218162
  return [];
@@ -245613,6 +245979,116 @@ var init_review_projection_overlay = __esm(() => {
245613
245979
  });
245614
245980
 
245615
245981
  // ../../../v2/editor-core/dist/document/internal/top-level-table-topology.js
245982
+ function hasOpaqueMarkup(bytes) {
245983
+ const cached2 = OPAQUE_MARKUP_BY_BYTES.get(bytes);
245984
+ if (cached2 != null)
245985
+ return cached2;
245986
+ let opaque = false;
245987
+ for (let at = bytes.indexOf(60);at >= 0; at = bytes.indexOf(60, at + 1)) {
245988
+ if (bytes[at + 1] === 33) {
245989
+ opaque = true;
245990
+ break;
245991
+ }
245992
+ if (bytes[at + 1] !== 63)
245993
+ continue;
245994
+ const declarationStart = at === 0 || at === 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191;
245995
+ if (!declarationStart || bytes[at + 2] !== 120 || bytes[at + 3] !== 109 || bytes[at + 4] !== 108 || ![9, 10, 13, 32].includes(bytes[at + 5])) {
245996
+ opaque = true;
245997
+ break;
245998
+ }
245999
+ }
246000
+ OPAQUE_MARKUP_BY_BYTES.set(bytes, opaque);
246001
+ return opaque;
246002
+ }
246003
+ function rememberTopology(state, partUri, bytes, topology) {
246004
+ TOPOLOGY_BY_SOURCE_BYTES.set(bytes, topology);
246005
+ const SourceReference = globalThis.WeakRef;
246006
+ if (!SourceReference)
246007
+ return;
246008
+ let entries = LAST_TOPOLOGY_BY_STATE.get(state);
246009
+ if (!entries)
246010
+ LAST_TOPOLOGY_BY_STATE.set(state, entries = new Map);
246011
+ entries.set(partUri, { source: new SourceReference(bytes), topology });
246012
+ }
246013
+ function cachedTopology(state, partUri, bytes) {
246014
+ const current = TOPOLOGY_BY_SOURCE_BYTES.get(bytes);
246015
+ if (current) {
246016
+ rememberTopology(state, partUri, bytes, current);
246017
+ return current;
246018
+ }
246019
+ const previous = LAST_TOPOLOGY_BY_STATE.get(state)?.get(partUri);
246020
+ const before = previous?.source.deref();
246021
+ if (!previous || !before || hasOpaqueMarkup(before))
246022
+ return null;
246023
+ const topology = previous.topology;
246024
+ const stableIds = (ids) => ids.every((id) => /^(?:tbl|tr|tc):[0-9a-f]{8}$/i.test(id));
246025
+ if (!stableIds(topology.tableNodeIds) || topology.tableReadFacts && (!stableIds(topology.tableReadFacts.rowNodeIds) || !stableIds(topology.tableReadFacts.cellNodeIds)))
246026
+ return null;
246027
+ const oldView = new DataView(before.buffer, before.byteOffset, before.byteLength);
246028
+ const newView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
246029
+ const commonLength = Math.min(before.length, bytes.length);
246030
+ let start = 0;
246031
+ while (start + 4 <= commonLength && oldView.getUint32(start) === newView.getUint32(start))
246032
+ start += 4;
246033
+ while (start < before.length && start < bytes.length && before[start] === bytes[start])
246034
+ start += 1;
246035
+ let end = before.length;
246036
+ let nextEnd = bytes.length;
246037
+ while (end - start >= 4 && nextEnd - start >= 4 && oldView.getUint32(end - 4) === newView.getUint32(nextEnd - 4)) {
246038
+ end -= 4;
246039
+ nextEnd -= 4;
246040
+ }
246041
+ while (end > start && nextEnd > start && before[end - 1] === bytes[nextEnd - 1]) {
246042
+ end -= 1;
246043
+ nextEnd -= 1;
246044
+ }
246045
+ let preceding = start - 1;
246046
+ while (preceding >= 0 && before[preceding] !== 60)
246047
+ preceding -= 1;
246048
+ if (preceding < 0)
246049
+ return null;
246050
+ let quote = 0;
246051
+ let closed = false;
246052
+ for (let at = preceding + 1;at < start; at += 1) {
246053
+ const value = before[at];
246054
+ if (quote) {
246055
+ if (value === quote)
246056
+ quote = 0;
246057
+ } else if (value === 34 || value === 39)
246058
+ quote = value;
246059
+ else if (value === 62) {
246060
+ closed = true;
246061
+ break;
246062
+ }
246063
+ }
246064
+ if (!closed)
246065
+ return null;
246066
+ for (let index = start;index < end; index += 1)
246067
+ if (before[index] === 60 || before[index] === 62)
246068
+ return null;
246069
+ for (let index = start;index < nextEnd; index += 1)
246070
+ if (bytes[index] === 60 || bytes[index] === 62)
246071
+ return null;
246072
+ for (let index = 0;index < topology.tableByteStarts.length; index += 1) {
246073
+ if (start < topology.tableByteEnds[index] && end > topology.tableByteStarts[index])
246074
+ return null;
246075
+ if (start === end && start >= topology.tableByteStarts[index] && start <= topology.tableByteEnds[index])
246076
+ return null;
246077
+ }
246078
+ const delta = bytes.length - before.length;
246079
+ const shift = (values) => values.map((value) => value >= end ? value + delta : value);
246080
+ const rebased = {
246081
+ ...topology,
246082
+ tableByteStarts: shift(topology.tableByteStarts),
246083
+ tableByteEnds: shift(topology.tableByteEnds),
246084
+ cellByteStarts: shift(topology.cellByteStarts),
246085
+ cellBodyByteStarts: shift(topology.cellBodyByteStarts),
246086
+ cellBodyByteEnds: shift(topology.cellBodyByteEnds),
246087
+ telemetry: { ...topology.telemetry, sourceBytesScanned: bytes.length }
246088
+ };
246089
+ rememberTopology(state, partUri, bytes, rebased);
246090
+ return rebased;
246091
+ }
245616
246092
  function buildTopLevelTableTopology(bytes) {
245617
246093
  const scanner = scanTopLevelTableTopology(bytes);
245618
246094
  let step2 = scanner.next();
@@ -245633,15 +246109,15 @@ function getOrBuildTopLevelTableTopologyForStory(state, storyId) {
245633
246109
  const resolved = resolveInputs(state, storyId);
245634
246110
  if (!resolved)
245635
246111
  return null;
245636
- const { bytes } = resolved;
246112
+ const { partUri, bytes } = resolved;
245637
246113
  const nested = nestedStoryTopologyShape(state, storyId, bytes);
245638
246114
  if (nested === "table-free")
245639
246115
  return emptyStoryTopology();
245640
- const current = TOPOLOGY_BY_SOURCE_BYTES.get(bytes);
246116
+ const current = cachedTopology(state, partUri, bytes);
245641
246117
  if (current)
245642
246118
  return nested === "has-tables" ? withoutReadFacts(current) : current;
245643
246119
  const topology = buildTopLevelTableTopology(bytes);
245644
- TOPOLOGY_BY_SOURCE_BYTES.set(bytes, topology);
246120
+ rememberTopology(state, partUri, bytes, topology);
245645
246121
  return nested === "has-tables" ? withoutReadFacts(topology) : topology;
245646
246122
  }
245647
246123
  async function getOrBuildTopLevelTableTopologyForStoryCooperatively(state, storyId, yieldPoint) {
@@ -245652,13 +246128,13 @@ async function getOrBuildTopLevelTableTopologyForStoryCooperatively(state, story
245652
246128
  const nested = nestedStoryTopologyShape(state, storyId, bytes);
245653
246129
  if (nested === "table-free")
245654
246130
  return emptyStoryTopology();
245655
- const current = TOPOLOGY_BY_SOURCE_BYTES.get(bytes);
246131
+ const current = cachedTopology(state, partUri, bytes);
245656
246132
  if (current)
245657
246133
  return nested === "has-tables" ? withoutReadFacts(current) : current;
245658
246134
  const topology = await buildTopLevelTableTopologyCooperatively(bytes, yieldPoint);
245659
246135
  if (state.packageBytes.get(partUri) !== bytes)
245660
246136
  return null;
245661
- TOPOLOGY_BY_SOURCE_BYTES.set(bytes, topology);
246137
+ rememberTopology(state, partUri, bytes, topology);
245662
246138
  return nested === "has-tables" ? withoutReadFacts(topology) : topology;
245663
246139
  }
245664
246140
  function emptyStoryTopology() {
@@ -246372,12 +246848,14 @@ function sameName(bytes, start, end, otherStart, otherEnd) {
246372
246848
  }
246373
246849
  return true;
246374
246850
  }
246375
- var TD70, TOPOLOGY_BY_SOURCE_BYTES, YIELD_BYTE_INTERVAL, TABLE_MARKUP_RE, NESTED_SHAPE_BY_SOURCE_BYTES, WITHOUT_READ_FACTS, emptyTopology = null, LocalName, UNPROVED_TABLE_ELEMENT_NAMES;
246851
+ var TD70, TOPOLOGY_BY_SOURCE_BYTES, LAST_TOPOLOGY_BY_STATE, YIELD_BYTE_INTERVAL, OPAQUE_MARKUP_BY_BYTES, TABLE_MARKUP_RE, NESTED_SHAPE_BY_SOURCE_BYTES, WITHOUT_READ_FACTS, emptyTopology = null, LocalName, UNPROVED_TABLE_ELEMENT_NAMES;
246376
246852
  var init_top_level_table_topology = __esm(() => {
246377
246853
  init_sd_document_state();
246378
246854
  TD70 = new TextDecoder;
246379
246855
  TOPOLOGY_BY_SOURCE_BYTES = new WeakMap;
246856
+ LAST_TOPOLOGY_BY_STATE = new WeakMap;
246380
246857
  YIELD_BYTE_INTERVAL = 1 << 20;
246858
+ OPAQUE_MARKUP_BY_BYTES = new WeakMap;
246381
246859
  TABLE_MARKUP_RE = /<\/?(?:[\w.-]+:)?tbl[\s/>]/;
246382
246860
  NESTED_SHAPE_BY_SOURCE_BYTES = new WeakMap;
246383
246861
  WITHOUT_READ_FACTS = new WeakMap;
@@ -252387,6 +252865,19 @@ function allocateSDDocumentSessionInternalRevisionWIds(session, input) {
252387
252865
  const base2 = reserveRevisionWIdBlock(internal.state, count);
252388
252866
  return Array.from({ length: count }, (_unused, index) => base2 + index);
252389
252867
  }
252868
+ function getSDDocumentSessionInternalRevisionWIdReservations(session) {
252869
+ const internal = INTERNALS.get(session);
252870
+ if (!internal)
252871
+ throw new Error("internal: unknown SDDocumentSession instance");
252872
+ const reservations = internal.state.idReservations.revisionWIds;
252873
+ return {
252874
+ seeded: reservations.seeded,
252875
+ max: reservations.max,
252876
+ issued: new Set(reservations.issued),
252877
+ replayOwners: new Map(Array.from(reservations.replayOwners, ([id, owners]) => [id, new Set(owners)])),
252878
+ conflictedReserved: new Set(reservations.conflictedReserved)
252879
+ };
252880
+ }
252390
252881
  function applySDDocumentSessionInternalPatchGroup(session, input) {
252391
252882
  const internal = INTERNALS.get(session);
252392
252883
  if (!internal)
@@ -257638,7 +258129,7 @@ Complete new body.`,
257638
258129
  find: {
257639
258130
  memberPath: "find",
257640
258131
  description: "Search the document for text or node matches using SDM/1 selectors. Returns discovery-grade results: for mutation targeting, use query.match instead.",
257641
- expectedResult: "Returns an SDFindResult envelope ({ total, limit, offset, items }). Each item is an SDNodeResult ({ node, address }).",
258132
+ expectedResult: "Returns an SDFindResult envelope ({ total, limit, offset, items }). Each item is an SDNodeResult ({ node, address }). Text hits contain only the matched text; use getNode or getNodeById for the full containing node. Node selectors return full node projections.",
257642
258133
  requiresDocumentContext: true,
257643
258134
  metadata: readOperation2({
257644
258135
  idempotency: "idempotent",
@@ -295031,6 +295522,47 @@ var init_logical_view_cache = __esm(() => {
295031
295522
  });
295032
295523
 
295033
295524
  // ../../../v2/document-api-v2-adapter/dist/tracked-changes/receipt-entities.js
295525
+ function projectFreshTrackedParagraphSplitEntityId(context, txId, headBlockId, tailBlockId, refs) {
295526
+ const tracked = refs.filter((ref6) => ref6.kind === "trackedChange");
295527
+ if (tracked.length !== 1)
295528
+ return null;
295529
+ const ref5 = tracked[0];
295530
+ const history = getSDDocumentSessionInternalHistoryEntry(context.session, txId);
295531
+ if (history?.forwardPatchGroup.source.kind !== "paragraphSplit")
295532
+ return null;
295533
+ if (history.forwardPatchGroup.source.offset === 0)
295534
+ return null;
295535
+ const index = getSDDocumentSessionInternalStoryParagraphIndex(context.session, ref5.storyId);
295536
+ const head = index?.byParaId(headBlockId);
295537
+ const tail = index?.byParaId(tailBlockId);
295538
+ if (!head || !tail || index?.duplicateParaIds.has(headBlockId) || index?.duplicateParaIds.has(tailBlockId) || head.directBodyChildOrdinal == null || tail.directBodyChildOrdinal !== head.directBodyChildOrdinal + 1 || head.partUri !== tail.partUri || head.storyId !== tail.storyId || head.storyId !== ref5.storyId)
295539
+ return null;
295540
+ const part = history.forwardPatchGroup.perPart[head.partUri];
295541
+ const patch = part?.kind === "modify" && part.patches.length === 1 ? part.patches[0] : null;
295542
+ const bytes = getSDDocumentSessionInternalPartBytes(context.session, head.partUri);
295543
+ if (!bytes || patch?.kind !== "replaceBytes" || patch.startByte !== head.byteStart)
295544
+ return null;
295545
+ const committed = bytes.subarray(head.byteStart, tail.byteEnd);
295546
+ if (committed.length !== patch.bytes.length || !committed.every((byte, offset) => byte === patch.bytes[offset]))
295547
+ return null;
295548
+ const input = {
295549
+ xml: receiptDecoder.decode(committed),
295550
+ partUri: head.partUri,
295551
+ storyId: head.storyId,
295552
+ wordId: ref5.entityId,
295553
+ replacementMode: resolveReplacementMode(context.trackedChangesReplacementMode)
295554
+ };
295555
+ const standalone = buildIsolatedTrackedParagraphSplitLogicalId(input);
295556
+ if (standalone)
295557
+ return standalone;
295558
+ const reservations = getSDDocumentSessionInternalRevisionWIdReservations(context.session);
295559
+ const authoredWordIds = new Set([...reservations.issued].filter((id) => !reservations.conflictedReserved.has(id) && !reservations.replayOwners.has(id)));
295560
+ return buildBoundedTrackedParagraphRangeReceiptProjection({
295561
+ ...input,
295562
+ authoredWordIds,
295563
+ namespaceBindings: getSDDocumentSessionInternalMainStoryRootNamespaceBindings(context.session) ?? undefined
295564
+ })?.id ?? null;
295565
+ }
295034
295566
  function projectTrackedStructuralEntityIds(context, rawEntityIds) {
295035
295567
  if (rawEntityIds.length === 0)
295036
295568
  return [];
@@ -295652,7 +296184,7 @@ function buildTableCellRangeFromMatches(matches) {
295652
296184
  end: { rowIndex: maxRow, columnIndex: maxColumn }
295653
296185
  };
295654
296186
  }
295655
- function selectionIsStructurallyOutsideTables(blockIds, index, session) {
296187
+ function selectionIsStructurallyOutsideTables(blockIds, index, session, maxScanBytes = Number.POSITIVE_INFINITY) {
295656
296188
  if (blockIds.length === 0)
295657
296189
  return false;
295658
296190
  const entries = [];
@@ -295665,10 +296197,12 @@ function selectionIsStructurallyOutsideTables(blockIds, index, session) {
295665
296197
  const partUri = entries[0].partUri;
295666
296198
  if (entries.some((entry) => entry.partUri !== partUri))
295667
296199
  return false;
296200
+ const scanEnd = Math.max(...entries.map((entry) => entry.byteEnd));
296201
+ if (scanEnd > maxScanBytes)
296202
+ return false;
295668
296203
  const bytes = getSDDocumentSessionInternalPartBytes(session, partUri);
295669
296204
  if (!bytes)
295670
296205
  return false;
295671
- const scanEnd = Math.max(...entries.map((entry) => entry.byteEnd));
295672
296206
  const contexts = buildStructuralBoundaryMap(bytes.subarray(0, scanEnd)).contexts;
295673
296207
  return entries.every((entry) => {
295674
296208
  const structural = contexts[entry.ordinal];
@@ -295818,6 +296352,9 @@ class V2TablesAdapter {
295818
296352
  const index = story.storyKind === "main" ? getSDDocumentSessionInternalParagraphIndex(session) : getSDDocumentSessionInternalStoryParagraphIndex(session, story.storyId);
295819
296353
  if (!index)
295820
296354
  return EMPTY_TABLE_CONTEXT_AT_SELECTION;
296355
+ if (!input.selectionTextBounds && story.storyKind === "main" && selectionIsStructurallyOutsideTables(input.blockIds, index, session, 128 * 1024)) {
296356
+ return EMPTY_TABLE_CONTEXT_AT_SELECTION;
296357
+ }
295821
296358
  if (!input.selectionTextBounds && (story.storyKind === "main" || story.storyKind === "header" || story.storyKind === "footer")) {
295822
296359
  const proved = readTableContextFromTopology(readTopLevelTableTopologyForSession(session, story.storyId), index, input.blockIds);
295823
296360
  if (proved)
@@ -302702,6 +303239,21 @@ var init_numbering_stories = __esm(() => {
302702
303239
  function isParagraphNodeType(nodeType) {
302703
303240
  return PARAGRAPH_TYPES.has(nodeType);
302704
303241
  }
303242
+ function blockNumberingCache(context, storyId, index) {
303243
+ if (getSDDocumentSessionInternalSourceCompletePosture(context.session) !== "source-complete")
303244
+ return null;
303245
+ const revision = String(getSDDocumentSessionInternalPackageRevision(context.session));
303246
+ const reviewRevision = JSON.stringify(getSDDocumentSessionInternalReviewProjectionRevision(context.session));
303247
+ const styleModel = projectionStyleModel(context);
303248
+ const mutationSerial = context.currentMutationSerial();
303249
+ const key2 = context.session;
303250
+ const existing = BLOCK_NUMBERING_CACHE.get(key2);
303251
+ if (existing?.revision === revision && existing.reviewRevision === reviewRevision && existing.styleModel === styleModel && existing.mutationSerial === mutationSerial && existing.storyId === storyId && existing.paragraphIndex === index)
303252
+ return existing;
303253
+ const cached2 = { revision, reviewRevision, styleModel, mutationSerial, storyId, paragraphIndex: index, modes: new Map };
303254
+ BLOCK_NUMBERING_CACHE.set(key2, cached2);
303255
+ return cached2;
303256
+ }
302705
303257
  function blocksListQueryKey(input) {
302706
303258
  const nodeTypes = input?.nodeTypes && input.nodeTypes.length > 0 ? input.nodeTypes : null;
302707
303259
  const limit = input?.limit != null && input.limit > 0 ? input.limit : null;
@@ -302724,6 +303276,10 @@ function captureParagraphIndexMaterialization(index) {
302724
303276
  };
302725
303277
  }
302726
303278
  function buildReviewAwareBlockNumbering(context, storyId, index, storyByteRange, reviewMode) {
303279
+ const cache = storyByteRange ? null : blockNumberingCache(context, storyId, index);
303280
+ const cached2 = cache?.modes.get(reviewMode);
303281
+ if (cached2)
303282
+ return cached2;
302727
303283
  const stories = blockNumberingStories(context, storyId, index);
302728
303284
  const tableContexts = new Map;
302729
303285
  for (const story of stories) {
@@ -302748,12 +303304,19 @@ function buildReviewAwareBlockNumbering(context, storyId, index, storyByteRange,
302748
303304
  rawXml: readParagraphXml(context, partUriBytes, entry)
302749
303305
  }, tableContext.resolver?.resolve(entry), source.storyId);
302750
303306
  }
302751
- return projector.result();
303307
+ const result = projector.result();
303308
+ cache?.modes.set(reviewMode, result);
303309
+ return result;
302752
303310
  }
302753
303311
  async function buildReviewAwareBlockNumberingCooperatively(context, storyId, index, reviewMode, yieldPoint, inputsAreCurrent) {
303312
+ const cache = blockNumberingCache(context, storyId, index);
303313
+ const cached2 = cache?.modes.get(reviewMode);
303314
+ if (cached2 && inputsAreCurrent())
303315
+ return cached2;
302754
303316
  const stories = blockNumberingStories(context, storyId, index);
302755
303317
  const sources = stories.map((story) => paragraphIndexEntrySource(story.index));
302756
- const current = () => inputsAreCurrent() && sources.every((source) => source.isCurrent());
303318
+ const reviewRevision = JSON.stringify(getSDDocumentSessionInternalReviewProjectionRevision(context.session));
303319
+ const current = () => inputsAreCurrent() && JSON.stringify(getSDDocumentSessionInternalReviewProjectionRevision(context.session)) === reviewRevision && sources.every((source) => source.isCurrent());
302757
303320
  const gate = createCooperativeSliceGate(yieldPoint);
302758
303321
  const tableContexts = new Map;
302759
303322
  for (const story of stories) {
@@ -302778,7 +303341,13 @@ async function buildReviewAwareBlockNumberingCooperatively(context, storyId, ind
302778
303341
  if (!current())
302779
303342
  return null;
302780
303343
  }
302781
- return current() ? projector.result() : null;
303344
+ if (!current())
303345
+ return null;
303346
+ const result = projector.result();
303347
+ if (cache && blockNumberingCache(context, storyId, index) !== cache)
303348
+ return null;
303349
+ cache?.modes.set(reviewMode, result);
303350
+ return result;
302782
303351
  }
302783
303352
  function readBlockNumberingTableContext(context, storyId, index) {
302784
303353
  const model = projectionStyleModel(context);
@@ -303375,7 +303944,13 @@ class V2BlocksAdapter {
303375
303944
  if (!tailParaId) {
303376
303945
  return failure3("INTERNAL_ERROR", "paragraph split did not return a created paragraph id.");
303377
303946
  }
303378
- const trackedChangeRefs = readTrackedChangeRefs(this.context, receipt3.createdRefs ?? [], resolved.story);
303947
+ const localSplitId = projectFreshTrackedParagraphSplitEntityId(this.context, receipt3.txId, input.target.nodeId, tailParaId, receipt3.createdRefs ?? []);
303948
+ const trackedChangeRefs = localSplitId ? [{
303949
+ kind: "entity",
303950
+ entityType: "trackedChange",
303951
+ entityId: localSplitId,
303952
+ ...resolved.story ? { story: resolved.story } : {}
303953
+ }] : readTrackedChangeRefs(this.context, receipt3.createdRefs ?? [], resolved.story);
303379
303954
  return attachStructuralCommitDiagnostics({
303380
303955
  success: true,
303381
303956
  inserted: {
@@ -304548,7 +305123,7 @@ function readTailParaId(provisionalToFinal, createdRefs) {
304548
305123
  }
304549
305124
  return null;
304550
305125
  }
304551
- var TD87, PARAGRAPH_TYPES, TOP_LEVEL_LIST_ROWS_CACHE;
305126
+ var TD87, PARAGRAPH_TYPES, TOP_LEVEL_LIST_ROWS_CACHE, BLOCK_NUMBERING_CACHE;
304552
305127
  var init_adapter5 = __esm(() => {
304553
305128
  init_sd_document_session_internal();
304554
305129
  init_adapter3();
@@ -304572,6 +305147,7 @@ var init_adapter5 = __esm(() => {
304572
305147
  TD87 = new TextDecoder;
304573
305148
  PARAGRAPH_TYPES = new Set(["paragraph", "heading", "listItem"]);
304574
305149
  TOP_LEVEL_LIST_ROWS_CACHE = new WeakMap;
305150
+ BLOCK_NUMBERING_CACHE = new WeakMap;
304575
305151
  });
304576
305152
 
304577
305153
  // ../../../v2/document-api-v2-adapter/dist/paragraph-run-boundary.js
@@ -325876,6 +326452,528 @@ var init_tracked_structural_wrapper = __esm(() => {
325876
326452
  init_common();
325877
326453
  });
325878
326454
 
326455
+ // ../../../v2/document-api-v2-adapter/dist/permission-ranges/adapter.js
326456
+ class V2PermissionRangesAdapter {
326457
+ constructor(context) {
326458
+ this.context = context;
326459
+ }
326460
+ list(input) {
326461
+ const ranges = listPermissionRanges(this.context).map(stripInternal2);
326462
+ const page = pageSlice(ranges, input);
326463
+ return buildDiscoveryResult({
326464
+ evaluatedRevision: this.context.currentPublicRevision(),
326465
+ total: ranges.length,
326466
+ items: page.items.map((range) => buildDiscoveryItem(range.id, buildResolvedHandle(`permissionRange:${range.id}`, "stable", "ext:permissionRange"), range)),
326467
+ page: { offset: page.offset, limit: page.limit, returned: page.items.length }
326468
+ });
326469
+ }
326470
+ get(input) {
326471
+ const range = listPermissionRanges(this.context).find((entry) => entry.id === input.id);
326472
+ if (!range)
326473
+ throw operationError("TARGET_NOT_FOUND", `permission range ${input.id} not found.`);
326474
+ return stripInternal2(range);
326475
+ }
326476
+ create(input, options) {
326477
+ const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326478
+ if (mutationGuard)
326479
+ return mutationGuard;
326480
+ const wholeControl = resolveWholeControlPermissionTarget(this.context, input.target);
326481
+ if (wholeControl) {
326482
+ const xml2 = this.readDocumentXml();
326483
+ const id2 = input.id ?? allocateRangeId(listPermissionRanges(this.context));
326484
+ if (listPermissionRanges(this.context).some((range) => range.id === id2)) {
326485
+ throw operationError("INVALID_INPUT", "permission range id already exists.");
326486
+ }
326487
+ const rangeXml = buildPermStart(id2, input.principal) + xml2.slice(wholeControl.start, wholeControl.end) + buildPermEnd(id2);
326488
+ const nextXml2 = replaceRange2(xml2, wholeControl.start, wholeControl.end, rangeXml);
326489
+ if (dryRunRequested(input, options)) {
326490
+ const positions = positionsForMarkerEnvelope(nextXml2, wholeControl.start, wholeControl.start + rangeXml.length - buildPermEnd(id2).length);
326491
+ return { success: true, range: { id: id2, principal: input.principal, kind: positions.start.blockId === positions.end.blockId ? "inline" : "block", ...positions } };
326492
+ }
326493
+ const committed2 = commitWholePartUpdates(this.context, "permission-range-create", { [DOCUMENT_PART_URI5]: encodeXml(nextXml2) }, { expectedRevision: expectedRevisionFrom(input, options) });
326494
+ if (!committed2.ok)
326495
+ return { success: false, failure: { code: committed2.code, message: committed2.message } };
326496
+ return { success: true, range: this.get({ id: id2 }) };
326497
+ }
326498
+ const resolved = resolveBodySelectionTarget(this.context, input.target);
326499
+ if ("error" in resolved)
326500
+ throw operationError(resolved.error, resolved.message);
326501
+ if (resolved.startBlockId !== resolved.endBlockId) {
326502
+ throw operationError("INVALID_TARGET", "permissionRanges.create requires a same-paragraph text selection.");
326503
+ }
326504
+ const xml = this.readDocumentXml();
326505
+ const id = input.id ?? allocateRangeId(listPermissionRanges(this.context));
326506
+ const para = findParagraphById2(xml, resolved.startBlockId);
326507
+ if (!para)
326508
+ throw operationError("TARGET_NOT_FOUND", `paragraph ${resolved.startBlockId} not found.`);
326509
+ if (dryRunRequested(input, options)) {
326510
+ return {
326511
+ success: true,
326512
+ range: {
326513
+ id,
326514
+ principal: input.principal,
326515
+ kind: "inline",
326516
+ start: { blockId: resolved.startBlockId, offset: resolved.startOffset },
326517
+ end: { blockId: resolved.endBlockId, offset: resolved.endOffset }
326518
+ }
326519
+ };
326520
+ }
326521
+ const wrapped = wrapTextRangeWithPermissionMarkers(para.xml, resolved.startOffset, resolved.endOffset, id, input.principal);
326522
+ const nextXml = replaceRange2(xml, para.start, para.end, wrapped);
326523
+ const committed = commitWholePartUpdates(this.context, "permission-range-create", { [DOCUMENT_PART_URI5]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326524
+ if (!committed.ok)
326525
+ return { success: false, failure: { code: committed.code, message: committed.message } };
326526
+ return { success: true, range: this.get({ id }) };
326527
+ }
326528
+ remove(input, options) {
326529
+ const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326530
+ if (mutationGuard)
326531
+ return mutationGuard;
326532
+ const range = listPermissionRanges(this.context).find((entry) => entry.id === input.id);
326533
+ if (!range)
326534
+ throw operationError("TARGET_NOT_FOUND", `permission range ${input.id} not found.`);
326535
+ if (dryRunRequested(input, options))
326536
+ return { success: true, id: input.id };
326537
+ let xml = this.readDocumentXml();
326538
+ xml = removeMarkerAt(xml, range.endTagStart, range.endTagEnd);
326539
+ xml = removeMarkerAt(xml, range.startTagStart, range.startTagEnd);
326540
+ const committed = commitWholePartUpdates(this.context, "permission-range-remove", { [DOCUMENT_PART_URI5]: encodeXml(xml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326541
+ if (!committed.ok)
326542
+ return { success: false, failure: { code: committed.code, message: committed.message } };
326543
+ return { success: true, id: input.id };
326544
+ }
326545
+ updatePrincipal(input, options) {
326546
+ const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326547
+ if (mutationGuard)
326548
+ return mutationGuard;
326549
+ const range = listPermissionRanges(this.context).find((entry) => entry.id === input.id);
326550
+ if (!range)
326551
+ throw operationError("TARGET_NOT_FOUND", `permission range ${input.id} not found.`);
326552
+ if (dryRunRequested(input, options))
326553
+ return { success: true, range: stripInternal2(range) };
326554
+ const xml = this.readDocumentXml();
326555
+ const marker = xml.slice(range.startTagStart, range.startTagEnd);
326556
+ const nextMarker = buildPermStart(input.id, input.principal);
326557
+ const nextXml = xml.replace(marker, nextMarker);
326558
+ const committed = commitWholePartUpdates(this.context, "permission-range-update", { [DOCUMENT_PART_URI5]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326559
+ if (!committed.ok)
326560
+ return { success: false, failure: { code: committed.code, message: committed.message } };
326561
+ return { success: true, range: this.get({ id: input.id }) };
326562
+ }
326563
+ readDocumentXml() {
326564
+ const xml = readPartXml(this.context, DOCUMENT_PART_URI5);
326565
+ if (!xml)
326566
+ throw operationError("PRECONDITION_FAILED", "document.xml bytes are unavailable.");
326567
+ return xml;
326568
+ }
326569
+ }
326570
+ function listPermissionRanges(context) {
326571
+ const xml = readPartXml(context, DOCUMENT_PART_URI5);
326572
+ if (!xml)
326573
+ return [];
326574
+ const starts = new Map;
326575
+ const startRe = /<w:permStart\b[^>]*\/>/g;
326576
+ for (let match = startRe.exec(xml);match; match = startRe.exec(xml)) {
326577
+ const id = attrValue(match[0], "id");
326578
+ if (id)
326579
+ starts.set(id, { start: match.index, end: startRe.lastIndex, tag: match[0] });
326580
+ }
326581
+ const out = [];
326582
+ const endRe = /<w:permEnd\b[^>]*\/>/g;
326583
+ for (let match = endRe.exec(xml);match; match = endRe.exec(xml)) {
326584
+ const id = attrValue(match[0], "id");
326585
+ if (!id)
326586
+ continue;
326587
+ const start = starts.get(id);
326588
+ if (!start)
326589
+ continue;
326590
+ const positions = positionsForMarkerEnvelope(xml, start.start, match.index);
326591
+ const startPos = positions.start;
326592
+ const endPos = positions.end;
326593
+ out.push({
326594
+ id,
326595
+ principal: principalFromPermStart(start.tag),
326596
+ kind: startPos.blockId === endPos.blockId ? "inline" : "block",
326597
+ start: startPos,
326598
+ end: endPos,
326599
+ startTagStart: start.start,
326600
+ startTagEnd: start.end,
326601
+ endTagStart: match.index,
326602
+ endTagEnd: endRe.lastIndex
326603
+ });
326604
+ }
326605
+ return out.sort((a, b) => a.startTagStart - b.startTagStart);
326606
+ }
326607
+ function findContentControlXmlRange(xml, id) {
326608
+ const parsed = collectXmlElementRanges(xml);
326609
+ if (parsed.errors.length)
326610
+ return null;
326611
+ const matches = parsed.ranges.filter((range) => range.tag.localName === "sdt" && range.tag.namespaceUri === "http://schemas.openxmlformats.org/wordprocessingml/2006/main" && attrValue(/^\s*<w:sdtPr\b[^>]*>[\s\S]*?<\/w:sdtPr>/.exec(xml.slice(range.openEnd, range.closeStart))?.[0]?.match(/<w:id\b[^>]*\/>/)?.[0] ?? "", "val") === id);
326612
+ return matches.length === 1 ? { start: matches[0].start, end: matches[0].end } : null;
326613
+ }
326614
+ function resolveWholeControlPermissionTarget(context, target) {
326615
+ const { start, end } = target;
326616
+ if (start.kind !== "nodeEdge" && end.kind !== "nodeEdge")
326617
+ return null;
326618
+ if (start.kind !== "nodeEdge" || end.kind !== "nodeEdge" || start.edge !== "before" || end.edge !== "after" || start.node.nodeType !== "sdt" || end.node.nodeType !== "sdt" || start.node.nodeId !== end.node.nodeId) {
326619
+ throw operationError("INVALID_TARGET", "permissionRanges.create requires before/after edges of one content control.");
326620
+ }
326621
+ for (const locator of [target.story, start.node.story, end.node.story]) {
326622
+ const story = context.resolveFullStoryLocator(locator);
326623
+ if ("error" in story || story.partUri !== DOCUMENT_PART_URI5) {
326624
+ throw operationError("INVALID_TARGET", "whole-control permission ranges require one body content control.");
326625
+ }
326626
+ }
326627
+ const control2 = findContentControlXmlRange(readPartXml(context, DOCUMENT_PART_URI5) ?? "", start.node.nodeId);
326628
+ if (!control2)
326629
+ throw operationError("TARGET_NOT_FOUND", "permission-range content control was not found unambiguously.");
326630
+ return control2;
326631
+ }
326632
+ function positionsForMarkerEnvelope(xml, start, end) {
326633
+ const startPos = positionForXmlIndex(xml, start);
326634
+ const endPos = positionForXmlIndex(xml, end);
326635
+ if (startPos.blockId !== "unknown" && endPos.blockId !== "unknown")
326636
+ return { start: startPos, end: endPos };
326637
+ const paragraphs = collectXmlElementRanges(xml).ranges.filter((range) => range.tag.localName === "p" && range.start > start && range.end <= end);
326638
+ if (!paragraphs.length)
326639
+ return { start: startPos, end: endPos };
326640
+ const first = paragraphs[0];
326641
+ const last = paragraphs[paragraphs.length - 1];
326642
+ return {
326643
+ start: { blockId: attrValue(xml.slice(first.start, first.openEnd), "paraId") ?? "unknown", offset: 0 },
326644
+ end: { blockId: attrValue(xml.slice(last.start, last.openEnd), "paraId") ?? "unknown", offset: extractVisibleTextFromXml(xml.slice(last.start, last.end)).length }
326645
+ };
326646
+ }
326647
+ function stripInternal2(range) {
326648
+ return {
326649
+ id: range.id,
326650
+ principal: range.principal,
326651
+ kind: range.kind,
326652
+ start: range.start,
326653
+ end: range.end
326654
+ };
326655
+ }
326656
+ function principalFromPermStart(tag) {
326657
+ const attrs = readAttrs(tag);
326658
+ const group = attrs["w:edGrp"] ?? attrs.edGrp;
326659
+ if (group === "everyone")
326660
+ return { kind: "everyone" };
326661
+ const editor = attrs["w:ed"] ?? attrs.ed;
326662
+ return { kind: "editor", id: editor ?? group ?? "unknown" };
326663
+ }
326664
+ function buildPermStart(id, principal) {
326665
+ const principalAttr = principal.kind === "everyone" ? ' w:edGrp="everyone"' : ` w:ed="${xmlEscapeAttr(principal.id)}"`;
326666
+ return `<w:permStart w:id="${xmlEscapeAttr(id)}"${principalAttr}/>`;
326667
+ }
326668
+ function buildPermEnd(id) {
326669
+ return `<w:permEnd w:id="${xmlEscapeAttr(id)}"/>`;
326670
+ }
326671
+ function wrapTextRangeWithPermissionMarkers(paragraphXml, start, end, id, principal) {
326672
+ return replaceTextRangeInParagraph(paragraphXml, start, end, (selected) => [
326673
+ `<w:r>${buildPermStart(id, principal)}</w:r>`,
326674
+ `<w:r><w:t>${xmlEscapeText(selected)}</w:t></w:r>`,
326675
+ `<w:r>${buildPermEnd(id)}</w:r>`
326676
+ ].join(""));
326677
+ }
326678
+ function positionForXmlIndex(documentXml, index2) {
326679
+ const para = findParagraphContaining2(documentXml, index2);
326680
+ if (!para)
326681
+ return { blockId: "unknown", offset: 0 };
326682
+ return { blockId: attrValue(para.openTag, "paraId") ?? "unknown", offset: extractText2(para.xml.slice(0, index2 - para.start)).length };
326683
+ }
326684
+ function findParagraphContaining2(documentXml, index2) {
326685
+ const paraRe = /<w:p\b[^>]*>[\s\S]*?<\/w:p>/g;
326686
+ for (let match = paraRe.exec(documentXml);match; match = paraRe.exec(documentXml)) {
326687
+ if (match.index <= index2 && paraRe.lastIndex >= index2) {
326688
+ return { start: match.index, end: paraRe.lastIndex, xml: match[0], openTag: /^<w:p\b[^>]*>/.exec(match[0])?.[0] ?? "" };
326689
+ }
326690
+ }
326691
+ return null;
326692
+ }
326693
+ function findParagraphById2(documentXml, blockId) {
326694
+ const paraRe = /<w:p\b[^>]*>[\s\S]*?<\/w:p>/g;
326695
+ for (let match = paraRe.exec(documentXml);match; match = paraRe.exec(documentXml)) {
326696
+ if (match[0].includes(`w14:paraId="${blockId}"`))
326697
+ return { start: match.index, end: paraRe.lastIndex, xml: match[0] };
326698
+ }
326699
+ return null;
326700
+ }
326701
+ function replaceTextRangeInParagraph(paragraphXml, start, end, replacement) {
326702
+ const textRe = /<w:t\b[^>]*>([\s\S]*?)<\/w:t>/g;
326703
+ let offset = 0;
326704
+ for (let match = textRe.exec(paragraphXml);match; match = textRe.exec(paragraphXml)) {
326705
+ const text4 = decodeXmlEntities(match[1]);
326706
+ const nextOffset = offset + text4.length;
326707
+ if (start >= offset && end <= nextOffset) {
326708
+ const localStart = start - offset;
326709
+ const localEnd = end - offset;
326710
+ const before = text4.slice(0, localStart);
326711
+ const selected = text4.slice(localStart, localEnd);
326712
+ const after = text4.slice(localEnd);
326713
+ const runStart = findEnclosingRunStart(paragraphXml, match.index);
326714
+ const runEnd = paragraphXml.indexOf("</w:r>", textRe.lastIndex) + "</w:r>".length;
326715
+ const { runOpenTag, runProperties } = readRunOpenTagAndProperties(paragraphXml, runStart);
326716
+ const mkRun = (segment) => `${runOpenTag}${runProperties}<w:t xml:space="preserve">${xmlEscapeText(segment)}</w:t></w:r>`;
326717
+ return [
326718
+ paragraphXml.slice(0, runStart),
326719
+ before ? mkRun(before) : "",
326720
+ replacement(selected),
326721
+ after ? mkRun(after) : "",
326722
+ paragraphXml.slice(runEnd)
326723
+ ].join("");
326724
+ }
326725
+ offset = nextOffset;
326726
+ }
326727
+ throw operationError("TARGET_NOT_FOUND", "text range not found in paragraph.");
326728
+ }
326729
+ function removeMarkerAt(xml, start, end) {
326730
+ const runStart = findEnclosingRunStart(xml, start);
326731
+ const runEnd = xml.indexOf("</w:r>", end);
326732
+ if (runStart >= 0 && runEnd >= end) {
326733
+ const runXml = xml.slice(runStart, runEnd + "</w:r>".length);
326734
+ if (/^<w:r\b[^>]*>\s*<w:perm(?:Start|End)\b[^>]*\/>\s*<\/w:r>$/.test(runXml)) {
326735
+ return replaceRange2(xml, runStart, runEnd + "</w:r>".length, "");
326736
+ }
326737
+ }
326738
+ return replaceRange2(xml, start, end, "");
326739
+ }
326740
+ function replaceRange2(xml, start, end, replacement) {
326741
+ return `${xml.slice(0, start)}${replacement}${xml.slice(end)}`;
326742
+ }
326743
+ function extractText2(xml) {
326744
+ let out = "";
326745
+ const re = /<w:t\b[^>]*>([\s\S]*?)<\/w:t>/g;
326746
+ for (let match = re.exec(xml);match; match = re.exec(xml))
326747
+ out += decodeXmlEntities(match[1]);
326748
+ return out;
326749
+ }
326750
+ function allocateRangeId(existing) {
326751
+ const max2 = existing.reduce((acc, range) => Math.max(acc, Number(range.id) || 0), 1000);
326752
+ return String(max2 + 1 + Math.floor(Math.random() * 1000));
326753
+ }
326754
+ var init_adapter6 = __esm(() => {
326755
+ init_src3();
326756
+ init_sd_document_session_internal();
326757
+ init_visible_text();
326758
+ init_shared();
326759
+ init_xml();
326760
+ });
326761
+
326762
+ // ../../../v2/document-api-v2-adapter/dist/protection/adapter.js
326763
+ class V2ProtectionAdapter {
326764
+ constructor(context) {
326765
+ this.context = context;
326766
+ }
326767
+ get(_input) {
326768
+ return projectProtectionStateFromSettings(readPartXml(this.context, SETTINGS_PART_URI3));
326769
+ }
326770
+ setEditingRestriction(input, options) {
326771
+ const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326772
+ if (mutationGuard)
326773
+ return mutationGuard;
326774
+ const currentXml3 = readPartXml(this.context, SETTINGS_PART_URI3);
326775
+ const nextXml = setDocumentProtectionXml(currentXml3, {
326776
+ mode: input.mode,
326777
+ enforced: true,
326778
+ formattingRestricted: Boolean(input.formattingRestricted)
326779
+ });
326780
+ if (dryRunRequested(input, options)) {
326781
+ return { success: true, state: projectProtectionStateFromSettings(nextXml) };
326782
+ }
326783
+ if (nextXml === currentXml3) {
326784
+ const expectedRevision = expectedRevisionFrom(input, options);
326785
+ const failure4 = this.context.validateMutation({ expectedRevision: expectedRevision === undefined ? undefined : String(expectedRevision) });
326786
+ if (failure4)
326787
+ return { success: false, failure: failure4 };
326788
+ return { success: true, state: projectProtectionStateFromSettings(nextXml), changed: false };
326789
+ }
326790
+ const committed = commitWholePartUpdates(this.context, "protection-set", { [SETTINGS_PART_URI3]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326791
+ if (!committed.ok)
326792
+ return { success: false, failure: { code: committed.code, message: committed.message } };
326793
+ return { success: true, state: projectProtectionStateFromSettings(nextXml) };
326794
+ }
326795
+ clearEditingRestriction(input, options) {
326796
+ const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326797
+ if (mutationGuard)
326798
+ return mutationGuard;
326799
+ const currentXml3 = readPartXml(this.context, SETTINGS_PART_URI3);
326800
+ const nextXml = clearDocumentProtectionXml(currentXml3);
326801
+ if (dryRunRequested(input ?? {}, options)) {
326802
+ return { success: true, state: projectProtectionStateFromSettings(nextXml) };
326803
+ }
326804
+ if (nextXml === currentXml3) {
326805
+ const expectedRevision = expectedRevisionFrom(input, options);
326806
+ const failure4 = this.context.validateMutation({ expectedRevision: expectedRevision === undefined ? undefined : String(expectedRevision) });
326807
+ if (failure4)
326808
+ return { success: false, failure: failure4 };
326809
+ return { success: true, state: projectProtectionStateFromSettings(nextXml), changed: false };
326810
+ }
326811
+ const committed = commitWholePartUpdates(this.context, "protection-clear", { [SETTINGS_PART_URI3]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326812
+ if (!committed.ok)
326813
+ return { success: false, failure: { code: committed.code, message: committed.message } };
326814
+ return { success: true, state: projectProtectionStateFromSettings(nextXml) };
326815
+ }
326816
+ }
326817
+ function projectProtectionStateFromSettings(settingsXml) {
326818
+ const documentProtection = settingsXml ? matchElement(settingsXml, "w:documentProtection") : null;
326819
+ const writeProtection = settingsXml ? matchElement(settingsXml, "w:writeProtection") : null;
326820
+ const readOnlyRecommended = settingsXml ? /<w:readOnlyRecommended\b/.test(settingsXml) : false;
326821
+ return {
326822
+ editingRestriction: projectEditingRestriction(documentProtection ? readAttrs(documentProtection) : null),
326823
+ writeProtection: projectWriteProtection(writeProtection ? readAttrs(writeProtection) : null),
326824
+ readOnlyRecommended
326825
+ };
326826
+ }
326827
+ function projectEditingRestriction(raw) {
326828
+ if (!raw) {
326829
+ return { ...DEFAULT_PROTECTION_STATE.editingRestriction };
326830
+ }
326831
+ const editRaw = pickAttr(raw, "edit");
326832
+ const mode = VALID_EDIT_MODES.has(editRaw) ? editRaw : "none";
326833
+ const enforced = parseBoolAttr(pickAttr(raw, "enforcement"));
326834
+ const formattingRestricted = parseBoolAttr(pickAttr(raw, "formatting"));
326835
+ const passwordProtected = hasPasswordMetadata(raw);
326836
+ return {
326837
+ mode,
326838
+ enforced,
326839
+ runtimeEnforced: enforced && mode === "readOnly",
326840
+ passwordProtected,
326841
+ formattingRestricted
326842
+ };
326843
+ }
326844
+ function projectWriteProtection(raw) {
326845
+ if (!raw) {
326846
+ return { ...DEFAULT_PROTECTION_STATE.writeProtection };
326847
+ }
326848
+ return {
326849
+ enabled: true,
326850
+ passwordProtected: hasPasswordMetadata(raw)
326851
+ };
326852
+ }
326853
+ function pickAttr(raw, localName2) {
326854
+ const wKey = `w:${localName2}`;
326855
+ if (Object.prototype.hasOwnProperty.call(raw, wKey))
326856
+ return raw[wKey];
326857
+ if (Object.prototype.hasOwnProperty.call(raw, localName2))
326858
+ return raw[localName2];
326859
+ return null;
326860
+ }
326861
+ function parseBoolAttr(value2) {
326862
+ if (value2 == null)
326863
+ return false;
326864
+ return value2 === "1" || value2 === "true" || value2 === "on";
326865
+ }
326866
+ function hasPasswordMetadata(raw) {
326867
+ for (const key2 of Object.keys(raw)) {
326868
+ if (PASSWORD_VERIFIER_ATTRS.has(key2)) {
326869
+ const value2 = raw[key2];
326870
+ if (value2 && value2.length > 0)
326871
+ return true;
326872
+ }
326873
+ }
326874
+ return false;
326875
+ }
326876
+ function setDocumentProtectionXml(settingsXml, input) {
326877
+ const xml = settingsXml ?? emptySettingsXml();
326878
+ const existing = matchElement(xml, "w:documentProtection");
326879
+ const attrs = existing ? readAttrs(existing) : {};
326880
+ attrs["w:edit"] = input.mode;
326881
+ attrs["w:enforcement"] = input.enforced ? "1" : "0";
326882
+ attrs["w:formatting"] = input.formattingRestricted ? "1" : "0";
326883
+ const element = buildDocumentProtectionElement(attrs);
326884
+ if (existing)
326885
+ return xml.replace(existing, element);
326886
+ return xml.replace(/<\/w:settings>\s*$/, `${element}</w:settings>`);
326887
+ }
326888
+ function clearDocumentProtectionXml(settingsXml) {
326889
+ const xml = settingsXml ?? emptySettingsXml();
326890
+ const existing = matchElement(xml, "w:documentProtection");
326891
+ const attrs = existing ? readAttrs(existing) : { "w:edit": "readOnly" };
326892
+ attrs["w:enforcement"] = "0";
326893
+ const element = buildDocumentProtectionElement(attrs);
326894
+ if (existing)
326895
+ return xml.replace(existing, element);
326896
+ return xml.replace(/<\/w:settings>\s*$/, `${element}</w:settings>`);
326897
+ }
326898
+ function buildDocumentProtectionElement(attrs) {
326899
+ const attrXml = Object.entries(attrs).map(([key2, value2]) => ` ${key2}="${xmlEscapeAttr(value2)}"`).join("");
326900
+ return `<w:documentProtection${attrXml}/>`;
326901
+ }
326902
+ function matchElement(xml, name) {
326903
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
326904
+ return new RegExp(`<${escaped}\\b[^>]*(?:/>|>[\\s\\S]*?</${escaped}>)`).exec(xml)?.[0] ?? null;
326905
+ }
326906
+ function emptySettingsXml() {
326907
+ return [
326908
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
326909
+ '<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"',
326910
+ ' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"',
326911
+ ' xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">',
326912
+ "</w:settings>"
326913
+ ].join("");
326914
+ }
326915
+ var PASSWORD_VERIFIER_ATTRS, VALID_EDIT_MODES;
326916
+ var init_adapter7 = __esm(() => {
326917
+ init_src3();
326918
+ init_shared();
326919
+ init_xml();
326920
+ PASSWORD_VERIFIER_ATTRS = new Set([
326921
+ "w:cryptProviderType",
326922
+ "w:cryptAlgorithmClass",
326923
+ "w:cryptAlgorithmType",
326924
+ "w:cryptAlgorithmSid",
326925
+ "w:cryptSpinCount",
326926
+ "w:hash",
326927
+ "w:salt",
326928
+ "w:algorithmName",
326929
+ "w:hashValue",
326930
+ "w:saltValue",
326931
+ "w:spinCount"
326932
+ ]);
326933
+ VALID_EDIT_MODES = new Set([
326934
+ "none",
326935
+ "readOnly",
326936
+ "comments",
326937
+ "trackedChanges",
326938
+ "forms"
326939
+ ]);
326940
+ });
326941
+
326942
+ // ../../../v2/document-api-v2-adapter/dist/protection/mutation-guard.js
326943
+ function documentProtectionAllowsXmlRange(context, partUri, start, end) {
326944
+ if (!new V2ProtectionAdapter(context).get().editingRestriction.runtimeEnforced)
326945
+ return true;
326946
+ if (partUri !== DOCUMENT_PART_URI5 || start < 0 || end < start)
326947
+ return false;
326948
+ return listPermissionRanges(context).some((range) => range.principal.kind === "everyone" && range.startTagEnd <= start && end <= range.endTagStart);
326949
+ }
326950
+ function requireDocumentProtectionXmlRange(context, partUri, start, end) {
326951
+ if (!documentProtectionAllowsXmlRange(context, partUri, start, end)) {
326952
+ throw operationError("PERMISSION_DENIED", DOCUMENT_PROTECTION_MESSAGE);
326953
+ }
326954
+ }
326955
+ function documentProtectionAllowsXmlRewrite(context, partUri, before, after) {
326956
+ if (!new V2ProtectionAdapter(context).get().editingRestriction.runtimeEnforced || before === after)
326957
+ return true;
326958
+ let start = 0;
326959
+ while (start < before.length && start < after.length && before[start] === after[start])
326960
+ start++;
326961
+ let end = before.length;
326962
+ let afterEnd = after.length;
326963
+ while (end > start && afterEnd > start && before[end - 1] === after[afterEnd - 1]) {
326964
+ end--;
326965
+ afterEnd--;
326966
+ }
326967
+ return documentProtectionAllowsXmlRange(context, partUri, start, end);
326968
+ }
326969
+ var DOCUMENT_PROTECTION_MESSAGE = "document protection permits edits only within an everyone permission range.";
326970
+ var init_mutation_guard = __esm(() => {
326971
+ init_shared();
326972
+ init_adapter6();
326973
+ init_xml();
326974
+ init_adapter7();
326975
+ });
326976
+
325879
326977
  // ../../../v2/editor-core/dist/review-read-model.js
325880
326978
  var init_review_read_model = __esm(() => {
325881
326979
  init_rewrite_groups();
@@ -326004,6 +327102,47 @@ function hasLocalTrackedTextEntries(context, logicalIds) {
326004
327102
  const cache = currentCache(context);
326005
327103
  return logicalIds.every((id) => cache.byLogicalId.has(id));
326006
327104
  }
327105
+ function tryProjectLocalTrackedParagraphRangeReceiptIds(context, refs, blockId) {
327106
+ const tracked = refs.filter((ref5) => ref5.kind === "trackedChange");
327107
+ const rsids = [...new Set(tracked.map((ref5) => ref5.entityId))];
327108
+ if (!rsids.length || rsids.length > 2)
327109
+ return null;
327110
+ const index2 = getSDDocumentSessionInternalParagraphIndex(context.session);
327111
+ const paragraph3 = index2?.byParaId(blockId);
327112
+ if (!index2 || !paragraph3 || paragraph3.directBodyChildOrdinal == null || index2.duplicateParaIds.has(blockId) || tracked.some((ref5) => ref5.storyId !== paragraph3.storyId))
327113
+ return null;
327114
+ const bytes = getSDDocumentSessionInternalPartBytes(context.session, paragraph3.partUri);
327115
+ if (!bytes)
327116
+ return null;
327117
+ const reservations = getSDDocumentSessionInternalRevisionWIdReservations(context.session);
327118
+ const authoredWordIds = new Set([...reservations.issued].filter((id) => !reservations.conflictedReserved.has(id) && !reservations.replayOwners.has(id)));
327119
+ for (const delta of [-1, 1]) {
327120
+ const adjacent = index2.entries[paragraph3.ordinal + delta];
327121
+ if (!adjacent || adjacent.partUri !== paragraph3.partUri || adjacent.storyId !== paragraph3.storyId || adjacent.directBodyChildOrdinal !== paragraph3.directBodyChildOrdinal + delta || index2.duplicateParaIds.has(adjacent.blockId))
327122
+ continue;
327123
+ const head = delta < 0 ? adjacent : paragraph3;
327124
+ const tail = delta < 0 ? paragraph3 : adjacent;
327125
+ const projection = buildBoundedTrackedParagraphRangeReceiptProjection({
327126
+ xml: TD88.decode(bytes.subarray(head.byteStart, tail.byteEnd)),
327127
+ partUri: paragraph3.partUri,
327128
+ storyId: paragraph3.storyId,
327129
+ rsids,
327130
+ authoredWordIds,
327131
+ replacementMode: resolveReplacementMode(context.trackedChangesReplacementMode),
327132
+ namespaceBindings: getSDDocumentSessionInternalMainStoryRootNamespaceBindings(context.session) ?? undefined
327133
+ });
327134
+ if (!projection)
327135
+ continue;
327136
+ const cache = currentCache(context);
327137
+ (cache.receiptGroups ?? (cache.receiptGroups = new Map)).set(projection.id, projection.childIds);
327138
+ return new Map(rsids.map((rsid) => [rsid, projection.id]));
327139
+ }
327140
+ return null;
327141
+ }
327142
+ function readLocalTrackedParagraphRangeReceiptGroups(context, ids) {
327143
+ const groups = currentCache(context).receiptGroups;
327144
+ return ids.length && groups && ids.every((id) => groups.has(id)) ? new Map(ids.map((id) => [id, groups.get(id)])) : null;
327145
+ }
326007
327146
  var cacheBySession, TD88;
326008
327147
  var init_local_text_projection = __esm(() => {
326009
327148
  init_sd_document_session_internal();
@@ -326765,428 +327904,6 @@ var init_raw_block_ref = __esm(() => {
326765
327904
  init_story_surface();
326766
327905
  });
326767
327906
 
326768
- // ../../../v2/document-api-v2-adapter/dist/permission-ranges/adapter.js
326769
- class V2PermissionRangesAdapter {
326770
- constructor(context) {
326771
- this.context = context;
326772
- }
326773
- list(input) {
326774
- const ranges = listPermissionRanges(this.context).map(stripInternal2);
326775
- const page = pageSlice(ranges, input);
326776
- return buildDiscoveryResult({
326777
- evaluatedRevision: this.context.currentPublicRevision(),
326778
- total: ranges.length,
326779
- items: page.items.map((range) => buildDiscoveryItem(range.id, buildResolvedHandle(`permissionRange:${range.id}`, "stable", "ext:permissionRange"), range)),
326780
- page: { offset: page.offset, limit: page.limit, returned: page.items.length }
326781
- });
326782
- }
326783
- get(input) {
326784
- const range = listPermissionRanges(this.context).find((entry) => entry.id === input.id);
326785
- if (!range)
326786
- throw operationError("TARGET_NOT_FOUND", `permission range ${input.id} not found.`);
326787
- return stripInternal2(range);
326788
- }
326789
- create(input, options) {
326790
- const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326791
- if (mutationGuard)
326792
- return mutationGuard;
326793
- const resolved = resolveBodySelectionTarget(this.context, input.target);
326794
- if ("error" in resolved)
326795
- throw operationError(resolved.error, resolved.message);
326796
- if (resolved.startBlockId !== resolved.endBlockId) {
326797
- throw operationError("INVALID_TARGET", "permissionRanges.create requires a same-paragraph text selection.");
326798
- }
326799
- const xml = this.readDocumentXml();
326800
- const id = input.id ?? allocateRangeId(listPermissionRanges(this.context));
326801
- const para = findParagraphById2(xml, resolved.startBlockId);
326802
- if (!para)
326803
- throw operationError("TARGET_NOT_FOUND", `paragraph ${resolved.startBlockId} not found.`);
326804
- if (dryRunRequested(input, options)) {
326805
- return {
326806
- success: true,
326807
- range: {
326808
- id,
326809
- principal: input.principal,
326810
- kind: "inline",
326811
- start: { blockId: resolved.startBlockId, offset: resolved.startOffset },
326812
- end: { blockId: resolved.endBlockId, offset: resolved.endOffset }
326813
- }
326814
- };
326815
- }
326816
- const wrapped = wrapTextRangeWithPermissionMarkers(para.xml, resolved.startOffset, resolved.endOffset, id, input.principal);
326817
- const nextXml = replaceRange2(xml, para.start, para.end, wrapped);
326818
- const committed = commitWholePartUpdates(this.context, "permission-range-create", { [DOCUMENT_PART_URI5]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326819
- if (!committed.ok)
326820
- return { success: false, failure: { code: committed.code, message: committed.message } };
326821
- return { success: true, range: this.get({ id }) };
326822
- }
326823
- remove(input, options) {
326824
- const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326825
- if (mutationGuard)
326826
- return mutationGuard;
326827
- const range = listPermissionRanges(this.context).find((entry) => entry.id === input.id);
326828
- if (!range)
326829
- throw operationError("TARGET_NOT_FOUND", `permission range ${input.id} not found.`);
326830
- if (dryRunRequested(input, options))
326831
- return { success: true, id: input.id };
326832
- let xml = this.readDocumentXml();
326833
- xml = removeMarkerAt(xml, range.endTagStart, range.endTagEnd);
326834
- xml = removeMarkerAt(xml, range.startTagStart, range.startTagEnd);
326835
- const committed = commitWholePartUpdates(this.context, "permission-range-remove", { [DOCUMENT_PART_URI5]: encodeXml(xml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326836
- if (!committed.ok)
326837
- return { success: false, failure: { code: committed.code, message: committed.message } };
326838
- return { success: true, id: input.id };
326839
- }
326840
- updatePrincipal(input, options) {
326841
- const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
326842
- if (mutationGuard)
326843
- return mutationGuard;
326844
- const range = listPermissionRanges(this.context).find((entry) => entry.id === input.id);
326845
- if (!range)
326846
- throw operationError("TARGET_NOT_FOUND", `permission range ${input.id} not found.`);
326847
- if (dryRunRequested(input, options))
326848
- return { success: true, range: stripInternal2(range) };
326849
- const xml = this.readDocumentXml();
326850
- const marker = xml.slice(range.startTagStart, range.startTagEnd);
326851
- const nextMarker = buildPermStart(input.id, input.principal);
326852
- const nextXml = xml.replace(marker, nextMarker);
326853
- const committed = commitWholePartUpdates(this.context, "permission-range-update", { [DOCUMENT_PART_URI5]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
326854
- if (!committed.ok)
326855
- return { success: false, failure: { code: committed.code, message: committed.message } };
326856
- return { success: true, range: this.get({ id: input.id }) };
326857
- }
326858
- readDocumentXml() {
326859
- const xml = readPartXml(this.context, DOCUMENT_PART_URI5);
326860
- if (!xml)
326861
- throw operationError("PRECONDITION_FAILED", "document.xml bytes are unavailable.");
326862
- return xml;
326863
- }
326864
- }
326865
- function listPermissionRanges(context) {
326866
- const xml = readPartXml(context, DOCUMENT_PART_URI5);
326867
- if (!xml)
326868
- return [];
326869
- const starts = new Map;
326870
- const startRe = /<w:permStart\b[^>]*\/>/g;
326871
- for (let match = startRe.exec(xml);match; match = startRe.exec(xml)) {
326872
- const id = attrValue(match[0], "id");
326873
- if (id)
326874
- starts.set(id, { start: match.index, end: startRe.lastIndex, tag: match[0] });
326875
- }
326876
- const out = [];
326877
- const endRe = /<w:permEnd\b[^>]*\/>/g;
326878
- for (let match = endRe.exec(xml);match; match = endRe.exec(xml)) {
326879
- const id = attrValue(match[0], "id");
326880
- if (!id)
326881
- continue;
326882
- const start = starts.get(id);
326883
- if (!start)
326884
- continue;
326885
- const startPos = positionForXmlIndex(xml, start.start);
326886
- const endPos = positionForXmlIndex(xml, match.index);
326887
- out.push({
326888
- id,
326889
- principal: principalFromPermStart(start.tag),
326890
- kind: startPos.blockId === endPos.blockId ? "inline" : "block",
326891
- start: startPos,
326892
- end: endPos,
326893
- startTagStart: start.start,
326894
- startTagEnd: start.end,
326895
- endTagStart: match.index,
326896
- endTagEnd: endRe.lastIndex
326897
- });
326898
- }
326899
- return out.sort((a, b) => a.startTagStart - b.startTagStart);
326900
- }
326901
- function stripInternal2(range) {
326902
- return {
326903
- id: range.id,
326904
- principal: range.principal,
326905
- kind: range.kind,
326906
- start: range.start,
326907
- end: range.end
326908
- };
326909
- }
326910
- function principalFromPermStart(tag) {
326911
- const attrs = readAttrs(tag);
326912
- const group = attrs["w:edGrp"] ?? attrs.edGrp;
326913
- if (group === "everyone")
326914
- return { kind: "everyone" };
326915
- const editor = attrs["w:ed"] ?? attrs.ed;
326916
- return { kind: "editor", id: editor ?? group ?? "unknown" };
326917
- }
326918
- function buildPermStart(id, principal) {
326919
- const principalAttr = principal.kind === "everyone" ? ' w:edGrp="everyone"' : ` w:ed="${xmlEscapeAttr(principal.id)}"`;
326920
- return `<w:permStart w:id="${xmlEscapeAttr(id)}"${principalAttr}/>`;
326921
- }
326922
- function buildPermEnd(id) {
326923
- return `<w:permEnd w:id="${xmlEscapeAttr(id)}"/>`;
326924
- }
326925
- function wrapTextRangeWithPermissionMarkers(paragraphXml, start, end, id, principal) {
326926
- return replaceTextRangeInParagraph(paragraphXml, start, end, (selected) => [
326927
- `<w:r>${buildPermStart(id, principal)}</w:r>`,
326928
- `<w:r><w:t>${xmlEscapeText(selected)}</w:t></w:r>`,
326929
- `<w:r>${buildPermEnd(id)}</w:r>`
326930
- ].join(""));
326931
- }
326932
- function positionForXmlIndex(documentXml, index2) {
326933
- const para = findParagraphContaining2(documentXml, index2);
326934
- if (!para)
326935
- return { blockId: "unknown", offset: 0 };
326936
- return { blockId: attrValue(para.openTag, "paraId") ?? "unknown", offset: extractText2(para.xml.slice(0, index2 - para.start)).length };
326937
- }
326938
- function findParagraphContaining2(documentXml, index2) {
326939
- const paraRe = /<w:p\b[^>]*>[\s\S]*?<\/w:p>/g;
326940
- for (let match = paraRe.exec(documentXml);match; match = paraRe.exec(documentXml)) {
326941
- if (match.index <= index2 && paraRe.lastIndex >= index2) {
326942
- return { start: match.index, end: paraRe.lastIndex, xml: match[0], openTag: /^<w:p\b[^>]*>/.exec(match[0])?.[0] ?? "" };
326943
- }
326944
- }
326945
- return null;
326946
- }
326947
- function findParagraphById2(documentXml, blockId) {
326948
- const paraRe = /<w:p\b[^>]*>[\s\S]*?<\/w:p>/g;
326949
- for (let match = paraRe.exec(documentXml);match; match = paraRe.exec(documentXml)) {
326950
- if (match[0].includes(`w14:paraId="${blockId}"`))
326951
- return { start: match.index, end: paraRe.lastIndex, xml: match[0] };
326952
- }
326953
- return null;
326954
- }
326955
- function replaceTextRangeInParagraph(paragraphXml, start, end, replacement) {
326956
- const textRe = /<w:t\b[^>]*>([\s\S]*?)<\/w:t>/g;
326957
- let offset = 0;
326958
- for (let match = textRe.exec(paragraphXml);match; match = textRe.exec(paragraphXml)) {
326959
- const text4 = decodeXmlEntities(match[1]);
326960
- const nextOffset = offset + text4.length;
326961
- if (start >= offset && end <= nextOffset) {
326962
- const localStart = start - offset;
326963
- const localEnd = end - offset;
326964
- const before = text4.slice(0, localStart);
326965
- const selected = text4.slice(localStart, localEnd);
326966
- const after = text4.slice(localEnd);
326967
- const runStart = findEnclosingRunStart(paragraphXml, match.index);
326968
- const runEnd = paragraphXml.indexOf("</w:r>", textRe.lastIndex) + "</w:r>".length;
326969
- const { runOpenTag, runProperties } = readRunOpenTagAndProperties(paragraphXml, runStart);
326970
- const mkRun = (segment) => `${runOpenTag}${runProperties}<w:t xml:space="preserve">${xmlEscapeText(segment)}</w:t></w:r>`;
326971
- return [
326972
- paragraphXml.slice(0, runStart),
326973
- before ? mkRun(before) : "",
326974
- replacement(selected),
326975
- after ? mkRun(after) : "",
326976
- paragraphXml.slice(runEnd)
326977
- ].join("");
326978
- }
326979
- offset = nextOffset;
326980
- }
326981
- throw operationError("TARGET_NOT_FOUND", "text range not found in paragraph.");
326982
- }
326983
- function removeMarkerAt(xml, start, end) {
326984
- const runStart = findEnclosingRunStart(xml, start);
326985
- const runEnd = xml.indexOf("</w:r>", end);
326986
- if (runStart >= 0 && runEnd >= end)
326987
- return replaceRange2(xml, runStart, runEnd + "</w:r>".length, "");
326988
- return replaceRange2(xml, start, end, "");
326989
- }
326990
- function replaceRange2(xml, start, end, replacement) {
326991
- return `${xml.slice(0, start)}${replacement}${xml.slice(end)}`;
326992
- }
326993
- function extractText2(xml) {
326994
- let out = "";
326995
- const re = /<w:t\b[^>]*>([\s\S]*?)<\/w:t>/g;
326996
- for (let match = re.exec(xml);match; match = re.exec(xml))
326997
- out += decodeXmlEntities(match[1]);
326998
- return out;
326999
- }
327000
- function allocateRangeId(existing) {
327001
- const max2 = existing.reduce((acc, range) => Math.max(acc, Number(range.id) || 0), 1000);
327002
- return String(max2 + 1 + Math.floor(Math.random() * 1000));
327003
- }
327004
- var init_adapter6 = __esm(() => {
327005
- init_src3();
327006
- init_shared();
327007
- init_xml();
327008
- });
327009
-
327010
- // ../../../v2/document-api-v2-adapter/dist/protection/adapter.js
327011
- class V2ProtectionAdapter {
327012
- constructor(context) {
327013
- this.context = context;
327014
- }
327015
- get(_input) {
327016
- return projectProtectionStateFromSettings(readPartXml(this.context, SETTINGS_PART_URI3));
327017
- }
327018
- setEditingRestriction(input, options) {
327019
- const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
327020
- if (mutationGuard)
327021
- return mutationGuard;
327022
- const currentXml3 = readPartXml(this.context, SETTINGS_PART_URI3);
327023
- const nextXml = setDocumentProtectionXml(currentXml3, {
327024
- mode: input.mode,
327025
- enforced: true,
327026
- formattingRestricted: Boolean(input.formattingRestricted)
327027
- });
327028
- if (dryRunRequested(input, options)) {
327029
- return { success: true, state: projectProtectionStateFromSettings(nextXml) };
327030
- }
327031
- if (nextXml === currentXml3) {
327032
- const expectedRevision = expectedRevisionFrom(input, options);
327033
- const failure5 = this.context.validateMutation({ expectedRevision: expectedRevision === undefined ? undefined : String(expectedRevision) });
327034
- if (failure5)
327035
- return { success: false, failure: failure5 };
327036
- return { success: true, state: projectProtectionStateFromSettings(nextXml), changed: false };
327037
- }
327038
- const committed = commitWholePartUpdates(this.context, "protection-set", { [SETTINGS_PART_URI3]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
327039
- if (!committed.ok)
327040
- return { success: false, failure: { code: committed.code, message: committed.message } };
327041
- return { success: true, state: projectProtectionStateFromSettings(nextXml) };
327042
- }
327043
- clearEditingRestriction(input, options) {
327044
- const mutationGuard = guardDirectOnlyMutation(this.context, input, options);
327045
- if (mutationGuard)
327046
- return mutationGuard;
327047
- const currentXml3 = readPartXml(this.context, SETTINGS_PART_URI3);
327048
- const nextXml = clearDocumentProtectionXml(currentXml3);
327049
- if (dryRunRequested(input ?? {}, options)) {
327050
- return { success: true, state: projectProtectionStateFromSettings(nextXml) };
327051
- }
327052
- if (nextXml === currentXml3) {
327053
- const expectedRevision = expectedRevisionFrom(input, options);
327054
- const failure5 = this.context.validateMutation({ expectedRevision: expectedRevision === undefined ? undefined : String(expectedRevision) });
327055
- if (failure5)
327056
- return { success: false, failure: failure5 };
327057
- return { success: true, state: projectProtectionStateFromSettings(nextXml), changed: false };
327058
- }
327059
- const committed = commitWholePartUpdates(this.context, "protection-clear", { [SETTINGS_PART_URI3]: encodeXml(nextXml) }, { expectedRevision: expectedRevisionFrom(input, options) });
327060
- if (!committed.ok)
327061
- return { success: false, failure: { code: committed.code, message: committed.message } };
327062
- return { success: true, state: projectProtectionStateFromSettings(nextXml) };
327063
- }
327064
- }
327065
- function projectProtectionStateFromSettings(settingsXml) {
327066
- const documentProtection = settingsXml ? matchElement(settingsXml, "w:documentProtection") : null;
327067
- const writeProtection = settingsXml ? matchElement(settingsXml, "w:writeProtection") : null;
327068
- const readOnlyRecommended = settingsXml ? /<w:readOnlyRecommended\b/.test(settingsXml) : false;
327069
- return {
327070
- editingRestriction: projectEditingRestriction(documentProtection ? readAttrs(documentProtection) : null),
327071
- writeProtection: projectWriteProtection(writeProtection ? readAttrs(writeProtection) : null),
327072
- readOnlyRecommended
327073
- };
327074
- }
327075
- function projectEditingRestriction(raw) {
327076
- if (!raw) {
327077
- return { ...DEFAULT_PROTECTION_STATE.editingRestriction };
327078
- }
327079
- const editRaw = pickAttr(raw, "edit");
327080
- const mode = VALID_EDIT_MODES.has(editRaw) ? editRaw : "none";
327081
- const enforced = parseBoolAttr(pickAttr(raw, "enforcement"));
327082
- const formattingRestricted = parseBoolAttr(pickAttr(raw, "formatting"));
327083
- const passwordProtected = hasPasswordMetadata(raw);
327084
- return {
327085
- mode,
327086
- enforced,
327087
- runtimeEnforced: enforced && mode === "readOnly",
327088
- passwordProtected,
327089
- formattingRestricted
327090
- };
327091
- }
327092
- function projectWriteProtection(raw) {
327093
- if (!raw) {
327094
- return { ...DEFAULT_PROTECTION_STATE.writeProtection };
327095
- }
327096
- return {
327097
- enabled: true,
327098
- passwordProtected: hasPasswordMetadata(raw)
327099
- };
327100
- }
327101
- function pickAttr(raw, localName2) {
327102
- const wKey = `w:${localName2}`;
327103
- if (Object.prototype.hasOwnProperty.call(raw, wKey))
327104
- return raw[wKey];
327105
- if (Object.prototype.hasOwnProperty.call(raw, localName2))
327106
- return raw[localName2];
327107
- return null;
327108
- }
327109
- function parseBoolAttr(value2) {
327110
- if (value2 == null)
327111
- return false;
327112
- return value2 === "1" || value2 === "true" || value2 === "on";
327113
- }
327114
- function hasPasswordMetadata(raw) {
327115
- for (const key2 of Object.keys(raw)) {
327116
- if (PASSWORD_VERIFIER_ATTRS.has(key2)) {
327117
- const value2 = raw[key2];
327118
- if (value2 && value2.length > 0)
327119
- return true;
327120
- }
327121
- }
327122
- return false;
327123
- }
327124
- function setDocumentProtectionXml(settingsXml, input) {
327125
- const xml = settingsXml ?? emptySettingsXml();
327126
- const existing = matchElement(xml, "w:documentProtection");
327127
- const attrs = existing ? readAttrs(existing) : {};
327128
- attrs["w:edit"] = input.mode;
327129
- attrs["w:enforcement"] = input.enforced ? "1" : "0";
327130
- attrs["w:formatting"] = input.formattingRestricted ? "1" : "0";
327131
- const element = buildDocumentProtectionElement(attrs);
327132
- if (existing)
327133
- return xml.replace(existing, element);
327134
- return xml.replace(/<\/w:settings>\s*$/, `${element}</w:settings>`);
327135
- }
327136
- function clearDocumentProtectionXml(settingsXml) {
327137
- const xml = settingsXml ?? emptySettingsXml();
327138
- const existing = matchElement(xml, "w:documentProtection");
327139
- const attrs = existing ? readAttrs(existing) : { "w:edit": "readOnly" };
327140
- attrs["w:enforcement"] = "0";
327141
- const element = buildDocumentProtectionElement(attrs);
327142
- if (existing)
327143
- return xml.replace(existing, element);
327144
- return xml.replace(/<\/w:settings>\s*$/, `${element}</w:settings>`);
327145
- }
327146
- function buildDocumentProtectionElement(attrs) {
327147
- const attrXml = Object.entries(attrs).map(([key2, value2]) => ` ${key2}="${xmlEscapeAttr(value2)}"`).join("");
327148
- return `<w:documentProtection${attrXml}/>`;
327149
- }
327150
- function matchElement(xml, name) {
327151
- const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
327152
- return new RegExp(`<${escaped}\\b[^>]*(?:/>|>[\\s\\S]*?</${escaped}>)`).exec(xml)?.[0] ?? null;
327153
- }
327154
- function emptySettingsXml() {
327155
- return [
327156
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
327157
- '<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"',
327158
- ' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"',
327159
- ' xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">',
327160
- "</w:settings>"
327161
- ].join("");
327162
- }
327163
- var PASSWORD_VERIFIER_ATTRS, VALID_EDIT_MODES;
327164
- var init_adapter7 = __esm(() => {
327165
- init_src3();
327166
- init_shared();
327167
- init_xml();
327168
- PASSWORD_VERIFIER_ATTRS = new Set([
327169
- "w:cryptProviderType",
327170
- "w:cryptAlgorithmClass",
327171
- "w:cryptAlgorithmType",
327172
- "w:cryptAlgorithmSid",
327173
- "w:cryptSpinCount",
327174
- "w:hash",
327175
- "w:salt",
327176
- "w:algorithmName",
327177
- "w:hashValue",
327178
- "w:saltValue",
327179
- "w:spinCount"
327180
- ]);
327181
- VALID_EDIT_MODES = new Set([
327182
- "none",
327183
- "readOnly",
327184
- "comments",
327185
- "trackedChanges",
327186
- "forms"
327187
- ]);
327188
- });
327189
-
327190
327907
  // ../../../v2/document-api-v2-adapter/dist/selection-mutation/replacement-span.js
327191
327908
  function uniqueTokenAnchors(before, after) {
327192
327909
  const uniquePositions = (tokens) => {
@@ -329920,12 +330637,14 @@ class V2SelectionMutationAdapter {
329920
330637
  recordCommittedTxIdForHistory(this.context, receipt3.txId);
329921
330638
  const textRangeShifts = projectTextRangeShifts(receipt3.textRangeShifts ?? [], this.context.session, effectiveStory);
329922
330639
  const affectedStories = projectAffectedStories(receipt3.storiesChanged ?? [], this.context.session, receipt3.partsChanged, effectiveStory);
330640
+ const inserted = projectTrackedTextEntities(this.context, receipt3.createdRefs ?? [], resolved.startBlockId);
329923
330641
  return {
329924
330642
  success: true,
329925
330643
  affectedStories,
329926
330644
  textRangeShifts,
329927
330645
  txId: receipt3.txId,
329928
- resolution
330646
+ resolution,
330647
+ ...inserted ? { inserted } : {}
329929
330648
  };
329930
330649
  }
329931
330650
  executeFormat(request, options, offsetSpace) {
@@ -330832,6 +331551,10 @@ function projectTrackedTextEntities(context, refs, localBlockId, refinement, pri
330832
331551
  return [...new Set(logicalIds)].map((entityId) => ({ kind: "entity", entityType: "trackedChange", entityId }));
330833
331552
  }
330834
331553
  }
331554
+ const groupIds = localBlockId ? tryProjectLocalTrackedParagraphRangeReceiptIds(context, refs, localBlockId) : null;
331555
+ if (groupIds && revisionIds.every((id) => groupIds.has(id))) {
331556
+ return [...new Set(revisionIds.map((id) => groupIds.get(id)))].map((entityId) => ({ kind: "entity", entityType: "trackedChange", entityId }));
331557
+ }
330835
331558
  if (diagnostics)
330836
331559
  diagnostics.globalCatalogFallbacks += 1;
330837
331560
  const { logical } = buildCachedTrackedChangeLogicalView(context);
@@ -330860,6 +331583,14 @@ function projectTrackedTextReviewGroupRemappings(context, inserted) {
330860
331583
  return;
330861
331584
  if (hasLocalTrackedTextEntries(context, inserted.map((entity) => entity.entityId)))
330862
331585
  return;
331586
+ const localGroups = readLocalTrackedParagraphRangeReceiptGroups(context, inserted.map((entity) => entity.entityId));
331587
+ if (localGroups) {
331588
+ const remapped2 = [...localGroups].flatMap(([parentId, childIds]) => childIds.filter((childId) => childId !== parentId).map((childId) => ({
331589
+ from: { kind: "entity", entityType: "trackedChange", entityId: childId },
331590
+ to: { kind: "entity", entityType: "trackedChange", entityId: parentId }
331591
+ })));
331592
+ return remapped2.length ? remapped2 : undefined;
331593
+ }
330863
331594
  const { logical } = buildCachedTrackedChangeLogicalView(context);
330864
331595
  const remapped = [];
330865
331596
  const seen = new Set;
@@ -333529,6 +334260,7 @@ class V2ContentControlsAdapter {
333529
334260
  }
333530
334261
  }
333531
334262
  create(input, options) {
334263
+ requireAuthorableControlType(input.controlType);
333532
334264
  const freshness = this.context.getReadFreshnessFailure("create.contentControl");
333533
334265
  if (freshness)
333534
334266
  return { success: false, failure: freshness };
@@ -333541,6 +334273,22 @@ class V2ContentControlsAdapter {
333541
334273
  throw error48;
333542
334274
  return { success: false, failure: { code: error48.code, message: error48.message } };
333543
334275
  }
334276
+ if (input.at) {
334277
+ const blocks = resolveWholeBlockSelection(part.xml, part.paragraphs, input.at);
334278
+ if (blocks.kind === "ok") {
334279
+ requireDocumentProtectionXmlRange(this.context, part.partUri, blocks.start, blocks.end);
334280
+ } else if (input.at.start.kind === "text" && input.at.end.kind === "text") {
334281
+ const startBlockId = input.at.start.blockId;
334282
+ const endBlockId = input.at.end.blockId;
334283
+ const first = part.paragraphs.find((p) => p.blockId === startBlockId);
334284
+ const last = part.paragraphs.find((p) => p.blockId === endBlockId);
334285
+ requireDocumentProtectionXmlRange(this.context, part.partUri, first?.start ?? -1, last?.end ?? -1);
334286
+ } else {
334287
+ requireDocumentProtectionXmlRange(this.context, part.partUri, -1, -1);
334288
+ }
334289
+ } else {
334290
+ requireDocumentProtectionXmlRange(this.context, part.partUri, -1, -1);
334291
+ }
333544
334292
  const trackedSecondaryStory = part.story && options?.changeMode === "tracked";
333545
334293
  if (trackedSecondaryStory && !supportsTrackedSecondaryStoryCreate(input)) {
333546
334294
  return { success: false, failure: { code: "CAPABILITY_UNAVAILABLE", message: "Tracked header/footer content-control creation requires an inline text control with plain-text content at a collapsed visible-text selection." } };
@@ -334142,6 +334890,7 @@ class V2ContentControlsAdapter {
334142
334890
  return this.mutatePr(input, options, (pr) => setLockMode(pr, input.lockMode));
334143
334891
  }
334144
334892
  setType(input, options) {
334893
+ requireAuthorableControlType(input.controlType);
334145
334894
  return this.mutatePr(input, options, (pr) => setControlType(pr, input.controlType));
334146
334895
  }
334147
334896
  getContent(input) {
@@ -334153,6 +334902,7 @@ class V2ContentControlsAdapter {
334153
334902
  return { success: false, failure: freshness };
334154
334903
  const loaded = this.load();
334155
334904
  const control2 = options?.changeMode === "tracked" ? this.requireBodyControl(input.target, loaded) : this.requireControl(input.target, loaded);
334905
+ this.requireProtectedControl(control2, loaded);
334156
334906
  guardContentUnlocked(control2);
334157
334907
  const part = loaded.parts.find((candidate2) => candidate2.storyId === control2.storyId);
334158
334908
  if (controlPlacement(part.xml, control2) !== control2.info.kind) {
@@ -334304,6 +335054,7 @@ class V2ContentControlsAdapter {
334304
335054
  if (control2.info.controlType !== "text") {
334305
335055
  throw operationError("TYPE_MISMATCH", `contentControls.text.setValue requires control type text, but found "${control2.info.controlType}".`);
334306
335056
  }
335057
+ this.requireProtectedControl(control2, loaded);
334307
335058
  guardContentUnlocked(control2);
334308
335059
  const value2 = input.value ?? "";
334309
335060
  if (value2 === (control2.info.text ?? "")) {
@@ -334335,6 +335086,7 @@ class V2ContentControlsAdapter {
334335
335086
  if (control2.info.controlType !== "date") {
334336
335087
  throw operationError("TYPE_MISMATCH", `contentControls.date.setValue requires control type date, but found "${control2.info.controlType}".`);
334337
335088
  }
335089
+ this.requireProtectedControl(control2, loaded);
334338
335090
  guardSdtWrapperUnlocked(control2);
334339
335091
  if (dryRunRequested(input, options))
334340
335092
  return { success: true, contentControl: control2.target };
@@ -334552,6 +335304,7 @@ class V2ContentControlsAdapter {
334552
335304
  const storyAware = prefix === "content-control-pr" || prefix === "content-control-unwrap";
334553
335305
  const control2 = tracked || !storyAware ? this.requireBodyControl(target, loaded) : this.requireControl(target, loaded);
334554
335306
  const part = loaded.parts.find((candidate2) => candidate2.storyId === control2.storyId);
335307
+ this.requireProtectedControl(control2, loaded);
334555
335308
  validate?.(control2, loaded);
334556
335309
  if (tracked) {
334557
335310
  this.validateTrackedControlMutation(input, options);
@@ -334717,6 +335470,10 @@ class V2ContentControlsAdapter {
334717
335470
  guardContentUnlocked(control2);
334718
335471
  });
334719
335472
  }
335473
+ requireProtectedControl(control2, loaded) {
335474
+ const part = loaded.parts.find((candidate2) => candidate2.storyId === control2.storyId);
335475
+ requireDocumentProtectionXmlRange(this.context, part.partUri, control2.start, control2.end);
335476
+ }
334720
335477
  requireControl(target, loaded = this.load()) {
334721
335478
  const story = this.context.resolveFullStoryLocator(target.story);
334722
335479
  if ("error" in story) {
@@ -334834,6 +335591,9 @@ class V2ContentControlsAdapter {
334834
335591
  }
334835
335592
  }
334836
335593
  commitTrackedMoveDocument(input) {
335594
+ if (!documentProtectionAllowsXmlRewrite(this.context, DOCUMENT_PART_URI5, readPartXml(this.context, DOCUMENT_PART_URI5) ?? "", input.nextXml)) {
335595
+ return { success: false, failure: { code: "PERMISSION_DENIED", message: DOCUMENT_PROTECTION_MESSAGE } };
335596
+ }
334837
335597
  const expectedRevision = expectedRevisionFrom(input.input, input.options);
334838
335598
  if (expectedRevision !== undefined) {
334839
335599
  const begun = this.context.beginMutation({ expectedRevision: String(expectedRevision) });
@@ -334868,6 +335628,10 @@ class V2ContentControlsAdapter {
334868
335628
  const current = readPartBytes2(this.context, partUri);
334869
335629
  if (!current)
334870
335630
  return { success: false, failure: { code: "PRECONDITION_FAILED", message: "document.xml bytes are unavailable." } };
335631
+ const before = readPartXml(this.context, partUri) ?? "";
335632
+ if (!documentProtectionAllowsXmlRewrite(this.context, partUri, before, nextXml)) {
335633
+ return { success: false, failure: { code: "PERMISSION_DENIED", message: DOCUMENT_PROTECTION_MESSAGE } };
335634
+ }
334871
335635
  if (commitOptions.storySurface?.contentControlRewrite && this.context.isCollaborativeSession()) {
334872
335636
  const existingIds = new Set(this.load().parts.flatMap((part) => Array.from(part.xml.matchAll(/\bw14:paraId="([^"]+)"/g), (match) => match[1])));
334873
335637
  const newIds = [...new Set(Array.from(nextXml.matchAll(/\bw14:paraId="([^"]+)"/g), (match) => match[1]))].filter((id) => !existingIds.has(id));
@@ -335111,26 +335875,33 @@ function inferKind(sdtXml, contentXml) {
335111
335875
  return /<w:r\b/.test(before) ? "inline" : "block";
335112
335876
  }
335113
335877
  function inferControlType(prXml) {
335114
- if (/<w14:checkbox\b/.test(prXml))
335878
+ if (findDirectRawProperty(prXml, "w14:checkbox"))
335115
335879
  return "checkbox";
335116
- if (/<w:comboBox\b/.test(prXml))
335880
+ if (findDirectRawProperty(prXml, "w:comboBox"))
335117
335881
  return "comboBox";
335118
- if (/<w:dropDownList\b/.test(prXml))
335882
+ if (findDirectRawProperty(prXml, "w:dropDownList"))
335119
335883
  return "dropDownList";
335120
- if (/<w:date\b/.test(prXml))
335884
+ if (findDirectRawProperty(prXml, "w:date"))
335121
335885
  return "date";
335122
- if (/<w15:repeatingSectionItem\b/.test(prXml))
335886
+ if (findDirectRawProperty(prXml, "w15:repeatingSectionItem"))
335123
335887
  return "repeatingSectionItem";
335124
- if (/<w15:repeatingSection\b/.test(prXml))
335888
+ if (findDirectRawProperty(prXml, "w15:repeatingSection"))
335125
335889
  return "repeatingSection";
335126
- if (/<w:group\b/.test(prXml))
335890
+ if (findDirectRawProperty(prXml, "w:group"))
335127
335891
  return "group";
335128
- if (/<w:text\b/.test(prXml))
335892
+ if (findDirectRawProperty(prXml, "w:text"))
335129
335893
  return "text";
335130
- if (/<w:richText\b/.test(prXml))
335894
+ if (findDirectRawProperty(prXml, "w:richText"))
335131
335895
  return "richText";
335896
+ if (UNMODELED_TYPE_TAGS.some((name) => findDirectRawProperty(prXml, name)))
335897
+ return "unknown";
335132
335898
  return "richText";
335133
335899
  }
335900
+ function requireAuthorableControlType(type) {
335901
+ if (type === "unknown") {
335902
+ throw operationError("INVALID_INPUT", "unknown is a read classification, not an authorable content-control type.");
335903
+ }
335904
+ }
335134
335905
  function readProperties2(prXml, controlType) {
335135
335906
  const properties = {};
335136
335907
  const alias = matchElement2(prXml, "w:alias");
@@ -335166,7 +335937,8 @@ function readProperties2(prXml, controlType) {
335166
335937
  return properties;
335167
335938
  }
335168
335939
  function readDateProperties(prXml) {
335169
- const date6 = matchElement2(prXml, "w:date") ?? "";
335940
+ const current = findDirectRawProperty(prXml, "w:date");
335941
+ const date6 = current ? prXml.slice(current.start, current.end) : "";
335170
335942
  return {
335171
335943
  ...attrValue(date6, "fullDate") ? { dateFormat: undefined, fullDate: attrValue(date6, "fullDate") } : {},
335172
335944
  ...attrValue(matchElement2(date6, "w:dateFormat") ?? "", "val") ? { dateFormat: attrValue(matchElement2(date6, "w:dateFormat") ?? "", "val") } : {},
@@ -336358,15 +337130,21 @@ function setLockMode(prXml, lockMode) {
336358
337130
  }
336359
337131
  function setControlType(prXml, type) {
336360
337132
  let next = prXml;
336361
- for (const name of TYPE_TAGS)
336362
- next = removeElement(next, name);
337133
+ for (const name of TYPE_TAGS) {
337134
+ let current = findDirectRawProperty(next, name);
337135
+ while (current) {
337136
+ next = next.slice(0, current.start) + next.slice(current.end);
337137
+ current = findDirectRawProperty(next, name);
337138
+ }
337139
+ }
336363
337140
  if (type === "repeatingSectionItem")
336364
337141
  next = setAttr(next, "xmlns:w15", "http://schemas.microsoft.com/office/word/2012/wordml");
336365
337142
  return next.replace(/<\/w:sdtPr>$/, `${typeElement(type)}</w:sdtPr>`);
336366
337143
  }
336367
337144
  function updateDateElement(prXml, input) {
336368
337145
  const next = setControlType(prXml, "date");
336369
- let date6 = matchElement2(next, "w:date") ?? "<w:date/>";
337146
+ const current = findDirectRawProperty(next, "w:date");
337147
+ let date6 = next.slice(current.start, current.end);
336370
337148
  if (date6.endsWith("/>"))
336371
337149
  date6 = date6.replace(/\/>$/, "></w:date>");
336372
337150
  if ("fullDate" in input) {
@@ -336383,14 +337161,15 @@ function updateDateElement(prXml, input) {
336383
337161
  date6 = upsertChildElement(date6, childName, { "w:val": input[key2] ?? "" });
336384
337162
  }
336385
337163
  }
336386
- return next.replace(matchElement2(next, "w:date") ?? "<w:date/>", date6);
337164
+ return next.slice(0, current.start) + date6 + next.slice(current.end);
336387
337165
  }
336388
337166
  function updateExistingDateFullDate(prXml, fullDate) {
336389
- const existing = matchElement2(prXml, "w:date");
336390
- if (!existing)
337167
+ const current = findDirectRawProperty(prXml, "w:date");
337168
+ if (!current)
336391
337169
  return prXml;
337170
+ const existing = prXml.slice(current.start, current.end);
336392
337171
  const updated = fullDate === null ? existing.replace(/\s+w:fullDate="[^"]*"/, "") : setAttr(existing, "w:fullDate", fullDate);
336393
- return prXml.replace(existing, updated);
337172
+ return prXml.slice(0, current.start) + updated + prXml.slice(current.end);
336394
337173
  }
336395
337174
  function upsertCheckbox(prXml, input) {
336396
337175
  const props = readCheckboxProperties(prXml);
@@ -336929,7 +337708,7 @@ function replaceTextRangeInParagraph2(paragraphXml, start, end, replacement) {
336929
337708
  }
336930
337709
  return paragraphXml;
336931
337710
  }
336932
- var DEFAULT_CHECKED, DEFAULT_UNCHECKED, SECONDARY_STORY_MUTATION_MESSAGE = "Content control mutations outside the document body are not supported by this adapter.", TYPE_TAGS, COOPERATIVE_PARSE_SLICE_PARAGRAPHS = 128, COOPERATIVE_PARSE_SLICE_CONTROLS = 16, RAW_ATTRIBUTE_PATTERN, COPIED_PROPERTY_REVISIONS;
337711
+ var DEFAULT_CHECKED, DEFAULT_UNCHECKED, SECONDARY_STORY_MUTATION_MESSAGE = "Content control mutations outside the document body are not supported by this adapter.", UNMODELED_TYPE_TAGS, TYPE_TAGS, COOPERATIVE_PARSE_SLICE_PARAGRAPHS = 128, COOPERATIVE_PARSE_SLICE_CONTROLS = 16, RAW_ATTRIBUTE_PATTERN, COPIED_PROPERTY_REVISIONS;
336933
337712
  var init_adapter10 = __esm(() => {
336934
337713
  init_sd_document_session_internal();
336935
337714
  init_src6();
@@ -336942,6 +337721,7 @@ var init_adapter10 = __esm(() => {
336942
337721
  init_tracked_pr_change();
336943
337722
  init_inline();
336944
337723
  init_tracked_structural_wrapper();
337724
+ init_mutation_guard();
336945
337725
  init_adapter9();
336946
337726
  init_rich_fragment_apply();
336947
337727
  init_receipt_entities();
@@ -336954,6 +337734,14 @@ var init_adapter10 = __esm(() => {
336954
337734
  init_tracked_move();
336955
337735
  DEFAULT_CHECKED = { font: "MS Gothic", char: "2612" };
336956
337736
  DEFAULT_UNCHECKED = { font: "MS Gothic", char: "2610" };
337737
+ UNMODELED_TYPE_TAGS = [
337738
+ "w:picture",
337739
+ "w:equation",
337740
+ "w:citation",
337741
+ "w:bibliography",
337742
+ "w:docPartList",
337743
+ "w:docPartObj"
337744
+ ];
336957
337745
  TYPE_TAGS = [
336958
337746
  "w:text",
336959
337747
  "w:richText",
@@ -336963,7 +337751,8 @@ var init_adapter10 = __esm(() => {
336963
337751
  "w:group",
336964
337752
  "w14:checkbox",
336965
337753
  "w15:repeatingSection",
336966
- "w15:repeatingSectionItem"
337754
+ "w15:repeatingSectionItem",
337755
+ ...UNMODELED_TYPE_TAGS
336967
337756
  ];
336968
337757
  RAW_ATTRIBUTE_PATTERN = /(?:^|[ \t\r\n]+)([\w.-]+:[\w.-]+|[\w.-]+)[ \t\r\n]*=[ \t\r\n]*(["'])([\s\S]*?)\2/g;
336969
337758
  COPIED_PROPERTY_REVISIONS = new Set([
@@ -353990,6 +354779,30 @@ class V2ImagesAdapter {
353990
354779
  const blocked = guardCanonicalMutation(this.context, options, "create.image");
353991
354780
  if (blocked)
353992
354781
  return blocked;
354782
+ if (new V2ProtectionAdapter(this.context).get().editingRestriction.runtimeEnforced) {
354783
+ const at = input.at;
354784
+ const locator = (at && "target" in at ? at.target.story : undefined) ?? input.in ?? { kind: "story", storyType: "body" };
354785
+ const story = this.context.resolveFullStoryLocator(locator);
354786
+ let allowed = false;
354787
+ if (!("error" in story) && story.partUri === "/word/document.xml") {
354788
+ const xml = readPartXml(this.context, story.partUri) ?? "";
354789
+ if (at?.kind === "inContentControl") {
354790
+ const range = findContentControlXmlRange(xml, at.target.nodeId);
354791
+ allowed = !!range && documentProtectionAllowsXmlRange(this.context, story.partUri, range.start, range.end);
354792
+ } else if (at?.kind === "inParagraph") {
354793
+ const paragraph4 = readBodyParagraphByBlockId(this.context, at.target.nodeId);
354794
+ if (paragraph4) {
354795
+ const bytes = getSDDocumentSessionInternalPartBytes(this.context.session, story.partUri);
354796
+ const decoder8 = new TextDecoder;
354797
+ const start = decoder8.decode(bytes.subarray(0, paragraph4.byteStart)).length;
354798
+ const end = decoder8.decode(bytes.subarray(0, paragraph4.byteEnd)).length;
354799
+ allowed = documentProtectionAllowsXmlRange(this.context, story.partUri, start, end);
354800
+ }
354801
+ }
354802
+ }
354803
+ if (!allowed)
354804
+ return createImageFailure("PERMISSION_DENIED", DOCUMENT_PROTECTION_MESSAGE);
354805
+ }
353993
354806
  const invalidAlias = validateHeaderFooterStoryAlias(this.context, input);
353994
354807
  if (invalidAlias)
353995
354808
  return invalidAlias;
@@ -357931,6 +358744,9 @@ function escapeRegExp17(value2) {
357931
358744
  }
357932
358745
  var IMAGE_HYPERLINK_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", EMU_PER_PX5 = 9525, CROP_SCALE2 = 1000, DEFAULT_FLOATING_RELATIVE_HEIGHT = 251659264, DECORATIVE_EXT_URI = "{C183D7F6-B498-43B3-948B-1728B52AA6E4}", DECORATIVE_NAMESPACE = "http://schemas.microsoft.com/office/drawing/2017/decorative", DRAWING_NAMESPACE = "http://schemas.openxmlformats.org/drawingml/2006/main", RELATIONSHIP_NAMESPACE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships", CONVERTED_INLINE_ANCHORS, DEFAULT_PAGE_WIDTH_TWIPS2 = 12240, DEFAULT_PAGE_MARGIN_TWIPS2 = 1440, TWIPS_PER_PX = 15;
357933
358746
  var init_adapter19 = __esm(() => {
358747
+ init_mutation_guard();
358748
+ init_adapter6();
358749
+ init_adapter7();
357934
358750
  init_pending_image_insertion();
357935
358751
  init_src3();
357936
358752
  init_sd_document_session_internal();
@@ -379632,7 +380448,7 @@ function readParagraphMatchNode(input) {
379632
380448
  };
379633
380449
  return {
379634
380450
  address: address3,
379635
- node: buildParagraphNode(paragraph4),
380451
+ node: buildParagraphNode(paragraph4, input.matchedText),
379636
380452
  byteRange: [paragraph4.byteStart, paragraph4.byteEnd]
379637
380453
  };
379638
380454
  }
@@ -379778,8 +380594,8 @@ function collectTableCellNodes(context, resolved, story) {
379778
380594
  }
379779
380595
  return items;
379780
380596
  }
379781
- function buildParagraphNode(paragraph4) {
379782
- const inlines = paragraph4.text.length > 0 ? [{ kind: "run", run: { text: paragraph4.text } }] : [];
380597
+ function buildParagraphNode(paragraph4, text4 = paragraph4.text) {
380598
+ const inlines = text4.length > 0 ? [{ kind: "run", run: { text: text4 } }] : [];
379783
380599
  if (paragraph4.headingLevel > 0) {
379784
380600
  return {
379785
380601
  id: paragraph4.blockId,
@@ -382780,11 +383596,11 @@ class V2FindAdapter {
382780
383596
  total: page.total,
382781
383597
  limit,
382782
383598
  offset,
382783
- items: page.hits.map(({ scope, hit, packageRevision, partRevision, storyRevision, coordinateSpace, paragraphText: paragraphText3 }) => buildSDNodeResult(this.context, scope, hit, packageRevision, partRevision, storyRevision, coordinateSpace, paragraphText3))
383599
+ items: page.hits.map(({ scope, hit, packageRevision, partRevision, storyRevision, coordinateSpace }) => buildSDNodeResult(this.context, scope, hit, packageRevision, partRevision, storyRevision, coordinateSpace))
382784
383600
  };
382785
383601
  }
382786
383602
  }
382787
- function buildSDNodeResult(context, scope, hit, rev2, partRev, storyRev, coordinateSpace, paragraphText3) {
383603
+ function buildSDNodeResult(context, scope, hit, rev2, partRev, storyRev, coordinateSpace) {
382788
383604
  const story = projectScopeToStoryLocator(scope);
382789
383605
  const descriptor = storySurfaceFromSearchScope(scope);
382790
383606
  const ref5 = encodeV2SearchRef({
@@ -382808,7 +383624,8 @@ function buildSDNodeResult(context, scope, hit, rev2, partRev, storyRev, coordin
382808
383624
  context,
382809
383625
  storyId: descriptor.storyId,
382810
383626
  blockId: hit.blockId,
382811
- story: story.storyType !== "body" ? story : undefined
383627
+ story: story.storyType !== "body" ? story : undefined,
383628
+ matchedText: hit.matchText
382812
383629
  });
382813
383630
  return {
382814
383631
  address: paragraphNode?.address ?? {
@@ -382817,21 +383634,14 @@ function buildSDNodeResult(context, scope, hit, rev2, partRev, storyRev, coordin
382817
383634
  nodeId: hit.blockId,
382818
383635
  ...story.storyType !== "body" ? { story } : {}
382819
383636
  },
382820
- node: coordinateSpace === "tracked" ? buildTextOnlyNode(paragraphText3 ?? hit.matchText, paragraphNode?.node) : paragraphNode?.node ?? buildTextOnlyNode(hit.matchText),
383637
+ node: paragraphNode?.node ?? buildTextOnlyNode(hit.matchText),
382821
383638
  context: {
382822
383639
  ancestors: [{ id: ref5, kind: "v2-search-ref" }]
382823
383640
  }
382824
383641
  };
382825
383642
  }
382826
- function buildTextOnlyNode(text4, source) {
382827
- const inlines = [{ kind: "run", run: { text: text4 } }];
382828
- if (source?.kind === "heading") {
382829
- return { ...source, heading: { ...source.heading, inlines } };
382830
- }
382831
- if (source?.kind === "paragraph") {
382832
- return { ...source, paragraph: { ...source.paragraph, inlines } };
382833
- }
382834
- return { kind: "paragraph", paragraph: { inlines } };
383643
+ function buildTextOnlyNode(text4) {
383644
+ return { kind: "paragraph", paragraph: { inlines: [{ kind: "run", run: { text: text4 } }] } };
382835
383645
  }
382836
383646
  function clampLimit2(limit) {
382837
383647
  if (limit == null)
@@ -389138,7 +389948,7 @@ function serializeSelectionRange(context, target, includeHtml, options) {
389138
389948
  const listLevel = numbering ? Number.parseInt(numbering.ilvl, 10) : undefined;
389139
389949
  const blockSdts = blockSdtPath.map((ordinal) => {
389140
389950
  const wrapper = blockSdtWrappers.get(ordinal);
389141
- if (!wrapper || !fullyCovered || !wrapper.supported || index2.entries.some((candidate2) => boundaryMap.byBlockId(candidate2.blockId)?.blockSdtPath.includes(ordinal) && ((boundaryMap.byBlockId(candidate2.blockId)?.tableCellPath.length ?? 0) > 1 || candidate2.ordinal < startEntry.ordinal || candidate2.ordinal > endEntry.ordinal || candidate2.ordinal === startEntry.ordinal && startPoint.offset !== 0 || candidate2.ordinal === endEntry.ordinal && endPoint.offset !== parseParagraphInlineMap(SERIALIZE_TD.decode(bytes.subarray(endEntry.byteStart, endEntry.byteEnd))).visibleLength)))
389951
+ if (!wrapper || !fullyCovered || !wrapper.supported || index2.entries.some((candidate2) => boundaryMap.byBlockId(candidate2.blockId)?.blockSdtPath.includes(ordinal) && ((boundaryMap.byBlockId(candidate2.blockId)?.tableCellPath.length ?? 0) > 1 || candidate2.ordinal < startEntry.ordinal || candidate2.ordinal > endEntry.ordinal || candidate2.ordinal === startEntry.ordinal && startPoint.offset !== 0 || candidate2.ordinal === endEntry.ordinal && endPoint.offset !== (options?.offsetSpace === "selection" ? paragraphPaintedLength(SERIALIZE_TD.decode(bytes.subarray(endEntry.byteStart, endEntry.byteEnd))) : parseParagraphInlineMap(SERIALIZE_TD.decode(bytes.subarray(endEntry.byteStart, endEntry.byteEnd))).visibleLength))))
389142
389952
  return null;
389143
389953
  return wrapper.properties;
389144
389954
  });
@@ -389182,10 +389992,22 @@ function serializeSelectionRange(context, target, includeHtml, options) {
389182
389992
  const anySoftBreak = blocks.some((block) => block.softBreaks);
389183
389993
  const items = [{ type: "text/plain", kind: "string", data: plainText }];
389184
389994
  if (includeHtml) {
389995
+ const assets = new Map([...rich.assetsByPartUri.values()].map(({ wire }) => [wire.id, wire]));
389996
+ let expandedImageBytes = 0;
389997
+ const admitPart = (part) => {
389998
+ if (part.kind === "image") {
389999
+ expandedImageBytes += (assets.get(part.image.assetId)?.data.length ?? 0) + 4096;
390000
+ return expandedImageBytes <= MAX_V22_PAYLOAD_BYTES2;
390001
+ }
390002
+ return part.kind !== "sdt" && part.kind !== "hyperlink" || part.parts.every(admitPart);
390003
+ };
390004
+ const admitted = grouped.every((entry) => entry.kind === "paragraph" ? entry.block.parts.every(admitPart) : entry.rows.every((row) => row.cells.every((cell) => cell.blocks.every((block) => block.parts.every(admitPart)))));
390005
+ if (!admitted)
390006
+ return { ok: false, code: "INVALID_PAYLOAD", message: "clipboard-html-image-payload-too-large" };
389185
390007
  items.push({
389186
390008
  type: "text/html",
389187
390009
  kind: "string",
389188
- data: buildHtmlFlavor(grouped)
390010
+ data: buildHtmlFlavor(grouped, assets)
389189
390011
  });
389190
390012
  }
389191
390013
  let plan;
@@ -390302,23 +391124,32 @@ function buildPlainFlavor(grouped) {
390302
391124
  }).join(`
390303
391125
  `);
390304
391126
  }
390305
- function blockInlineHtml(block) {
390306
- return block.parts.map(renderHtmlPart).join("");
391127
+ function paragraphPaintedLength(xml) {
391128
+ const map3 = parseParagraphInlineMap(xml);
391129
+ return map3.visibleLength + map3.leaves().filter(isVisibleZeroWidthObjectPiece).length;
391130
+ }
391131
+ function blockInlineHtml(block, assets) {
391132
+ return block.parts.map((part) => renderHtmlPart(part, assets)).join("");
390307
391133
  }
390308
- function renderHtmlPart(part) {
391134
+ function renderHtmlPart(part, assets) {
390309
391135
  if (part.kind === "break")
390310
391136
  return "<br/>";
390311
391137
  if (part.kind === "run")
390312
391138
  return renderHtmlRun(part.run);
390313
- if (part.kind === "image")
390314
- return "";
391139
+ if (part.kind === "image") {
391140
+ const asset = assets.get(part.image.assetId);
391141
+ if (!asset)
391142
+ return "";
391143
+ const { widthPx, heightPx, alt, title: title2 } = part.image;
391144
+ return `<img src="data:${asset.mimeType};base64,${asset.data}" width="${widthPx}" height="${heightPx}"` + (alt ? ` alt="${escapeHtmlAttribute3(alt)}"` : "") + (title2 ? ` title="${escapeHtmlAttribute3(title2)}"` : "") + "/>";
391145
+ }
390315
391146
  if (part.kind === "sdt")
390316
- return part.parts.map(renderHtmlPart).join("");
391147
+ return part.parts.map((child) => renderHtmlPart(child, assets)).join("");
390317
391148
  const href = part.target.kind === "external" ? part.target.url : `#${part.target.anchor}`;
390318
391149
  const title = part.tooltip ? ` title="${escapeHtmlAttribute3(part.tooltip)}"` : "";
390319
- return `<a href="${escapeHtmlAttribute3(href)}"${title}>${part.parts.map(renderHtmlPart).join("")}</a>`;
391150
+ return `<a href="${escapeHtmlAttribute3(href)}"${title}>${part.parts.map((child) => renderHtmlPart(child, assets)).join("")}</a>`;
390320
391151
  }
390321
- function buildHtmlFlavor(grouped) {
391152
+ function buildHtmlFlavor(grouped, assets) {
390322
391153
  const out = [];
390323
391154
  let openList2 = null;
390324
391155
  const closeList = () => {
@@ -390330,11 +391161,11 @@ function buildHtmlFlavor(grouped) {
390330
391161
  for (const entry of grouped) {
390331
391162
  if (entry.kind === "table") {
390332
391163
  closeList();
390333
- out.push(`<table${entry.cellSpacingPt !== undefined ? ` style="border-spacing: ${entry.cellSpacingPt}pt"` : ""}>${entry.rows.map((row) => `<tr>${row.cells.map((cell) => `<td${tableCellHtmlStyle(cell)}>${cell.blocks.map((block2) => block2.headingLevel ? `<h${block2.headingLevel}>${blockInlineHtml(block2)}</h${block2.headingLevel}>` : `<p>${blockInlineHtml(block2)}</p>`).join("")}</td>`).join("")}</tr>`).join("")}</table>`);
391164
+ out.push(`<table${entry.cellSpacingPt !== undefined ? ` style="border-spacing: ${entry.cellSpacingPt}pt"` : ""}>${entry.rows.map((row) => `<tr>${row.cells.map((cell) => `<td${tableCellHtmlStyle(cell)}>${cell.blocks.map((block2) => block2.headingLevel ? `<h${block2.headingLevel}>${blockInlineHtml(block2, assets)}</h${block2.headingLevel}>` : `<p>${blockInlineHtml(block2, assets)}</p>`).join("")}</td>`).join("")}</tr>`).join("")}</table>`);
390334
391165
  continue;
390335
391166
  }
390336
391167
  const block = entry.block;
390337
- const inline = blockInlineHtml(block);
391168
+ const inline = blockInlineHtml(block, assets);
390338
391169
  if (block.listKind) {
390339
391170
  const tag = block.listKind === "bullet" ? "ul" : "ol";
390340
391171
  if (openList2 !== tag) {
@@ -390546,7 +391377,7 @@ class V2ClipboardAdapter {
390546
391377
  });
390547
391378
  if (!serialized2.ok)
390548
391379
  throw new DocumentApiValidationError2(serialized2.code, serialized2.message);
390549
- return serialized2.result;
391380
+ return attachMutationPublicRevision(serialized2.result, this.context.currentPublicRevision());
390550
391381
  }
390551
391382
  if (target.kind === "documentEnd") {
390552
391383
  throw new DocumentApiValidationError2("INVALID_TARGET", "clipboard.serializeSelection does not support documentEnd targets.");
@@ -390576,7 +391407,7 @@ class V2ClipboardAdapter {
390576
391407
  });
390577
391408
  if (!serialized.ok)
390578
391409
  throw new DocumentApiValidationError2(serialized.code, serialized.message);
390579
- return serialized.result;
391410
+ return attachMutationPublicRevision(serialized.result, this.context.currentPublicRevision());
390580
391411
  }
390581
391412
  }
390582
391413
  function pointStoryLocator(target) {
@@ -390995,6 +391826,7 @@ var init_adapter37 = __esm(() => {
390995
391826
  init_note_story();
390996
391827
  init_selection_target();
390997
391828
  init_document_reader();
391829
+ init_mutation_public_revision();
390998
391830
  init_adapter();
390999
391831
  init_stories();
391000
391832
  init_text_range_shifts();
@@ -429640,7 +430472,6 @@ function materializeProjection(input) {
429640
430472
  previousByPartUri.set(story.partUri, story);
429641
430473
  }
429642
430474
  }
429643
- const blockOnlyByShard = new Map;
429644
430475
  const dirtyStoryShardIds = new Set;
429645
430476
  const explicitDirtyStoryShardIds = new Set;
429646
430477
  const dirtyStoryBlocks = new Map;
@@ -429682,16 +430513,8 @@ function materializeProjection(input) {
429682
430513
  const set3 = dirtyStoryBlocks.get(record4.shardId) ?? new Set;
429683
430514
  set3.add(record4.blockId);
429684
430515
  dirtyStoryBlocks.set(record4.shardId, set3);
429685
- if (record4.kind === PROJECTION_DIRTY_KIND.storyText) {
429686
- const blockSet = blockOnlyByShard.get(record4.shardId) ?? new Set;
429687
- blockSet.add(record4.blockId);
429688
- blockOnlyByShard.set(record4.shardId, blockSet);
429689
- } else {
429690
- blockOnlyByShard.delete(record4.shardId);
429691
- }
429692
430516
  } else {
429693
430517
  wholeStoryDirtyShardIds.add(record4.shardId);
429694
- blockOnlyByShard.delete(record4.shardId);
429695
430518
  }
429696
430519
  } else {
429697
430520
  for (const handle of input.shardRegistry.listStories()) {
@@ -429834,7 +430657,8 @@ function materializeProjection(input) {
429834
430657
  blockHints.add(blockId);
429835
430658
  }
429836
430659
  if (blockHints && blockHints.size > 0 && previous3) {
429837
- const currentSnapshot = structuralSnapshot ?? readStorySnapshot(readTarget);
430660
+ const textLocalSnapshot = !structuralSnapshot && tableReplacements.length === 0 ? readTextLocalStorySnapshot({ previous: previous3, target: readTarget, shardId: handle.shardId, dirty: input.dirty }) : null;
430661
+ const currentSnapshot = structuralSnapshot ?? textLocalSnapshot?.snapshot ?? readStorySnapshot(readTarget);
429838
430662
  let placements2;
429839
430663
  const currentBlockIds = currentSnapshot.blocks.map((block) => block.blockId);
429840
430664
  if (wholeStoryDirtyShardIds.has(handle.shardId)) {
@@ -429986,6 +430810,7 @@ function materializeProjection(input) {
429986
430810
  }) ?? blockPatchedStory;
429987
430811
  const projected = replaceProjectedTrailingXml(projectedWithTables, trailingXml, bootstrap);
429988
430812
  stories.push(projected);
430813
+ rememberTextLocalStorySnapshot(projected, readTarget, currentSnapshot, textLocalSnapshot);
429989
430814
  blockDigestIndex(projected.blockDigests);
429990
430815
  storiesRebuilt += 1;
429991
430816
  } else if (tableReplacements.length > 0) {
@@ -430006,6 +430831,7 @@ function materializeProjection(input) {
430006
430831
  storiesRebuilt += 1;
430007
430832
  } else {
430008
430833
  stories.push(previous3);
430834
+ rememberTextLocalStorySnapshot(previous3, readTarget, currentSnapshot, textLocalSnapshot);
430009
430835
  }
430010
430836
  continue;
430011
430837
  }
@@ -430142,6 +430968,55 @@ function materializeProjection(input) {
430142
430968
  };
430143
430969
  return { record: withDigest, storiesRebuilt, fullStoryRebuilds, fullPackageRebuild };
430144
430970
  }
430971
+ function readTextLocalStorySnapshot(input) {
430972
+ const cached2 = TEXT_LOCAL_STORY_SNAPSHOTS.get(input.previous);
430973
+ if (!cached2 || input.previous.tableStructuralOverlays?.length || input.dirty.length === 0)
430974
+ return null;
430975
+ if (input.dirty.some((reason) => reason.kind !== PROJECTION_DIRTY_KIND.storyText || reason.shardId !== input.shardId || !reason.blockId || reason.source === "bootstrap"))
430976
+ return null;
430977
+ const scope = resolveStoryShardScope(input.target);
430978
+ if (scope.blocks !== cached2.blocks || hasContentControlGroups(scope))
430979
+ return null;
430980
+ const entries2 = listOrderedBlocks(scope);
430981
+ if (entries2.length !== cached2.snapshot.blocks.length || entries2.length !== scope.blocks.length)
430982
+ return null;
430983
+ const changed = new Set(input.dirty.map((reason) => reason.blockId));
430984
+ for (const [index2, entry] of entries2.entries()) {
430985
+ if (entry.block !== cached2.carriers[index2] || entry.blockId !== cached2.snapshot.blocks[index2].blockId || entry.block.get(BLOCK_KEY.mergedIntoBlockId))
430986
+ return null;
430987
+ changed.delete(entry.blockId);
430988
+ }
430989
+ if (changed.size > 0)
430990
+ return null;
430991
+ const dirtyIds = new Set(input.dirty.map((reason) => reason.blockId));
430992
+ return {
430993
+ blocks: scope.blocks,
430994
+ carriers: cached2.carriers,
430995
+ snapshot: {
430996
+ meta: readMeta(scope),
430997
+ blocks: entries2.map((entry, index2) => dirtyIds.has(entry.blockId) ? snapshotBlock(entry.block) : cached2.snapshot.blocks[index2])
430998
+ }
430999
+ };
431000
+ }
431001
+ function rememberTextLocalStorySnapshot(story, target, snapshot3, validated) {
431002
+ if (story.tableStructuralOverlays?.length || snapshot3.blocks.some((block) => block.mergedIntoBlockId || block.mergedTailBlockIds.length > 0))
431003
+ return;
431004
+ if (validated && validated.snapshot === snapshot3 && story.blockDigests.length === snapshot3.blocks.length && story.blockDigests.every((entry, index2) => entry.blockId === snapshot3.blocks[index2].blockId)) {
431005
+ TEXT_LOCAL_STORY_SNAPSHOTS.set(story, validated);
431006
+ return;
431007
+ }
431008
+ const scope = resolveStoryShardScope(target);
431009
+ if (hasContentControlGroups(scope))
431010
+ return;
431011
+ const entries2 = listOrderedBlocks(scope);
431012
+ if (entries2.length !== snapshot3.blocks.length || entries2.length !== scope.blocks.length || entries2.length !== story.blockDigests.length || entries2.some((entry, index2) => entry.blockId !== snapshot3.blocks[index2].blockId || entry.blockId !== story.blockDigests[index2].blockId))
431013
+ return;
431014
+ TEXT_LOCAL_STORY_SNAPSHOTS.set(story, {
431015
+ blocks: scope.blocks,
431016
+ carriers: entries2.map((entry) => entry.block),
431017
+ snapshot: snapshot3
431018
+ });
431019
+ }
430145
431020
  function byPartUri(a, b) {
430146
431021
  if (a.partUri < b.partUri)
430147
431022
  return -1;
@@ -433393,7 +434268,7 @@ function canonicalStoryDigestInputs(stories) {
433393
434268
  tableStructuralOverlays: [...story.tableStructuralOverlays ?? []].sort((left, right) => left.tableNodeId < right.tableNodeId ? -1 : left.tableNodeId > right.tableNodeId ? 1 : 0)
433394
434269
  }));
433395
434270
  }
433396
- var WORD_ML_NS2 = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"', WORD_ML_2010_NS = 'xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"', STORY_ROOT_NS, TEXT_DECODER7, STORY_BLOCK_INDEX_CACHE, SYNTHETIC_PARAGRAPH_BLOCK_ID_PREFIX4 = "__sd:paragraph:", UTF8_ENCODER3, SOURCE_XML_BYTE_ALIGNED_CACHE, XML_EMISSION_CONTEXTS, CONTENT_CONTROL_TOPOLOGIES, PROJECTED_NAMESPACE_CONTEXTS, PARAGRAPH_PROPERTY_ORDER, RUN_PROPERTY_CONTENT_LOCAL_NAMES;
434271
+ var WORD_ML_NS2 = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"', WORD_ML_2010_NS = 'xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"', STORY_ROOT_NS, TEXT_DECODER7, STORY_BLOCK_INDEX_CACHE, SYNTHETIC_PARAGRAPH_BLOCK_ID_PREFIX4 = "__sd:paragraph:", UTF8_ENCODER3, SOURCE_XML_BYTE_ALIGNED_CACHE, XML_EMISSION_CONTEXTS, CONTENT_CONTROL_TOPOLOGIES, PROJECTED_NAMESPACE_CONTEXTS, TEXT_LOCAL_STORY_SNAPSHOTS, PARAGRAPH_PROPERTY_ORDER, RUN_PROPERTY_CONTENT_LOCAL_NAMES;
433397
434272
  var init_materialize = __esm(() => {
433398
434273
  init_package_part();
433399
434274
  init_anchors();
@@ -433421,6 +434296,7 @@ var init_materialize = __esm(() => {
433421
434296
  XML_EMISSION_CONTEXTS = new WeakMap;
433422
434297
  CONTENT_CONTROL_TOPOLOGIES = new WeakMap;
433423
434298
  PROJECTED_NAMESPACE_CONTEXTS = new WeakMap;
434299
+ TEXT_LOCAL_STORY_SNAPSHOTS = new WeakMap;
433424
434300
  PARAGRAPH_PROPERTY_ORDER = new Map([
433425
434301
  "pStyle",
433426
434302
  "keepNext",