@superdoc/mcp 1.9.0-next.10 → 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 +522 -332
  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.10";
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");
@@ -186198,7 +186234,7 @@ function captureCooperativeTrackedCatalogRead(state, mode, assertActive) {
186198
186234
  numberingCatalog: listContext.numberingCatalog,
186199
186235
  styleNumberingIndex: listContext.styleIndex,
186200
186236
  stylesStatus: listContext.stylesStatus,
186201
- textboxRegistryRecords: state.textboxRegistry.records
186237
+ textboxRegistryRecords: Array.from(state.textboxRegistry.records)
186202
186238
  });
186203
186239
  let released = false, building = false;
186204
186240
  const check2 = () => {
@@ -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/;
@@ -314315,6 +314387,7 @@ function computeFieldResult(context, instruction, options = {}) {
314315
314387
  }
314316
314388
  switch (keyword) {
314317
314389
  case "PAGE":
314390
+ return resolvePageFieldText(context, options.currentField ?? options.pageLocation, instruction);
314318
314391
  case "PAGEREF":
314319
314392
  return resolvePageFieldText(context, options.currentField);
314320
314393
  case "NUMPAGES":
@@ -315934,32 +316007,60 @@ function readPreservedTocPageByText(preserved, text) {
315934
316007
  function normalizeGeneratedTocHeadingText(text) {
315935
316008
  return text.replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim();
315936
316009
  }
315937
- function resolvePageFieldText(context, currentField) {
316010
+ function resolvePageFieldText(context, currentField, instruction) {
316011
+ const format = (page, sectionFormat) => instruction == null ? String(page) : formatPageFieldNumber(page, instruction, sectionFormat);
315938
316012
  if (!currentField)
315939
- return "1";
316013
+ return format(1);
315940
316014
  const pages = estimateDocumentPages(context);
315941
316015
  if (!currentField.storyId.startsWith("header:") && !currentField.storyId.startsWith("footer:")) {
315942
- return String(pages.displayPageByBlockId.get(currentField.blockId) ?? 1);
316016
+ return format(pages.displayPageByBlockId.get(currentField.blockId) ?? 1, pages.numberFormatByBlockId.get(currentField.blockId));
315943
316017
  }
315944
316018
  const snapshot2 = getSDDocumentSessionInternalSourceSignalsSnapshot(context.session);
315945
316019
  const main = snapshot2?.stories.find((story) => story.storyKind === "main");
315946
316020
  if (!main)
315947
- return "1";
316021
+ return format(1);
315948
316022
  const kind = currentField.storyId.startsWith("header:") ? "header" : "footer";
315949
316023
  const liveSections = readLiveSectionSignals(context);
315950
316024
  const rel = listSDDocumentSessionInternalHeaderFooterRels(context.session).find((candidate2) => candidate2.partUri === currentField.partUri);
315951
316025
  if (!rel)
315952
- return "1";
316026
+ return format(1);
315953
316027
  for (const section of liveSections) {
315954
316028
  const ref5 = section.headerFooterRefs.find((candidate2) => candidate2.kind === kind && candidate2.relationshipId === rel.refId);
315955
316029
  if (!ref5)
315956
316030
  continue;
315957
316031
  const sectionPages = pages.sectionById.get(section.sectionId);
315958
316032
  if (!sectionPages)
315959
- return "1";
315960
- return String(sectionPages.startDisplayPage + headerFooterPageOffset(ref5.variant, sectionPages.startDisplayPage, sectionPages.pageCount, sectionPages.titlePage, sectionPages.pageNumberingMode));
316033
+ return format(1);
316034
+ return format(sectionPages.startDisplayPage + headerFooterPageOffset(ref5.variant, sectionPages.startDisplayPage, sectionPages.pageCount, sectionPages.titlePage, sectionPages.pageNumberingMode), section.pageNumbering.format);
316035
+ }
316036
+ return format(1);
316037
+ }
316038
+ function formatPageFieldNumber(page, instruction, sectionFormat) {
316039
+ let format = sectionFormat ?? "decimal";
316040
+ for (const match of instruction.matchAll(/(?:^|\s)\\\*\s*(?:"([^"]*)"|([^\s"]+))/g)) {
316041
+ const value2 = match[1] ?? match[2];
316042
+ switch (value2.toLowerCase()) {
316043
+ case "roman":
316044
+ format = value2[0] === "r" ? "lowerRoman" : "upperRoman";
316045
+ break;
316046
+ case "alphabetic":
316047
+ format = value2[0] === "a" ? "lowerLetter" : "upperLetter";
316048
+ break;
316049
+ case "arabic":
316050
+ format = "decimal";
316051
+ break;
316052
+ case "arabicdash":
316053
+ format = "numberInDash";
316054
+ break;
316055
+ }
316056
+ }
316057
+ if (format === "numberInDash")
316058
+ return `- ${page} -`;
316059
+ if ((format === "upperLetter" || format === "lowerLetter") && page > 0) {
316060
+ const letter = String.fromCharCode(65 + (page - 1) % 26).repeat(Math.floor((page - 1) / 26) + 1);
316061
+ return format === "lowerLetter" ? letter.toLowerCase() : letter;
315961
316062
  }
315962
- return "1";
316063
+ return formatNumberingOrdinal(page, format);
315963
316064
  }
