@ai-matrx/records 0.58.27 → 0.58.28

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.
@@ -36166,7 +36166,8 @@ import {
36166
36166
  createContext,
36167
36167
  createElement,
36168
36168
  useContext,
36169
- useMemo
36169
+ useMemo,
36170
+ useRef
36170
36171
  } from "react";
36171
36172
 
36172
36173
  // src/archive.ts
@@ -41798,8 +41799,15 @@ function asWriteConflict(error, recordId) {
41798
41799
  // src/react/context.tsx
41799
41800
  var RecordsContext = createContext(null);
41800
41801
  function RecordsProvider({ config, children }) {
41802
+ const latestOnError = useRef(config.onError);
41803
+ latestOnError.current = config.onError;
41804
+ const hasOnError = config.onError !== void 0;
41805
+ const stableOnError = useMemo(
41806
+ () => hasOnError ? (error) => latestOnError.current?.(error) : void 0,
41807
+ [hasOnError]
41808
+ );
41801
41809
  const client = useMemo(
41802
- () => createRecordsClient(config),
41810
+ () => createRecordsClient(stableOnError === void 0 ? config : { ...config, onError: stableOnError }),
41803
41811
  // The identity of the organization and the actor is what makes a client a
41804
41812
  // different client. Rebuilding on those is the point, not a cost.
41805
41813
  [
@@ -41810,7 +41818,7 @@ function RecordsProvider({ config, children }) {
41810
41818
  config.actor.on_behalf_of,
41811
41819
  config.realtime,
41812
41820
  config.resolver,
41813
- config.onError,
41821
+ stableOnError,
41814
41822
  config.schema
41815
41823
  ]
41816
41824
  );
@@ -41833,7 +41841,7 @@ function useRecordsActor() {
41833
41841
  }
41834
41842
 
41835
41843
  // src/react/hooks.ts
41836
- import { useCallback, useEffect, useMemo as useMemo2, useRef, useState, useSyncExternalStore } from "react";
41844
+ import { useCallback, useEffect, useMemo as useMemo2, useRef as useRef2, useState, useSyncExternalStore } from "react";
41837
41845
  var SHARED_ANSWER_MS = 2e3;
41838
41846
  var sharedAnswers = /* @__PURE__ */ new WeakMap();
41839
41847
  function askShared(client, key, fresh, run) {
@@ -41862,7 +41870,7 @@ function useAsync(run, deps, share) {
41862
41870
  { data: null, loading: true, error: null }
41863
41871
  );
41864
41872
  const [nonce, setNonce] = useState(0);
41865
- const alive = useRef(true);
41873
+ const alive = useRef2(true);
41866
41874
  useEffect(() => {
41867
41875
  alive.current = true;
41868
41876
  return () => {
@@ -41971,6 +41979,8 @@ function useLiveRows(tableId, base) {
41971
41979
  const client = useRecordsClient();
41972
41980
  const realtime = client.config.realtime;
41973
41981
  const { reload, setData } = base;
41982
+ const heldRows = useRef2([]);
41983
+ heldRows.current = base.data?.rows ?? [];
41974
41984
  useEffect(() => {
41975
41985
  if (!realtime || !tableId) return;
41976
41986
  return realtime.subscribeRecords(
@@ -41989,7 +41999,7 @@ function useLiveRows(tableId, base) {
41989
41999
  return;
41990
42000
  }
41991
42001
  const fresh = new Map(answered.data.map((row) => [row.id, row]));
41992
- const onThisPage = (id) => (base.data?.rows ?? []).some((row) => row.id === id);
42002
+ const onThisPage = (id) => heldRows.current.some((row) => row.id === id);
41993
42003
  const needsThePage = ids.some((id) => !onThisPage(id) && fresh.has(id));
41994
42004
  if (needsThePage) {
41995
42005
  void reload();
@@ -42012,19 +42022,51 @@ function useLiveRows(tableId, base) {
42012
42022
  }
42013
42023
  }
42014
42024
  );
42015
- }, [realtime, tableId, client, reload, setData, base.data]);
42025
+ }, [realtime, tableId, client, reload, setData]);
42016
42026
  const live = Boolean(realtime && tableId);
42017
42027
  const liveReason = realtime ? tableId ? "Live: changes to this table re-read through the read door." : "Not live: no table selected." : "Not live: this host bound no realtime port, so this list updates when you reload it.";
42018
42028
  return { live, liveReason };
42019
42029
  }
42020
42030
  function useKeptPage(tableId, base) {
42021
- const lastGood = useRef(null);
42031
+ const lastGood = useRef2(null);
42022
42032
  if (base.data !== null && !base.error) lastGood.current = { tableId, data: base.data };
42023
42033
  if (base.error && base.data === null && lastGood.current && lastGood.current.tableId === tableId) {
42024
42034
  return { ...base, data: lastGood.current.data };
42025
42035
  }
42026
42036
  return base;
42027
42037
  }
42038
+ function sameRowAnswer(a, b) {
42039
+ if (a === b) return true;
42040
+ if (a.id !== b.id) return false;
42041
+ try {
42042
+ return JSON.stringify(a) === JSON.stringify(b);
42043
+ } catch {
42044
+ return false;
42045
+ }
42046
+ }
42047
+ function useSharedRows(state) {
42048
+ const held = useRef2({
42049
+ source: null,
42050
+ shared: null,
42051
+ byId: /* @__PURE__ */ new Map()
42052
+ });
42053
+ const data = state.data;
42054
+ if (data === null) return state;
42055
+ const memo = held.current;
42056
+ if (memo.source === data && memo.shared !== null) return { ...state, data: memo.shared };
42057
+ let reused = 0;
42058
+ const rows = data.rows.map((row) => {
42059
+ const before = memo.byId.get(row.id);
42060
+ if (before && sameRowAnswer(before, row)) {
42061
+ reused += 1;
42062
+ return before;
42063
+ }
42064
+ return row;
42065
+ });
42066
+ const shared = reused === 0 ? data : { ...data, rows };
42067
+ held.current = { source: data, shared, byId: new Map(rows.map((row) => [row.id, row])) };
42068
+ return { ...state, data: shared };
42069
+ }
42028
42070
  function useRecords(tableId, options = {}) {
42029
42071
  const pageSize = options.pageSize ?? 50;
42030
42072
  const page = options.page ?? 0;
@@ -42045,7 +42087,7 @@ function useRecords(tableId, options = {}) {
42045
42087
  [tableId, pageSize, page, filterKey]
42046
42088
  );
42047
42089
  const { live, liveReason } = useLiveRows(tableId, base);
42048
- return { ...useKeptPage(tableId, base), live, liveReason };
42090
+ return { ...useSharedRows(useKeptPage(tableId, base)), live, liveReason };
42049
42091
  }
42050
42092
  function useRecordPage(tableId, options = {}) {
42051
42093
  const pageSize = options.pageSize ?? 50;
@@ -42071,7 +42113,7 @@ function useRecordPage(tableId, options = {}) {
42071
42113
  [tableId, pageSize, page, filterKey, search, sortKey, viewId]
42072
42114
  );
42073
42115
  const { live, liveReason } = useLiveRows(tableId, base);
42074
- return { ...useKeptPage(tableId, base), live, liveReason };
42116
+ return { ...useSharedRows(useKeptPage(tableId, base)), live, liveReason };
42075
42117
  }
42076
42118
  function useRecordChangeRevision(recordId) {
42077
42119
  const [revision, setRevision] = useState(0);
@@ -42153,7 +42195,7 @@ function useTableArchive(tableId, options) {
42153
42195
  const [interrupted, setInterrupted] = useState(false);
42154
42196
  const [chunkInUse, setChunkInUse] = useState(chunk);
42155
42197
  const [slowedDown, setSlowedDown] = useState(false);
42156
- const cut = useRef(false);
42198
+ const cut = useRef2(false);
42157
42199
  const preview = useCallback(async () => {
42158
42200
  setError(null);
42159
42201
  const answered = await client.tableArchive({ table_id: tableId, chunk: 0, includeTable });