@ai-matrx/records 0.73.3 → 0.73.4

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog — @ai-matrx/records
2
2
 
3
+ ## 0.73.4
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/records/v0.73.3..npm/records/v0.73.4 -- apps/shared/records`).
7
+ No source changes intended and no consumer action required.
8
+
3
9
  ## 0.73.3
4
10
 
5
11
  Automatic changed-only republish (docs/metadata drift since the last tag — see
@@ -22,13 +22,127 @@ var memory_exports = {};
22
22
  __export(memory_exports, {
23
23
  MEMORY_KERNEL: () => MEMORY_KERNEL,
24
24
  PREVIEW_REFUSAL: () => PREVIEW_REFUSAL,
25
+ entityStore: () => entityStore,
25
26
  memoryDataSource: () => memoryDataSource,
27
+ memoryEntityDescribe: () => memoryEntityDescribe,
28
+ memoryEntityRows: () => memoryEntityRows,
29
+ memoryEntityWrite: () => memoryEntityWrite,
26
30
  stableId: () => stableId,
27
31
  templatePreview: () => templatePreview,
28
- templateWorld: () => templateWorld
32
+ templateWorld: () => templateWorld,
33
+ withEntities: () => withEntities
29
34
  });
30
35
  module.exports = __toCommonJS(memory_exports);
31
36
 
37
+ // src/memory/entity.ts
38
+ var ok = (data) => ({ data, error: null });
39
+ var refuse = (message, code = "22023", hint = null) => ({
40
+ data: null,
41
+ error: { code, message, details: null, hint }
42
+ });
43
+ function memoryEntityDescribe(e) {
44
+ const dimensions = e.columns.filter((c) => c.type === "choice" && Array.isArray(c.choices)).map((c) => ({
45
+ key: c.api_name,
46
+ label: c.name,
47
+ from: c.api_name,
48
+ kind: "choice",
49
+ cardinality: "low",
50
+ choices: (c.choices ?? []).map((w) => ({ value: w, label: w }))
51
+ }));
52
+ const measures = [
53
+ { key: "count", label: `Number of ${e.label.toLowerCase()}`, op: "count", unit: "count", additive: true },
54
+ ...e.columns.filter((c) => c.type === "number").map((c) => ({
55
+ key: `sum_${c.api_name}`,
56
+ label: `Total ${c.name.toLowerCase()}`,
57
+ op: "sum",
58
+ of: c.api_name,
59
+ additive: true
60
+ }))
61
+ ];
62
+ return {
63
+ key: e.token,
64
+ label: e.label,
65
+ grain: `one row per ${e.label.toLowerCase()}`,
66
+ lanes: ["organization", "platform"],
67
+ dimensions,
68
+ measures,
69
+ paths: [],
70
+ inferred: [],
71
+ detail: { columns: e.columns.map((c) => c.api_name) },
72
+ source: { kind: "entity", token: e.token },
73
+ mode: "invoker",
74
+ api: { label: e.label, reach: "read_write", columns: e.columns },
75
+ calendar: { time_zone: "UTC", week_start: "monday" }
76
+ };
77
+ }
78
+ function matches(row, where) {
79
+ for (const [k, want] of Object.entries(where ?? {})) {
80
+ const have = row[k] ?? null;
81
+ if (Array.isArray(want)) {
82
+ if (!want.includes(have)) return false;
83
+ } else if (want === null) {
84
+ if (have !== null) return false;
85
+ } else if (typeof want === "object") continue;
86
+ else if (String(have).toLowerCase() !== String(want).toLowerCase()) return false;
87
+ }
88
+ return true;
89
+ }
90
+ function memoryEntityRows(e, question2) {
91
+ const limit = Number(question2["limit"] ?? 50);
92
+ const offset = Number(question2["offset"] ?? 0);
93
+ const rows = e.rows.filter((r) => matches(r, question2["where"]));
94
+ const page = rows.slice(offset, offset + limit);
95
+ return {
96
+ rows: page,
97
+ total: rows.length,
98
+ limit,
99
+ offset,
100
+ as_of: null,
101
+ columns: e.columns.map((c) => c.api_name),
102
+ ...offset + page.length < rows.length ? { next_offset: offset + page.length } : {}
103
+ };
104
+ }
105
+ function memoryEntityWrite(e, recordId, columns) {
106
+ const row = e.rows.find((r) => r["id"] === recordId);
107
+ if (!row) return refuse(`There is no ${e.label} you can open with that id.`, "02000");
108
+ const next = {};
109
+ for (const [k, v] of Object.entries(columns ?? {})) {
110
+ const c = e.columns.find((x) => x.api_name === k);
111
+ if (!c) return refuse(`This table has no column called "${k}".`);
112
+ if (c.lookup && !c.lookup.replaces) return refuse(`"${c.name}" is shown from another table, so it is changed there. Nothing was written.`);
113
+ if (!c.writable) return refuse(`"${c.name}" is not changed through this door.`, "42501");
114
+ if (c.type === "choice" && v !== null && v !== "") {
115
+ const word = (c.choices ?? []).find((w) => w === v) ?? (c.choices ?? []).find((w) => w.toLowerCase() === String(v).toLowerCase());
116
+ if (!word) return refuse(`"${String(v)}" is not one of the choices of "${c.name}".`, "22023", "The columns call lists its choices.");
117
+ next[k] = word;
118
+ } else next[k] = v === "" ? null : v;
119
+ }
120
+ const changed = Object.entries(next).some(([k, v]) => row[k] !== v);
121
+ Object.assign(row, next);
122
+ return ok({ id: recordId, organization_id: row["organization_id"] ?? null, changed, row });
123
+ }
124
+ function memoryEntityDoors(entities) {
125
+ const of = (args) => {
126
+ const src = args["p_source"];
127
+ return src && src["kind"] === "entity" ? entities.get(String(src["token"])) : void 0;
128
+ };
129
+ return {
130
+ drill_describe: (args) => {
131
+ const e = of(args);
132
+ return e ? ok(memoryEntityDescribe(e)) : null;
133
+ },
134
+ drill_rows: (args) => {
135
+ const e = of(args);
136
+ return e ? ok(memoryEntityRows(e, args["p_question"] ?? {})) : null;
137
+ },
138
+ entity_row_write: (args) => {
139
+ const e = entities.get(String(args["p_token"] ?? ""));
140
+ if (!e) return null;
141
+ return memoryEntityWrite(e, String(args["p_record_id"] ?? ""), args["p_columns"] ?? {});
142
+ }
143
+ };
144
+ }
145
+
32
146
  // src/templates/payloads.ts
33
147
  var ACTOR = "user";
34
148
  var COMPUTED = /* @__PURE__ */ new Set(["lookup", "rollup", "formula"]);
@@ -2257,10 +2371,10 @@ var PREVIEW_REFUSAL = {
2257
2371
  hint: null
2258
2372
  };
2259
2373
  var WRITE_DOOR = /(^|_)(write|writes|declare|delete|update|upsert|archive|restore|set|move|save|submit|insert|merge|retype|undo|retire|assign|claim|clear|snooze|unsnooze|publish|invite|revoke|issue|pin|duplicate|designate|bind|unbind|change|start|complete|decide|request|hold|release|expire|forget|begin|finish|rows|take|nudge|import|mute|sign|render|instantiate|ensure)(_|$)/;
2260
- function ok(data) {
2374
+ function ok2(data) {
2261
2375
  return { data, error: null };
2262
2376
  }
2263
- function refuse(message, code = "PGRST202") {
2377
+ function refuse2(message, code = "PGRST202") {
2264
2378
  return { data: null, error: { code, message, details: null, hint: null } };
2265
2379
  }
2266
2380
  function stamp(world) {
@@ -2584,55 +2698,55 @@ function memoryDataSource(world) {
2584
2698
  return typeof v === "string" ? v : v === void 0 || v === null ? null : String(v);
2585
2699
  };
2586
2700
  const doors = {
2587
- table_kernel_id: () => ok(MEMORY_KERNEL.table),
2588
- field_kernel_id: () => ok(MEMORY_KERNEL.field),
2589
- person_kernel_id: () => ok(MEMORY_KERNEL.person),
2590
- file_kernel_id: () => ok(MEMORY_KERNEL.file),
2591
- rule_kernel_id: () => ok(MEMORY_KERNEL.rule),
2592
- store_is_open: () => ok(true),
2701
+ table_kernel_id: () => ok2(MEMORY_KERNEL.table),
2702
+ field_kernel_id: () => ok2(MEMORY_KERNEL.field),
2703
+ person_kernel_id: () => ok2(MEMORY_KERNEL.person),
2704
+ file_kernel_id: () => ok2(MEMORY_KERNEL.file),
2705
+ rule_kernel_id: () => ok2(MEMORY_KERNEL.rule),
2706
+ store_is_open: () => ok2(true),
2593
2707
  read_records: (args) => {
2594
2708
  const limit = Number(args["p_limit"] ?? 50);
2595
2709
  const offset = Number(args["p_offset"] ?? 0);
2596
- if (args["p_table_id"] === MEMORY_KERNEL.table) return ok(world.tables.slice(offset, offset + limit).map(tableRow));
2710
+ if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.slice(offset, offset + limit).map(tableRow));
2597
2711
  const t = tableOf(args);
2598
- if (!t) return ok([]);
2599
- return ok(t.order.slice(offset, offset + limit).map((id) => row(t, id)));
2712
+ if (!t) return ok2([]);
2713
+ return ok2(t.order.slice(offset, offset + limit).map((id) => row(t, id)));
2600
2714
  },
2601
2715
  read_records_by_ids: (args) => {
2602
2716
  const ids = args["p_record_ids"] ?? [];
2603
- if (args["p_table_id"] === MEMORY_KERNEL.table) return ok(world.tables.filter((t2) => ids.includes(t2.id)).map(tableRow));
2717
+ if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.filter((t2) => ids.includes(t2.id)).map(tableRow));
2604
2718
  const t = tableOf(args);
2605
- if (!t) return ok([]);
2606
- return ok(ids.filter((id) => t.rows.has(id)).map((id) => row(t, id)));
2719
+ if (!t) return ok2([]);
2720
+ return ok2(ids.filter((id) => t.rows.has(id)).map((id) => row(t, id)));
2607
2721
  },
2608
2722
  read_records_matching: (args) => {
2609
2723
  const t = tableOf(args);
2610
- if (!t) return ok([]);
2724
+ if (!t) return ok2([]);
2611
2725
  const limit = Number(args["p_limit"] ?? 50);
2612
2726
  const offset = Number(args["p_offset"] ?? 0);
2613
- return ok(matching(world, t, args).slice(offset, offset + limit).map((id) => row(t, id)));
2727
+ return ok2(matching(world, t, args).slice(offset, offset + limit).map((id) => row(t, id)));
2614
2728
  },
2615
2729
  read_records_page: (args) => {
2616
2730
  const t = tableOf(args);
2617
2731
  const limit = Number(args["p_limit"] ?? 50);
2618
2732
  const offset = Number(args["p_offset"] ?? 0);
2619
- if (!t) return ok({ rows: [], total: 0, limit, offset, sort_ignored: [] });
2733
+ if (!t) return ok2({ rows: [], total: 0, limit, offset, sort_ignored: [] });
2620
2734
  const ids = matching(world, t, args);
2621
- return ok({ rows: ids.slice(offset, offset + limit).map((id) => row(t, id)), total: ids.length, limit, offset, sort_ignored: [] });
2735
+ return ok2({ rows: ids.slice(offset, offset + limit).map((id) => row(t, id)), total: ids.length, limit, offset, sort_ignored: [] });
2622
2736
  },
2623
2737
  read_record: (args) => {
2624
2738
  const id = String(args["p_record_id"] ?? "");
2625
2739
  const t = world.recordTable.get(id);
2626
- if (!t) return refuse("That record is not in this template.", "P0002");
2627
- return ok(readDocument(world, t, id));
2740
+ if (!t) return refuse2("That record is not in this template.", "P0002");
2741
+ return ok2(readDocument(world, t, id));
2628
2742
  },
2629
- record_headers: (args) => ok(
2743
+ record_headers: (args) => ok2(
2630
2744
  (args["p_ids"] ?? []).filter((id) => world.recordTable.has(id)).map((id) => ({ id, mine: false, version: 1, table_id: world.recordTable.get(id).id, deleted_at: null, ...stamp(world) }))
2631
2745
  ),
2632
2746
  applicable_fields: (args) => {
2633
2747
  const t = tableOf(args);
2634
- if (!t) return ok([]);
2635
- return ok(
2748
+ if (!t) return ok2([]);
2749
+ return ok2(
2636
2750
  t.fields.map((f) => ({
2637
2751
  id: f.id,
2638
2752
  data: f.data,
@@ -2651,9 +2765,9 @@ function memoryDataSource(world) {
2651
2765
  },
2652
2766
  field_options: (args) => {
2653
2767
  const hit = fieldById(args["p_field_id"]);
2654
- if (!hit) return ok([]);
2768
+ if (!hit) return ok2([]);
2655
2769
  const opts = hit.t.options.get(String(hit.f.data["key"])) ?? [];
2656
- return ok(
2770
+ return ok2(
2657
2771
  opts.map((o, i) => ({
2658
2772
  id: o.id,
2659
2773
  organization_id: world.organization_id,
@@ -2669,46 +2783,46 @@ function memoryDataSource(world) {
2669
2783
  }))
2670
2784
  );
2671
2785
  },
2672
- my_levels: (args) => ok((args["p_ids"] ?? []).map((id) => ({ id, level: VIEWER }))),
2673
- views: (args) => ok(
2786
+ my_levels: (args) => ok2((args["p_ids"] ?? []).map((id) => ({ id, level: VIEWER }))),
2787
+ views: (args) => ok2(
2674
2788
  world.views.filter((v) => !args["p_table_id"] || v.table_id === args["p_table_id"]).map((v) => ({ view_id: v.view_id, name: v.name, table_id: v.table_id, filters: v.filters, definition: v.definition, created_at: `${world.today}T09:00:00Z` }))
2675
2789
  ),
2676
2790
  view_look_read: (args) => {
2677
2791
  const out = {};
2678
2792
  for (const [key, look] of looks) if (key.startsWith(`${String(args["p_table_id"])}:`)) out[key.split(":")[1]] = look;
2679
- return ok(out);
2793
+ return ok2(out);
2680
2794
  },
2681
2795
  view_look_set: (args) => {
2682
2796
  const key = `${String(args["p_table_id"])}:${String(args["p_view_id"])}`;
2683
2797
  const look = args["p_look"] ?? null;
2684
2798
  if (look) looks.set(key, { look, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
2685
2799
  else looks.delete(key);
2686
- return ok(look);
2800
+ return ok2(look);
2687
2801
  },
2688
- grid_layout: (args) => ok({
2802
+ grid_layout: (args) => ok2({
2689
2803
  layout: { mode: "auto", wrap: false, row_height: "normal", fit_max_columns: 8, freeze_first_column: false },
2690
2804
  source: { mode: "platform", wrap: "platform", row_height: "platform", fit_max_columns: "platform", freeze_first_column: "platform" },
2691
2805
  refused: [],
2692
2806
  view_id: args["p_view_id"] ?? null
2693
2807
  }),
2694
- table_decorations: () => ok({ rows: {}, cells: {}, rules: [], stale: [], colors: ["slate", "green", "amber", "red", "blue", "violet", "teal"], columns: {}, version: 1, rule_ops: [] }),
2695
- row_actions: () => ok({ stale: [], actions: [] }),
2696
- table_stage_field: (args) => ok(world.stageField.get(String(args["p_table_id"])) ?? null),
2808
+ table_decorations: () => ok2({ rows: {}, cells: {}, rules: [], stale: [], colors: ["slate", "green", "amber", "red", "blue", "violet", "teal"], columns: {}, version: 1, rule_ops: [] }),
2809
+ row_actions: () => ok2({ stale: [], actions: [] }),
2810
+ table_stage_field: (args) => ok2(world.stageField.get(String(args["p_table_id"])) ?? null),
2697
2811
  pipeline_read: (args) => {
2698
2812
  const t = tableOf(args);
2699
2813
  const stage = t ? world.stageField.get(t.id) : void 0;
2700
2814
  const field = stage ? t.fields.find((f) => f.data["key"] === stage) : void 0;
2701
- if (!t || !stage || !field) return ok({ is_pipeline: false, why: "This table has no stage column." });
2815
+ if (!t || !stage || !field) return ok2({ is_pipeline: false, why: "This table has no stage column." });
2702
2816
  const stages = (t.options.get(stage) ?? []).map((o) => ({ key: o.key, label: o.label, retired: false }));
2703
- return ok({ is_pipeline: true, table_id: t.id, stage_field: stage, field_id: field.id, stage_label: field.data["label"], stages, rules: [] });
2817
+ return ok2({ is_pipeline: true, table_id: t.id, stage_field: stage, field_id: field.id, stage_label: field.data["label"], stages, rules: [] });
2704
2818
  },
2705
2819
  pipeline_board: (args) => {
2706
2820
  const t = tableOf(args);
2707
2821
  const stage = t ? world.stageField.get(t.id) : void 0;
2708
- if (!t || !stage) return ok([]);
2822
+ if (!t || !stage) return ok2([]);
2709
2823
  const measure = typeof args["p_measure"] === "string" ? args["p_measure"] : null;
2710
2824
  const ids = t.order.filter((id) => admits(world, t, id, args["p_filter"]));
2711
- return ok(
2825
+ return ok2(
2712
2826
  (t.options.get(stage) ?? []).map((o, i) => {
2713
2827
  const inIt = ids.filter((id) => t.rows.get(id)[stage] === o.key);
2714
2828
  const total = measure ? inIt.reduce((sum, id) => sum + (typeof t.rows.get(id)[measure] === "number" ? t.rows.get(id)[measure] : 0), 0) : null;
@@ -2716,7 +2830,7 @@ function memoryDataSource(world) {
2716
2830
  })
2717
2831
  );
2718
2832
  },
2719
- relation_words_many: (args) => ok((args["p_record_ids"] ?? []).map((id) => ({ record_id: id, words: nameOf(id), archived: false }))),
2833
+ relation_words_many: (args) => ok2((args["p_record_ids"] ?? []).map((id) => ({ record_id: id, words: nameOf(id), archived: false }))),
2720
2834
  reverse_columns: (args) => {
2721
2835
  const target = String(args["p_table_id"] ?? "");
2722
2836
  const out = [];
@@ -2736,11 +2850,11 @@ function memoryDataSource(world) {
2736
2850
  });
2737
2851
  }
2738
2852
  }
2739
- return ok(out);
2853
+ return ok2(out);
2740
2854
  },
2741
2855
  reverse_links_many: (args) => {
2742
2856
  const hit = fieldById(args["p_field_id"]);
2743
- return ok(
2857
+ return ok2(
2744
2858
  (args["p_record_ids"] ?? []).map((rid) => {
2745
2859
  if (!hit) return { record_id: rid, total: 0, links: [] };
2746
2860
  const key = String(hit.f.data["key"]);
@@ -2754,28 +2868,28 @@ function memoryDataSource(world) {
2754
2868
  },
2755
2869
  // A template's own record has no history, comments, checklists or worked-out provenance yet:
2756
2870
  // these are the answers an installed template gives on its first day.
2757
- record_history: () => ok([]),
2758
- field_history: () => ok([]),
2759
- computed_provenance: () => ok([]),
2760
- comment_thread: (args) => ok({ record_id: args["p_record_id"] ?? null, comments: [], may_comment: false, may_resolve: false }),
2761
- checklist_runs: () => ok([]),
2762
- checklist_templates: () => ok([]),
2763
- doc_templates: () => ok([]),
2764
- doc_renders: () => ok([]),
2765
- doc_signatures: () => ok([]),
2766
- record_row_controls: () => ok({
2871
+ record_history: () => ok2([]),
2872
+ field_history: () => ok2([]),
2873
+ computed_provenance: () => ok2([]),
2874
+ comment_thread: (args) => ok2({ record_id: args["p_record_id"] ?? null, comments: [], may_comment: false, may_resolve: false }),
2875
+ checklist_runs: () => ok2([]),
2876
+ checklist_templates: () => ok2([]),
2877
+ doc_templates: () => ok2([]),
2878
+ doc_renders: () => ok2([]),
2879
+ doc_signatures: () => ok2([]),
2880
+ record_row_controls: () => ok2({
2767
2881
  shown_to: { value: null, effective: "everyone", type_default: null, table_default: null, allowed: ["everyone"], is_child: false, can_change: false },
2768
2882
  published_to_web: { available: false, value: false, table_default: null, can_change: false },
2769
2883
  indexed: { available: false, value: null, table_default: null, effective: false, can_change: false }
2770
2884
  }),
2771
- enrich_cells: () => ok([]),
2772
- enrichments: () => ok([]),
2773
- pipeline_pending: () => ok([]),
2774
- record_stage_pending: () => ok([]),
2775
- io_imports: () => ok([]),
2776
- relation_words: (args) => ok(nameOf(String(args["p_value"] ?? ""))),
2885
+ enrich_cells: () => ok2([]),
2886
+ enrichments: () => ok2([]),
2887
+ pipeline_pending: () => ok2([]),
2888
+ record_stage_pending: () => ok2([]),
2889
+ io_imports: () => ok2([]),
2890
+ relation_words: (args) => ok2(nameOf(String(args["p_value"] ?? ""))),
2777
2891
  // The read doors a form, a booking page and a dashboard are drawn from (lane CHAIR-GALLERY-3).
2778
- forms: (args) => ok(
2892
+ forms: (args) => ok2(
2779
2893
  world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
2780
2894
  form_id: f.form_id,
2781
2895
  table_id: f.table_id,
@@ -2798,7 +2912,7 @@ function memoryDataSource(world) {
2798
2912
  form_preview_asks: (args) => {
2799
2913
  const t = tableOf(args);
2800
2914
  const values = args["p_values"] ?? {};
2801
- return ok(
2915
+ return ok2(
2802
2916
  (args["p_questions"] ?? []).map((q) => {
2803
2917
  const when = q["show_if"] ?? q["showIf"] ?? null;
2804
2918
  const asked = !when || !t ? true : rule(t, values, values, when) !== false;
@@ -2806,7 +2920,7 @@ function memoryDataSource(world) {
2806
2920
  })
2807
2921
  );
2808
2922
  },
2809
- bookings: (args) => ok(
2923
+ bookings: (args) => ok2(
2810
2924
  world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
2811
2925
  form_id: f.form_id,
2812
2926
  table_id: f.table_id,
@@ -2828,9 +2942,9 @@ function memoryDataSource(world) {
2828
2942
  booking_public: (args) => {
2829
2943
  const f = world.forms.find((x) => x.form_id === args["p_form_id"] && x.booking);
2830
2944
  const t = f ? world.tableById.get(f.table_id) : void 0;
2831
- if (!f || !t) return refuse("That booking page is not in this template.", "P0002");
2945
+ if (!f || !t) return refuse2("That booking page is not in this template.", "P0002");
2832
2946
  const availability = bookingAvailability(world, f.booking);
2833
- return ok({
2947
+ return ok2({
2834
2948
  form_id: f.form_id,
2835
2949
  organization_id: world.organization_id,
2836
2950
  table_id: t.id,
@@ -2844,7 +2958,7 @@ function memoryDataSource(world) {
2844
2958
  message: null
2845
2959
  });
2846
2960
  },
2847
- dashboards: (args) => ok(
2961
+ dashboards: (args) => ok2(
2848
2962
  world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
2849
2963
  dashboard_id: d.dashboard_id,
2850
2964
  table_id: d.table_id,
@@ -2859,9 +2973,9 @@ function memoryDataSource(world) {
2859
2973
  ),
2860
2974
  dashboard_run: (args) => {
2861
2975
  const d = world.dashboards.find((x) => x.dashboard_id === args["p_dashboard_id"]);
2862
- if (!d) return refuse("That dashboard is not in this template.", "P0002");
2976
+ if (!d) return refuse2("That dashboard is not in this template.", "P0002");
2863
2977
  const canvas = args["p_filter"] ?? {};
2864
- return ok({
2978
+ return ok2({
2865
2979
  dashboard_id: d.dashboard_id,
2866
2980
  name: d.name,
2867
2981
  subject_table_id: d.table_id,
@@ -2873,16 +2987,19 @@ function memoryDataSource(world) {
2873
2987
  blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
2874
2988
  });
2875
2989
  },
2876
- dashboard_stuck: () => ok([])
2990
+ dashboard_stuck: () => ok2([])
2877
2991
  };
2878
2992
  const source = {
2879
2993
  world,
2880
2994
  rpc(fn, args) {
2881
- const name = fn.replace(/^custom\./, "");
2995
+ const name = fn.replace(/^custom\./, "").replace(/^platform\./, "");
2996
+ const entityDoor = world.entities ? memoryEntityDoors(world.entities)[name] : void 0;
2997
+ const fromEntity = entityDoor ? entityDoor(args ?? {}) : null;
2998
+ if (fromEntity) return Promise.resolve(fromEntity);
2882
2999
  const door = doors[name];
2883
3000
  if (door) return Promise.resolve(door(args ?? {}));
2884
3001
  if (WRITE_DOOR.test(name)) return Promise.resolve({ data: null, error: PREVIEW_REFUSAL });
2885
- return Promise.resolve(refuse(`A template preview does not answer ${name}.`));
3002
+ return Promise.resolve(refuse2(`A template preview does not answer ${name}.`));
2886
3003
  },
2887
3004
  schema() {
2888
3005
  return {
@@ -2896,6 +3013,12 @@ function memoryDataSource(world) {
2896
3013
  }
2897
3014
 
2898
3015
  // src/memory/index.ts
3016
+ function withEntities(world, specs) {
3017
+ const entities = new Map(world.entities ?? []);
3018
+ for (const s of specs) entities.set(s.token, { ...s, rows: s.rows.map((r) => ({ ...r })) });
3019
+ world.entities = entities;
3020
+ return world;
3021
+ }
2899
3022
  function templatePreview(spec, options = {}) {
2900
3023
  const world = templateWorld(spec, options);
2901
3024
  const config = {
@@ -2911,4 +3034,25 @@ function templatePreview(spec, options = {}) {
2911
3034
  dashboards: world.dashboards.map((d) => ({ id: d.dashboard_id, token: d.token, name: d.name, tableId: d.table_id }))
2912
3035
  };
2913
3036
  }
3037
+ function entityStore(specs, options = {}) {
3038
+ const world = {
3039
+ organization_id: stableId("entity-store-organization"),
3040
+ user_id: stableId("entity-store-person"),
3041
+ timezone: "UTC",
3042
+ today: options.today ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
3043
+ businessName: "",
3044
+ tables: [],
3045
+ tableById: /* @__PURE__ */ new Map(),
3046
+ views: [],
3047
+ forms: [],
3048
+ dashboards: [],
3049
+ recordTable: /* @__PURE__ */ new Map(),
3050
+ stageField: /* @__PURE__ */ new Map()
3051
+ };
3052
+ withEntities(world, specs);
3053
+ return {
3054
+ world,
3055
+ config: { dataSource: memoryDataSource(world), actor: { actor: "user", user_id: world.user_id }, organizationId: world.organization_id }
3056
+ };
3057
+ }
2914
3058
  //# sourceMappingURL=index.cjs.map