315964
316065
  function headerFooterPageOffset(variant, startDisplayPage, pageCount, titlePage, pageNumberingMode = "unknown") {
315965
316066
  const firstBodyPageOffset = titlePage && pageCount > 1 && (pageNumberingMode === "restart" || pageNumberingMode === "invalid") ? 1 : 0;
@@ -315977,11 +316078,12 @@ function headerFooterPageOffset(variant, startDisplayPage, pageCount, titlePage,
315977
316078
  function estimateDocumentPages(context) {
315978
316079
  const physicalPageByBlockId = new Map;
315979
316080
  const displayPageByBlockId = new Map;
316081
+ const numberFormatByBlockId = new Map;
315980
316082
  const sectionById = new Map;
315981
316083
  const snapshot2 = getSDDocumentSessionInternalSourceSignalsSnapshot(context.session);
315982
316084
  const main = snapshot2?.stories.find((story) => story.storyKind === "main");
315983
316085
  if (!main)
315984
- return { physicalPageByBlockId, displayPageByBlockId, sectionById };
316086
+ return { physicalPageByBlockId, displayPageByBlockId, numberFormatByBlockId, sectionById };
315985
316087
  const sections = readLiveSectionSignals(context);
315986
316088
  const liveBody = readLiveBodyPageSignals(context);
315987
316089
  const paragraphOrdinals = main.paragraphIndex.map((signal, index) => ({
@@ -316018,9 +316120,10 @@ function estimateDocumentPages(context) {
316018
316120
  const priorBreaks = breaksInSection.filter((entry) => entry.bodyChildOrdinal < paragraph2.ordinal || entry.bodyChildOrdinal === paragraph2.ordinal && entry.source === "paragraph-page-break-before").length;
316019
316121
  physicalPageByBlockId.set(paragraph2.blockId, startPhysicalPage + priorBreaks);
316020
316122
  displayPageByBlockId.set(paragraph2.blockId, startDisplayPage + priorBreaks);
316123
+ numberFormatByBlockId.set(paragraph2.blockId, section.pageNumbering.format);
316021
316124
  }
316022
316125
  }
316023
- return { physicalPageByBlockId, displayPageByBlockId, sectionById };
316126
+ return { physicalPageByBlockId, displayPageByBlockId, numberFormatByBlockId, sectionById };
316024
316127
  }
316025
316128
  function readLiveBodyPageSignals(context) {
316026
316129
  const documentBytes = getSDDocumentSessionInternalPartBytes(context.session, "/word/document.xml");
@@ -377801,13 +377904,29 @@ function resolveCommentEntryByParaId(catalog, paraId) {
377801
377904
  return null;
377802
377905
  return catalog.commentsByCommentId.get(canonicalCommentId) ?? null;
377803
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
+ }
377804
377924
  function toCommentInfo(entry, catalog, anchorIndex, headerFooterRels, trackedAssociations) {
377805
377925
  const publicCommentId = publicCommentIdForEntry(entry);
377806
377926
  const parentParaId = entry.parentParaId;
377807
377927
  const parentEntry = parentParaId ? resolveCommentEntryByParaId(catalog, parentParaId) : null;
377808
377928
  const parentCommentId = parentEntry ? publicCommentIdForEntry(parentEntry) : undefined;
377809
377929
  const rootCommentId = parentCommentId ? rootCommentIdForCatalogEntry(entry, catalog) : null;
377810
- const anchorProjectionEntry = entry;
377811
377930
  const info = {
377812
377931
  address: { kind: "entity", entityType: "comment", entityId: publicCommentId },
377813
377932
  commentId: publicCommentId,
@@ -377829,10 +377948,9 @@ function toCommentInfo(entry, catalog, anchorIndex, headerFooterRels, trackedAss
377829
377948
  info.creatorImage = entry.authorImage;
377830
377949
  if (entry.importedId !== null && entry.importedId !== publicCommentId)
377831
377950
  info.importedId = entry.importedId;
377832
- let sourceSiblings;
377833
377951
  if (entry.sourceWId) {
377834
377952
  info.rawOoxmlId = entry.sourceWId;
377835
- sourceSiblings = catalog.commentsBySourceWId.get(entry.sourceWId);
377953
+ const sourceSiblings = catalog.commentsBySourceWId.get(entry.sourceWId);
377836
377954
  if (sourceSiblings && sourceSiblings.length > 1) {
377837
377955
  info.rawOoxmlOccurrenceIndex = entry.sourceWIdOccurrenceIndex;
377838
377956
  }
@@ -377870,11 +377988,12 @@ function toCommentInfo(entry, catalog, anchorIndex, headerFooterRels, trackedAss
377870
377988
  if (!info.trackedChange) {
377871
377989
  attachMetadataOnlyTrackedChangeLink(info, entry, anchorIndex ? null : trackedAssociations, metadataAssociation.status !== "unsafe");
377872
377990
  }
377873
- if (anchorIndex && anchorProjectionEntry) {
377991
+ if (anchorIndex) {
377992
+ const anchorProjectionEntry = commentAnchorProjectionEntry(entry, catalog, anchorIndex);
377874
377993
  const hits = anchorIndex.hitsBySourceWId.get(anchorProjectionEntry.sourceWId) ?? [];
377875
377994
  const projectable = hits.filter((h) => h.story.kind === "body" || h.story.kind === "header" || h.story.kind === "footer");
377876
377995
  if (projectable.length > 0) {
377877
- sourceSiblings ?? (sourceSiblings = catalog.commentsBySourceWId.get(anchorProjectionEntry.sourceWId));
377996
+ const sourceSiblings = catalog.commentsBySourceWId.get(anchorProjectionEntry.sourceWId);
377878
377997
  const globalSegmentIndex = sourceSiblings && sourceSiblings.length > 1 ? anchorProjectionEntry.sourceWIdOccurrenceIndex : undefined;
377879
377998
  const projected = projectAnchor(projectable, headerFooterRels, globalSegmentIndex);
377880
377999
  if (projected) {
@@ -379066,8 +379185,17 @@ class V2TrackedChangesAdapter {
379066
379185
  items: [],
379067
379186
  unresolvedTrackedChangeIds: [...new Set(requestedIds)]
379068
379187
  };
379069
- const sourceFilter = source && { ...source, structuralScope: structuralScope ?? undefined };
379070
379188
  const resolveSession = createTrackedChangeFragmentResolveSession();
379189
+ const range = source?.textRange;
379190
+ const validTextRange = range && Number.isSafeInteger(range.start) && Number.isSafeInteger(range.end) && range.start >= 0 && range.end > range.start;
379191
+ const sourceFilter = source && {
379192
+ ...source,
379193
+ structuralScope: structuralScope ?? undefined,
379194
+ matchesTextFragment: validTextRange ? (fragment4) => {
379195
+ const resolved = resolveTrackedChangeFragmentTextTarget(this.context, fragment4, "tracked", story, resolveSession);
379196
+ return resolved.ok && resolved.normalizedTarget.segments.some((segment) => segment.blockId === range.blockId && segment.range.start <= range.start && range.end <= segment.range.end);
379197
+ } : undefined
379198
+ };
379071
379199
  const seenInput = new Set;
379072
379200
  const seenCanonical = new Set;
379073
379201
  const orderedRequestedIds = [];
@@ -382043,6 +382171,11 @@ function resolveReviewSnapshotOwner(logical, entry) {
382043
382171
  function reviewSnapshotEntryMatchesSource(entry, source, requestedId) {
382044
382172
  if (source?.partUri && entry.partUri !== source.partUri)
382045
382173
  return false;
382174
+ if (source?.textRange) {
382175
+ const aliases = requestedId ? reviewSnapshotRequestedIdAliases(requestedId) : [];
382176
+ if (!entry.fragments.some((fragment4) => (requestedId === entry.id || aliases.includes(fragment4.wId) || aliases.includes(fragment4.rsid)) && (source.kind === "insert" ? fragment4.kind === "ins" || fragment4.kind === "moveTo" : source.kind === "delete" ? fragment4.kind === "del" || fragment4.kind === "moveFrom" : false) && source.matchesTextFragment?.(fragment4)))
382177
+ return false;
382178
+ }
382046
382179
  if (source?.structuralScope) {
382047
382180
  const scope = source.structuralScope;
382048
382181
  const aliases = requestedId ? reviewSnapshotRequestedIdAliases(requestedId) : [];
@@ -389529,15 +389662,16 @@ class V2FieldsAdapter {
389529
389662
  const resolved = resolveInsertTarget(this.context, input.at, options);
389530
389663
  if ("failure" in resolved)
389531
389664
  return mutationFailure2(resolved.failure.code, resolved.failure.message);
389665
+ const paragraph4 = findParagraphInStory(this.context, resolved.range.storyId, resolved.range.startBlockId);
389666
+ if (!paragraph4)
389667
+ return mutationFailure2("TARGET_NOT_FOUND", `Paragraph "${resolved.range.startBlockId}" was not found.`);
389532
389668
  const beforeFieldEntries = listCanonicalFieldEntries(this.context);
389533
389669
  const beforeFieldIds = new Set(beforeFieldEntries.map((entry) => entry.stableFieldId));
389534
389670
  const preserveCached = input.updatePolicy === "preserveCached" && typeof input.cachedResultText === "string";
389535
389671
  const resultText = preserveCached ? input.cachedResultText : computeFieldResult(this.context, input.instruction, {
389672
+ pageLocation: paragraph4,
389536
389673
  seqFallbackLabel: parseSeqFallbackLabel(input.instruction)
389537
389674
  });
389538
- const paragraph4 = findParagraphInStory(this.context, resolved.range.storyId, resolved.range.startBlockId);
389539
- if (!paragraph4)
389540
- return mutationFailure2("TARGET_NOT_FOUND", `Paragraph "${resolved.range.startBlockId}" was not found.`);
389541
389675
  const selectedText = paragraph4.text.slice(resolved.range.startOffset, resolved.range.endOffset);
389542
389676
  const replaceSelection = resolved.range.endOffset > resolved.range.startOffset && selectedText === resultText;
389543
389677
  let fieldXml = preserveCached ? buildPreservedCachedFieldXml(input.instruction, resultText) : options?.changeMode === "tracked" ? buildComplexFieldTextXml(input.instruction, resultText) : buildSimpleFieldXml(input.instruction, resultText);
@@ -478713,6 +478847,9 @@ function createHeadlessCollabRoomCoordinator(options) {
478713
478847
  let syncingManifest = false;
478714
478848
  let registryChangedDuringSync = false;
478715
478849
  let packageParts = getPackagePartsMap(options.rootDoc);
478850
+ const numberingPartKey = encodeLogicalOwnerKey(NUMBERING_PART_URI7);
478851
+ const numberingShardId = packageShardId(options.rootId, SHARD_KIND.numbering, NUMBERING_PART_URI7);
478852
+ let numberingDeletionObserved = false;
478716
478853
  const meta3 = getMetaMap(options.rootDoc);
478717
478854
  const packageSelection = options.rootDoc.getMap(ROOT_MAP.package);
478718
478855
  const observedReplacements = new Set;
@@ -478727,9 +478864,19 @@ function createHeadlessCollabRoomCoordinator(options) {
478727
478864
  return changed;
478728
478865
  }
478729
478866
  observeReplacementCommits();
478730
- const manifestObserver = () => {
478867
+ const manifestObserver = (event) => {
478731
478868
  if (disposed)
478732
478869
  return;
478870
+ if (event.target === packageParts) {
478871
+ for (const [partKey2, change] of event.changes.keys) {
478872
+ if (change.action !== "delete")
478873
+ continue;
478874
+ const previous3 = toManifestPartDescriptor(partKey2, change.oldValue);
478875
+ if (previous3?.partKind === "numbering" && previous3.partUri === NUMBERING_PART_URI7 && partKey2 === numberingPartKey) {
478876
+ numberingDeletionObserved = true;
478877
+ }
478878
+ }
478879
+ }
478733
478880
  const replacementCommitted = observeReplacementCommits();
478734
478881
  if (replacementCommitted)
478735
478882
  pruneReplacedRoomOrphans(options.rootDoc);
@@ -479876,7 +480023,8 @@ function createHeadlessCollabRoomCoordinator(options) {
479876
480023
  for (const [shardId, handle] of options.graph.projectionHandles.entries()) {
479877
480024
  if (activeShardIds.has(shardId))
479878
480025
  continue;
479879
- if (!replacingPackage && !isManifestPrunableProjectionHandle(handle))
480026
+ const explicitlyRetiredNumbering = handle.shardKind === SHARD_KIND.numbering && shardId === numberingShardId && numberingDeletionObserved;
480027
+ if (!replacingPackage && !explicitlyRetiredNumbering && !isManifestPrunableProjectionHandle(handle))
479880
480028
  continue;
479881
480029
  options.graph.projectionHandles.delete(shardId);
479882
480030
  options.graph.requiredShardIds.delete(shardId);
@@ -479884,6 +480032,7 @@ function createHeadlessCollabRoomCoordinator(options) {
479884
480032
  options.graph.commentsHandle = null;
479885
480033
  changed = true;
479886
480034
  }
480035
+ numberingDeletionObserved = false;
479887
480036
  if (changed)
479888
480037
  notifyRegistryChangedIfActive();
479889
480038
  }
@@ -482800,6 +482949,25 @@ async function openV2CollaborativeDocumentSession(options) {
482800
482949
  } else {
482801
482950
  trace.mark("source-complete-deferred");
482802
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
+ }
482803
482971
  const canonical = await buildCanonicalShardGraph({
482804
482972
  runtime: options.runtime,
482805
482973
  rootDoc: rootConn.ydoc,
@@ -483334,14 +483502,17 @@ async function buildCanonicalShardGraph(input) {
483334
483502
  for (const { story, shardId, bytes } of stories) {
483335
483503
  let unit;
483336
483504
  if (maySeedStoryShardsFromLocalSource && bytes) {
483337
- unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.story });
483338
- trySeedStoryShard(unit, {
483339
- shardId,
483340
- storyId: story.storyId,
483341
- storyKind: story.storyKind,
483342
- sourcePartUri: story.partUri,
483343
- bytes
483344
- });
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");
483345
483516
  } else {
483346
483517
  await waitForStoryShardSeeded(rootDoc, shardId);
483347
483518
  unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.story });
@@ -483414,13 +483585,16 @@ async function buildCanonicalShardGraph(input) {
483414
483585
  let commentsHandle = null;
483415
483586
  const commentsShardId = packageShardId2(input.runtime.rootId, SHARD_KIND.comments, COMMENTS_PART_URI6);
483416
483587
  {
483417
- const unit = createCollabUnitHandle({ rootDoc, shardId: commentsShardId, shardKind: SHARD_KIND.comments });
483418
- if (commentsFamily != null) {
483419
- const commentsCatalog = buildCommentsCatalogFromParts(new Map(commentsFamily.parts.flatMap((part) => part.bytes ? [[part.partUri, part.bytes]] : [])));
483420
- trySeedCommentsShard(unit, commentsShardId, commentsCatalog, commentsFamily.partKeys, commentsFamily.parts);
483421
- } else {
483422
- trySeedEmptyCommentsShard(unit, commentsShardId);
483423
- }
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");
483424
483598
  projectionHandles.set(commentsShardId, {
483425
483599
  shardId: commentsShardId,
483426
483600
  shardKind: SHARD_KIND.comments,
@@ -483548,243 +483722,259 @@ function subtreePackageHandle(rootDoc, unit, shardKind, bootstrap) {
483548
483722
  };
483549
483723
  }
483550
483724
  async function connectRelationshipsShard(rootDoc, shardId, part) {
483551
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.relationships });
483552
- if (part.bytes) {
483553
- const ownerPartUri2 = ownerPartUriForRels3(part.partUri);
483554
- const xml = TEXT_DECODER12.decode(part.bytes);
483555
- const parsed = parseRelationshipsXml(xml, {
483556
- ownerPartUri: ownerPartUri2,
483557
- relsUri: part.partUri,
483558
- resolveTarget(target, targetMode) {
483559
- return resolveTargetUri(ownerPartUri2, target, targetMode);
483560
- }
483561
- });
483562
- try {
483563
- seedRelationshipsShard({
483564
- doc: unit,
483565
- shardId,
483566
- 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, {
483567
483731
  ownerPartUri: ownerPartUri2,
483568
- relationships: parsed.relationships.map((relationship) => ({
483569
- rId: relationship.id,
483570
- type: relationship.type,
483571
- target: relationship.target,
483572
- targetMode: relationship.targetMode,
483573
- external: relationship.targetMode === "External"
483574
- }))
483732
+ relsUri: part.partUri,
483733
+ resolveTarget(target, targetMode) {
483734
+ return resolveTargetUri(ownerPartUri2, target, targetMode);
483735
+ }
483575
483736
  });
483576
- } catch (error50) {
483577
- if (!isAlreadySeededError(error50))
483578
- 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
+ }
483579
483755
  }
483580
- }
483581
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.relationships);
483756
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.relationships);
483757
+ }, "collab-v2:bootstrap:seed-unit");
483582
483758
  }
483583
483759
  async function connectContentTypesShard(rootDoc, shardId, part) {
483584
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.contentTypes });
483585
- if (part.bytes) {
483586
- const parsed = parseContentTypes(TEXT_DECODER12.decode(part.bytes));
483587
- try {
483588
- seedContentTypesShard({
483589
- doc: unit,
483590
- shardId,
483591
- ownerPartKey: part.partKey,
483592
- ownerPartUri: part.partUri,
483593
- defaults: Array.from(parsed.defaults.entries()).map(([extension2, contentType]) => ({
483594
- extension: extension2,
483595
- contentType
483596
- })),
483597
- overrides: Array.from(parsed.overrides.entries()).map(([partKey2, contentType]) => ({
483598
- partKey: partKey2,
483599
- contentType
483600
- }))
483601
- });
483602
- } catch (error50) {
483603
- if (!isAlreadySeededError(error50))
483604
- 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
+ }
483605
483783
  }
483606
- }
483607
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.contentTypes);
483784
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.contentTypes);
483785
+ }, "collab-v2:bootstrap:seed-unit");
483608
483786
  }
483609
483787
  async function connectStylesShard(rootDoc, shardId, part) {
483610
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.styles });
483611
- let bootstrap;
483612
- if (part.bytes) {
483613
- const xml = TEXT_DECODER12.decode(part.bytes);
483614
- const parsed = parseStylesPart3(xml);
483615
- bootstrap = bootstrapPartProjection(xml);
483616
- try {
483617
- seedStylesShard({
483618
- doc: unit,
483619
- shardId,
483620
- ownerPartKey: part.partKey,
483621
- ownerPartUri: part.partUri,
483622
- documentDefaults: parsed.documentDefaults,
483623
- styles: parsed.styles
483624
- });
483625
- } catch (error50) {
483626
- if (!isAlreadySeededError(error50))
483627
- 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
+ }
483628
483808
  }
483629
- }
483630
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.styles, bootstrap);
483809
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.styles, bootstrap);
483810
+ }, "collab-v2:bootstrap:seed-unit");
483631
483811
  }
483632
483812
  async function connectNumberingShard(rootDoc, shardId, part, numbering) {
483633
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.numbering });
483634
- let bootstrap;
483635
- if (part.bytes) {
483636
- bootstrap = bootstrapPartProjection(TEXT_DECODER12.decode(part.bytes));
483637
- }
483638
- if (part.bytes && numbering.present) {
483639
- try {
483640
- seedNumberingShard({
483641
- doc: unit,
483642
- shardId,
483643
- ownerPartKey: part.partKey,
483644
- ownerPartUri: part.partUri,
483645
- abstractNums: Array.from(numbering.abstracts.values()).map((entry) => ({
483646
- abstractNumId: entry.abstractNumId,
483647
- multiLevelType: entry.multiLevelType,
483648
- rawXml: entry.rawXml,
483649
- levels: Array.from(entry.levels.values()).map((level) => ({
483650
- ilvl: level.ilvl,
483651
- numFmt: level.numFmt,
483652
- lvlText: level.lvlText,
483653
- start: level.start,
483654
- opaqueXml: null
483655
- }))
483656
- })),
483657
- nums: Array.from(numbering.instances.values()).map((entry) => ({
483658
- numId: entry.numId,
483659
- abstractNumId: entry.abstractNumId,
483660
- rawXml: entry.rawXml,
483661
- lvlOverrides: Array.from(entry.lvlOverrides.entries()).map(([ilvl, value2]) => ({
483662
- ilvl,
483663
- 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
+ }))
483664
483846
  }))
483665
- }))
483666
- });
483667
- } catch (error50) {
483668
- if (!isAlreadySeededError(error50))
483669
- throw error50;
483847
+ });
483848
+ } catch (error50) {
483849
+ if (!isAlreadySeededError(error50))
483850
+ throw error50;
483851
+ }
483670
483852
  }
