@ai-matrx/records 0.87.32 → 0.92.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/README.md +115 -0
  3. package/dist/{client-E0VQ0NPO.d.ts → client-DE9Mq6YX.d.cts} +8 -5
  4. package/dist/{client-C3ZZNfGH.d.cts → client-vJAb7g9r.d.ts} +8 -5
  5. package/dist/core/index.cjs +25 -7
  6. package/dist/core/index.cjs.map +1 -1
  7. package/dist/core/index.d.cts +23 -12
  8. package/dist/core/index.d.ts +23 -12
  9. package/dist/core/index.js +25 -7
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/data/index.cjs +19 -7
  12. package/dist/data/index.cjs.map +1 -1
  13. package/dist/data/index.d.cts +12 -142
  14. package/dist/data/index.d.ts +12 -142
  15. package/dist/data/index.js +19 -7
  16. package/dist/data/index.js.map +1 -1
  17. package/dist/{declareTable-BK3zufr7.d.cts → declareTable-Btg5bql1.d.cts} +4 -4
  18. package/dist/{declareTable-B12XybRp.d.ts → declareTable-JKt2q34d.d.ts} +4 -4
  19. package/dist/entity/index.cjs +984 -0
  20. package/dist/entity/index.cjs.map +1 -0
  21. package/dist/entity/index.d.cts +36 -0
  22. package/dist/entity/index.d.ts +36 -0
  23. package/dist/entity/index.js +964 -0
  24. package/dist/entity/index.js.map +1 -0
  25. package/dist/entity/react.cjs +1024 -0
  26. package/dist/entity/react.cjs.map +1 -0
  27. package/dist/entity/react.d.cts +511 -0
  28. package/dist/entity/react.d.ts +511 -0
  29. package/dist/entity/react.js +1015 -0
  30. package/dist/entity/react.js.map +1 -0
  31. package/dist/{field-BanTVGK2.d.cts → field-BJBnTyJ0.d.cts} +1 -1
  32. package/dist/{field-BPABOJ2Y.d.ts → field-Ti5iAxFr.d.ts} +1 -1
  33. package/dist/forms/index.cjs +984 -0
  34. package/dist/forms/index.cjs.map +1 -0
  35. package/dist/forms/index.d.cts +333 -0
  36. package/dist/forms/index.d.ts +333 -0
  37. package/dist/forms/index.js +961 -0
  38. package/dist/forms/index.js.map +1 -0
  39. package/dist/index.cjs +10 -1
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +11 -8
  42. package/dist/index.d.ts +11 -8
  43. package/dist/index.js +10 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/memory/index.d.cts +7 -6
  46. package/dist/memory/index.d.ts +7 -6
  47. package/dist/port-CPVBfDxS.d.cts +301 -0
  48. package/dist/port-D2i2o7Lg.d.ts +301 -0
  49. package/dist/portal-Db4CYyHe.d.ts +331 -0
  50. package/dist/portal-DfeY2Boy.d.cts +331 -0
  51. package/dist/{ports-TMWX-t9l.d.ts → ports-BWtxAnXh.d.ts} +2 -2
  52. package/dist/{ports-D8-iuY1P.d.cts → ports-DSU2RsR6.d.cts} +2 -2
  53. package/dist/react/index.cjs +55 -523
  54. package/dist/react/index.cjs.map +1 -1
  55. package/dist/react/index.d.cts +14 -1
  56. package/dist/react/index.d.ts +14 -1
  57. package/dist/react/index.js +52 -527
  58. package/dist/react/index.js.map +1 -1
  59. package/dist/realtime/index.d.cts +2 -2
  60. package/dist/realtime/index.d.ts +2 -2
  61. package/dist/{record-DpB2QgAZ.d.cts → record-BQi92d4-.d.cts} +7 -1
  62. package/dist/{record-DpB2QgAZ.d.ts → record-BQi92d4-.d.ts} +7 -1
  63. package/dist/relation-DMwkmzgN.d.cts +230 -0
  64. package/dist/relation-DlcqV_W5.d.ts +230 -0
  65. package/dist/rule-B8kR0l01.d.ts +250 -0
  66. package/dist/rule-BMViCLmW.d.cts +250 -0
  67. package/dist/search/index.cjs +283 -0
  68. package/dist/search/index.cjs.map +1 -0
  69. package/dist/search/index.d.cts +44 -0
  70. package/dist/search/index.d.ts +44 -0
  71. package/dist/search/index.js +260 -0
  72. package/dist/search/index.js.map +1 -0
  73. package/dist/setup/index.cjs +6854 -0
  74. package/dist/setup/index.cjs.map +1 -0
  75. package/dist/setup/index.d.cts +87 -0
  76. package/dist/setup/index.d.ts +87 -0
  77. package/dist/setup/index.js +6829 -0
  78. package/dist/setup/index.js.map +1 -0
  79. package/dist/{subscription-D7KQBHXN.d.ts → subscription-5CLN3Jug.d.ts} +3 -249
  80. package/dist/{subscription-BD9DnJxX.d.cts → subscription-D-VEzvyy.d.cts} +3 -249
  81. package/dist/{table-kind-BZu8mtND.d.cts → table-kind-CVp43g6h.d.ts} +3 -558
  82. package/dist/{table-kind-xKxTHtrV.d.ts → table-kind-Cm6PXkWx.d.cts} +3 -558
  83. package/dist/templates/index.d.cts +10 -9
  84. package/dist/templates/index.d.ts +10 -9
  85. package/dist/typed-table/index.cjs +19 -7
  86. package/dist/typed-table/index.cjs.map +1 -1
  87. package/dist/typed-table/index.d.cts +10 -7
  88. package/dist/typed-table/index.d.ts +10 -7
  89. package/dist/typed-table/index.js +19 -7
  90. package/dist/typed-table/index.js.map +1 -1
  91. package/dist/{types-CLP5H4Wk.d.cts → types-9Q5SHRDJ.d.cts} +2 -2
  92. package/dist/{types-DmPkWQic.d.ts → types-CfYy-vdV.d.ts} +2 -2
  93. package/dist/{types-C2uspRtf.d.cts → types-Cs2MyE3u.d.cts} +2 -2
  94. package/dist/{types-Dv61jStB.d.ts → types-DF-dxB_l.d.ts} +2 -2
  95. package/dist/types-DTEGaxso.d.cts +139 -0
  96. package/dist/types-Dji5SpFS.d.ts +139 -0
  97. package/dist/use-cases/index.d.cts +5 -5
  98. package/dist/use-cases/index.d.ts +5 -5
  99. package/dist/{validate-CWVToe1T.d.ts → validate-BydKd-Le.d.ts} +1 -1
  100. package/dist/{validate-DEB_mn4Y.d.cts → validate-CqJakTKk.d.cts} +1 -1
  101. package/dist/versions/index.cjs +375 -0
  102. package/dist/versions/index.cjs.map +1 -0
  103. package/dist/versions/index.d.cts +160 -0
  104. package/dist/versions/index.d.ts +160 -0
  105. package/dist/versions/index.js +353 -0
  106. package/dist/versions/index.js.map +1 -0
  107. package/package.json +62 -2
