superdoc 2.12.0-next.13 → 2.12.0-next.15

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.
@@ -4071,8 +4071,11 @@ function createSuperDocUI(options) {
4071
4071
  const incompleteTrackChangesDirectoryReadTokens = /* @__PURE__ */ new Map();
4072
4072
  const postSourceCompletionRefreshTokens = /* @__PURE__ */ new Map();
4073
4073
  let sourceCompletionObservedToken = null;
4074
- let commentsDirectoryLeaseCount = 0;
4075
- let trackChangesDirectoryLeaseCount = 0;
4074
+ const directoryLeaseCounts = {
4075
+ comments: 0,
4076
+ trackChanges: 0,
4077
+ contentControls: 0
4078
+ };
4076
4079
  const demandHeavyDocRead = (key) => {
4077
4080
  const token = contentToken();
4078
4081
  if (demandedHeavyReads.get(key) === token) return;
@@ -4107,16 +4110,14 @@ function createSuperDocUI(options) {
4107
4110
  if (invalidated) scheduleAsyncRefresh();
4108
4111
  };
4109
4112
  const acquireDirectoryLease = (family) => {
4110
- if (family === "comments") commentsDirectoryLeaseCount += 1;
4111
- else trackChangesDirectoryLeaseCount += 1;
4113
+ directoryLeaseCounts[family] += 1;
4112
4114
  demandHeavyDocRead(family);
4113
4115
  let released = false;
4114
4116
  return () => {
4115
4117
  if (released) return;
4116
4118
  released = true;
4117
- if (family === "comments") commentsDirectoryLeaseCount = Math.max(0, commentsDirectoryLeaseCount - 1);
4118
- else trackChangesDirectoryLeaseCount = Math.max(0, trackChangesDirectoryLeaseCount - 1);
4119
- if ((family === "comments" ? commentsDirectoryLeaseCount : trackChangesDirectoryLeaseCount) === 0 && demandedHeavyReads.get(family) === contentToken()) demandedHeavyReads.delete(family);
4119
+ directoryLeaseCounts[family] = Math.max(0, directoryLeaseCounts[family] - 1);
4120
+ if (directoryLeaseCounts[family] === 0 && demandedHeavyReads.get(family) === contentToken()) demandedHeavyReads.delete(family);
4120
4121
  scheduleAsyncRefresh();
4121
4122
  };
4122
4123
  };
@@ -4887,7 +4888,7 @@ function createSuperDocUI(options) {
4887
4888
  const activeIds = selection.activeCommentIds;
4888
4889
  const directory = asyncReads.get("comments");
4889
4890
  const directoryItems = directory?.token === contentToken() && directory.hasSettled && Array.isArray(directory.value) ? directory.value : null;
4890
- const activeValidationItems = commentsDirectoryLeaseCount > 0 ? directoryItems : items;
4891
+ const activeValidationItems = directoryLeaseCounts.comments > 0 ? directoryItems : items;
4891
4892
  if (explicitActiveCommentId && activeValidationItems && !activeValidationItems.some((item) => readEntityId(item) === explicitActiveCommentId)) explicitActiveCommentId = null;
4892
4893
  const activeId = explicitActiveCommentId ?? activeIds[0] ?? null;
4893
4894
  return {
@@ -4962,7 +4963,7 @@ function createSuperDocUI(options) {
4962
4963
  if (active && !pendingTrackChangeRevealFocuses.has(active)) {
4963
4964
  const directory = asyncReads.get("trackChanges");
4964
4965
  const directoryItems = directory?.token === token && directory.hasSettled && Array.isArray(directory.value) ? filterPostDecisionTrackChanges(projectTrackChangesItems(directory.value), postDecisionIds) : null;
4965
- const activeValidationItems = trackChangesDirectoryLeaseCount > 0 ? directoryItems : active.story ? allStoryItems : items;
4966
+ const activeValidationItems = directoryLeaseCounts.trackChanges > 0 ? directoryItems : active.story ? allStoryItems : items;
4966
4967
  if (activeValidationItems && !activeValidationItems.some((row) => entityRowMatchesRequest(row, active.id, active.story))) setExplicitActiveChange(null);
4967
4968
  }
4968
4969
  const publicIdItems = allStoryItems ?? items;
@@ -7453,11 +7454,8 @@ function createSuperDocUI(options) {
7453
7454
  return false;
7454
7455
  }
7455
7456
  }
7456
- function resolveTrackDecisionTarget(command, payload) {
7457
- if (command.scope === "all") return {
7458
- target: { kind: "all" },
7459
- changeId: null
7460
- };
7457
+ /** A decision target carried by the payload itself, independent of the selection. */
7458
+ function explicitTrackDecisionTarget(payload) {
7461
7459
  if (typeof payload === "string" && payload.length > 0) return {
7462
7460
  target: {
7463
7461
  kind: "id",
@@ -7482,6 +7480,15 @@ function createSuperDocUI(options) {
7482
7480
  story: record.story
7483
7481
  };
7484
7482
  }
7483
+ return null;
7484
+ }
7485
+ function resolveTrackDecisionTarget(command, payload) {
7486
+ if (command.scope === "all") return {
7487
+ target: { kind: "all" },
7488
+ changeId: null
7489
+ };
7490
+ const explicit = explicitTrackDecisionTarget(payload);
7491
+ if (explicit) return explicit;
7485
7492
  const selectedId = state.selection.activeChangeIds[0];
7486
7493
  const story = nonBodySelectionStoryLocator(state.selection);
7487
7494
  return selectedId ? {
@@ -8435,6 +8442,7 @@ function createSuperDocUI(options) {
8435
8442
  const commandNeedsFreshSelection = (id, payload) => {
8436
8443
  const trackCommand = trackDecisionCommand(id);
8437
8444
  const descriptor = getCommandDescriptor(id);
8445
+ if (trackCommand?.scope === "id" && explicitTrackDecisionTarget(payload)) return false;
8438
8446
  if (trackCommand?.scope !== "id" && !descriptorNeedsFreshSelection(descriptor)) return false;
8439
8447
  return !commandSelectionIsReady(id, descriptor, payload);
8440
8448
  };
@@ -9212,6 +9220,7 @@ function createSuperDocUI(options) {
9212
9220
  */
9213
9221
  const resolveEntityTarget = async (namespace, id, loaded, request) => {
9214
9222
  const requestedStory = namespace === "trackChanges" ? request?.story : void 0;
9223
+ const rowStory = namespace === "trackChanges" ? request?.matchStory ?? requestedStory : void 0;
9215
9224
  const withRequestedStory = (target) => {
9216
9225
  if (!requestedStory || !target || typeof target !== "object") return target;
9217
9226
  const record = target;
@@ -9223,7 +9232,7 @@ function createSuperDocUI(options) {
9223
9232
  };
9224
9233
  };
9225
9234
  const readTarget = namespace === "trackChanges" ? readTrackedChangeNavigationTarget : readEntityTarget;
9226
- const loadedRow = loaded.find((row) => entityRowMatchesRequest(row, id, requestedStory));
9235
+ const loadedRow = loaded.find((row) => entityRowMatchesRequest(row, id, rowStory));
9227
9236
  const loadedRecord = loadedRow && typeof loadedRow === "object" ? loadedRow : null;
9228
9237
  const moveSide = namespace === "trackChanges" && loadedRecord?.type === "move" && (loadedRecord.subtype === "move-to" || loadedRecord.subtype === "move-from") ? loadedRecord.subtype : null;
9229
9238
  const trackedChangeLookupId = moveSide && typeof loadedRecord?.trackedChangeCanonicalId === "string" ? loadedRecord.trackedChangeCanonicalId : id;
@@ -9517,9 +9526,13 @@ function createSuperDocUI(options) {
9517
9526
  });
9518
9527
  },
9519
9528
  accept: (changeId) => executeTrackDecision("accept", changeId),
9529
+ acceptAsync: (changeId) => settleTrackDecision(() => executeTrackDecision("accept", changeId)),
9520
9530
  reject: (changeId) => executeTrackDecision("reject", changeId),
9531
+ rejectAsync: (changeId) => settleTrackDecision(() => executeTrackDecision("reject", changeId)),
9521
9532
  acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
9533
+ acceptAllAsync: () => settleTrackDecision(() => executeTrackDecisionTarget("accept", { kind: "all" }, null)),
9522
9534
  rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
9535
+ rejectAllAsync: () => settleTrackDecision(() => executeTrackDecisionTarget("reject", { kind: "all" }, null)),
9523
9536
  next: () => navigateTrackChange(1),
9524
9537
  previous: () => navigateTrackChange(-1),
9525
9538
  navigateNext: () => navigateAndScroll(1),
@@ -9584,19 +9597,27 @@ function createSuperDocUI(options) {
9584
9597
  recompute();
9585
9598
  return true;
9586
9599
  },
9587
- scrollTo: async (changeId) => {
9600
+ scrollTo: async (input) => {
9588
9601
  if (!getDoc()) return {
9589
9602
  success: false,
9590
9603
  ok: false,
9591
9604
  reason: getEditor() ? SUPERDOC_UI_REASONS.documentApiUnavailable : SUPERDOC_UI_REASONS.notReady
9592
9605
  };
9606
+ const changeId = typeof input === "string" ? input : input.id;
9607
+ const matchStory = typeof input === "string" || !input.story || typeof input.story !== "object" ? void 0 : input.story;
9608
+ const requestedStory = matchStory ? readEntityRequestStory({ address: { story: matchStory } }) : void 0;
9609
+ if (typeof changeId !== "string" || changeId.length === 0) return {
9610
+ success: false,
9611
+ ok: false,
9612
+ reason: SUPERDOC_UI_REASONS.targetUnresolved
9613
+ };
9593
9614
  queuedTrackChangeNavigationInvalidation += 1;
9594
9615
  trackChangeRevealInvalidation += 1;
9595
9616
  const requestedAtInvalidation = trackChangeRevealInvalidation;
9596
- const loadedItems = trackChangesSub.get().items;
9597
- const publicId = buildTrackedChangeIdContext(loadedItems).toPublicId(changeId) ?? changeId;
9598
- const matchingRow = loadedItems.find((item) => readEntityId(item) === publicId);
9599
- const story = readEntityRequestStory(matchingRow);
9617
+ const loadedItems = matchStory ? readAllStoryTrackChanges() ?? trackChangesSub.get().items : trackChangesSub.get().items;
9618
+ const publicId = matchStory ? buildStoryScopedTrackedChangeIdContext(loadedItems, matchStory).toPublicId(changeId) ?? changeId : buildTrackedChangeIdContext(loadedItems).toPublicId(changeId) ?? changeId;
9619
+ const matchingRow = matchStory ? loadedItems.find((item) => entityRowMatchesRequest(item, publicId, matchStory)) : loadedItems.find((item) => readEntityId(item) === publicId);
9620
+ const story = matchStory ? requestedStory : readEntityRequestStory(matchingRow);
9600
9621
  const importedId = deriveTrackedChangeImportedId(matchingRow);
9601
9622
  const previousActiveChange = explicitActiveChange;
9602
9623
  const requestedActiveChange = {
@@ -9606,7 +9627,10 @@ function createSuperDocUI(options) {
9606
9627
  };
9607
9628
  pendingTrackChangeRevealFocuses.add(requestedActiveChange);
9608
9629
  try {
9609
- const target = await resolveEntityTarget("trackChanges", publicId, loadedItems, story ? { story } : void 0);
9630
+ const target = await resolveEntityTarget("trackChanges", publicId, loadedItems, story || matchStory ? {
9631
+ story,
9632
+ matchStory
9633
+ } : void 0);
9610
9634
  if (trackChangeRevealInvalidation !== requestedAtInvalidation) return {
9611
9635
  success: false,
9612
9636
  ok: false
@@ -9666,6 +9690,7 @@ function createSuperDocUI(options) {
9666
9690
  id: input,
9667
9691
  story: void 0
9668
9692
  } : input;
9693
+ if (typeof id !== "string" || id.length === 0) return false;
9669
9694
  const target = {
9670
9695
  kind: "id",
9671
9696
  id,
@@ -9673,6 +9698,19 @@ function createSuperDocUI(options) {
9673
9698
  };
9674
9699
  return executeTrackDecisionTarget(kind, target, id, story);
9675
9700
  };
9701
+ /**
9702
+ * Run a domain decision and resolve with its settled result. The domain
9703
+ * helpers call the decision route directly so an application command that
9704
+ * reuses a built-in tracked-change id cannot intercept them; only the command
9705
+ * registry (`commands.execute*`) honours those overrides.
9706
+ */
9707
+ const settleTrackDecision = (run) => {
9708
+ pendingCommandSettlement = null;
9709
+ lastCommandSettlement = Promise.resolve(false);
9710
+ if (disposed) return Promise.resolve(false);
9711
+ if (run() === false) return Promise.resolve(false);
9712
+ return lastCommandSettlement;
9713
+ };
9676
9714
  const executeTrackDecisionTarget = (kind, target, changeId, story) => {
9677
9715
  try {
9678
9716
  return settleCommandExecution(callTrackDecisionTarget(kind, target, changeId, story));
@@ -9705,12 +9743,16 @@ function createSuperDocUI(options) {
9705
9743
  const findContentControl = (id) => {
9706
9744
  return contentControlsSub.get().items.find((item) => item?.id === id) ?? null;
9707
9745
  };
9708
- const contentControlsSnap = snapshotHandle(contentControlsSub);
9746
+ const contentControlsSnap = directorySnapshotHandle(contentControlsSub, select((s) => {
9747
+ if (directoryLeaseCounts.contentControls > 0) demandHeavyDocRead("contentControls");
9748
+ return s.contentControls;
9749
+ }), "contentControls");
9709
9750
  const contentControlsGet = ((input) => {
9710
9751
  if (input === void 0) return contentControlsSnap.get();
9711
9752
  const id = readContentControlRequestId(input);
9712
9753
  return id ? findContentControl(id) : null;
9713
9754
  });
9755
+ const contentControlsPassiveSnap = snapshotHandle(contentControlsSub);
9714
9756
  const contentControls = {
9715
9757
  get: ((input) => {
9716
9758
  if (input !== void 0) ensureContentControlsCatalog("api");
@@ -9719,6 +9761,7 @@ function createSuperDocUI(options) {
9719
9761
  getSnapshot: contentControlsSnap.getSnapshot,
9720
9762
  subscribe: contentControlsSnap.subscribe,
9721
9763
  observe: contentControlsSnap.observe,
9764
+ observeActivePath: contentControlsPassiveSnap.observe,
9722
9765
  list: () => {
9723
9766
  ensureContentControlsCatalog("api");
9724
9767
  return contentControlsSub.get().items;
@@ -10822,8 +10865,7 @@ function createSuperDocUI(options) {
10822
10865
  if (detachSourceLoading) detachSourceLoading();
10823
10866
  detachSourceLoading = null;
10824
10867
  sourceLoadingSubscriptionHost = null;
10825
- commentsDirectoryLeaseCount = 0;
10826
- trackChangesDirectoryLeaseCount = 0;
10868
+ for (const family of Object.keys(directoryLeaseCounts)) directoryLeaseCounts[family] = 0;
10827
10869
  demandedHeavyReads.clear();
10828
10870
  incompleteTrackChangesDirectoryReadTokens.clear();
10829
10871
  postSourceCompletionRefreshTokens.clear();
@@ -4071,8 +4071,11 @@ function createSuperDocUI(options) {
4071
4071
  const incompleteTrackChangesDirectoryReadTokens = /* @__PURE__ */ new Map();
4072
4072
  const postSourceCompletionRefreshTokens = /* @__PURE__ */ new Map();
4073
4073
  let sourceCompletionObservedToken = null;
4074
- let commentsDirectoryLeaseCount = 0;
4075
- let trackChangesDirectoryLeaseCount = 0;
4074
+ const directoryLeaseCounts = {
4075
+ comments: 0,
4076
+ trackChanges: 0,
4077
+ contentControls: 0
4078
+ };
4076
4079
  const demandHeavyDocRead = (key) => {
4077
4080
  const token = contentToken();
4078
4081
  if (demandedHeavyReads.get(key) === token) return;
@@ -4107,16 +4110,14 @@ function createSuperDocUI(options) {
4107
4110
  if (invalidated) scheduleAsyncRefresh();
4108
4111
  };
4109
4112
  const acquireDirectoryLease = (family) => {
4110
- if (family === "comments") commentsDirectoryLeaseCount += 1;
4111
- else trackChangesDirectoryLeaseCount += 1;
4113
+ directoryLeaseCounts[family] += 1;
4112
4114
  demandHeavyDocRead(family);
4113
4115
  let released = false;
4114
4116
  return () => {
4115
4117
  if (released) return;
4116
4118
  released = true;
4117
- if (family === "comments") commentsDirectoryLeaseCount = Math.max(0, commentsDirectoryLeaseCount - 1);
4118
- else trackChangesDirectoryLeaseCount = Math.max(0, trackChangesDirectoryLeaseCount - 1);
4119
- if ((family === "comments" ? commentsDirectoryLeaseCount : trackChangesDirectoryLeaseCount) === 0 && demandedHeavyReads.get(family) === contentToken()) demandedHeavyReads.delete(family);
4119
+ directoryLeaseCounts[family] = Math.max(0, directoryLeaseCounts[family] - 1);
4120
+ if (directoryLeaseCounts[family] === 0 && demandedHeavyReads.get(family) === contentToken()) demandedHeavyReads.delete(family);
4120
4121
  scheduleAsyncRefresh();
4121
4122
  };
4122
4123
  };
@@ -4887,7 +4888,7 @@ function createSuperDocUI(options) {
4887
4888
  const activeIds = selection.activeCommentIds;
4888
4889
  const directory = asyncReads.get("comments");
4889
4890
  const directoryItems = directory?.token === contentToken() && directory.hasSettled && Array.isArray(directory.value) ? directory.value : null;
4890
- const activeValidationItems = commentsDirectoryLeaseCount > 0 ? directoryItems : items;
4891
+ const activeValidationItems = directoryLeaseCounts.comments > 0 ? directoryItems : items;
4891
4892
  if (explicitActiveCommentId && activeValidationItems && !activeValidationItems.some((item) => readEntityId(item) === explicitActiveCommentId)) explicitActiveCommentId = null;
4892
4893
  const activeId = explicitActiveCommentId ?? activeIds[0] ?? null;
4893
4894
  return {
@@ -4962,7 +4963,7 @@ function createSuperDocUI(options) {
4962
4963
  if (active && !pendingTrackChangeRevealFocuses.has(active)) {
4963
4964
  const directory = asyncReads.get("trackChanges");
4964
4965
  const directoryItems = directory?.token === token && directory.hasSettled && Array.isArray(directory.value) ? filterPostDecisionTrackChanges(projectTrackChangesItems(directory.value), postDecisionIds) : null;
4965
- const activeValidationItems = trackChangesDirectoryLeaseCount > 0 ? directoryItems : active.story ? allStoryItems : items;
4966
+ const activeValidationItems = directoryLeaseCounts.trackChanges > 0 ? directoryItems : active.story ? allStoryItems : items;
4966
4967
  if (activeValidationItems && !activeValidationItems.some((row) => entityRowMatchesRequest(row, active.id, active.story))) setExplicitActiveChange(null);
4967
4968
  }
4968
4969
  const publicIdItems = allStoryItems ?? items;
@@ -7453,11 +7454,8 @@ function createSuperDocUI(options) {
7453
7454
  return false;
7454
7455
  }
7455
7456
  }
7456
- function resolveTrackDecisionTarget(command, payload) {
7457
- if (command.scope === "all") return {
7458
- target: { kind: "all" },
7459
- changeId: null
7460
- };
7457
+ /** A decision target carried by the payload itself, independent of the selection. */
7458
+ function explicitTrackDecisionTarget(payload) {
7461
7459
  if (typeof payload === "string" && payload.length > 0) return {
7462
7460
  target: {
7463
7461
  kind: "id",
@@ -7482,6 +7480,15 @@ function createSuperDocUI(options) {
7482
7480
  story: record.story
7483
7481
  };
7484
7482
  }
7483
+ return null;
7484
+ }
7485
+ function resolveTrackDecisionTarget(command, payload) {
7486
+ if (command.scope === "all") return {
7487
+ target: { kind: "all" },
7488
+ changeId: null
7489
+ };
7490
+ const explicit = explicitTrackDecisionTarget(payload);
7491
+ if (explicit) return explicit;
7485
7492
  const selectedId = state.selection.activeChangeIds[0];
7486
7493
  const story = nonBodySelectionStoryLocator(state.selection);
7487
7494
  return selectedId ? {
@@ -8435,6 +8442,7 @@ function createSuperDocUI(options) {
8435
8442
  const commandNeedsFreshSelection = (id, payload) => {
8436
8443
  const trackCommand = trackDecisionCommand(id);
8437
8444
  const descriptor = getCommandDescriptor(id);
8445
+ if (trackCommand?.scope === "id" && explicitTrackDecisionTarget(payload)) return false;
8438
8446
  if (trackCommand?.scope !== "id" && !descriptorNeedsFreshSelection(descriptor)) return false;
8439
8447
  return !commandSelectionIsReady(id, descriptor, payload);
8440
8448
  };
@@ -9212,6 +9220,7 @@ function createSuperDocUI(options) {
9212
9220
  */
9213
9221
  const resolveEntityTarget = async (namespace, id, loaded, request) => {
9214
9222
  const requestedStory = namespace === "trackChanges" ? request?.story : void 0;
9223
+ const rowStory = namespace === "trackChanges" ? request?.matchStory ?? requestedStory : void 0;
9215
9224
  const withRequestedStory = (target) => {
9216
9225
  if (!requestedStory || !target || typeof target !== "object") return target;
9217
9226
  const record = target;
@@ -9223,7 +9232,7 @@ function createSuperDocUI(options) {
9223
9232
  };
9224
9233
  };
9225
9234
  const readTarget = namespace === "trackChanges" ? readTrackedChangeNavigationTarget : readEntityTarget;
9226
- const loadedRow = loaded.find((row) => entityRowMatchesRequest(row, id, requestedStory));
9235
+ const loadedRow = loaded.find((row) => entityRowMatchesRequest(row, id, rowStory));
9227
9236
  const loadedRecord = loadedRow && typeof loadedRow === "object" ? loadedRow : null;
9228
9237
  const moveSide = namespace === "trackChanges" && loadedRecord?.type === "move" && (loadedRecord.subtype === "move-to" || loadedRecord.subtype === "move-from") ? loadedRecord.subtype : null;
9229
9238
  const trackedChangeLookupId = moveSide && typeof loadedRecord?.trackedChangeCanonicalId === "string" ? loadedRecord.trackedChangeCanonicalId : id;
@@ -9517,9 +9526,13 @@ function createSuperDocUI(options) {
9517
9526
  });
9518
9527
  },
9519
9528
  accept: (changeId) => executeTrackDecision("accept", changeId),
9529
+ acceptAsync: (changeId) => settleTrackDecision(() => executeTrackDecision("accept", changeId)),
9520
9530
  reject: (changeId) => executeTrackDecision("reject", changeId),
9531
+ rejectAsync: (changeId) => settleTrackDecision(() => executeTrackDecision("reject", changeId)),
9521
9532
  acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
9533
+ acceptAllAsync: () => settleTrackDecision(() => executeTrackDecisionTarget("accept", { kind: "all" }, null)),
9522
9534
  rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
9535
+ rejectAllAsync: () => settleTrackDecision(() => executeTrackDecisionTarget("reject", { kind: "all" }, null)),
9523
9536
  next: () => navigateTrackChange(1),
9524
9537
  previous: () => navigateTrackChange(-1),
9525
9538
  navigateNext: () => navigateAndScroll(1),
@@ -9584,19 +9597,27 @@ function createSuperDocUI(options) {
9584
9597
  recompute();
9585
9598
  return true;
9586
9599
  },
9587
- scrollTo: async (changeId) => {
9600
+ scrollTo: async (input) => {
9588
9601
  if (!getDoc()) return {
9589
9602
  success: false,
9590
9603
  ok: false,
9591
9604
  reason: getEditor() ? SUPERDOC_UI_REASONS.documentApiUnavailable : SUPERDOC_UI_REASONS.notReady
9592
9605
  };
9606
+ const changeId = typeof input === "string" ? input : input.id;
9607
+ const matchStory = typeof input === "string" || !input.story || typeof input.story !== "object" ? void 0 : input.story;
9608
+ const requestedStory = matchStory ? readEntityRequestStory({ address: { story: matchStory } }) : void 0;
9609
+ if (typeof changeId !== "string" || changeId.length === 0) return {
9610
+ success: false,
9611
+ ok: false,
9612
+ reason: SUPERDOC_UI_REASONS.targetUnresolved
9613
+ };
9593
9614
  queuedTrackChangeNavigationInvalidation += 1;
9594
9615
  trackChangeRevealInvalidation += 1;
9595
9616
  const requestedAtInvalidation = trackChangeRevealInvalidation;
9596
- const loadedItems = trackChangesSub.get().items;
9597
- const publicId = buildTrackedChangeIdContext(loadedItems).toPublicId(changeId) ?? changeId;
9598
- const matchingRow = loadedItems.find((item) => readEntityId(item) === publicId);
9599
- const story = readEntityRequestStory(matchingRow);
9617
+ const loadedItems = matchStory ? readAllStoryTrackChanges() ?? trackChangesSub.get().items : trackChangesSub.get().items;
9618
+ const publicId = matchStory ? buildStoryScopedTrackedChangeIdContext(loadedItems, matchStory).toPublicId(changeId) ?? changeId : buildTrackedChangeIdContext(loadedItems).toPublicId(changeId) ?? changeId;
9619
+ const matchingRow = matchStory ? loadedItems.find((item) => entityRowMatchesRequest(item, publicId, matchStory)) : loadedItems.find((item) => readEntityId(item) === publicId);
9620
+ const story = matchStory ? requestedStory : readEntityRequestStory(matchingRow);
9600
9621
  const importedId = deriveTrackedChangeImportedId(matchingRow);
9601
9622
  const previousActiveChange = explicitActiveChange;
9602
9623
  const requestedActiveChange = {
@@ -9606,7 +9627,10 @@ function createSuperDocUI(options) {
9606
9627
  };
9607
9628
  pendingTrackChangeRevealFocuses.add(requestedActiveChange);
9608
9629
  try {
9609
- const target = await resolveEntityTarget("trackChanges", publicId, loadedItems, story ? { story } : void 0);
9630
+ const target = await resolveEntityTarget("trackChanges", publicId, loadedItems, story || matchStory ? {
9631
+ story,
9632
+ matchStory
9633
+ } : void 0);
9610
9634
  if (trackChangeRevealInvalidation !== requestedAtInvalidation) return {
9611
9635
  success: false,
9612
9636
  ok: false
@@ -9666,6 +9690,7 @@ function createSuperDocUI(options) {
9666
9690
  id: input,
9667
9691
  story: void 0
9668
9692
  } : input;
9693
+ if (typeof id !== "string" || id.length === 0) return false;
9669
9694
  const target = {
9670
9695
  kind: "id",
9671
9696
  id,
@@ -9673,6 +9698,19 @@ function createSuperDocUI(options) {
9673
9698
  };
9674
9699
  return executeTrackDecisionTarget(kind, target, id, story);
9675
9700
  };
9701
+ /**
9702
+ * Run a domain decision and resolve with its settled result. The domain
9703
+ * helpers call the decision route directly so an application command that
9704
+ * reuses a built-in tracked-change id cannot intercept them; only the command
9705
+ * registry (`commands.execute*`) honours those overrides.
9706
+ */
9707
+ const settleTrackDecision = (run) => {
9708
+ pendingCommandSettlement = null;
9709
+ lastCommandSettlement = Promise.resolve(false);
9710
+ if (disposed) return Promise.resolve(false);
9711
+ if (run() === false) return Promise.resolve(false);
9712
+ return lastCommandSettlement;
9713
+ };
9676
9714
  const executeTrackDecisionTarget = (kind, target, changeId, story) => {
9677
9715
  try {
9678
9716
  return settleCommandExecution(callTrackDecisionTarget(kind, target, changeId, story));
@@ -9705,12 +9743,16 @@ function createSuperDocUI(options) {
9705
9743
  const findContentControl = (id) => {
9706
9744
  return contentControlsSub.get().items.find((item) => item?.id === id) ?? null;
9707
9745
  };
9708
- const contentControlsSnap = snapshotHandle(contentControlsSub);
9746
+ const contentControlsSnap = directorySnapshotHandle(contentControlsSub, select((s) => {
9747
+ if (directoryLeaseCounts.contentControls > 0) demandHeavyDocRead("contentControls");
9748
+ return s.contentControls;
9749
+ }), "contentControls");
9709
9750
  const contentControlsGet = ((input) => {
9710
9751
  if (input === void 0) return contentControlsSnap.get();
9711
9752
  const id = readContentControlRequestId(input);
9712
9753
  return id ? findContentControl(id) : null;
9713
9754
  });
9755
+ const contentControlsPassiveSnap = snapshotHandle(contentControlsSub);
9714
9756
  const contentControls = {
9715
9757
  get: ((input) => {
9716
9758
  if (input !== void 0) ensureContentControlsCatalog("api");
@@ -9719,6 +9761,7 @@ function createSuperDocUI(options) {
9719
9761
  getSnapshot: contentControlsSnap.getSnapshot,
9720
9762
  subscribe: contentControlsSnap.subscribe,
9721
9763
  observe: contentControlsSnap.observe,
9764
+ observeActivePath: contentControlsPassiveSnap.observe,
9722
9765
  list: () => {
9723
9766
  ensureContentControlsCatalog("api");
9724
9767
  return contentControlsSub.get().items;
@@ -10822,8 +10865,7 @@ function createSuperDocUI(options) {
10822
10865
  if (detachSourceLoading) detachSourceLoading();
10823
10866
  detachSourceLoading = null;
10824
10867
  sourceLoadingSubscriptionHost = null;
10825
- commentsDirectoryLeaseCount = 0;
10826
- trackChangesDirectoryLeaseCount = 0;
10868
+ for (const family of Object.keys(directoryLeaseCounts)) directoryLeaseCounts[family] = 0;
10827
10869
  demandedHeavyReads.clear();
10828
10870
  incompleteTrackChangesDirectoryReadTokens.clear();
10829
10871
  postSourceCompletionRefreshTokens.clear();
@@ -19,7 +19,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
19
19
  var PRIVATE_ENGINE_INFO = (0, _superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
20
20
  var ENGINE_INFO = Object.freeze({
21
21
  ...PRIVATE_ENGINE_INFO,
22
- superdocVersion: "2.12.0-next.13",
22
+ superdocVersion: "2.12.0-next.15",
23
23
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
24
24
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
25
25
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -18,7 +18,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
18
18
  var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
19
19
  var ENGINE_INFO = Object.freeze({
20
20
  ...PRIVATE_ENGINE_INFO,
21
- superdocVersion: "2.12.0-next.13",
21
+ superdocVersion: "2.12.0-next.15",
22
22
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
23
23
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
24
24
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -0,0 +1,9 @@
1
+ import { FlowBlock, Run } from '../../../contracts/src/index.js';
2
+ export type DerivedRunTextPlane = {
3
+ generation: number;
4
+ revision: string;
5
+ valuesByDataAttribute: ReadonlyMap<string, ReadonlyMap<string, string>>;
6
+ };
7
+ export declare function validateDerivedRunTextPlane(plane: DerivedRunTextPlane | null | undefined, generation: number): void;
8
+ export declare function resolveDerivedRunText(run: Run, plane: DerivedRunTextPlane | null | undefined): string | undefined;
9
+ export declare function blockUsesDerivedRunTextPlane(block: FlowBlock | undefined, plane: DerivedRunTextPlane | null | undefined): boolean;
@@ -15,6 +15,7 @@ export type { RulerDefinition, RulerConfig, RulerConfigPx, RulerTick, CreateRule
15
15
  export type { PaintSnapshot, PaintSnapshotAnnotationEntity, PaintSnapshotStructuredContentBlockEntity, PaintSnapshotStructuredContentInlineEntity, PaintSnapshotImageEntity, PaintSnapshotEntities, } from './renderer.js';
16
16
  export type { DomPainterInput, PositionMapping } from './renderer.js';
17
17
  export type { DomPainterPersistentPacketSource, DomPainterPersistentPageInput, DomPainterPersistentScaffold, DomPainterPersistentScaffoldPage, } from './persistent-page-surface.js';
18
+ export type { DerivedRunTextPlane } from './derived-run-text-plane.js';
18
19
  export type { PaintWorkSummary } from './page-content.js';
19
20
  export type { RenderedLineInfo } from './runs/index.js';
20
21
  export { sanitizeUrl, linkMetrics, applyRunDataAttributes } from './runs/index.js';
@@ -3,6 +3,7 @@ import { FragmentRenderContext, PositionMapping } from './renderer.js';
3
3
  import { SdtBoundaryOptions } from './sdt/container.js';
4
4
  import { BetweenBorderInfo } from './paragraph/borders/index.js';
5
5
  import { PageStyles } from './styles.js';
6
+ import { DerivedRunTextPlane } from './derived-run-text-plane.js';
6
7
  export type FragmentDomState = {
7
8
  key: string;
8
9
  signature: string;
@@ -116,7 +117,7 @@ export declare function createEmptyPaintWorkSummary(): PaintWorkSummary;
116
117
  * attribute-for-attribute — that exactness is the proof, never normalize it
117
118
  * away at the pass level (only the §7.7 unit tests use the normalized form).
118
119
  */
119
- export declare function persistentPageVersionKey(page: ResolvedPage, totalPages: number, sectionPageCount: number): string | null;
120
+ export declare function persistentPageVersionKey(page: ResolvedPage, totalPages: number, sectionPageCount: number, derivedRunTextPlane?: DerivedRunTextPlane | null): string | null;
120
121
  /**
121
122
  * The class state `renderPage`/`patchPage` consume, made explicit. The
122
123
  * DomPainter builds one per call (values like `totalPages`, `layoutEpoch`,
@@ -130,6 +131,7 @@ export interface PageContentContext {
130
131
  totalPages: number;
131
132
  currentMapping: PositionMapping | null;
132
133
  changedBlocks: ReadonlySet<string>;
134
+ derivedRunTextPlane?: DerivedRunTextPlane | null;
133
135
  /** Record the smallest newly painted subtree for transaction finalization. */
134
136
  recordChangedRoot?(root: HTMLElement): void;
135
137
  sdtLabelsRendered: Set<string>;
@@ -1,4 +1,5 @@
1
1
  import { DocumentBackground, ResolvedPage } from '../../../contracts/src/index.js';
2
+ import { DerivedRunTextPlane } from './derived-run-text-plane.js';
2
3
  import { PageContentContext, PageDomState, PaintWorkSummary } from './page-content.js';
3
4
  /**
4
5
  * One exact page band of the committed scaffold (numbers-only,
@@ -69,6 +70,7 @@ export type DomPainterPersistentPageInput = {
69
70
  packetsByPageIndex: DomPainterPersistentPacketSource;
70
71
  sectionPageCounts?: Readonly<Record<string, number>>;
71
72
  documentBackground?: DocumentBackground | null;
73
+ derivedRunTextPlane?: DerivedRunTextPlane | null;
72
74
  captureSnapshot?: boolean;
73
75
  };
74
76
  /** Shell registry entry: the persistent page root and its geometry/style reuse key. */
@@ -1,6 +1,7 @@
1
1
  import { FlowMode, Fragment, PageMargins, PageNumberChapterSeparator, PageNumberFormat, SourceAnchor, ResolvedLayout, ResolvedPage, ResolvedPaintItem, LayoutSourceIdentity, LayoutStoryLocator } from '../../../contracts/src/index.js';
2
2
  import { PaintWorkSummary } from './page-content.js';
3
3
  import { DomPainterPersistentPageInput } from './persistent-page-surface.js';
4
+ import { DerivedRunTextPlane } from './derived-run-text-plane.js';
4
5
  import { PageStyles } from './styles.js';
5
6
  import { PaintSnapshotStructuredContentBlockEntity, PaintSnapshotStructuredContentInlineEntity } from './sdt/snapshot.js';
6
7
  import { PositionValidationOptions, PositionValidationSummary } from './pm-position-validation.js';
@@ -143,6 +144,7 @@ export type FragmentRenderContext = {
143
144
  * `totalPages` / `sectionPageCount`. Absent/`true` = exact (default).
144
145
  */
145
146
  pageCountFieldsExact?: boolean;
147
+ derivedRunTextPlane?: DerivedRunTextPlane | null;
146
148
  };
147
149
  export type PaintSnapshotLineStyle = {
148
150
  paddingLeftPx?: number;
@@ -305,6 +307,7 @@ export declare class DomPainter {
305
307
  * `dispose()` so a stale window value can never leak across modes/mounts.
306
308
  */
307
309
  private persistentDocumentBackground;
310
+ private persistentDerivedRunTextPlane;
308
311
  private paintWork;
309
312
  /**
310
313
  * P5 §4.6 (review fix): per-page attribution arrays are opt-in. Counters
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-CBFGggZ2.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BkDVQgqj.cjs");
3
3
  const require_slice_source = require("../chunks/slice-source-CFaqq0Vo.cjs");
4
4
  let react = require("react");
5
5
  //#region src/public/ui/react.ts
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-C-AuEM9F.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-Biwv0tas.es.js";
2
2
  import { t as toSliceSource } from "../chunks/slice-source-gfOhG2MW.es.js";
3
3
  import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
4
4
  //#region src/public/ui/react.ts
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-CBFGggZ2.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BkDVQgqj.cjs");
3
3
  const require_slice_source = require("../chunks/slice-source-CFaqq0Vo.cjs");
4
4
  let vue = require("vue");
5
5
  //#region src/public/ui/vue.ts
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-C-AuEM9F.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-Biwv0tas.es.js";
2
2
  import { t as toSliceSource } from "../chunks/slice-source-gfOhG2MW.es.js";
3
3
  import { computed, inject, onScopeDispose, provide, shallowRef, toRaw, toValue, watch } from "vue";
4
4
  //#region src/public/ui/vue.ts
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-CBFGggZ2.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BkDVQgqj.cjs");
3
3
  exports.BUILT_IN_COMMAND_IDS = require_create_super_doc_ui.BUILT_IN_COMMAND_IDS;
4
4
  exports.createSuperDocUI = require_create_super_doc_ui.createSuperDocUI;
5
5
  exports.shallowEqual = require_create_super_doc_ui.shallowEqual;
@@ -1,2 +1,2 @@
1
- import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-C-AuEM9F.es.js";
1
+ import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-Biwv0tas.es.js";
2
2
  export { BUILT_IN_COMMAND_IDS, createSuperDocUI, shallowEqual };