483671
- }
483672
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.numbering, bootstrap);
483853
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.numbering, bootstrap);
483854
+ }, "collab-v2:bootstrap:seed-unit");
483673
483855
  }
483674
483856
  async function connectSettingsShard(rootDoc, shardId, settingsPart, webSettingsPart) {
483675
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.settings });
483676
- const settingsBootstrap = settingsPart?.bytes ? bootstrapPartProjection(TEXT_DECODER12.decode(settingsPart.bytes)) : null;
483677
- const webSettingsBootstrap = webSettingsPart?.bytes ? bootstrapPartProjection(TEXT_DECODER12.decode(webSettingsPart.bytes)) : null;
483678
- if (settingsPart?.bytes || webSettingsPart?.bytes) {
483679
- try {
483680
- seedSettingsShard({
483681
- doc: unit,
483682
- shardId,
483683
- ownerPartKey: settingsPart?.partKey ?? encodeLogicalOwnerKey(SETTINGS_PART_URI7),
483684
- ownerPartUri: settingsPart?.partUri ?? SETTINGS_PART_URI7,
483685
- pairedPartKeys: [settingsPart?.partKey, webSettingsPart?.partKey].filter(Boolean),
483686
- settings: {
483687
- fields: {},
483688
- webFields: {},
483689
- opaqueXml: settingsPart?.bytes ? settingsInnerXmlWithNamespaceScope(TEXT_DECODER12.decode(settingsPart.bytes)) : null,
483690
- webOpaqueXml: webSettingsPart?.bytes ? settingsInnerXmlWithNamespaceScope(TEXT_DECODER12.decode(webSettingsPart.bytes)) : null
483691
- }
483692
- });
483693
- } catch (error50) {
483694
- if (!isAlreadySeededError(error50))
483695
- 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
+ }
483696
483880
  }
