superdoc 2.4.0-next.2 → 2.4.0-next.4

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.
@@ -115,14 +115,21 @@ function getV2TrackedChangeMutationImpact(event) {
115
115
  });
116
116
  }
117
117
  for (const id of removedIds) upsertIds.delete(id);
118
- if (upsertIds.size === 0 && removedIds.size === 0) return null;
118
+ const allResolved = readAllResolvedFact(event, payload);
119
+ if (upsertIds.size === 0 && removedIds.size === 0 && !allResolved) return null;
119
120
  return {
120
121
  upsertIds,
121
122
  removedIds,
122
123
  remappedPairs,
123
- reconcileMode: event.origin === "history" ? "authoritative" : "targeted"
124
+ reconcileMode: event.origin === "history" ? "authoritative" : "targeted",
125
+ ...allResolved ? { allResolved } : {}
124
126
  };
125
127
  }
128
+ function readAllResolvedFact(event, receipt) {
129
+ const fact = event?.trackedChangeAllResolved;
130
+ if (event?.origin === "history" || !fact || fact.schemaVersion !== 1 || fact.targetKind !== "all" || fact.decision !== "accept" && fact.decision !== "reject" || fact.remainingLogicalCount !== 0 || typeof fact.catalogRevision !== "string" || !fact.catalogRevision || typeof fact.sourceCoverageRevision !== "string" || !fact.sourceCoverageRevision || !Number.isSafeInteger(fact.logicalTargetCount) || fact.logicalTargetCount <= 0 || !Number.isSafeInteger(fact.physicalCarrierCount) || fact.physicalCarrierCount < fact.logicalTargetCount || typeof fact.txId !== "string" || fact.txId !== receipt.txId || typeof fact.documentEpoch !== "string" || !Number.isSafeInteger(fact.commitSequence) || typeof fact.packagePreviousRevision !== "string" || typeof fact.packageNextRevision !== "string" || fact.packagePreviousRevision === fact.packageNextRevision) return null;
131
+ return fact;
132
+ }
126
133
  var normalizeIds = (values) => new Set(Array.from(values ?? []).filter((value) => typeof value === "string" && value.length > 0));
127
134
  var itemId = (item) => {
128
135
  if (typeof item?.id === "string" && item.id.length > 0) return item.id;
@@ -133,10 +140,20 @@ var itemId = (item) => {
133
140
  var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor && left?.reconcileToken === right?.reconcileToken;
134
141
  function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onReconciled }) {
135
142
  const pendingUpserts = /* @__PURE__ */ new Map();
143
+ let pendingAllResolved = null;
136
144
  let sequence = 0;
137
145
  let generation = 0;
138
146
  let flushInFlight = null;
139
147
  let flushRequested = false;
148
+ const settlementWaiters = [];
149
+ const resolveSettlementsThrough = (version, value) => {
150
+ for (let index = settlementWaiters.length - 1; index >= 0; index -= 1) {
151
+ const waiter = settlementWaiters[index];
152
+ if (waiter.generation !== generation || waiter.version > version) continue;
153
+ settlementWaiters.splice(index, 1);
154
+ waiter.resolve(value === true && waiter.requiresAllResolved ? pendingAllResolved == null : value);
155
+ }
156
+ };
140
157
  const isCurrent = (capturedGeneration, context) => generation === capturedGeneration && contextMatches(context, getContext());
141
158
  const clearResolved = (ids, snapshot) => {
142
159
  const clearedIds = /* @__PURE__ */ new Set();
@@ -150,6 +167,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
150
167
  const readySnapshot = (reconcileMode) => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true && entry.reconcileMode === reconcileMode));
