@ai-matrx/records 0.80.2 → 0.80.7

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 (71) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +19 -0
  3. package/dist/app-table/index.cjs +100 -23
  4. package/dist/app-table/index.cjs.map +1 -1
  5. package/dist/app-table/index.d.cts +7 -7
  6. package/dist/app-table/index.d.ts +7 -7
  7. package/dist/app-table/index.js +100 -23
  8. package/dist/app-table/index.js.map +1 -1
  9. package/dist/{client-DKKRZKNw.d.ts → client-D1LTezMZ.d.ts} +10 -5
  10. package/dist/{client-BfNJEpar.d.cts → client-DLIKeBWF.d.cts} +10 -5
  11. package/dist/core/index.cjs +115 -31
  12. package/dist/core/index.cjs.map +1 -1
  13. package/dist/core/index.d.cts +22 -12
  14. package/dist/core/index.d.ts +22 -12
  15. package/dist/core/index.js +115 -31
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/data/index.cjs +100 -23
  18. package/dist/data/index.cjs.map +1 -1
  19. package/dist/data/index.d.cts +7 -7
  20. package/dist/data/index.d.ts +7 -7
  21. package/dist/data/index.js +100 -23
  22. package/dist/data/index.js.map +1 -1
  23. package/dist/{declareTable-CzLMdOSy.d.cts → declareTable-02uao-5n.d.cts} +4 -4
  24. package/dist/{declareTable-Cg522Sk0.d.ts → declareTable-C5FlIS0z.d.ts} +4 -4
  25. package/dist/{field-DJAvDExi.d.ts → field-BIJiFPc0.d.ts} +1 -1
  26. package/dist/{field-DCXU6k9i.d.cts → field-snQG2jMq.d.cts} +1 -1
  27. package/dist/index.cjs +12 -0
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +7 -7
  30. package/dist/index.d.ts +7 -7
  31. package/dist/index.js +12 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/memory/index.cjs +5 -0
  34. package/dist/memory/index.cjs.map +1 -1
  35. package/dist/memory/index.d.cts +6 -6
  36. package/dist/memory/index.d.ts +6 -6
  37. package/dist/memory/index.js +5 -0
  38. package/dist/memory/index.js.map +1 -1
  39. package/dist/{ports-Kpc-RihV.d.ts → ports-Y5gLbCXe.d.ts} +1 -1
  40. package/dist/{ports-DaHUjVg7.d.cts → ports-y1QNfM80.d.cts} +1 -1
  41. package/dist/react/index.cjs +107 -27
  42. package/dist/react/index.cjs.map +1 -1
  43. package/dist/react/index.d.cts +31 -1
  44. package/dist/react/index.d.ts +31 -1
  45. package/dist/react/index.js +107 -27
  46. package/dist/react/index.js.map +1 -1
  47. package/dist/realtime/index.d.cts +2 -2
  48. package/dist/realtime/index.d.ts +2 -2
  49. package/dist/{record-DCaOJbhA.d.cts → record-1yDCn169.d.cts} +26 -1
  50. package/dist/{record-DCaOJbhA.d.ts → record-1yDCn169.d.ts} +26 -1
  51. package/dist/{subscription-C_hNjbaR.d.cts → subscription-B_WaT-kr.d.cts} +1 -1
  52. package/dist/{subscription-B9znK2dw.d.ts → subscription-CUok1vAm.d.ts} +1 -1
  53. package/dist/{table-kind-B9RBUmSb.d.ts → table-kind-COmkYYkc.d.ts} +3 -3
  54. package/dist/{table-kind-DXktQGzR.d.cts → table-kind-LodkBhCZ.d.cts} +3 -3
  55. package/dist/templates/index.cjs +70 -6
  56. package/dist/templates/index.cjs.map +1 -1
  57. package/dist/templates/index.d.cts +26 -10
  58. package/dist/templates/index.d.ts +26 -10
  59. package/dist/templates/index.js +70 -6
  60. package/dist/templates/index.js.map +1 -1
  61. package/dist/{types-DuyBN2im.d.cts → types-BJGTxu3Y.d.cts} +2 -2
  62. package/dist/{types-b-VGi15H.d.ts → types-C5-AaPa6.d.ts} +2 -2
  63. package/dist/{types-CHEFgCu1.d.ts → types-CU_Tn2Np.d.ts} +2 -2
  64. package/dist/{types-CD2HoaZt.d.cts → types-yBZLtxrZ.d.cts} +2 -2
  65. package/dist/use-cases/index.cjs.map +1 -1
  66. package/dist/use-cases/index.d.cts +5 -5
  67. package/dist/use-cases/index.d.ts +5 -5
  68. package/dist/use-cases/index.js.map +1 -1
  69. package/dist/{validate-CubFFxpu.d.cts → validate-CE6qpJIb.d.cts} +1 -1
  70. package/dist/{validate-BEfYwBpA.d.ts → validate-Rz9djP6H.d.ts} +1 -1
  71. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog — @ai-matrx/records