483697
- }
483698
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.settings, {
483699
- sourceXml: settingsBootstrap?.sourceXml ?? null,
483700
- rootOpenTagXml: settingsBootstrap?.rootOpenTagXml ?? null,
483701
- rootCloseTagXml: settingsBootstrap?.rootCloseTagXml ?? null,
483702
- containerOpenTagXml: webSettingsBootstrap?.rootOpenTagXml ?? null,
483703
- containerCloseTagXml: webSettingsBootstrap?.rootCloseTagXml ?? null
483704
- });
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");
483705
483889
  }
483706
483890
  async function connectMediaManifestShard(rootDoc, shardId, parts, session, binaryMode) {
483707
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.mediaManifest });
483708
- const assets = buildMediaAssets(parts, session, binaryMode);
483709
- if (assets.length > 0) {
483710
- try {
483711
- seedMediaManifestShard({
483712
- doc: unit,
483713
- shardId,
483714
- ownerPartKey: encodeLogicalOwnerKey(MEDIA_OWNER_URI2),
483715
- ownerPartUri: MEDIA_OWNER_URI2,
483716
- assets
483717
- });
483718
- } catch (error50) {
483719
- if (!isAlreadySeededError(error50))
483720
- 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
+ }
483721
483907
  }
483722
- }
483723
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.mediaManifest);
483908
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.mediaManifest);
483909
+ }, "collab-v2:bootstrap:seed-unit");
483724
483910
  }
