superdoc 2.4.0-next.1 → 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/chunks/{create-super-doc-ui-DXdWuTzm.cjs → create-super-doc-ui-BHMQEL2y.cjs} +247 -25
- package/dist/chunks/{create-super-doc-ui-D4kk9AjM.es.js → create-super-doc-ui-Dli6Wq70.es.js} +247 -25
- package/dist/collaboration-upgrade-engine.cjs +1 -1
- package/dist/collaboration-upgrade-engine.es.js +1 -1
- package/dist/public/ui-react.cjs +1 -1
- package/dist/public/ui-react.es.js +1 -1
- package/dist/public/ui.cjs +1 -1
- package/dist/public/ui.es.js +1 -1
- package/dist/style.css +87 -87
- package/dist/style.layered.css +87 -87
- package/dist/superdoc/src/helpers/v2-review-mutation-impact.d.ts +1 -0
- package/dist/superdoc/src/helpers/v2-review-mutation-reconciler.d.ts +1 -1
- package/dist/superdoc/src/stores/comments-store.d.ts +79 -19
- package/dist/superdoc/src/stores/superdoc-store.d.ts +237 -57
- package/dist/superdoc.cjs +281 -35
- package/dist/superdoc.es.js +281 -35
- package/dist-cdn/style.layered.css +1 -1
- package/dist-cdn/superdoc.min.css +1 -1
- package/dist-cdn/superdoc.min.js +36 -36
- package/package.json +2 -2
|
@@ -334,14 +334,21 @@ function getV2TrackedChangeMutationImpact(event) {
|
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
for (const id of removedIds) upsertIds.delete(id);
|
|
337
|
-
|
|
337
|
+
const allResolved = readAllResolvedFact(event, payload);
|
|
338
|
+
if (upsertIds.size === 0 && removedIds.size === 0 && !allResolved) return null;
|
|
338
339
|
return {
|
|
339
340
|
upsertIds,
|
|
340
341
|
removedIds,
|
|
341
342
|
remappedPairs,
|
|
342
|
-
reconcileMode: event.origin === "history" ? "authoritative" : "targeted"
|
|
343
|
+
reconcileMode: event.origin === "history" ? "authoritative" : "targeted",
|
|
344
|
+
...allResolved ? { allResolved } : {}
|
|
343
345
|
};
|
|
344
346
|
}
|
|
347
|
+
function readAllResolvedFact(event, receipt) {
|
|
348
|
+
const fact = event?.trackedChangeAllResolved;
|
|
349
|
+
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;
|
|
350
|
+
return fact;
|
|
351
|
+
}
|
|
345
352
|
var normalizeIds = (values) => new Set(Array.from(values ?? []).filter((value) => typeof value === "string" && value.length > 0));
|
|
346
353
|
var itemId = (item) => {
|
|
347
354
|
if (typeof item?.id === "string" && item.id.length > 0) return item.id;
|
|
@@ -352,10 +359,20 @@ var itemId = (item) => {
|
|
|
352
359
|
var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor && left?.reconcileToken === right?.reconcileToken;
|
|
353
360
|
function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onReconciled }) {
|
|
354
361
|
const pendingUpserts = /* @__PURE__ */ new Map();
|
|
362
|
+
let pendingAllResolved = null;
|
|
355
363
|
let sequence = 0;
|
|
356
364
|
let generation = 0;
|
|
357
365
|
let flushInFlight = null;
|
|
358
366
|
let flushRequested = false;
|
|
367
|
+
const settlementWaiters = [];
|
|
368
|
+
const resolveSettlementsThrough = (version, value) => {
|
|
369
|
+
for (let index = settlementWaiters.length - 1; index >= 0; index -= 1) {
|
|
370
|
+
const waiter = settlementWaiters[index];
|
|
371
|
+
if (waiter.generation !== generation || waiter.version > version) continue;
|
|
372
|
+
settlementWaiters.splice(index, 1);
|
|
373
|
+
waiter.resolve(value === true && waiter.requiresAllResolved ? pendingAllResolved == null : value);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
359
376
|
const isCurrent = (capturedGeneration, context) => generation === capturedGeneration && contextMatches(context, getContext());
|
|
360
377
|
const clearResolved = (ids, snapshot) => {
|
|
361
378
|
const clearedIds = /* @__PURE__ */ new Set();
|
|
@@ -369,6 +386,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
369
386
|
const readySnapshot = (reconcileMode) => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true && entry.reconcileMode === reconcileMode));
|
|
370
387
|
const markRenderGatedReady = () => {
|
|
371
388
|
let changed = false;
|
|
389
|
+
if (pendingAllResolved?.gate === "render" && !pendingAllResolved.ready) {
|
|
390
|
+
pendingAllResolved.ready = true;
|
|
391
|
+
changed = true;
|
|
392
|
+
}
|
|
372
393
|
for (const entry of pendingUpserts.values()) {
|
|
373
394
|
if (entry.gate !== "render" || entry.ready) continue;
|
|
374
395
|
entry.ready = true;
|
|
@@ -378,6 +399,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
378
399
|
};
|
|
379
400
|
const markEntriesReadyThrough = (maxVersion) => {
|
|
380
401
|
let changed = false;
|
|
402
|
+
if (pendingAllResolved && pendingAllResolved.version <= maxVersion && !pendingAllResolved.ready) {
|
|
403
|
+
pendingAllResolved.ready = true;
|
|
404
|
+
changed = true;
|
|
405
|
+
}
|
|
381
406
|
for (const entry of pendingUpserts.values()) {
|
|
382
407
|
if (entry.version > maxVersion || entry.ready) continue;
|
|
383
408
|
entry.ready = true;
|
|
@@ -428,14 +453,31 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
428
453
|
};
|
|
429
454
|
const flush = () => {
|
|
430
455
|
if (flushInFlight) return flushInFlight;
|
|
456
|
+
const allResolvedSnapshot = pendingAllResolved?.ready ? pendingAllResolved : null;
|
|
431
457
|
const targetedSnapshot = readySnapshot("targeted");
|
|
432
458
|
const authoritativeSnapshot = readySnapshot("authoritative");
|
|
433
|
-
if (targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
|
|
459
|
+
if (!allResolvedSnapshot && targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
|
|
434
460
|
const context = getContext();
|
|
435
461
|
if (!context?.adapter) return null;
|
|
436
462
|
flushRequested = false;
|
|
437
463
|
const capturedGeneration = generation;
|
|
438
464
|
flushInFlight = Promise.resolve().then(async () => {
|
|
465
|
+
if (allResolvedSnapshot) {
|
|
466
|
+
let result = null;
|
|
467
|
+
try {
|
|
468
|
+
result = await reconcile(context, {
|
|
469
|
+
upsertIds: /* @__PURE__ */ new Set(),
|
|
470
|
+
removedIds: /* @__PURE__ */ new Set(),
|
|
471
|
+
allResolved: allResolvedSnapshot.fact,
|
|
472
|
+
reconcileMode: "targeted"
|
|
473
|
+
});
|
|
474
|
+
} catch {}
|
|
475
|
+
if (!isCurrent(capturedGeneration, context)) return;
|
|
476
|
+
if (result?.ok === true) {
|
|
477
|
+
if (pendingAllResolved === allResolvedSnapshot) pendingAllResolved = null;
|
|
478
|
+
await notifyReconciled(context, /* @__PURE__ */ new Set(), result, true);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
439
481
|
if (authoritativeSnapshot.size > 0) await reconcileAuthoritativeSnapshot(context, authoritativeSnapshot, capturedGeneration).catch(() => void 0);
|
|
440
482
|
if (targetedSnapshot.size > 0) await reconcileTargetedSnapshot(context, targetedSnapshot, capturedGeneration).catch(() => void 0);
|
|
441
483
|
}).catch(() => {}).finally(() => {
|
|
@@ -446,6 +488,15 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
446
488
|
};
|
|
447
489
|
const enqueueWithGate = (impact, gate) => {
|
|
448
490
|
if (!impact) return;
|
|
491
|
+
if (impact.allResolved) {
|
|
492
|
+
pendingUpserts.clear();
|
|
493
|
+
pendingAllResolved = {
|
|
494
|
+
fact: impact.allResolved,
|
|
495
|
+
version: ++sequence,
|
|
496
|
+
gate,
|
|
497
|
+
ready: false
|
|
498
|
+
};
|
|
499
|
+
}
|
|
449
500
|
const reconcileMode = impact.reconcileMode === "authoritative" ? "authoritative" : "targeted";
|
|
450
501
|
const removedIds = normalizeIds(impact.removedIds);
|
|
451
502
|
const upsertIds = normalizeIds(impact.upsertIds);
|
|
@@ -460,7 +511,7 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
460
511
|
else pendingUpserts.delete(id);
|
|
461
512
|
}
|
|
462
513
|
const context = getContext();
|
|
463
|
-
if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter) try {
|
|
514
|
+
if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter && !impact.allResolved) try {
|
|
464
515
|
Promise.resolve(reconcile(context, {
|
|
465
516
|
upsertIds: /* @__PURE__ */ new Set(),
|
|
466
517
|
removedIds
|
|
@@ -487,20 +538,34 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
487
538
|
enqueueAfterPaint(impact, waitForPaint) {
|
|
488
539
|
if (!impact || typeof waitForPaint !== "function") {
|
|
489
540
|
enqueue(impact);
|
|
490
|
-
return;
|
|
541
|
+
return Promise.resolve(false);
|
|
491
542
|
}
|
|
492
543
|
enqueueWithGate(impact, "exact-paint");
|
|
493
544
|
const context = getContext();
|
|
494
|
-
if (!context?.adapter) return;
|
|
495
545
|
const capturedGeneration = generation;
|
|
496
546
|
const capturedSequence = sequence;
|
|
547
|
+
if (!context?.adapter) {
|
|
548
|
+
markEntriesReadyThrough(capturedSequence);
|
|
549
|
+
return Promise.resolve(false);
|
|
550
|
+
}
|
|
551
|
+
const completion = new Promise((resolve) => {
|
|
552
|
+
settlementWaiters.push({
|
|
553
|
+
generation: capturedGeneration,
|
|
554
|
+
version: capturedSequence,
|
|
555
|
+
requiresAllResolved: Boolean(impact.allResolved),
|
|
556
|
+
resolve
|
|
557
|
+
});
|
|
558
|
+
});
|
|
497
559
|
const impactedIds = new Set([...normalizeIds(impact.upsertIds), ...normalizeIds(impact.removedIds)]);
|
|
498
560
|
const capturedEntries = new Map([...impactedIds].flatMap((id) => {
|
|
499
561
|
const entry = pendingUpserts.get(id);
|
|
500
562
|
return entry ? [[id, entry]] : [];
|
|
501
563
|
}));
|
|
502
|
-
Promise.resolve().then(() => waitForPaint()).then(() => {
|
|
503
|
-
if (!isCurrent(capturedGeneration, context))
|
|
564
|
+
Promise.resolve().then(() => waitForPaint()).then(async () => {
|
|
565
|
+
if (!isCurrent(capturedGeneration, context)) {
|
|
566
|
+
resolveSettlementsThrough(capturedSequence, false);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
504
569
|
let madeReady = markRenderGatedReady();
|
|
505
570
|
if (markEntriesReadyThrough(capturedSequence)) madeReady = true;
|
|
506
571
|
for (const [id, entry] of capturedEntries) {
|
|
@@ -509,16 +574,35 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
|
|
|
509
574
|
entry.ready = true;
|
|
510
575
|
}
|
|
511
576
|
if (flushInFlight && (madeReady || capturedSequence > 0)) flushRequested = true;
|
|
512
|
-
|
|
577
|
+
const preceding = flushInFlight;
|
|
578
|
+
const pending = flush();
|
|
579
|
+
if (pending) await pending;
|
|
580
|
+
if (preceding) {
|
|
581
|
+
const followUp = flushInFlight;
|
|
582
|
+
if (followUp && followUp !== preceding) await followUp;
|
|
583
|
+
}
|
|
584
|
+
if (!isCurrent(capturedGeneration, context)) {
|
|
585
|
+
resolveSettlementsThrough(capturedSequence, false);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
resolveSettlementsThrough(capturedSequence, true);
|
|
513
589
|
}).catch(() => {
|
|
514
|
-
if (!isCurrent(capturedGeneration, context))
|
|
590
|
+
if (!isCurrent(capturedGeneration, context)) {
|
|
591
|
+
resolveSettlementsThrough(capturedSequence, false);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
515
594
|
for (const [id, entry] of capturedEntries) if (pendingUpserts.get(id) === entry) entry.gate = "render";
|
|
595
|
+
if (pendingAllResolved?.gate === "exact-paint") pendingAllResolved.gate = "render";
|
|
596
|
+
resolveSettlementsThrough(capturedSequence, false);
|
|
516
597
|
});
|
|
598
|
+
return completion;
|
|
517
599
|
},
|
|
518
600
|
onRender,
|
|
519
601
|
reset() {
|
|
602
|
+
for (const waiter of settlementWaiters.splice(0)) waiter.resolve(false);
|
|
520
603
|
generation += 1;
|
|
521
604
|
pendingUpserts.clear();
|
|
605
|
+
pendingAllResolved = null;
|
|
522
606
|
flushRequested = false;
|
|
523
607
|
},
|
|
524
608
|
getPendingIds() {
|
|
@@ -1716,6 +1800,30 @@ const INLINE_PROPERTY_KEYS_BY_STORAGE = {
|
|
|
1716
1800
|
mark: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry) => entry.key),
|
|
1717
1801
|
runAttribute: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "runAttribute").map((entry) => entry.key)
|
|
1718
1802
|
};
|
|
1803
|
+
var sharedUiTrackedChangesCatalogByHost = /* @__PURE__ */ new WeakMap();
|
|
1804
|
+
function acquireSharedUiTrackedChangesCatalog(host) {
|
|
1805
|
+
let state = sharedUiTrackedChangesCatalogByHost.get(host);
|
|
1806
|
+
if (!state) {
|
|
1807
|
+
state = {
|
|
1808
|
+
refCount: 0,
|
|
1809
|
+
generation: 0,
|
|
1810
|
+
abortController: new AbortController(),
|
|
1811
|
+
inFlight: null,
|
|
1812
|
+
activeMutationTokens: /* @__PURE__ */ new Set()
|
|
1813
|
+
};
|
|
1814
|
+
sharedUiTrackedChangesCatalogByHost.set(host, state);
|
|
1815
|
+
}
|
|
1816
|
+
state.refCount += 1;
|
|
1817
|
+
return state;
|
|
1818
|
+
}
|
|
1819
|
+
function releaseSharedUiTrackedChangesCatalog(host, state) {
|
|
1820
|
+
state.refCount = Math.max(0, state.refCount - 1);
|
|
1821
|
+
if (state.refCount > 0) return;
|
|
1822
|
+
state.abortController.abort("ui-controller-destroyed");
|
|
1823
|
+
state.inFlight = null;
|
|
1824
|
+
state.activeMutationTokens.clear();
|
|
1825
|
+
sharedUiTrackedChangesCatalogByHost.delete(host);
|
|
1826
|
+
}
|
|
1719
1827
|
var SUPERDOC_UI_REASON_VALUES = new Set(Object.values(SUPERDOC_UI_REASONS));
|
|
1720
1828
|
function coerceSuperDocUIReason(reason, fallback) {
|
|
1721
1829
|
return typeof reason === "string" && SUPERDOC_UI_REASON_VALUES.has(reason) ? reason : fallback;
|
|
@@ -1812,12 +1920,12 @@ const HEAVY_DOC_READ_POLICY = [
|
|
|
1812
1920
|
{
|
|
1813
1921
|
key: "trackChanges",
|
|
1814
1922
|
match: "exact",
|
|
1815
|
-
note: "audited: all-story tracked-changes
|
|
1923
|
+
note: "audited: shared all-story tracked-changes catalog; stale-served during load"
|
|
1816
1924
|
},
|
|
1817
1925
|
{
|
|
1818
1926
|
key: "trackChanges:all",
|
|
1819
1927
|
match: "exact",
|
|
1820
|
-
note: "audited: all-story
|
|
1928
|
+
note: "audited: current-token validation over the shared all-story catalog; consumers fail closed on non-ready"
|
|
1821
1929
|
},
|
|
1822
1930
|
{
|
|
1823
1931
|
key: "tables",
|
|
@@ -3276,6 +3384,63 @@ function createSuperDocUI(options) {
|
|
|
3276
3384
|
};
|
|
3277
3385
|
let documentMutationRevision = 0;
|
|
3278
3386
|
let reviewMutationToken = {};
|
|
3387
|
+
const uiTrackedChangesCatalogHost = options.superdoc;
|
|
3388
|
+
const uiTrackedChangesCatalogState = acquireSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost);
|
|
3389
|
+
const supersedeUiTrackedChangesCatalogRead = () => {
|
|
3390
|
+
uiTrackedChangesCatalogState.abortController.abort("review-mutation-started");
|
|
3391
|
+
uiTrackedChangesCatalogState.inFlight = null;
|
|
3392
|
+
};
|
|
3393
|
+
const renewUiTrackedChangesCatalogRead = () => {
|
|
3394
|
+
uiTrackedChangesCatalogState.generation += 1;
|
|
3395
|
+
uiTrackedChangesCatalogState.abortController = new AbortController();
|
|
3396
|
+
uiTrackedChangesCatalogState.inFlight = null;
|
|
3397
|
+
};
|
|
3398
|
+
const beginUiReviewMutation = (token) => {
|
|
3399
|
+
const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
|
|
3400
|
+
if (typeof token !== "string" || token.length === 0 || activeTokens.has(token)) return;
|
|
3401
|
+
const firstToken = activeTokens.size === 0;
|
|
3402
|
+
activeTokens.add(token);
|
|
3403
|
+
if (firstToken) supersedeUiTrackedChangesCatalogRead();
|
|
3404
|
+
};
|
|
3405
|
+
const settleUiReviewMutation = (token) => {
|
|
3406
|
+
const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
|
|
3407
|
+
if (typeof token !== "string" || !activeTokens.delete(token)) return;
|
|
3408
|
+
if (activeTokens.size === 0) renewUiTrackedChangesCatalogRead();
|
|
3409
|
+
};
|
|
3410
|
+
const runUiTrackedChangesCatalogRead = (fallback) => {
|
|
3411
|
+
const v2TrackedChanges = getV2TrackedChanges();
|
|
3412
|
+
const listTrackedChanges = v2TrackedChanges?.listTrackedChanges;
|
|
3413
|
+
if (typeof listTrackedChanges !== "function") {
|
|
3414
|
+
if (getEditor()?.editorVersion === 2) return Promise.reject(/* @__PURE__ */ new Error("v2-tracked-changes-bridge-pending"));
|
|
3415
|
+
return fallback();
|
|
3416
|
+
}
|
|
3417
|
+
if (uiTrackedChangesCatalogState.activeMutationTokens.size > 0) return Promise.reject(/* @__PURE__ */ new Error("ui-review-catalog-superseded"));
|
|
3418
|
+
if ((getEditor()?.reviewHydration?.getDiagnostics?.())?.inFlight === true) return Promise.reject(/* @__PURE__ */ new Error("shell-review-hydration-in-flight"));
|
|
3419
|
+
const generation = uiTrackedChangesCatalogState.generation;
|
|
3420
|
+
const existing = uiTrackedChangesCatalogState.inFlight;
|
|
3421
|
+
if (existing?.generation === generation) return existing.promise;
|
|
3422
|
+
const signal = uiTrackedChangesCatalogState.abortController.signal;
|
|
3423
|
+
const validateResult = (result) => {
|
|
3424
|
+
if (signal.aborted || generation !== uiTrackedChangesCatalogState.generation || result?.reason === "review-hydration-superseded") throw new Error("ui-review-catalog-superseded");
|
|
3425
|
+
return result;
|
|
3426
|
+
};
|
|
3427
|
+
const rawResult = listTrackedChanges.call(v2TrackedChanges, {
|
|
3428
|
+
blocking: false,
|
|
3429
|
+
signal
|
|
3430
|
+
});
|
|
3431
|
+
if (!isPromiseLike(rawResult)) return validateResult(rawResult);
|
|
3432
|
+
const promise = Promise.resolve(rawResult).then(validateResult);
|
|
3433
|
+
uiTrackedChangesCatalogState.inFlight = {
|
|
3434
|
+
generation,
|
|
3435
|
+
promise
|
|
3436
|
+
};
|
|
3437
|
+
promise.then(() => {
|
|
3438
|
+
if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
|
|
3439
|
+
}, () => {
|
|
3440
|
+
if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
|
|
3441
|
+
});
|
|
3442
|
+
return promise;
|
|
3443
|
+
};
|
|
3279
3444
|
let authoritativeTrackChangesPendingToken = null;
|
|
3280
3445
|
let authoritativeTrackChangesRetryTimer = null;
|
|
3281
3446
|
let authoritativeTrackChangesFailureCount = 0;
|
|
@@ -3287,6 +3452,7 @@ function createSuperDocUI(options) {
|
|
|
3287
3452
|
let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
|
|
3288
3453
|
let postDecisionTrackChangesToken = null;
|
|
3289
3454
|
let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
|
|
3455
|
+
let allTrackedChangesResolvedToken = null;
|
|
3290
3456
|
let selectionEpoch = 0;
|
|
3291
3457
|
let lastCoordinatorEditor = null;
|
|
3292
3458
|
const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
|
|
@@ -3365,6 +3531,23 @@ function createSuperDocUI(options) {
|
|
|
3365
3531
|
};
|
|
3366
3532
|
notifyPostDecisionTrackChanges(receipt);
|
|
3367
3533
|
};
|
|
3534
|
+
const publishAllTrackedChangesResolved = (receipt) => {
|
|
3535
|
+
const previous = state.trackChanges;
|
|
3536
|
+
const changed = previous.items.length > 0 || previous.total !== 0 || previous.activeId !== null || previous.authors.length > 0;
|
|
3537
|
+
allTrackedChangesResolvedToken = contentToken();
|
|
3538
|
+
if (explicitActiveChange !== null) setExplicitActiveChange(null);
|
|
3539
|
+
state = {
|
|
3540
|
+
...state,
|
|
3541
|
+
trackChanges: {
|
|
3542
|
+
...previous,
|
|
3543
|
+
items: [],
|
|
3544
|
+
total: 0,
|
|
3545
|
+
activeId: null,
|
|
3546
|
+
authors: []
|
|
3547
|
+
}
|
|
3548
|
+
};
|
|
3549
|
+
if (changed) notifyPostDecisionTrackChanges(receipt);
|
|
3550
|
+
};
|
|
3368
3551
|
const markPostDecisionTrackChanges = (ids, receipt) => {
|
|
3369
3552
|
if (ids.size === 0) return;
|
|
3370
3553
|
const token = contentToken();
|
|
@@ -4043,6 +4226,7 @@ function createSuperDocUI(options) {
|
|
|
4043
4226
|
detachSourceLoading = null;
|
|
4044
4227
|
sourceLoadingSubscriptionHost = null;
|
|
4045
4228
|
clearPostDecisionTrackChanges();
|
|
4229
|
+
allTrackedChangesResolvedToken = null;
|
|
4046
4230
|
};
|
|
4047
4231
|
const invalidateDocumentContent = () => {
|
|
4048
4232
|
const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
|
|
@@ -4050,6 +4234,15 @@ function createSuperDocUI(options) {
|
|
|
4050
4234
|
if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
|
|
4051
4235
|
clearPostDecisionTrackChanges();
|
|
4052
4236
|
};
|
|
4237
|
+
const invalidateAfterCommandSettlement = () => {
|
|
4238
|
+
const carryAllResolvedCatalog = allTrackedChangesResolvedToken === contentToken();
|
|
4239
|
+
invalidateDocumentContent();
|
|
4240
|
+
if (carryAllResolvedCatalog) {
|
|
4241
|
+
replaceTrackedChangeItemsInCache([]);
|
|
4242
|
+
allTrackedChangesResolvedToken = contentToken();
|
|
4243
|
+
}
|
|
4244
|
+
recompute();
|
|
4245
|
+
};
|
|
4053
4246
|
const insertText = (text) => {
|
|
4054
4247
|
if (typeof text !== "string" || text.length === 0) return failedReceipt("insertText requires a non-empty string.", "INVALID_INPUT");
|
|
4055
4248
|
if (readDocumentMode() === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
|
|
@@ -4253,7 +4446,17 @@ function createSuperDocUI(options) {
|
|
|
4253
4446
|
const { value, status } = authoritativeTrackChangesPendingToken === token ? {
|
|
4254
4447
|
value: heldEntry?.hasSettled ? heldEntry.value : null,
|
|
4255
4448
|
status: heldEntry?.hasSettled ? "stale" : "pending"
|
|
4256
|
-
} : readAsync("trackChanges:all", token, () =>
|
|
4449
|
+
} : readAsync("trackChanges:all", token, () => {
|
|
4450
|
+
if (!tcApi?.list) return void 0;
|
|
4451
|
+
const fallback = () => tcApi.list({ in: "all" });
|
|
4452
|
+
const bridgeOwnsCatalog = typeof getV2TrackedChanges()?.listTrackedChanges === "function";
|
|
4453
|
+
const shared = runUiTrackedChangesCatalogRead(fallback);
|
|
4454
|
+
if (!bridgeOwnsCatalog) return shared;
|
|
4455
|
+
return Promise.resolve(shared).then((raw) => {
|
|
4456
|
+
const record = isLooseObject(raw) ? raw : null;
|
|
4457
|
+
return (Array.isArray(record?.items) ? record.items : []).some((item) => readEntityStory(item) == null) ? fallback() : raw;
|
|
4458
|
+
});
|
|
4459
|
+
}, (raw) => {
|
|
4257
4460
|
return (raw && Array.isArray(raw.items) ? raw.items : []).map(projectTrackChangesItem).filter((item) => item != null);
|
|
4258
4461
|
});
|
|
4259
4462
|
return status === "ready" ? value : null;
|
|
@@ -4269,7 +4472,7 @@ function createSuperDocUI(options) {
|
|
|
4269
4472
|
value: heldEntry?.hasSettled ? heldEntry.value : null,
|
|
4270
4473
|
status: heldEntry?.hasSettled ? "stale" : "pending"
|
|
4271
4474
|
} : readAsync("trackChanges", token, () => {
|
|
4272
|
-
if (listTrackedChanges) return
|
|
4475
|
+
if (listTrackedChanges) return runUiTrackedChangesCatalogRead(() => tcApi?.list?.());
|
|
4273
4476
|
return tcApi?.list ? tcApi.list({ in: "all" }) : void 0;
|
|
4274
4477
|
}, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
|
|
4275
4478
|
const items = (value ?? []).map(projectTrackChangesItem).filter((item) => item != null).filter((item) => {
|
|
@@ -4292,7 +4495,7 @@ function createSuperDocUI(options) {
|
|
|
4292
4495
|
}
|
|
4293
4496
|
const publicIdItems = allStoryItems ?? items;
|
|
4294
4497
|
const selectionIdContext = buildStoryScopedTrackedChangeIdContext(publicIdItems, selectionStory(selection$1));
|
|
4295
|
-
const selectionActiveChangeIds = postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
|
|
4498
|
+
const selectionActiveChangeIds = allTrackedChangesResolvedToken === token ? [] : postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
|
|
4296
4499
|
const selectionPublicChangeIds = selectionActiveChangeIds.map((id) => selectionIdContext.toPublicId(id) ?? id);
|
|
4297
4500
|
const explicitActiveIdContext = explicitActiveChange?.story ? buildStoryScopedTrackedChangeIdContext(publicIdItems, explicitActiveChange.story) : buildTrackedChangeIdContext(publicIdItems);
|
|
4298
4501
|
const explicitActiveId = explicitActiveChange ? explicitActiveIdContext.toPublicId(explicitActiveChange.id) ?? explicitActiveChange.id : null;
|
|
@@ -6055,6 +6258,20 @@ function createSuperDocUI(options) {
|
|
|
6055
6258
|
try {
|
|
6056
6259
|
const off = next.subscribe((event) => {
|
|
6057
6260
|
const type = event?.type;
|
|
6261
|
+
if (type === "review-mutation:started") {
|
|
6262
|
+
beginUiReviewMutation(event.reviewMutation?.token);
|
|
6263
|
+
return;
|
|
6264
|
+
}
|
|
6265
|
+
if (type === "review-mutation:aborted") {
|
|
6266
|
+
settleUiReviewMutation(event.reviewMutation?.token);
|
|
6267
|
+
scheduleAsyncRefresh();
|
|
6268
|
+
return;
|
|
6269
|
+
}
|
|
6270
|
+
if (type === "mutation:rejected" && event.reviewMutation) {
|
|
6271
|
+
settleUiReviewMutation(event.reviewMutation.token);
|
|
6272
|
+
scheduleAsyncRefresh();
|
|
6273
|
+
}
|
|
6274
|
+
if (type === "mutation:committed" && event.reviewMutation) settleUiReviewMutation(event.reviewMutation.token);
|
|
6058
6275
|
if (type === "source:complete" || type === "source:signals-complete") {
|
|
6059
6276
|
if (authoritativeTrackChangesPendingToken !== null) {
|
|
6060
6277
|
clearAuthoritativeTrackChangesRetry();
|
|
@@ -6070,6 +6287,13 @@ function createSuperDocUI(options) {
|
|
|
6070
6287
|
if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
|
|
6071
6288
|
const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
|
|
6072
6289
|
const supersedesPendingReviewReconcile = type === "mutation:committed" && reviewMutationReconciler.getPendingIds().size > 0;
|
|
6290
|
+
if (impact?.allResolved) {
|
|
6291
|
+
reviewMutationReconciler.reset();
|
|
6292
|
+
replaceTrackedChangeItemsInCache([]);
|
|
6293
|
+
authoritativeTrackChangesPendingToken = null;
|
|
6294
|
+
publishAllTrackedChangesResolved(event.receipt);
|
|
6295
|
+
return;
|
|
6296
|
+
}
|
|
6073
6297
|
if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds), event.receipt);
|
|
6074
6298
|
const authoritativeHistoryImpact = impact?.reconcileMode === "authoritative" && impact.upsertIds.size > 0;
|
|
6075
6299
|
if (authoritativeHistoryImpact) {
|
|
@@ -6303,7 +6527,7 @@ function createSuperDocUI(options) {
|
|
|
6303
6527
|
}
|
|
6304
6528
|
function resolveTrackDecisionTarget(command, payload) {
|
|
6305
6529
|
if (command.scope === "all") return {
|
|
6306
|
-
target: {
|
|
6530
|
+
target: { kind: "all" },
|
|
6307
6531
|
changeId: null
|
|
6308
6532
|
};
|
|
6309
6533
|
if (typeof payload === "string" && payload.length > 0) return {
|
|
@@ -6549,13 +6773,11 @@ function createSuperDocUI(options) {
|
|
|
6549
6773
|
};
|
|
6550
6774
|
const finalizeCommandSettlement = (promise, onSettled) => promise.then((settled) => {
|
|
6551
6775
|
onSettled?.(settled);
|
|
6552
|
-
|
|
6553
|
-
recompute();
|
|
6776
|
+
invalidateAfterCommandSettlement();
|
|
6554
6777
|
return settled;
|
|
6555
6778
|
}, () => {
|
|
6556
6779
|
onSettled?.(false);
|
|
6557
|
-
|
|
6558
|
-
recompute();
|
|
6780
|
+
invalidateAfterCommandSettlement();
|
|
6559
6781
|
return false;
|
|
6560
6782
|
});
|
|
6561
6783
|
const settleCommandExecution = (result, onSettled) => {
|
|
@@ -6578,8 +6800,7 @@ function createSuperDocUI(options) {
|
|
|
6578
6800
|
}
|
|
6579
6801
|
onSettled?.(settled);
|
|
6580
6802
|
lastCommandSettlement = Promise.resolve(settled);
|
|
6581
|
-
|
|
6582
|
-
recompute();
|
|
6803
|
+
invalidateAfterCommandSettlement();
|
|
6583
6804
|
return settled;
|
|
6584
6805
|
};
|
|
6585
6806
|
const normalizeWorkflowReceipt = (value, fallback) => {
|
|
@@ -8175,8 +8396,8 @@ function createSuperDocUI(options) {
|
|
|
8175
8396
|
},
|
|
8176
8397
|
accept: (changeId) => executeTrackDecision("accept", changeId),
|
|
8177
8398
|
reject: (changeId) => executeTrackDecision("reject", changeId),
|
|
8178
|
-
acceptAll: () => executeTrackDecisionTarget("accept", {
|
|
8179
|
-
rejectAll: () => executeTrackDecisionTarget("reject", {
|
|
8399
|
+
acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
|
|
8400
|
+
rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
|
|
8180
8401
|
next: () => navigateTrackChange(1),
|
|
8181
8402
|
previous: () => navigateTrackChange(-1),
|
|
8182
8403
|
navigateNext: () => navigateAndScroll(1),
|
|
@@ -8330,7 +8551,7 @@ function createSuperDocUI(options) {
|
|
|
8330
8551
|
const callTrackDecisionTarget = (kind, target, changeId, story) => {
|
|
8331
8552
|
if (reviewMutationsAreReadOnly()) return false;
|
|
8332
8553
|
const tcApi = getDoc()?.trackChanges;
|
|
8333
|
-
const isAllTarget = target.scope === "all";
|
|
8554
|
+
const isAllTarget = target.kind === "all" || target.scope === "all";
|
|
8334
8555
|
const isRangeTarget = target.kind === "range";
|
|
8335
8556
|
const isMultiIdTarget = target.kind === "ids";
|
|
8336
8557
|
if (bulkTrackDecisionBlockedReason({
|
|
@@ -9380,6 +9601,7 @@ function createSuperDocUI(options) {
|
|
|
9380
9601
|
const destroy = () => {
|
|
9381
9602
|
if (disposed) return;
|
|
9382
9603
|
disposed = true;
|
|
9604
|
+
releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
|
|
9383
9605
|
reviewMutationReconciler.reset();
|
|
9384
9606
|
clearAuthoritativeTrackChangesRetry();
|
|
9385
9607
|
if (foregroundAsyncRetryTimer) {
|