@ai-matrx/records 0.80.7 → 0.81.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.
@@ -86,6 +86,8 @@ __export(react_exports, {
86
86
  RULE_USES: () => RULE_USES,
87
87
  RecordsHoldScope: () => RecordsHoldScope,
88
88
  RecordsProvider: () => RecordsProvider,
89
+ RecordsSeedProvider: () => RecordsSeedProvider,
90
+ SEED_FRESH_MS: () => SEED_FRESH_MS,
89
91
  SHOWN_TO_LABEL: () => SHOWN_TO_LABEL,
90
92
  SHOWN_TO_VALUES: () => SHOWN_TO_VALUES,
91
93
  SHOWN_TO_WHO_MAY_CHANGE: () => SHOWN_TO_WHO_MAY_CHANGE,
@@ -277,6 +279,7 @@ __export(react_exports, {
277
279
  useReverseColumns: () => useReverseColumns,
278
280
  useReverseLinks: () => useReverseLinks,
279
281
  useRowActions: () => useRowActions,
282
+ useSeededAnswer: () => useSeededAnswer,
280
283
  useStoreTable: () => useStoreTable,
281
284
  useTable: () => useTable,
282
285
  useTableArchive: () => useTableArchive,
@@ -300,6 +303,10 @@ function registry() {
300
303
  return g[REGISTRY] ??= /* @__PURE__ */ new Map();
301
304
  }
302
305
  var primedKey = (organizationId, tableId, viewId) => `${organizationId}|${tableId}|${viewId ?? ""}`;
306
+ function primeTablePageBundle(input) {
307
+ const answer = Promise.resolve(input.answer).catch((thrown) => ({ data: null, error: thrown }));
308
+ registry().set(primedKey(input.organizationId, input.tableId, input.viewId), { answer, at: Date.now() });
309
+ }
303
310
  function takePrimedTablePageBundle(organizationId, tableId, viewId) {
304
311
  if (!organizationId) return null;
305
312
  const key = primedKey(organizationId, tableId, viewId);
@@ -309,6 +316,9 @@ function takePrimedTablePageBundle(organizationId, tableId, viewId) {
309
316
  primed.delete(key);
310
317
  return Date.now() - held.at < PRIMED_TTL_MS ? held.answer : null;
311
318
  }
319
+ function primeRecordPageBundle(input) {
320
+ primeTablePageBundle({ organizationId: input.organizationId, tableId: `record:${input.recordId}`, answer: input.answer });
321
+ }
312
322
 
313
323
  // src/core/recordChanges.ts
314
324
  var listeners = /* @__PURE__ */ new Set();
@@ -426,8 +436,8 @@ function liftWithheld(rows) {
426
436
  }
427
437
 
428
438
  // src/subscription.ts
429
- function hasQuietHours(quiet) {
430
- return Boolean(quiet?.start && quiet?.end);
439
+ function hasQuietHours(quiet2) {
440
+ return Boolean(quiet2?.start && quiet2?.end);
431
441
  }
432
442
  function callersTimeZone() {
433
443
  try {
@@ -7851,7 +7861,7 @@ function useRecordsActor() {
7851
7861
  }
7852
7862
 
7853
7863
  // src/react/hooks.ts
7854
- var import_react3 = require("react");
7864
+ var import_react4 = require("react");
7855
7865
 
7856
7866
  // src/react/dataCache.ts
7857
7867
  var RECORDS_CACHE_GRACE_MS = 3e4;
@@ -8004,6 +8014,12 @@ function releaseEntry(handle) {
8004
8014
  entry.refs = Math.max(0, entry.refs - 1);
8005
8015
  if (entry.refs === 0) scheduleClose(entry);
8006
8016
  }
8017
+ function seedEntry(handle, data, stale) {
8018
+ const entry = handle;
8019
+ if (entry.started || entry.snapshot.data !== null) return;
8020
+ entry.snapshot = { data, loading: false, error: null };
8021
+ entry.started = !stale;
8022
+ }
8007
8023
  function openHold(holdKey) {
8008
8024
  const holds = root().holds;
8009
8025
  let hold = holds.get(holdKey);
@@ -8034,65 +8050,190 @@ function recordsCacheCounters() {
8034
8050
  return { ...root().counters };
8035
8051
  }
8036
8052
 
8037
- // src/react/hold.tsx
8053
+ // src/react/seed.tsx
8038
8054
  var import_react2 = require("react");
8039
- var HoldContext = (0, import_react2.createContext)(null);
8055
+
8056
+ // src/core/seed.ts
8057
+ var BUNDLE_DOORS = /* @__PURE__ */ new Set(["table_page_bundle", "record_page_bundle"]);
8058
+ function seedKey(door, args) {
8059
+ return `${door}|${canonicalArgs(args)}`;
8060
+ }
8061
+ function answersOf(door, args, data) {
8062
+ const out = [{ door, args, data }];
8063
+ if (!BUNDLE_DOORS.has(door) || !data || typeof data !== "object") return out;
8064
+ const parts = data.parts;
8065
+ if (!Array.isArray(parts)) return out;
8066
+ for (const part of parts) {
8067
+ if (part.error !== void 0 || part.data === void 0) continue;
8068
+ if (typeof part.door !== "string" || !part.args || typeof part.args !== "object") continue;
8069
+ out.push({ door: part.door, args: part.args, data: part.data });
8070
+ }
8071
+ return out;
8072
+ }
8073
+ function seedIndex(seed) {
8074
+ const index = /* @__PURE__ */ new Map();
8075
+ for (const a of seed.answers) {
8076
+ for (const spread of answersOf(a.door, a.args, a.data)) index.set(seedKey(spread.door, spread.args), spread.data);
8077
+ }
8078
+ return index;
8079
+ }
8080
+ var MISS = { code: "SEED_MISS", message: "Not in the page's seed.", details: null, hint: null };
8081
+ function missingQuery(onMiss) {
8082
+ const answer = () => {
8083
+ onMiss();
8084
+ return Promise.resolve({ data: null, error: MISS, count: null });
8085
+ };
8086
+ const chain = new Proxy(function() {
8087
+ }, {
8088
+ get(_target, prop) {
8089
+ if (prop === "then") return (ok2, bad) => answer().then(ok2, bad);
8090
+ return () => chain;
8091
+ },
8092
+ apply: () => chain
8093
+ });
8094
+ return { select: () => chain };
8095
+ }
8096
+ function seededDataSource(index) {
8097
+ let missed = false;
8098
+ const source = {
8099
+ rpc(fn, args) {
8100
+ const key = seedKey(fn, args);
8101
+ if (index.has(key)) return Promise.resolve({ data: index.get(key), error: null });
8102
+ missed = true;
8103
+ return Promise.resolve({ data: null, error: MISS });
8104
+ },
8105
+ schema: () => ({ from: () => missingQuery(() => missed = true) })
8106
+ };
8107
+ return { source, missed: () => missed };
8108
+ }
8109
+
8110
+ // src/react/seed.tsx
8111
+ var SEED_FRESH_MS = 3e4;
8112
+ var stores = /* @__PURE__ */ new WeakMap();
8113
+ var quiet = () => {
8114
+ };
8115
+ function storeFor(seed) {
8116
+ const held = stores.get(seed);
8117
+ if (held) return held;
8118
+ const index = seedIndex(seed);
8119
+ const runs = /* @__PURE__ */ new Map();
8120
+ const store = {
8121
+ live: true,
8122
+ run(slot, run, config) {
8123
+ const asked = runs.get(slot);
8124
+ if (asked) return asked;
8125
+ const { source, missed } = seededDataSource(index);
8126
+ const { realtime: _live, ...quietConfig } = config;
8127
+ const client = createRecordsClient({ ...quietConfig, dataSource: source, onError: quiet });
8128
+ const stale = typeof seed.at !== "number" || Date.now() - seed.at > SEED_FRESH_MS;
8129
+ const outcome = Promise.resolve().then(() => run(client)).then(
8130
+ (answer) => answer.ok && !missed() ? { seeded: true, data: answer.data, stale } : { seeded: false },
8131
+ () => ({ seeded: false })
8132
+ );
8133
+ runs.set(slot, outcome);
8134
+ return outcome;
8135
+ }
8136
+ };
8137
+ stores.set(seed, store);
8138
+ if (typeof window !== "undefined") {
8139
+ for (const a of seed.answers) {
8140
+ const org = a.args["p_organization_id"];
8141
+ if (typeof org !== "string") continue;
8142
+ if (a.door === "table_page_bundle" && typeof a.args["p_table_id"] === "string") {
8143
+ const view = a.args["p_view_id"];
8144
+ primeTablePageBundle({ organizationId: org, tableId: a.args["p_table_id"], viewId: typeof view === "string" ? view : null, answer: { data: a.data, error: null } });
8145
+ } else if (a.door === "record_page_bundle" && typeof a.args["p_record_id"] === "string") {
8146
+ primeRecordPageBundle({ organizationId: org, recordId: a.args["p_record_id"], answer: { data: a.data, error: null } });
8147
+ }
8148
+ }
8149
+ }
8150
+ return store;
8151
+ }
8152
+ var SeedContext = (0, import_react2.createContext)(null);
8153
+ function RecordsSeedProvider({ seed, children }) {
8154
+ const store = seed && Array.isArray(seed.answers) ? storeFor(seed) : null;
8155
+ (0, import_react2.useEffect)(() => {
8156
+ if (store) store.live = false;
8157
+ }, [store]);
8158
+ return (0, import_react2.createElement)(SeedContext.Provider, { value: store }, children);
8159
+ }
8160
+ function useSeedStore() {
8161
+ const store = (0, import_react2.useContext)(SeedContext);
8162
+ return store && store.live ? store : null;
8163
+ }
8164
+
8165
+ // src/react/hold.tsx
8166
+ var import_react3 = require("react");
8167
+ var HoldContext = (0, import_react3.createContext)(null);
8040
8168
  function RecordsHoldScope({ holdKey, children }) {
8041
- return (0, import_react2.createElement)(HoldContext.Provider, { value: holdKey }, children);
8169
+ return (0, import_react3.createElement)(HoldContext.Provider, { value: holdKey }, children);
8042
8170
  }
8043
8171
  function useRecordsHold(holdKey) {
8044
- (0, import_react2.useEffect)(() => holdKey ? openHold(holdKey) : void 0, [holdKey]);
8172
+ (0, import_react3.useEffect)(() => holdKey ? openHold(holdKey) : void 0, [holdKey]);
8045
8173
  }
8046
8174
  function useHoldKey() {
8047
- return (0, import_react2.useContext)(HoldContext);
8175
+ return (0, import_react3.useContext)(HoldContext);
8048
8176
  }
8049
8177
 
8050
8178
  // src/react/hooks.ts
8051
8179
  function useAsync(run, key, live) {
8052
8180
  const client = useRecordsClient();
8053
8181
  const holdKey = useHoldKey();
8054
- const slot = (0, import_react3.useId)();
8055
- const entry = (0, import_react3.useMemo)(
8182
+ const slot = (0, import_react4.useId)();
8183
+ const entry = (0, import_react4.useMemo)(
8056
8184
  () => typeof window === "undefined" ? serverEntry(run, client) : entryFor(client, key, run, live ?? null),
8057
8185
  // eslint-disable-next-line react-hooks/exhaustive-deps
8058
8186
  [client, key]
8059
8187
  );
8060
8188
  entry.run = run;
8061
8189
  entry.client = client;
8062
- const snapshot = (0, import_react3.useSyncExternalStore)(entry.subscribe, entry.getSnapshot, entry.getSnapshot);
8063
- (0, import_react3.useEffect)(() => {
8190
+ const seed = useSeedStore();
8191
+ if (seed && entry.snapshot.data === null && !entry.snapshot.error && !entry.started) {
8192
+ const outcome = (0, import_react4.use)(seed.run(`${identityOf(client)}|${key}`, run, client.config));
8193
+ if (outcome.seeded) seedEntry(entry, outcome.data, outcome.stale);
8194
+ }
8195
+ const snapshot = (0, import_react4.useSyncExternalStore)(entry.subscribe, entry.getSnapshot, entry.getSnapshot);
8196
+ (0, import_react4.useEffect)(() => {
8064
8197
  acquireEntry(entry);
8065
8198
  return () => releaseEntry(entry);
8066
8199
  }, [entry]);
8067
- (0, import_react3.useEffect)(() => {
8200
+ (0, import_react4.useEffect)(() => {
8068
8201
  if (holdKey) pinToHold(holdKey, slot, entry);
8069
8202
  }, [holdKey, slot, entry]);
8070
- const lastData = (0, import_react3.useRef)(null);
8203
+ const lastData = (0, import_react4.useRef)(null);
8071
8204
  if (snapshot.data !== null) lastData.current = snapshot.data;
8072
8205
  const shown = snapshot.data === null && snapshot.loading && !snapshot.error && lastData.current !== null ? { ...snapshot, data: lastData.current } : snapshot;
8073
- const reload = (0, import_react3.useCallback)(() => entry.refetch(), [entry]);
8074
- const setData = (0, import_react3.useCallback)((update) => entry.setData(update), [entry]);
8206
+ const reload = (0, import_react4.useCallback)(() => entry.refetch(), [entry]);
8207
+ const setData = (0, import_react4.useCallback)((update) => entry.setData(update), [entry]);
8075
8208
  return { ...shown, reload, setData };
8076
8209
  }
8210
+ function useSeededAnswer(key, run) {
8211
+ const client = useRecordsClient();
8212
+ const seed = useSeedStore();
8213
+ if (!seed || key === null) return void 0;
8214
+ const outcome = (0, import_react4.use)(seed.run(`${identityOf(client)}|own:${key}`, run, client.config));
8215
+ return outcome.seeded ? outcome.data : void 0;
8216
+ }
8077
8217
  function serverEntry(run, client) {
8078
- const snapshot = { data: null, loading: true, error: null };
8079
- return {
8218
+ const entry = {
8080
8219
  key: "server",
8081
- snapshot,
8220
+ snapshot: { data: null, loading: true, error: null },
8082
8221
  run,
8083
8222
  client,
8084
8223
  subscribe: () => () => {
8085
8224
  },
8086
- getSnapshot: () => snapshot,
8225
+ // Read through the entry: a page seed may answer it during this render (`seedEntry`).
8226
+ getSnapshot: () => entry.snapshot,
8087
8227
  refetch: () => {
8088
8228
  },
8089
8229
  setData: () => {
8090
8230
  }
8091
8231
  };
8232
+ return entry;
8092
8233
  }
8093
8234
  function useTable(tableId) {
8094
8235
  const revision = useShapeRevision(tableId);
8095
- (0, import_react3.useEffect)(() => {
8236
+ (0, import_react4.useEffect)(() => {
8096
8237
  if (tableId) registerShapeInterest(tableId);
8097
8238
  }, [tableId]);
8098
8239
  return useAsync(
@@ -8149,12 +8290,12 @@ function subscribeToShape(listener) {
8149
8290
  };
8150
8291
  }
8151
8292
  function useShapeRevision(tableId) {
8152
- const read = (0, import_react3.useCallback)(() => tableId ? shapeRevisions.get(tableId) ?? 0 : 0, [tableId]);
8153
- return (0, import_react3.useSyncExternalStore)(subscribeToShape, read, () => 0);
8293
+ const read = (0, import_react4.useCallback)(() => tableId ? shapeRevisions.get(tableId) ?? 0 : 0, [tableId]);
8294
+ return (0, import_react4.useSyncExternalStore)(subscribeToShape, read, () => 0);
8154
8295
  }
8155
8296
  function useFields(tableId, recordType) {
8156
8297
  const revision = useShapeRevision(tableId);
8157
- (0, import_react3.useEffect)(() => {
8298
+ (0, import_react4.useEffect)(() => {
8158
8299
  if (tableId) registerShapeInterest(tableId);
8159
8300
  }, [tableId]);
8160
8301
  return useAsync(
@@ -8179,7 +8320,7 @@ async function answerOrRefusal(ask, where) {
8179
8320
  }
8180
8321
  }
8181
8322
  function useReverseColumns(tableId) {
8182
- const revision = (0, import_react3.useSyncExternalStore)(subscribeToShape, () => anyShapeRevision, () => 0);
8323
+ const revision = (0, import_react4.useSyncExternalStore)(subscribeToShape, () => anyShapeRevision, () => 0);
8183
8324
  return useAsync(
8184
8325
  async (client) => {
8185
8326
  if (!tableId || !doorReady(client.config, DOORS.reverseColumns)) return { ok: true, data: [] };
@@ -8189,8 +8330,8 @@ function useReverseColumns(tableId) {
8189
8330
  );
8190
8331
  }
8191
8332
  function useReverseLinks(tableId, columns, recordIds, limit = 3, offset = 0) {
8192
- const [writes, setWrites] = (0, import_react3.useState)(0);
8193
- (0, import_react3.useEffect)(() => onRecordChanged(() => setWrites((n) => n + 1)), []);
8333
+ const [writes, setWrites] = (0, import_react4.useState)(0);
8334
+ (0, import_react4.useEffect)(() => onRecordChanged(() => setWrites((n) => n + 1)), []);
8194
8335
  const idsKey = recordIds.join(",");
8195
8336
  const columnsKey = columns.map((c) => c.source_field_id).join(",");
8196
8337
  return useAsync(
@@ -8285,7 +8426,7 @@ function liveStatus(client, tableId) {
8285
8426
  return { live, liveReason };
8286
8427
  }
8287
8428
  function useKeptPage(tableId, base) {
8288
- const lastGood = (0, import_react3.useRef)(null);
8429
+ const lastGood = (0, import_react4.useRef)(null);
8289
8430
  if (base.data !== null && !base.error) lastGood.current = { tableId, data: base.data };
8290
8431
  if (base.error && base.data === null && lastGood.current && lastGood.current.tableId === tableId) {
8291
8432
  return { ...base, data: lastGood.current.data };
@@ -8302,7 +8443,7 @@ function sameRowAnswer(a, b) {
8302
8443
  }
8303
8444
  }
8304
8445
  function useSharedRows(state) {
8305
- const held = (0, import_react3.useRef)({
8446
+ const held = (0, import_react4.useRef)({
8306
8447
  source: null,
8307
8448
  shared: null,
8308
8449
  byId: /* @__PURE__ */ new Map()
@@ -8377,8 +8518,8 @@ function useRecordPage(tableId, options = {}) {
8377
8518
  return { ...useSharedRows(useKeptPage(tableId, base)), live, liveReason };
8378
8519
  }
8379
8520
  function useRecordChangeRevision(recordId) {
8380
- const [revision, setRevision] = (0, import_react3.useState)(0);
8381
- (0, import_react3.useEffect)(() => {
8521
+ const [revision, setRevision] = (0, import_react4.useState)(0);
8522
+ (0, import_react4.useEffect)(() => {
8382
8523
  if (!recordId) return;
8383
8524
  return onRecordChanged((changed) => {
8384
8525
  if (changed === recordId) setRevision((n) => n + 1);
@@ -8429,10 +8570,10 @@ function liveRecordFor(recordId, tableId) {
8429
8570
  }
8430
8571
  function useRecordMutation() {
8431
8572
  const client = useRecordsClient();
8432
- const [saving, setSaving] = (0, import_react3.useState)(false);
8433
- const [error, setError] = (0, import_react3.useState)(null);
8434
- const [conflict, setConflict] = (0, import_react3.useState)(null);
8435
- const run = (0, import_react3.useCallback)(
8573
+ const [saving, setSaving] = (0, import_react4.useState)(false);
8574
+ const [error, setError] = (0, import_react4.useState)(null);
8575
+ const [conflict, setConflict] = (0, import_react4.useState)(null);
8576
+ const run = (0, import_react4.useCallback)(
8436
8577
  async (recordId, call) => {
8437
8578
  setSaving(true);
8438
8579
  setError(null);
@@ -8451,7 +8592,7 @@ function useRecordMutation() {
8451
8592
  },
8452
8593
  []
8453
8594
  );
8454
- return (0, import_react3.useMemo)(
8595
+ return (0, import_react4.useMemo)(
8455
8596
  () => ({
8456
8597
  write: (args) => run(null, () => client.recordWrite({ table_id: args.table_id, data: args.data })),
8457
8598
  update: (args) => run(
@@ -8480,15 +8621,15 @@ function useTableArchive(tableId, options) {
8480
8621
  const client = useRecordsClient();
8481
8622
  const chunk = options?.chunk ?? TABLE_ARCHIVE_PASS;
8482
8623
  const includeTable = options?.includeTable ?? true;
8483
- const [progress, setProgress] = (0, import_react3.useState)(null);
8484
- const [running, setRunning] = (0, import_react3.useState)(false);
8485
- const [passes, setPasses] = (0, import_react3.useState)(0);
8486
- const [error, setError] = (0, import_react3.useState)(null);
8487
- const [interrupted, setInterrupted] = (0, import_react3.useState)(false);
8488
- const [chunkInUse, setChunkInUse] = (0, import_react3.useState)(chunk);
8489
- const [slowedDown, setSlowedDown] = (0, import_react3.useState)(false);
8490
- const cut = (0, import_react3.useRef)(false);
8491
- const preview = (0, import_react3.useCallback)(async () => {
8624
+ const [progress, setProgress] = (0, import_react4.useState)(null);
8625
+ const [running, setRunning] = (0, import_react4.useState)(false);
8626
+ const [passes, setPasses] = (0, import_react4.useState)(0);
8627
+ const [error, setError] = (0, import_react4.useState)(null);
8628
+ const [interrupted, setInterrupted] = (0, import_react4.useState)(false);
8629
+ const [chunkInUse, setChunkInUse] = (0, import_react4.useState)(chunk);
8630
+ const [slowedDown, setSlowedDown] = (0, import_react4.useState)(false);
8631
+ const cut = (0, import_react4.useRef)(false);
8632
+ const preview = (0, import_react4.useCallback)(async () => {
8492
8633
  setError(null);
8493
8634
  const answered = await client.tableArchive({ table_id: tableId, chunk: 0, includeTable });
8494
8635
  if (!answered.ok) {
@@ -8499,7 +8640,7 @@ function useTableArchive(tableId, options) {
8499
8640
  if (answered.data.in_progress) setInterrupted(true);
8500
8641
  return answered.data;
8501
8642
  }, [client, tableId, includeTable]);
8502
- const loop = (0, import_react3.useCallback)(async () => {
8643
+ const loop = (0, import_react4.useCallback)(async () => {
8503
8644
  cut.current = false;
8504
8645
  setRunning(true);
8505
8646
  setError(null);
@@ -8536,7 +8677,7 @@ function useTableArchive(tableId, options) {
8536
8677
  setRunning(false);
8537
8678
  }
8538
8679
  }, [client, tableId, chunk, includeTable]);
8539
- return (0, import_react3.useMemo)(
8680
+ return (0, import_react4.useMemo)(
8540
8681
  () => ({
8541
8682
  progress,
8542
8683
  running,
@@ -8581,11 +8722,11 @@ function useEntityBackLinks(token, recordId, options) {
8581
8722
  }) : Promise.resolve({ ok: true, data: null }),
8582
8723
  `entity-back-links:${scope}`
8583
8724
  );
8584
- const [more, setMore] = (0, import_react3.useState)({ scope, items: [], cursor: void 0, busy: false, error: null });
8725
+ const [more, setMore] = (0, import_react4.useState)({ scope, items: [], cursor: void 0, busy: false, error: null });
8585
8726
  const current = more.scope === scope ? more : { scope, items: [], cursor: void 0, busy: false, error: null };
8586
8727
  const firstAnswer = first.data;
8587
8728
  const cursor = current.cursor === void 0 ? firstAnswer?.next_cursor ?? null : current.cursor;
8588
- const loadMore = (0, import_react3.useCallback)(async () => {
8729
+ const loadMore = (0, import_react4.useCallback)(async () => {
8589
8730
  if (!asking || !cursor) return;
8590
8731
  setMore({ ...current, busy: true, error: null });
8591
8732
  const answered = await client.entityBackLinks({
@@ -8607,7 +8748,7 @@ function useEntityBackLinks(token, recordId, options) {
8607
8748
  error: null
8608
8749
  });
8609
8750
  }, [client, asking?.token, asking?.recordId, asking?.organizationId, limit, cursor, current, scope]);
8610
- const reload = (0, import_react3.useCallback)(() => {
8751
+ const reload = (0, import_react4.useCallback)(() => {
8611
8752
  setMore({ scope, items: [], cursor: void 0, busy: false, error: null });
8612
8753
  first.reload();
8613
8754
  }, [first, scope]);
@@ -8643,9 +8784,9 @@ function useEntityFieldRights(token) {
8643
8784
  }
8644
8785
  function useEntityFieldMutation() {
8645
8786
  const client = useRecordsClient();
8646
- const [saving, setSaving] = (0, import_react3.useState)(false);
8647
- const [error, setError] = (0, import_react3.useState)(null);
8648
- const run = (0, import_react3.useCallback)(
8787
+ const [saving, setSaving] = (0, import_react4.useState)(false);
8788
+ const [error, setError] = (0, import_react4.useState)(null);
8789
+ const run = (0, import_react4.useCallback)(
8649
8790
  async (call, whenRefused) => {
8650
8791
  setSaving(true);
8651
8792
  setError(null);
@@ -8660,7 +8801,7 @@ function useEntityFieldMutation() {
8660
8801
  },
8661
8802
  []
8662
8803
  );
8663
- return (0, import_react3.useMemo)(
8804
+ return (0, import_react4.useMemo)(
8664
8805
  () => ({
8665
8806
  declare: (args) => run(() => client.entityFieldDeclare({ token: args.token, spec: args.spec }), null),
8666
8807
  update: (args) => run(
@@ -8686,9 +8827,9 @@ function useEntityFieldMutation() {
8686
8827
  }
8687
8828
  function useFieldMutation() {
8688
8829
  const client = useRecordsClient();
8689
- const [saving, setSaving] = (0, import_react3.useState)(false);
8690
- const [error, setError] = (0, import_react3.useState)(null);
8691
- const run = (0, import_react3.useCallback)(
8830
+ const [saving, setSaving] = (0, import_react4.useState)(false);
8831
+ const [error, setError] = (0, import_react4.useState)(null);
8832
+ const run = (0, import_react4.useCallback)(
8692
8833
  async (call, whenRefused) => {
8693
8834
  setSaving(true);
8694
8835
  setError(null);
@@ -8703,14 +8844,14 @@ function useFieldMutation() {
8703
8844
  },
8704
8845
  []
8705
8846
  );
8706
- const announce = (0, import_react3.useCallback)((tableId) => {
8847
+ const announce = (0, import_react4.useCallback)((tableId) => {
8707
8848
  if (tableId) {
8708
8849
  tableShapeChanged(tableId);
8709
8850
  return;
8710
8851
  }
8711
8852
  for (const id of [...shapeRevisions.keys()]) tableShapeChanged(id);
8712
8853
  }, []);
8713
- return (0, import_react3.useMemo)(
8854
+ return (0, import_react4.useMemo)(
8714
8855
  () => ({
8715
8856
  declare: async (args) => {
8716
8857
  const made = await run(
@@ -8747,9 +8888,9 @@ function useFieldMutation() {
8747
8888
  }
8748
8889
  function useMergeField(key, state) {
8749
8890
  const client = useRecordsClient();
8750
- const [resolution, setResolution] = (0, import_react3.useState)(null);
8891
+ const [resolution, setResolution] = (0, import_react4.useState)(null);
8751
8892
  const resolver = client.config.resolver;
8752
- (0, import_react3.useEffect)(() => {
8893
+ (0, import_react4.useEffect)(() => {
8753
8894
  if (!key) {
8754
8895
  setResolution(null);
8755
8896
  return;
@@ -8784,11 +8925,11 @@ function useMergeField(key, state) {
8784
8925
  }
8785
8926
 
8786
8927
  // src/react/entity-reference.ts
8787
- var import_react4 = require("react");
8928
+ var import_react5 = require("react");
8788
8929
  function useEntityReferenceKinds() {
8789
8930
  const client = useRecordsClient();
8790
- const [state, setState] = (0, import_react4.useState)({ data: null, loading: true, error: null });
8791
- (0, import_react4.useEffect)(() => {
8931
+ const [state, setState] = (0, import_react5.useState)({ data: null, loading: true, error: null });
8932
+ (0, import_react5.useEffect)(() => {
8792
8933
  let live = true;
8793
8934
  void entityReferenceKinds(client.config.dataSource).then((res) => {
8794
8935
  if (!live) return;
@@ -8803,8 +8944,8 @@ function useEntityReferenceKinds() {
8803
8944
  function useEntityReferenceWords(refs) {
8804
8945
  const client = useRecordsClient();
8805
8946
  const key = refs.map((r) => `${r.token}:${r.id}`).join(",");
8806
- const [state, setState] = (0, import_react4.useState)({ data: null, loading: refs.length > 0, error: null });
8807
- (0, import_react4.useEffect)(() => {
8947
+ const [state, setState] = (0, import_react5.useState)({ data: null, loading: refs.length > 0, error: null });
8948
+ (0, import_react5.useEffect)(() => {
8808
8949
  let live = true;
8809
8950
  void entityReferenceWords(client.config.dataSource, client.config.organizationId, refs).then((res) => {
8810
8951
  if (!live) return;
@@ -8819,8 +8960,8 @@ function useEntityReferenceWords(refs) {
8819
8960
  function useEntityReferenceSearch(tokens, search, enabled = true) {
8820
8961
  const client = useRecordsClient();
8821
8962
  const key = `${tokens.join(",")}|${search.trim()}|${enabled ? 1 : 0}`;
8822
- const [state, setState] = (0, import_react4.useState)({ data: null, loading: enabled && tokens.length > 0, error: null });
8823
- (0, import_react4.useEffect)(() => {
8963
+ const [state, setState] = (0, import_react5.useState)({ data: null, loading: enabled && tokens.length > 0, error: null });
8964
+ (0, import_react5.useEffect)(() => {
8824
8965
  if (!enabled || tokens.length === 0) {
8825
8966
  setState({ data: [], loading: false, error: null });
8826
8967
  return;
@@ -8842,7 +8983,7 @@ function useEntityReferenceSearch(tokens, search, enabled = true) {
8842
8983
  }
8843
8984
 
8844
8985
  // src/react/useAppTable.ts
8845
- var import_react5 = require("react");
8986
+ var import_react6 = require("react");
8846
8987
 
8847
8988
  // src/core/declareTable.ts
8848
8989
  function tokenFor(name) {
@@ -9137,16 +9278,16 @@ function useAppTable(def, options = {}) {
9137
9278
  const client = useRecordsClient();
9138
9279
  const narrowed = options.organizationId ?? null;
9139
9280
  const writeOrg = narrowed ?? client.config.organizationId;
9140
- const [rows, setRows] = (0, import_react5.useState)([]);
9141
- const [total, setTotal] = (0, import_react5.useState)(null);
9142
- const [truncated, setTruncated] = (0, import_react5.useState)(false);
9143
- const [loading, setLoading] = (0, import_react5.useState)(true);
9144
- const [error, setError] = (0, import_react5.useState)(null);
9145
- const [status, setStatus] = (0, import_react5.useState)(null);
9146
- const [revision, setRevision] = (0, import_react5.useState)(0);
9147
- const rowsRef = (0, import_react5.useRef)([]);
9281
+ const [rows, setRows] = (0, import_react6.useState)([]);
9282
+ const [total, setTotal] = (0, import_react6.useState)(null);
9283
+ const [truncated, setTruncated] = (0, import_react6.useState)(false);
9284
+ const [loading, setLoading] = (0, import_react6.useState)(true);
9285
+ const [error, setError] = (0, import_react6.useState)(null);
9286
+ const [status, setStatus] = (0, import_react6.useState)(null);
9287
+ const [revision, setRevision] = (0, import_react6.useState)(0);
9288
+ const rowsRef = (0, import_react6.useRef)([]);
9148
9289
  rowsRef.current = rows;
9149
- (0, import_react5.useEffect)(() => {
9290
+ (0, import_react6.useEffect)(() => {
9150
9291
  let live = true;
9151
9292
  setLoading(true);
9152
9293
  (async () => {
@@ -9178,8 +9319,8 @@ function useAppTable(def, options = {}) {
9178
9319
  live = false;
9179
9320
  };
9180
9321
  }, [client, def.slug, def.kept_for, def.specHash, writeOrg, narrowed, revision]);
9181
- const reload = (0, import_react5.useCallback)(() => setRevision((n) => n + 1), []);
9182
- const upsert = (0, import_react5.useCallback)(
9322
+ const reload = (0, import_react6.useCallback)(() => setRevision((n) => n + 1), []);
9323
+ const upsert = (0, import_react6.useCallback)(
9183
9324
  async (data, upsertOptions = {}) => {
9184
9325
  if (!writeOrg) {
9185
9326
  return { ok: false, error: { code: "invalid_argument", message: `${def.name}: no organization to write to.` } };
@@ -9190,7 +9331,7 @@ function useAppTable(def, options = {}) {
9190
9331
  },
9191
9332
  [client, def, writeOrg, reload]
9192
9333
  );
9193
- const remove = (0, import_react5.useCallback)(
9334
+ const remove = (0, import_react6.useCallback)(
9194
9335
  async (rowId) => {
9195
9336
  const org = rowsRef.current.find((r) => r._id === rowId)?._organizationId ?? writeOrg;
9196
9337
  const answer = await removeAppRow(client, def, rowId, { organizationId: org });
@@ -9207,7 +9348,7 @@ function archivedTableOf(error) {
9207
9348
  }
9208
9349
 
9209
9350
  // src/react/useStoreTable.ts
9210
- var import_react7 = require("react");
9351
+ var import_react8 = require("react");
9211
9352
 
9212
9353
  // src/app-table/store-table.ts
9213
9354
  function storeTable(def) {
@@ -10442,7 +10583,7 @@ function createTableDataPort({ client, aliases }) {
10442
10583
  }
10443
10584
 
10444
10585
  // src/data/react.tsx
10445
- var import_react6 = require("react");
10586
+ var import_react7 = require("react");
10446
10587
  var import_react_query = require("@tanstack/react-query");
10447
10588
  var RECORDS_QUERY_ROOT = "@ai-matrx/records";
10448
10589
  var DATA_LIVE_GRACE_MS = 3e4;
@@ -10489,13 +10630,13 @@ function retryable(failureCount, thrown) {
10489
10630
  const code = thrown instanceof DataRefusal ? thrown.error.code : "unreachable";
10490
10631
  return (code === "unreachable" || code === "timed_out") && failureCount < 2;
10491
10632
  }
10492
- var DataPortContext = (0, import_react6.createContext)(null);
10633
+ var DataPortContext = (0, import_react7.createContext)(null);
10493
10634
  function hostEvents(port) {
10494
10635
  return { on: (event, listener) => port.subscribe(event, listener) };
10495
10636
  }
10496
10637
  var warnedNotLive = false;
10497
10638
  function useDataPort(scope) {
10498
- const held = (0, import_react6.useContext)(DataPortContext);
10639
+ const held = (0, import_react7.useContext)(DataPortContext);
10499
10640
  if (scope) return scope;
10500
10641
  if (!held) {
10501
10642
  throw new Error(
@@ -10781,7 +10922,7 @@ function acquireLive(qc, port, events, portKey, alias) {
10781
10922
  }
10782
10923
  var FALLBACK_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-query-client");
10783
10924
  function useRecordsQueryClient() {
10784
- const provided = (0, import_react6.useContext)(import_react_query.QueryClientContext);
10925
+ const provided = (0, import_react7.useContext)(import_react_query.QueryClientContext);
10785
10926
  if (provided) return provided;
10786
10927
  const g = globalThis;
10787
10928
  let held = g[FALLBACK_KEY];
@@ -10794,7 +10935,7 @@ function useRecordsQueryClient() {
10794
10935
  function useLive(alias, scope) {
10795
10936
  const qc = useRecordsQueryClient();
10796
10937
  const { port, portKey, events } = useDataPort(scope);
10797
- (0, import_react6.useEffect)(() => {
10938
+ (0, import_react7.useEffect)(() => {
10798
10939
  if (!alias) return;
10799
10940
  return acquireLive(qc, port, events, portKey, alias);
10800
10941
  }, [qc, port, events, portKey, alias]);
@@ -10814,7 +10955,7 @@ function useDataRows(alias, query = {}, scope) {
10814
10955
  },
10815
10956
  qc
10816
10957
  );
10817
- const rows = (0, import_react6.useMemo)(() => {
10958
+ const rows = (0, import_react7.useMemo)(() => {
10818
10959
  const seen = /* @__PURE__ */ new Set();
10819
10960
  const out = [];
10820
10961
  for (const page2 of q.data?.pages ?? []) {
@@ -10826,11 +10967,11 @@ function useDataRows(alias, query = {}, scope) {
10826
10967
  }
10827
10968
  return out;
10828
10969
  }, [q.data]);
10829
- const want = (0, import_react6.useRef)({ key: "", pages: 0 });
10970
+ const want = (0, import_react7.useRef)({ key: "", pages: 0 });
10830
10971
  const keyHash = (0, import_react_query.hashKey)(rowsKey);
10831
10972
  const loaded = q.data?.pages.length ?? 0;
10832
10973
  const { isFetching, hasNextPage, isFetchNextPageError, fetchNextPage } = q;
10833
- (0, import_react6.useEffect)(() => {
10974
+ (0, import_react7.useEffect)(() => {
10834
10975
  const w = want.current;
10835
10976
  if (w.key !== keyHash || isFetching || loaded >= w.pages) return;
10836
10977
  if (!hasNextPage || isFetchNextPageError) {
@@ -10870,7 +11011,7 @@ function drawPatch(before, patch) {
10870
11011
  function useDataMutations(alias, scope) {
10871
11012
  const qc = useRecordsQueryClient();
10872
11013
  const { port, portKey } = useDataPort(scope);
10873
- return (0, import_react6.useMemo)(() => {
11014
+ return (0, import_react7.useMemo)(() => {
10874
11015
  const snapshotRows = () => qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
10875
11016
  const putBack = (snap) => {
10876
11017
  for (const [key, data] of snap) qc.setQueryData(key, data);
@@ -10972,7 +11113,7 @@ function toNamed(table, row) {
10972
11113
  function useStoreTable(table, options = {}) {
10973
11114
  const client = useRecordsClient();
10974
11115
  const alias = table.id;
10975
- const scope = (0, import_react7.useMemo)(
11116
+ const scope = (0, import_react8.useMemo)(
10976
11117
  () => {
10977
11118
  const port = createTableDataPort({ client, aliases: { [alias]: { kind: "table", tableId: table.id, organizationId: table.organizationId, label: table.name } } });
10978
11119
  return { port, events: hostEvents(port), portKey: `store-table|${client.config.organizationId ?? "-"}|${client.config.actor.user_id ?? "-"}` };
@@ -10980,7 +11121,7 @@ function useStoreTable(table, options = {}) {
10980
11121
  [client, alias, table.id, table.organizationId, table.name]
10981
11122
  );
10982
11123
  const asked = JSON.stringify(options);
10983
- const built = (0, import_react7.useMemo)(() => {
11124
+ const built = (0, import_react8.useMemo)(() => {
10984
11125
  const where = [];
10985
11126
  for (const [name, value] of Object.entries(options.where ?? {})) {
10986
11127
  const column = table.columns[name];
@@ -11007,10 +11148,10 @@ function useStoreTable(table, options = {}) {
11007
11148
  const limit = Math.min(options.limit ?? STORE_ROWS_CEILING, STORE_ROWS_CEILING);
11008
11149
  const read = useDataRows(alias, built.ok ? built.data : { pageSize: 1 }, scope);
11009
11150
  const write = useDataMutations(alias, scope);
11010
- (0, import_react7.useEffect)(() => {
11151
+ (0, import_react8.useEffect)(() => {
11011
11152
  if (built.ok && read.hasMore && !read.loadingMore && !read.loading && !read.error && read.rows.length < limit) read.loadMore();
11012
11153
  }, [built.ok, read.hasMore, read.loadingMore, read.loading, read.error, read.rows.length, limit, read]);
11013
- const rows = (0, import_react7.useMemo)(() => read.rows.slice(0, limit).filter((r) => r["_pending"] !== true).map((r) => toNamed(table, r)), [read.rows, limit, table]);
11154
+ const rows = (0, import_react8.useMemo)(() => read.rows.slice(0, limit).filter((r) => r["_pending"] !== true).map((r) => toNamed(table, r)), [read.rows, limit, table]);
11014
11155
  const total = built.ok ? read.total : null;
11015
11156
  return {
11016
11157
  rows: built.ok ? rows : [],