@xnetjs/react 0.12.0 → 2.0.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/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  useInfiniteQuery,
6
6
  useIsOffline,
7
7
  useNode
8
- } from "./chunk-Q3NDLI6Z.js";
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-WL7OCTSM.js";
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-SEYIZDHG.js";
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-EJEGIEIC.js";
109
+ } from "./chunk-ZGP56IIJ.js";
110
110
  import {
111
111
  useUndoScope
112
- } from "./chunk-BDBDZXYS.js";
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-RIN2MXZK.js";
147
+ } from "./chunk-H44ZSIH4.js";
146
148
 
147
149
  // src/hooks/useEffectiveSchema.ts
148
150
  import {
@@ -4205,6 +4207,92 @@ function formatSavedViewInspectorValue(key, value) {
4205
4207
  return formatSavedViewCellValue(key, value);
4206
4208
  }
4207
4209
 
4210
+ // src/hooks/usePresence.ts
4211
+ import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef3, useState as useState5 } from "react";
4212
+ function readPeers(awareness, ownKeys) {
4213
+ const peers = [];
4214
+ awareness.getStates().forEach((state, clientId) => {
4215
+ if (clientId === awareness.clientID || !state) return;
4216
+ for (const key of ownKeys) {
4217
+ if (key in state) {
4218
+ peers.push({ clientId, state });
4219
+ return;
4220
+ }
4221
+ }
4222
+ });
4223
+ return peers;
4224
+ }
4225
+ function usePresence(awareness, initialState, options = {}) {
4226
+ const { throttleMs = 33 } = options;
4227
+ const [peers, setPeers] = useState5([]);
4228
+ const [clientId, setClientId] = useState5(null);
4229
+ const ownKeysRef = useRef3(new Set(Object.keys(initialState)));
4230
+ const initialStateRef = useRef3(initialState);
4231
+ initialStateRef.current = initialState;
4232
+ const awarenessRef = useRef3(null);
4233
+ const pendingRef = useRef3({});
4234
+ const lastBroadcastRef = useRef3(0);
4235
+ const timerRef = useRef3(null);
4236
+ const flush = useCallback2(() => {
4237
+ const aw = awarenessRef.current;
4238
+ if (!aw) return;
4239
+ lastBroadcastRef.current = Date.now();
4240
+ const patch = pendingRef.current;
4241
+ pendingRef.current = {};
4242
+ aw.setLocalState({ ...aw.getLocalState() ?? {}, ...patch });
4243
+ }, []);
4244
+ const setState = useCallback2(
4245
+ (patch) => {
4246
+ for (const key of Object.keys(patch)) ownKeysRef.current.add(key);
4247
+ pendingRef.current = { ...pendingRef.current, ...patch };
4248
+ const elapsed = Date.now() - lastBroadcastRef.current;
4249
+ if (elapsed >= throttleMs) {
4250
+ flush();
4251
+ } else if (timerRef.current === null) {
4252
+ timerRef.current = setTimeout(() => {
4253
+ timerRef.current = null;
4254
+ flush();
4255
+ }, throttleMs - elapsed);
4256
+ }
4257
+ },
4258
+ [flush, throttleMs]
4259
+ );
4260
+ useEffect5(() => {
4261
+ if (!awareness) {
4262
+ awarenessRef.current = null;
4263
+ setClientId(null);
4264
+ setPeers([]);
4265
+ return;
4266
+ }
4267
+ awarenessRef.current = awareness;
4268
+ setClientId(awareness.clientID);
4269
+ const ownKeys = ownKeysRef.current;
4270
+ awareness.setLocalState({
4271
+ ...awareness.getLocalState() ?? {},
4272
+ ...initialStateRef.current
4273
+ });
4274
+ lastBroadcastRef.current = Date.now();
4275
+ const handleChange = () => {
4276
+ setPeers(readPeers(awareness, ownKeysRef.current));
4277
+ };
4278
+ handleChange();
4279
+ awareness.on("change", handleChange);
4280
+ return () => {
4281
+ awareness.off("change", handleChange);
4282
+ if (timerRef.current !== null) {
4283
+ clearTimeout(timerRef.current);
4284
+ timerRef.current = null;
4285
+ }
4286
+ pendingRef.current = {};
4287
+ const remaining = { ...awareness.getLocalState() ?? {} };
4288
+ for (const key of ownKeys) delete remaining[key];
4289
+ awareness.setLocalState(remaining);
4290
+ if (awarenessRef.current === awareness) awarenessRef.current = null;
4291
+ };
4292
+ }, [awareness]);
4293
+ return { peers, setState, clientId };
4294
+ }
4295
+
4208
4296
  // src/hooks/useCanvasTaskSync.ts