483725
483911
  async function connectBinaryShard(rootDoc, shardId, part, assetId, binaryMode, blobStore) {
483726
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.binary });
483727
- if (part.bytes) {
483728
- try {
483729
- const payload = prepareSingleDocBinaryPayload(part.bytes, binaryMode, blobStore);
483730
- seedBinaryShard({
483731
- doc: unit,
483732
- shardId,
483733
- ownerPartKey: part.partKey,
483734
- ownerPartUri: part.partUri,
483735
- assetId,
483736
- mode: payload.mode,
483737
- contentType: part.contentType ?? "",
483738
- ...payload.mode === BINARY_MODE.blob ? {
483739
- blobRef: payload.blobRef,
483740
- sha256: payload.sha256,
483741
- byteLength: payload.byteLength
483742
- } : {
483743
- bytes: payload.bytes,
483744
- sha256: payload.sha256
483745
- }
483746
- });
483747
- } catch (error50) {
483748
- if (!isAlreadySeededError(error50))
483749
- 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
+ }
483750
483938
  }
483751
- }
483752
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.binary);
483939
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.binary);
483940
+ }, "collab-v2:bootstrap:seed-unit");
483753
483941
  }
483754
483942
  async function connectOpaqueShard(rootDoc, shardId, part, sourceZipSha256, binaryMode, blobStore) {
483755
- const unit = createCollabUnitHandle({ rootDoc, shardId, shardKind: SHARD_KIND.opaquePart });
483756
- if (part.bytes) {
483757
- try {
483758
- const payload = prepareSingleDocBinaryPayload(part.bytes, binaryMode, blobStore);
483759
- seedOpaquePartShard({
483760
- doc: unit,
483761
- shardId,
483762
- ownerPartKey: part.partKey,
483763
- ownerPartUri: part.partUri,
483764
- partKey: part.partKey,
483765
- partUri: part.partUri,
483766
- contentType: part.contentType,
483767
- mode: payload.mode,
483768
- ...payload.mode === BINARY_MODE.blob ? {
483769
- blobRef: payload.blobRef,
483770
- sha256: payload.sha256,
483771
- byteLength: payload.byteLength
483772
- } : {
483773
- bytes: payload.bytes,
483774
- sha256: payload.sha256
483775
- },
483776
- sourceProvenance: {
483777
- sha256Zip: sourceZipSha256,
483778
- committedAt: null,
483779
- committerId: null
483780
- }
483781
- });
483782
- } catch (error50) {
483783
- if (!isAlreadySeededError(error50))
483784
- 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
+ }
483785
483975
  }
483786
- }
483787
- return subtreePackageHandle(rootDoc, unit, SHARD_KIND.opaquePart);
483976
+ return subtreePackageHandle(rootDoc, unit, SHARD_KIND.opaquePart);
483977
+ }, "collab-v2:bootstrap:seed-unit");
483788
483978
  }
483789
483979
  function storyProjectionHandle(handle) {
483790
483980
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.9.0-next.10",
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.10",
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.10",
33
- "@superdoc/docx-engine": "0.24.0-next.10",
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",