@superdoc/mcp 1.9.0-next.11 → 1.9.0-next.12

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 +444 -315
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31620,7 +31620,7 @@ var init_host = __esm(() => {
31620
31620
  });
31621
31621
 
31622
31622
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31623
- var SDK_VERSION = "2.22.0-next.11";
31623
+ var SDK_VERSION = "2.22.0-next.12";
31624
31624
 
31625
31625
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31626
31626
  import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
@@ -159330,7 +159330,7 @@ function buildCommentsCatalog(state) {
159330
159330
  const extendedBytes = state.packageBytes.get(COMMENTS_EXTENDED_PART_URI);
159331
159331
  let extendedByParaId = extendedBytes ? parseCommentsExtendedXml(TD12.decode(extendedBytes)) : new Map;
159332
159332
  if (entries.length > 1) {
159333
- extendedByParaId = mergeInferredThreading(extendedByParaId, inferThreadingFromStoryAnchors(state, entries));
159333
+ extendedByParaId = mergeInferredThreading(extendedByParaId, inferThreadingFromStoryAnchors(state, entries, extendedByParaId));
159334
159334
  }
159335
159335
  const idsBytes = state.packageBytes.get(COMMENTS_IDS_PART_URI);
159336
159336
  const durableByParaId = idsBytes ? parseCommentsIdsXml(TD12.decode(idsBytes)) : new Map;
@@ -159630,17 +159630,25 @@ function normalizeNullableCustomAttr(value) {
159630
159630
  return null;
159631
159631
  return decodeAttr(value);
159632
159632
  }
159633
- function inferThreadingFromStoryAnchors(state, entries) {
159633
+ function inferThreadingFromStoryAnchors(state, entries, explicit) {
159634
159634
  const entryByWId = new Map;
159635
159635
  for (const entry of entries) {
159636
159636
  if (!entryByWId.has(entry.wId))
159637
159637
  entryByWId.set(entry.wId, entry);
159638
159638
  }
159639
+ const paraIdOwners = new Map;
159640
+ for (const entry of entries) {
159641
+ for (const paraId of new Set(entry.bodyParaIds))
159642
+ paraIdOwners.set(paraId, (paraIdOwners.get(paraId) ?? 0) + 1);
159643
+ }
159639
159644
  const sessionParaIds = state.idReservations.comments.paraIds;
159640
159645
  const importedSourceIds = new Set(entries.filter((entry) => {
159641
159646
  const paraId = entry.bodyParaIds[0];
159642
- return paraId && !entry.isExplicitRoot && !sessionParaIds.has(paraId);
159647
+ return paraId && paraIdOwners.get(paraId) === 1 && !entry.isExplicitRoot && !sessionParaIds.has(paraId);
159643
159648
  }).map((entry) => entry.wId));
159649
+ const inferenceSourceIds = new Set([...entryByWId.values()].filter((entry) => importedSourceIds.has(entry.wId) && !entry.bodyParaIds.some((paraId) => explicit.has(paraId))).map((entry) => entry.wId));
159650
+ if (inferenceSourceIds.size === 0)
159651
+ return new Map;
159644
159652
  const sourceOrder = new Map;
159645
159653
  for (let i = 0;i < entries.length; i += 1) {
159646
159654
  const entry = entries[i];
@@ -159664,11 +159672,6 @@ function inferThreadingFromStoryAnchors(state, entries) {
159664
159672
  groups.push([anchor]);
159665
159673
  }
159666
159674
  const out = new Map;
159667
- for (const entry of entries) {
159668
- const paraId = entry.bodyParaIds[0];
159669
- if (paraId)
159670
- out.set(paraId, { parentParaId: null, done: false });
159671
- }
159672
159675
  for (const group of groups) {
159673
159676
  const uniqueSourceIds = Array.from(new Set(group.map((a) => a.sourceWId)));
159674
159677
  if (uniqueSourceIds.length < 2)
@@ -159680,7 +159683,7 @@ function inferThreadingFromStoryAnchors(state, entries) {
159680
159683
  if (!rootParaId)
159681
159684
  continue;
159682
159685
  for (const sourceWId of uniqueSourceIds) {
159683
- if (sourceWId === rootSourceId)
159686
+ if (sourceWId === rootSourceId || !inferenceSourceIds.has(sourceWId))
159684
159687
  continue;
159685
159688
  const replyEntry = entryByWId.get(sourceWId);
159686
159689
  const replyParaId = replyEntry?.bodyParaIds[0];
@@ -159688,12 +159691,25 @@ function inferThreadingFromStoryAnchors(state, entries) {
159688
159691
  continue;
159689
159692
  const parentSourceId = chooseContainingParentSourceId(sourceWId, uniqueSourceIds, envelopeBySourceId, sourceOrder) ?? rootSourceId;
159690
159693
  const parentEntry = entryByWId.get(parentSourceId);
159691
- const parentParaId = parentEntry?.bodyParaIds[0] ?? rootParaId;
159694
+ const parentParaId = parentEntry ? selectThreadingParaId(parentEntry, explicit) : rootParaId;
159695
+ if (wouldCreateThreadCycle(replyParaId, parentParaId, explicit, out))
159696
+ continue;
159692
159697
  out.set(replyParaId, { parentParaId, done: false });
159693
159698
  }
159694
159699
  }
159695
159700
  return out;
159696
159701
  }
159702
+ function wouldCreateThreadCycle(childParaId, parentParaId, explicit, inferred) {
159703
+ const seen = new Set([childParaId]);
159704
+ let cursor = parentParaId;
159705
+ while (cursor !== null) {
159706
+ if (seen.has(cursor))
159707
+ return true;
159708
+ seen.add(cursor);
159709
+ cursor = (explicit.get(cursor) ?? inferred.get(cursor))?.parentParaId ?? null;
159710
+ }
159711
+ return false;
159712
+ }
159697
159713
  function representativeEnvelopeBySourceId(group) {
159698
159714
  const out = new Map;
159699
159715
  for (const envelope of group) {
@@ -159758,17 +159774,8 @@ function mergeInferredThreading(explicit, inferred) {
159758
159774
  return explicit;
159759
159775
  const out = new Map(explicit);
159760
159776
  for (const [paraId, inferredExt] of inferred) {
159761
- const existing = out.get(paraId);
159762
- if (!existing) {
159777
+ if (!out.has(paraId))
159763
159778
  out.set(paraId, inferredExt);
159764
- continue;
159765
- }
159766
- if (existing.parentParaId === null && inferredExt.parentParaId !== null) {
159767
- out.set(paraId, {
159768
- parentParaId: inferredExt.parentParaId,
159769
- done: existing.done
159770
- });
159771
- }
159772
159779
  }
159773
159780
  return out;
159774
159781
  }
@@ -159779,25 +159786,38 @@ function collectCommentAnchorEnvelopes(state) {
159779
159786
  continue;
159780
159787
  const xml = TD12.decode(bytes);
159781
159788
  const starts = [];
159782
- const ends = [];
159789
+ const endsBySourceId = new Map;
159783
159790
  const tokenRe = /<[\w.-]+:(commentRangeStart|commentRangeEnd)\b[^>]*\bw:id="([^"]+)"[^>]*\/?>/g;
159784
159791
  for (let match = tokenRe.exec(xml);match; match = tokenRe.exec(xml)) {
159785
159792
  const item = { sourceWId: match[2] ?? "", pos: match.index };
159786
159793
  if (match[1] === "commentRangeStart")
159787
159794
  starts.push(item);
159788
- else
159789
- ends.push(item);
159795
+ else {
159796
+ const ends = endsBySourceId.get(item.sourceWId);
159797
+ if (ends)
159798
+ ends.push(item.pos);
159799
+ else
159800
+ endsBySourceId.set(item.sourceWId, [item.pos]);
159801
+ }
159790
159802
  }
159803
+ const endCursors = new Map;
159791
159804
  for (const start of starts) {
159792
- const end = ends.find((candidate2) => candidate2.sourceWId === start.sourceWId && candidate2.pos >= start.pos);
159793
- if (end)
159794
- out.push({ sourceWId: start.sourceWId, start: start.pos, end: end.pos });
159805
+ const ends = endsBySourceId.get(start.sourceWId);
159806
+ if (!ends)
159807
+ continue;
159808
+ let cursor = endCursors.get(start.sourceWId) ?? 0;
159809
+ while (cursor < ends.length && ends[cursor] < start.pos)
159810
+ cursor++;
159811
+ endCursors.set(start.sourceWId, cursor);
159812
+ const end = ends[cursor];
159813
+ if (end !== undefined)
159814
+ out.push({ partUri, sourceWId: start.sourceWId, start: start.pos, end });
159795
159815
  }
159796
159816
  }
159797
159817
  return out;
159798
159818
  }
159799
159819
  function envelopesOverlap(a, b) {
159800
- return a.start <= b.end && b.start <= a.end;
159820
+ return a.partUri === b.partUri && a.start <= b.end && b.start <= a.end;
159801
159821
  }
159802
159822
  function isStoryPartUri(partUri) {
159803
159823
  return partUri === "/word/document.xml" || /^\/word\/header\d+\.xml$/.test(partUri) || /^\/word\/footer\d+\.xml$/.test(partUri) || partUri === "/word/footnotes.xml" || partUri === "/word/endnotes.xml";
@@ -159961,27 +159981,42 @@ function shiftedMarker(marker, delta) {
159961
159981
  paragraph: marker.paragraph ? { ...marker.paragraph, range: shift(marker.paragraph.range) } : null
159962
159982
  };
159963
159983
  }
159964
- function getBodyCommentMarkerFacts(state, partUri) {
159984
+ function indexMarkersBySourceId(markers) {
159985
+ const index = new Map;
159986
+ for (const marker of markers) {
159987
+ const existing = index.get(marker.id);
159988
+ if (existing)
159989
+ existing.push(marker);
159990
+ else
159991
+ index.set(marker.id, [marker]);
159992
+ }
159993
+ return index;
159994
+ }
159995
+ function getBodyCommentByteFacts(state, partUri) {
159965
159996
  const bytes = state.packageBytes.get(partUri);
159966
159997
  const revision = state.parts.get(partUri)?.descriptor.revision;
159967
159998
  if (!bytes || !revision)
159968
- return [];
159999
+ return null;
159969
160000
  const cache = byteFacts(state);
159970
160001
  const prior = cache.get(partUri);
159971
160002
  if (prior?.bytes === bytes && prior.partRevision === revision)
159972
- return prior.markers;
160003
+ return prior;
159973
160004
  const bom = bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? 3 : 0;
159974
160005
  const scanned = scanBodyCommentMarkers(TD13.decode(bytes));
159975
160006
  const markers = scanned.markers.map((marker) => shiftedMarker(marker, bom));
159976
- cache.set(partUri, { bytes, partRevision: revision, markers, complete: scanned.complete });
159977
- return markers;
160007
+ const facts = { bytes, partRevision: revision, markers, markersBySourceId: indexMarkersBySourceId(markers), complete: scanned.complete };
160008
+ cache.set(partUri, facts);
160009
+ return facts;
160010
+ }
160011
+ function getBodyCommentMarkerFacts(state, partUri) {
160012
+ return getBodyCommentByteFacts(state, partUri)?.markers ?? [];
160013
+ }
160014
+ function getBodyCommentMarkersForSourceId(state, partUri, commentId) {
160015
+ return getBodyCommentByteFacts(state, partUri)?.markersBySourceId.get(commentId) ?? [];
159978
160016
  }
159979
160017
  function readCompleteBodyCommentMarkerFacts(state, partUri) {
159980
- if (!state.packageBytes.has(partUri))
159981
- return null;
159982
- const markers = getBodyCommentMarkerFacts(state, partUri);
159983
- const facts = byteFacts(state).get(partUri);
159984
- return facts?.complete === true && facts.bytes === state.packageBytes.get(partUri) && facts.partRevision === state.parts.get(partUri)?.descriptor.revision ? markers : null;
160018
+ const facts = getBodyCommentByteFacts(state, partUri);
160019
+ return facts?.complete === true ? facts.markers : null;
159985
160020
  }
159986
160021
  function peekBodyCommentMarkerFacts(state, partUri) {
159987
160022
  const cache = state.partRegistries.get(BYTE_FACTS_KEY);
@@ -160011,22 +160046,22 @@ function refreshBodyCommentMarkerFactsAfterParagraphMutation(input) {
160011
160046
  }
160012
160047
  const scanned = scanBodyCommentMarkers(TD13.decode(bytes.subarray(input.beforeStart, input.afterEnd)), input.namespaceBindings);
160013
160048
  const current = scanned.markers.map((marker) => shiftedMarker(marker, input.beforeStart));
160049
+ const markers = [...unchanged, ...current].sort((a, b) => a.range.byteStart - b.range.byteStart);
160014
160050
  cache.set(input.partUri, {
160015
160051
  bytes,
160016
160052
  partRevision: revision,
160017
160053
  complete: prior.complete && scanned.complete,
160018
- markers: [...unchanged, ...current].sort((a, b) => a.range.byteStart - b.range.byteStart)
160054
+ markers,
160055
+ markersBySourceId: indexMarkersBySourceId(markers)
160019
160056
  });
160020
160057
  }
160021
160058
  function findRetainedBodyCommentAnchors(state, partUri, commentId, occurrenceIndex) {
160022
- return anchorsFromMarkers(getBodyCommentMarkerFacts(state, partUri), commentId, occurrenceIndex);
160059
+ return anchorsFromMarkers(getBodyCommentMarkersForSourceId(state, partUri, commentId), commentId, occurrenceIndex);
160023
160060
  }
160024
160061
  function countRetainedBodyCommentAnchorOccurrences(state, partUri, commentId) {
160025
160062
  const counts = { commentRangeStart: 0, commentRangeEnd: 0, commentReference: 0 };
160026
- for (const marker of getBodyCommentMarkerFacts(state, partUri)) {
160027
- if (marker.id === commentId)
160028
- counts[marker.kind] += 1;
160029
- }
160063
+ for (const marker of getBodyCommentMarkersForSourceId(state, partUri, commentId))
160064
+ counts[marker.kind] += 1;
160030
160065
  return Math.max(counts.commentRangeStart, counts.commentRangeEnd, counts.commentReference);
160031
160066
  }
160032
160067
  function collectBodyCommentMarkers(documentXml, namespaceBindings) {
@@ -185500,7 +185535,8 @@ function createReviewStagingState(state, targetBlockIds) {
185500
185535
  result[key3] = clone2(item);
185501
185536
  return result;
185502
185537
  };
185503
- Object.assign(staged, Object.fromEntries(Object.entries(staged).filter(([key3]) => !["packageBytes", "paragraphIndexes", "partRegistries"].includes(key3)).map(([key3, value]) => [key3, clone2(value)])));
185538
+ Object.assign(staged, Object.fromEntries(Object.entries(staged).filter(([key3]) => !["packageBytes", "paragraphIndexes", "partRegistries", "history"].includes(key3)).map(([key3, value]) => [key3, clone2(value)])));
185539
+ staged.history = { entries: new Map(state.history.entries), order: [...state.history.order] };
185504
185540
  staged.paragraphIndexes = new Map;
185505
185541
  staged.partRegistries = new Map;
185506
185542
  staged.revisions = new RevisionAllocator("review-preview");
@@ -264694,8 +264730,7 @@ class TxContext {
264694
264730
  const documentBytes = this.state.packageBytes.get(op.on.partUri);
264695
264731
  if (!documentBytes)
264696
264732
  return rejected21(this.txId, "invalid-range");
264697
- const documentXml = TD78.decode(documentBytes);
264698
- const anchors = findBodyCommentAnchors(documentXml, markerWId, sourceStoryInfo.localOccurrenceIndex);
264733
+ const anchors = sourceStoryInfo.anchors;
264699
264734
  if (!anchors.rangeStart || !anchors.rangeEnd) {
264700
264735
  return rejected21(this.txId, "comment-anchor-not-found");
264701
264736
  }
@@ -264714,7 +264749,7 @@ class TxContext {
264714
264749
  continue;
264715
264750
  if (threadStory.partUri !== op.on.partUri)
264716
264751
  return rejected21(this.txId, "comment-move-cross-story");
264717
- const threadAnchors = findBodyCommentAnchors(documentXml, threadMarkerWId, threadStory.localOccurrenceIndex);
264752
+ const threadAnchors = threadStory.anchors;
264718
264753
  if (threadAnchors.rangeStart)
264719
264754
  removeRanges.push(threadAnchors.rangeStart);
264720
264755
  if (threadAnchors.rangeEnd)
@@ -264741,7 +264776,7 @@ class TxContext {
264741
264776
  };
264742
264777
  if (newRange.byteEnd < newRange.byteStart)
264743
264778
  return rejected21(this.txId, "invalid-range");
264744
- if (!op.allowMarkerCarrierOverlap && rangesOverlap(oldEnvelope, newRange)) {
264779
+ if (!op.allowMarkerCarrierOverlap && rangesOverlap(oldEnvelope, newRange) && !isUnchangedCommentRange(this.state, op.on, markerWId, anchors)) {
264745
264780
  return rejected21(this.txId, "comment-move-overlap");
264746
264781
  }
264747
264782
  const stripped = stripBytes2(documentBytes, mergedRemovals);
@@ -264749,7 +264784,7 @@ class TxContext {
264749
264784
  const newEnd = translateAfterRemovals(newRange.byteEnd, mergedRemovals);
264750
264785
  if (newStart == null || newEnd == null)
264751
264786
  return rejected21(this.txId, "comment-move-overlap");
264752
- const rewrite = rewriteDocumentXml(TD78.decode(stripped), { ...op.on, startByte: newStart, endByte: newEnd }, markerWId, undefined, {
264787
+ const rewrite = rewriteDocumentXml(TD_KEEP_BOM.decode(stripped), { ...op.on, startByte: newStart, endByte: newEnd }, markerWId, undefined, {
264753
264788
  start: relocatedAnchors.map((anchor) => commentRangeStart(anchor.markerWId)).join(""),
264754
264789
  end: relocatedAnchors.map((anchor) => commentRangeEnd(anchor.markerWId) + commentReferenceRun(anchor.markerWId, anchor.referenceRunXml)).join("")
264755
264790
  });
@@ -264778,28 +264813,31 @@ class TxContext {
264778
264813
  const commentsBytes = this.state.packageBytes.get(COMMENTS_PART_URI3);
264779
264814
  if (!commentsBytes)
264780
264815
  return rejected21(this.txId, "comments-part-missing");
264781
- const commentsXml = TD78.decode(commentsBytes);
264782
- let commentsNext = commentsXml;
264816
+ const bom = commentsBytes[0] === 239 && commentsBytes[1] === 187 && commentsBytes[2] === 191 ? 3 : 0;
264817
+ const commentsPatches = [];
264783
264818
  for (const threadEntry of threadEntries) {
264784
- const rewritten = rewriteCommentTrackedChangeMetadata(commentsNext, threadEntry.sourceWId || threadEntry.wId, threadEntry.sourceWIdOccurrenceIndex, op.trackedChangeMetadata);
264819
+ const startByte = threadEntry.byteStart + bom;
264820
+ const endByte = threadEntry.byteEnd + bom;
264821
+ const fragment3 = TD78.decode(commentsBytes.subarray(startByte, endByte));
264822
+ const rewritten = rewriteCommentTrackedChangeMetadata(fragment3, threadEntry.sourceWId || threadEntry.wId, 0, op.trackedChangeMetadata);
264785
264823
  if (!rewritten.ok)
264786
264824
  return rejected21(this.txId, rewritten.reason);
264787
- commentsNext = rewritten.xml;
264825
+ if (rewritten.xml !== fragment3)
264826
+ commentsPatches.push({
264827
+ kind: "replaceBytes",
264828
+ order: commentsPatches.length,
264829
+ startByte,
264830
+ endByte,
264831
+ bytes: TE44.encode(rewritten.xml)
264832
+ });
264788
264833
  }
264789
- if (commentsNext !== commentsXml) {
264790
- const commentsPatch = {
264791
- kind: "replaceBytes",
264792
- order: 0,
264793
- startByte: 0,
264794
- endByte: commentsBytes.length,
264795
- bytes: TE44.encode(commentsNext)
264796
- };
264797
- perPart[COMMENTS_PART_URI3] = { kind: "modify", patches: [commentsPatch] };
264834
+ if (commentsPatches.length > 0) {
264835
+ perPart[COMMENTS_PART_URI3] = { kind: "modify", patches: commentsPatches };
264798
264836
  preconditions.push(byteWindowPrecondition10(COMMENTS_PART_URI3, commentsBytes));
264799
264837
  const commentsMap = buildPatchMap({
264800
264838
  partUri: COMMENTS_PART_URI3,
264801
264839
  originalLength: commentsBytes.length,
264802
- patches: [commentsPatch]
264840
+ patches: commentsPatches
264803
264841
  });
264804
264842
  patchMaps[COMMENTS_PART_URI3] = commentsMap.ok ? commentsMap.value : { partUri: COMMENTS_PART_URI3, ranges: [] };
264805
264843
  }
@@ -265440,6 +265478,34 @@ function locateCommentAnchorStory(state, commentId, occurrenceIndex) {
265440
265478
  }
265441
265479
  return null;
265442
265480
  }
265481
+ function isUnchangedCommentRange(state, target, markerWId, anchors) {
265482
+ if (!anchors.rangeStart || !anchors.rangeEnd)
265483
+ return false;
265484
+ const markers = getBodyCommentMarkersForSourceId(state, target.partUri, markerWId);
265485
+ const bytes = state.packageBytes.get(target.partUri);
265486
+ if (!bytes)
265487
+ return false;
265488
+ const models = new Map;
265489
+ const matchesBoundary = (kind, anchor, blockId, offset) => {
265490
+ const marker = markers.find((item) => item.kind === kind && item.range.byteStart === anchor.byteStart);
265491
+ const paragraph = marker?.paragraph;
265492
+ if (!paragraph || anchor.byteStart < paragraph.range.byteStart || anchor.byteEnd > paragraph.range.byteEnd)
265493
+ return false;
265494
+ if (paragraph.blockId !== blockId) {
265495
+ const indexed = getStoryParagraphIndexFromState(state, target.storyId)?.byParaId(blockId);
265496
+ if (!indexed || indexed.partUri !== target.partUri || indexed.partRevision !== target.partRevision || indexed.byteStart !== paragraph.range.byteStart || indexed.byteEnd !== paragraph.range.byteEnd)
265497
+ return false;
265498
+ }
265499
+ let model = models.get(paragraph.range.byteStart);
265500
+ if (!model) {
265501
+ model = parseParagraphInlineMap(TD78.decode(bytes.subarray(paragraph.range.byteStart, paragraph.range.byteEnd)), paragraph.namespaceBindings);
265502
+ models.set(paragraph.range.byteStart, model);
265503
+ }
265504
+ const leaf = model.leaves().find((piece) => piece.kind === "marker" && piece.id === markerWId && piece.markerKind === kind && piece.byteStart + paragraph.range.byteStart === anchor.byteStart);
265505
+ return !!leaf && (target.coordinateSpace === "tracked" ? leaf.trackedStart : leaf.visibleStart) === offset;
265506
+ };
265507
+ return matchesBoundary("commentRangeStart", anchors.rangeStart, target.startBlockId, target.startOffset) && matchesBoundary("commentRangeEnd", anchors.rangeEnd, target.endBlockId, target.endOffset);
265508
+ }
265443
265509
  function findCommentAnchorsForStory(state, partUri, storyXml, commentId, occurrenceIndex) {
265444
265510
  const localOccurrenceIndex = localOccurrenceIndexForStory(state, partUri, storyXml, commentId, occurrenceIndex);
265445
265511
  if (localOccurrenceIndex === null) {
@@ -266206,22 +266272,25 @@ function materializeCurrentCommentThreadExtendedRows(input) {
266206
266272
  Object.assign(input.patchMaps, compiled.value.patchMaps);
266207
266273
  return { ok: true };
266208
266274
  }
266209
- let nextXml = TD78.decode(extendedBytes);
266210
- let changed = false;
266211
- for (const item of entries2) {
266212
- const next = upsertCommentsExtendedThreadRow(nextXml, {
266213
- paraId: item.paraId,
266214
- parentParaId: item.parentParaId,
266215
- done: item.done
266216
- });
266217
- if (!next.ok)
266218
- return next;
266219
- if (next.value !== nextXml) {
266220
- nextXml = next.value;
266221
- changed = true;
266222
- }
266275
+ const xml = TD_KEEP_BOM.decode(extendedBytes);
266276
+ const remaining = new Map(entries2.map((item) => [item.paraId, item]));
266277
+ let nextXml = xml.replace(/<[\w.-]+:commentEx\b[^>]*>/g, (fragment3) => {
266278
+ const paraId = /\b(?:w14|w15):paraId="([^"]*)"/.exec(fragment3)?.[1];
266279
+ const item = paraId ? remaining.get(paraId) : undefined;
266280
+ if (!item)
266281
+ return fragment3;
266282
+ remaining.delete(item.paraId);
266283
+ const next = upsertCommentsExtendedThreadRow(fragment3, item);
266284
+ return next.ok ? next.value : fragment3;
266285
+ });
266286
+ if (remaining.size > 0) {
266287
+ const fragments = [...remaining.values()].map(commentsExtendedRowXml).join("");
266288
+ const appended = appendToExistingXmlRoot(nextXml, fragments, "commentsEx");
266289
+ if (!appended.ok)
266290
+ return appended;
266291
+ nextXml = appended.value;
266223
266292
  }
266224
- if (changed)
266293
+ if (nextXml !== xml)
266225
266294
  addWholePartReplace(input, COMMENTS_EXTENDED_PART_URI3, extendedBytes, nextXml);
266226
266295
  return { ok: true };
266227
266296
  }
@@ -266277,11 +266346,13 @@ function threadRootParaId(catalog, entry) {
266277
266346
  }
266278
266347
  return entry.paraId;
266279
266348
  }
266280
- function appendCommentsExtendedXml(xml, input) {
266349
+ function commentsExtendedRowXml(input) {
266281
266350
  const parentAttr = input.parentParaId ? ` w15:paraIdParent="${escapeXmlAttribute(input.parentParaId)}"` : "";
266282
266351
  const doneAttr = input.done ? "1" : "0";
266283
- const fragment3 = `<w15:commentEx w15:paraId="${escapeXmlAttribute(input.paraId)}" w15:done="${doneAttr}"${parentAttr}/>`;
266284
- return appendToExistingXmlRoot(xml, fragment3, "commentsEx");
266352
+ return `<w15:commentEx w15:paraId="${escapeXmlAttribute(input.paraId)}" w15:done="${doneAttr}"${parentAttr}/>`;
266353
+ }
266354
+ function appendCommentsExtendedXml(xml, input) {
266355
+ return appendToExistingXmlRoot(xml, commentsExtendedRowXml(input), "commentsEx");
266285
266356
  }
266286
266357
  function appendCommentsIdsXml(xml, input) {
266287
266358
  const fragment3 = `<w16cid:commentId w16cid:paraId="${escapeXmlAttribute(input.paraId)}" w16cid:durableId="${escapeXmlAttribute(input.durableId)}"/>`;
@@ -266448,7 +266519,7 @@ function emptyHeaderFooterSkeleton(kind) {
266448
266519
  const root = kind === "header" ? "w:hdr" : "w:ftr";
266449
266520
  return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + `<${root}` + ' xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"' + ' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"' + ">" + "<w:p/>" + `</${root}>`;
266450
266521
  }
266451
- var TE44, TD78, nextTx = 0, CONTENT_TYPES_PART_URI12 = "/[Content_Types].xml", DOCUMENT_RELS_PART_URI10 = "/word/_rels/document.xml.rels", COMMENTS_PART_URI3 = "/word/comments.xml", COMMENTS_IDS_PART_URI3 = "/word/commentsIds.xml", COMMENTS_EXTENDED_PART_URI3 = "/word/commentsExtended.xml", SDCOM_COMMENTS_NS_URI = "http://superdoc.dev/2024/comments", COMMENT_ELEMENT_RE, RUN_HAS_TEXT_LEAF_VISIBLE_RE, RUN_HAS_TEXT_LEAF_TRACKED_RE, RUN_CONTROL_LEAF_RE, RUN_TEXT_LEAF_RE_VISIBLE, RUN_TEXT_LEAF_RE_TRACKED;
266522
+ var TE44, TD78, TD_KEEP_BOM, nextTx = 0, CONTENT_TYPES_PART_URI12 = "/[Content_Types].xml", DOCUMENT_RELS_PART_URI10 = "/word/_rels/document.xml.rels", COMMENTS_PART_URI3 = "/word/comments.xml", COMMENTS_IDS_PART_URI3 = "/word/commentsIds.xml", COMMENTS_EXTENDED_PART_URI3 = "/word/commentsExtended.xml", SDCOM_COMMENTS_NS_URI = "http://superdoc.dev/2024/comments", COMMENT_ELEMENT_RE, RUN_HAS_TEXT_LEAF_VISIBLE_RE, RUN_HAS_TEXT_LEAF_TRACKED_RE, RUN_CONTROL_LEAF_RE, RUN_TEXT_LEAF_RE_VISIBLE, RUN_TEXT_LEAF_RE_TRACKED;
266452
266523
  var init_tx_context = __esm(() => {
266453
266524
  init_resident_paragraph_ownership();
266454
266525
  init_canonical_xml_analysis_frame();
@@ -266494,6 +266565,7 @@ var init_tx_context = __esm(() => {
266494
266565
  init_compile_image_ops();
266495
266566
  TE44 = new TextEncoder;
266496
266567
  TD78 = new TextDecoder;
266568
+ TD_KEEP_BOM = new TextDecoder("utf-8", { ignoreBOM: true });
266497
266569
  COMMENT_ELEMENT_RE = /<[\w.-]+:comment(?=[\s>/])/;
266498
266570
  RUN_HAS_TEXT_LEAF_VISIBLE_RE = /<[\w.-]+:t\b/;
266499
266571
  RUN_HAS_TEXT_LEAF_TRACKED_RE = /<[\w.-]+:(t|delText)\b/;
@@ -377832,13 +377904,29 @@ function resolveCommentEntryByParaId(catalog, paraId) {
377832
377904
  return null;
377833
377905
  return catalog.commentsByCommentId.get(canonicalCommentId) ?? null;
377834
377906
  }
377907
+ function commentAnchorProjectionEntry(entry, catalog, anchorIndex) {
377908
+ let cursor = entry;
377909
+ const seen = new Set;
377910
+ while (cursor.parentParaId !== null) {
377911
+ if (seen.has(cursor.commentId))
377912
+ return entry;
377913
+ seen.add(cursor.commentId);
377914
+ const hits = anchorIndex.hitsBySourceWId.get(cursor.sourceWId) ?? [];
377915
+ if (catalog.commentsBySourceWId.get(cursor.sourceWId)?.length !== 1 || !hits.some((hit) => hit.hasReference) || hits.some((hit) => hit.hasRangeStart || hit.hasRangeEnd))
377916
+ break;
377917
+ const parent = resolveCommentEntryByParaId(catalog, cursor.parentParaId);
377918
+ if (!parent)
377919
+ break;
377920
+ cursor = parent;
377921
+ }
377922
+ return cursor;
377923
+ }
377835
377924
  function toCommentInfo(entry, catalog, anchorIndex, headerFooterRels, trackedAssociations) {
377836
377925
  const publicCommentId = publicCommentIdForEntry(entry);
377837
377926
  const parentParaId = entry.parentParaId;
377838
377927
  const parentEntry = parentParaId ? resolveCommentEntryByParaId(catalog, parentParaId) : null;
377839
377928
  const parentCommentId = parentEntry ? publicCommentIdForEntry(parentEntry) : undefined;
377840
377929
  const rootCommentId = parentCommentId ? rootCommentIdForCatalogEntry(entry, catalog) : null;
377841
- const anchorProjectionEntry = entry;
377842
377930
  const info = {
377843
377931
  address: { kind: "entity", entityType: "comment", entityId: publicCommentId },
377844
377932
  commentId: publicCommentId,
@@ -377860,10 +377948,9 @@ function toCommentInfo(entry, catalog, anchorIndex, headerFooterRels, trackedAss
377860
377948
  info.creatorImage = entry.authorImage;
377861
377949
  if (entry.importedId !== null && entry.importedId !== publicCommentId)
377862
377950
  info.importedId = entry.importedId;
377863
- let sourceSiblings;
377864
377951
  if (entry.sourceWId) {
377865
377952
  info.rawOoxmlId = entry.sourceWId;
377866
- sourceSiblings = catalog.commentsBySourceWId.get(entry.sourceWId);
377953
+ const sourceSiblings = catalog.commentsBySourceWId.get(entry.sourceWId);
377867
377954
  if (sourceSiblings && sourceSiblings.length > 1) {
377868
377955
  info.rawOoxmlOccurrenceIndex = entry.sourceWIdOccurrenceIndex;
377869
377956
  }
@@ -377901,11 +377988,12 @@ function toCommentInfo(entry, catalog, anchorIndex, headerFooterRels, trackedAss
377901
377988
  if (!info.trackedChange) {
377902
377989
  attachMetadataOnlyTrackedChangeLink(info, entry, anchorIndex ? null : trackedAssociations, metadataAssociation.status !== "unsafe");
377903
377990
  }
377904
- if (anchorIndex && anchorProjectionEntry) {
377991
+ if (anchorIndex) {
377992
+ const anchorProjectionEntry = commentAnchorProjectionEntry(entry, catalog, anchorIndex);
377905
377993
  const hits = anchorIndex.hitsBySourceWId.get(anchorProjectionEntry.sourceWId) ?? [];
377906
377994
  const projectable = hits.filter((h) => h.story.kind === "body" || h.story.kind === "header" || h.story.kind === "footer");
377907
377995
  if (projectable.length > 0) {
377908
- sourceSiblings ?? (sourceSiblings = catalog.commentsBySourceWId.get(anchorProjectionEntry.sourceWId));
377996
+ const sourceSiblings = catalog.commentsBySourceWId.get(anchorProjectionEntry.sourceWId);
377909
377997
  const globalSegmentIndex = sourceSiblings && sourceSiblings.length > 1 ? anchorProjectionEntry.sourceWIdOccurrenceIndex : undefined;
377910
377998
  const projected = projectAnchor(projectable, headerFooterRels, globalSegmentIndex);
377911
377999
  if (projected) {
@@ -482861,6 +482949,25 @@ async function openV2CollaborativeDocumentSession(options) {
482861
482949
  } else {
482862
482950
  trace.mark("source-complete-deferred");
482863
482951
  }
482952
+ if (ownsPreparedBootstrap) {
482953
+ const current = readRoomManifest(rootConn.ydoc);
482954
+ if (current.snapshot?.meta.bootstrapState === "committed") {
482955
+ const committed = options.runtime.validateLateJoin({
482956
+ compatibility: { supports: COLLAB_V2_ROOM_SCHEMA_VERSION },
482957
+ readiness: READINESS_CLASS.bodyEditable
482958
+ });
482959
+ if (!committed.ok)
482960
+ throwLateJoinValidationFailure(committed, options.runtime.rootId);
482961
+ throw new CollabV2DiagnosticError(COLLAB_V2_DIAGNOSTICS.COLLAB_V2_ROOM_ALREADY_EXISTS, "another creator committed this v2 collaboration room during open; reopen with join", { rootId: options.runtime.rootId });
482962
+ }
482963
+ if (current.snapshot?.meta.bootstrapState !== "pending" || current.diagnostics.length > 0) {
482964
+ throw new CollabV2DiagnosticError(COLLAB_V2_DIAGNOSTICS.COLLAB_V2_ROOM_CORRUPT, "prepared v2 collaboration room is no longer a valid pending room; this open did not publish content", { rootId: options.runtime.rootId });
482965
+ }
482966
+ const leader = readBootstrapClaims(rootConn.ydoc).find((claim) => claim.status !== "aborted");
482967
+ if (leader?.claimerId !== expectedClaimerId || leader?.status !== "pending") {
482968
+ throw new CollabV2DiagnosticError(COLLAB_V2_DIAGNOSTICS.COLLAB_V2_ROOM_INITIALIZING, "another creator is initializing this v2 collaboration room", { rootId: options.runtime.rootId });
482969
+ }
482970
+ }
482864
482971
  const canonical = await buildCanonicalShardGraph({
482865
482972
  runtime: options.runtime,
482866
482973
  rootDoc: rootConn.ydoc,
@@ -483395,14 +483502,17 @@ async function buildCanonicalShardGraph(input) {
483395
483502
  for (const { story, shardId, bytes } of stories) {
483396
483503
  let unit;
483397
483504
  if (maySeedStoryShardsFromLocalSource && bytes) {
483398
- unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.story });
483399
- trySeedStoryShard(unit, {
483400
- shardId,
483401
- storyId: story.storyId,
483402
- storyKind: story.storyKind,
483403
- sourcePartUri: story.partUri,
483404
- bytes
483405
- });
483505
+ unit = rootDoc.transact(() => {
483506
+ const created = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.story });
483507
+ trySeedStoryShard(created, {
483508
+ shardId,
483509
+ storyId: story.storyId,
483510
+ storyKind: story.storyKind,
483511
+ sourcePartUri: story.partUri,
483512
+ bytes
483513
+ });
483514
+ return created;
483515
+ }, "collab-v2:bootstrap:seed-unit");
483406
483516
  } else {
483407
483517
  await waitForStoryShardSeeded(rootDoc, shardId);
483408
483518
  unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.story });
@@ -483475,13 +483585,16 @@ async function buildCanonicalShardGraph(input) {
483475
483585
  let commentsHandle = null;
483476
483586
  const commentsShardId = packageShardId2(input.runtime.rootId, SHARD_KIND.comments, COMMENTS_PART_URI6);
483477
483587
  {
483478
- const unit = createCollabUnitHandle({ rootDoc, shardId: commentsShardId, shardKind: SHARD_KIND.comments });
483479
- if (commentsFamily != null) {
483480
- const commentsCatalog = buildCommentsCatalogFromParts(new Map(commentsFamily.parts.flatMap((part) => part.bytes ? [[part.partUri, part.bytes]] : [])));
483481
- trySeedCommentsShard(unit, commentsShardId, commentsCatalog, commentsFamily.partKeys, commentsFamily.parts);
483482
- } else {
483483
- trySeedEmptyCommentsShard(unit, commentsShardId);
483484
- }
483588
+ const unit = rootDoc.transact(() => {
483589
+ const created = createCollabUnitHandle({ rootDoc, shardId: commentsShardId, shardKind: SHARD_KIND.comments });
483590
+ if (commentsFamily != null) {
483591
+ const commentsCatalog = buildCommentsCatalogFromParts(new Map(commentsFamily.parts.flatMap((part) => part.bytes ? [[part.partUri, part.bytes]] : [])));
483592
+ trySeedCommentsShard(created, commentsShardId, commentsCatalog, commentsFamily.partKeys, commentsFamily.parts);
483593
+ } else {
483594
+ trySeedEmptyCommentsShard(created, commentsShardId);
483595
+ }
483596
+ return created;
483597
+ }, "collab-v2:bootstrap:seed-unit");
483485
483598
  projectionHandles.set(commentsShardId, {
483486
483599
  shardId: commentsShardId,
483487
483600
  shardKind: SHARD_KIND.comments,
@@ -483609,243 +483722,259 @@ function subtreePackageHandle(rootDoc, unit, shardKind, bootstrap) {
483609
483722
  };
483610
483723
  }
483611
483724
  async function connectRelationshipsShard(rootDoc, shardId, part) {
483612
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.relationships });
483613
- if (part.bytes) {
483614
- const ownerPartUri2 = ownerPartUriForRels3(part.partUri);
483615
- const xml = TEXT_DECODER12.decode(part.bytes);
483616
- const parsed = parseRelationshipsXml(xml, {
483617
- ownerPartUri: ownerPartUri2,
483618
- relsUri: part.partUri,
483619
- resolveTarget(target, targetMode) {
483620
- return resolveTargetUri(ownerPartUri2, target, targetMode);
483621
- }
483622
- });
483623
- try {
483624
- seedRelationshipsShard({
483625
- doc: unit,
483626
- shardId,
483627
- ownerPartKey: part.partKey,
483725
+ return rootDoc.transact(() => {
483726
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.relationships });
483727
+ if (part.bytes) {
483728
+ const ownerPartUri2 = ownerPartUriForRels3(part.partUri);
483729
+ const xml = TEXT_DECODER12.decode(part.bytes);
483730
+ const parsed = parseRelationshipsXml(xml, {
483628
483731
  ownerPartUri: ownerPartUri2,
483629
- relationships: parsed.relationships.map((relationship) => ({
483630
- rId: relationship.id,
483631
- type: relationship.type,
483632
- target: relationship.target,
483633
- targetMode: relationship.targetMode,
483634
- external: relationship.targetMode === "External"
483635
- }))
483732
+ relsUri: part.partUri,
483733
+ resolveTarget(target, targetMode) {
483734
+ return resolveTargetUri(ownerPartUri2, target, targetMode);
483735
+ }
483636
483736
  });
483637
- } catch (error50) {
483638
- if (!isAlreadySeededError(error50))
483639
- throw error50;
483737
+ try {
483738
+ seedRelationshipsShard({
483739
+ doc: unit,
483740
+ shardId,
483741
+ ownerPartKey: part.partKey,
483742
+ ownerPartUri: ownerPartUri2,
483743
+ relationships: parsed.relationships.map((relationship) => ({
483744
+ rId: relationship.id,
483745
+ type: relationship.type,
483746
+ target: relationship.target,
483747
+ targetMode: relationship.targetMode,
483748
+ external: relationship.targetMode === "External"
483749
+ }))
483750
+ });
483751
+ } catch (error50) {
483752
+ if (!isAlreadySeededError(error50))
483753
+ throw error50;
483754
+ }
483640
483755
  }
483641
- }
483642
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.relationships);
483756
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.relationships);
483757
+ }, "collab-v2:bootstrap:seed-unit");
483643
483758
  }
483644
483759
  async function connectContentTypesShard(rootDoc, shardId, part) {
483645
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.contentTypes });
483646
- if (part.bytes) {
483647
- const parsed = parseContentTypes(TEXT_DECODER12.decode(part.bytes));
483648
- try {
483649
- seedContentTypesShard({
483650
- doc: unit,
483651
- shardId,
483652
- ownerPartKey: part.partKey,
483653
- ownerPartUri: part.partUri,
483654
- defaults: Array.from(parsed.defaults.entries()).map(([extension2, contentType]) => ({
483655
- extension: extension2,
483656
- contentType
483657
- })),
483658
- overrides: Array.from(parsed.overrides.entries()).map(([partKey2, contentType]) => ({
483659
- partKey: partKey2,
483660
- contentType
483661
- }))
483662
- });
483663
- } catch (error50) {
483664
- if (!isAlreadySeededError(error50))
483665
- throw error50;
483760
+ return rootDoc.transact(() => {
483761
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.contentTypes });
483762
+ if (part.bytes) {
483763
+ const parsed = parseContentTypes(TEXT_DECODER12.decode(part.bytes));
483764
+ try {
483765
+ seedContentTypesShard({
483766
+ doc: unit,
483767
+ shardId,
483768
+ ownerPartKey: part.partKey,
483769
+ ownerPartUri: part.partUri,
483770
+ defaults: Array.from(parsed.defaults.entries()).map(([extension2, contentType]) => ({
483771
+ extension: extension2,
483772
+ contentType
483773
+ })),
483774
+ overrides: Array.from(parsed.overrides.entries()).map(([partKey2, contentType]) => ({
483775
+ partKey: partKey2,
483776
+ contentType
483777
+ }))
483778
+ });
483779
+ } catch (error50) {
483780
+ if (!isAlreadySeededError(error50))
483781
+ throw error50;
483782
+ }
483666
483783
  }
483667
- }
483668
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.contentTypes);
483784
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.contentTypes);
483785
+ }, "collab-v2:bootstrap:seed-unit");
483669
483786
  }
483670
483787
  async function connectStylesShard(rootDoc, shardId, part) {
483671
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.styles });
483672
- let bootstrap;
483673
- if (part.bytes) {
483674
- const xml = TEXT_DECODER12.decode(part.bytes);
483675
- const parsed = parseStylesPart3(xml);
483676
- bootstrap = bootstrapPartProjection(xml);
483677
- try {
483678
- seedStylesShard({
483679
- doc: unit,
483680
- shardId,
483681
- ownerPartKey: part.partKey,
483682
- ownerPartUri: part.partUri,
483683
- documentDefaults: parsed.documentDefaults,
483684
- styles: parsed.styles
483685
- });
483686
- } catch (error50) {
483687
- if (!isAlreadySeededError(error50))
483688
- throw error50;
483788
+ return rootDoc.transact(() => {
483789
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.styles });
483790
+ let bootstrap;
483791
+ if (part.bytes) {
483792
+ const xml = TEXT_DECODER12.decode(part.bytes);
483793
+ const parsed = parseStylesPart3(xml);
483794
+ bootstrap = bootstrapPartProjection(xml);
483795
+ try {
483796
+ seedStylesShard({
483797
+ doc: unit,
483798
+ shardId,
483799
+ ownerPartKey: part.partKey,
483800
+ ownerPartUri: part.partUri,
483801
+ documentDefaults: parsed.documentDefaults,
483802
+ styles: parsed.styles
483803
+ });
483804
+ } catch (error50) {
483805
+ if (!isAlreadySeededError(error50))
483806
+ throw error50;
483807
+ }
483689
483808
  }
483690
- }
483691
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.styles, bootstrap);
483809
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.styles, bootstrap);
483810
+ }, "collab-v2:bootstrap:seed-unit");
483692
483811
  }
483693
483812
  async function connectNumberingShard(rootDoc, shardId, part, numbering) {
483694
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.numbering });
483695
- let bootstrap;
483696
- if (part.bytes) {
483697
- bootstrap = bootstrapPartProjection(TEXT_DECODER12.decode(part.bytes));
483698
- }
483699
- if (part.bytes && numbering.present) {
483700
- try {
483701
- seedNumberingShard({
483702
- doc: unit,
483703
- shardId,
483704
- ownerPartKey: part.partKey,
483705
- ownerPartUri: part.partUri,
483706
- abstractNums: Array.from(numbering.abstracts.values()).map((entry) => ({
483707
- abstractNumId: entry.abstractNumId,
483708
- multiLevelType: entry.multiLevelType,
483709
- rawXml: entry.rawXml,
483710
- levels: Array.from(entry.levels.values()).map((level) => ({
483711
- ilvl: level.ilvl,
483712
- numFmt: level.numFmt,
483713
- lvlText: level.lvlText,
483714
- start: level.start,
483715
- opaqueXml: null
483716
- }))
483717
- })),
483718
- nums: Array.from(numbering.instances.values()).map((entry) => ({
483719
- numId: entry.numId,
483720
- abstractNumId: entry.abstractNumId,
483721
- rawXml: entry.rawXml,
483722
- lvlOverrides: Array.from(entry.lvlOverrides.entries()).map(([ilvl, value2]) => ({
483723
- ilvl,
483724
- startOverride: value2.startOverride
483813
+ return rootDoc.transact(() => {
483814
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.numbering });
483815
+ let bootstrap;
483816
+ if (part.bytes) {
483817
+ bootstrap = bootstrapPartProjection(TEXT_DECODER12.decode(part.bytes));
483818
+ }
483819
+ if (part.bytes && numbering.present) {
483820
+ try {
483821
+ seedNumberingShard({
483822
+ doc: unit,
483823
+ shardId,
483824
+ ownerPartKey: part.partKey,
483825
+ ownerPartUri: part.partUri,
483826
+ abstractNums: Array.from(numbering.abstracts.values()).map((entry) => ({
483827
+ abstractNumId: entry.abstractNumId,
483828
+ multiLevelType: entry.multiLevelType,
483829
+ rawXml: entry.rawXml,
483830
+ levels: Array.from(entry.levels.values()).map((level) => ({
483831
+ ilvl: level.ilvl,
483832
+ numFmt: level.numFmt,
483833
+ lvlText: level.lvlText,
483834
+ start: level.start,
483835
+ opaqueXml: null
483836
+ }))
483837
+ })),
483838
+ nums: Array.from(numbering.instances.values()).map((entry) => ({
483839
+ numId: entry.numId,
483840
+ abstractNumId: entry.abstractNumId,
483841
+ rawXml: entry.rawXml,
483842
+ lvlOverrides: Array.from(entry.lvlOverrides.entries()).map(([ilvl, value2]) => ({
483843
+ ilvl,
483844
+ startOverride: value2.startOverride
483845
+ }))
483725
483846
  }))
483726
- }))
483727
- });
483728
- } catch (error50) {
483729
- if (!isAlreadySeededError(error50))
483730
- throw error50;
483847
+ });
483848
+ } catch (error50) {
483849
+ if (!isAlreadySeededError(error50))
483850
+ throw error50;
483851
+ }
483731
483852
  }
483732
- }
483733
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.numbering, bootstrap);
483853
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.numbering, bootstrap);
483854
+ }, "collab-v2:bootstrap:seed-unit");
483734
483855
  }
483735
483856
  async function connectSettingsShard(rootDoc, shardId, settingsPart, webSettingsPart) {
483736
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.settings });
483737
- const settingsBootstrap = settingsPart?.bytes ? bootstrapPartProjection(TEXT_DECODER12.decode(settingsPart.bytes)) : null;
483738
- const webSettingsBootstrap = webSettingsPart?.bytes ? bootstrapPartProjection(TEXT_DECODER12.decode(webSettingsPart.bytes)) : null;
483739
- if (settingsPart?.bytes || webSettingsPart?.bytes) {
483740
- try {
483741
- seedSettingsShard({
483742
- doc: unit,
483743
- shardId,
483744
- ownerPartKey: settingsPart?.partKey ?? encodeLogicalOwnerKey(SETTINGS_PART_URI7),
483745
- ownerPartUri: settingsPart?.partUri ?? SETTINGS_PART_URI7,
483746
- pairedPartKeys: [settingsPart?.partKey, webSettingsPart?.partKey].filter(Boolean),
483747
- settings: {
483748
- fields: {},
483749
- webFields: {},
483750
- opaqueXml: settingsPart?.bytes ? settingsInnerXmlWithNamespaceScope(TEXT_DECODER12.decode(settingsPart.bytes)) : null,
483751
- webOpaqueXml: webSettingsPart?.bytes ? settingsInnerXmlWithNamespaceScope(TEXT_DECODER12.decode(webSettingsPart.bytes)) : null
483752
- }
483753
- });
483754
- } catch (error50) {
483755
- if (!isAlreadySeededError(error50))
483756
- throw error50;
483857
+ return rootDoc.transact(() => {
483858
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.settings });
483859
+ const settingsBootstrap = settingsPart?.bytes ? bootstrapPartProjection(TEXT_DECODER12.decode(settingsPart.bytes)) : null;
483860
+ const webSettingsBootstrap = webSettingsPart?.bytes ? bootstrapPartProjection(TEXT_DECODER12.decode(webSettingsPart.bytes)) : null;
483861
+ if (settingsPart?.bytes || webSettingsPart?.bytes) {
483862
+ try {
483863
+ seedSettingsShard({
483864
+ doc: unit,
483865
+ shardId,
483866
+ ownerPartKey: settingsPart?.partKey ?? encodeLogicalOwnerKey(SETTINGS_PART_URI7),
483867
+ ownerPartUri: settingsPart?.partUri ?? SETTINGS_PART_URI7,
483868
+ pairedPartKeys: [settingsPart?.partKey, webSettingsPart?.partKey].filter(Boolean),
483869
+ settings: {
483870
+ fields: {},
483871
+ webFields: {},
483872
+ opaqueXml: settingsPart?.bytes ? settingsInnerXmlWithNamespaceScope(TEXT_DECODER12.decode(settingsPart.bytes)) : null,
483873
+ webOpaqueXml: webSettingsPart?.bytes ? settingsInnerXmlWithNamespaceScope(TEXT_DECODER12.decode(webSettingsPart.bytes)) : null
483874
+ }
483875
+ });
483876
+ } catch (error50) {
483877
+ if (!isAlreadySeededError(error50))
483878
+ throw error50;
483879
+ }
483757
483880
  }
483758
- }
483759
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.settings, {
483760
- sourceXml: settingsBootstrap?.sourceXml ?? null,
483761
- rootOpenTagXml: settingsBootstrap?.rootOpenTagXml ?? null,
483762
- rootCloseTagXml: settingsBootstrap?.rootCloseTagXml ?? null,
483763
- containerOpenTagXml: webSettingsBootstrap?.rootOpenTagXml ?? null,
483764
- containerCloseTagXml: webSettingsBootstrap?.rootCloseTagXml ?? null
483765
- });
483881
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.settings, {
483882
+ sourceXml: settingsBootstrap?.sourceXml ?? null,
483883
+ rootOpenTagXml: settingsBootstrap?.rootOpenTagXml ?? null,
483884
+ rootCloseTagXml: settingsBootstrap?.rootCloseTagXml ?? null,
483885
+ containerOpenTagXml: webSettingsBootstrap?.rootOpenTagXml ?? null,
483886
+ containerCloseTagXml: webSettingsBootstrap?.rootCloseTagXml ?? null
483887
+ });
483888
+ }, "collab-v2:bootstrap:seed-unit");
483766
483889
  }
483767
483890
  async function connectMediaManifestShard(rootDoc, shardId, parts, session, binaryMode) {
483768
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.mediaManifest });
483769
- const assets = buildMediaAssets(parts, session, binaryMode);
483770
- if (assets.length > 0) {
483771
- try {
483772
- seedMediaManifestShard({
483773
- doc: unit,
483774
- shardId,
483775
- ownerPartKey: encodeLogicalOwnerKey(MEDIA_OWNER_URI2),
483776
- ownerPartUri: MEDIA_OWNER_URI2,
483777
- assets
483778
- });
483779
- } catch (error50) {
483780
- if (!isAlreadySeededError(error50))
483781
- throw error50;
483891
+ return rootDoc.transact(() => {
483892
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.mediaManifest });
483893
+ const assets = buildMediaAssets(parts, session, binaryMode);
483894
+ if (assets.length > 0) {
483895
+ try {
483896
+ seedMediaManifestShard({
483897
+ doc: unit,
483898
+ shardId,
483899
+ ownerPartKey: encodeLogicalOwnerKey(MEDIA_OWNER_URI2),
483900
+ ownerPartUri: MEDIA_OWNER_URI2,
483901
+ assets
483902
+ });
483903
+ } catch (error50) {
483904
+ if (!isAlreadySeededError(error50))
483905
+ throw error50;
483906
+ }
483782
483907
  }
483783
- }
483784
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.mediaManifest);
483908
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.mediaManifest);
483909
+ }, "collab-v2:bootstrap:seed-unit");
483785
483910
  }
483786
483911
  async function connectBinaryShard(rootDoc, shardId, part, assetId, binaryMode, blobStore) {
483787
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.binary });
483788
- if (part.bytes) {
483789
- try {
483790
- const payload = prepareSingleDocBinaryPayload(part.bytes, binaryMode, blobStore);
483791
- seedBinaryShard({
483792
- doc: unit,
483793
- shardId,
483794
- ownerPartKey: part.partKey,
483795
- ownerPartUri: part.partUri,
483796
- assetId,
483797
- mode: payload.mode,
483798
- contentType: part.contentType ?? "",
483799
- ...payload.mode === BINARY_MODE.blob ? {
483800
- blobRef: payload.blobRef,
483801
- sha256: payload.sha256,
483802
- byteLength: payload.byteLength
483803
- } : {
483804
- bytes: payload.bytes,
483805
- sha256: payload.sha256
483806
- }
483807
- });
483808
- } catch (error50) {
483809
- if (!isAlreadySeededError(error50))
483810
- throw error50;
483912
+ return rootDoc.transact(() => {
483913
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.binary });
483914
+ if (part.bytes) {
483915
+ try {
483916
+ const payload = prepareSingleDocBinaryPayload(part.bytes, binaryMode, blobStore);
483917
+ seedBinaryShard({
483918
+ doc: unit,
483919
+ shardId,
483920
+ ownerPartKey: part.partKey,
483921
+ ownerPartUri: part.partUri,
483922
+ assetId,
483923
+ mode: payload.mode,
483924
+ contentType: part.contentType ?? "",
483925
+ ...payload.mode === BINARY_MODE.blob ? {
483926
+ blobRef: payload.blobRef,
483927
+ sha256: payload.sha256,
483928
+ byteLength: payload.byteLength
483929
+ } : {
483930
+ bytes: payload.bytes,
483931
+ sha256: payload.sha256
483932
+ }
483933
+ });
483934
+ } catch (error50) {
483935
+ if (!isAlreadySeededError(error50))
483936
+ throw error50;
483937
+ }
483811
483938
  }
483812
- }
483813
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.binary);
483939
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.binary);
483940
+ }, "collab-v2:bootstrap:seed-unit");
483814
483941
  }