2
2
 
3
+ ## 0.80.7
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/records/v0.80.4..npm/records/v0.80.7 -- apps/shared/records`).
7
+ No source changes intended and no consumer action required.
8
+
9
+ ## 0.80.6
10
+ ### PAGE-BUNDLE-2: a record page opens in one call
11
+
12
+ RECORD PAGE BUNDLE: the records client answers a record page's own doors (`read_record`, `record_row_controls`, `my_levels` for the record, `record_history` head, `comment_thread`, `computed_provenance`, `record_headers`) from ONE `custom.record_page_bundle(p_organization_id, p_record_id)` call (live; SECURITY INVOKER; each part equals its door's own answer, verified part by part as admin@admin.com). Same contract as the table bundle: exact door + arguments, used once, 10 s; a refusing part is asked by its own door; a write that lands on the record drops what is still held. `primeRecordPageBundle({ organizationId, recordId, answer })` hands it an answer the server render asked as the same person.
13
+
14
+ **Consumer action:** none (additive). A host that seeds its record route calls `primeRecordPageBundle`.
15
+
16
+ ## 0.80.5
17
+
18
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
19
+ `git diff npm/records/v0.80.4..npm/records/v0.80.5 -- apps/shared/records`).
20
+ No source changes intended and no consumer action required.
21
+
22
+ ## 0.80.4
23
+
24
+ The door catalogue (`store.generated.ts`) regenerated so `form_knobs` is known (0.80.3 was refused by its own real-doors gate and never published).
25
+
26
+ ## 0.80.3
27
+
28
+ TYPEFORM-2: `client.formKnobs()` reads the organization's form knobs (`custom.form_knobs`: `show_owner_header`, `choice_auto_advance`) for the builder's preview.
29
+
30
+ **Consumer action:** none.
31
+
3
32
  ## 0.80.2
4
33
 
5
34
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/README.md CHANGED
@@ -278,6 +278,25 @@ const { write, update, remove, conflict } = useRecordMutation();
278
278
  `live` is never quietly false: when realtime is not bound, `liveOffReason` says
279
279
  why in a sentence a screen can show.
280
280
 
281
+ ## Drill-down — declared definitions
282
+
283
+ A server drill (`platform.drill_describe` / `platform.drill_ask`) answers a standard table from
284
+ the registry, or a **declared definition**: a `*.drill.ts` file (`declareDrillDefinition({...})`,
285
+ shape in `scripts/drill-definitions/ai_usage.drill.ts`) compiled to one function per definition,
286
+ `platform.drill_def__<key>()`. A Dimension may carry `level` (breakouts, show, attributes,
287
+ records); the UI side is `useDrill` in `@ai-matrx/records-ui` and the table in
288
+ `@ai-matrx/design-system` (its README § Drill-down).
289
+
290
+ | Command (in this package) | Does |
291
+ |---|---|
292
+ | `pnpm drill:sync --write --lane <LANE>` | writes a campaign file (+ inverse) for every declaration whose live body differs |
293
+ | `pnpm drill:sync --write --lane <LANE> --only <key,key>` | the same, for ONLY your definitions — never a peer's half-done one |
294
+ | `pnpm drill:sync --check` | the census: every declaration sound and equal to its live body (exit 1 otherwise) |
295
+ | `pnpm drill:sync --check --only <key,key>` | the census of your definitions only |
296
+ | `... --target clone` | reads the nightly copy instead of production |
297
+
298
+ `--only` naming a key no file declares fails, so a typo never passes as "nothing to do".
299
+
281
300
  ## The generated half
282
301
 
283
302
  `src/store.generated.ts` is written by `pnpm records:generate` from the live
@@ -434,6 +434,32 @@ function takePrimedTablePageBundle(organizationId, tableId, viewId) {
434
434
  return Date.now() - held.at < PRIMED_TTL_MS ? held.answer : null;
435
435
  }
436
436
 
437
+ // src/core/recordChanges.ts
438
+ var listeners = /* @__PURE__ */ new Set();
439
+ function announceRecordChanged(recordId) {
440
+ for (const listener of [...listeners]) {
441
+ try {
442
+ listener(recordId);
443
+ } catch (thrown) {
444
+ console.error("[@ai-matrx/records] a record-change listener threw", thrown);
445
+ }
446
+ }
447
+ }
448
+ function onRecordChanged(listener) {
449
+ listeners.add(listener);
450
+ return () => listeners.delete(listener);
451
+ }
452
+ var tableListeners = /* @__PURE__ */ new Set();
453
+ function announceTableStructureChanged(tableId) {
454
+ for (const listener of [...tableListeners]) {
455
+ try {
456
+ listener(tableId);
457
+ } catch (thrown) {
458
+ console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
459
+ }
460
+ }
461
+ }
462
+
437
463
  // src/archive.ts
438
464
  var DEFAULT_ARCHIVE_LANE = "org";
439
465
 
@@ -1279,21 +1305,25 @@ var STORE_DOORS = [
1279
1305
  { name: "form_declare", args: "p_organization_id uuid, p_table_id uuid, p_title text, p_questions jsonb, p_presentation jsonb DEFAULT '{}'::jsonb, p_submission_cap integer DEFAULT NULL::integer, p_quarantine_rule_id uuid DEFAULT NULL::uuid, p_notify_rule_id uuid DEFAULT NULL::uuid, p_form_id uuid DEFAULT NULL::uuid, p_slug text DEFAULT NULL::text", returns: "uuid", security: "definer" },
1280
1306
  { name: "form_draft_read", args: "p_form_id uuid, p_secret text", returns: "TABLE(answers jsonb, saved_at timestamp with time zone, expires_at timestamp with time zone, state text, message text)", security: "definer" },
1281
1307
  { name: "form_draft_save", args: "p_form_id uuid, p_answers jsonb, p_secret text DEFAULT NULL::text, p_bucket text DEFAULT NULL::text, p_origin text DEFAULT NULL::text", returns: "TABLE(draft_secret text, saved_at timestamp with time zone, expires_at timestamp with time zone, state text, message text)", security: "definer" },
1308
+ { name: "form_knobs", args: "p_organization_id uuid", returns: "jsonb", security: "definer" },
1282
1309
  { name: "form_look_options", args: "p_organization_id uuid, p_presentation jsonb DEFAULT '{}'::jsonb", returns: "jsonb", security: "definer" },
1283
1310
  { name: "form_notify", args: "p_organization_id uuid, p_form_id uuid, p_record_id uuid, p_submission_id uuid", returns: "uuid", security: "invoker" },
1284
1311
  { name: "form_preview_asks", args: "p_organization_id uuid, p_table_id uuid, p_questions jsonb, p_values jsonb", returns: "TABLE(field_key text, asked boolean, decided boolean, said text)", security: "definer" },
1285
1312
  { name: "form_preview_route", args: "p_organization_id uuid, p_table_id uuid, p_questions jsonb, p_endings jsonb, p_values jsonb", returns: "jsonb", security: "definer" },
1286
1313
  { name: "form_public", args: "p_form_id uuid", returns: "TABLE(form_id uuid, organization_id uuid, table_id uuid, title text, presentation jsonb, fields jsonb, honeypot_key text, state text, message text)", security: "definer" },
1287
1314
  { name: "form_public_asks", args: "p_form_id uuid, p_values jsonb, p_secret text DEFAULT NULL::text, p_origin text DEFAULT NULL::text", returns: "TABLE(field_key text, asked boolean, decided boolean, said text)", security: "definer" },
1315
+ { name: "form_public_options", args: "p_form_id uuid", returns: "jsonb", security: "definer" },
1288
1316
  { name: "form_public_route", args: "p_form_id uuid, p_values jsonb", returns: "jsonb", security: "definer" },
1289
1317
  { name: "form_redirect_domains", args: "p_organization_id uuid", returns: "text[]", security: "invoker" },
1290
1318
  { name: "form_redirect_refusal", args: "p_organization_id uuid, p_url text", returns: "text", security: "invoker" },
1319
+ { name: "form_respondent_copy", args: "p_organization_id uuid, p_form_id uuid, p_record_id uuid, p_submission_id uuid", returns: "jsonb", security: "definer" },
1291
1320
  { name: "form_restore", args: "p_organization_id uuid, p_form_id uuid", returns: "jsonb", security: "definer" },
1292
1321
  { name: "form_results", args: "p_organization_id uuid, p_form_id uuid", returns: "jsonb", security: "definer" },
1293
1322
  { name: "form_slug", args: "p_organization_id uuid, p_title text, p_form_id uuid DEFAULT NULL::uuid", returns: "text", security: "invoker" },
1294
1323
  { name: "form_submit", args: "p_form_id uuid, p_origin text, p_payload jsonb, p_bucket text, p_honeypot text DEFAULT NULL::text, p_client_key text DEFAULT NULL::text", returns: "TABLE(submission_id uuid, record_id uuid, state text, message text)", security: "definer" },
1295
1324
  { name: "form_theme_options", args: "", returns: "jsonb", security: "invoker" },
1296
1325
  { name: "form_visit", args: "p_form_id uuid, p_visit text, p_event text, p_field text DEFAULT NULL::text", returns: "text", security: "definer" },
1326
+ { name: "form_visit_admit", args: "p_form_id uuid, p_bucket text", returns: "boolean", security: "definer" },
1297
1327
  { name: "forms", args: "p_organization_id uuid, p_table_id uuid DEFAULT NULL::uuid", returns: "TABLE(form_id uuid, table_id uuid, title text, slug text, published_at timestamp with time zone, closed_at timestamp with time zone, submission_cap integer, responses bigint, in_table bigint, held bigint, rejected bigint, state text, quarantine_rule_id uuid, notify_rule_id uuid, presentation jsonb)", security: "definer" },
1298
1328
  { name: "forms_archived", args: "p_organization_id uuid, p_table_id uuid DEFAULT NULL::uuid, p_limit integer DEFAULT 100", returns: "TABLE(form_id uuid, table_id uuid, table_name text, kind text, title text, slug text, archived_at timestamp with time zone, archived_by uuid, table_archived boolean, can_restore boolean)", security: "definer" },
1299
1329
  { name: "formula_compile_sql", args: "p_organization_id uuid, p_expr jsonb, p_values_sql text", returns: "text", security: "invoker" },
@@ -1561,6 +1591,7 @@ var STORE_DOORS = [
1561
1591
  { name: "record_filter_sql", args: "p_organization_id uuid, p_table_id uuid, p_filter jsonb", returns: "text", security: "invoker" },
1562
1592
  { name: "record_headers", args: "p_organization_id uuid, p_ids uuid[]", returns: "TABLE(id uuid, table_id uuid, created_at timestamp with time zone, updated_at timestamp with time zone, version integer, deleted_at timestamp with time zone, mine boolean, created_by uuid)", security: "definer" },
1563
1593
  { name: "record_history", args: "p_organization_id uuid, p_record_id uuid, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(version integer, occurred_at timestamp with time zone, operation text, operation_label text, actor jsonb, changes jsonb, migration_id uuid, undoable boolean)", security: "definer" },
1594
+ { name: "record_page_bundle", args: "p_organization_id uuid, p_record_id uuid", returns: "jsonb", security: "invoker" },
1564
1595
  { name: "record_platform_keys", args: "", returns: "text[]", security: "invoker" },
1565
1596
  { name: "record_relation_edges", args: "p_organization_id uuid, p_id uuid, p_table_id uuid, p_data_class text, p_data jsonb, p_deleted_at timestamp with time zone", returns: "TABLE(target_id uuid, edge_role text, field_id uuid, ord integer)", security: "invoker" },
1566
1597
  { name: "record_reparent", args: "p_organization_id uuid, p_record_id uuid, p_parent_id uuid", returns: "void", security: "definer" },
@@ -2226,6 +2257,7 @@ var DOORS = {
2226
2257
  formPreviewRoute: "form_preview_route",
2227
2258
  /** TYPEFORM-DUP: views, starts, completions, drop-off and answers per question. */
2228
2259
  formResults: "form_results",
2260
+ formKnobs: "form_knobs",
2229
2261
  formLookOptions: "form_look_options",
2230
2262
  // PRODUCTS row 14 — "let clients book a 30-minute consult". A booking page IS an
2231
2263
  // `anon_form`, so it is opened and closed by `anonPublish` like any other; this is
@@ -2657,28 +2689,6 @@ var DRILL_DOORS = {
2657
2689
  rows: "drill_rows"
2658
2690
  };
2659
2691
 
2660
- // src/core/recordChanges.ts
2661
- var listeners = /* @__PURE__ */ new Set();
2662
- function announceRecordChanged(recordId) {
2663
- for (const listener of [...listeners]) {
2664
- try {
2665
- listener(recordId);
2666
- } catch (thrown) {
2667
- console.error("[@ai-matrx/records] a record-change listener threw", thrown);
2668
- }
2669
- }
2670
- }
2671
- var tableListeners = /* @__PURE__ */ new Set();
2672
- function announceTableStructureChanged(tableId) {
2673
- for (const listener of [...tableListeners]) {
2674
- try {
2675
- listener(tableId);
2676
- } catch (thrown) {
2677
- console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
2678
- }
2679
- }
2680
- }
2681
-
2682
2692
  // src/core/query.ts
2683
2693
  var DEFAULT_PAGE_SIZE = 50;
2684
2694
  function planQuery(query) {
@@ -2798,8 +2808,68 @@ function createRecordsClient(given) {
2798
2808
  } catch {
2799
2809
  }
2800
2810
  }
2811
+ const RECORD_OPENERS = /* @__PURE__ */ new Set(["read_record", "record_row_controls", "record_history", "comment_thread", "computed_provenance"]);
2812
+ const recordFlights = /* @__PURE__ */ new Map();
2813
+ const recordAsked = /* @__PURE__ */ new Map();
2814
+ let recordChangesHeard = false;
2815
+ function bundleRecordOf(door, args) {
2816
+ if (RECORD_OPENERS.has(door)) return typeof args["p_record_id"] === "string" ? args["p_record_id"] : null;
2817
+ const ids = args["p_ids"];
2818
+ const one = Array.isArray(ids) && ids.length === 1 && typeof ids[0] === "string" ? ids[0] : null;
2819
+ if (door === "record_headers") return one;
2820
+ if (door === "my_levels" && args["p_type"] === "record") return one;
2821
+ return null;
2822
+ }
2823
+ async function fillRecordBundle(recordId) {
2824
+ if (!recordChangesHeard) {
2825
+ recordChangesHeard = true;
2826
+ onRecordChanged((changed) => {
2827
+ recordAsked.delete(changed);
2828
+ for (const key of [...bundleParts.keys()]) if (key.includes(changed)) bundleParts.delete(key);
2829
+ });
2830
+ }
2831
+ try {
2832
+ const usable = (r) => r !== null && !r.error && r.data !== null && typeof r.data === "object" && Array.isArray(r.data.parts);
2833
+ const primedAnswer = takePrimedTablePageBundle(org, `record:${recordId}`, null);
2834
+ let response = primedAnswer ? await primedAnswer : null;
2835
+ if (!usable(response)) {
2836
+ response = await config.dataSource.rpc("record_page_bundle", { p_organization_id: org, p_record_id: recordId }, { schema });
2837
+ }
2838
+ if (!usable(response)) return;
2839
+ const now = Date.now();
2840
+ for (const part of response.data.parts) {
2841
+ if (part.error !== void 0 || part.data === void 0) continue;
2842
+ bundleParts.set(bundleKey(part.door, part.args), { data: part.data, at: now });
2843
+ }
2844
+ } catch {
2845
+ }
2846
+ }
2847
+ async function fromRecordBundle(door, args) {
2848
+ if (!doorReady(config, "record_page_bundle")) return void 0;
2849
+ const recordId = bundleRecordOf(door, args);
2850
+ if (!recordId) return void 0;
2851
+ const opener = RECORD_OPENERS.has(door);
2852
+ if (!opener && !recordFlights.has(recordId) && !recordAsked.has(recordId)) return void 0;
2853
+ const asked = recordAsked.get(recordId);
2854
+ const fresh = asked !== void 0 && Date.now() - asked < BUNDLE_TTL_MS;
2855
+ if (!fresh && opener) {
2856
+ recordAsked.set(recordId, Date.now());
2857
+ const flight2 = fillRecordBundle(recordId).finally(() => recordFlights.delete(recordId));
2858
+ recordFlights.set(recordId, flight2);
2859
+ }
2860
+ const flight = recordFlights.get(recordId);
2861
+ if (flight) await flight;
2862
+ const key = bundleKey(door, args);
2863
+ const held = bundleParts.get(key);
2864
+ if (!held) return opener ? null : void 0;
2865
+ bundleParts.delete(key);
2866
+ return Date.now() - held.at < BUNDLE_TTL_MS ? { data: held.data } : null;
2867
+ }
2801
2868
  async function fromBundle(door, args) {
2802
- if (!config.dataSource.opensInOneCall || !doorReady(config, "table_page_bundle")) return null;
2869
+ if (!config.dataSource.opensInOneCall) return null;
2870
+ const fromRecord = await fromRecordBundle(door, args);
2871
+ if (fromRecord !== void 0) return fromRecord;
2872
+ if (!doorReady(config, "table_page_bundle")) return null;
2803
2873
  const tableId = bundleTableOf(door, args);
2804
2874
  if (tableId) {
2805
2875
  const asked = bundleAsked.get(tableId);
@@ -4244,6 +4314,13 @@ function createRecordsClient(given) {
4244
4314
  "formResults"
4245
4315
  );
4246
4316
  },
4317
+ async formKnobs() {
4318
+ return callDoor(
4319
+ DOORS.formKnobs,
4320
+ { p_organization_id: org },
4321
+ "formKnobs"
4322
+ );
4323
+ },
4247
4324
  async formLookOptions(args) {
4248
4325
  return callDoor(
4249
4326
  DOORS.formLookOptions,