151
168
  const markRenderGatedReady = () => {
152
169
  let changed = false;
170
+ if (pendingAllResolved?.gate === "render" && !pendingAllResolved.ready) {
171
+ pendingAllResolved.ready = true;
172
+ changed = true;
173
+ }
153
174
  for (const entry of pendingUpserts.values()) {
154
175
  if (entry.gate !== "render" || entry.ready) continue;
155
176
  entry.ready = true;
@@ -159,6 +180,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
159
180
  };
160
181
  const markEntriesReadyThrough = (maxVersion) => {
161
182
  let changed = false;
183
+ if (pendingAllResolved && pendingAllResolved.version <= maxVersion && !pendingAllResolved.ready) {
184
+ pendingAllResolved.ready = true;
185
+ changed = true;
186
+ }
162
187
  for (const entry of pendingUpserts.values()) {
163
188
  if (entry.version > maxVersion || entry.ready) continue;
164
189
  entry.ready = true;
@@ -209,14 +234,31 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
209
234
  };
210
235
  const flush = () => {
211
236
  if (flushInFlight) return flushInFlight;
237
+ const allResolvedSnapshot = pendingAllResolved?.ready ? pendingAllResolved : null;
212
238
  const targetedSnapshot = readySnapshot("targeted");
213
239
  const authoritativeSnapshot = readySnapshot("authoritative");
214
- if (targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
240
+ if (!allResolvedSnapshot && targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
215
241
  const context = getContext();
216
242
  if (!context?.adapter) return null;
217
243
  flushRequested = false;
218
244
  const capturedGeneration = generation;
219
245
  flushInFlight = Promise.resolve().then(async () => {
246
+ if (allResolvedSnapshot) {
247
+ let result = null;
248
+ try {
249
+ result = await reconcile(context, {
250
+ upsertIds: /* @__PURE__ */ new Set(),
251
+ removedIds: /* @__PURE__ */ new Set(),
252
+ allResolved: allResolvedSnapshot.fact,
253
+ reconcileMode: "targeted"
254
+ });
255
+ } catch {}
256
+ if (!isCurrent(capturedGeneration, context)) return;
257
+ if (result?.ok === true) {
258
+ if (pendingAllResolved === allResolvedSnapshot) pendingAllResolved = null;
259
+ await notifyReconciled(context, /* @__PURE__ */ new Set(), result, true);
260
+ }
261
+ }
220
262
  if (authoritativeSnapshot.size > 0) await reconcileAuthoritativeSnapshot(context, authoritativeSnapshot, capturedGeneration).catch(() => void 0);
221
263
  if (targetedSnapshot.size > 0) await reconcileTargetedSnapshot(context, targetedSnapshot, capturedGeneration).catch(() => void 0);
222
264
  }).catch(() => {}).finally(() => {
@@ -227,6 +269,15 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
227
269
  };
228
270
  const enqueueWithGate = (impact, gate) => {
229
271
  if (!impact) return;
272
+ if (impact.allResolved) {
273
+ pendingUpserts.clear();
274
+ pendingAllResolved = {
275
+ fact: impact.allResolved,
276
+ version: ++sequence,
277
+ gate,
278
+ ready: false
279
+ };
280
+ }
230
281
  const reconcileMode = impact.reconcileMode === "authoritative" ? "authoritative" : "targeted";
231
282
  const removedIds = normalizeIds(impact.removedIds);
232
283
  const upsertIds = normalizeIds(impact.upsertIds);
@@ -241,7 +292,7 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
241
292
  else pendingUpserts.delete(id);
242
293
  }
243
294
  const context = getContext();
244
- if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter) try {
295
+ if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter && !impact.allResolved) try {
245
296
  Promise.resolve(reconcile(context, {
246
297
  upsertIds: /* @__PURE__ */ new Set(),
247
298
  removedIds
@@ -268,20 +319,34 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
268
319
  enqueueAfterPaint(impact, waitForPaint) {
269
320
  if (!impact || typeof waitForPaint !== "function") {
270
321
  enqueue(impact);
271
- return;
322
+ return Promise.resolve(false);
272
323
  }
273
324
  enqueueWithGate(impact, "exact-paint");
274
325
  const context = getContext();
275
- if (!context?.adapter) return;
276
326
  const capturedGeneration = generation;
277
327
  const capturedSequence = sequence;
328
+ if (!context?.adapter) {
329
+ markEntriesReadyThrough(capturedSequence);
330
+ return Promise.resolve(false);
331
+ }
332
+ const completion = new Promise((resolve) => {
333
+ settlementWaiters.push({
334
+ generation: capturedGeneration,
335
+ version: capturedSequence,
336
+ requiresAllResolved: Boolean(impact.allResolved),
337
+ resolve
338
+ });
339
+ });
278
340
  const impactedIds = new Set([...normalizeIds(impact.upsertIds), ...normalizeIds(impact.removedIds)]);
279
341
  const capturedEntries = new Map([...impactedIds].flatMap((id) => {
280
342
  const entry = pendingUpserts.get(id);
281
343
  return entry ? [[id, entry]] : [];
282
344
  }));
283
- Promise.resolve().then(() => waitForPaint()).then(() => {
284
- if (!isCurrent(capturedGeneration, context)) return;
345
+ Promise.resolve().then(() => waitForPaint()).then(async () => {
346
+ if (!isCurrent(capturedGeneration, context)) {
347
+ resolveSettlementsThrough(capturedSequence, false);
348
+ return;
349
+ }
285
350
  let madeReady = markRenderGatedReady();
286
351
  if (markEntriesReadyThrough(capturedSequence)) madeReady = true;
287
352
  for (const [id, entry] of capturedEntries) {
@@ -290,16 +355,35 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
290
355
  entry.ready = true;
291
356
  }
292
357
  if (flushInFlight && (madeReady || capturedSequence > 0)) flushRequested = true;
293
- flush();
358
+ const preceding = flushInFlight;
359
+ const pending = flush();
360
+ if (pending) await pending;
361
+ if (preceding) {
362
+ const followUp = flushInFlight;
363
+ if (followUp && followUp !== preceding) await followUp;
364
+ }
365
+ if (!isCurrent(capturedGeneration, context)) {
366
+ resolveSettlementsThrough(capturedSequence, false);
367
+ return;
368
+ }
369
+ resolveSettlementsThrough(capturedSequence, true);
294
370
  }).catch(() => {
295
- if (!isCurrent(capturedGeneration, context)) return;
371
+ if (!isCurrent(capturedGeneration, context)) {
372
+ resolveSettlementsThrough(capturedSequence, false);
373
+ return;
374
+ }
296
375
  for (const [id, entry] of capturedEntries) if (pendingUpserts.get(id) === entry) entry.gate = "render";
376
+ if (pendingAllResolved?.gate === "exact-paint") pendingAllResolved.gate = "render";
377
+ resolveSettlementsThrough(capturedSequence, false);
297
378
  });
379
+ return completion;
298
380
  },
299
381
  onRender,
300
382
  reset() {
383
+ for (const waiter of settlementWaiters.splice(0)) waiter.resolve(false);
301
384
  generation += 1;
302
385
  pendingUpserts.clear();
386
+ pendingAllResolved = null;
303
387
  flushRequested = false;
304
388
  },
305
389
  getPendingIds() {
@@ -1494,6 +1578,30 @@ const INLINE_PROPERTY_REGISTRY = [
1494
1578
  new Set(INLINE_PROPERTY_REGISTRY.map((entry) => entry.key));
1495
1579
  const INLINE_PROPERTY_BY_KEY = Object.fromEntries(INLINE_PROPERTY_REGISTRY.map((entry) => [entry.key, entry]));
1496
1580
  INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry) => entry.key), INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "runAttribute").map((entry) => entry.key);
1581
+ var sharedUiTrackedChangesCatalogByHost = /* @__PURE__ */ new WeakMap();
1582
+ function acquireSharedUiTrackedChangesCatalog(host) {
1583
+ let state = sharedUiTrackedChangesCatalogByHost.get(host);
1584
+ if (!state) {
1585
+ state = {
1586
+ refCount: 0,
1587
+ generation: 0,
1588
+ abortController: new AbortController(),
1589
+ inFlight: null,
1590
+ activeMutationTokens: /* @__PURE__ */ new Set()
1591
+ };
1592
+ sharedUiTrackedChangesCatalogByHost.set(host, state);
1593
+ }
1594
+ state.refCount += 1;
1595
+ return state;
1596
+ }
1597
+ function releaseSharedUiTrackedChangesCatalog(host, state) {
1598
+ state.refCount = Math.max(0, state.refCount - 1);
1599
+ if (state.refCount > 0) return;
1600
+ state.abortController.abort("ui-controller-destroyed");
1601
+ state.inFlight = null;
1602
+ state.activeMutationTokens.clear();
1603
+ sharedUiTrackedChangesCatalogByHost.delete(host);
1604
+ }
1497
1605
  var SUPERDOC_UI_REASON_VALUES = new Set(Object.values(SUPERDOC_UI_REASONS));
1498
1606
  function coerceSuperDocUIReason(reason, fallback) {
1499
1607
  return typeof reason === "string" && SUPERDOC_UI_REASON_VALUES.has(reason) ? reason : fallback;
@@ -1590,12 +1698,12 @@ const HEAVY_DOC_READ_POLICY = [
1590
1698
  {
1591
1699
  key: "trackChanges",
1592
1700
  match: "exact",
1593
- note: "audited: all-story tracked-changes list; stale-served during load"
1701
+ note: "audited: shared all-story tracked-changes catalog; stale-served during load"
1594
1702
  },
1595
1703
  {
1596
1704
  key: "trackChanges:all",
1597
1705
  match: "exact",
1598
- note: "audited: all-story tracked-changes list; consumers already fail closed on non-ready"
1706
+ note: "audited: current-token validation over the shared all-story catalog; consumers fail closed on non-ready"
1599
1707
  },
1600
1708
  {
1601
1709
  key: "tables",
@@ -3054,6 +3162,63 @@ function createSuperDocUI(options) {
3054
3162
  };
3055
3163
  let documentMutationRevision = 0;
3056
3164
  let reviewMutationToken = {};
3165
+ const uiTrackedChangesCatalogHost = options.superdoc;
3166
+ const uiTrackedChangesCatalogState = acquireSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost);
3167
+ const supersedeUiTrackedChangesCatalogRead = () => {
3168
+ uiTrackedChangesCatalogState.abortController.abort("review-mutation-started");
3169
+ uiTrackedChangesCatalogState.inFlight = null;
3170
+ };
3171
+ const renewUiTrackedChangesCatalogRead = () => {
3172
+ uiTrackedChangesCatalogState.generation += 1;
3173
+ uiTrackedChangesCatalogState.abortController = new AbortController();
3174
+ uiTrackedChangesCatalogState.inFlight = null;
3175
+ };
3176
+ const beginUiReviewMutation = (token) => {
3177
+ const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
3178
+ if (typeof token !== "string" || token.length === 0 || activeTokens.has(token)) return;
3179
+ const firstToken = activeTokens.size === 0;
3180
+ activeTokens.add(token);
3181
+ if (firstToken) supersedeUiTrackedChangesCatalogRead();
3182
+ };
3183
+ const settleUiReviewMutation = (token) => {
3184
+ const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
3185
+ if (typeof token !== "string" || !activeTokens.delete(token)) return;
3186
+ if (activeTokens.size === 0) renewUiTrackedChangesCatalogRead();
3187
+ };
3188
+ const runUiTrackedChangesCatalogRead = (fallback) => {
3189
+ const v2TrackedChanges = getV2TrackedChanges();
3190
+ const listTrackedChanges = v2TrackedChanges?.listTrackedChanges;
3191
+ if (typeof listTrackedChanges !== "function") {
3192
+ if (getEditor()?.editorVersion === 2) return Promise.reject(/* @__PURE__ */ new Error("v2-tracked-changes-bridge-pending"));
3193
+ return fallback();
3194
+ }
3195
+ if (uiTrackedChangesCatalogState.activeMutationTokens.size > 0) return Promise.reject(/* @__PURE__ */ new Error("ui-review-catalog-superseded"));
3196
+ if ((getEditor()?.reviewHydration?.getDiagnostics?.())?.inFlight === true) return Promise.reject(/* @__PURE__ */ new Error("shell-review-hydration-in-flight"));
3197
+ const generation = uiTrackedChangesCatalogState.generation;
3198
+ const existing = uiTrackedChangesCatalogState.inFlight;
3199
+ if (existing?.generation === generation) return existing.promise;
3200
+ const signal = uiTrackedChangesCatalogState.abortController.signal;
3201
+ const validateResult = (result) => {
3202
+ if (signal.aborted || generation !== uiTrackedChangesCatalogState.generation || result?.reason === "review-hydration-superseded") throw new Error("ui-review-catalog-superseded");
3203
+ return result;
3204
+ };
3205
+ const rawResult = listTrackedChanges.call(v2TrackedChanges, {
3206
+ blocking: false,
3207
+ signal
3208
+ });
3209
+ if (!isPromiseLike(rawResult)) return validateResult(rawResult);
3210
+ const promise = Promise.resolve(rawResult).then(validateResult);
3211
+ uiTrackedChangesCatalogState.inFlight = {
3212
+ generation,
3213
+ promise
3214
+ };
3215
+ promise.then(() => {
3216
+ if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
3217
+ }, () => {
3218
+ if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
3219
+ });
3220
+ return promise;
3221
+ };
3057
3222
  let authoritativeTrackChangesPendingToken = null;
3058
3223
  let authoritativeTrackChangesRetryTimer = null;
3059
3224
  let authoritativeTrackChangesFailureCount = 0;
@@ -3065,6 +3230,7 @@ function createSuperDocUI(options) {
3065
3230
  let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
3066
3231
  let postDecisionTrackChangesToken = null;
3067
3232
  let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
3233
+ let allTrackedChangesResolvedToken = null;
3068
3234
  let selectionEpoch = 0;
3069
3235
  let lastCoordinatorEditor = null;
3070
3236
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
@@ -3143,6 +3309,23 @@ function createSuperDocUI(options) {
3143
3309
  };
3144
3310
  notifyPostDecisionTrackChanges(receipt);
3145
3311
  };
3312
+ const publishAllTrackedChangesResolved = (receipt) => {
3313
+ const previous = state.trackChanges;
3314
+ const changed = previous.items.length > 0 || previous.total !== 0 || previous.activeId !== null || previous.authors.length > 0;
3315
+ allTrackedChangesResolvedToken = contentToken();
3316
+ if (explicitActiveChange !== null) setExplicitActiveChange(null);
3317
+ state = {
3318
+ ...state,
3319
+ trackChanges: {
3320
+ ...previous,
3321
+ items: [],
3322
+ total: 0,
3323
+ activeId: null,
3324
+ authors: []
3325
+ }
3326
+ };
3327
+ if (changed) notifyPostDecisionTrackChanges(receipt);
3328
+ };
3146
3329
  const markPostDecisionTrackChanges = (ids, receipt) => {
3147
3330
  if (ids.size === 0) return;
3148
3331
  const token = contentToken();
@@ -3821,6 +4004,7 @@ function createSuperDocUI(options) {
3821
4004
  detachSourceLoading = null;
3822
4005
  sourceLoadingSubscriptionHost = null;
3823
4006
  clearPostDecisionTrackChanges();
4007
+ allTrackedChangesResolvedToken = null;
3824
4008
  };
3825
4009
  const invalidateDocumentContent = () => {
3826
4010
  const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
@@ -3828,6 +4012,15 @@ function createSuperDocUI(options) {
3828
4012
  if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
3829
4013
  clearPostDecisionTrackChanges();
3830
4014
  };
4015
+ const invalidateAfterCommandSettlement = () => {
4016
+ const carryAllResolvedCatalog = allTrackedChangesResolvedToken === contentToken();
4017
+ invalidateDocumentContent();
4018
+ if (carryAllResolvedCatalog) {
4019
+ replaceTrackedChangeItemsInCache([]);
4020
+ allTrackedChangesResolvedToken = contentToken();
4021
+ }
4022
+ recompute();
4023
+ };
3831
4024
  const insertText = (text) => {
3832
4025
  if (typeof text !== "string" || text.length === 0) return failedReceipt("insertText requires a non-empty string.", "INVALID_INPUT");
3833
4026
  if (readDocumentMode() === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
@@ -4031,7 +4224,17 @@ function createSuperDocUI(options) {
4031
4224
  const { value, status } = authoritativeTrackChangesPendingToken === token ? {
4032
4225
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4033
4226
  status: heldEntry?.hasSettled ? "stale" : "pending"
4034
- } : readAsync("trackChanges:all", token, () => tcApi?.list ? tcApi.list({ in: "all" }) : void 0, (raw) => {
4227
+ } : readAsync("trackChanges:all", token, () => {
4228
+ if (!tcApi?.list) return void 0;
4229
+ const fallback = () => tcApi.list({ in: "all" });
4230
+ const bridgeOwnsCatalog = typeof getV2TrackedChanges()?.listTrackedChanges === "function";
4231
+ const shared = runUiTrackedChangesCatalogRead(fallback);
4232
+ if (!bridgeOwnsCatalog) return shared;
4233
+ return Promise.resolve(shared).then((raw) => {
4234
+ const record = isLooseObject(raw) ? raw : null;
4235
+ return (Array.isArray(record?.items) ? record.items : []).some((item) => readEntityStory(item) == null) ? fallback() : raw;
4236
+ });
4237
+ }, (raw) => {
4035
4238
  return (raw && Array.isArray(raw.items) ? raw.items : []).map(projectTrackChangesItem).filter((item) => item != null);
4036
4239
  });
4037
4240
  return status === "ready" ? value : null;
@@ -4047,7 +4250,7 @@ function createSuperDocUI(options) {
4047
4250
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4048
4251
  status: heldEntry?.hasSettled ? "stale" : "pending"
4049
4252
  } : readAsync("trackChanges", token, () => {
4050
- if (listTrackedChanges) return listTrackedChanges.call(v2TrackedChanges);
4253
+ if (listTrackedChanges) return runUiTrackedChangesCatalogRead(() => tcApi?.list?.());
4051
4254
  return tcApi?.list ? tcApi.list({ in: "all" }) : void 0;
4052
4255
  }, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
4053
4256
  const items = (value ?? []).map(projectTrackChangesItem).filter((item) => item != null).filter((item) => {
@@ -4070,7 +4273,7 @@ function createSuperDocUI(options) {
4070
4273
  }
4071
4274
  const publicIdItems = allStoryItems ?? items;
4072
4275
  const selectionIdContext = buildStoryScopedTrackedChangeIdContext(publicIdItems, selectionStory(selection$1));
4073
- const selectionActiveChangeIds = postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4276
+ const selectionActiveChangeIds = allTrackedChangesResolvedToken === token ? [] : postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4074
4277
  const selectionPublicChangeIds = selectionActiveChangeIds.map((id) => selectionIdContext.toPublicId(id) ?? id);
4075
4278
  const explicitActiveIdContext = explicitActiveChange?.story ? buildStoryScopedTrackedChangeIdContext(publicIdItems, explicitActiveChange.story) : buildTrackedChangeIdContext(publicIdItems);
4076
4279
  const explicitActiveId = explicitActiveChange ? explicitActiveIdContext.toPublicId(explicitActiveChange.id) ?? explicitActiveChange.id : null;
@@ -5833,6 +6036,20 @@ function createSuperDocUI(options) {
5833
6036
  try {
5834
6037
  const off = next.subscribe((event) => {
5835
6038
  const type = event?.type;
6039
+ if (type === "review-mutation:started") {
6040
+ beginUiReviewMutation(event.reviewMutation?.token);
6041
+ return;
6042
+ }
6043
+ if (type === "review-mutation:aborted") {
6044
+ settleUiReviewMutation(event.reviewMutation?.token);
6045
+ scheduleAsyncRefresh();
6046
+ return;
6047
+ }
6048
+ if (type === "mutation:rejected" && event.reviewMutation) {
6049
+ settleUiReviewMutation(event.reviewMutation.token);
6050
+ scheduleAsyncRefresh();
6051
+ }
6052
+ if (type === "mutation:committed" && event.reviewMutation) settleUiReviewMutation(event.reviewMutation.token);
5836
6053
  if (type === "source:complete" || type === "source:signals-complete") {
5837
6054
  if (authoritativeTrackChangesPendingToken !== null) {
5838
6055
  clearAuthoritativeTrackChangesRetry();
@@ -5848,6 +6065,13 @@ function createSuperDocUI(options) {
5848
6065
  if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
5849
6066
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
5850
6067
  const supersedesPendingReviewReconcile = type === "mutation:committed" && reviewMutationReconciler.getPendingIds().size > 0;
6068
+ if (impact?.allResolved) {
6069
+ reviewMutationReconciler.reset();
6070
+ replaceTrackedChangeItemsInCache([]);
6071
+ authoritativeTrackChangesPendingToken = null;
6072
+ publishAllTrackedChangesResolved(event.receipt);
6073
+ return;
6074
+ }
5851
6075
  if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds), event.receipt);
5852
6076
  const authoritativeHistoryImpact = impact?.reconcileMode === "authoritative" && impact.upsertIds.size > 0;
5853
6077
  if (authoritativeHistoryImpact) {
@@ -6081,7 +6305,7 @@ function createSuperDocUI(options) {
6081
6305
  }
6082
6306
  function resolveTrackDecisionTarget(command, payload) {
6083
6307
  if (command.scope === "all") return {
6084
- target: { scope: "all" },
6308
+ target: { kind: "all" },
6085
6309
  changeId: null
6086
6310
  };
6087
6311
  if (typeof payload === "string" && payload.length > 0) return {
@@ -6327,13 +6551,11 @@ function createSuperDocUI(options) {
6327
6551
  };
6328
6552
  const finalizeCommandSettlement = (promise, onSettled) => promise.then((settled) => {
6329
6553
  onSettled?.(settled);
6330
- invalidateDocumentContent();
6331
- recompute();
6554
+ invalidateAfterCommandSettlement();
6332
6555
  return settled;
6333
6556
  }, () => {
6334
6557
  onSettled?.(false);
6335
- invalidateDocumentContent();
6336
- recompute();
6558
+ invalidateAfterCommandSettlement();
6337
6559
  return false;
6338
6560
  });
6339
6561
  const settleCommandExecution = (result, onSettled) => {
@@ -6356,8 +6578,7 @@ function createSuperDocUI(options) {
6356
6578
  }
6357
6579
  onSettled?.(settled);
6358
6580
  lastCommandSettlement = Promise.resolve(settled);
6359
- invalidateDocumentContent();
6360
- recompute();
6581
+ invalidateAfterCommandSettlement();
6361
6582
  return settled;
6362
6583
  };
6363
6584
  const normalizeWorkflowReceipt = (value, fallback) => {
@@ -7953,8 +8174,8 @@ function createSuperDocUI(options) {
7953
8174
  },
7954
8175
  accept: (changeId) => executeTrackDecision("accept", changeId),
7955
8176
  reject: (changeId) => executeTrackDecision("reject", changeId),
7956
- acceptAll: () => executeTrackDecisionTarget("accept", { scope: "all" }, null),
7957
- rejectAll: () => executeTrackDecisionTarget("reject", { scope: "all" }, null),
8177
+ acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
8178
+ rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
7958
8179
  next: () => navigateTrackChange(1),
7959
8180
  previous: () => navigateTrackChange(-1),
7960
8181
  navigateNext: () => navigateAndScroll(1),
@@ -8108,7 +8329,7 @@ function createSuperDocUI(options) {
8108
8329
  const callTrackDecisionTarget = (kind, target, changeId, story) => {
8109
8330
  if (reviewMutationsAreReadOnly()) return false;
8110
8331
  const tcApi = getDoc()?.trackChanges;
8111
- const isAllTarget = target.scope === "all";
8332
+ const isAllTarget = target.kind === "all" || target.scope === "all";
8112
8333
  const isRangeTarget = target.kind === "range";
8113
8334
  const isMultiIdTarget = target.kind === "ids";
8114
8335
  if (bulkTrackDecisionBlockedReason({
@@ -9158,6 +9379,7 @@ function createSuperDocUI(options) {
9158
9379
  const destroy = () => {
9159
9380
  if (disposed) return;
9160
9381
  disposed = true;
9382
+ releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
9161
9383
  reviewMutationReconciler.reset();
9162
9384
  clearAuthoritativeTrackChangesRetry();
9163
9385
  if (foregroundAsyncRetryTimer) {
@@ -7,7 +7,7 @@ const COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
7
7
  var PRIVATE_ENGINE_INFO = (0, __superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
8
8
  var ENGINE_INFO = Object.freeze({
9
9
  ...PRIVATE_ENGINE_INFO,
10
- superdocVersion: "2.4.0-next.2",
10
+ superdocVersion: "2.4.0-next.4",
11
11
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
12
12
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
13
13
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -6,7 +6,7 @@ const COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
6
6
  var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
7
7
  var ENGINE_INFO = Object.freeze({
8
8
  ...PRIVATE_ENGINE_INFO,
9
- superdocVersion: "2.4.0-next.2",
9
+ superdocVersion: "2.4.0-next.4",
10
10
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
11
11
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
12
12
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("../chunks/rolldown-runtime-1Y-nnZJ3.cjs");
3
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-DXdWuTzm.cjs");
3
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BHMQEL2y.cjs");
4
4
  let react = require("react");
5
5
  var SuperDocUIContext = (0, react.createContext)(null);
6
6
  function disposeOwnedUi(ref) {
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-D4kk9AjM.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-Dli6Wq70.es.js";
2
2
  import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
3
3
  var SuperDocUIContext = createContext(null);
4
4
  function disposeOwnedUi(ref) {
@@ -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-DXdWuTzm.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BHMQEL2y.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-D4kk9AjM.es.js";
1
+ import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-Dli6Wq70.es.js";
2
2
  export { BUILT_IN_COMMAND_IDS, createSuperDocUI, shallowEqual };