483815
483942
  async function connectOpaqueShard(rootDoc, shardId, part, sourceZipSha256, binaryMode, blobStore) {
483816
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.opaquePart });
483817
- if (part.bytes) {
483818
- try {
483819
- const payload = prepareSingleDocBinaryPayload(part.bytes, binaryMode, blobStore);
483820
- seedOpaquePartShard({
483821
- doc: unit,
483822
- shardId,
483823
- ownerPartKey: part.partKey,
483824
- ownerPartUri: part.partUri,
483825
- partKey: part.partKey,
483826
- partUri: part.partUri,
483827
- contentType: part.contentType,
483828
- mode: payload.mode,
483829
- ...payload.mode === BINARY_MODE.blob ? {
483830
- blobRef: payload.blobRef,
483831
- sha256: payload.sha256,
483832
- byteLength: payload.byteLength
483833
- } : {
483834
- bytes: payload.bytes,
483835
- sha256: payload.sha256
483836
- },
483837
- sourceProvenance: {
483838
- sha256Zip: sourceZipSha256,
483839
- committedAt: null,
483840
- committerId: null
483841
- }
483842
- });
483843
- } catch (error50) {
483844
- if (!isAlreadySeededError(error50))
483845
- throw error50;
483943
+ return rootDoc.transact(() => {
483944
+ const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.opaquePart });
483945
+ if (part.bytes) {
483946
+ try {
483947
+ const payload = prepareSingleDocBinaryPayload(part.bytes, binaryMode, blobStore);
483948
+ seedOpaquePartShard({
483949
+ doc: unit,
483950
+ shardId,
483951
+ ownerPartKey: part.partKey,
483952
+ ownerPartUri: part.partUri,
483953
+ partKey: part.partKey,
483954
+ partUri: part.partUri,
483955
+ contentType: part.contentType,
483956
+ mode: payload.mode,
483957
+ ...payload.mode === BINARY_MODE.blob ? {
483958
+ blobRef: payload.blobRef,
483959
+ sha256: payload.sha256,
483960
+ byteLength: payload.byteLength
483961
+ } : {
483962
+ bytes: payload.bytes,
483963
+ sha256: payload.sha256
483964
+ },
483965
+ sourceProvenance: {
483966
+ sha256Zip: sourceZipSha256,
483967
+ committedAt: null,
483968
+ committerId: null
483969
+ }
483970
+ });
483971
+ } catch (error50) {
483972
+ if (!isAlreadySeededError(error50))
483973
+ throw error50;
483974
+ }
483846
483975
  }
483847
- }
483848
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.opaquePart);
483976
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.opaquePart);
483977
+ }, "collab-v2:bootstrap:seed-unit");
483849
483978
  }
483850
483979
  function storyProjectionHandle(handle) {
483851
483980
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.9.0-next.11",
3
+ "version": "1.9.0-next.12",
4
4
  "description": "Model Context Protocol server for SuperDoc, giving an AI agent tools to read and edit .docx files.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -24,13 +24,13 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/sdk": "^1.26.0",
27
- "@superdoc/sdk": "2.22.0-next.11",
27
+ "@superdoc/sdk": "2.22.0-next.12",
28
28
  "debug": "^4.4.3",
29
29
  "zod": "^4.3.6"
30
30
  },
31
31
  "devDependencies": {
32
- "superdoc": "2.25.0-next.11",
33
- "@superdoc/docx-engine": "0.24.0-next.11",
32
+ "superdoc": "2.25.0-next.12",
33
+ "@superdoc/docx-engine": "0.24.0-next.12",
34
34
  "@superdoc/document-api": "0.1.0-alpha.0",
35
35
  "@types/bun": "^1.3.8",
36
36
  "@types/node": "22.19.2",