@ai-matrx/records 0.73.3 → 0.73.5
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 +12 -0
- package/dist/memory/index.cjs +310 -79
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.d.cts +65 -1
- package/dist/memory/index.d.ts +65 -1
- package/dist/memory/index.js +310 -79
- package/dist/memory/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records
|
|
2
2
|
|
|
3
|
+
## 0.73.5
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records/v0.73.4..npm/records/v0.73.5 -- apps/shared/records`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.73.4
|
|
10
|
+
|
|
11
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
12
|
+
`git diff npm/records/v0.73.3..npm/records/v0.73.4 -- apps/shared/records`).
|
|
13
|
+
No source changes intended and no consumer action required.
|
|
14
|
+
|
|
3
15
|
## 0.73.3
|
|
4
16
|
|
|
5
17
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/memory/index.cjs
CHANGED
|
@@ -22,13 +22,187 @@ 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
|
+
memoryEntityAsk: () => memoryEntityAsk,
|
|
28
|
+
memoryEntityDescribe: () => memoryEntityDescribe,
|
|
29
|
+
memoryEntityRows: () => memoryEntityRows,
|
|
30
|
+
memoryEntityWrite: () => memoryEntityWrite,
|
|
26
31
|
stableId: () => stableId,
|
|
27
32
|
templatePreview: () => templatePreview,
|
|
28
|
-
templateWorld: () => templateWorld
|
|
33
|
+
templateWorld: () => templateWorld,
|
|
34
|
+
withEntities: () => withEntities
|
|
29
35
|
});
|
|
30
36
|
module.exports = __toCommonJS(memory_exports);
|
|
31
37
|
|
|
38
|
+
// src/memory/entity.ts
|
|
39
|
+
var ok = (data) => ({ data, error: null });
|
|
40
|
+
var refuse = (message, code = "22023", hint = null) => ({
|
|
41
|
+
data: null,
|
|
42
|
+
error: { code, message, details: null, hint }
|
|
43
|
+
});
|
|
44
|
+
function memoryEntityDescribe(e) {
|
|
45
|
+
const dimensions = e.columns.filter((c) => c.type === "choice" && Array.isArray(c.choices)).map((c) => ({
|
|
46
|
+
key: c.api_name,
|
|
47
|
+
label: c.name,
|
|
48
|
+
from: c.api_name,
|
|
49
|
+
kind: "choice",
|
|
50
|
+
cardinality: "low",
|
|
51
|
+
choices: (c.choices ?? []).map((w) => ({ value: w, label: w }))
|
|
52
|
+
}));
|
|
53
|
+
const measures = [
|
|
54
|
+
{ key: "count", label: `Number of ${e.label.toLowerCase()}`, op: "count", unit: "count", additive: true },
|
|
55
|
+
...e.columns.filter((c) => c.type === "number").map((c) => ({
|
|
56
|
+
key: `sum_${c.api_name}`,
|
|
57
|
+
label: `Total ${c.name.toLowerCase()}`,
|
|
58
|
+
op: "sum",
|
|
59
|
+
of: c.api_name,
|
|
60
|
+
additive: true
|
|
61
|
+
}))
|
|
62
|
+
];
|
|
63
|
+
return {
|
|
64
|
+
key: e.token,
|
|
65
|
+
label: e.label,
|
|
66
|
+
grain: `one row per ${e.label.toLowerCase()}`,
|
|
67
|
+
lanes: ["organization", "platform"],
|
|
68
|
+
dimensions,
|
|
69
|
+
measures,
|
|
70
|
+
paths: [],
|
|
71
|
+
inferred: [],
|
|
72
|
+
detail: { columns: e.columns.map((c) => c.api_name) },
|
|
73
|
+
source: { kind: "entity", token: e.token },
|
|
74
|
+
mode: "invoker",
|
|
75
|
+
api: { label: e.label, reach: "read_write", columns: e.columns },
|
|
76
|
+
calendar: { time_zone: "UTC", week_start: "monday" }
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function matches(row, where) {
|
|
80
|
+
for (const [k, want] of Object.entries(where ?? {})) {
|
|
81
|
+
const have = row[k] ?? null;
|
|
82
|
+
if (Array.isArray(want)) {
|
|
83
|
+
if (!want.includes(have)) return false;
|
|
84
|
+
} else if (want === null) {
|
|
85
|
+
if (have !== null) return false;
|
|
86
|
+
} else if (typeof want === "object") continue;
|
|
87
|
+
else if (String(have).toLowerCase() !== String(want).toLowerCase()) return false;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
function memoryEntityRows(e, question2) {
|
|
92
|
+
const limit = Number(question2["limit"] ?? 50);
|
|
93
|
+
const offset = Number(question2["offset"] ?? 0);
|
|
94
|
+
const rows = e.rows.filter((r) => matches(r, question2["where"]));
|
|
95
|
+
const page = rows.slice(offset, offset + limit);
|
|
96
|
+
return {
|
|
97
|
+
rows: page,
|
|
98
|
+
total: rows.length,
|
|
99
|
+
limit,
|
|
100
|
+
offset,
|
|
101
|
+
as_of: null,
|
|
102
|
+
columns: e.columns.map((c) => c.api_name),
|
|
103
|
+
...offset + page.length < rows.length ? { next_offset: offset + page.length } : {}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function memoryEntityAsk(e, question2) {
|
|
107
|
+
const by = (question2["by"] ?? []).map((k) => k.split(":")[0]);
|
|
108
|
+
const shown = question2["show"] ?? ["count"];
|
|
109
|
+
const measures = (shown.length ? shown : ["count"]).map((m) => typeof m === "string" ? m === "count" ? { key: "count", op: "count", of: null } : { key: m, op: m.split("_")[0], of: m.slice(m.indexOf("_") + 1) } : { key: m.op === "count" ? "count" : `${m.op}_${m.of ?? ""}`, op: m.op, of: m.of ?? null });
|
|
110
|
+
const rows = e.rows.filter((r) => matches(r, question2["where"]));
|
|
111
|
+
const measure = (list) => {
|
|
112
|
+
const out2 = {};
|
|
113
|
+
for (const m of measures) {
|
|
114
|
+
if (m.op === "count") {
|
|
115
|
+
out2[m.key] = list.length;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const nums = list.map((r) => r[m.of ?? ""]).filter((v) => typeof v === "number");
|
|
119
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
120
|
+
out2[m.key] = !nums.length ? null : m.op === "sum" ? sum : m.op === "avg" ? sum / nums.length : m.op === "min" ? Math.min(...nums) : m.op === "max" ? Math.max(...nums) : null;
|
|
121
|
+
}
|
|
122
|
+
return out2;
|
|
123
|
+
};
|
|
124
|
+
const row = (kind, groups, list) => ({
|
|
125
|
+
kind,
|
|
126
|
+
groups,
|
|
127
|
+
measures: measure(list),
|
|
128
|
+
row_count: list.length,
|
|
129
|
+
prior_groups: null,
|
|
130
|
+
prior_measures: null,
|
|
131
|
+
prior_row_count: null,
|
|
132
|
+
delta: null,
|
|
133
|
+
compare: null,
|
|
134
|
+
distinct_groups: null,
|
|
135
|
+
labels: {},
|
|
136
|
+
says: null,
|
|
137
|
+
as_of: null
|
|
138
|
+
});
|
|
139
|
+
const out = [];
|
|
140
|
+
if (by.length) {
|
|
141
|
+
const groups = /* @__PURE__ */ new Map();
|
|
142
|
+
for (const r of rows) {
|
|
143
|
+
const g = {};
|
|
144
|
+
for (const k of by) {
|
|
145
|
+
const v = r[k];
|
|
146
|
+
g[k] = v === void 0 || v === "" ? null : v;
|
|
147
|
+
}
|
|
148
|
+
const key = JSON.stringify(g);
|
|
149
|
+
const hit = groups.get(key) ?? { groups: g, rows: [] };
|
|
150
|
+
hit.rows.push(r);
|
|
151
|
+
groups.set(key, hit);
|
|
152
|
+
}
|
|
153
|
+
const first = measures[0].key;
|
|
154
|
+
const answered = [...groups.values()].map((g) => row("group", g.groups, g.rows));
|
|
155
|
+
answered.sort((a, b) => Number(b["measures"][first] ?? 0) - Number(a["measures"][first] ?? 0));
|
|
156
|
+
out.push(...answered.slice(0, Number(question2["limit"] ?? 50)));
|
|
157
|
+
}
|
|
158
|
+
out.push(row("total", {}, rows));
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
function memoryEntityWrite(e, recordId, columns) {
|
|
162
|
+
const row = e.rows.find((r) => r["id"] === recordId);
|
|
163
|
+
if (!row) return refuse(`There is no ${e.label} you can open with that id.`, "02000");
|
|
164
|
+
const next = {};
|
|
165
|
+
for (const [k, v] of Object.entries(columns ?? {})) {
|
|
166
|
+
const c = e.columns.find((x) => x.api_name === k);
|
|
167
|
+
if (!c) return refuse(`This table has no column called "${k}".`);
|
|
168
|
+
if (c.lookup && !c.lookup.replaces) return refuse(`"${c.name}" is shown from another table, so it is changed there. Nothing was written.`);
|
|
169
|
+
if (!c.writable) return refuse(`"${c.name}" is not changed through this door.`, "42501");
|
|
170
|
+
if (c.type === "choice" && v !== null && v !== "") {
|
|
171
|
+
const word = (c.choices ?? []).find((w) => w === v) ?? (c.choices ?? []).find((w) => w.toLowerCase() === String(v).toLowerCase());
|
|
172
|
+
if (!word) return refuse(`"${String(v)}" is not one of the choices of "${c.name}".`, "22023", "The columns call lists its choices.");
|
|
173
|
+
next[k] = word;
|
|
174
|
+
} else next[k] = v === "" ? null : v;
|
|
175
|
+
}
|
|
176
|
+
const changed = Object.entries(next).some(([k, v]) => row[k] !== v);
|
|
177
|
+
Object.assign(row, next);
|
|
178
|
+
return ok({ id: recordId, organization_id: row["organization_id"] ?? null, changed, row });
|
|
179
|
+
}
|
|
180
|
+
function memoryEntityDoors(entities) {
|
|
181
|
+
const of = (args) => {
|
|
182
|
+
const src = args["p_source"];
|
|
183
|
+
return src && src["kind"] === "entity" ? entities.get(String(src["token"])) : void 0;
|
|
184
|
+
};
|
|
185
|
+
return {
|
|
186
|
+
drill_describe: (args) => {
|
|
187
|
+
const e = of(args);
|
|
188
|
+
return e ? ok(memoryEntityDescribe(e)) : null;
|
|
189
|
+
},
|
|
190
|
+
drill_ask: (args) => {
|
|
191
|
+
const e = of(args);
|
|
192
|
+
return e ? ok(memoryEntityAsk(e, args["p_question"] ?? {})) : null;
|
|
193
|
+
},
|
|
194
|
+
drill_rows: (args) => {
|
|
195
|
+
const e = of(args);
|
|
196
|
+
return e ? ok(memoryEntityRows(e, args["p_question"] ?? {})) : null;
|
|
197
|
+
},
|
|
198
|
+
entity_row_write: (args) => {
|
|
199
|
+
const e = entities.get(String(args["p_token"] ?? ""));
|
|
200
|
+
if (!e) return null;
|
|
201
|
+
return memoryEntityWrite(e, String(args["p_record_id"] ?? ""), args["p_columns"] ?? {});
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
32
206
|
// src/templates/payloads.ts
|
|
33
207
|
var ACTOR = "user";
|
|
34
208
|
var COMPUTED = /* @__PURE__ */ new Set(["lookup", "rollup", "formula"]);
|
|
@@ -2257,10 +2431,10 @@ var PREVIEW_REFUSAL = {
|
|
|
2257
2431
|
hint: null
|
|
2258
2432
|
};
|
|
2259
2433
|
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
|
|
2434
|
+
function ok2(data) {
|
|
2261
2435
|
return { data, error: null };
|
|
2262
2436
|
}
|
|
2263
|
-
function
|
|
2437
|
+
function refuse2(message, code = "PGRST202") {
|
|
2264
2438
|
return { data: null, error: { code, message, details: null, hint: null } };
|
|
2265
2439
|
}
|
|
2266
2440
|
function stamp(world) {
|
|
@@ -2445,16 +2619,11 @@ function groupValues(doc, stored, key) {
|
|
|
2445
2619
|
const out = list.map((v) => v === void 0 || v === null || v === "" ? null : String(v));
|
|
2446
2620
|
return out.length ? out : [null];
|
|
2447
2621
|
}
|
|
2448
|
-
function
|
|
2449
|
-
const
|
|
2450
|
-
const
|
|
2451
|
-
|
|
2452
|
-
if (
|
|
2453
|
-
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2454
|
-
const measures = (raw["measures"] ?? [{ op: "count" }]).map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2455
|
-
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2456
|
-
const bucket = raw["bucket"] ?? null;
|
|
2457
|
-
const ids = table.order.filter((id) => admits(world, table, id, raw["filter"]) && admits(world, table, id, canvas));
|
|
2622
|
+
function aggregateRows(world, table, ask) {
|
|
2623
|
+
const { groupBy, measures, bucket } = ask;
|
|
2624
|
+
const search = (ask.search ?? "").trim().toLowerCase();
|
|
2625
|
+
let ids = table.order.filter((id) => ask.filters.every((f) => admits(world, table, id, f)));
|
|
2626
|
+
if (search) ids = ids.filter((id) => JSON.stringify(readDocument(world, table, id)).toLowerCase().includes(search));
|
|
2458
2627
|
const groups = /* @__PURE__ */ new Map();
|
|
2459
2628
|
for (const id of ids) {
|
|
2460
2629
|
const doc = readDocument(world, table, id);
|
|
@@ -2496,8 +2665,25 @@ function runBlock(world, subject, raw, canvas, index) {
|
|
|
2496
2665
|
const k = `${bucket.key}_${bucket.by ?? "month"}`;
|
|
2497
2666
|
rows.sort((a, b) => String(a.groups[k]).localeCompare(String(b.groups[k])));
|
|
2498
2667
|
} else rows.sort((a, b) => (b.measures[primary] ?? 0) - (a.measures[primary] ?? 0));
|
|
2499
|
-
const limit = Number(
|
|
2668
|
+
const limit = Number(ask.limit ?? 0);
|
|
2500
2669
|
if (limit > 0) rows = rows.slice(0, limit);
|
|
2670
|
+
return rows;
|
|
2671
|
+
}
|
|
2672
|
+
function measuresOf(raw) {
|
|
2673
|
+
const list = Array.isArray(raw) ? raw : [];
|
|
2674
|
+
const out = list.map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2675
|
+
return out.length ? out : [{ op: "count" }];
|
|
2676
|
+
}
|
|
2677
|
+
function runBlock(world, subject, raw, canvas, index) {
|
|
2678
|
+
const table = world.tableById.get(String(raw["table_id"] ?? subject));
|
|
2679
|
+
const title = String(raw["title"] ?? `Block ${index + 1}`);
|
|
2680
|
+
const base = { ...raw, title, table_id: table?.id ?? subject, ms: 0 };
|
|
2681
|
+
if (!table) return { ...base, rows: [], refused: "This block's table is not in this template." };
|
|
2682
|
+
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2683
|
+
const measures = measuresOf(raw["measures"]);
|
|
2684
|
+
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2685
|
+
const bucket = raw["bucket"] ?? null;
|
|
2686
|
+
const rows = aggregateRows(world, table, { groupBy, measures, bucket, filters: [raw["filter"], canvas], limit: Number(raw["limit"] ?? 0) });
|
|
2501
2687
|
return { ...base, measures, group_by: groupBy, rows };
|
|
2502
2688
|
}
|
|
2503
2689
|
function bookingAvailability(world, raw) {
|
|
@@ -2584,55 +2770,55 @@ function memoryDataSource(world) {
|
|
|
2584
2770
|
return typeof v === "string" ? v : v === void 0 || v === null ? null : String(v);
|
|
2585
2771
|
};
|
|
2586
2772
|
const doors = {
|
|
2587
|
-
table_kernel_id: () =>
|
|
2588
|
-
field_kernel_id: () =>
|
|
2589
|
-
person_kernel_id: () =>
|
|
2590
|
-
file_kernel_id: () =>
|
|
2591
|
-
rule_kernel_id: () =>
|
|
2592
|
-
store_is_open: () =>
|
|
2773
|
+
table_kernel_id: () => ok2(MEMORY_KERNEL.table),
|
|
2774
|
+
field_kernel_id: () => ok2(MEMORY_KERNEL.field),
|
|
2775
|
+
person_kernel_id: () => ok2(MEMORY_KERNEL.person),
|
|
2776
|
+
file_kernel_id: () => ok2(MEMORY_KERNEL.file),
|
|
2777
|
+
rule_kernel_id: () => ok2(MEMORY_KERNEL.rule),
|
|
2778
|
+
store_is_open: () => ok2(true),
|
|
2593
2779
|
read_records: (args) => {
|
|
2594
2780
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2595
2781
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2596
|
-
if (args["p_table_id"] === MEMORY_KERNEL.table) return
|
|
2782
|
+
if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.slice(offset, offset + limit).map(tableRow));
|
|
2597
2783
|
const t = tableOf(args);
|
|
2598
|
-
if (!t) return
|
|
2599
|
-
return
|
|
2784
|
+
if (!t) return ok2([]);
|
|
2785
|
+
return ok2(t.order.slice(offset, offset + limit).map((id) => row(t, id)));
|
|
2600
2786
|
},
|
|
2601
2787
|
read_records_by_ids: (args) => {
|
|
2602
2788
|
const ids = args["p_record_ids"] ?? [];
|
|
2603
|
-
if (args["p_table_id"] === MEMORY_KERNEL.table) return
|
|
2789
|
+
if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.filter((t2) => ids.includes(t2.id)).map(tableRow));
|
|
2604
2790
|
const t = tableOf(args);
|
|
2605
|
-
if (!t) return
|
|
2606
|
-
return
|
|
2791
|
+
if (!t) return ok2([]);
|
|
2792
|
+
return ok2(ids.filter((id) => t.rows.has(id)).map((id) => row(t, id)));
|
|
2607
2793
|
},
|
|
2608
2794
|
read_records_matching: (args) => {
|
|
2609
2795
|
const t = tableOf(args);
|
|
2610
|
-
if (!t) return
|
|
2796
|
+
if (!t) return ok2([]);
|
|
2611
2797
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2612
2798
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2613
|
-
return
|
|
2799
|
+
return ok2(matching(world, t, args).slice(offset, offset + limit).map((id) => row(t, id)));
|
|
2614
2800
|
},
|
|
2615
2801
|
read_records_page: (args) => {
|
|
2616
2802
|
const t = tableOf(args);
|
|
2617
2803
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2618
2804
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2619
|
-
if (!t) return
|
|
2805
|
+
if (!t) return ok2({ rows: [], total: 0, limit, offset, sort_ignored: [] });
|
|
2620
2806
|
const ids = matching(world, t, args);
|
|
2621
|
-
return
|
|
2807
|
+
return ok2({ rows: ids.slice(offset, offset + limit).map((id) => row(t, id)), total: ids.length, limit, offset, sort_ignored: [] });
|
|
2622
2808
|
},
|
|
2623
2809
|
read_record: (args) => {
|
|
2624
2810
|
const id = String(args["p_record_id"] ?? "");
|
|
2625
2811
|
const t = world.recordTable.get(id);
|
|
2626
|
-
if (!t) return
|
|
2627
|
-
return
|
|
2812
|
+
if (!t) return refuse2("That record is not in this template.", "P0002");
|
|
2813
|
+
return ok2(readDocument(world, t, id));
|
|
2628
2814
|
},
|
|
2629
|
-
record_headers: (args) =>
|
|
2815
|
+
record_headers: (args) => ok2(
|
|
2630
2816
|
(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
2817
|
),
|
|
2632
2818
|
applicable_fields: (args) => {
|
|
2633
2819
|
const t = tableOf(args);
|
|
2634
|
-
if (!t) return
|
|
2635
|
-
return
|
|
2820
|
+
if (!t) return ok2([]);
|
|
2821
|
+
return ok2(
|
|
2636
2822
|
t.fields.map((f) => ({
|
|
2637
2823
|
id: f.id,
|
|
2638
2824
|
data: f.data,
|
|
@@ -2651,9 +2837,9 @@ function memoryDataSource(world) {
|
|
|
2651
2837
|
},
|
|
2652
2838
|
field_options: (args) => {
|
|
2653
2839
|
const hit = fieldById(args["p_field_id"]);
|
|
2654
|
-
if (!hit) return
|
|
2840
|
+
if (!hit) return ok2([]);
|
|
2655
2841
|
const opts = hit.t.options.get(String(hit.f.data["key"])) ?? [];
|
|
2656
|
-
return
|
|
2842
|
+
return ok2(
|
|
2657
2843
|
opts.map((o, i) => ({
|
|
2658
2844
|
id: o.id,
|
|
2659
2845
|
organization_id: world.organization_id,
|
|
@@ -2669,46 +2855,46 @@ function memoryDataSource(world) {
|
|
|
2669
2855
|
}))
|
|
2670
2856
|
);
|
|
2671
2857
|
},
|
|
2672
|
-
my_levels: (args) =>
|
|
2673
|
-
views: (args) =>
|
|
2858
|
+
my_levels: (args) => ok2((args["p_ids"] ?? []).map((id) => ({ id, level: VIEWER }))),
|
|
2859
|
+
views: (args) => ok2(
|
|
2674
2860
|
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
2861
|
),
|
|
2676
2862
|
view_look_read: (args) => {
|
|
2677
2863
|
const out = {};
|
|
2678
2864
|
for (const [key, look] of looks) if (key.startsWith(`${String(args["p_table_id"])}:`)) out[key.split(":")[1]] = look;
|
|
2679
|
-
return
|
|
2865
|
+
return ok2(out);
|
|
2680
2866
|
},
|
|
2681
2867
|
view_look_set: (args) => {
|
|
2682
2868
|
const key = `${String(args["p_table_id"])}:${String(args["p_view_id"])}`;
|
|
2683
2869
|
const look = args["p_look"] ?? null;
|
|
2684
2870
|
if (look) looks.set(key, { look, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2685
2871
|
else looks.delete(key);
|
|
2686
|
-
return
|
|
2872
|
+
return ok2(look);
|
|
2687
2873
|
},
|
|
2688
|
-
grid_layout: (args) =>
|
|
2874
|
+
grid_layout: (args) => ok2({
|
|
2689
2875
|
layout: { mode: "auto", wrap: false, row_height: "normal", fit_max_columns: 8, freeze_first_column: false },
|
|
2690
2876
|
source: { mode: "platform", wrap: "platform", row_height: "platform", fit_max_columns: "platform", freeze_first_column: "platform" },
|
|
2691
2877
|
refused: [],
|
|
2692
2878
|
view_id: args["p_view_id"] ?? null
|
|
2693
2879
|
}),
|
|
2694
|
-
table_decorations: () =>
|
|
2695
|
-
row_actions: () =>
|
|
2696
|
-
table_stage_field: (args) =>
|
|
2880
|
+
table_decorations: () => ok2({ rows: {}, cells: {}, rules: [], stale: [], colors: ["slate", "green", "amber", "red", "blue", "violet", "teal"], columns: {}, version: 1, rule_ops: [] }),
|
|
2881
|
+
row_actions: () => ok2({ stale: [], actions: [] }),
|
|
2882
|
+
table_stage_field: (args) => ok2(world.stageField.get(String(args["p_table_id"])) ?? null),
|
|
2697
2883
|
pipeline_read: (args) => {
|
|
2698
2884
|
const t = tableOf(args);
|
|
2699
2885
|
const stage = t ? world.stageField.get(t.id) : void 0;
|
|
2700
2886
|
const field = stage ? t.fields.find((f) => f.data["key"] === stage) : void 0;
|
|
2701
|
-
if (!t || !stage || !field) return
|
|
2887
|
+
if (!t || !stage || !field) return ok2({ is_pipeline: false, why: "This table has no stage column." });
|
|
2702
2888
|
const stages = (t.options.get(stage) ?? []).map((o) => ({ key: o.key, label: o.label, retired: false }));
|
|
2703
|
-
return
|
|
2889
|
+
return ok2({ is_pipeline: true, table_id: t.id, stage_field: stage, field_id: field.id, stage_label: field.data["label"], stages, rules: [] });
|
|
2704
2890
|
},
|
|
2705
2891
|
pipeline_board: (args) => {
|
|
2706
2892
|
const t = tableOf(args);
|
|
2707
2893
|
const stage = t ? world.stageField.get(t.id) : void 0;
|
|
2708
|
-
if (!t || !stage) return
|
|
2894
|
+
if (!t || !stage) return ok2([]);
|
|
2709
2895
|
const measure = typeof args["p_measure"] === "string" ? args["p_measure"] : null;
|
|
2710
2896
|
const ids = t.order.filter((id) => admits(world, t, id, args["p_filter"]));
|
|
2711
|
-
return
|
|
2897
|
+
return ok2(
|
|
2712
2898
|
(t.options.get(stage) ?? []).map((o, i) => {
|
|
2713
2899
|
const inIt = ids.filter((id) => t.rows.get(id)[stage] === o.key);
|
|
2714
2900
|
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 +2902,7 @@ function memoryDataSource(world) {
|
|
|
2716
2902
|
})
|
|
2717
2903
|
);
|
|
2718
2904
|
},
|
|
2719
|
-
relation_words_many: (args) =>
|
|
2905
|
+
relation_words_many: (args) => ok2((args["p_record_ids"] ?? []).map((id) => ({ record_id: id, words: nameOf(id), archived: false }))),
|
|
2720
2906
|
reverse_columns: (args) => {
|
|
2721
2907
|
const target = String(args["p_table_id"] ?? "");
|
|
2722
2908
|
const out = [];
|
|
@@ -2736,11 +2922,11 @@ function memoryDataSource(world) {
|
|
|
2736
2922
|
});
|
|
2737
2923
|
}
|
|
2738
2924
|
}
|
|
2739
|
-
return
|
|
2925
|
+
return ok2(out);
|
|
2740
2926
|
},
|
|
2741
2927
|
reverse_links_many: (args) => {
|
|
2742
2928
|
const hit = fieldById(args["p_field_id"]);
|
|
2743
|
-
return
|
|
2929
|
+
return ok2(
|
|
2744
2930
|
(args["p_record_ids"] ?? []).map((rid) => {
|
|
2745
2931
|
if (!hit) return { record_id: rid, total: 0, links: [] };
|
|
2746
2932
|
const key = String(hit.f.data["key"]);
|
|
@@ -2754,28 +2940,28 @@ function memoryDataSource(world) {
|
|
|
2754
2940
|
},
|
|
2755
2941
|
// A template's own record has no history, comments, checklists or worked-out provenance yet:
|
|
2756
2942
|
// these are the answers an installed template gives on its first day.
|
|
2757
|
-
record_history: () =>
|
|
2758
|
-
field_history: () =>
|
|
2759
|
-
computed_provenance: () =>
|
|
2760
|
-
comment_thread: (args) =>
|
|
2761
|
-
checklist_runs: () =>
|
|
2762
|
-
checklist_templates: () =>
|
|
2763
|
-
doc_templates: () =>
|
|
2764
|
-
doc_renders: () =>
|
|
2765
|
-
doc_signatures: () =>
|
|
2766
|
-
record_row_controls: () =>
|
|
2943
|
+
record_history: () => ok2([]),
|
|
2944
|
+
field_history: () => ok2([]),
|
|
2945
|
+
computed_provenance: () => ok2([]),
|
|
2946
|
+
comment_thread: (args) => ok2({ record_id: args["p_record_id"] ?? null, comments: [], may_comment: false, may_resolve: false }),
|
|
2947
|
+
checklist_runs: () => ok2([]),
|
|
2948
|
+
checklist_templates: () => ok2([]),
|
|
2949
|
+
doc_templates: () => ok2([]),
|
|
2950
|
+
doc_renders: () => ok2([]),
|
|
2951
|
+
doc_signatures: () => ok2([]),
|
|
2952
|
+
record_row_controls: () => ok2({
|
|
2767
2953
|
shown_to: { value: null, effective: "everyone", type_default: null, table_default: null, allowed: ["everyone"], is_child: false, can_change: false },
|
|
2768
2954
|
published_to_web: { available: false, value: false, table_default: null, can_change: false },
|
|
2769
2955
|
indexed: { available: false, value: null, table_default: null, effective: false, can_change: false }
|
|
2770
2956
|
}),
|
|
2771
|
-
enrich_cells: () =>
|
|
2772
|
-
enrichments: () =>
|
|
2773
|
-
pipeline_pending: () =>
|
|
2774
|
-
record_stage_pending: () =>
|
|
2775
|
-
io_imports: () =>
|
|
2776
|
-
relation_words: (args) =>
|
|
2957
|
+
enrich_cells: () => ok2([]),
|
|
2958
|
+
enrichments: () => ok2([]),
|
|
2959
|
+
pipeline_pending: () => ok2([]),
|
|
2960
|
+
record_stage_pending: () => ok2([]),
|
|
2961
|
+
io_imports: () => ok2([]),
|
|
2962
|
+
relation_words: (args) => ok2(nameOf(String(args["p_value"] ?? ""))),
|
|
2777
2963
|
// The read doors a form, a booking page and a dashboard are drawn from (lane CHAIR-GALLERY-3).
|
|
2778
|
-
forms: (args) =>
|
|
2964
|
+
forms: (args) => ok2(
|
|
2779
2965
|
world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2780
2966
|
form_id: f.form_id,
|
|
2781
2967
|
table_id: f.table_id,
|
|
@@ -2798,7 +2984,7 @@ function memoryDataSource(world) {
|
|
|
2798
2984
|
form_preview_asks: (args) => {
|
|
2799
2985
|
const t = tableOf(args);
|
|
2800
2986
|
const values = args["p_values"] ?? {};
|
|
2801
|
-
return
|
|
2987
|
+
return ok2(
|
|
2802
2988
|
(args["p_questions"] ?? []).map((q) => {
|
|
2803
2989
|
const when = q["show_if"] ?? q["showIf"] ?? null;
|
|
2804
2990
|
const asked = !when || !t ? true : rule(t, values, values, when) !== false;
|
|
@@ -2806,7 +2992,7 @@ function memoryDataSource(world) {
|
|
|
2806
2992
|
})
|
|
2807
2993
|
);
|
|
2808
2994
|
},
|
|
2809
|
-
bookings: (args) =>
|
|
2995
|
+
bookings: (args) => ok2(
|
|
2810
2996
|
world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2811
2997
|
form_id: f.form_id,
|
|
2812
2998
|
table_id: f.table_id,
|
|
@@ -2828,9 +3014,9 @@ function memoryDataSource(world) {
|
|
|
2828
3014
|
booking_public: (args) => {
|
|
2829
3015
|
const f = world.forms.find((x) => x.form_id === args["p_form_id"] && x.booking);
|
|
2830
3016
|
const t = f ? world.tableById.get(f.table_id) : void 0;
|
|
2831
|
-
if (!f || !t) return
|
|
3017
|
+
if (!f || !t) return refuse2("That booking page is not in this template.", "P0002");
|
|
2832
3018
|
const availability = bookingAvailability(world, f.booking);
|
|
2833
|
-
return
|
|
3019
|
+
return ok2({
|
|
2834
3020
|
form_id: f.form_id,
|
|
2835
3021
|
organization_id: world.organization_id,
|
|
2836
3022
|
table_id: t.id,
|
|
@@ -2844,7 +3030,7 @@ function memoryDataSource(world) {
|
|
|
2844
3030
|
message: null
|
|
2845
3031
|
});
|
|
2846
3032
|
},
|
|
2847
|
-
dashboards: (args) =>
|
|
3033
|
+
dashboards: (args) => ok2(
|
|
2848
3034
|
world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
|
|
2849
3035
|
dashboard_id: d.dashboard_id,
|
|
2850
3036
|
table_id: d.table_id,
|
|
@@ -2859,9 +3045,9 @@ function memoryDataSource(world) {
|
|
|
2859
3045
|
),
|
|
2860
3046
|
dashboard_run: (args) => {
|
|
2861
3047
|
const d = world.dashboards.find((x) => x.dashboard_id === args["p_dashboard_id"]);
|
|
2862
|
-
if (!d) return
|
|
3048
|
+
if (!d) return refuse2("That dashboard is not in this template.", "P0002");
|
|
2863
3049
|
const canvas = args["p_filter"] ?? {};
|
|
2864
|
-
return
|
|
3050
|
+
return ok2({
|
|
2865
3051
|
dashboard_id: d.dashboard_id,
|
|
2866
3052
|
name: d.name,
|
|
2867
3053
|
subject_table_id: d.table_id,
|
|
@@ -2873,16 +3059,34 @@ function memoryDataSource(world) {
|
|
|
2873
3059
|
blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
|
|
2874
3060
|
});
|
|
2875
3061
|
},
|
|
2876
|
-
dashboard_stuck: () =>
|
|
3062
|
+
dashboard_stuck: () => ok2([]),
|
|
3063
|
+
// THE EIGHTH VERB, in memory: the same groups and measures as the live `custom.record_aggregate`
|
|
3064
|
+
// (and its row shape: no comparison asked ⇒ every prior_* null).
|
|
3065
|
+
record_aggregate: (args) => {
|
|
3066
|
+
const t = tableOf(args);
|
|
3067
|
+
if (!t) return refuse2("That table is not in this template.", "P0002");
|
|
3068
|
+
const rows = aggregateRows(world, t, {
|
|
3069
|
+
groupBy: (args["p_group_by"] ?? []).slice(),
|
|
3070
|
+
measures: measuresOf(args["p_measures"]),
|
|
3071
|
+
bucket: args["p_bucket"] ?? null,
|
|
3072
|
+
filters: [args["p_filter"]],
|
|
3073
|
+
...typeof args["p_search"] === "string" ? { search: args["p_search"] } : {},
|
|
3074
|
+
limit: Number(args["p_limit"] ?? 200)
|
|
3075
|
+
});
|
|
3076
|
+
return ok2(rows.map((r) => ({ ...r, prior_groups: null, prior_measures: null, prior_row_count: null, delta: null, compare: null })));
|
|
3077
|
+
}
|
|
2877
3078
|
};
|
|
2878
3079
|
const source = {
|
|
2879
3080
|
world,
|
|
2880
3081
|
rpc(fn, args) {
|
|
2881
|
-
const name = fn.replace(/^custom\./, "");
|
|
3082
|
+
const name = fn.replace(/^custom\./, "").replace(/^platform\./, "");
|
|
3083
|
+
const entityDoor = world.entities ? memoryEntityDoors(world.entities)[name] : void 0;
|
|
3084
|
+
const fromEntity = entityDoor ? entityDoor(args ?? {}) : null;
|
|
3085
|
+
if (fromEntity) return Promise.resolve(fromEntity);
|
|
2882
3086
|
const door = doors[name];
|
|
2883
3087
|
if (door) return Promise.resolve(door(args ?? {}));
|
|
2884
3088
|
if (WRITE_DOOR.test(name)) return Promise.resolve({ data: null, error: PREVIEW_REFUSAL });
|
|
2885
|
-
return Promise.resolve(
|
|
3089
|
+
return Promise.resolve(refuse2(`A template preview does not answer ${name}.`));
|
|
2886
3090
|
},
|
|
2887
3091
|
schema() {
|
|
2888
3092
|
return {
|
|
@@ -2896,6 +3100,12 @@ function memoryDataSource(world) {
|
|
|
2896
3100
|
}
|
|
2897
3101
|
|
|
2898
3102
|
// src/memory/index.ts
|
|
3103
|
+
function withEntities(world, specs) {
|
|
3104
|
+
const entities = new Map(world.entities ?? []);
|
|
3105
|
+
for (const s of specs) entities.set(s.token, { ...s, rows: s.rows.map((r) => ({ ...r })) });
|
|
3106
|
+
world.entities = entities;
|
|
3107
|
+
return world;
|
|
3108
|
+
}
|
|
2899
3109
|
function templatePreview(spec, options = {}) {
|
|
2900
3110
|
const world = templateWorld(spec, options);
|
|
2901
3111
|
const config = {
|
|
@@ -2911,4 +3121,25 @@ function templatePreview(spec, options = {}) {
|
|
|
2911
3121
|
dashboards: world.dashboards.map((d) => ({ id: d.dashboard_id, token: d.token, name: d.name, tableId: d.table_id }))
|
|
2912
3122
|
};
|
|
2913
3123
|
}
|
|
3124
|
+
function entityStore(specs, options = {}) {
|
|
3125
|
+
const world = {
|
|
3126
|
+
organization_id: stableId("entity-store-organization"),
|
|
3127
|
+
user_id: stableId("entity-store-person"),
|
|
3128
|
+
timezone: "UTC",
|
|
3129
|
+
today: options.today ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3130
|
+
businessName: "",
|
|
3131
|
+
tables: [],
|
|
3132
|
+
tableById: /* @__PURE__ */ new Map(),
|
|
3133
|
+
views: [],
|
|
3134
|
+
forms: [],
|
|
3135
|
+
dashboards: [],
|
|
3136
|
+
recordTable: /* @__PURE__ */ new Map(),
|
|
3137
|
+
stageField: /* @__PURE__ */ new Map()
|
|
3138
|
+
};
|
|
3139
|
+
withEntities(world, specs);
|
|
3140
|
+
return {
|
|
3141
|
+
world,
|
|
3142
|
+
config: { dataSource: memoryDataSource(world), actor: { actor: "user", user_id: world.user_id }, organizationId: world.organization_id }
|
|
3143
|
+
};
|
|
3144
|
+
}
|
|
2914
3145
|
//# sourceMappingURL=index.cjs.map
|