@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 +6 -0
- package/dist/memory/index.cjs +212 -68
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.d.cts +59 -1
- package/dist/memory/index.d.ts +59 -1
- package/dist/memory/index.js +212 -68
- package/dist/memory/index.js.map +1 -1
- package/package.json +3 -3
package/dist/memory/index.d.cts
CHANGED
|
@@ -3,6 +3,52 @@ import { T as TemplateSpec } from '../types-F7PcHWG_.cjs';
|
|
|
3
3
|
import { P as PgError } from '../field-CugcsP2y.cjs';
|
|
4
4
|
import '../types-DT_Sk6qp.cjs';
|
|
5
5
|
|
|
6
|
+
type Json$1 = Record<string, unknown>;
|
|
7
|
+
/** One presented column, exactly as `platform.drill_describe(...).api.columns[]` says it. */
|
|
8
|
+
interface MemoryEntityColumn {
|
|
9
|
+
api_name: string;
|
|
10
|
+
name: string;
|
|
11
|
+
/** "text" | "number" | "choice" | "date" | "datetime" | "checkbox" | … */
|
|
12
|
+
type: string;
|
|
13
|
+
writable?: boolean;
|
|
14
|
+
choices?: string[];
|
|
15
|
+
/** A column shown as the words another table holds (`replaces`: the id column itself). */
|
|
16
|
+
lookup?: {
|
|
17
|
+
via: string;
|
|
18
|
+
token: string;
|
|
19
|
+
column: string;
|
|
20
|
+
replaces: boolean;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
interface MemoryEntitySpec {
|
|
24
|
+
token: string;
|
|
25
|
+
label: string;
|
|
26
|
+
columns: MemoryEntityColumn[];
|
|
27
|
+
/** Rows as the door returns them: `id` plus api_name → value, lookups and choices in words. */
|
|
28
|
+
rows: Json$1[];
|
|
29
|
+
}
|
|
30
|
+
interface MemoryEntity extends MemoryEntitySpec {
|
|
31
|
+
rows: Json$1[];
|
|
32
|
+
}
|
|
33
|
+
type Answer = {
|
|
34
|
+
data: unknown;
|
|
35
|
+
error: null;
|
|
36
|
+
} | {
|
|
37
|
+
data: null;
|
|
38
|
+
error: {
|
|
39
|
+
code: string;
|
|
40
|
+
message: string;
|
|
41
|
+
details: null;
|
|
42
|
+
hint: string | null;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** What `drill_describe` answers for a memory entity (dimensions from its choices, count + sums). */
|
|
46
|
+
declare function memoryEntityDescribe(e: MemoryEntity): Json$1;
|
|
47
|
+
/** What `drill_rows` answers: one page, rows in words. */
|
|
48
|
+
declare function memoryEntityRows(e: MemoryEntity, question: Json$1): Json$1;
|
|
49
|
+
/** What `entity_row_write` does: a choice by its word (any case), refused in the door's words otherwise. */
|
|
50
|
+
declare function memoryEntityWrite(e: MemoryEntity, recordId: string, columns: Json$1): Answer;
|
|
51
|
+
|
|
6
52
|
type Json = Record<string, unknown>;
|
|
7
53
|
/** The ids the store's kernel tables carry everywhere (custom.table_kernel_id() and its siblings). */
|
|
8
54
|
declare const MEMORY_KERNEL: {
|
|
@@ -78,6 +124,8 @@ interface MemoryWorld {
|
|
|
78
124
|
recordTable: Map<string, MemoryTable>;
|
|
79
125
|
/** Table id → the field key that is its pipeline stage. */
|
|
80
126
|
stageField: Map<string, string>;
|
|
127
|
+
/** Standard sources (`{ kind: "entity", token }`) this world answers — `withEntities`. */
|
|
128
|
+
entities?: Map<string, MemoryEntity>;
|
|
81
129
|
}
|
|
82
130
|
interface TemplateWorldOptions {
|
|
83
131
|
/** "YYYY-MM-DD" the template's relative dates resolve against. Default: today (UTC). */
|
|
@@ -95,6 +143,9 @@ declare function memoryDataSource(world: MemoryWorld): RecordsDataSource & {
|
|
|
95
143
|
readonly world: MemoryWorld;
|
|
96
144
|
};
|
|
97
145
|
|
|
146
|
+
/** Add standard sources (`{ kind: "entity", token }`) to a memory world, in the live doors' shapes. */
|
|
147
|
+
declare function withEntities(world: MemoryWorld, specs: MemoryEntitySpec[]): MemoryWorld;
|
|
148
|
+
|
|
98
149
|
interface TemplatePreview {
|
|
99
150
|
/** Mount this: `<RecordsMount config={preview.config}>` / `<RecordsProvider config={preview.config}>`. */
|
|
100
151
|
config: RecordsConfig;
|
|
@@ -122,5 +173,12 @@ interface TemplatePreview {
|
|
|
122
173
|
}
|
|
123
174
|
/** A template, installed into memory and ready to mount. Pure for a given spec and day. */
|
|
124
175
|
declare function templatePreview(spec: TemplateSpec, options?: TemplateWorldOptions): TemplatePreview;
|
|
176
|
+
/** A memory store holding only standard sources — mount it like a template preview. */
|
|
177
|
+
declare function entityStore(specs: MemoryEntitySpec[], options?: {
|
|
178
|
+
today?: string;
|
|
179
|
+
}): {
|
|
180
|
+
config: RecordsConfig;
|
|
181
|
+
world: MemoryWorld;
|
|
182
|
+
};
|
|
125
183
|
|
|
126
|
-
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, memoryDataSource, stableId, templatePreview, templateWorld };
|
|
184
|
+
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryEntity, type MemoryEntityColumn, type MemoryEntitySpec, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, entityStore, memoryDataSource, memoryEntityDescribe, memoryEntityRows, memoryEntityWrite, stableId, templatePreview, templateWorld, withEntities };
|
package/dist/memory/index.d.ts
CHANGED
|
@@ -3,6 +3,52 @@ import { T as TemplateSpec } from '../types-DL7FEBKg.js';
|
|
|
3
3
|
import { P as PgError } from '../field-CugcsP2y.js';
|
|
4
4
|
import '../types-DZgTYEVh.js';
|
|
5
5
|
|
|
6
|
+
type Json$1 = Record<string, unknown>;
|
|
7
|
+
/** One presented column, exactly as `platform.drill_describe(...).api.columns[]` says it. */
|
|
8
|
+
interface MemoryEntityColumn {
|
|
9
|
+
api_name: string;
|
|
10
|
+
name: string;
|
|
11
|
+
/** "text" | "number" | "choice" | "date" | "datetime" | "checkbox" | … */
|
|
12
|
+
type: string;
|
|
13
|
+
writable?: boolean;
|
|
14
|
+
choices?: string[];
|
|
15
|
+
/** A column shown as the words another table holds (`replaces`: the id column itself). */
|
|
16
|
+
lookup?: {
|
|
17
|
+
via: string;
|
|
18
|
+
token: string;
|
|
19
|
+
column: string;
|
|
20
|
+
replaces: boolean;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
interface MemoryEntitySpec {
|
|
24
|
+
token: string;
|
|
25
|
+
label: string;
|
|
26
|
+
columns: MemoryEntityColumn[];
|
|
27
|
+
/** Rows as the door returns them: `id` plus api_name → value, lookups and choices in words. */
|
|
28
|
+
rows: Json$1[];
|
|
29
|
+
}
|
|
30
|
+
interface MemoryEntity extends MemoryEntitySpec {
|
|
31
|
+
rows: Json$1[];
|
|
32
|
+
}
|
|
33
|
+
type Answer = {
|
|
34
|
+
data: unknown;
|
|
35
|
+
error: null;
|
|
36
|
+
} | {
|
|
37
|
+
data: null;
|
|
38
|
+
error: {
|
|
39
|
+
code: string;
|
|
40
|
+
message: string;
|
|
41
|
+
details: null;
|
|
42
|
+
hint: string | null;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** What `drill_describe` answers for a memory entity (dimensions from its choices, count + sums). */
|
|
46
|
+
declare function memoryEntityDescribe(e: MemoryEntity): Json$1;
|
|
47
|
+
/** What `drill_rows` answers: one page, rows in words. */
|
|
48
|
+
declare function memoryEntityRows(e: MemoryEntity, question: Json$1): Json$1;
|
|
49
|
+
/** What `entity_row_write` does: a choice by its word (any case), refused in the door's words otherwise. */
|
|
50
|
+
declare function memoryEntityWrite(e: MemoryEntity, recordId: string, columns: Json$1): Answer;
|
|
51
|
+
|
|
6
52
|
type Json = Record<string, unknown>;
|
|
7
53
|
/** The ids the store's kernel tables carry everywhere (custom.table_kernel_id() and its siblings). */
|
|
8
54
|
declare const MEMORY_KERNEL: {
|
|
@@ -78,6 +124,8 @@ interface MemoryWorld {
|
|
|
78
124
|
recordTable: Map<string, MemoryTable>;
|
|
79
125
|
/** Table id → the field key that is its pipeline stage. */
|
|
80
126
|
stageField: Map<string, string>;
|
|
127
|
+
/** Standard sources (`{ kind: "entity", token }`) this world answers — `withEntities`. */
|
|
128
|
+
entities?: Map<string, MemoryEntity>;
|
|
81
129
|
}
|
|
82
130
|
interface TemplateWorldOptions {
|
|
83
131
|
/** "YYYY-MM-DD" the template's relative dates resolve against. Default: today (UTC). */
|
|
@@ -95,6 +143,9 @@ declare function memoryDataSource(world: MemoryWorld): RecordsDataSource & {
|
|
|
95
143
|
readonly world: MemoryWorld;
|
|
96
144
|
};
|
|
97
145
|
|
|
146
|
+
/** Add standard sources (`{ kind: "entity", token }`) to a memory world, in the live doors' shapes. */
|
|
147
|
+
declare function withEntities(world: MemoryWorld, specs: MemoryEntitySpec[]): MemoryWorld;
|
|
148
|
+
|
|
98
149
|
interface TemplatePreview {
|
|
99
150
|
/** Mount this: `<RecordsMount config={preview.config}>` / `<RecordsProvider config={preview.config}>`. */
|
|
100
151
|
config: RecordsConfig;
|
|
@@ -122,5 +173,12 @@ interface TemplatePreview {
|
|
|
122
173
|
}
|
|
123
174
|
/** A template, installed into memory and ready to mount. Pure for a given spec and day. */
|
|
124
175
|
declare function templatePreview(spec: TemplateSpec, options?: TemplateWorldOptions): TemplatePreview;
|
|
176
|
+
/** A memory store holding only standard sources — mount it like a template preview. */
|
|
177
|
+
declare function entityStore(specs: MemoryEntitySpec[], options?: {
|
|
178
|
+
today?: string;
|
|
179
|
+
}): {
|
|
180
|
+
config: RecordsConfig;
|
|
181
|
+
world: MemoryWorld;
|
|
182
|
+
};
|
|
125
183
|
|
|
126
|
-
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, memoryDataSource, stableId, templatePreview, templateWorld };
|
|
184
|
+
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryEntity, type MemoryEntityColumn, type MemoryEntitySpec, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, entityStore, memoryDataSource, memoryEntityDescribe, memoryEntityRows, memoryEntityWrite, stableId, templatePreview, templateWorld, withEntities };
|
package/dist/memory/index.js
CHANGED
|
@@ -1,3 +1,112 @@
|
|
|
1
|
+
// src/memory/entity.ts
|
|
2
|
+
var ok = (data) => ({ data, error: null });
|
|
3
|
+
var refuse = (message, code = "22023", hint = null) => ({
|
|
4
|
+
data: null,
|
|
5
|
+
error: { code, message, details: null, hint }
|
|
6
|
+
});
|
|
7
|
+
function memoryEntityDescribe(e) {
|
|
8
|
+
const dimensions = e.columns.filter((c) => c.type === "choice" && Array.isArray(c.choices)).map((c) => ({
|
|
9
|
+
key: c.api_name,
|
|
10
|
+
label: c.name,
|
|
11
|
+
from: c.api_name,
|
|
12
|
+
kind: "choice",
|
|
13
|
+
cardinality: "low",
|
|
14
|
+
choices: (c.choices ?? []).map((w) => ({ value: w, label: w }))
|
|
15
|
+
}));
|
|
16
|
+
const measures = [
|
|
17
|
+
{ key: "count", label: `Number of ${e.label.toLowerCase()}`, op: "count", unit: "count", additive: true },
|
|
18
|
+
...e.columns.filter((c) => c.type === "number").map((c) => ({
|
|
19
|
+
key: `sum_${c.api_name}`,
|
|
20
|
+
label: `Total ${c.name.toLowerCase()}`,
|
|
21
|
+
op: "sum",
|
|
22
|
+
of: c.api_name,
|
|
23
|
+
additive: true
|
|
24
|
+
}))
|
|
25
|
+
];
|
|
26
|
+
return {
|
|
27
|
+
key: e.token,
|
|
28
|
+
label: e.label,
|
|
29
|
+
grain: `one row per ${e.label.toLowerCase()}`,
|
|
30
|
+
lanes: ["organization", "platform"],
|
|
31
|
+
dimensions,
|
|
32
|
+
measures,
|
|
33
|
+
paths: [],
|
|
34
|
+
inferred: [],
|
|
35
|
+
detail: { columns: e.columns.map((c) => c.api_name) },
|
|
36
|
+
source: { kind: "entity", token: e.token },
|
|
37
|
+
mode: "invoker",
|
|
38
|
+
api: { label: e.label, reach: "read_write", columns: e.columns },
|
|
39
|
+
calendar: { time_zone: "UTC", week_start: "monday" }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function matches(row, where) {
|
|
43
|
+
for (const [k, want] of Object.entries(where ?? {})) {
|
|
44
|
+
const have = row[k] ?? null;
|
|
45
|
+
if (Array.isArray(want)) {
|
|
46
|
+
if (!want.includes(have)) return false;
|
|
47
|
+
} else if (want === null) {
|
|
48
|
+
if (have !== null) return false;
|
|
49
|
+
} else if (typeof want === "object") continue;
|
|
50
|
+
else if (String(have).toLowerCase() !== String(want).toLowerCase()) return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function memoryEntityRows(e, question2) {
|
|
55
|
+
const limit = Number(question2["limit"] ?? 50);
|
|
56
|
+
const offset = Number(question2["offset"] ?? 0);
|
|
57
|
+
const rows = e.rows.filter((r) => matches(r, question2["where"]));
|
|
58
|
+
const page = rows.slice(offset, offset + limit);
|
|
59
|
+
return {
|
|
60
|
+
rows: page,
|
|
61
|
+
total: rows.length,
|
|
62
|
+
limit,
|
|
63
|
+
offset,
|
|
64
|
+
as_of: null,
|
|
65
|
+
columns: e.columns.map((c) => c.api_name),
|
|
66
|
+
...offset + page.length < rows.length ? { next_offset: offset + page.length } : {}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function memoryEntityWrite(e, recordId, columns) {
|
|
70
|
+
const row = e.rows.find((r) => r["id"] === recordId);
|
|
71
|
+
if (!row) return refuse(`There is no ${e.label} you can open with that id.`, "02000");
|
|
72
|
+
const next = {};
|
|
73
|
+
for (const [k, v] of Object.entries(columns ?? {})) {
|
|
74
|
+
const c = e.columns.find((x) => x.api_name === k);
|
|
75
|
+
if (!c) return refuse(`This table has no column called "${k}".`);
|
|
76
|
+
if (c.lookup && !c.lookup.replaces) return refuse(`"${c.name}" is shown from another table, so it is changed there. Nothing was written.`);
|
|
77
|
+
if (!c.writable) return refuse(`"${c.name}" is not changed through this door.`, "42501");
|
|
78
|
+
if (c.type === "choice" && v !== null && v !== "") {
|
|
79
|
+
const word = (c.choices ?? []).find((w) => w === v) ?? (c.choices ?? []).find((w) => w.toLowerCase() === String(v).toLowerCase());
|
|
80
|
+
if (!word) return refuse(`"${String(v)}" is not one of the choices of "${c.name}".`, "22023", "The columns call lists its choices.");
|
|
81
|
+
next[k] = word;
|
|
82
|
+
} else next[k] = v === "" ? null : v;
|
|
83
|
+
}
|
|
84
|
+
const changed = Object.entries(next).some(([k, v]) => row[k] !== v);
|
|
85
|
+
Object.assign(row, next);
|
|
86
|
+
return ok({ id: recordId, organization_id: row["organization_id"] ?? null, changed, row });
|
|
87
|
+
}
|
|
88
|
+
function memoryEntityDoors(entities) {
|
|
89
|
+
const of = (args) => {
|
|
90
|
+
const src = args["p_source"];
|
|
91
|
+
return src && src["kind"] === "entity" ? entities.get(String(src["token"])) : void 0;
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
drill_describe: (args) => {
|
|
95
|
+
const e = of(args);
|
|
96
|
+
return e ? ok(memoryEntityDescribe(e)) : null;
|
|
97
|
+
},
|
|
98
|
+
drill_rows: (args) => {
|
|
99
|
+
const e = of(args);
|
|
100
|
+
return e ? ok(memoryEntityRows(e, args["p_question"] ?? {})) : null;
|
|
101
|
+
},
|
|
102
|
+
entity_row_write: (args) => {
|
|
103
|
+
const e = entities.get(String(args["p_token"] ?? ""));
|
|
104
|
+
if (!e) return null;
|
|
105
|
+
return memoryEntityWrite(e, String(args["p_record_id"] ?? ""), args["p_columns"] ?? {});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
1
110
|
// src/templates/payloads.ts
|
|
2
111
|
var ACTOR = "user";
|
|
3
112
|
var COMPUTED = /* @__PURE__ */ new Set(["lookup", "rollup", "formula"]);
|
|
@@ -2226,10 +2335,10 @@ var PREVIEW_REFUSAL = {
|
|
|
2226
2335
|
hint: null
|
|
2227
2336
|
};
|
|
2228
2337
|
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)(_|$)/;
|
|
2229
|
-
function
|
|
2338
|
+
function ok2(data) {
|
|
2230
2339
|
return { data, error: null };
|
|
2231
2340
|
}
|
|
2232
|
-
function
|
|
2341
|
+
function refuse2(message, code = "PGRST202") {
|
|
2233
2342
|
return { data: null, error: { code, message, details: null, hint: null } };
|
|
2234
2343
|
}
|
|
2235
2344
|
function stamp(world) {
|
|
@@ -2553,55 +2662,55 @@ function memoryDataSource(world) {
|
|
|
2553
2662
|
return typeof v === "string" ? v : v === void 0 || v === null ? null : String(v);
|
|
2554
2663
|
};
|
|
2555
2664
|
const doors = {
|
|
2556
|
-
table_kernel_id: () =>
|
|
2557
|
-
field_kernel_id: () =>
|
|
2558
|
-
person_kernel_id: () =>
|
|
2559
|
-
file_kernel_id: () =>
|
|
2560
|
-
rule_kernel_id: () =>
|
|
2561
|
-
store_is_open: () =>
|
|
2665
|
+
table_kernel_id: () => ok2(MEMORY_KERNEL.table),
|
|
2666
|
+
field_kernel_id: () => ok2(MEMORY_KERNEL.field),
|
|
2667
|
+
person_kernel_id: () => ok2(MEMORY_KERNEL.person),
|
|
2668
|
+
file_kernel_id: () => ok2(MEMORY_KERNEL.file),
|
|
2669
|
+
rule_kernel_id: () => ok2(MEMORY_KERNEL.rule),
|
|
2670
|
+
store_is_open: () => ok2(true),
|
|
2562
2671
|
read_records: (args) => {
|
|
2563
2672
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2564
2673
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2565
|
-
if (args["p_table_id"] === MEMORY_KERNEL.table) return
|
|
2674
|
+
if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.slice(offset, offset + limit).map(tableRow));
|
|
2566
2675
|
const t = tableOf(args);
|
|
2567
|
-
if (!t) return
|
|
2568
|
-
return
|
|
2676
|
+
if (!t) return ok2([]);
|
|
2677
|
+
return ok2(t.order.slice(offset, offset + limit).map((id) => row(t, id)));
|
|
2569
2678
|
},
|
|
2570
2679
|
read_records_by_ids: (args) => {
|
|
2571
2680
|
const ids = args["p_record_ids"] ?? [];
|
|
2572
|
-
if (args["p_table_id"] === MEMORY_KERNEL.table) return
|
|
2681
|
+
if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.filter((t2) => ids.includes(t2.id)).map(tableRow));
|
|
2573
2682
|
const t = tableOf(args);
|
|
2574
|
-
if (!t) return
|
|
2575
|
-
return
|
|
2683
|
+
if (!t) return ok2([]);
|
|
2684
|
+
return ok2(ids.filter((id) => t.rows.has(id)).map((id) => row(t, id)));
|
|
2576
2685
|
},
|
|
2577
2686
|
read_records_matching: (args) => {
|
|
2578
2687
|
const t = tableOf(args);
|
|
2579
|
-
if (!t) return
|
|
2688
|
+
if (!t) return ok2([]);
|
|
2580
2689
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2581
2690
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2582
|
-
return
|
|
2691
|
+
return ok2(matching(world, t, args).slice(offset, offset + limit).map((id) => row(t, id)));
|
|
2583
2692
|
},
|
|
2584
2693
|
read_records_page: (args) => {
|
|
2585
2694
|
const t = tableOf(args);
|
|
2586
2695
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2587
2696
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2588
|
-
if (!t) return
|
|
2697
|
+
if (!t) return ok2({ rows: [], total: 0, limit, offset, sort_ignored: [] });
|
|
2589
2698
|
const ids = matching(world, t, args);
|
|
2590
|
-
return
|
|
2699
|
+
return ok2({ rows: ids.slice(offset, offset + limit).map((id) => row(t, id)), total: ids.length, limit, offset, sort_ignored: [] });
|
|
2591
2700
|
},
|
|
2592
2701
|
read_record: (args) => {
|
|
2593
2702
|
const id = String(args["p_record_id"] ?? "");
|
|
2594
2703
|
const t = world.recordTable.get(id);
|
|
2595
|
-
if (!t) return
|
|
2596
|
-
return
|
|
2704
|
+
if (!t) return refuse2("That record is not in this template.", "P0002");
|
|
2705
|
+
return ok2(readDocument(world, t, id));
|
|
2597
2706
|
},
|
|
2598
|
-
record_headers: (args) =>
|
|
2707
|
+
record_headers: (args) => ok2(
|
|
2599
2708
|
(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) }))
|
|
2600
2709
|
),
|
|
2601
2710
|
applicable_fields: (args) => {
|
|
2602
2711
|
const t = tableOf(args);
|
|
2603
|
-
if (!t) return
|
|
2604
|
-
return
|
|
2712
|
+
if (!t) return ok2([]);
|
|
2713
|
+
return ok2(
|
|
2605
2714
|
t.fields.map((f) => ({
|
|
2606
2715
|
id: f.id,
|
|
2607
2716
|
data: f.data,
|
|
@@ -2620,9 +2729,9 @@ function memoryDataSource(world) {
|
|
|
2620
2729
|
},
|
|
2621
2730
|
field_options: (args) => {
|
|
2622
2731
|
const hit = fieldById(args["p_field_id"]);
|
|
2623
|
-
if (!hit) return
|
|
2732
|
+
if (!hit) return ok2([]);
|
|
2624
2733
|
const opts = hit.t.options.get(String(hit.f.data["key"])) ?? [];
|
|
2625
|
-
return
|
|
2734
|
+
return ok2(
|
|
2626
2735
|
opts.map((o, i) => ({
|
|
2627
2736
|
id: o.id,
|
|
2628
2737
|
organization_id: world.organization_id,
|
|
@@ -2638,46 +2747,46 @@ function memoryDataSource(world) {
|
|
|
2638
2747
|
}))
|
|
2639
2748
|
);
|
|
2640
2749
|
},
|
|
2641
|
-
my_levels: (args) =>
|
|
2642
|
-
views: (args) =>
|
|
2750
|
+
my_levels: (args) => ok2((args["p_ids"] ?? []).map((id) => ({ id, level: VIEWER }))),
|
|
2751
|
+
views: (args) => ok2(
|
|
2643
2752
|
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` }))
|
|
2644
2753
|
),
|
|
2645
2754
|
view_look_read: (args) => {
|
|
2646
2755
|
const out = {};
|
|
2647
2756
|
for (const [key, look] of looks) if (key.startsWith(`${String(args["p_table_id"])}:`)) out[key.split(":")[1]] = look;
|
|
2648
|
-
return
|
|
2757
|
+
return ok2(out);
|
|
2649
2758
|
},
|
|
2650
2759
|
view_look_set: (args) => {
|
|
2651
2760
|
const key = `${String(args["p_table_id"])}:${String(args["p_view_id"])}`;
|
|
2652
2761
|
const look = args["p_look"] ?? null;
|
|
2653
2762
|
if (look) looks.set(key, { look, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2654
2763
|
else looks.delete(key);
|
|
2655
|
-
return
|
|
2764
|
+
return ok2(look);
|
|
2656
2765
|
},
|
|
2657
|
-
grid_layout: (args) =>
|
|
2766
|
+
grid_layout: (args) => ok2({
|
|
2658
2767
|
layout: { mode: "auto", wrap: false, row_height: "normal", fit_max_columns: 8, freeze_first_column: false },
|
|
2659
2768
|
source: { mode: "platform", wrap: "platform", row_height: "platform", fit_max_columns: "platform", freeze_first_column: "platform" },
|
|
2660
2769
|
refused: [],
|
|
2661
2770
|
view_id: args["p_view_id"] ?? null
|
|
2662
2771
|
}),
|
|
2663
|
-
table_decorations: () =>
|
|
2664
|
-
row_actions: () =>
|
|
2665
|
-
table_stage_field: (args) =>
|
|
2772
|
+
table_decorations: () => ok2({ rows: {}, cells: {}, rules: [], stale: [], colors: ["slate", "green", "amber", "red", "blue", "violet", "teal"], columns: {}, version: 1, rule_ops: [] }),
|
|
2773
|
+
row_actions: () => ok2({ stale: [], actions: [] }),
|
|
2774
|
+
table_stage_field: (args) => ok2(world.stageField.get(String(args["p_table_id"])) ?? null),
|
|
2666
2775
|
pipeline_read: (args) => {
|
|
2667
2776
|
const t = tableOf(args);
|
|
2668
2777
|
const stage = t ? world.stageField.get(t.id) : void 0;
|
|
2669
2778
|
const field = stage ? t.fields.find((f) => f.data["key"] === stage) : void 0;
|
|
2670
|
-
if (!t || !stage || !field) return
|
|
2779
|
+
if (!t || !stage || !field) return ok2({ is_pipeline: false, why: "This table has no stage column." });
|
|
2671
2780
|
const stages = (t.options.get(stage) ?? []).map((o) => ({ key: o.key, label: o.label, retired: false }));
|
|
2672
|
-
return
|
|
2781
|
+
return ok2({ is_pipeline: true, table_id: t.id, stage_field: stage, field_id: field.id, stage_label: field.data["label"], stages, rules: [] });
|
|
2673
2782
|
},
|
|
2674
2783
|
pipeline_board: (args) => {
|
|
2675
2784
|
const t = tableOf(args);
|
|
2676
2785
|
const stage = t ? world.stageField.get(t.id) : void 0;
|
|
2677
|
-
if (!t || !stage) return
|
|
2786
|
+
if (!t || !stage) return ok2([]);
|
|
2678
2787
|
const measure = typeof args["p_measure"] === "string" ? args["p_measure"] : null;
|
|
2679
2788
|
const ids = t.order.filter((id) => admits(world, t, id, args["p_filter"]));
|
|
2680
|
-
return
|
|
2789
|
+
return ok2(
|
|
2681
2790
|
(t.options.get(stage) ?? []).map((o, i) => {
|
|
2682
2791
|
const inIt = ids.filter((id) => t.rows.get(id)[stage] === o.key);
|
|
2683
2792
|
const total = measure ? inIt.reduce((sum, id) => sum + (typeof t.rows.get(id)[measure] === "number" ? t.rows.get(id)[measure] : 0), 0) : null;
|
|
@@ -2685,7 +2794,7 @@ function memoryDataSource(world) {
|
|
|
2685
2794
|
})
|
|
2686
2795
|
);
|
|
2687
2796
|
},
|
|
2688
|
-
relation_words_many: (args) =>
|
|
2797
|
+
relation_words_many: (args) => ok2((args["p_record_ids"] ?? []).map((id) => ({ record_id: id, words: nameOf(id), archived: false }))),
|
|
2689
2798
|
reverse_columns: (args) => {
|
|
2690
2799
|
const target = String(args["p_table_id"] ?? "");
|
|
2691
2800
|
const out = [];
|
|
@@ -2705,11 +2814,11 @@ function memoryDataSource(world) {
|
|
|
2705
2814
|
});
|
|
2706
2815
|
}
|
|
2707
2816
|
}
|
|
2708
|
-
return
|
|
2817
|
+
return ok2(out);
|
|
2709
2818
|
},
|
|
2710
2819
|
reverse_links_many: (args) => {
|
|
2711
2820
|
const hit = fieldById(args["p_field_id"]);
|
|
2712
|
-
return
|
|
2821
|
+
return ok2(
|
|
2713
2822
|
(args["p_record_ids"] ?? []).map((rid) => {
|
|
2714
2823
|
if (!hit) return { record_id: rid, total: 0, links: [] };
|
|
2715
2824
|
const key = String(hit.f.data["key"]);
|
|
@@ -2723,28 +2832,28 @@ function memoryDataSource(world) {
|
|
|
2723
2832
|
},
|
|
2724
2833
|
// A template's own record has no history, comments, checklists or worked-out provenance yet:
|
|
2725
2834
|
// these are the answers an installed template gives on its first day.
|
|
2726
|
-
record_history: () =>
|
|
2727
|
-
field_history: () =>
|
|
2728
|
-
computed_provenance: () =>
|
|
2729
|
-
comment_thread: (args) =>
|
|
2730
|
-
checklist_runs: () =>
|
|
2731
|
-
checklist_templates: () =>
|
|
2732
|
-
doc_templates: () =>
|
|
2733
|
-
doc_renders: () =>
|
|
2734
|
-
doc_signatures: () =>
|
|
2735
|
-
record_row_controls: () =>
|
|
2835
|
+
record_history: () => ok2([]),
|
|
2836
|
+
field_history: () => ok2([]),
|
|
2837
|
+
computed_provenance: () => ok2([]),
|
|
2838
|
+
comment_thread: (args) => ok2({ record_id: args["p_record_id"] ?? null, comments: [], may_comment: false, may_resolve: false }),
|
|
2839
|
+
checklist_runs: () => ok2([]),
|
|
2840
|
+
checklist_templates: () => ok2([]),
|
|
2841
|
+
doc_templates: () => ok2([]),
|
|
2842
|
+
doc_renders: () => ok2([]),
|
|
2843
|
+
doc_signatures: () => ok2([]),
|
|
2844
|
+
record_row_controls: () => ok2({
|
|
2736
2845
|
shown_to: { value: null, effective: "everyone", type_default: null, table_default: null, allowed: ["everyone"], is_child: false, can_change: false },
|
|
2737
2846
|
published_to_web: { available: false, value: false, table_default: null, can_change: false },
|
|
2738
2847
|
indexed: { available: false, value: null, table_default: null, effective: false, can_change: false }
|
|
2739
2848
|
}),
|
|
2740
|
-
enrich_cells: () =>
|
|
2741
|
-
enrichments: () =>
|
|
2742
|
-
pipeline_pending: () =>
|
|
2743
|
-
record_stage_pending: () =>
|
|
2744
|
-
io_imports: () =>
|
|
2745
|
-
relation_words: (args) =>
|
|
2849
|
+
enrich_cells: () => ok2([]),
|
|
2850
|
+
enrichments: () => ok2([]),
|
|
2851
|
+
pipeline_pending: () => ok2([]),
|
|
2852
|
+
record_stage_pending: () => ok2([]),
|
|
2853
|
+
io_imports: () => ok2([]),
|
|
2854
|
+
relation_words: (args) => ok2(nameOf(String(args["p_value"] ?? ""))),
|
|
2746
2855
|
// The read doors a form, a booking page and a dashboard are drawn from (lane CHAIR-GALLERY-3).
|
|
2747
|
-
forms: (args) =>
|
|
2856
|
+
forms: (args) => ok2(
|
|
2748
2857
|
world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2749
2858
|
form_id: f.form_id,
|
|
2750
2859
|
table_id: f.table_id,
|
|
@@ -2767,7 +2876,7 @@ function memoryDataSource(world) {
|
|
|
2767
2876
|
form_preview_asks: (args) => {
|
|
2768
2877
|
const t = tableOf(args);
|
|
2769
2878
|
const values = args["p_values"] ?? {};
|
|
2770
|
-
return
|
|
2879
|
+
return ok2(
|
|
2771
2880
|
(args["p_questions"] ?? []).map((q) => {
|
|
2772
2881
|
const when = q["show_if"] ?? q["showIf"] ?? null;
|
|
2773
2882
|
const asked = !when || !t ? true : rule(t, values, values, when) !== false;
|
|
@@ -2775,7 +2884,7 @@ function memoryDataSource(world) {
|
|
|
2775
2884
|
})
|
|
2776
2885
|
);
|
|
2777
2886
|
},
|
|
2778
|
-
bookings: (args) =>
|
|
2887
|
+
bookings: (args) => ok2(
|
|
2779
2888
|
world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2780
2889
|
form_id: f.form_id,
|
|
2781
2890
|
table_id: f.table_id,
|
|
@@ -2797,9 +2906,9 @@ function memoryDataSource(world) {
|
|
|
2797
2906
|
booking_public: (args) => {
|
|
2798
2907
|
const f = world.forms.find((x) => x.form_id === args["p_form_id"] && x.booking);
|
|
2799
2908
|
const t = f ? world.tableById.get(f.table_id) : void 0;
|
|
2800
|
-
if (!f || !t) return
|
|
2909
|
+
if (!f || !t) return refuse2("That booking page is not in this template.", "P0002");
|
|
2801
2910
|
const availability = bookingAvailability(world, f.booking);
|
|
2802
|
-
return
|
|
2911
|
+
return ok2({
|
|
2803
2912
|
form_id: f.form_id,
|
|
2804
2913
|
organization_id: world.organization_id,
|
|
2805
2914
|
table_id: t.id,
|
|
@@ -2813,7 +2922,7 @@ function memoryDataSource(world) {
|
|
|
2813
2922
|
message: null
|
|
2814
2923
|
});
|
|
2815
2924
|
},
|
|
2816
|
-
dashboards: (args) =>
|
|
2925
|
+
dashboards: (args) => ok2(
|
|
2817
2926
|
world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
|
|
2818
2927
|
dashboard_id: d.dashboard_id,
|
|
2819
2928
|
table_id: d.table_id,
|
|
@@ -2828,9 +2937,9 @@ function memoryDataSource(world) {
|
|
|
2828
2937
|
),
|
|
2829
2938
|
dashboard_run: (args) => {
|
|
2830
2939
|
const d = world.dashboards.find((x) => x.dashboard_id === args["p_dashboard_id"]);
|
|
2831
|
-
if (!d) return
|
|
2940
|
+
if (!d) return refuse2("That dashboard is not in this template.", "P0002");
|
|
2832
2941
|
const canvas = args["p_filter"] ?? {};
|
|
2833
|
-
return
|
|
2942
|
+
return ok2({
|
|
2834
2943
|
dashboard_id: d.dashboard_id,
|
|
2835
2944
|
name: d.name,
|
|
2836
2945
|
subject_table_id: d.table_id,
|
|
@@ -2842,16 +2951,19 @@ function memoryDataSource(world) {
|
|
|
2842
2951
|
blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
|
|
2843
2952
|
});
|
|
2844
2953
|
},
|
|
2845
|
-
dashboard_stuck: () =>
|
|
2954
|
+
dashboard_stuck: () => ok2([])
|
|
2846
2955
|
};
|
|
2847
2956
|
const source = {
|
|
2848
2957
|
world,
|
|
2849
2958
|
rpc(fn, args) {
|
|
2850
|
-
const name = fn.replace(/^custom\./, "");
|
|
2959
|
+
const name = fn.replace(/^custom\./, "").replace(/^platform\./, "");
|
|
2960
|
+
const entityDoor = world.entities ? memoryEntityDoors(world.entities)[name] : void 0;
|
|
2961
|
+
const fromEntity = entityDoor ? entityDoor(args ?? {}) : null;
|
|
2962
|
+
if (fromEntity) return Promise.resolve(fromEntity);
|
|
2851
2963
|
const door = doors[name];
|
|
2852
2964
|
if (door) return Promise.resolve(door(args ?? {}));
|
|
2853
2965
|
if (WRITE_DOOR.test(name)) return Promise.resolve({ data: null, error: PREVIEW_REFUSAL });
|
|
2854
|
-
return Promise.resolve(
|
|
2966
|
+
return Promise.resolve(refuse2(`A template preview does not answer ${name}.`));
|
|
2855
2967
|
},
|
|
2856
2968
|
schema() {
|
|
2857
2969
|
return {
|
|
@@ -2865,6 +2977,12 @@ function memoryDataSource(world) {
|
|
|
2865
2977
|
}
|
|
2866
2978
|
|
|
2867
2979
|
// src/memory/index.ts
|
|
2980
|
+
function withEntities(world, specs) {
|
|
2981
|
+
const entities = new Map(world.entities ?? []);
|
|
2982
|
+
for (const s of specs) entities.set(s.token, { ...s, rows: s.rows.map((r) => ({ ...r })) });
|
|
2983
|
+
world.entities = entities;
|
|
2984
|
+
return world;
|
|
2985
|
+
}
|
|
2868
2986
|
function templatePreview(spec, options = {}) {
|
|
2869
2987
|
const world = templateWorld(spec, options);
|
|
2870
2988
|
const config = {
|
|
@@ -2880,12 +2998,38 @@ function templatePreview(spec, options = {}) {
|
|
|
2880
2998
|
dashboards: world.dashboards.map((d) => ({ id: d.dashboard_id, token: d.token, name: d.name, tableId: d.table_id }))
|
|
2881
2999
|
};
|
|
2882
3000
|
}
|
|
3001
|
+
function entityStore(specs, options = {}) {
|
|
3002
|
+
const world = {
|
|
3003
|
+
organization_id: stableId("entity-store-organization"),
|
|
3004
|
+
user_id: stableId("entity-store-person"),
|
|
3005
|
+
timezone: "UTC",
|
|
3006
|
+
today: options.today ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3007
|
+
businessName: "",
|
|
3008
|
+
tables: [],
|
|
3009
|
+
tableById: /* @__PURE__ */ new Map(),
|
|
3010
|
+
views: [],
|
|
3011
|
+
forms: [],
|
|
3012
|
+
dashboards: [],
|
|
3013
|
+
recordTable: /* @__PURE__ */ new Map(),
|
|
3014
|
+
stageField: /* @__PURE__ */ new Map()
|
|
3015
|
+
};
|
|
3016
|
+
withEntities(world, specs);
|
|
3017
|
+
return {
|
|
3018
|
+
world,
|
|
3019
|
+
config: { dataSource: memoryDataSource(world), actor: { actor: "user", user_id: world.user_id }, organizationId: world.organization_id }
|
|
3020
|
+
};
|
|
3021
|
+
}
|
|
2883
3022
|
export {
|
|
2884
3023
|
MEMORY_KERNEL,
|
|
2885
3024
|
PREVIEW_REFUSAL,
|
|
3025
|
+
entityStore,
|
|
2886
3026
|
memoryDataSource,
|
|
3027
|
+
memoryEntityDescribe,
|
|
3028
|
+
memoryEntityRows,
|
|
3029
|
+
memoryEntityWrite,
|
|
2887
3030
|
stableId,
|
|
2888
3031
|
templatePreview,
|
|
2889
|
-
templateWorld
|
|
3032
|
+
templateWorld,
|
|
3033
|
+
withEntities
|
|
2890
3034
|
};
|
|
2891
3035
|
//# sourceMappingURL=index.js.map
|