superdoc 2.4.0-next.2 → 2.4.0-next.3

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.
package/dist/superdoc.cjs CHANGED
@@ -6,7 +6,7 @@ const require_uuid = require("./chunks/uuid-CFp0WGVU.cjs");
6
6
  const require_jszip = require("./chunks/jszip-Cs9JBLlJ.cjs");
7
7
  const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-BTwbGDKw.cjs");
8
8
  const require_constants = require("./chunks/constants-sbCZ2O_A.cjs");
9
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-DXdWuTzm.cjs");
9
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-BHMQEL2y.cjs");
10
10
  let vue = require("vue");
11
11
  vue = require_rolldown_runtime.__toESM(vue);
12
12
  require("y-websocket");
@@ -6728,8 +6728,17 @@ const useCommentsStore = defineStore("comments", () => {
6728
6728
  return viewingVisibility.commentsVisible || viewingVisibility.trackChangesVisible;
6729
6729
  });
6730
6730
  const v2CommentsAdapter = (0, vue.shallowRef)(null);
6731
+ const v2CommentSyncGenerations = /* @__PURE__ */ new WeakMap();
6732
+ const commentSyncGeneration = (adapter) => v2CommentSyncGenerations.get(adapter) ?? 0;
6733
+ const supersedeCommentSyncGeneration = (adapter) => {
6734
+ if (!adapter || typeof adapter !== "object" && typeof adapter !== "function") return 0;
6735
+ const next = commentSyncGeneration(adapter) + 1;
6736
+ v2CommentSyncGenerations.set(adapter, next);
6737
+ return next;
6738
+ };
6731
6739
  const setV2CommentsAdapter = (adapter) => {
6732
6740
  v2CommentsAdapter.value = adapter ?? null;
6741
+ if (adapter && !v2CommentSyncGenerations.has(adapter)) v2CommentSyncGenerations.set(adapter, 0);
6733
6742
  };