4209
4297
  function useCanvasTaskSync({
4210
4298
  canvasId,
@@ -4237,7 +4325,7 @@ import {
4237
4325
  convertCellValue,
4238
4326
  FormulaService
4239
4327
  } from "@xnetjs/data";
4240
- import { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef3, useState as useState5 } from "react";
4328
+ import { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef4, useState as useState6 } from "react";
4241
4329
  function toFieldModel(node) {
4242
4330
  return {
4243
4331
  id: node.id,
@@ -4358,8 +4446,8 @@ function useGridDatabase(databaseId, options = {}) {
4358
4446
  return effective.map((e) => e.field);
4359
4447
  }, [fields, activeView]);
4360
4448
  const { store } = useNodeStore();
4361
- const [rollupValues, setRollupValues] = useState5(/* @__PURE__ */ new Map());
4362
- useEffect5(() => {
4449
+ const [rollupValues, setRollupValues] = useState6(/* @__PURE__ */ new Map());
4450
+ useEffect6(() => {
4363
4451
  const rollupFields = fields.filter((f) => f.type === "rollup");
4364
4452
  if (rollupFields.length === 0 || !store) {
4365
4453
  setRollupValues((prev) => prev.size > 0 ? /* @__PURE__ */ new Map() : prev);
@@ -4459,11 +4547,11 @@ function useGridDatabase(databaseId, options = {}) {
4459
4547
  return sortRows(filtered, columns, activeView.sorts);
4460
4548
  }, [rowNodes, activeView, fields, databaseId, rollupValues]);
4461
4549
  const loading = dbStatus === "loading" || fieldStatus === "loading" || viewStatus === "loading" || rowStatus === "loading";
4462
- const rowTailRef = useRef3(void 0);
4463
- const fieldTailRef = useRef3(void 0);
4464
- const viewTailRef = useRef3(void 0);
4465
- const optionTailRef = useRef3(/* @__PURE__ */ new Map());
4466
- useEffect5(() => {
4550
+ const rowTailRef = useRef4(void 0);
4551
+ const fieldTailRef = useRef4(void 0);
4552
+ const viewTailRef = useRef4(void 0);
4553
+ const optionTailRef = useRef4(/* @__PURE__ */ new Map());
4554
+ useEffect6(() => {
4467
4555
  const dataTail = rows.reduce(
4468
4556
  (max, r) => !max || compareSortKeys(r.sortKey, max) > 0 ? r.sortKey : max,
4469
4557
  void 0
@@ -4472,19 +4560,19 @@ function useGridDatabase(databaseId, options = {}) {
4472
4560
  rowTailRef.current = dataTail;
4473
4561
  }
4474
4562
  }, [rows]);
4475
- useEffect5(() => {
4563
+ useEffect6(() => {
4476
4564
  const dataTail = fields[fields.length - 1]?.sortKey;
4477
4565
  if (dataTail && (!fieldTailRef.current || compareSortKeys(dataTail, fieldTailRef.current) > 0)) {
4478
4566
  fieldTailRef.current = dataTail;
4479
4567
  }
4480
4568
  }, [fields]);
4481
- useEffect5(() => {
4569
+ useEffect6(() => {
4482
4570
  const dataTail = views[views.length - 1]?.sortKey;
4483
4571
  if (dataTail && (!viewTailRef.current || compareSortKeys(dataTail, viewTailRef.current) > 0)) {
4484
4572
  viewTailRef.current = dataTail;
4485
4573
  }
4486
4574
  }, [views]);
4487
- useEffect5(() => {
4575
+ useEffect6(() => {
4488
4576
  for (const [fieldId, list] of optionsByField) {
4489
4577
  const dataTail = list[list.length - 1]?.sortKey;
4490
4578
  const current = optionTailRef.current.get(fieldId);
@@ -4493,7 +4581,7 @@ function useGridDatabase(databaseId, options = {}) {
4493
4581
  }
4494
4582
  }
4495
4583
  }, [optionsByField]);
4496
- const nextAppendKey = useCallback2((tailRef) => {
4584
+ const nextAppendKey = useCallback3((tailRef) => {
4497
4585
  const key = generateSortKey(tailRef.current, void 0);
4498
4586
  tailRef.current = key;
4499
4587
  return key;
@@ -4511,19 +4599,19 @@ function useGridDatabase(databaseId, options = {}) {
4511
4599
  localDID: did ?? null,
4512
4600
  options: { localOnly: true }
4513
4601
  });
4514
- const updateRowProps = useCallback2(
4602
+ const updateRowProps = useCallback3(
4515
4603
  async (rowId, properties) => {
4516
4604
  await mutate.update(DatabaseRowSchema, rowId, properties);
4517
4605
  },
4518
4606
  [mutate]
4519
4607
  );
4520
- const updateCell = useCallback2(
4608
+ const updateCell = useCallback3(
4521
4609
  async (rowId, fieldId, value) => {
4522
4610
  await updateRowProps(rowId, { [cellKey(fieldId)]: value });
4523
4611
  },
4524
4612
  [updateRowProps]
4525
4613
  );
4526
- const clearCells = useCallback2(
4614
+ const clearCells = useCallback3(
4527
4615
  async (cells) => {
4528
4616
  const byRow = /* @__PURE__ */ new Map();
4529
4617
  for (const { rowId, fieldId } of cells) {
@@ -4535,7 +4623,7 @@ function useGridDatabase(databaseId, options = {}) {
4535
4623
  },
4536
4624
  [updateRowProps]
4537
4625
  );
4538
- const addRow = useCallback2(
4626
+ const addRow = useCallback3(
4539
4627
  async (afterRowId, cells, opts) => {
4540
4628
  let sortKey;
4541
4629
  if (afterRowId) {
@@ -4570,13 +4658,13 @@ function useGridDatabase(databaseId, options = {}) {
4570
4658
  },
4571
4659
  [mutate, databaseId, rows, nextAppendKey]
4572
4660
  );
4573
- const deleteRows = useCallback2(
4661
+ const deleteRows = useCallback3(
4574
4662
  async (rowIds) => {
4575
4663
  await Promise.all(rowIds.map((id) => mutate.remove(id)));
4576
4664
  },
4577
4665
  [mutate]
4578
4666
  );
4579
- const moveRowToIndex = useCallback2(
4667
+ const moveRowToIndex = useCallback3(
4580
4668
  async (rowId, targetIndex) => {
4581
4669
  if (activeView && activeView.sorts.length > 0) return;
4582
4670
  const ordered = rows.map((r) => ({ id: r.id, key: r.sortKey }));
@@ -4585,7 +4673,7 @@ function useGridDatabase(databaseId, options = {}) {
4585
4673
  },
4586
4674
  [rows, activeView, updateRowProps]
4587
4675
  );
4588
- const createOption = useCallback2(
4676
+ const createOption = useCallback3(
4589
4677
  async (fieldId, name) => {
4590
4678
  const existing = optionsByField.get(fieldId) ?? [];
4591
4679
  const match = existing.find((o) => o.name.toLowerCase() === name.toLowerCase());
@@ -4604,7 +4692,7 @@ function useGridDatabase(databaseId, options = {}) {
4604
4692
  },
4605
4693
  [mutate, databaseId, optionsByField]
4606
4694
  );
4607
- const addField = useCallback2(
4695
+ const addField = useCallback3(
4608
4696
  async (name, type, config, opts) => {
4609
4697
  const node = await mutate.create(DatabaseFieldSchema, {
4610
4698
  database: databaseId,
@@ -4619,13 +4707,13 @@ function useGridDatabase(databaseId, options = {}) {
4619
4707
  },
4620
4708
  [mutate, databaseId, nextAppendKey]
4621
4709
  );
4622
- const renameField = useCallback2(
4710
+ const renameField = useCallback3(
4623
4711
  async (fieldId, name) => {
4624
4712
  await mutate.update(DatabaseFieldSchema, fieldId, { name });
4625
4713
  },
4626
4714
  [mutate]
4627
4715
  );
4628
- const updateFieldConfig = useCallback2(
4716
+ const updateFieldConfig = useCallback3(
4629
4717
  async (fieldId, config) => {
4630
4718
  await mutate.update(DatabaseFieldSchema, fieldId, {
4631
4719
  config
@@ -4633,7 +4721,7 @@ function useGridDatabase(databaseId, options = {}) {
4633
4721
  },
4634
4722
  [mutate]
4635
4723
  );
4636
- const changeFieldType = useCallback2(
4724
+ const changeFieldType = useCallback3(
4637
4725
  async (fieldId, type) => {
4638
4726
  const field = fields.find((f) => f.id === fieldId);
4639
4727
  const sourceType = field?.type ?? "text";
@@ -4670,7 +4758,7 @@ function useGridDatabase(databaseId, options = {}) {
4670
4758
  },
4671
4759
  [mutate, fields, rows, createOption, updateRowProps]
4672
4760
  );
4673
- const removeField = useCallback2(
4761
+ const removeField = useCallback3(
4674
4762
  async (fieldId) => {
4675
4763
  const orphanedOptions = optionsByField.get(fieldId) ?? [];
4676
4764
  await Promise.all(orphanedOptions.map((o) => mutate.remove(o.id)));
@@ -4678,7 +4766,7 @@ function useGridDatabase(databaseId, options = {}) {
4678
4766
  },
4679
4767
  [mutate, optionsByField]
4680
4768
  );
4681
- const moveFieldToIndex = useCallback2(
4769
+ const moveFieldToIndex = useCallback3(
4682
4770
  async (fieldId, targetIndex) => {
4683
4771
  if (!activeView) return;
4684
4772
  const ordered = visibleFields.map((f) => ({
@@ -4692,7 +4780,7 @@ function useGridDatabase(databaseId, options = {}) {
4692
4780
  },
4693
4781
  [mutate, activeView, visibleFields, fields]
4694
4782
  );
4695
- const resizeField = useCallback2(
4783
+ const resizeField = useCallback3(
4696
4784
  async (fieldId, width) => {
4697
4785
  if (!activeView) return;
4698
4786
  await mutate.update(DatabaseViewSchema, activeView.id, {
@@ -4701,7 +4789,7 @@ function useGridDatabase(databaseId, options = {}) {
4701
4789
  },
4702
4790
  [mutate, activeView]
4703
4791
  );
4704
- const setFieldHiddenInView = useCallback2(
4792
+ const setFieldHiddenInView = useCallback3(
4705
4793
  async (fieldId, hidden) => {
4706
4794
  if (!activeView) return;
4707
4795
  const set = new Set(activeView.hiddenFields);
@@ -4711,7 +4799,7 @@ function useGridDatabase(databaseId, options = {}) {
4711
4799
  },
4712
4800
  [mutate, activeView]
4713
4801
  );
4714
- const toggleSort = useCallback2(
4802
+ const toggleSort = useCallback3(
4715
4803
  async (fieldId) => {
4716
4804
  if (!activeView) return;
4717
4805
  const current = activeView.sorts.find((s) => s.columnId === fieldId);
@@ -4727,28 +4815,28 @@ function useGridDatabase(databaseId, options = {}) {
4727
4815
  },
4728
4816
  [mutate, activeView]
4729
4817
  );
4730
- const setFilters = useCallback2(
4818
+ const setFilters = useCallback3(
4731
4819
  async (filters) => {
4732
4820
  if (!activeView) return;
4733
4821
  await mutate.update(DatabaseViewSchema, activeView.id, { filters });
4734
4822
  },
4735
4823
  [mutate, activeView]
4736
4824
  );
4737
- const setGroupBy = useCallback2(
4825
+ const setGroupBy = useCallback3(
4738
4826
  async (fieldId) => {
4739
4827
  if (!activeView) return;
4740
4828
  await mutate.update(DatabaseViewSchema, activeView.id, { groupBy: fieldId ?? void 0 });
4741
4829
  },
4742
4830
  [mutate, activeView]
4743
4831
  );
4744
- const setRowHeight = useCallback2(
4832
+ const setRowHeight = useCallback3(
4745
4833
  async (rowHeight) => {
4746
4834
  if (!activeView) return;
4747
4835
  await mutate.update(DatabaseViewSchema, activeView.id, { rowHeight });
4748
4836
  },
4749
4837
  [mutate, activeView]
4750
4838
  );
4751
- const setColumnSummary = useCallback2(
4839
+ const setColumnSummary = useCallback3(
4752
4840
  async (fieldId, fn) => {
4753
4841
  if (!activeView) return;
4754
4842
  const next = { ...activeView.columnSummaries };
@@ -4758,28 +4846,28 @@ function useGridDatabase(databaseId, options = {}) {
4758
4846
  },
4759
4847
  [mutate, activeView]
4760
4848
  );
4761
- const setFormConfig = useCallback2(
4849
+ const setFormConfig = useCallback3(
4762
4850
  async (config) => {
4763
4851
  if (!activeView) return;
4764
4852
  await mutate.update(DatabaseViewSchema, activeView.id, { formConfig: config });
4765
4853
  },
4766
4854
  [mutate, activeView]
4767
4855
  );
4768
- const setFormRules = useCallback2(
4856
+ const setFormRules = useCallback3(
4769
4857
  async (rules) => {
4770
4858
  if (!activeView) return;
4771
4859
  await mutate.update(DatabaseViewSchema, activeView.id, { formRules: rules });
4772
4860
  },
4773
4861
  [mutate, activeView]
4774
4862
  );
4775
- const setFormAccepting = useCallback2(
4863
+ const setFormAccepting = useCallback3(
4776
4864
  async (accepting) => {
4777
4865
  if (!activeView) return;
4778
4866
  await mutate.update(DatabaseViewSchema, activeView.id, { formAccepting: accepting });
4779
4867
  },
4780
4868
  [mutate, activeView]
4781
4869
  );
4782
- const addView = useCallback2(
4870
+ const addView = useCallback3(
4783
4871
  async (name, type) => {
4784
4872
  const node = await mutate.create(DatabaseViewSchema, {
4785
4873
  database: databaseId,
@@ -4791,13 +4879,13 @@ function useGridDatabase(databaseId, options = {}) {
4791
4879
  },
4792
4880
  [mutate, databaseId, nextAppendKey]
4793
4881
  );
4794
- const renameView = useCallback2(
4882
+ const renameView = useCallback3(
4795
4883
  async (id, name) => {
4796
4884
  await mutate.update(DatabaseViewSchema, id, { name });
4797
4885
  },
4798
4886
  [mutate]
4799
4887
  );
4800
- const removeView = useCallback2(
4888
+ const removeView = useCallback3(
4801
4889
  async (id) => {
4802
4890
  await mutate.remove(id);
4803
4891
  },
@@ -4843,8 +4931,531 @@ function useGridDatabase(databaseId, options = {}) {
4843
4931
  };
4844
4932
  }
4845
4933
 
4934
+ // src/hooks/useTimeMachine.ts
4935
+ import { CHECKPOINT_SCHEMA_IRI } from "@xnetjs/data";
4936
+ import {
4937
+ HistoryEngine,
4938
+ HistoryHorizonError,
4939
+ MemorySnapshotStorage,
4940
+ ScopeTimeline,
4941
+ SnapshotCache,
4942
+ createCheckpoint,
4943
+ listCheckpoints,
4944
+ restoreToFrontier
4945
+ } from "@xnetjs/history";
4946
+ import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef5, useState as useState7 } from "react";
4947
+ function useTimeMachine(nodeId, options) {
4948
+ const { store, isReady } = useNodeStore();
4949
+ const memberKey = options?.memberIds?.join(",") ?? "";
4950
+ const members = useMemo6(() => {
4951
+ if (!nodeId) return [];
4952
+ const extra = options?.memberIds ?? [];
4953
+ return [nodeId, ...extra.filter((id) => id !== nodeId)];
4954
+ }, [nodeId, memberKey]);
4955
+ const [timeline, setTimeline] = useState7([]);
4956
+ const [checkpoints, setCheckpoints] = useState7([]);
4957
+ const [horizon, setHorizon] = useState7(null);
4958
+ const [docSnapshotCount, setDocSnapshotCount] = useState7(null);
4959
+ const [loading, setLoading] = useState7(false);
4960
+ const [error, setError] = useState7(null);
4961
+ const [rawPosition, setRawPosition] = useState7(null);
4962
+ const position = rawPosition === null ? Math.max(0, timeline.length - 1) : Math.max(0, Math.min(rawPosition, timeline.length - 1));
4963
+ const atLatest = timeline.length === 0 || position === timeline.length - 1;
4964
+ const [preview, setPreview] = useState7(null);
4965
+ const [diffs, setDiffs] = useState7([]);
4966
+ const engineRef = useRef5(null);
4967
+ const getEngines = useCallback4(() => {
4968
+ if (!store) return null;
4969
+ const storage = store.getStorageAdapter();
4970
+ if (!storage) return null;
4971
+ if (!engineRef.current || engineRef.current.storage !== storage) {
4972
+ const snapshots = new SnapshotCache(new MemorySnapshotStorage(), { interval: 50 });
4973
+ engineRef.current = {
4974
+ engine: new HistoryEngine(storage, snapshots),
4975
+ scope: new ScopeTimeline(storage),
4976
+ storage
4977
+ };
4978
+ }
4979
+ return engineRef.current;
4980
+ }, [store]);
4981
+ const reload = useCallback4(async () => {
4982
+ if (!nodeId || !isReady || !store) return;
4983
+ const engines = getEngines();
4984
+ if (!engines) return;
4985
+ setLoading(true);
4986
+ setError(null);
4987
+ try {
4988
+ const [line, nodeHorizon, named] = await Promise.all([
4989
+ engines.scope.getMergedTimeline(members),
4990
+ engines.engine.getHorizon(nodeId),
4991
+ listCheckpoints(store, nodeId)
4992
+ ]);
4993
+ setTimeline(line);
4994
+ setHorizon(nodeHorizon);
4995
+ setCheckpoints(named);
4996
+ const snapshotStorage = engines.storage;
4997
+ if (typeof snapshotStorage.getYjsSnapshots === "function") {
4998
+ const snapshots = await snapshotStorage.getYjsSnapshots(nodeId);
4999
+ setDocSnapshotCount(snapshots.length);
5000
+ } else {
5001
+ setDocSnapshotCount(null);
5002
+ }
5003
+ } catch (err) {
5004
+ setError(err instanceof Error ? err : new Error(String(err)));
5005
+ } finally {
5006
+ setLoading(false);
5007
+ }
5008
+ }, [nodeId, isReady, store, members, getEngines]);
5009
+ useEffect7(() => {
5010
+ setRawPosition(null);
5011
+ void reload();
5012
+ }, [reload]);
5013
+ useEffect7(() => {
5014
+ if (!store || !nodeId) return;
5015
+ const memberSet = new Set(members);
5016
+ const unsub = store.subscribe((event) => {
5017
+ if (memberSet.has(event.change.payload.nodeId) || event.change.payload.schemaId === CHECKPOINT_SCHEMA_IRI) {
5018
+ void reload();
5019
+ }
5020
+ });
5021
+ return unsub;
5022
+ }, [store, nodeId, members, reload]);
5023
+ useEffect7(() => {
5024
+ let cancelled = false;
5025
+ const engines = getEngines();
5026
+ if (!nodeId || !engines || timeline.length === 0) {
5027
+ setPreview(null);
5028
+ setDiffs([]);
5029
+ return;
5030
+ }
5031
+ let hash = null;
5032
+ for (let i = position; i >= 0; i--) {
5033
+ if (timeline[i].nodeId === nodeId) {
5034
+ hash = timeline[i].change.hash;
5035
+ break;
5036
+ }
5037
+ }
5038
+ if (!hash) {
5039
+ setPreview(null);
5040
+ setDiffs([]);
5041
+ return;
5042
+ }
5043
+ const target = { type: "hash", hash };
5044
+ Promise.all([
5045
+ engines.engine.materializeAt(nodeId, target),
5046
+ engines.engine.diff(nodeId, target, { type: "latest" })
5047
+ ]).then(([state, propertyDiffs]) => {
5048
+ if (cancelled) return;
5049
+ setPreview(state.node);
5050
+ setDiffs(propertyDiffs);
5051
+ }).catch((err) => {
5052
+ if (cancelled) return;
5053
+ setPreview(null);
5054
+ setDiffs([]);
5055
+ if (err instanceof HistoryHorizonError) {
5056
+ setHorizon(err.horizon);
5057
+ } else {
5058
+ setError(err instanceof Error ? err : new Error(String(err)));
5059
+ }
5060
+ });
5061
+ return () => {
5062
+ cancelled = true;
5063
+ };
5064
+ }, [nodeId, timeline, position, getEngines]);
5065
+ const setPosition = useCallback4(
5066
+ (index) => {
5067
+ const max = timeline.length - 1;
5068
+ const clamped = Math.max(0, Math.min(index, max));
5069
+ setRawPosition(clamped >= max ? null : clamped);
5070
+ },
5071
+ [timeline.length]
5072
+ );
5073
+ const stepBack = useCallback4(() => setPosition(position - 1), [setPosition, position]);
5074
+ const stepForward = useCallback4(() => setPosition(position + 1), [setPosition, position]);
5075
+ const goToLatest = useCallback4(() => setRawPosition(null), []);
5076
+ const createNamedVersion = useCallback4(
5077
+ async (name, note) => {
5078
+ if (!nodeId || !store) return null;
5079
+ const engines = getEngines();
5080
+ if (!engines) return null;
5081
+ try {
5082
+ const checkpoint = await createCheckpoint(store, engines.storage, {
5083
+ name,
5084
+ ...note !== void 0 ? { note } : {},
5085
+ nodeIds: members,
5086
+ scopeId: nodeId
5087
+ });
5088
+ await reload();
5089
+ return checkpoint;
5090
+ } catch (err) {
5091
+ setError(err instanceof Error ? err : new Error(String(err)));
5092
+ return null;
5093
+ }
5094
+ },
5095
+ [nodeId, store, members, getEngines, reload]
5096
+ );
5097
+ const positionOfCheckpoint = useCallback4(
5098
+ (checkpoint) => {
5099
+ const frontier = checkpoint.properties.frontier;
5100
+ if (!frontier) return null;
5101
+ let best = -1;
5102
+ for (let i = 0; i < timeline.length; i++) {
5103
+ const pinned = frontier[timeline[i].nodeId];
5104
+ if (pinned && pinned.hash === timeline[i].change.hash) {
5105
+ best = Math.max(best, i);
5106
+ }
5107
+ }
5108
+ return best >= 0 ? best : null;
5109
+ },
5110
+ [timeline]
5111
+ );
5112
+ const frontierAt = useCallback4(
5113
+ (index) => {
5114
+ const scope = getEngines()?.scope;
5115
+ if (!scope) return {};
5116
+ return scope.frontierAtPosition(timeline, index);
5117
+ },
5118
+ [getEngines, timeline]
5119
+ );
5120
+ const restore = useCallback4(async () => {
5121
+ if (!nodeId || !store || timeline.length === 0) return null;
5122
+ const engines = getEngines();
5123
+ if (!engines) return null;
5124
+ try {
5125
+ const frontier = engines.scope.frontierAtPosition(timeline, position);
5126
+ const result = await restoreToFrontier(store, engines.engine, frontier, members);
5127
+ setRawPosition(null);
5128
+ await reload();
5129
+ return result;
5130
+ } catch (err) {
5131
+ if (err instanceof HistoryHorizonError) setHorizon(err.horizon);
5132
+ setError(err instanceof Error ? err : new Error(String(err)));
5133
+ return null;
5134
+ }
5135
+ }, [nodeId, store, timeline, position, members, getEngines, reload]);
5136
+ return {
5137
+ timeline,
5138
+ changeCount: timeline.length,
5139
+ position,
5140
+ atLatest,
5141
+ setPosition,
5142
+ stepBack,
5143
+ stepForward,
5144
+ goToLatest,
5145
+ preview,
5146
+ diffs,
5147
+ horizon,
5148
+ docSnapshotCount,
5149
+ checkpoints,
5150
+ createNamedVersion,
5151
+ positionOfCheckpoint,
5152
+ frontierAt,
5153
+ restore,
5154
+ loading,
5155
+ error,
5156
+ reload
5157
+ };
5158
+ }
5159
+
5160
+ // src/hooks/useDraft.ts
5161
+ import { DRAFT_SCHEMA_IRI, DatabaseRowSchema as DatabaseRowSchema2, DatabaseSchema as DatabaseSchema2 } from "@xnetjs/data";
5162
+ import {
5163
+ HistoryEngine as HistoryEngine2,
5164
+ MemorySnapshotStorage as MemorySnapshotStorage2,
5165
+ SnapshotCache as SnapshotCache2,
5166
+ createDraft as createDraftNode,
5167
+ discardDraft,
5168
+ draftEntries,
5169
+ forkNodeIntoDraft,
5170
+ listDrafts,
5171
+ mergeDraft,
5172
+ refreshDraftFromMain,
5173
+ threeWayPropertyMerge
5174
+ } from "@xnetjs/history";
5175
+ import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
5176
+ var baseIRI = (schemaId) => schemaId.split("@")[0];
5177
+ async function resolveMembers(store, hostId) {
5178
+ const members = [hostId];
5179
+ const host = await store.getRaw(hostId);
5180
+ if (host && baseIRI(host.schemaId) === baseIRI(DatabaseSchema2.schema["@id"])) {
5181
+ const rows = await store.list({ schemaId: DatabaseRowSchema2.schema["@id"] });
5182
+ for (const row of rows) {
5183
+ if (row.properties.database === hostId) members.push(row.id);
5184
+ }
5185
+ }
5186
+ return members;
5187
+ }
5188
+ function clonesFromEntries(draft) {
5189
+ const clones = {};
5190
+ for (const [originalId, entry] of Object.entries(draftEntries(draft))) {
5191
+ clones[originalId] = entry.cloneId;
5192
+ }
5193
+ return clones;
5194
+ }
5195
+ function useDraft(hostId) {
5196
+ const { store, isReady } = useNodeStore();
5197
+ const [drafts, setDrafts] = useState8([]);
5198
+ const [checkedOut, setCheckedOut] = useState8(null);
5199
+ const [loading, setLoading] = useState8(false);
5200
+ const [error, setError] = useState8(null);
5201
+ const engineRef = useRef6(null);
5202
+ const getEngines = useCallback5(() => {
5203
+ if (!store) return null;
5204
+ const storage = store.getStorageAdapter();
5205
+ if (!storage) return null;
5206
+ if (!engineRef.current || engineRef.current.storage !== storage) {
5207
+ engineRef.current = {
5208
+ engine: new HistoryEngine2(
5209
+ storage,
5210
+ new SnapshotCache2(new MemorySnapshotStorage2(), { interval: 50 })
5211
+ ),
5212
+ storage
5213
+ };
5214
+ }
5215
+ return engineRef.current;
5216
+ }, [store]);
5217
+ const draftIdsRef = useRef6(/* @__PURE__ */ new Set());
5218
+ const reload = useCallback5(async () => {
5219
+ if (!hostId || !isReady || !store) return;
5220
+ setLoading(true);
5221
+ setError(null);
5222
+ try {
5223
+ const open = await listDrafts(store, hostId);
5224
+ setDrafts(open);
5225
+ for (const draft of open) draftIdsRef.current.add(draft.id);
5226
+ const overlay = store.getCheckedOutDraft();
5227
+ if (overlay) {
5228
+ const draftNode = await store.getRaw(overlay.draftId);
5229
+ setCheckedOut(
5230
+ draftNode && draftNode.properties.status === "open" && draftNode.properties.target === hostId ? draftNode : null
5231
+ );
5232
+ } else {
5233
+ setCheckedOut(null);
5234
+ }
5235
+ } catch (err) {
5236
+ setError(err instanceof Error ? err : new Error(String(err)));
5237
+ } finally {
5238
+ setLoading(false);
5239
+ }
5240
+ }, [hostId, isReady, store]);
5241
+ useEffect8(() => {
5242
+ void reload();
5243
+ }, [reload]);
5244
+ useEffect8(() => {
5245
+ if (!store || !hostId) return;
5246
+ const unsubStore = store.subscribe((event) => {
5247
+ if (event.change.payload.schemaId === DRAFT_SCHEMA_IRI || draftIdsRef.current.has(event.change.payload.nodeId)) {
5248
+ void reload();
5249
+ }
5250
+ });
5251
+ const unsubOverlay = store.subscribeToDraftOverlay(() => void reload());
5252
+ return () => {
5253
+ unsubStore();
5254
+ unsubOverlay();
5255
+ };
5256
+ }, [store, hostId, reload]);
5257
+ const checkout = useCallback5(
5258
+ async (draftId) => {
5259
+ if (!hostId || !store) return false;
5260
+ const engines = getEngines();
5261
+ if (!engines) return false;
5262
+ try {
5263
+ const draft = await store.getRaw(draftId);
5264
+ if (!draft || draft.properties.status !== "open") return false;
5265
+ const members = await resolveMembers(store, hostId);
5266
+ store.setCheckedOutDraft({
5267
+ draftId,
5268
+ members,
5269
+ clones: clonesFromEntries(draft),
5270
+ // Lazy copy-on-write: the first write to an unforked member clones
5271
+ // it. Returning null declines — the write then targets the
5272
+ // original (never-fork schemas stay live by policy).
5273
+ onMissingMember: async (originalId) => {
5274
+ try {
5275
+ const entry = await forkNodeIntoDraft(store, engines.storage, draftId, originalId);
5276
+ return entry.cloneId;
5277
+ } catch {
5278
+ return null;
5279
+ }
5280
+ }
5281
+ });
5282
+ await reload();
5283
+ return true;
5284
+ } catch (err) {
5285
+ setError(err instanceof Error ? err : new Error(String(err)));
5286
+ return false;
5287
+ }
5288
+ },
5289
+ [hostId, store, getEngines, reload]
5290
+ );
5291
+ const returnToMain = useCallback5(() => {
5292
+ if (!store) return;
5293
+ store.setCheckedOutDraft(null);
5294
+ }, [store]);
5295
+ const createDraft = useCallback5(
5296
+ async (name) => {
5297
+ if (!hostId || !store) return null;
5298
+ try {
5299
+ const draft = await createDraftNode(store, { name, targetId: hostId });
5300
+ await checkout(draft.id);
5301
+ return draft;
5302
+ } catch (err) {
5303
+ setError(err instanceof Error ? err : new Error(String(err)));
5304
+ return null;
5305
+ }
5306
+ },
5307
+ [hostId, store, checkout]
5308
+ );
5309
+ const discard = useCallback5(
5310
+ async (draftId) => {
5311
+ if (!store) return false;
5312
+ const engines = getEngines();
5313
+ if (!engines) return false;
5314
+ try {
5315
+ if (store.getCheckedOutDraft()?.draftId === draftId) {
5316
+ store.setCheckedOutDraft(null);
5317
+ }
5318
+ await discardDraft(store, engines.storage, draftId);
5319
+ await reload();
5320
+ return true;
5321
+ } catch (err) {
5322
+ setError(err instanceof Error ? err : new Error(String(err)));
5323
+ return false;
5324
+ }
5325
+ },
5326
+ [store, getEngines, reload]
5327
+ );
5328
+ const merge = useCallback5(
5329
+ async (draftId) => {
5330
+ if (!store) return null;
5331
+ const engines = getEngines();
5332
+ if (!engines) return null;
5333
+ try {
5334
+ const result = await mergeDraft(store, engines.storage, engines.engine, draftId);
5335
+ if (result.status === "merged" && store.getCheckedOutDraft()?.draftId === draftId) {
5336
+ store.setCheckedOutDraft(null);
5337
+ }
5338
+ await reload();
5339
+ return result;
5340
+ } catch (err) {
5341
+ setError(err instanceof Error ? err : new Error(String(err)));
5342
+ return null;
5343
+ }
5344
+ },
5345
+ [store, getEngines, reload]
5346
+ );
5347
+ const refresh = useCallback5(
5348
+ async (draftId) => {
5349
+ if (!store) return null;
5350
+ const engines = getEngines();
5351
+ if (!engines) return null;
5352
+ try {
5353
+ const result = await refreshDraftFromMain(store, engines.storage, engines.engine, draftId);
5354
+ await reload();
5355
+ return result;
5356
+ } catch (err) {
5357
+ setError(err instanceof Error ? err : new Error(String(err)));
5358
+ return null;
5359
+ }
5360
+ },
5361
+ [store, getEngines, reload]
5362
+ );
5363
+ const setReviewRequested = useCallback5(
5364
+ async (draftId, requested) => {
5365
+ if (!store) return;
5366
+ try {
5367
+ await store.update(draftId, { properties: { reviewRequested: requested } });
5368
+ } catch (err) {
5369
+ setError(err instanceof Error ? err : new Error(String(err)));
5370
+ }
5371
+ },
5372
+ [store]
5373
+ );
5374
+ const computeReview = useCallback5(
5375
+ async (draftId) => {
5376
+ if (!store) return null;
5377
+ const engines = getEngines();
5378
+ if (!engines) return null;
5379
+ try {
5380
+ const draft = await store.getRaw(draftId);
5381
+ if (!draft) return null;
5382
+ const cards = [];
5383
+ const members = [];
5384
+ for (const [id, entry] of Object.entries(draftEntries(draft))) {
5385
+ const originalId = id;
5386
+ const cloneId = entry.cloneId;
5387
+ const [base, ours, theirs] = await Promise.all([
5388
+ engines.engine.materializeAt(originalId, {
5389
+ type: "hash",
5390
+ hash: entry.forkedAtHash
5391
+ }),
5392
+ store.getRaw(originalId),
5393
+ store.getRaw(cloneId)
5394
+ ]);
5395
+ if (!ours || !theirs) continue;
5396
+ const result = threeWayPropertyMerge(
5397
+ base.node.properties,
5398
+ ours.properties,
5399
+ theirs.properties
5400
+ );
5401
+ for (const [property, draftValue] of Object.entries(result.patch)) {
5402
+ cards.push({
5403
+ originalId,
5404
+ property,
5405
+ base: base.node.properties[property],
5406
+ main: ours.properties[property],
5407
+ draft: draftValue,
5408
+ conflict: false
5409
+ });
5410
+ }
5411
+ for (const conflict of result.conflicts) {
5412
+ cards.push({
5413
+ originalId,
5414
+ property: conflict.property,
5415
+ base: conflict.base,
5416
+ main: conflict.ours,
5417
+ draft: conflict.theirs,
5418
+ conflict: true
5419
+ });
5420
+ }
5421
+ const hasDocument = Boolean(entry.forkedAtYjsStateVector);
5422
+ let documentDiffers = false;
5423
+ if (hasDocument) {
5424
+ const [cloneBlob, mainBlob] = await Promise.all([
5425
+ engines.storage.getDocumentContent(cloneId),
5426
+ engines.storage.getDocumentContent(originalId)
5427
+ ]);
5428
+ documentDiffers = (cloneBlob?.length ?? 0) !== (mainBlob?.length ?? 0);
5429
+ }
5430
+ members.push({ originalId, cloneId, hasDocument, documentDiffers });
5431
+ }
5432
+ return { cards, members };
5433
+ } catch (err) {
5434
+ setError(err instanceof Error ? err : new Error(String(err)));
5435
+ return null;
5436
+ }
5437
+ },
5438
+ [store, getEngines]
5439
+ );
5440
+ return {
5441
+ drafts,
5442
+ checkedOut,
5443
+ createDraft,
5444
+ checkout,
5445
+ returnToMain,
5446
+ discard,
5447
+ merge,
5448
+ refresh,
5449
+ setReviewRequested,
5450
+ computeReview,
5451
+ loading,
5452
+ error,
5453
+ reload
5454
+ };
5455
+ }
5456
+
4846
5457
  // src/hooks/useGlobalUndo.ts
4847
- import { useCallback as useCallback3, useContext, useEffect as useEffect6, useReducer } from "react";
5458
+ import { useCallback as useCallback6, useContext, useEffect as useEffect9, useReducer } from "react";
4848
5459
  function readUndoContext(ctx) {
4849
5460
  if (!ctx) return { undoManager: null, nodeStore: null };
4850
5461
  return { undoManager: ctx.undoManager, nodeStore: ctx.nodeStore };
@@ -4853,17 +5464,17 @@ function useGlobalUndo() {
4853
5464
  const ctx = useContext(XNetContext);
4854
5465
  const { undoManager, nodeStore } = readUndoContext(ctx);
4855
5466
  const [, bump] = useReducer((n) => n + 1, 0);
4856
- useEffect6(() => {
5467
+ useEffect9(() => {
4857
5468
  if (!nodeStore) return;
4858
5469
  return nodeStore.subscribe(() => bump());
4859
5470
  }, [nodeStore]);
4860
- const undo = useCallback3(async () => {
5471
+ const undo = useCallback6(async () => {
4861
5472
  if (!undoManager) return false;
4862
5473
  const ok = await undoManager.undoLatest();
4863
5474
  bump();
4864
5475
  return ok;
4865
5476
  }, [undoManager]);
4866
- const redo = useCallback3(async () => {
5477
+ const redo = useCallback6(async () => {
4867
5478
  if (!undoManager) return false;
4868
5479
  const ok = await undoManager.redoLatest();
4869
5480
  bump();
@@ -4877,6 +5488,57 @@ function useGlobalUndo() {
4877
5488
  };
4878
5489
  }
4879
5490
 
5491
+ // src/hooks/useCanCreate.ts
5492
+ import { useEffect as useEffect10, useMemo as useMemo7, useRef as useRef7, useState as useState9 } from "react";
5493
+ var INITIAL_STATE = {
5494
+ canCreate: false,
5495
+ loading: true,
5496
+ error: null
5497
+ };
5498
+ function useCanCreate(schemaId, properties) {
5499
+ const { store, isReady } = useNodeStore();
5500
+ const [state, setState] = useState9(INITIAL_STATE);
5501
+ const requestRef = useRef7(0);
5502
+ const propertiesKey = useMemo7(() => JSON.stringify(properties ?? {}), [properties]);
5503
+ useEffect10(() => {
5504
+ if (!store || !isReady) {
5505
+ setState((prev) => ({ ...prev, loading: true }));
5506
+ return;
5507
+ }
5508
+ if (!store.auth) {
5509
+ setState({
5510
+ ...INITIAL_STATE,
5511
+ loading: false,
5512
+ error: new Error("Authorization API is not configured on this NodeStore")
5513
+ });
5514
+ return;
5515
+ }
5516
+ const run = async () => {
5517
+ const requestId = ++requestRef.current;
5518
+ setState((prev) => ({ ...prev, loading: true, error: null }));
5519
+ try {
5520
+ const decision = await store.auth.can({
5521
+ action: "create",
5522
+ // A synthetic id: the draft node must not collide with a stored one.
5523
+ nodeId: `draft:${schemaId}`,
5524
+ node: {
5525
+ schemaId,
5526
+ properties: JSON.parse(propertiesKey)
5527
+ }
5528
+ });
5529
+ if (requestRef.current !== requestId) return;
5530
+ setState({ canCreate: decision.allowed, loading: false, error: null });
5531
+ } catch (error) {
5532
+ if (requestRef.current !== requestId) return;
5533
+ const normalized = error instanceof Error ? error : new Error(String(error));
5534
+ setState((prev) => ({ ...prev, loading: false, error: normalized }));
5535
+ }
5536
+ };
5537
+ void run();
5538
+ }, [isReady, propertiesKey, schemaId, store]);
5539
+ return state;
5540
+ }
5541
+
4880
5542
  // src/index.ts
4881
5543
  import { WebSocketSyncProvider } from "@xnetjs/runtime";
4882
5544
  import {
@@ -4907,7 +5569,7 @@ import {
4907
5569
  } from "@xnetjs/runtime";
4908
5570
 
4909
5571
  // src/hooks/useBilling.ts
4910
- import { useCallback as useCallback4, useContext as useContext2, useEffect as useEffect7, useMemo as useMemo6, useState as useState6 } from "react";
5572
+ import { useCallback as useCallback7, useContext as useContext2, useEffect as useEffect11, useMemo as useMemo8, useState as useState10 } from "react";
4911
5573
  var toHttpUrl = (hubUrl) => {
4912
5574
  try {
4913
5575
  const url = new URL(hubUrl);
@@ -4944,20 +5606,20 @@ function deriveBilling(state) {
4944
5606
  }
4945
5607
  function useBilling() {
4946
5608
  const context = useContext2(XNetContext);
4947
- const [state, setState] = useState6(null);
4948
- const [loading, setLoading] = useState6(
5609
+ const [state, setState] = useState10(null);
5610
+ const [loading, setLoading] = useState10(
4949
5611
  Boolean(context?.hubUrl || context?.billing?.apiBase)
4950
5612
  );
4951
- const [error, setError] = useState6(null);
4952
- const apiBase = useMemo6(() => {
5613
+ const [error, setError] = useState10(null);
5614
+ const apiBase = useMemo8(() => {
4953
5615
  if (context?.billing?.apiBase) return context.billing.apiBase.replace(/\/$/, "");
4954
5616
  return context?.hubUrl ? toHttpUrl(context.hubUrl) : null;
4955
5617
  }, [context?.billing?.apiBase, context?.hubUrl]);
4956
- const authHeaders = useCallback4(async () => {
5618
+ const authHeaders = useCallback7(async () => {
4957
5619
  const token = context?.getHubAuthToken ? await context.getHubAuthToken() : "";
4958
5620
  return token ? { Authorization: `Bearer ${token}` } : {};
4959
5621
  }, [context]);
4960
- const reload = useCallback4(async () => {
5622
+ const reload = useCallback7(async () => {
4961
5623
  if (!apiBase) {
4962
5624
  setState(null);
4963
5625
  setLoading(false);
@@ -4975,10 +5637,10 @@ function useBilling() {
4975
5637
  setLoading(false);
4976
5638
  }
4977
5639
  }, [apiBase, authHeaders]);
4978
- useEffect7(() => {
5640
+ useEffect11(() => {
4979
5641
  void reload();
4980
5642
  }, [reload]);
4981
- const redirectVia = useCallback4(
5643
+ const redirectVia = useCallback7(
4982
5644
  async (path, body) => {
4983
5645
  if (!apiBase) throw new Error("Hub URL not configured");
4984
5646
  const res = await fetch(`${apiBase}${path}`, {
@@ -4992,11 +5654,11 @@ function useBilling() {
4992
5654
  },
4993
5655
  [apiBase, authHeaders]
4994
5656
  );
4995
- const openCheckout = useCallback4(
5657
+ const openCheckout = useCallback7(
4996
5658
  (priceRef, options = {}) => redirectVia("/billing/checkout", buildCheckoutBody(priceRef, options)),
4997
5659
  [redirectVia]
4998
5660
  );
4999
- const openPortal = useCallback4(
5661
+ const openPortal = useCallback7(
5000
5662
  (returnUrl) => redirectVia("/billing/portal", returnUrl ? { returnUrl } : {}),
5001
5663
  [redirectVia]
5002
5664
  );
@@ -5102,6 +5764,7 @@ export {
5102
5764
  isReactionVisible,
5103
5765
  isSavedViewVisualPreviewEmbeddable,
5104
5766
  isTaskOverdue,
5767
+ mergeEditorContributions,
5105
5768
  mergeSavedViewFeedEnrichment,
5106
5769
  moderateThread,
5107
5770
  onboardingReducer,
@@ -5120,6 +5783,7 @@ export {
5120
5783
  useBilling,
5121
5784
  useBlame,
5122
5785
  useCan,
5786
+ useCanCreate,
5123
5787
  useCanEdit,
5124
5788
  useCanvasTaskSync,
5125
5789
  useCell,
@@ -5136,6 +5800,7 @@ export {
5136
5800
  useDatabaseSchema,
5137
5801
  useDemoMode,
5138
5802
  useDiff,
5803
+ useDraft,
5139
5804
  useEditorExtensions,
5140
5805
  useEditorExtensionsSafe,
5141
5806
  useEffectiveSchema,
@@ -5152,6 +5817,7 @@ export {
5152
5817
  useInfiniteQuery,
5153
5818
  useInstrumentation,
5154
5819
  useIsOffline,
5820
+ useMergedEditorContributions,
5155
5821
  useMessageRequests,
5156
5822
  useModeratedThread,
5157
5823
  useMutate,
@@ -5164,6 +5830,7 @@ export {
5164
5830
  usePluginRegistryOptional,
5165
5831
  usePlugins,
5166
5832
  usePolicyFilteredReactionCounters,
5833
+ usePresence,
5167
5834
  useQuery,
5168
5835
  useRelatedRows,
5169
5836
  useRemoteSchema,
@@ -5178,6 +5845,7 @@ export {
5178
5845
  useTaskProjectionSync,
5179
5846
  useTasks,
5180
5847
  useTelemetryReporter,
5848
+ useTimeMachine,
5181
5849
  useTracingReporter,
5182
5850
  useUndo,
5183
5851
  useVerification,