@xnetjs/react 1.0.0 → 2.1.0
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/{chunk-MEIYFD6R.js → chunk-ANCTAEML.js} +2 -2
- package/dist/{chunk-RIN2MXZK.js → chunk-H44ZSIH4.js} +43 -7
- package/dist/{chunk-WL7OCTSM.js → chunk-HTFAHJQK.js} +1 -1
- package/dist/{chunk-BDBDZXYS.js → chunk-SZQNGRTO.js} +1 -1
- package/dist/{chunk-Q3NDLI6Z.js → chunk-VZMZQTR7.js} +2 -2
- package/dist/{chunk-EJEGIEIC.js → chunk-ZGP56IIJ.js} +1 -1
- package/dist/core.js +3 -3
- package/dist/database.js +2 -2
- package/dist/{experimental-B2FrBnkV.d.ts → experimental-DyPoZcJT.d.ts} +39 -1
- package/dist/experimental.d.ts +1 -1
- package/dist/experimental.js +7 -3
- package/dist/index.d.ts +182 -6
- package/dist/index.js +613 -61
- package/dist/internal.js +2 -2
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
useInfiniteQuery,
|
|
6
6
|
useIsOffline,
|
|
7
7
|
useNode
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VZMZQTR7.js";
|
|
9
9
|
import {
|
|
10
10
|
useCell,
|
|
11
11
|
useDatabase,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
useDatabaseSchema,
|
|
15
15
|
useRelatedRows,
|
|
16
16
|
useReverseRelations
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-HTFAHJQK.js";
|
|
18
18
|
import {
|
|
19
19
|
AuthErrorScreen,
|
|
20
20
|
AuthenticatingScreen,
|
|
@@ -94,7 +94,7 @@ import {
|
|
|
94
94
|
useUndo,
|
|
95
95
|
useVerification,
|
|
96
96
|
useVisibleComments
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-ANCTAEML.js";
|
|
98
98
|
import {
|
|
99
99
|
EMPTY_PAGE_INFO,
|
|
100
100
|
computeFallbackPageInfo,
|
|
@@ -106,10 +106,10 @@ import {
|
|
|
106
106
|
useMutate,
|
|
107
107
|
useQuery,
|
|
108
108
|
useSyncManager
|
|
109
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-ZGP56IIJ.js";
|
|
110
110
|
import {
|
|
111
111
|
useUndoScope
|
|
112
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-SZQNGRTO.js";
|
|
113
113
|
import {
|
|
114
114
|
InstrumentationContext,
|
|
115
115
|
useInstrumentation
|
|
@@ -122,6 +122,7 @@ import {
|
|
|
122
122
|
TracingContext,
|
|
123
123
|
XNetContext,
|
|
124
124
|
XNetProvider,
|
|
125
|
+
mergeEditorContributions,
|
|
125
126
|
useCommand,
|
|
126
127
|
useCommands,
|
|
127
128
|
useContributions,
|
|
@@ -129,6 +130,7 @@ import {
|
|
|
129
130
|
useEditorExtensions,
|
|
130
131
|
useEditorExtensionsSafe,
|
|
131
132
|
useImporters,
|
|
133
|
+
useMergedEditorContributions,
|
|
132
134
|
useNodeStore,
|
|
133
135
|
usePluginRegistry,
|
|
134
136
|
usePluginRegistryOptional,
|
|
@@ -142,7 +144,7 @@ import {
|
|
|
142
144
|
useView,
|
|
143
145
|
useViews,
|
|
144
146
|
useXNet
|
|
145
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-H44ZSIH4.js";
|
|
146
148
|
|
|
147
149
|
// src/hooks/useEffectiveSchema.ts
|
|
148
150
|
import {
|
|
@@ -4375,7 +4377,7 @@ function dropSortKey(ordered, movedId, targetIndex) {
|
|
|
4375
4377
|
}
|
|
4376
4378
|
var formulaService = new FormulaService();
|
|
4377
4379
|
function useGridDatabase(databaseId, options = {}) {
|
|
4378
|
-
const { viewId, search, pageSize = 500 } = options;
|
|
4380
|
+
const { viewId, search, pageSize = 500, maxLoaded = 2e3 } = options;
|
|
4379
4381
|
const mutate = useMutate();
|
|
4380
4382
|
const { did } = useIdentity();
|
|
4381
4383
|
const { data: database, status: dbStatus } = useQuery(DatabaseSchema, databaseId);
|
|
@@ -4391,10 +4393,22 @@ function useGridDatabase(databaseId, options = {}) {
|
|
|
4391
4393
|
where: { database: databaseId },
|
|
4392
4394
|
orderBy: { sortKey: "asc" }
|
|
4393
4395
|
});
|
|
4394
|
-
const {
|
|
4396
|
+
const {
|
|
4397
|
+
data: rowNodes,
|
|
4398
|
+
// Masked while a window grow is in flight (previous rows stay visible):
|
|
4399
|
+
// consumers must not fall back to a skeleton mid-grow or scroll position
|
|
4400
|
+
// is lost — `isFetchingMoreRows` reports the in-flight grow instead.
|
|
4401
|
+
loading: rowsLoading,
|
|
4402
|
+
totalCount: totalRowCount,
|
|
4403
|
+
hasMore: hasMoreRows,
|
|
4404
|
+
isFetchingNextPage: isFetchingMoreRows,
|
|
4405
|
+
fetchNextPage: fetchMoreRows
|
|
4406
|
+
} = useInfiniteQuery(DatabaseRowSchema, {
|
|
4395
4407
|
where: { database: databaseId },
|
|
4396
4408
|
orderBy: { sortKey: "asc" },
|
|
4397
|
-
|
|
4409
|
+
pageSize,
|
|
4410
|
+
maxLoaded,
|
|
4411
|
+
page: { count: "exact" },
|
|
4398
4412
|
materializedView: `db:${databaseId}${viewId ? `:view:${viewId}` : ""}`,
|
|
4399
4413
|
...search ? { search } : {}
|
|
4400
4414
|
});
|
|
@@ -4482,11 +4496,22 @@ function useGridDatabase(databaseId, options = {}) {
|
|
|
4482
4496
|
cancelled = true;
|
|
4483
4497
|
};
|
|
4484
4498
|
}, [rowNodes, fields, store]);
|
|
4499
|
+
const rowModelCacheRef = useRef4(
|
|
4500
|
+
{ deps: [], map: /* @__PURE__ */ new WeakMap() }
|
|
4501
|
+
);
|
|
4485
4502
|
const rows = useMemo5(() => {
|
|
4503
|
+
const cacheDeps = [fields, rollupValues, databaseId];
|
|
4504
|
+
if (cacheDeps.length !== rowModelCacheRef.current.deps.length || cacheDeps.some((d, i) => d !== rowModelCacheRef.current.deps[i])) {
|
|
4505
|
+
rowModelCacheRef.current = { deps: cacheDeps, map: /* @__PURE__ */ new WeakMap() };
|
|
4506
|
+
}
|
|
4507
|
+
const cache = rowModelCacheRef.current.map;
|
|
4486
4508
|
const autoFields = fields.filter(
|
|
4487
4509
|
(f) => ["created", "createdBy", "updated", "updatedBy"].includes(f.type)
|
|
4488
4510
|
);
|
|
4489
|
-
const
|
|
4511
|
+
const formulaFields = fields.filter((f) => f.type === "formula");
|
|
4512
|
+
const rollupFields = fields.filter((f) => f.type === "rollup");
|
|
4513
|
+
const columnDefs = formulaFields.length > 0 || activeView ? fieldsToColumnDefinitions(fields) : [];
|
|
4514
|
+
const buildRow = (node) => {
|
|
4490
4515
|
const cells = fromCellProperties(node);
|
|
4491
4516
|
for (const field of autoFields) {
|
|
4492
4517
|
switch (field.type) {
|
|
@@ -4504,47 +4529,43 @@ function useGridDatabase(databaseId, options = {}) {
|
|
|
4504
4529
|
break;
|
|
4505
4530
|
}
|
|
4506
4531
|
}
|
|
4507
|
-
|
|
4532
|
+
const row = {
|
|
4508
4533
|
id: node.id,
|
|
4509
4534
|
sortKey: node.sortKey ?? "",
|
|
4510
4535
|
cells
|
|
4511
4536
|
};
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
columnDef,
|
|
4524
|
-
columnDefs
|
|
4525
|
-
);
|
|
4526
|
-
} catch {
|
|
4527
|
-
row.cells[field.id] = null;
|
|
4528
|
-
}
|
|
4537
|
+
for (const field of formulaFields) {
|
|
4538
|
+
const columnDef = columnDefs.find((c) => c.id === field.id);
|
|
4539
|
+
if (!columnDef) continue;
|
|
4540
|
+
try {
|
|
4541
|
+
row.cells[field.id] = formulaService.compute(
|
|
4542
|
+
{ id: row.id, databaseId, cells: row.cells },
|
|
4543
|
+
columnDef,
|
|
4544
|
+
columnDefs
|
|
4545
|
+
);
|
|
4546
|
+
} catch {
|
|
4547
|
+
row.cells[field.id] = null;
|
|
4529
4548
|
}
|
|
4530
4549
|
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
for (const field of fields) {
|
|
4535
|
-
if (field.type !== "rollup") continue;
|
|
4536
|
-
const computed = rollupValues.get(`${row.id}:${field.id}`);
|
|
4537
|
-
if (computed !== void 0) row.cells[field.id] = computed;
|
|
4538
|
-
}
|
|
4550
|
+
for (const field of rollupFields) {
|
|
4551
|
+
const computed = rollupValues.get(`${row.id}:${field.id}`);
|
|
4552
|
+
if (computed !== void 0) row.cells[field.id] = computed;
|
|
4539
4553
|
}
|
|
4540
|
-
|
|
4554
|
+
return row;
|
|
4555
|
+
};
|
|
4556
|
+
const base = (rowNodes ?? []).map((node) => {
|
|
4557
|
+
const hit = cache.get(node);
|
|
4558
|
+
if (hit) return hit;
|
|
4559
|
+
const row = buildRow(node);
|
|
4560
|
+
cache.set(node, row);
|
|
4561
|
+
return row;
|
|
4562
|
+
});
|
|
4541
4563
|
base.sort((a, b) => compareSortKeys(a.sortKey, b.sortKey));
|
|
4542
4564
|
if (!activeView) return base;
|
|
4543
|
-
const
|
|
4544
|
-
|
|
4545
|
-
return sortRows(filtered, columns, activeView.sorts);
|
|
4565
|
+
const filtered = filterRows(base, columnDefs, activeView.filters);
|
|
4566
|
+
return sortRows(filtered, columnDefs, activeView.sorts);
|
|
4546
4567
|
}, [rowNodes, activeView, fields, databaseId, rollupValues]);
|
|
4547
|
-
const loading = dbStatus === "loading" || fieldStatus === "loading" || viewStatus === "loading" ||
|
|
4568
|
+
const loading = dbStatus === "loading" || fieldStatus === "loading" || viewStatus === "loading" || rowsLoading;
|
|
4548
4569
|
const rowTailRef = useRef4(void 0);
|
|
4549
4570
|
const fieldTailRef = useRef4(void 0);
|
|
4550
4571
|
const viewTailRef = useRef4(void 0);
|
|
@@ -4897,6 +4918,10 @@ function useGridDatabase(databaseId, options = {}) {
|
|
|
4897
4918
|
activeView,
|
|
4898
4919
|
rows,
|
|
4899
4920
|
loading,
|
|
4921
|
+
totalRowCount,
|
|
4922
|
+
hasMoreRows,
|
|
4923
|
+
isFetchingMoreRows,
|
|
4924
|
+
fetchMoreRows,
|
|
4900
4925
|
updateCell,
|
|
4901
4926
|
clearCells,
|
|
4902
4927
|
addRow,
|
|
@@ -4929,8 +4954,531 @@ function useGridDatabase(databaseId, options = {}) {
|
|
|
4929
4954
|
};
|
|
4930
4955
|
}
|
|
4931
4956
|
|
|
4957
|
+
// src/hooks/useTimeMachine.ts
|
|
4958
|
+
import { CHECKPOINT_SCHEMA_IRI } from "@xnetjs/data";
|
|
4959
|
+
import {
|
|
4960
|
+
HistoryEngine,
|
|
4961
|
+
HistoryHorizonError,
|
|
4962
|
+
MemorySnapshotStorage,
|
|
4963
|
+
ScopeTimeline,
|
|
4964
|
+
SnapshotCache,
|
|
4965
|
+
createCheckpoint,
|
|
4966
|
+
listCheckpoints,
|
|
4967
|
+
restoreToFrontier
|
|
4968
|
+
} from "@xnetjs/history";
|
|
4969
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef5, useState as useState7 } from "react";
|
|
4970
|
+
function useTimeMachine(nodeId, options) {
|
|
4971
|
+
const { store, isReady } = useNodeStore();
|
|
4972
|
+
const memberKey = options?.memberIds?.join(",") ?? "";
|
|
4973
|
+
const members = useMemo6(() => {
|
|
4974
|
+
if (!nodeId) return [];
|
|
4975
|
+
const extra = options?.memberIds ?? [];
|
|
4976
|
+
return [nodeId, ...extra.filter((id) => id !== nodeId)];
|
|
4977
|
+
}, [nodeId, memberKey]);
|
|
4978
|
+
const [timeline, setTimeline] = useState7([]);
|
|
4979
|
+
const [checkpoints, setCheckpoints] = useState7([]);
|
|
4980
|
+
const [horizon, setHorizon] = useState7(null);
|
|
4981
|
+
const [docSnapshotCount, setDocSnapshotCount] = useState7(null);
|
|
4982
|
+
const [loading, setLoading] = useState7(false);
|
|
4983
|
+
const [error, setError] = useState7(null);
|
|
4984
|
+
const [rawPosition, setRawPosition] = useState7(null);
|
|
4985
|
+
const position = rawPosition === null ? Math.max(0, timeline.length - 1) : Math.max(0, Math.min(rawPosition, timeline.length - 1));
|
|
4986
|
+
const atLatest = timeline.length === 0 || position === timeline.length - 1;
|
|
4987
|
+
const [preview, setPreview] = useState7(null);
|
|
4988
|
+
const [diffs, setDiffs] = useState7([]);
|
|
4989
|
+
const engineRef = useRef5(null);
|
|
4990
|
+
const getEngines = useCallback4(() => {
|
|
4991
|
+
if (!store) return null;
|
|
4992
|
+
const storage = store.getStorageAdapter();
|
|
4993
|
+
if (!storage) return null;
|
|
4994
|
+
if (!engineRef.current || engineRef.current.storage !== storage) {
|
|
4995
|
+
const snapshots = new SnapshotCache(new MemorySnapshotStorage(), { interval: 50 });
|
|
4996
|
+
engineRef.current = {
|
|
4997
|
+
engine: new HistoryEngine(storage, snapshots),
|
|
4998
|
+
scope: new ScopeTimeline(storage),
|
|
4999
|
+
storage
|
|
5000
|
+
};
|
|
5001
|
+
}
|
|
5002
|
+
return engineRef.current;
|
|
5003
|
+
}, [store]);
|
|
5004
|
+
const reload = useCallback4(async () => {
|
|
5005
|
+
if (!nodeId || !isReady || !store) return;
|
|
5006
|
+
const engines = getEngines();
|
|
5007
|
+
if (!engines) return;
|
|
5008
|
+
setLoading(true);
|
|
5009
|
+
setError(null);
|
|
5010
|
+
try {
|
|
5011
|
+
const [line, nodeHorizon, named] = await Promise.all([
|
|
5012
|
+
engines.scope.getMergedTimeline(members),
|
|
5013
|
+
engines.engine.getHorizon(nodeId),
|
|
5014
|
+
listCheckpoints(store, nodeId)
|
|
5015
|
+
]);
|
|
5016
|
+
setTimeline(line);
|
|
5017
|
+
setHorizon(nodeHorizon);
|
|
5018
|
+
setCheckpoints(named);
|
|
5019
|
+
const snapshotStorage = engines.storage;
|
|
5020
|
+
if (typeof snapshotStorage.getYjsSnapshots === "function") {
|
|
5021
|
+
const snapshots = await snapshotStorage.getYjsSnapshots(nodeId);
|
|
5022
|
+
setDocSnapshotCount(snapshots.length);
|
|
5023
|
+
} else {
|
|
5024
|
+
setDocSnapshotCount(null);
|
|
5025
|
+
}
|
|
5026
|
+
} catch (err) {
|
|
5027
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5028
|
+
} finally {
|
|
5029
|
+
setLoading(false);
|
|
5030
|
+
}
|
|
5031
|
+
}, [nodeId, isReady, store, members, getEngines]);
|
|
5032
|
+
useEffect7(() => {
|
|
5033
|
+
setRawPosition(null);
|
|
5034
|
+
void reload();
|
|
5035
|
+
}, [reload]);
|
|
5036
|
+
useEffect7(() => {
|
|
5037
|
+
if (!store || !nodeId) return;
|
|
5038
|
+
const memberSet = new Set(members);
|
|
5039
|
+
const unsub = store.subscribe((event) => {
|
|
5040
|
+
if (memberSet.has(event.change.payload.nodeId) || event.change.payload.schemaId === CHECKPOINT_SCHEMA_IRI) {
|
|
5041
|
+
void reload();
|
|
5042
|
+
}
|
|
5043
|
+
});
|
|
5044
|
+
return unsub;
|
|
5045
|
+
}, [store, nodeId, members, reload]);
|
|
5046
|
+
useEffect7(() => {
|
|
5047
|
+
let cancelled = false;
|
|
5048
|
+
const engines = getEngines();
|
|
5049
|
+
if (!nodeId || !engines || timeline.length === 0) {
|
|
5050
|
+
setPreview(null);
|
|
5051
|
+
setDiffs([]);
|
|
5052
|
+
return;
|
|
5053
|
+
}
|
|
5054
|
+
let hash = null;
|
|
5055
|
+
for (let i = position; i >= 0; i--) {
|
|
5056
|
+
if (timeline[i].nodeId === nodeId) {
|
|
5057
|
+
hash = timeline[i].change.hash;
|
|
5058
|
+
break;
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
if (!hash) {
|
|
5062
|
+
setPreview(null);
|
|
5063
|
+
setDiffs([]);
|
|
5064
|
+
return;
|
|
5065
|
+
}
|
|
5066
|
+
const target = { type: "hash", hash };
|
|
5067
|
+
Promise.all([
|
|
5068
|
+
engines.engine.materializeAt(nodeId, target),
|
|
5069
|
+
engines.engine.diff(nodeId, target, { type: "latest" })
|
|
5070
|
+
]).then(([state, propertyDiffs]) => {
|
|
5071
|
+
if (cancelled) return;
|
|
5072
|
+
setPreview(state.node);
|
|
5073
|
+
setDiffs(propertyDiffs);
|
|
5074
|
+
}).catch((err) => {
|
|
5075
|
+
if (cancelled) return;
|
|
5076
|
+
setPreview(null);
|
|
5077
|
+
setDiffs([]);
|
|
5078
|
+
if (err instanceof HistoryHorizonError) {
|
|
5079
|
+
setHorizon(err.horizon);
|
|
5080
|
+
} else {
|
|
5081
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5082
|
+
}
|
|
5083
|
+
});
|
|
5084
|
+
return () => {
|
|
5085
|
+
cancelled = true;
|
|
5086
|
+
};
|
|
5087
|
+
}, [nodeId, timeline, position, getEngines]);
|
|
5088
|
+
const setPosition = useCallback4(
|
|
5089
|
+
(index) => {
|
|
5090
|
+
const max = timeline.length - 1;
|
|
5091
|
+
const clamped = Math.max(0, Math.min(index, max));
|
|
5092
|
+
setRawPosition(clamped >= max ? null : clamped);
|
|
5093
|
+
},
|
|
5094
|
+
[timeline.length]
|
|
5095
|
+
);
|
|
5096
|
+
const stepBack = useCallback4(() => setPosition(position - 1), [setPosition, position]);
|
|
5097
|
+
const stepForward = useCallback4(() => setPosition(position + 1), [setPosition, position]);
|
|
5098
|
+
const goToLatest = useCallback4(() => setRawPosition(null), []);
|
|
5099
|
+
const createNamedVersion = useCallback4(
|
|
5100
|
+
async (name, note) => {
|
|
5101
|
+
if (!nodeId || !store) return null;
|
|
5102
|
+
const engines = getEngines();
|
|
5103
|
+
if (!engines) return null;
|
|
5104
|
+
try {
|
|
5105
|
+
const checkpoint = await createCheckpoint(store, engines.storage, {
|
|
5106
|
+
name,
|
|
5107
|
+
...note !== void 0 ? { note } : {},
|
|
5108
|
+
nodeIds: members,
|
|
5109
|
+
scopeId: nodeId
|
|
5110
|
+
});
|
|
5111
|
+
await reload();
|
|
5112
|
+
return checkpoint;
|
|
5113
|
+
} catch (err) {
|
|
5114
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5115
|
+
return null;
|
|
5116
|
+
}
|
|
5117
|
+
},
|
|
5118
|
+
[nodeId, store, members, getEngines, reload]
|
|
5119
|
+
);
|
|
5120
|
+
const positionOfCheckpoint = useCallback4(
|
|
5121
|
+
(checkpoint) => {
|
|
5122
|
+
const frontier = checkpoint.properties.frontier;
|
|
5123
|
+
if (!frontier) return null;
|
|
5124
|
+
let best = -1;
|
|
5125
|
+
for (let i = 0; i < timeline.length; i++) {
|
|
5126
|
+
const pinned = frontier[timeline[i].nodeId];
|
|
5127
|
+
if (pinned && pinned.hash === timeline[i].change.hash) {
|
|
5128
|
+
best = Math.max(best, i);
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
return best >= 0 ? best : null;
|
|
5132
|
+
},
|
|
5133
|
+
[timeline]
|
|
5134
|
+
);
|
|
5135
|
+
const frontierAt = useCallback4(
|
|
5136
|
+
(index) => {
|
|
5137
|
+
const scope = getEngines()?.scope;
|
|
5138
|
+
if (!scope) return {};
|
|
5139
|
+
return scope.frontierAtPosition(timeline, index);
|
|
5140
|
+
},
|
|
5141
|
+
[getEngines, timeline]
|
|
5142
|
+
);
|
|
5143
|
+
const restore = useCallback4(async () => {
|
|
5144
|
+
if (!nodeId || !store || timeline.length === 0) return null;
|
|
5145
|
+
const engines = getEngines();
|
|
5146
|
+
if (!engines) return null;
|
|
5147
|
+
try {
|
|
5148
|
+
const frontier = engines.scope.frontierAtPosition(timeline, position);
|
|
5149
|
+
const result = await restoreToFrontier(store, engines.engine, frontier, members);
|
|
5150
|
+
setRawPosition(null);
|
|
5151
|
+
await reload();
|
|
5152
|
+
return result;
|
|
5153
|
+
} catch (err) {
|
|
5154
|
+
if (err instanceof HistoryHorizonError) setHorizon(err.horizon);
|
|
5155
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5156
|
+
return null;
|
|
5157
|
+
}
|
|
5158
|
+
}, [nodeId, store, timeline, position, members, getEngines, reload]);
|
|
5159
|
+
return {
|
|
5160
|
+
timeline,
|
|
5161
|
+
changeCount: timeline.length,
|
|
5162
|
+
position,
|
|
5163
|
+
atLatest,
|
|
5164
|
+
setPosition,
|
|
5165
|
+
stepBack,
|
|
5166
|
+
stepForward,
|
|
5167
|
+
goToLatest,
|
|
5168
|
+
preview,
|
|
5169
|
+
diffs,
|
|
5170
|
+
horizon,
|
|
5171
|
+
docSnapshotCount,
|
|
5172
|
+
checkpoints,
|
|
5173
|
+
createNamedVersion,
|
|
5174
|
+
positionOfCheckpoint,
|
|
5175
|
+
frontierAt,
|
|
5176
|
+
restore,
|
|
5177
|
+
loading,
|
|
5178
|
+
error,
|
|
5179
|
+
reload
|
|
5180
|
+
};
|
|
5181
|
+
}
|
|
5182
|
+
|
|
5183
|
+
// src/hooks/useDraft.ts
|
|
5184
|
+
import { DRAFT_SCHEMA_IRI, DatabaseRowSchema as DatabaseRowSchema2, DatabaseSchema as DatabaseSchema2 } from "@xnetjs/data";
|
|
5185
|
+
import {
|
|
5186
|
+
HistoryEngine as HistoryEngine2,
|
|
5187
|
+
MemorySnapshotStorage as MemorySnapshotStorage2,
|
|
5188
|
+
SnapshotCache as SnapshotCache2,
|
|
5189
|
+
createDraft as createDraftNode,
|
|
5190
|
+
discardDraft,
|
|
5191
|
+
draftEntries,
|
|
5192
|
+
forkNodeIntoDraft,
|
|
5193
|
+
listDrafts,
|
|
5194
|
+
mergeDraft,
|
|
5195
|
+
refreshDraftFromMain,
|
|
5196
|
+
threeWayPropertyMerge
|
|
5197
|
+
} from "@xnetjs/history";
|
|
5198
|
+
import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
|
|
5199
|
+
var baseIRI = (schemaId) => schemaId.split("@")[0];
|
|
5200
|
+
async function resolveMembers(store, hostId) {
|
|
5201
|
+
const members = [hostId];
|
|
5202
|
+
const host = await store.getRaw(hostId);
|
|
5203
|
+
if (host && baseIRI(host.schemaId) === baseIRI(DatabaseSchema2.schema["@id"])) {
|
|
5204
|
+
const rows = await store.list({ schemaId: DatabaseRowSchema2.schema["@id"] });
|
|
5205
|
+
for (const row of rows) {
|
|
5206
|
+
if (row.properties.database === hostId) members.push(row.id);
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
return members;
|
|
5210
|
+
}
|
|
5211
|
+
function clonesFromEntries(draft) {
|
|
5212
|
+
const clones = {};
|
|
5213
|
+
for (const [originalId, entry] of Object.entries(draftEntries(draft))) {
|
|
5214
|
+
clones[originalId] = entry.cloneId;
|
|
5215
|
+
}
|
|
5216
|
+
return clones;
|
|
5217
|
+
}
|
|
5218
|
+
function useDraft(hostId) {
|
|
5219
|
+
const { store, isReady } = useNodeStore();
|
|
5220
|
+
const [drafts, setDrafts] = useState8([]);
|
|
5221
|
+
const [checkedOut, setCheckedOut] = useState8(null);
|
|
5222
|
+
const [loading, setLoading] = useState8(false);
|
|
5223
|
+
const [error, setError] = useState8(null);
|
|
5224
|
+
const engineRef = useRef6(null);
|
|
5225
|
+
const getEngines = useCallback5(() => {
|
|
5226
|
+
if (!store) return null;
|
|
5227
|
+
const storage = store.getStorageAdapter();
|
|
5228
|
+
if (!storage) return null;
|
|
5229
|
+
if (!engineRef.current || engineRef.current.storage !== storage) {
|
|
5230
|
+
engineRef.current = {
|
|
5231
|
+
engine: new HistoryEngine2(
|
|
5232
|
+
storage,
|
|
5233
|
+
new SnapshotCache2(new MemorySnapshotStorage2(), { interval: 50 })
|
|
5234
|
+
),
|
|
5235
|
+
storage
|
|
5236
|
+
};
|
|
5237
|
+
}
|
|
5238
|
+
return engineRef.current;
|
|
5239
|
+
}, [store]);
|
|
5240
|
+
const draftIdsRef = useRef6(/* @__PURE__ */ new Set());
|
|
5241
|
+
const reload = useCallback5(async () => {
|
|
5242
|
+
if (!hostId || !isReady || !store) return;
|
|
5243
|
+
setLoading(true);
|
|
5244
|
+
setError(null);
|
|
5245
|
+
try {
|
|
5246
|
+
const open = await listDrafts(store, hostId);
|
|
5247
|
+
setDrafts(open);
|
|
5248
|
+
for (const draft of open) draftIdsRef.current.add(draft.id);
|
|
5249
|
+
const overlay = store.getCheckedOutDraft();
|
|
5250
|
+
if (overlay) {
|
|
5251
|
+
const draftNode = await store.getRaw(overlay.draftId);
|
|
5252
|
+
setCheckedOut(
|
|
5253
|
+
draftNode && draftNode.properties.status === "open" && draftNode.properties.target === hostId ? draftNode : null
|
|
5254
|
+
);
|
|
5255
|
+
} else {
|
|
5256
|
+
setCheckedOut(null);
|
|
5257
|
+
}
|
|
5258
|
+
} catch (err) {
|
|
5259
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5260
|
+
} finally {
|
|
5261
|
+
setLoading(false);
|
|
5262
|
+
}
|
|
5263
|
+
}, [hostId, isReady, store]);
|
|
5264
|
+
useEffect8(() => {
|
|
5265
|
+
void reload();
|
|
5266
|
+
}, [reload]);
|
|
5267
|
+
useEffect8(() => {
|
|
5268
|
+
if (!store || !hostId) return;
|
|
5269
|
+
const unsubStore = store.subscribe((event) => {
|
|
5270
|
+
if (event.change.payload.schemaId === DRAFT_SCHEMA_IRI || draftIdsRef.current.has(event.change.payload.nodeId)) {
|
|
5271
|
+
void reload();
|
|
5272
|
+
}
|
|
5273
|
+
});
|
|
5274
|
+
const unsubOverlay = store.subscribeToDraftOverlay(() => void reload());
|
|
5275
|
+
return () => {
|
|
5276
|
+
unsubStore();
|
|
5277
|
+
unsubOverlay();
|
|
5278
|
+
};
|
|
5279
|
+
}, [store, hostId, reload]);
|
|
5280
|
+
const checkout = useCallback5(
|
|
5281
|
+
async (draftId) => {
|
|
5282
|
+
if (!hostId || !store) return false;
|
|
5283
|
+
const engines = getEngines();
|
|
5284
|
+
if (!engines) return false;
|
|
5285
|
+
try {
|
|
5286
|
+
const draft = await store.getRaw(draftId);
|
|
5287
|
+
if (!draft || draft.properties.status !== "open") return false;
|
|
5288
|
+
const members = await resolveMembers(store, hostId);
|
|
5289
|
+
store.setCheckedOutDraft({
|
|
5290
|
+
draftId,
|
|
5291
|
+
members,
|
|
5292
|
+
clones: clonesFromEntries(draft),
|
|
5293
|
+
// Lazy copy-on-write: the first write to an unforked member clones
|
|
5294
|
+
// it. Returning null declines — the write then targets the
|
|
5295
|
+
// original (never-fork schemas stay live by policy).
|
|
5296
|
+
onMissingMember: async (originalId) => {
|
|
5297
|
+
try {
|
|
5298
|
+
const entry = await forkNodeIntoDraft(store, engines.storage, draftId, originalId);
|
|
5299
|
+
return entry.cloneId;
|
|
5300
|
+
} catch {
|
|
5301
|
+
return null;
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
});
|
|
5305
|
+
await reload();
|
|
5306
|
+
return true;
|
|
5307
|
+
} catch (err) {
|
|
5308
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5309
|
+
return false;
|
|
5310
|
+
}
|
|
5311
|
+
},
|
|
5312
|
+
[hostId, store, getEngines, reload]
|
|
5313
|
+
);
|
|
5314
|
+
const returnToMain = useCallback5(() => {
|
|
5315
|
+
if (!store) return;
|
|
5316
|
+
store.setCheckedOutDraft(null);
|
|
5317
|
+
}, [store]);
|
|
5318
|
+
const createDraft = useCallback5(
|
|
5319
|
+
async (name) => {
|
|
5320
|
+
if (!hostId || !store) return null;
|
|
5321
|
+
try {
|
|
5322
|
+
const draft = await createDraftNode(store, { name, targetId: hostId });
|
|
5323
|
+
await checkout(draft.id);
|
|
5324
|
+
return draft;
|
|
5325
|
+
} catch (err) {
|
|
5326
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5327
|
+
return null;
|
|
5328
|
+
}
|
|
5329
|
+
},
|
|
5330
|
+
[hostId, store, checkout]
|
|
5331
|
+
);
|
|
5332
|
+
const discard = useCallback5(
|
|
5333
|
+
async (draftId) => {
|
|
5334
|
+
if (!store) return false;
|
|
5335
|
+
const engines = getEngines();
|
|
5336
|
+
if (!engines) return false;
|
|
5337
|
+
try {
|
|
5338
|
+
if (store.getCheckedOutDraft()?.draftId === draftId) {
|
|
5339
|
+
store.setCheckedOutDraft(null);
|
|
5340
|
+
}
|
|
5341
|
+
await discardDraft(store, engines.storage, draftId);
|
|
5342
|
+
await reload();
|
|
5343
|
+
return true;
|
|
5344
|
+
} catch (err) {
|
|
5345
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5346
|
+
return false;
|
|
5347
|
+
}
|
|
5348
|
+
},
|
|
5349
|
+
[store, getEngines, reload]
|
|
5350
|
+
);
|
|
5351
|
+
const merge = useCallback5(
|
|
5352
|
+
async (draftId) => {
|
|
5353
|
+
if (!store) return null;
|
|
5354
|
+
const engines = getEngines();
|
|
5355
|
+
if (!engines) return null;
|
|
5356
|
+
try {
|
|
5357
|
+
const result = await mergeDraft(store, engines.storage, engines.engine, draftId);
|
|
5358
|
+
if (result.status === "merged" && store.getCheckedOutDraft()?.draftId === draftId) {
|
|
5359
|
+
store.setCheckedOutDraft(null);
|
|
5360
|
+
}
|
|
5361
|
+
await reload();
|
|
5362
|
+
return result;
|
|
5363
|
+
} catch (err) {
|
|
5364
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5365
|
+
return null;
|
|
5366
|
+
}
|
|
5367
|
+
},
|
|
5368
|
+
[store, getEngines, reload]
|
|
5369
|
+
);
|
|
5370
|
+
const refresh = useCallback5(
|
|
5371
|
+
async (draftId) => {
|
|
5372
|
+
if (!store) return null;
|
|
5373
|
+
const engines = getEngines();
|
|
5374
|
+
if (!engines) return null;
|
|
5375
|
+
try {
|
|
5376
|
+
const result = await refreshDraftFromMain(store, engines.storage, engines.engine, draftId);
|
|
5377
|
+
await reload();
|
|
5378
|
+
return result;
|
|
5379
|
+
} catch (err) {
|
|
5380
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5381
|
+
return null;
|
|
5382
|
+
}
|
|
5383
|
+
},
|
|
5384
|
+
[store, getEngines, reload]
|
|
5385
|
+
);
|
|
5386
|
+
const setReviewRequested = useCallback5(
|
|
5387
|
+
async (draftId, requested) => {
|
|
5388
|
+
if (!store) return;
|
|
5389
|
+
try {
|
|
5390
|
+
await store.update(draftId, { properties: { reviewRequested: requested } });
|
|
5391
|
+
} catch (err) {
|
|
5392
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5393
|
+
}
|
|
5394
|
+
},
|
|
5395
|
+
[store]
|
|
5396
|
+
);
|
|
5397
|
+
const computeReview = useCallback5(
|
|
5398
|
+
async (draftId) => {
|
|
5399
|
+
if (!store) return null;
|
|
5400
|
+
const engines = getEngines();
|
|
5401
|
+
if (!engines) return null;
|
|
5402
|
+
try {
|
|
5403
|
+
const draft = await store.getRaw(draftId);
|
|
5404
|
+
if (!draft) return null;
|
|
5405
|
+
const cards = [];
|
|
5406
|
+
const members = [];
|
|
5407
|
+
for (const [id, entry] of Object.entries(draftEntries(draft))) {
|
|
5408
|
+
const originalId = id;
|
|
5409
|
+
const cloneId = entry.cloneId;
|
|
5410
|
+
const [base, ours, theirs] = await Promise.all([
|
|
5411
|
+
engines.engine.materializeAt(originalId, {
|
|
5412
|
+
type: "hash",
|
|
5413
|
+
hash: entry.forkedAtHash
|
|
5414
|
+
}),
|
|
5415
|
+
store.getRaw(originalId),
|
|
5416
|
+
store.getRaw(cloneId)
|
|
5417
|
+
]);
|
|
5418
|
+
if (!ours || !theirs) continue;
|
|
5419
|
+
const result = threeWayPropertyMerge(
|
|
5420
|
+
base.node.properties,
|
|
5421
|
+
ours.properties,
|
|
5422
|
+
theirs.properties
|
|
5423
|
+
);
|
|
5424
|
+
for (const [property, draftValue] of Object.entries(result.patch)) {
|
|
5425
|
+
cards.push({
|
|
5426
|
+
originalId,
|
|
5427
|
+
property,
|
|
5428
|
+
base: base.node.properties[property],
|
|
5429
|
+
main: ours.properties[property],
|
|
5430
|
+
draft: draftValue,
|
|
5431
|
+
conflict: false
|
|
5432
|
+
});
|
|
5433
|
+
}
|
|
5434
|
+
for (const conflict of result.conflicts) {
|
|
5435
|
+
cards.push({
|
|
5436
|
+
originalId,
|
|
5437
|
+
property: conflict.property,
|
|
5438
|
+
base: conflict.base,
|
|
5439
|
+
main: conflict.ours,
|
|
5440
|
+
draft: conflict.theirs,
|
|
5441
|
+
conflict: true
|
|
5442
|
+
});
|
|
5443
|
+
}
|
|
5444
|
+
const hasDocument = Boolean(entry.forkedAtYjsStateVector);
|
|
5445
|
+
let documentDiffers = false;
|
|
5446
|
+
if (hasDocument) {
|
|
5447
|
+
const [cloneBlob, mainBlob] = await Promise.all([
|
|
5448
|
+
engines.storage.getDocumentContent(cloneId),
|
|
5449
|
+
engines.storage.getDocumentContent(originalId)
|
|
5450
|
+
]);
|
|
5451
|
+
documentDiffers = (cloneBlob?.length ?? 0) !== (mainBlob?.length ?? 0);
|
|
5452
|
+
}
|
|
5453
|
+
members.push({ originalId, cloneId, hasDocument, documentDiffers });
|
|
5454
|
+
}
|
|
5455
|
+
return { cards, members };
|
|
5456
|
+
} catch (err) {
|
|
5457
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
5458
|
+
return null;
|
|
5459
|
+
}
|
|
5460
|
+
},
|
|
5461
|
+
[store, getEngines]
|
|
5462
|
+
);
|
|
5463
|
+
return {
|
|
5464
|
+
drafts,
|
|
5465
|
+
checkedOut,
|
|
5466
|
+
createDraft,
|
|
5467
|
+
checkout,
|
|
5468
|
+
returnToMain,
|
|
5469
|
+
discard,
|
|
5470
|
+
merge,
|
|
5471
|
+
refresh,
|
|
5472
|
+
setReviewRequested,
|
|
5473
|
+
computeReview,
|
|
5474
|
+
loading,
|
|
5475
|
+
error,
|
|
5476
|
+
reload
|
|
5477
|
+
};
|
|
5478
|
+
}
|
|
5479
|
+
|
|
4932
5480
|
// src/hooks/useGlobalUndo.ts
|
|
4933
|
-
import { useCallback as
|
|
5481
|
+
import { useCallback as useCallback6, useContext, useEffect as useEffect9, useReducer } from "react";
|
|
4934
5482
|
function readUndoContext(ctx) {
|
|
4935
5483
|
if (!ctx) return { undoManager: null, nodeStore: null };
|
|
4936
5484
|
return { undoManager: ctx.undoManager, nodeStore: ctx.nodeStore };
|
|
@@ -4939,17 +5487,17 @@ function useGlobalUndo() {
|
|
|
4939
5487
|
const ctx = useContext(XNetContext);
|
|
4940
5488
|
const { undoManager, nodeStore } = readUndoContext(ctx);
|
|
4941
5489
|
const [, bump] = useReducer((n) => n + 1, 0);
|
|
4942
|
-
|
|
5490
|
+
useEffect9(() => {
|
|
4943
5491
|
if (!nodeStore) return;
|
|
4944
5492
|
return nodeStore.subscribe(() => bump());
|
|
4945
5493
|
}, [nodeStore]);
|
|
4946
|
-
const undo =
|
|
5494
|
+
const undo = useCallback6(async () => {
|
|
4947
5495
|
if (!undoManager) return false;
|
|
4948
5496
|
const ok = await undoManager.undoLatest();
|
|
4949
5497
|
bump();
|
|
4950
5498
|
return ok;
|
|
4951
5499
|
}, [undoManager]);
|
|
4952
|
-
const redo =
|
|
5500
|
+
const redo = useCallback6(async () => {
|
|
4953
5501
|
if (!undoManager) return false;
|
|
4954
5502
|
const ok = await undoManager.redoLatest();
|
|
4955
5503
|
bump();
|
|
@@ -4964,7 +5512,7 @@ function useGlobalUndo() {
|
|
|
4964
5512
|
}
|
|
4965
5513
|
|
|
4966
5514
|
// src/hooks/useCanCreate.ts
|
|
4967
|
-
import { useEffect as
|
|
5515
|
+
import { useEffect as useEffect10, useMemo as useMemo7, useRef as useRef7, useState as useState9 } from "react";
|
|
4968
5516
|
var INITIAL_STATE = {
|
|
4969
5517
|
canCreate: false,
|
|
4970
5518
|
loading: true,
|
|
@@ -4972,10 +5520,10 @@ var INITIAL_STATE = {
|
|
|
4972
5520
|
};
|
|
4973
5521
|
function useCanCreate(schemaId, properties) {
|
|
4974
5522
|
const { store, isReady } = useNodeStore();
|
|
4975
|
-
const [state, setState] =
|
|
4976
|
-
const requestRef =
|
|
4977
|
-
const propertiesKey =
|
|
4978
|
-
|
|
5523
|
+
const [state, setState] = useState9(INITIAL_STATE);
|
|
5524
|
+
const requestRef = useRef7(0);
|
|
5525
|
+
const propertiesKey = useMemo7(() => JSON.stringify(properties ?? {}), [properties]);
|
|
5526
|
+
useEffect10(() => {
|
|
4979
5527
|
if (!store || !isReady) {
|
|
4980
5528
|
setState((prev) => ({ ...prev, loading: true }));
|
|
4981
5529
|
return;
|
|
@@ -5044,7 +5592,7 @@ import {
|
|
|
5044
5592
|
} from "@xnetjs/runtime";
|
|
5045
5593
|
|
|
5046
5594
|
// src/hooks/useBilling.ts
|
|
5047
|
-
import { useCallback as
|
|
5595
|
+
import { useCallback as useCallback7, useContext as useContext2, useEffect as useEffect11, useMemo as useMemo8, useState as useState10 } from "react";
|
|
5048
5596
|
var toHttpUrl = (hubUrl) => {
|
|
5049
5597
|
try {
|
|
5050
5598
|
const url = new URL(hubUrl);
|
|
@@ -5081,20 +5629,20 @@ function deriveBilling(state) {
|
|
|
5081
5629
|
}
|
|
5082
5630
|
function useBilling() {
|
|
5083
5631
|
const context = useContext2(XNetContext);
|
|
5084
|
-
const [state, setState] =
|
|
5085
|
-
const [loading, setLoading] =
|
|
5632
|
+
const [state, setState] = useState10(null);
|
|
5633
|
+
const [loading, setLoading] = useState10(
|
|
5086
5634
|
Boolean(context?.hubUrl || context?.billing?.apiBase)
|
|
5087
5635
|
);
|
|
5088
|
-
const [error, setError] =
|
|
5089
|
-
const apiBase =
|
|
5636
|
+
const [error, setError] = useState10(null);
|
|
5637
|
+
const apiBase = useMemo8(() => {
|
|
5090
5638
|
if (context?.billing?.apiBase) return context.billing.apiBase.replace(/\/$/, "");
|
|
5091
5639
|
return context?.hubUrl ? toHttpUrl(context.hubUrl) : null;
|
|
5092
5640
|
}, [context?.billing?.apiBase, context?.hubUrl]);
|
|
5093
|
-
const authHeaders =
|
|
5641
|
+
const authHeaders = useCallback7(async () => {
|
|
5094
5642
|
const token = context?.getHubAuthToken ? await context.getHubAuthToken() : "";
|
|
5095
5643
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
5096
5644
|
}, [context]);
|
|
5097
|
-
const reload =
|
|
5645
|
+
const reload = useCallback7(async () => {
|
|
5098
5646
|
if (!apiBase) {
|
|
5099
5647
|
setState(null);
|
|
5100
5648
|
setLoading(false);
|
|
@@ -5112,10 +5660,10 @@ function useBilling() {
|
|
|
5112
5660
|
setLoading(false);
|
|
5113
5661
|
}
|
|
5114
5662
|
}, [apiBase, authHeaders]);
|
|
5115
|
-
|
|
5663
|
+
useEffect11(() => {
|
|
5116
5664
|
void reload();
|
|
5117
5665
|
}, [reload]);
|
|
5118
|
-
const redirectVia =
|
|
5666
|
+
const redirectVia = useCallback7(
|
|
5119
5667
|
async (path, body) => {
|
|
5120
5668
|
if (!apiBase) throw new Error("Hub URL not configured");
|
|
5121
5669
|
const res = await fetch(`${apiBase}${path}`, {
|
|
@@ -5129,11 +5677,11 @@ function useBilling() {
|
|
|
5129
5677
|
},
|
|
5130
5678
|
[apiBase, authHeaders]
|
|
5131
5679
|
);
|
|
5132
|
-
const openCheckout =
|
|
5680
|
+
const openCheckout = useCallback7(
|
|
5133
5681
|
(priceRef, options = {}) => redirectVia("/billing/checkout", buildCheckoutBody(priceRef, options)),
|
|
5134
5682
|
[redirectVia]
|
|
5135
5683
|
);
|
|
5136
|
-
const openPortal =
|
|
5684
|
+
const openPortal = useCallback7(
|
|
5137
5685
|
(returnUrl) => redirectVia("/billing/portal", returnUrl ? { returnUrl } : {}),
|
|
5138
5686
|
[redirectVia]
|
|
5139
5687
|
);
|
|
@@ -5239,6 +5787,7 @@ export {
|
|
|
5239
5787
|
isReactionVisible,
|
|
5240
5788
|
isSavedViewVisualPreviewEmbeddable,
|
|
5241
5789
|
isTaskOverdue,
|
|
5790
|
+
mergeEditorContributions,
|
|
5242
5791
|
mergeSavedViewFeedEnrichment,
|
|
5243
5792
|
moderateThread,
|
|
5244
5793
|
onboardingReducer,
|
|
@@ -5274,6 +5823,7 @@ export {
|
|
|
5274
5823
|
useDatabaseSchema,
|
|
5275
5824
|
useDemoMode,
|
|
5276
5825
|
useDiff,
|
|
5826
|
+
useDraft,
|
|
5277
5827
|
useEditorExtensions,
|
|
5278
5828
|
useEditorExtensionsSafe,
|
|
5279
5829
|
useEffectiveSchema,
|
|
@@ -5290,6 +5840,7 @@ export {
|
|
|
5290
5840
|
useInfiniteQuery,
|
|
5291
5841
|
useInstrumentation,
|
|
5292
5842
|
useIsOffline,
|
|
5843
|
+
useMergedEditorContributions,
|
|
5293
5844
|
useMessageRequests,
|
|
5294
5845
|
useModeratedThread,
|
|
5295
5846
|
useMutate,
|
|
@@ -5317,6 +5868,7 @@ export {
|
|
|
5317
5868
|
useTaskProjectionSync,
|
|
5318
5869
|
useTasks,
|
|
5319
5870
|
useTelemetryReporter,
|
|
5871
|
+
useTimeMachine,
|
|
5320
5872
|
useTracingReporter,
|
|
5321
5873
|
useUndo,
|
|
5322
5874
|
useVerification,
|