6734
6743
  const getV2CommentsAdapter = (superdoc) => {
6735
6744
  const fromFacade = superdoc?.activeEditor?.v2Comments ?? null;
@@ -6738,14 +6747,27 @@ const useCommentsStore = defineStore("comments", () => {
6738
6747
  };
6739
6748
  const isV2EditorActive = (superdoc) => superdoc?.activeEditor?.editorVersion === 2 || v2CommentsAdapter.value !== null;
6740
6749
  const v2TrackedChangesAdapter = (0, vue.shallowRef)(null);
6750
+ const v2TrackedChangeSyncGenerations = /* @__PURE__ */ new WeakMap();
6751
+ const trackedChangeSyncGeneration = (adapter) => v2TrackedChangeSyncGenerations.get(adapter) ?? 0;
6752
+ const supersedeTrackedChangeSyncGeneration = (adapter) => {
6753
+ if (!adapter || typeof adapter !== "object" && typeof adapter !== "function") return 0;
6754
+ const next = trackedChangeSyncGeneration(adapter) + 1;
6755
+ v2TrackedChangeSyncGenerations.set(adapter, next);
6756
+ return next;
6757
+ };
6741
6758
  const setV2TrackedChangesAdapter = (adapter) => {
6742
6759
  v2TrackedChangesAdapter.value = adapter ?? null;
6760
+ if (adapter && !v2TrackedChangeSyncGenerations.has(adapter)) v2TrackedChangeSyncGenerations.set(adapter, 0);
6743
6761
  };
6744
6762
  const getV2TrackedChangesAdapter = (superdoc) => {
6745
6763
  const fromFacade = superdoc?.activeEditor?.v2TrackedChanges ?? null;
6746
6764
  if (fromFacade) return fromFacade;
6747
6765
  return v2TrackedChangesAdapter.value;
6748
6766
  };
6767
+ const supersedeV2ReviewHydration = ({ commentsAdapter, trackedChangesAdapter } = {}) => ({
6768
+ commentsGeneration: supersedeCommentSyncGeneration(commentsAdapter ?? v2CommentsAdapter.value),
6769
+ trackedChangesGeneration: supersedeTrackedChangeSyncGeneration(trackedChangesAdapter ?? v2TrackedChangesAdapter.value)
6770
+ });
6749
6771
  const init = (config = {}) => {
6750
6772
  const updatedConfig = {
6751
6773
  ...commentsConfig,
@@ -7201,7 +7223,7 @@ const useCommentsStore = defineStore("comments", () => {
7201
7223
  }
7202
7224
  activeEditor?.commands?.setActiveComment({ commentId: activeComment.value });
7203
7225
  };
7204
- const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, documentState = void 0 }) => {
7226
+ const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, documentState = void 0, trackedChangeIdentityIndex = null }) => {
7205
7227
  const span = startInteractionSpan("store.trackedChanges.handleUpdate", "store-reconciliation", {
7206
7228
  event: params?.event ?? null,
7207
7229
  changeId: params?.changeId ?? null,
@@ -7304,6 +7326,17 @@ const useCommentsStore = defineStore("comments", () => {
7304
7326
  if (normalizedAnchorKey && commentAnchorKey) return commentAnchorKey === normalizedAnchorKey;
7305
7327
  return false;
7306
7328
  };
7329
+ if (trackedChangeIdentityIndex) {
7330
+ const candidates = trackedChangeIdentityIndex.candidates({
7331
+ changeId: normalizedChangeId,
7332
+ importedId: normalizedImportedId,
7333
+ anchorKey: normalizedAnchorKey,
7334
+ canonicalId: normalizedTrackedChangeCanonicalId,
7335
+ positionAliases: normalizedTrackedChangePositionAliases
7336
+ });
7337
+ for (const trackedComment of candidates) if (matchesId(trackedComment) && (!normalizedDocumentId || belongsToTrackedChangeSyncDocument(trackedComment, normalizedDocumentId))) return trackedComment;
7338
+ return null;
7339
+ }
7307
7340
  if (normalizedDocumentId) return commentsList.value.find((trackedComment) => matchesId(trackedComment) && belongsToTrackedChangeSyncDocument(trackedComment, normalizedDocumentId));
7308
7341
  return commentsList.value.find(matchesId);
7309
7342
  };
@@ -7372,6 +7405,7 @@ const useCommentsStore = defineStore("comments", () => {
7372
7405
  const existing = findTrackedChangeById();
7373
7406
  if (existing) {
7374
7407
  if (!updateExistingTrackedChange(existing)) return;
7408
+ trackedChangeIdentityIndex?.add(existing);
7375
7409
  emitTrackedChangeEvent({
7376
7410
  type: COMMENT_EVENTS.UPDATE,
7377
7411
  comment: getCommentEventPayload(existing)
@@ -7383,10 +7417,12 @@ const useCommentsStore = defineStore("comments", () => {
7383
7417
  comment,
7384
7418
  broadcastChanges
7385
7419
  });
7420
+ trackedChangeIdentityIndex?.add(comment);
7386
7421
  } else if (event === "update") {
7387
7422
  const existingTrackedChange = findTrackedChangeById();
7388
7423
  if (!existingTrackedChange) return;
7389
7424
  if (!updateExistingTrackedChange(existingTrackedChange)) return;
7425
+ trackedChangeIdentityIndex?.add(existingTrackedChange);
7390
7426
  emitTrackedChangeEvent({
7391
7427
  type: COMMENT_EVENTS.UPDATE,
7392
7428
  comment: getCommentEventPayload(existingTrackedChange)
@@ -8200,15 +8236,24 @@ const useCommentsStore = defineStore("comments", () => {
8200
8236
  trackedItems: preparedParams.length
8201
8237
  };
8202
8238
  });
8203
- const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId } = {}) => withInteractionSpan("store.comments.hydrateFromV2", "comments-list", { documentId: documentId ?? null }, async () => {
8239
+ const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId, signal, hydrationGeneration } = {}) => withInteractionSpan("store.comments.hydrateFromV2", "comments-list", { documentId: documentId ?? null }, async () => {
8204
8240
  const effectiveAdapter = adapter ?? getV2CommentsAdapter(superdoc);
8205
8241
  if (!effectiveAdapter || typeof effectiveAdapter.refresh !== "function") return {
8206
8242
  ok: false,
8207
8243
  reason: "adapter-missing"
8208
8244
  };
8245
+ if (signal?.aborted) return {
8246
+ ok: false,
8247
+ reason: "review-hydration-superseded",
8248
+ lateResultDropped: false
8249
+ };
8250
+ const syncGeneration = commentSyncGeneration(effectiveAdapter);
8209
8251
  let result;
8210
8252
  try {
8211
- result = await effectiveAdapter.refresh();
8253
+ const refreshOptions = {};
8254
+ if (signal) refreshOptions.signal = signal;
8255
+ if (typeof hydrationGeneration === "number") refreshOptions.hydrationGeneration = hydrationGeneration;
8256
+ result = Object.keys(refreshOptions).length > 0 ? await effectiveAdapter.refresh(refreshOptions) : await effectiveAdapter.refresh();
8212
8257
  } catch (err) {
8213
8258
  return {
8214
8259
  ok: false,
@@ -8220,21 +8265,35 @@ const useCommentsStore = defineStore("comments", () => {
8220
8265
  ok: false,
8221
8266
  reason: "adapter-stale"
8222
8267
  };
8268
+ if (signal?.aborted || commentSyncGeneration(effectiveAdapter) !== syncGeneration) return {
8269
+ ok: false,
8270
+ reason: "review-hydration-superseded",
8271
+ lateResultDropped: true
8272
+ };
8223
8273
  if (!result?.ok) return result;
8274
+ if (signal?.aborted || commentSyncGeneration(effectiveAdapter) !== syncGeneration) return {
8275
+ ok: false,
8276
+ reason: "review-hydration-superseded",
8277
+ lateResultDropped: true
8278
+ };
8224
8279
  reconcileCommentsFromV2({
8225
8280
  superdoc,
8226
8281
  adapter: effectiveAdapter,
8227
8282
  documentId,
8228
- items: result.items ?? []
8283
+ items: result.items ?? [],
8284
+ hydrationGeneration
8229
8285
  });
8230
8286
  return {
8231
8287
  ok: true,
8232
- items: result.items ?? []
8288
+ items: result.items ?? [],
8289
+ reconciled: true,
8290
+ ...typeof hydrationGeneration === "number" ? { hydrationGeneration } : {}
8233
8291
  };
8234
8292
  });
8235
- const reconcileCommentsFromV2 = ({ superdoc, adapter, documentId, items, preparedInputs = null } = {}) => withInteractionSpan("store.comments.reconcile", "store-reconciliation", {
8293
+ const reconcileCommentsFromV2 = ({ superdoc, adapter, documentId, items, preparedInputs = null, hydrationGeneration } = {}) => withInteractionSpan("store.comments.reconcile", "store-reconciliation", {
8236
8294
  documentId: documentId ?? null,
8237
- itemCount: Array.isArray(items) ? items.length : null
8295
+ itemCount: Array.isArray(items) ? items.length : null,
8296
+ hydrationGeneration: hydrationGeneration ?? null
8238
8297
  }, () => {
8239
8298
  if (!adapter || !Array.isArray(items)) return { added: null };
8240
8299
  if (!isCurrentV2CommentsAdapter(adapter)) return {
@@ -9008,7 +9067,7 @@ const useCommentsStore = defineStore("comments", () => {
9008
9067
  let removed = false;
9009
9068
  const targetIndex = targetComment ? commentsList.value.indexOf(targetComment) : -1;
9010
9069
  const targetIds = targetComment?.trackedChange ? collectTrackedChangeDecisionIds(targetComment) : /* @__PURE__ */ new Set();
9011
- if (targetIndex >= 0 && belongsToTrackedChangeSyncDocument(targetComment, normalizedDocumentId) && Array.from(normalizedDecidedIds).some((id) => targetIds.has(id))) {
9070
+ if (targetIndex >= 0 && belongsToTrackedChangeSyncDocument(targetComment, normalizedDocumentId) && Array.from(targetIds).some((id) => normalizedDecidedIds.has(id))) {
9012
9071
  targetIds.forEach((id) => removedIds.add(id));
9013
9072
  commentsList.value.splice(targetIndex, 1);
9014
9073
  removed = true;
@@ -9016,7 +9075,7 @@ const useCommentsStore = defineStore("comments", () => {
9016
9075
  if (!comment?.trackedChange) return true;
9017
9076
  if (!belongsToTrackedChangeSyncDocument(comment, normalizedDocumentId)) return true;
9018
9077
  const ids = collectTrackedChangeDecisionIds(comment);
9019
- if (!Array.from(normalizedDecidedIds).some((id) => ids.has(id))) return true;
9078
+ if (!Array.from(ids).some((id) => normalizedDecidedIds.has(id))) return true;
9020
9079
  removed = true;
9021
9080
  ids.forEach((id) => removedIds.add(id));
9022
9081
  return false;
@@ -9032,6 +9091,31 @@ const useCommentsStore = defineStore("comments", () => {
9032
9091
  removedIds
9033
9092
  };
9034
9093
  };
9094
+ const clearAllResolvedTrackedChangeRows = ({ adapter, documentId } = {}) => {
9095
+ const normalizedDocumentId = normalizeCommentId(documentId);
9096
+ if (!adapter || !normalizedDocumentId) return {
9097
+ removed: 0,
9098
+ removedIds: /* @__PURE__ */ new Set()
9099
+ };
9100
+ supersedeTrackedChangeSyncGeneration(adapter);
9101
+ const removedIds = /* @__PURE__ */ new Set();
9102
+ const activeId = normalizeCommentId(activeComment.value);
9103
+ let activeWasRemoved = false;
9104
+ const next = commentsList.value.filter((comment) => {
9105
+ if (!comment?.trackedChange || !belongsToTrackedChangeSyncDocument(comment, normalizedDocumentId)) return true;
9106
+ const aliases = collectTrackedChangeDecisionIds(comment);
9107
+ aliases.forEach((id) => removedIds.add(id));
9108
+ if (activeId && aliases.has(activeId)) activeWasRemoved = true;
9109
+ return false;
9110
+ });
9111
+ const removed = commentsList.value.length - next.length;
9112
+ if (removed > 0) commentsList.value = next;
9113
+ if (activeWasRemoved) clearActiveCommentSelection();
9114
+ return {
9115
+ removed,
9116
+ removedIds
9117
+ };
9118
+ };
9035
9119
  const clearV2ActiveTrackedChangeTarget = (adapter, decidedId) => {
9036
9120
  if (!decidedId || typeof adapter?.clearActiveTrackedChangeTargetIfMatches !== "function") return;
9037
9121
  try {
@@ -9242,7 +9326,7 @@ const useCommentsStore = defineStore("comments", () => {
9242
9326
  success: Boolean(command(id))
9243
9327
  };
9244
9328
  };
9245
- const hydrateTrackedChangesFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", refreshReason, blocking } = {}) => withInteractionSpan("store.trackedChanges.hydrateFromV2", "tracked-change-list", {
9329
+ const hydrateTrackedChangesFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", refreshReason, blocking, signal, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.hydrateFromV2", "tracked-change-list", {
9246
9330
  documentId: documentId ?? null,
9247
9331
  trackedChangesListMode,
9248
9332
  refreshReason: refreshReason ?? null,
@@ -9253,11 +9337,19 @@ const useCommentsStore = defineStore("comments", () => {
9253
9337
  ok: false,
9254
9338
  reason: "adapter-missing"
9255
9339
  };
9340
+ const syncGeneration = trackedChangeSyncGeneration(effectiveAdapter);
9341
+ if (signal?.aborted) return {
9342
+ ok: false,
9343
+ reason: "review-hydration-superseded",
9344
+ lateResultDropped: false
9345
+ };
9256
9346
  let result;
9257
9347
  try {
9258
9348
  const listOptions = { mode: trackedChangesListMode };
9259
9349
  if (refreshReason != null) listOptions.refreshReason = refreshReason;
9260
9350
  if (typeof blocking === "boolean") listOptions.blocking = blocking;
9351
+ if (signal) listOptions.signal = signal;
9352
+ if (typeof hydrationGeneration === "number") listOptions.hydrationGeneration = hydrationGeneration;
9261
9353
  result = await effectiveAdapter.listTrackedChanges(listOptions);
9262
9354
  } catch (err) {
9263
9355
  return {
@@ -9270,18 +9362,36 @@ const useCommentsStore = defineStore("comments", () => {
9270
9362
  ok: false,
9271
9363
  reason: "adapter-stale"
9272
9364
  };
9365
+ if (trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
9366
+ ok: false,
9367
+ reason: "review-hydration-superseded",
9368
+ lateResultDropped: true
9369
+ };
9370
+ if (signal?.aborted) return {
9371
+ ok: false,
9372
+ reason: "review-hydration-superseded",
9373
+ lateResultDropped: true
9374
+ };
9273
9375
  if (!result?.ok) return result;
9274
9376
  const pruneStale = !(trackedChangesListMode === "startup-page" || trackedChangesListMode === "interaction-prime" || trackedChangesListMode === "visible-window") && result.visibleWindowSource == null && result.complete === true && result.sourceCoverageComplete === true;
9377
+ if (signal?.aborted || trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
9378
+ ok: false,
9379
+ reason: "review-hydration-superseded",
9380
+ lateResultDropped: true
9381
+ };
9275
9382
  reconcileTrackedChangesFromV2({
9276
9383
  superdoc,
9277
9384
  adapter: effectiveAdapter,
9278
9385
  documentId,
9279
9386
  items: result.items ?? [],
9280
- pruneStale
9387
+ pruneStale,
9388
+ hydrationGeneration
9281
9389
  });
9282
9390
  const hydrationResult = {
9283
9391
  ok: true,
9284
- items: result.items ?? []
9392
+ items: result.items ?? [],
9393
+ reconciled: true,
9394
+ ...typeof hydrationGeneration === "number" ? { hydrationGeneration } : {}
9285
9395
  };
9286
9396
  if (typeof result.complete === "boolean") hydrationResult.complete = result.complete;
9287
9397
  if (typeof result.sourceCoverageComplete === "boolean") hydrationResult.sourceCoverageComplete = result.sourceCoverageComplete;
@@ -9292,11 +9402,14 @@ const useCommentsStore = defineStore("comments", () => {
9292
9402
  if (typeof result.refreshReason === "string") hydrationResult.refreshReason = result.refreshReason;
9293
9403
  if (typeof result.blocking === "boolean") hydrationResult.blocking = result.blocking;
9294
9404
  if (typeof result.pageCount === "number") hydrationResult.pageCount = result.pageCount;
9405
+ if (typeof result.pagesStarted === "number") hydrationResult.pagesStarted = result.pagesStarted;
9406
+ if (typeof result.pagesCompleted === "number") hydrationResult.pagesCompleted = result.pagesCompleted;
9407
+ if (typeof result.pagesSkippedAfterAbort === "number") hydrationResult.pagesSkippedAfterAbort = result.pagesSkippedAfterAbort;
9295
9408
  if (typeof result.totalItems === "number") hydrationResult.totalItems = result.totalItems;
9296
9409
  if (typeof result.coalesced === "boolean") hydrationResult.coalesced = result.coalesced;
9297
9410
  return hydrationResult;
9298
9411
  });
9299
- const reconcileTrackedChangeMutationFromV2 = async ({ superdoc, adapter, documentId, upsertIds = [], removedIds = [] } = {}) => {
9412
+ const reconcileTrackedChangeMutationFromV2 = async ({ superdoc, adapter, documentId, upsertIds = [], removedIds = [], allResolved } = {}) => {
9300
9413
  const effectiveAdapter = adapter ?? getV2TrackedChangesAdapter(superdoc);
9301
9414
  if (!effectiveAdapter) return {
9302
9415
  ok: false,
@@ -9307,6 +9420,26 @@ const useCommentsStore = defineStore("comments", () => {
9307
9420
  reason: "adapter-stale"
9308
9421
  };
9309
9422
  const effectiveDocumentId = documentId ?? effectiveAdapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9423
+ if (allResolved && effectiveDocumentId == null) return {
9424
+ ok: false,
9425
+ reason: "document-id-missing"
9426
+ };
9427
+ if (allResolved) return {
9428
+ ok: true,
9429
+ items: [],
9430
+ resolvedIds: [],
9431
+ unresolvedIds: [],
9432
+ allResolved: true,
9433
+ removedRows: withInteractionSpan("store.trackedChanges.allResolved", "store-reconciliation", {
9434
+ documentId: String(effectiveDocumentId),
9435
+ logicalTargetCount: allResolved.logicalTargetCount ?? null,
9436
+ physicalCarrierCount: allResolved.physicalCarrierCount ?? null
9437
+ }, () => clearAllResolvedTrackedChangeRows({
9438
+ adapter: effectiveAdapter,
9439
+ documentId: effectiveDocumentId
9440
+ })).removed
9441
+ };
9442
+ const syncGeneration = trackedChangeSyncGeneration(effectiveAdapter);
9310
9443
  const normalizedRemovedIds = new Set(Array.from(removedIds ?? []).map((id) => normalizeCommentId(id)).filter(Boolean));
9311
9444
  const normalizedUpsertIds = [...new Set(Array.from(upsertIds ?? []).map((id) => normalizeCommentId(id)).filter(Boolean))];
9312
9445
  if (normalizedRemovedIds.size > 0 && normalizedUpsertIds.length === 0 && effectiveDocumentId != null) pruneDecidedTrackedChangeRow({
@@ -9345,6 +9478,10 @@ const useCommentsStore = defineStore("comments", () => {
9345
9478
  ok: false,
9346
9479
  reason: "adapter-stale"
9347
9480
  };
9481
+ if (trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
9482
+ ok: false,
9483
+ reason: "generation-stale"
9484
+ };
9348
9485
  const resolvedIds = [];
9349
9486
  const unresolvedIds = [];
9350
9487
  const items = [];
@@ -9371,35 +9508,105 @@ const useCommentsStore = defineStore("comments", () => {
9371
9508
  failures: reads.map(({ result }) => result).filter((result) => !result?.ok)
9372
9509
  };
9373
9510
  };
9374
- const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
9511
+ const createTrackedChangeBatchIdentityIndex = (documentId) => {
9512
+ const byIdentityAlias = /* @__PURE__ */ new Map();
9513
+ const indexedRows = /* @__PURE__ */ new Set();
9514
+ let aliasLookups = 0;
9515
+ let candidateVisits = 0;
9516
+ const addAlias = (index, value, comment) => {
9517
+ const alias = normalizeCommentId(value);
9518
+ if (!alias) return;
9519
+ const bucket = index.get(alias) ?? /* @__PURE__ */ new Set();
9520
+ bucket.add(comment);
9521
+ index.set(alias, bucket);
9522
+ };
9523
+ const add = (comment) => {
9524
+ if (!comment?.trackedChange) return;
9525
+ if (documentId && !belongsToTrackedChangeSyncDocument(comment, documentId)) return;
9526
+ indexedRows.add(comment);
9527
+ addAlias(byIdentityAlias, comment.commentId, comment);
9528
+ addAlias(byIdentityAlias, comment.importedId, comment);
9529
+ addAlias(byIdentityAlias, comment.trackedChangeCanonicalId, comment);
9530
+ addAlias(byIdentityAlias, comment.trackedChangeAnchorKey, comment);
9531
+ getCommentAliasIds(comment).forEach((alias) => addAlias(byIdentityAlias, alias, comment));
9532
+ };
9533
+ commentsList.value.forEach(add);
9534
+ return {
9535
+ add,
9536
+ work: () => ({
9537
+ trackedRowsIndexed: indexedRows.size,
9538
+ invalidatedIdMembershipChecks: 0,
9539
+ incomingAliasLookups: aliasLookups,
9540
+ candidateVisits
9541
+ }),
9542
+ candidates({ changeId, importedId, anchorKey, canonicalId, positionAliases = [] } = {}) {
9543
+ const out = /* @__PURE__ */ new Set();
9544
+ const include = (value) => {
9545
+ const alias = normalizeCommentId(value);
9546
+ if (!alias) return;
9547
+ aliasLookups += 1;
9548
+ const bucket = byIdentityAlias.get(alias);
9549
+ if (!bucket) return;
9550
+ candidateVisits += bucket.size;
9551
+ bucket.forEach((comment) => out.add(comment));
9552
+ };
9553
+ new Set([
9554
+ changeId,
9555
+ importedId,
9556
+ canonicalId,
9557
+ anchorKey,
9558
+ ...positionAliases
9559
+ ]).forEach(include);
9560
+ return out;
9561
+ }
9562
+ };
9563
+ };
9564
+ const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
9375
9565
  documentId: documentId ?? null,
9376
9566
  itemCount: Array.isArray(items) ? items.length : null,
9377
- pruneStale
9567
+ pruneStale,
9568
+ hydrationGeneration: hydrationGeneration ?? null
9378
9569
  }, () => {
9379
9570
  if (!adapter || !Array.isArray(items)) return;
9380
9571
  if (!isCurrentV2TrackedChangesAdapter(adapter)) return;
9381
9572
  const effectiveDocumentId = documentId ?? adapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9382
9573
  const liveAnchorKeys = /* @__PURE__ */ new Set();
9383
9574
  const liveIds = /* @__PURE__ */ new Set();
9575
+ const trackedChangeIdentityIndex = createTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
9576
+ const identitySpan = startInteractionSpan("store.trackedChanges.batchIdentity", "store-reconciliation", { itemCount: items.length });
9384
9577
  const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
9385
- for (const params of paramsList) {
9386
- if (!params) continue;
9387
- if (params.event === "omit") {
9578
+ try {
9579
+ for (const params of paramsList) {
9580
+ if (!params) continue;
9581
+ if (params.event === "omit") {
9582
+ if (params.changeId != null) liveIds.add(String(params.changeId));
9583
+ continue;
9584
+ }
9585
+ if (effectiveDocumentId && params.documentId == null) params.documentId = effectiveDocumentId;
9388
9586
  if (params.changeId != null) liveIds.add(String(params.changeId));
9389
- continue;
9587
+ if (params.trackedChangeAnchorKey != null) liveAnchorKeys.add(String(params.trackedChangeAnchorKey));
9588
+ handleTrackedChangeUpdate({
9589
+ superdoc,
9590
+ params,
9591
+ broadcastChanges: false,
9592
+ trackedChangeIdentityIndex
9593
+ });
9390
9594
  }
9391
- if (effectiveDocumentId && params.documentId == null) params.documentId = effectiveDocumentId;
9392
- if (params.changeId != null) liveIds.add(String(params.changeId));
9393
- if (params.trackedChangeAnchorKey != null) liveAnchorKeys.add(String(params.trackedChangeAnchorKey));
9394
- handleTrackedChangeUpdate({
9395
- superdoc,
9396
- params,
9397
- broadcastChanges: false
9398
- });
9595
+ } finally {
9596
+ endInteractionSpan(identitySpan, trackedChangeIdentityIndex.work());
9399
9597
  }
9400
9598
  if (!effectiveDocumentId || !pruneStale) return;
9401
9599
  pruneStaleTrackedChangeComments(liveIds, liveAnchorKeys, String(effectiveDocumentId), superdoc, { broadcastChanges: false });
9402
9600
  });
9601
+ const getV2TrackedChangeRowCount = (documentId = null) => {
9602
+ const normalizedDocumentId = documentId == null ? null : String(documentId);
9603
+ return commentsList.value.filter((comment) => {
9604
+ if (comment?.trackedChange !== true) return false;
9605
+ if (normalizedDocumentId == null) return true;
9606
+ const rowDocumentId = comment?.documentId ?? comment?.fileId ?? null;
9607
+ return rowDocumentId != null && String(rowDocumentId) === normalizedDocumentId;
9608
+ }).length;
9609
+ };
9403
9610
  const syncTrackedChangeComments = ({ superdoc, editor, broadcastChanges = true }) => {
9404
9611
  if (!superdoc || !editor) return;
9405
9612
  const activeDocumentId = editor?.options?.documentId != null ? String(editor.options.documentId) : null;
@@ -9966,6 +10173,7 @@ const useCommentsStore = defineStore("comments", () => {
9966
10173
  getV2CommentsAdapter,
9967
10174
  hydrateCommentsFromV2,
9968
10175
  applyReviewSnapshotFromV2,
10176
+ supersedeV2ReviewHydration,
9969
10177
  reconcileCommentsFromV2,
9970
10178
  isV2EditorActive,
9971
10179
  replyCommentV2,
@@ -9975,6 +10183,7 @@ const useCommentsStore = defineStore("comments", () => {
9975
10183
  v2TrackedChangesAdapter,
9976
10184
  setV2TrackedChangesAdapter,
9977
10185
  getV2TrackedChangesAdapter,
10186
+ getV2TrackedChangeRowCount,
9978
10187
  hydrateTrackedChangesFromV2,
9979
10188
  reconcileTrackedChangeMutationFromV2,
9980
10189
  reconcileTrackedChangesFromV2,
@@ -18940,6 +19149,23 @@ var _sfc_main$20 = {
18940
19149
  const onV2HostEvent = (document$1, event) => {
18941
19150
  if (!event) return;
18942
19151
  const documentId = document$1?.id ?? null;
19152
+ if (event.type === "review-mutation:started") {
19153
+ const activeEditor = proxy.$superdoc?.activeEditor ?? null;
19154
+ commentsStore.supersedeV2ReviewHydration?.({
19155
+ commentsAdapter: activeEditor?.v2Comments ?? null,
19156
+ trackedChangesAdapter: activeEditor?.v2TrackedChanges ?? null
19157
+ });
19158
+ v2ReviewHydrationController.beginMutation(event.reviewMutation);
19159
+ return;
19160
+ }
19161
+ if (event.type === "review-mutation:aborted") {
19162
+ v2ReviewHydrationController.settleMutation(event.reviewMutation?.token, {
19163
+ outcome: "aborted",
19164
+ resumeDomains: ["comments", "trackedChanges"],
19165
+ trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
19166
+ });
19167
+ return;
19168
+ }
18943
19169
  if (event.type === "reviewTarget:changed") {
18944
19170
  syncSidebarActiveCommentFromV2ReviewTarget(event.next);
18945
19171
  return;
@@ -18958,6 +19184,11 @@ var _sfc_main$20 = {
18958
19184
  return;
18959
19185
  }
18960
19186
  if (event.type === "mutation:rejected") {
19187
+ if (event.reviewMutation?.token) v2ReviewHydrationController.settleMutation(event.reviewMutation.token, {
19188
+ outcome: "rejected",
19189
+ resumeDomains: ["comments", "trackedChanges"],
19190
+ trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
19191
+ });
18961
19192
  maybeNotifyV2AuthorRequired(documentId, event);
18962
19193
  return;
18963
19194
  }
@@ -18973,7 +19204,22 @@ var _sfc_main$20 = {
18973
19204
  const readiness = (proxy.$superdoc?.activeEditor ?? null)?.documentMutationReadiness ?? null;
18974
19205
  const receipt = event.origin === "history" ? null : event.receipt;
18975
19206
  const canWaitForExactPaint = reviewImpact && typeof receipt?.txId === "string" && receipt.txId.length > 0 && typeof readiness?.whenPainted === "function";
18976
- v2ReviewMutationReconciler.enqueueAfterPaint(reviewImpact, canWaitForExactPaint ? () => readiness.whenPainted.call(readiness, receipt) : null);
19207
+ const reconciliation = v2ReviewMutationReconciler.enqueueAfterPaint(reviewImpact, canWaitForExactPaint ? () => readiness.whenPainted.call(readiness, receipt) : null);
19208
+ if (event.reviewMutation?.token) {
19209
+ const reviewMutation = event.reviewMutation;
19210
+ const allResolved = Boolean(reviewImpact?.allResolved ?? event.trackedChangeAllResolved);
19211
+ const settleReviewMutation = (reconciled) => {
19212
+ const reconciledAllResolved = allResolved && reconciled === true;
19213
+ v2ReviewHydrationController.settleMutation(reviewMutation.token, {
19214
+ outcome: "committed",
19215
+ allResolved: reconciledAllResolved,
19216
+ resumeDomains: reconciledAllResolved ? ["comments"] : ["comments", "trackedChanges"],
19217
+ trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
19218
+ });
19219
+ };
19220
+ Promise.resolve(reconciliation).then(settleReviewMutation, () => settleReviewMutation(false));
19221
+ return;
19222
+ }
18977
19223
  if (reviewImpact?.reconcileMode === "authoritative" && reviewImpact.upsertIds.size > 0) {
18978
19224
  hydrateV2CommentRowsFromHost();
18979
19225
  return;
@@ -20109,7 +20355,7 @@ var _sfc_main$20 = {
20109
20355
  };
20110
20356
  }
20111
20357
  };
20112
- var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-d75089d2"]]);
20358
+ var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-e489229f"]]);
20113
20359
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
20114
20360
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
20115
20361
  var piniaDevtoolsSuppressionState = {
@@ -38846,7 +39092,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
38846
39092
  this.config.colors = shuffleArray(this.config.colors);
38847
39093
  this.userColorMap = /* @__PURE__ */ new Map();
38848
39094
  this.colorIndex = 0;
38849
- this.version = "2.4.0-next.2";
39095
+ this.version = "2.4.0-next.3";
38850
39096
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
38851
39097
  this.superdocId = config.superdocId || require_uuid.v4_default();
38852
39098
  this.colors = this.config.colors ?? [];
@@ -39728,8 +39974,8 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
39728
39974
  },
39729
39975
  {
39730
39976
  feature: "shell.tracked-change-sidebar.bulk",
39731
- status: "not-shipped",
39732
- reason: "bulk-tracked-change-decisions-omitted: acceptAll/rejectAll are matrix-disabled by default in the v2 host"
39977
+ status: "supported",
39978
+ reason: "SD-4039/SD-4040: the shipped v2 command posture exposes all-story Accept All and Reject All through the canonical doc.trackChanges.decide({ target: { kind: 'all' } }) mutation"
39733
39979
  },
39734
39980
  {
39735
39981
  feature: "shell.tracked-change-sidebar.non-body",