@@ -292,6 +292,7 @@ __export(react_exports, {
292
292
  useRecordChangeRevision: () => useRecordChangeRevision,
293
293
  useRecordMutation: () => useRecordMutation,
294
294
  useRecordPage: () => useRecordPage,
295
+ useRecordWrites: () => useRecordWrites,
295
296
  useRecords: () => useRecords,
296
297
  useRecordsActor: () => useRecordsActor,
297
298
  useRecordsClient: () => useRecordsClient,
@@ -480,9 +481,18 @@ function stableFilterKey(filter) {
480
481
  return `{${parts.join(",")}}`;
481
482
  }
482
483
  function liftWithheld(rows) {
484
+ let shared;
485
+ for (const row of rows) {
486
+ const m = (row.measures ?? {})["_withheld"];
487
+ if (m !== void 0 && m !== null && typeof m === "object") {
488
+ shared = m;
489
+ break;
490
+ }
491
+ }
483
492
  return rows.map((row) => {
484
493
  const measures = row.measures ?? {};
485
- const marker = measures["_withheld"];
494
+ const own = measures["_withheld"];
495
+ const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
486
496
  const rowCount = row.row_count ?? 0;
487
497
  if (marker === void 0 || marker === null || typeof marker !== "object") {
488
498
  return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
@@ -5094,12 +5104,15 @@ function createRecordsClient(given) {
5094
5104
  () => true
5095
5105
  );
5096
5106
  }
5097
- const door = await callDoor(
5098
- DOORS.readRecord,
5099
- { p_organization_id: org, p_record_id: record_id },
5100
- "recordRead"
5101
- );
5107
+ const [door, header] = await Promise.all([
5108
+ callDoor(DOORS.readRecord, { p_organization_id: org, p_record_id: record_id }, "recordRead"),
5109
+ // A version that cannot be read never takes the record away: it comes back as null.
5110
+ callDoor(DOORS.recordHeaders, { p_organization_id: org, p_ids: [record_id] }, "recordRead.version").catch(
5111
+ () => null
5112
+ )
5113
+ ]);
5102
5114
  if (!door.ok) return err(door.error);
5115
+ const version = header && header.ok ? header.data?.find((h) => h.id === record_id)?.version ?? null : null;
5103
5116
  const { document, hidden } = unfold(door.data);
5104
5117
  let computed = [];
5105
5118
  let computedUnavailable = null;
@@ -5112,7 +5125,7 @@ function createRecordsClient(given) {
5112
5125
  if (provenance.ok) computed = provenance.data ?? [];
5113
5126
  else computedUnavailable = provenance.error;
5114
5127
  }
5115
- return ok({ record_id, document, hidden, computed, computedUnavailable });
5128
+ return ok({ record_id, document, hidden, computed, computedUnavailable, version });
5116
5129
  },
5117
5130
  async listByIds({ table_id, ids }) {
5118
5131
  if (ids.length === 0) return ok([]);
@@ -8749,11 +8762,14 @@ function liveRowsFor(tableId, order = { sortFields: [], narrowed: false }) {
8749
8762
  );
8750
8763
  };
8751
8764
  let timer = null;
8752
- const stopLocal = onRecordChanged(() => {
8765
+ const written = /* @__PURE__ */ new Set();
8766
+ const stopLocal = onRecordChanged((changed) => {
8767
+ written.add(changed);
8753
8768
  if (timer !== null) clearTimeout(timer);
8754
8769
  timer = setTimeout(() => {
8755
8770
  timer = null;
8756
- const ids = (entry.snapshot.data?.rows ?? []).map((row) => row.id);
8771
+ const ids = [.../* @__PURE__ */ new Set([...(entry.snapshot.data?.rows ?? []).map((row) => row.id), ...written])];
8772
+ written.clear();
8757
8773
  if (ids.length > 0) patchIds(ids).catch(() => entry.refetch());
8758
8774
  }, 250);
8759
8775
  });
@@ -8881,6 +8897,24 @@ function useRecordPage(tableId, options = {}) {
8881
8897
  const { live, liveReason } = liveStatus(useRecordsClient(), tableId);
8882
8898
  return { ...useSharedRows(useKeptPage(tableId, base)), live, liveReason };
8883
8899
  }
8900
+ function useRecordWrites() {
8901
+ const [writes, setWrites] = (0, import_react4.useState)(0);
8902
+ (0, import_react4.useEffect)(() => {
8903
+ let timer = null;
8904
+ const stop = onRecordChanged(() => {
8905
+ if (timer !== null) clearTimeout(timer);
8906
+ timer = setTimeout(() => {
8907
+ timer = null;
8908
+ setWrites((n) => n + 1);
8909
+ }, 250);
8910
+ });
8911
+ return () => {
8912
+ if (timer !== null) clearTimeout(timer);
8913
+ stop();
8914
+ };
8915
+ }, []);
8916
+ return writes;
8917
+ }
8884
8918
  function useRecordChangeRevision(recordId) {
8885
8919
  const [revision, setRevision] = (0, import_react4.useState)(0);
8886
8920
  (0, import_react4.useEffect)(() => {
@@ -9905,7 +9939,7 @@ function archivedTableOf(error) {
9905
9939
  }
9906
9940
 
9907
9941
  // src/react/useStoreTable.ts
9908
- var import_react8 = require("react");
9942
+ var import_react7 = require("react");
9909
9943
 
9910
9944
  // src/typed-table/store-table.ts
9911
9945
  function storeTable(def) {
@@ -10998,7 +11032,7 @@ function blankToNull(type, value, field2) {
10998
11032
  }
10999
11033
  function createTableDataPort({ client, aliases }) {
11000
11034
  const shapes = /* @__PURE__ */ new Map();
11001
- let warnedNotLive2 = false;
11035
+ let warnedNotLive = false;
11002
11036
  function bindingOf(alias) {
11003
11037
  return Object.prototype.hasOwnProperty.call(aliases, alias) ? aliases[alias] : null;
11004
11038
  }
@@ -11198,8 +11232,8 @@ function createTableDataPort({ client, aliases }) {
11198
11232
  }
11199
11233
  const realtime = client.config.realtime;
11200
11234
  if (!realtime) {
11201
- if (!warnedNotLive2) {
11202
- warnedNotLive2 = true;
11235
+ if (!warnedNotLive) {
11236
+ warnedNotLive = true;
11203
11237
  console.warn("[@ai-matrx/records/data] This host bound no realtime port, so other people's changes will not appear until a re-read.");
11204
11238
  }
11205
11239
  return () => {
@@ -11219,510 +11253,8 @@ function createTableDataPort({ client, aliases }) {
11219
11253
  };
11220
11254
  }
11221
11255
 
11222
- // src/data/react.tsx
11223
- var import_react7 = require("react");
11224
- var import_react_query = require("@tanstack/react-query");
11225
- var RECORDS_QUERY_ROOT = "@ai-matrx/records";
11226
- var DATA_LIVE_GRACE_MS = 3e4;
11227
- var BUMP_BATCH_MS = 40;
11228
- var dataKeys = {
11229
- all: (portKey) => [RECORDS_QUERY_ROOT, "data", portKey],
11230
- sources: (portKey) => [RECORDS_QUERY_ROOT, "data", portKey, "sources"],
11231
- alias: (portKey, alias) => [RECORDS_QUERY_ROOT, "data", portKey, "alias", alias],
11232
- columns: (portKey, alias) => [...dataKeys.alias(portKey, alias), "columns"],
11233
- rowsPrefix: (portKey, alias) => [...dataKeys.alias(portKey, alias), "rows"],
11234
- rows: (portKey, alias, query) => [...dataKeys.rowsPrefix(portKey, alias), stableQuery(query)],
11235
- row: (portKey, alias, id) => [...dataKeys.alias(portKey, alias), "row", id]
11236
- };
11237
- function stableQuery(query) {
11238
- const sortKeys = (value) => {
11239
- if (Array.isArray(value)) return value.map(sortKeys);
11240
- if (value && typeof value === "object") {
11241
- return Object.fromEntries(
11242
- Object.keys(value).sort().filter((k) => value[k] !== void 0).map((k) => [k, sortKeys(value[k])])
11243
- );
11244
- }
11245
- return value;
11246
- };
11247
- return JSON.stringify(sortKeys(query ?? {}));
11248
- }
11249
- var DataRefusal = class extends Error {
11250
- error;
11251
- constructor(error) {
11252
- super(error.message);
11253
- this.name = "DataRefusal";
11254
- this.error = error;
11255
- }
11256
- };
11257
- function unwrap(answer) {
11258
- if (answer.ok) return answer.data;
11259
- throw new DataRefusal(answer.error);
11260
- }
11261
- function asRecordsError(thrown) {
11262
- if (!thrown) return null;
11263
- if (thrown instanceof DataRefusal) return thrown.error;
11264
- return { code: "unreachable", message: `The data could not be reached: ${thrown instanceof Error ? thrown.message : String(thrown)}` };
11265
- }
11266
- function retryable(failureCount, thrown) {
11267
- const code = thrown instanceof DataRefusal ? thrown.error.code : "unreachable";
11268
- return (code === "unreachable" || code === "timed_out") && failureCount < 2;
11269
- }
11270
- var DataPortContext = (0, import_react7.createContext)(null);
11271
- function hostEvents(port) {
11272
- return { on: (event, listener) => port.subscribe(event, listener) };
11273
- }
11274
- var warnedNotLive = false;
11275
- function useDataPort(scope) {
11276
- const held = (0, import_react7.useContext)(DataPortContext);
11277
- if (scope) return scope;
11278
- if (!held) {
11279
- throw new Error(
11280
- "A data hook was called outside <DataPortProvider>. The frame mounts it once with the host's DataPort and this Applet's portKey."
11281
- );
11282
- }
11283
- return held;
11284
- }
11285
- function forEachRowsEntry(qc, portKey, alias, fn) {
11286
- for (const [key, data] of qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) })) {
11287
- if (!data) continue;
11288
- const next = fn(key, data);
11289
- if (next && next !== data) qc.setQueryData(key, next);
11290
- }
11291
- }
11292
- var LANDED_MS = 3e4;
11293
- var LANDED_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-landed");
11294
- function landedHome(qc) {
11295
- const holder = qc;
11296
- let home = holder[LANDED_KEY];
11297
- if (!home) {
11298
- const made = { byAlias: /* @__PURE__ */ new Map(), unsubscribe: () => {
11299
- } };
11300
- made.unsubscribe = qc.getQueryCache().subscribe((event) => {
11301
- if (event.type !== "updated" || event.action.type !== "success") return;
11302
- const key = event.query.queryKey;
11303
- if (key[0] !== RECORDS_QUERY_ROOT || key[1] !== "data" || key[3] !== "alias" || key[5] !== "rows") return;
11304
- const portKey = String(key[2]);
11305
- const alias = String(key[4]);
11306
- const landed = made.byAlias.get(`${portKey}${alias}`);
11307
- if (!landed || landed.size === 0) return;
11308
- reapplyLanded(qc, event.query.queryKey, landed);
11309
- });
11310
- holder[LANDED_KEY] = made;
11311
- home = made;
11312
- }
11313
- return home;
11314
- }
11315
- function remember(qc, portKey, alias, id, row) {
11316
- const home = landedHome(qc);
11317
- const key = `${portKey}${alias}`;
11318
- let landed = home.byAlias.get(key);
11319
- if (!landed) home.byAlias.set(key, landed = /* @__PURE__ */ new Map());
11320
- const now = Date.now();
11321
- for (const [oldId, entry] of landed) if (now - entry.at > LANDED_MS) landed.delete(oldId);
11322
- landed.set(id, { row, at: now });
11323
- }
11324
- function reapplyLanded(qc, key, landed) {
11325
- const data = qc.getQueryData(key);
11326
- if (!data) return;
11327
- const now = Date.now();
11328
- let changed = false;
11329
- const pages = data.pages.map((page2) => {
11330
- let rows = null;
11331
- page2.rows.forEach((r, i) => {
11332
- const entry = landed.get(r._id);
11333
- if (!entry || now - entry.at > LANDED_MS) return;
11334
- if (entry.row === null) {
11335
- rows ??= page2.rows.slice();
11336
- rows[i] = null;
11337
- } else if (entry.row._version > r._version) {
11338
- rows ??= page2.rows.slice();
11339
- rows[i] = entry.row;
11340
- }
11341
- });
11342
- if (!rows) return page2;
11343
- changed = true;
11344
- return { ...page2, rows: rows.filter((r) => r !== null) };
11345
- });
11346
- if (changed) qc.setQueryData(key, { ...data, pages });
11347
- }
11348
- function patchRow(qc, portKey, alias, row, options = {}) {
11349
- if (options.fromStore) remember(qc, portKey, alias, row._id, row);
11350
- let held = false;
11351
- forEachRowsEntry(qc, portKey, alias, (_key, data) => {
11352
- let changed = false;
11353
- const pages = data.pages.map((page2) => {
11354
- const i = page2.rows.findIndex((r) => r._id === row._id);
11355
- if (i < 0) return page2;
11356
- held = true;
11357
- if (!options.force && page2.rows[i]._version > row._version) return page2;
11358
- changed = true;
11359
- const rows = page2.rows.slice();
11360
- rows[i] = row;
11361
- return { ...page2, rows };
11362
- });
11363
- return changed ? { ...data, pages } : data;
11364
- });
11365
- const rowKey = dataKeys.row(portKey, alias, row._id);
11366
- const current = qc.getQueryData(rowKey);
11367
- if (options.force || !current || current._version <= row._version) qc.setQueryData(rowKey, row);
11368
- return held;
11369
- }
11370
- function dropRow(qc, portKey, alias, id, options = {}) {
11371
- if (options.fromStore) remember(qc, portKey, alias, id, null);
11372
- forEachRowsEntry(qc, portKey, alias, (_key, data) => {
11373
- let changed = false;
11374
- const pages = data.pages.map((page2) => {
11375
- if (!page2.rows.some((r) => r._id === id)) return page2;
11376
- changed = true;
11377
- return { ...page2, rows: page2.rows.filter((r) => r._id !== id), total: page2.total === null ? null : Math.max(0, page2.total - 1) };
11378
- });
11379
- return changed ? { ...data, pages } : data;
11380
- });
11381
- qc.setQueryData(dataKeys.row(portKey, alias, id), null);
11382
- }
11383
- function findRow(qc, portKey, alias, id) {
11384
- const direct = qc.getQueryData(dataKeys.row(portKey, alias, id));
11385
- if (direct) return direct;
11386
- for (const [, data] of qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) })) {
11387
- for (const page2 of data?.pages ?? []) {
11388
- const hit = page2.rows.find((r) => r._id === id);
11389
- if (hit) return hit;
11390
- }
11391
- }
11392
- return null;
11393
- }
11394
- var LIVE_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-live");
11395
- function liveHome(qc) {
11396
- const holder = qc;
11397
- let home = holder[LIVE_KEY];
11398
- if (!home) {
11399
- home = /* @__PURE__ */ new Map();
11400
- holder[LIVE_KEY] = home;
11401
- }
11402
- return home;
11403
- }
11404
- function isPlainNewestFirst(key) {
11405
- try {
11406
- const q = JSON.parse(String(key[key.length - 1]));
11407
- return !(q.where && q.where.length) && !q.search?.trim() && !(q.sort && q.sort.length);
11408
- } catch {
11409
- return false;
11410
- }
11411
- }
11412
- var REREAD_PAGES_MAX = 2;
11413
- async function sourceKind(qc, port, portKey, alias) {
11414
- try {
11415
- const sources = await qc.ensureQueryData({ queryKey: dataKeys.sources(portKey), queryFn: async () => unwrap(await port.sources()) });
11416
- return sources.find((s) => s.alias === alias)?.kind ?? null;
11417
- } catch {
11418
- return null;
11419
- }
11420
- }
11421
- var DEFERRED_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-deferred-rereads");
11422
- var OWED_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-owed-pages");
11423
- function owedPages(qc) {
11424
- const holder = qc;
11425
- return holder[OWED_KEY] ??= /* @__PURE__ */ new Map();
11426
- }
11427
- function owedPage(qc, hash) {
11428
- const owed = owedPages(qc).get(hash);
11429
- if (!owed) return null;
11430
- const query = qc.getQueryCache().get(hash);
11431
- const data = query?.state.data;
11432
- const last = data?.pages[data.pages.length - 1];
11433
- if (!query || query.state.status === "error" || !data || data.pages.length >= owed.pages || !last?.cursor) {
11434
- owedPages(qc).delete(hash);
11435
- return null;
11436
- }
11437
- return owed;
11438
- }
11439
- function rereadList(qc, key) {
11440
- const query = qc.getQueryCache().find({ queryKey: key, exact: true });
11441
- if (!query || query.state.fetchStatus !== "fetching" && !owedPage(qc, query.queryHash)) {
11442
- void qc.invalidateQueries({ queryKey: key, exact: true });
11443
- return;
11444
- }
11445
- const holder = qc;
11446
- const waiting = holder[DEFERRED_KEY] ??= /* @__PURE__ */ new Set();
11447
- if (waiting.has(query.queryHash)) return;
11448
- waiting.add(query.queryHash);
11449
- const settle = () => {
11450
- if (query.state.fetchStatus === "fetching") return;
11451
- const owed = owedPage(qc, query.queryHash);
11452
- if (owed) {
11453
- owed.fetchNext();
11454
- return;
11455
- }
11456
- stop();
11457
- waiting.delete(query.queryHash);
11458
- void qc.invalidateQueries({ queryKey: key, exact: true });
11459
- };
11460
- const stop = qc.getQueryCache().subscribe((event) => {
11461
- if (event.query === query) settle();
11462
- });
11463
- settle();
11464
- }
11465
- function rereadOrCount(qc, key, data, count) {
11466
- if (data.pages.length <= REREAD_PAGES_MAX) rereadList(qc, key);
11467
- else qc.setQueryData(key, { ...data, newer: (data.newer ?? 0) + count });
11468
- }
11469
- function placeUnseen(qc, portKey, alias, rows, kind) {
11470
- for (const [key, data] of qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) })) {
11471
- if (!data || data.pages.length === 0) continue;
11472
- const missing = rows.filter((row) => !data.pages.some((page2) => page2.rows.some((r) => r._id === row._id)));
11473
- if (missing.length === 0) continue;
11474
- if (kind === "table" && isPlainNewestFirst(key)) {
11475
- const [first, ...rest] = data.pages;
11476
- qc.setQueryData(key, {
11477
- ...data,
11478
- pages: [{ ...first, rows: [...missing, ...first.rows], total: first.total === null ? null : first.total + missing.length }, ...rest]
11479
- });
11480
- } else {
11481
- rereadOrCount(qc, key, data, missing.length);
11482
- }
11483
- }
11484
- }
11485
- async function rereadIds(qc, port, portKey, alias, ids) {
11486
- const answers = await Promise.all(ids.map((id) => port.get(alias, id).then((a) => [id, a])));
11487
- const unseen = [];
11488
- for (const [id, answer] of answers) {
11489
- if (!answer.ok) continue;
11490
- if (answer.data === null) {
11491
- dropRow(qc, portKey, alias, id, { fromStore: true });
11492
- } else if (!patchRow(qc, portKey, alias, answer.data, { fromStore: true })) {
11493
- unseen.push(answer.data);
11494
- }
11495
- }
11496
- if (unseen.length > 0) placeUnseen(qc, portKey, alias, unseen, await sourceKind(qc, port, portKey, alias));
11497
- }
11498
- function rereadUnknown(qc, portKey, alias) {
11499
- for (const [key, data] of qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) })) {
11500
- if (!data || data.pages.length === 0) {
11501
- rereadList(qc, key);
11502
- continue;
11503
- }
11504
- if (data.pages.length <= REREAD_PAGES_MAX) rereadList(qc, key);
11505
- else qc.setQueryData(key, { ...data, newer: Math.max(data.newer ?? 0, 1) });
11506
- }
11507
- void qc.invalidateQueries({ queryKey: [...dataKeys.alias(portKey, alias), "row"] });
11508
- }
11509
- function onBump(qc, port, portKey, alias, entry, event) {
11510
- if (event.shape) {
11511
- void qc.invalidateQueries({ queryKey: dataKeys.alias(portKey, alias) });
11512
- return;
11513
- }
11514
- if (event.ids === null) entry.unknown = true;
11515
- else for (const id of event.ids) entry.pending.add(id);
11516
- if (entry.flush) return;
11517
- entry.flush = setTimeout(() => {
11518
- entry.flush = null;
11519
- const ids = [...entry.pending];
11520
- const unknown = entry.unknown;
11521
- entry.pending.clear();
11522
- entry.unknown = false;
11523
- if (unknown) rereadUnknown(qc, portKey, alias);
11524
- else if (ids.length > 0) void rereadIds(qc, port, portKey, alias, ids);
11525
- }, BUMP_BATCH_MS);
11526
- }
11527
- function acquireLive(qc, port, events, portKey, alias) {
11528
- const home = liveHome(qc);
11529
- const key = `${portKey}${alias}`;
11530
- let entry = home.get(key);
11531
- if (!entry) {
11532
- const made = { refs: 0, stop: () => {
11533
- }, timer: null, pending: /* @__PURE__ */ new Set(), unknown: false, flush: null };
11534
- if (events) {
11535
- made.stop = events.on(`rows:${alias}`, (event) => onBump(qc, port, portKey, alias, made, event));
11536
- } else if (!warnedNotLive) {
11537
- warnedNotLive = true;
11538
- console.warn("[@ai-matrx/records/data/react] No event stream was given to DataPortProvider, so this view is not live.");
11539
- }
11540
- home.set(key, made);
11541
- entry = made;
11542
- }
11543
- const mine = entry;
11544
- mine.refs += 1;
11545
- if (mine.timer) {
11546
- clearTimeout(mine.timer);
11547
- mine.timer = null;
11548
- }
11549
- return () => {
11550
- mine.refs -= 1;
11551
- if (mine.refs > 0) return;
11552
- mine.timer = setTimeout(() => {
11553
- if (mine.refs > 0) return;
11554
- if (mine.flush) clearTimeout(mine.flush);
11555
- mine.stop();
11556
- if (home.get(key) === mine) home.delete(key);
11557
- }, DATA_LIVE_GRACE_MS);
11558
- };
11559
- }
11560
- var FALLBACK_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-query-client");
11561
- function useRecordsQueryClient() {
11562
- const provided = (0, import_react7.useContext)(import_react_query.QueryClientContext);
11563
- if (provided) return provided;
11564
- const g = globalThis;
11565
- let held = g[FALLBACK_KEY];
11566
- if (!held) {
11567
- held = new import_react_query.QueryClient({ defaultOptions: { queries: { staleTime: 3e4, refetchOnWindowFocus: false } } });
11568
- g[FALLBACK_KEY] = held;
11569
- }
11570
- return held;
11571
- }
11572
- function useLive(alias, scope) {
11573
- const qc = useRecordsQueryClient();
11574
- const { port, portKey, events } = useDataPort(scope);
11575
- (0, import_react7.useEffect)(() => {
11576
- if (!alias) return;
11577
- return acquireLive(qc, port, events, portKey, alias);
11578
- }, [qc, port, events, portKey, alias]);
11579
- }
11580
- function useDataRows(alias, query = {}, scope, seed) {
11581
- const { port, portKey } = useDataPort(scope);
11582
- const qc = useRecordsQueryClient();
11583
- useLive(alias, scope);
11584
- const rowsKey = dataKeys.rows(portKey, alias, query);
11585
- const q = (0, import_react_query.useInfiniteQuery)(
11586
- {
11587
- queryKey: rowsKey,
11588
- queryFn: async ({ pageParam }) => unwrap(await port.list(alias, query, pageParam ?? void 0)),
11589
- initialPageParam: null,
11590
- getNextPageParam: (last) => last.cursor ?? void 0,
11591
- retry: retryable,
11592
- ...seed ? { initialData: { pages: [seed.data], pageParams: [null] }, initialDataUpdatedAt: seed.at } : {}
11593
- },
11594
- qc
11595
- );
11596
- const rows = (0, import_react7.useMemo)(() => {
11597
- const seen = /* @__PURE__ */ new Set();
11598
- const out = [];
11599
- for (const page2 of q.data?.pages ?? []) {
11600
- for (const row of page2.rows) {
11601
- if (seen.has(row._id)) continue;
11602
- seen.add(row._id);
11603
- out.push(row);
11604
- }
11605
- }
11606
- return out;
11607
- }, [q.data]);
11608
- const want = (0, import_react7.useRef)({ key: "", pages: 0 });
11609
- const keyHash = (0, import_react_query.hashKey)(rowsKey);
11610
- const loaded = q.data?.pages.length ?? 0;
11611
- const { isFetching, hasNextPage, isFetchNextPageError, fetchNextPage } = q;
11612
- (0, import_react7.useEffect)(() => {
11613
- const w = want.current;
11614
- if (w.key !== keyHash || isFetching || loaded >= w.pages) return;
11615
- if (!hasNextPage || isFetchNextPageError) {
11616
- want.current = { key: keyHash, pages: 0 };
11617
- owedPages(qc).delete(keyHash);
11618
- return;
11619
- }
11620
- void fetchNextPage({ cancelRefetch: false });
11621
- }, [qc, keyHash, isFetching, loaded, hasNextPage, isFetchNextPageError, fetchNextPage]);
11622
- return {
11623
- rows,
11624
- total: q.data?.pages[0]?.total ?? null,
11625
- loading: q.isPending,
11626
- loadingMore: q.isFetchingNextPage,
11627
- hasMore: Boolean(q.hasNextPage),
11628
- error: asRecordsError(q.error),
11629
- loadMore: () => {
11630
- if (!q.hasNextPage || q.isFetchingNextPage) return;
11631
- want.current = { key: keyHash, pages: loaded + 1 };
11632
- owedPages(qc).set(keyHash, { pages: loaded + 1, fetchNext: () => void q.fetchNextPage({ cancelRefetch: false }) });
11633
- if (!q.isFetching) void q.fetchNextPage({ cancelRefetch: false });
11634
- },
11635
- newer: q.data?.newer ?? 0,
11636
- refresh: () => void q.refetch()
11637
- };
11638
- }
11639
- var tempCounter = 0;
11640
- function drawPatch(before, patch) {
11641
- const drawn = { ...before, ...patch, _id: before._id, _version: before._version, _organization_id: before._organization_id };
11642
- if (patch._custom && typeof patch._custom === "object") {
11643
- drawn._custom = { ...before._custom ?? {}, ...patch._custom };
11644
- } else if (before._custom !== void 0) {
11645
- drawn._custom = before._custom;
11646
- }
11647
- return drawn;
11648
- }
11649
- function useDataMutations(alias, scope) {
11650
- const qc = useRecordsQueryClient();
11651
- const { port, portKey } = useDataPort(scope);
11652
- return (0, import_react7.useMemo)(() => {
11653
- const snapshotRows = () => qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
11654
- const putBack = (snap) => {
11655
- for (const [key, data] of snap) qc.setQueryData(key, data);
11656
- };
11657
- return {
11658
- async create(values) {
11659
- const tempId = `pending-${Date.now().toString(36)}-${tempCounter += 1}`;
11660
- const drawn = { ...values, _id: tempId, _version: 0, _organization_id: "", _pending: true };
11661
- await qc.cancelQueries({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
11662
- forEachRowsEntry(qc, portKey, alias, (_key, data) => {
11663
- if (data.pages.length === 0) return data;
11664
- const [first, ...rest] = data.pages;
11665
- return { ...data, pages: [{ ...first, rows: [drawn, ...first.rows], total: first.total === null ? null : first.total + 1 }, ...rest] };
11666
- });
11667
- const answer = await port.create(alias, values);
11668
- forEachRowsEntry(qc, portKey, alias, (_key, data) => {
11669
- const pages = data.pages.map((page2) => {
11670
- if (!page2.rows.some((r) => r._id === tempId)) return page2;
11671
- const rows = answer.ok ? page2.rows.map((r) => r._id === tempId ? answer.data : r) : page2.rows.filter((r) => r._id !== tempId);
11672
- return { ...page2, rows, total: answer.ok || page2.total === null ? page2.total : Math.max(0, page2.total - 1) };
11673
- });
11674
- return { ...data, pages };
11675
- });
11676
- if (answer.ok) qc.setQueryData(dataKeys.row(portKey, alias, answer.data._id), answer.data);
11677
- return answer;
11678
- },
11679
- async update(id, patch, options = {}) {
11680
- const before = findRow(qc, portKey, alias, id);
11681
- const baseVersion = options.baseVersion ?? before?._version;
11682
- if (typeof baseVersion !== "number") {
11683
- return { ok: false, error: { code: "stale_read", message: "Nothing was saved: this row's version is not known here.", hint: "Read the row first, then change it." } };
11684
- }
11685
- await qc.cancelQueries({ queryKey: dataKeys.alias(portKey, alias) });
11686
- const rowKey = dataKeys.row(portKey, alias, id);
11687
- const rowBefore = qc.getQueryData(rowKey);
11688
- if (before) patchRow(qc, portKey, alias, drawPatch(before, patch), { force: true });
11689
- const answer = await port.update(alias, id, patch, baseVersion);
11690
- if (answer.ok) {
11691
- patchRow(qc, portKey, alias, answer.data, { force: true, fromStore: true });
11692
- return answer;
11693
- }
11694
- if (before) patchRow(qc, portKey, alias, before, { force: true });
11695
- qc.setQueryData(rowKey, rowBefore);
11696
- void rereadIds(qc, port, portKey, alias, [id]);
11697
- return answer;
11698
- },
11699
- async archive(id) {
11700
- await qc.cancelQueries({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
11701
- const snap = snapshotRows();
11702
- const rowKey = dataKeys.row(portKey, alias, id);
11703
- const rowBefore = qc.getQueryData(rowKey);
11704
- dropRow(qc, portKey, alias, id);
11705
- const answer = await port.archive(alias, id);
11706
- if (!answer.ok) {
11707
- putBack(snap);
11708
- qc.setQueryData(rowKey, rowBefore);
11709
- void qc.invalidateQueries({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
11710
- }
11711
- return answer;
11712
- },
11713
- async restore(id) {
11714
- const answer = await port.restore(alias, id);
11715
- if (answer.ok) {
11716
- void qc.invalidateQueries({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
11717
- void qc.invalidateQueries({ queryKey: dataKeys.row(portKey, alias, id) });
11718
- }
11719
- return answer;
11720
- }
11721
- };
11722
- }, [qc, port, portKey, alias]);
11723
- }
11724
-
11725
11256
  // src/react/useStoreTable.ts
11257
+ var import_react8 = require("@ai-matrx/records/data/react");
11726
11258
  var PAGE3 = 500;
11727
11259
  function columnRefusal2(table, column) {
11728
11260
  return {
@@ -11751,15 +11283,15 @@ function toNamed(table, row) {
11751
11283
  function useStoreTable(table, options = {}) {
11752
11284
  const client = useRecordsClient();
11753
11285
  const alias = table.id;
11754
- const scope = (0, import_react8.useMemo)(
11286
+ const scope = (0, import_react7.useMemo)(
11755
11287
  () => {
11756
11288
  const port = createTableDataPort({ client, aliases: { [alias]: { kind: "table", tableId: table.id, organizationId: table.organizationId, label: table.name } } });
11757
- return { port, events: hostEvents(port), portKey: `store-table|${client.config.organizationId ?? "-"}|${client.config.actor.user_id ?? "-"}` };
11289
+ return { port, events: (0, import_react8.hostEvents)(port), portKey: `store-table|${client.config.organizationId ?? "-"}|${client.config.actor.user_id ?? "-"}` };
11758
11290
  },
11759
11291
  [client, alias, table.id, table.organizationId, table.name]
11760
11292
  );
11761
11293
  const asked = JSON.stringify(options);
11762
- const built = (0, import_react8.useMemo)(() => {
11294
+ const built = (0, import_react7.useMemo)(() => {
11763
11295
  const where = [];
11764
11296
  for (const [name, value] of Object.entries(options.where ?? {})) {
11765
11297
  const column = table.columns[name];
@@ -11784,12 +11316,12 @@ function useStoreTable(table, options = {}) {
11784
11316
  };
11785
11317
  }, [asked, table]);
11786
11318
  const limit = Math.min(options.limit ?? STORE_ROWS_CEILING, STORE_ROWS_CEILING);
11787
- const read = useDataRows(alias, built.ok ? built.data : { pageSize: 1 }, scope);
11788
- const write = useDataMutations(alias, scope);
11789
- (0, import_react8.useEffect)(() => {
11319
+ const read = (0, import_react8.useDataRows)(alias, built.ok ? built.data : { pageSize: 1 }, scope);
11320
+ const write = (0, import_react8.useDataMutations)(alias, scope);
11321
+ (0, import_react7.useEffect)(() => {
11790
11322
  if (built.ok && read.hasMore && !read.loadingMore && !read.loading && !read.error && read.rows.length < limit) read.loadMore();
11791
11323
  }, [built.ok, read.hasMore, read.loadingMore, read.loading, read.error, read.rows.length, limit, read]);
11792
- 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]);
11324
+ 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]);
11793
11325
  const total = built.ok ? read.total : null;
11794
11326
  return {
11795
11327
  rows: built.ok ? rows : [],