@ai-matrx/records 0.92.1 → 0.93.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 (103) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +4 -4
  3. package/dist/{client-Dzd8gtAo.d.ts → client-DsPuWFp0.d.ts} +8 -8
  4. package/dist/{client-Cn3odIIB.d.cts → client-EyD3rS0T.d.cts} +8 -8
  5. package/dist/core/index.cjs +101 -32
  6. package/dist/core/index.cjs.map +1 -1
  7. package/dist/core/index.d.cts +16 -15
  8. package/dist/core/index.d.ts +16 -15
  9. package/dist/core/index.js +101 -32
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/data/index.cjs +46 -24
  12. package/dist/data/index.cjs.map +1 -1
  13. package/dist/data/index.d.cts +11 -11
  14. package/dist/data/index.d.ts +11 -11
  15. package/dist/data/index.js +46 -24
  16. package/dist/data/index.js.map +1 -1
  17. package/dist/{declareTable-CrL6AZKB.d.cts → declareTable-Bkk_Ewib.d.cts} +4 -4
  18. package/dist/{declareTable-ZRW5EsTQ.d.ts → declareTable-kL5qZoTe.d.ts} +4 -4
  19. package/dist/entity/index.cjs +43 -29
  20. package/dist/entity/index.cjs.map +1 -1
  21. package/dist/entity/index.d.cts +7 -6
  22. package/dist/entity/index.d.ts +7 -6
  23. package/dist/entity/index.js +43 -29
  24. package/dist/entity/index.js.map +1 -1
  25. package/dist/entity/react.cjs +43 -29
  26. package/dist/entity/react.cjs.map +1 -1
  27. package/dist/entity/react.js +43 -29
  28. package/dist/entity/react.js.map +1 -1
  29. package/dist/{field-CCY1rG9l.d.cts → field-6rwt4ejZ.d.cts} +1 -1
  30. package/dist/{field-enufS5ry.d.ts → field-B-WaVZnS.d.ts} +1 -1
  31. package/dist/forms/index.d.cts +3 -3
  32. package/dist/forms/index.d.ts +3 -3
  33. package/dist/index.cjs +92 -25
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +13 -33
  36. package/dist/index.d.ts +13 -33
  37. package/dist/index.js +92 -25
  38. package/dist/index.js.map +1 -1
  39. package/dist/memory/index.d.cts +7 -7
  40. package/dist/memory/index.d.ts +7 -7
  41. package/dist/objectOrganization-BII_K3Gm.d.ts +45 -0
  42. package/dist/objectOrganization-DfjDQtDb.d.cts +45 -0
  43. package/dist/{port-C54ykAOv.d.ts → port--acgmxh5.d.ts} +5 -2
  44. package/dist/{port-Drioh9al.d.cts → port-Cx76dq-X.d.cts} +5 -2
  45. package/dist/{portal-DRdmZ-xv.d.cts → portal-9sRr6cpG.d.cts} +1 -1
  46. package/dist/{portal-or_f7BkT.d.ts → portal-BDAqsGkg.d.ts} +1 -1
  47. package/dist/{ports-s0D2jvqn.d.cts → ports-9BQ3zo2y.d.cts} +108 -2
  48. package/dist/{ports-BeOgjwYl.d.ts → ports-DYWE1ENo.d.ts} +108 -2
  49. package/dist/react/index.cjs +101 -32
  50. package/dist/react/index.cjs.map +1 -1
  51. package/dist/react/index.d.cts +1463 -1363
  52. package/dist/react/index.d.ts +1463 -1363
  53. package/dist/react/index.js +101 -32
  54. package/dist/react/index.js.map +1 -1
  55. package/dist/realtime/index.cjs +43 -13
  56. package/dist/realtime/index.cjs.map +1 -1
  57. package/dist/realtime/index.d.cts +9 -3
  58. package/dist/realtime/index.d.ts +9 -3
  59. package/dist/realtime/index.js +43 -13
  60. package/dist/realtime/index.js.map +1 -1
  61. package/dist/{record-BwCf9wKW.d.cts → record-DmmeuUrC.d.cts} +1 -1
  62. package/dist/{record-BwCf9wKW.d.ts → record-DmmeuUrC.d.ts} +1 -1
  63. package/dist/{relation-eLMgv_dV.d.ts → relation-Op1M67le.d.ts} +2 -2
  64. package/dist/{relation-8vAWCa67.d.cts → relation-qrb2NbHf.d.cts} +2 -2
  65. package/dist/{rule-wHI5B0Ka.d.cts → rule-CeHg1sy1.d.cts} +1 -1
  66. package/dist/{rule-D9yNiorf.d.ts → rule-tN2lxvJ1.d.ts} +1 -1
  67. package/dist/search/index.d.cts +1 -1
  68. package/dist/search/index.d.ts +1 -1
  69. package/dist/setup/index.cjs +117 -42
  70. package/dist/setup/index.cjs.map +1 -1
  71. package/dist/setup/index.d.cts +25 -11
  72. package/dist/setup/index.d.ts +25 -11
  73. package/dist/setup/index.js +117 -42
  74. package/dist/setup/index.js.map +1 -1
  75. package/dist/{subscription-CdoI-UaB.d.cts → subscription-Drbxn-9Z.d.cts} +3 -3
  76. package/dist/{subscription-BynsG1K6.d.ts → subscription-hdTaRrfK.d.ts} +3 -3
  77. package/dist/{table-kind-i3lZJa3f.d.ts → table-kind-BZkvzBgc.d.ts} +4 -29
  78. package/dist/{table-kind-DzctQ7dO.d.cts → table-kind-C-hZxDN7.d.cts} +4 -29
  79. package/dist/templates/index.d.cts +10 -10
  80. package/dist/templates/index.d.ts +10 -10
  81. package/dist/typed-table/index.cjs +46 -24
  82. package/dist/typed-table/index.cjs.map +1 -1
  83. package/dist/typed-table/index.d.cts +10 -10
  84. package/dist/typed-table/index.d.ts +10 -10
  85. package/dist/typed-table/index.js +46 -24
  86. package/dist/typed-table/index.js.map +1 -1
  87. package/dist/{types-BvL_oKFl.d.ts → types-BauAeFW8.d.ts} +2 -2
  88. package/dist/{types-DAFP6XFe.d.cts → types-CBmUdBT0.d.cts} +2 -2
  89. package/dist/{types-BKYEeFt4.d.cts → types-Dek9owBe.d.cts} +2 -2
  90. package/dist/{types-D8qdG3Lg.d.cts → types-DsgXrESm.d.cts} +2 -2
  91. package/dist/{types-cpKY7Pjb.d.ts → types-HVgWcZDY.d.ts} +2 -2
  92. package/dist/{types-DYzXhD7j.d.ts → types-hrw-Eff1.d.ts} +2 -2
  93. package/dist/use-cases/index.d.cts +5 -5
  94. package/dist/use-cases/index.d.ts +5 -5
  95. package/dist/{validate-DfNMxjmU.d.cts → validate-B_iUeyh2.d.cts} +1 -1
  96. package/dist/{validate-DbvAParj.d.ts → validate-w-HGGTf-.d.ts} +1 -1
  97. package/dist/views/index.cjs +438 -0
  98. package/dist/views/index.cjs.map +1 -0
  99. package/dist/views/index.d.cts +401 -0
  100. package/dist/views/index.d.ts +401 -0
  101. package/dist/views/index.js +415 -0
  102. package/dist/views/index.js.map +1 -0
  103. package/package.json +12 -2
@@ -410,35 +410,48 @@ function sourceArchivedOf(value) {
410
410
  var import_global_slot2 = require("@ai-matrx/kit/global-slot");
411
411
  var REMEMBER_MS = 3e4;
412
412
  var REMEMBER_MAX = 500;
413
- var ours = (0, import_global_slot2.globalSlot)("ai-matrx.records.op-ledger", () => /* @__PURE__ */ new Map());
414
- function trim(now) {
415
- for (const [id, at] of ours) {
416
- if (now - at <= REMEMBER_MS) break;
417
- ours.delete(id);
418
- }
419
- while (ours.size > REMEMBER_MAX) {
420
- const oldest = ours.keys().next();
421
- if (oldest.done === true) break;
422
- ours.delete(oldest.value);
413
+ function ledgerOver(ours) {
414
+ function trim(now) {
415
+ for (const [id, at] of ours) {
416
+ if (now - at <= REMEMBER_MS) break;
417
+ ours.delete(id);
418
+ }
419
+ while (ours.size > REMEMBER_MAX) {
420
+ const oldest = ours.keys().next();
421
+ if (oldest.done === true) break;
422
+ ours.delete(oldest.value);
423
+ }
423
424
  }
425
+ return {
426
+ mint() {
427
+ const id = crypto.randomUUID();
428
+ const now = Date.now();
429
+ ours.set(id, now);
430
+ trim(now);
431
+ return id;
432
+ },
433
+ isOwn(opId) {
434
+ if (!opId) return false;
435
+ const at = ours.get(opId);
436
+ if (at === void 0) return false;
437
+ if (Date.now() - at > REMEMBER_MS) {
438
+ ours.delete(opId);
439
+ return false;
440
+ }
441
+ return true;
442
+ },
443
+ clear() {
444
+ ours.clear();
445
+ },
446
+ get size() {
447
+ return ours.size;
448
+ }
449
+ };
424
450
  }
425
- function mintOpId() {
426
- const id = crypto.randomUUID();
427
- const now = Date.now();
428
- ours.set(id, now);
429
- trim(now);
430
- return id;
431
- }
432
- function isOwnOp(opId) {
433
- if (!opId) return false;
434
- const at = ours.get(opId);
435
- if (at === void 0) return false;
436
- if (Date.now() - at > REMEMBER_MS) {
437
- ours.delete(opId);
438
- return false;
439
- }
440
- return true;
451
+ function createOpLedger() {
452
+ return ledgerOver(/* @__PURE__ */ new Map());
441
453
  }
454
+ var defaultOpLedger = ledgerOver((0, import_global_slot2.globalSlot)("ai-matrx.records.op-ledger", () => /* @__PURE__ */ new Map()));
442
455
 
443
456
  // src/choice.ts
444
457
  var import_uuid2 = require("@ai-matrx/kit/uuid");
@@ -2497,6 +2510,8 @@ function createRecordsClient(given) {
2497
2510
  const config = { ...given, dataSource: asRecordsDataSource(given.dataSource) };
2498
2511
  const schema = config.schema ?? DEFAULT_SCHEMA;
2499
2512
  const org = config.organizationId;
2513
+ const ledger = config.opLedger ?? defaultOpLedger;
2514
+ const mintOp = () => ledger.mint();
2500
2515
  const scream = sink(config);
2501
2516
  const BUNDLE_TTL_MS = 1e4;
2502
2517
  const BUNDLE_OPENERS = /* @__PURE__ */ new Set(["applicable_fields", "views", "view_look_read", "table_decorations", "row_actions", "reverse_columns", "record_change_actions", "grid_layout", "io_imports"]);
@@ -2883,14 +2898,14 @@ function createRecordsClient(given) {
2883
2898
  async recordWrite({ table_id, data }) {
2884
2899
  const result = await callDoor(
2885
2900
  DOORS.recordWrite,
2886
- { p_organization_id: org, p_table_id: table_id, p_data: { ...data, _op_id: mintOpId() } },
2901
+ { p_organization_id: org, p_table_id: table_id, p_data: { ...data, _op_id: mintOp() } },
2887
2902
  "recordWrite"
2888
2903
  );
2889
2904
  if (result.ok && typeof result.data === "string") announceRecordChanged(result.data);
2890
2905
  return result;
2891
2906
  },
2892
2907
  async recordWriteMany({ table_id, rows, ids }) {
2893
- const opId = mintOpId();
2908
+ const opId = mintOp();
2894
2909
  return callDoor(
2895
2910
  DOORS.recordWriteMany,
2896
2911
  {
@@ -2903,7 +2918,7 @@ function createRecordsClient(given) {
2903
2918
  );
2904
2919
  },
2905
2920
  async recordChangeMany({ table_id, changes }) {
2906
- const opId = mintOpId();
2921
+ const opId = mintOp();
2907
2922
  const result = await callDoor(
2908
2923
  DOORS.recordChangeMany,
2909
2924
  {
@@ -2926,7 +2941,7 @@ function createRecordsClient(given) {
2926
2941
  return result;
2927
2942
  },
2928
2943
  async recordWriteGraph({ table_id, parent, children, edges }) {
2929
- const opId = mintOpId();
2944
+ const opId = mintOp();
2930
2945
  return callDoor(
2931
2946
  DOORS.recordWriteGraph,
2932
2947
  {
@@ -2950,7 +2965,7 @@ function createRecordsClient(given) {
2950
2965
  {
2951
2966
  p_organization_id: org,
2952
2967
  p_record_id: record_id,
2953
- p_patch: { ...patch, _op_id: mintOpId() },
2968
+ p_patch: { ...patch, _op_id: mintOp() },
2954
2969
  ...expectedVersion === void 0 ? {} : { p_expected_version: expectedVersion }
2955
2970
  },
2956
2971
  "recordUpdate"
@@ -2964,7 +2979,7 @@ function createRecordsClient(given) {
2964
2979
  {
2965
2980
  p_organization_id: org,
2966
2981
  p_record_id: record_id,
2967
- p_patch: { ...patch, _op_id: mintOpId() },
2982
+ p_patch: { ...patch, _op_id: mintOp() },
2968
2983
  p_add: add,
2969
2984
  ...expectedVersion === void 0 ? {} : { p_expected_version: expectedVersion }
2970
2985
  },
@@ -3989,7 +4004,7 @@ function createRecordsClient(given) {
3989
4004
  p_table_id: table_id,
3990
4005
  p_key: keys,
3991
4006
  // The op id rides the envelope, as `recordWrite` / `recordUpdate` send it; each door takes it off.
3992
- p_data: { ...data, _op_id: mintOpId() },
4007
+ p_data: { ...data, _op_id: mintOp() },
3993
4008
  ...expectedVersion === void 0 ? {} : { p_expected_version: expectedVersion }
3994
4009
  },
3995
4010
  "recordUpsert"
@@ -6374,6 +6389,7 @@ function toWireValues(values) {
6374
6389
  }
6375
6390
  function createEntityDataPort(options) {
6376
6391
  const client = options.client ?? createEntityClient({ dataSource: options.dataSource });
6392
+ const ledger = options.opLedger ?? defaultOpLedger;
6377
6393
  const activeOrganization = () => (options.activeOrganizationId ? options.activeOrganizationId() : options.organization) ?? null;
6378
6394
  const gets = /* @__PURE__ */ new Map();
6379
6395
  const aliases = options.aliases;
@@ -6564,27 +6580,27 @@ function createEntityDataPort(options) {
6564
6580
  "Pick an organization, then add the row again. Nothing was saved."
6565
6581
  );
6566
6582
  }
6567
- const answer = await client.insert({ token: binding.token, organizationId, rows: [toWireValues(values)], opId: mintOpId() });
6583
+ const answer = await client.insert({ token: binding.token, organizationId, rows: [toWireValues(values)], opId: ledger.mint() });
6568
6584
  return readBack(alias, answer, "The new row");
6569
6585
  },
6570
6586
  async update(alias, id, patch, baseVersion) {
6571
6587
  const binding = bindingOf(alias);
6572
6588
  if (!binding) return noSuchAlias(alias);
6573
6589
  if (!(0, import_uuid3.isUuidShape)(id)) return refusal("invalid_argument", `"${String(id)}" is not a row id.`);
6574
- const answer = await client.update({ token: binding.token, id, baseVersion, patch: toWireValues(patch), opId: mintOpId() });
6590
+ const answer = await client.update({ token: binding.token, id, baseVersion, patch: toWireValues(patch), opId: ledger.mint() });
6575
6591
  return readBack(alias, answer, "The change");
6576
6592
  },
6577
6593
  async archive(alias, id) {
6578
6594
  const binding = bindingOf(alias);
6579
6595
  if (!binding) return noSuchAlias(alias);
6580
6596
  if (!(0, import_uuid3.isUuidShape)(id)) return refusal("invalid_argument", `"${String(id)}" is not a row id.`);
6581
- return done(await client.archive({ token: binding.token, ids: [id], opId: mintOpId() }));
6597
+ return done(await client.archive({ token: binding.token, ids: [id], opId: ledger.mint() }));
6582
6598
  },
6583
6599
  async restore(alias, id) {
6584
6600
  const binding = bindingOf(alias);
6585
6601
  if (!binding) return noSuchAlias(alias);
6586
6602
  if (!(0, import_uuid3.isUuidShape)(id)) return refusal("invalid_argument", `"${String(id)}" is not a row id.`);
6587
- return done(await client.unarchive({ token: binding.token, ids: [id], opId: mintOpId() }));
6603
+ return done(await client.unarchive({ token: binding.token, ids: [id], opId: ledger.mint() }));
6588
6604
  },
6589
6605
  subscribe(event, listener) {
6590
6606
  const alias = event.startsWith("rows:") ? event.slice(5) : null;
@@ -6634,6 +6650,48 @@ function createEntityDataPort(options) {
6634
6650
  };
6635
6651
  }
6636
6652
 
6653
+ // src/objectOrganization.ts
6654
+ var WHERE_ID_OPENS_DOOR = "where_id_opens";
6655
+ function doorIsAbsent(error) {
6656
+ if (error.code === "PGRST202" || error.code === "42883") return true;
6657
+ return /could not find the function/i.test(error.message ?? "");
6658
+ }
6659
+ var DOOR_ABSENT_WHY = "custom.where_id_opens is missing from this database, so this page cannot tell which organization the record lives in and holds instead of guessing. Remedy: the chair applies migrations/campaign/openbyid_one_address_opens_any_id.sql and openbyid_the_resolver_can_be_reached.sql.";
6660
+ async function resolveObjectOrganization(dataSource, id) {
6661
+ let answered;
6662
+ try {
6663
+ answered = await dataSource.rpc(WHERE_ID_OPENS_DOOR, { p_id: id }, { schema: "custom" });
6664
+ } catch (thrown) {
6665
+ return { state: "unavailable", why: thrown instanceof Error ? thrown.message : "The record store did not answer." };
6666
+ }
6667
+ return readObjectOrganizationAnswer(answered, id);
6668
+ }
6669
+ function readObjectOrganizationAnswer(answered, id) {
6670
+ if (answered.error) {
6671
+ if (doorIsAbsent(answered.error)) {
6672
+ console.warn(`[@ai-matrx/records] ${DOOR_ABSENT_WHY}`);
6673
+ return { state: "unavailable", why: DOOR_ABSENT_WHY };
6674
+ }
6675
+ return { state: "unavailable", why: answered.error.message ?? "The record store refused to say where this is." };
6676
+ }
6677
+ const row = answered.data;
6678
+ if (row === null || row === void 0) return { state: "not-given" };
6679
+ if (typeof row !== "object" || typeof row.organization_id !== "string" || typeof row.kind !== "string") {
6680
+ return { state: "unavailable", why: "The record store answered something this page cannot read." };
6681
+ }
6682
+ return {
6683
+ state: "found",
6684
+ organizationId: row.organization_id,
6685
+ kind: row.kind,
6686
+ path: typeof row.path === "string" ? row.path : null,
6687
+ live: row.live !== false,
6688
+ resolvedId: typeof row.resolved_id === "string" ? row.resolved_id : id
6689
+ };
6690
+ }
6691
+ function whereIdOpensPort(dataSource) {
6692
+ return { organizationOf: (id) => resolveObjectOrganization(dataSource, id) };
6693
+ }
6694
+
6637
6695
  // src/realtime/index.ts
6638
6696
  var import_realtime3 = require("@ai-matrx/realtime");
6639
6697
  var storeTableChannel = (0, import_realtime3.defineChannelNamespace)({
@@ -6649,7 +6707,7 @@ function noticeKey(notice) {
6649
6707
  const ids = notice.record_ids == null ? "*" : [...notice.record_ids].sort().join(",");
6650
6708
  return `${notice.table_id ?? ""}:${notice.kind ?? ""}:${notice.op ?? ""}:${notice.op_id ?? ""}:${notice.at}:${ids}`;
6651
6709
  }
6652
- function storeTableChannelSpec(tableId, onNotice, onBackfill) {
6710
+ function storeTableChannelSpec(tableId, onNotice, onBackfill, ledger = defaultOpLedger) {
6653
6711
  return {
6654
6712
  topic: storeTableChannel.topic({ tableId }),
6655
6713
  // Database Broadcast is authorized by RLS on realtime.messages — that is what `private` means here;
@@ -6657,14 +6715,14 @@ function storeTableChannelSpec(tableId, onNotice, onBackfill) {
6657
6715
  // delivers nothing forever).
6658
6716
  private: true,
6659
6717
  // The sender is Postgres: no Matrx envelope. OUR OWN WRITE is known by the op id the write door carried.
6660
- wire: { mode: "raw", isOwnMessage: (payload) => isOwnOp(payload?.op_id) },
6718
+ wire: { mode: "raw", isOwnMessage: (payload) => ledger.isOwn(payload?.op_id) },
6661
6719
  eventKey: (_source, payload) => noticeKey(payload ?? {}),
6662
6720
  broadcast: [
6663
6721
  {
6664
6722
  event: STORE_NOTICE_EVENT,
6665
6723
  onMessage: (message) => {
6666
6724
  const notice = message.data ?? {};
6667
- if (isOwnOp(notice.op_id)) return;
6725
+ if (ledger.isOwn(notice.op_id)) return;
6668
6726
  onNotice(notice);
6669
6727
  }
6670
6728
  }
@@ -6684,7 +6742,8 @@ function createRecordsRealtimePort(options = {}) {
6684
6742
  },
6685
6743
  () => {
6686
6744
  for (const listener of channel.listeners) listener.backfill();
6687
- }
6745
+ },
6746
+ options.ledger
6688
6747
  );
6689
6748
  if (options.manager) {
6690
6749
  const handle = options.manager.open(spec);
@@ -6802,22 +6861,26 @@ async function createRecords(options) {
6802
6861
  } else if (options.live) {
6803
6862
  realtime = options.live;
6804
6863
  }
6805
- const realtimePort = realtime ? createRecordsRealtimePort({ manager: realtime }) : void 0;
6864
+ const opLedger = createOpLedger();
6865
+ const realtimePort = realtime ? createRecordsRealtimePort({ manager: realtime, ledger: opLedger }) : void 0;
6806
6866
  const actor = options.actor ?? { actor: "user", ...userId ? { user_id: userId } : {} };
6807
6867
  const records = createRecordsClient({
6808
6868
  dataSource,
6809
6869
  actor,
6810
6870
  organizationId,
6811
6871
  organizationIds,
6872
+ opLedger,
6812
6873
  ...realtimePort ? { realtime: realtimePort } : {},
6813
6874
  ...options.onError ? { onError: options.onError } : {}
6814
6875
  });
6815
6876
  const entities = createEntityDataPort({
6816
6877
  dataSource,
6817
6878
  aliases: options.entityAliases ?? {},
6879
+ opLedger,
6818
6880
  ...organizationId ? { organization: organizationId } : {}
6819
6881
  });
6820
6882
  const organizationIdChosen = organizationId;
6883
+ const organizationPort = options.organizationOf ?? whereIdOpensPort(dataSource);
6821
6884
  let warnedNotLive = false;
6822
6885
  return {
6823
6886
  authKind: options.auth.kind,
@@ -6846,6 +6909,18 @@ async function createRecords(options) {
6846
6909
  }) });
6847
6910
  },
6848
6911
  associations: options.associations,
6912
+ organizationOf: (id) => organizationPort.organizationOf(id),
6913
+ rowAgent: options.rowAgent ?? null,
6914
+ async runAgentOnRow(target) {
6915
+ if (!options.rowAgent) {
6916
+ return {
6917
+ ok: false,
6918
+ error: { code: "not_supported", message: "No agent runner is bound: pass createRecords({ rowAgent }) to run an agent on a row." }
6919
+ };
6920
+ }
6921
+ await options.rowAgent.run(target);
6922
+ return { ok: true, data: void 0 };
6923
+ },
6849
6924
  close() {
6850
6925
  if (ownsRealtime) realtime?.dispose();
6851
6926
  }