@ai-matrx/records 0.57.3 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +116 -0
- package/dist/core/index.cjs +625 -151
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +272 -7
- package/dist/core/index.d.ts +272 -7
- package/dist/core/index.js +625 -151
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +329 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +825 -195
- package/dist/index.d.ts +825 -195
- package/dist/index.js +329 -2
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +428 -30
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1029 -205
- package/dist/react/index.d.ts +1029 -205
- package/dist/react/index.js +428 -30
- package/dist/react/index.js.map +1 -1
- package/dist/{types-BpBSMhYq.d.cts → types-NKSc_jZq.d.cts} +31 -3
- package/dist/{types-BpBSMhYq.d.ts → types-NKSc_jZq.d.ts} +31 -3
- package/dist/use-cases/index.cjs.map +1 -1
- package/dist/use-cases/index.d.cts +2 -2
- package/dist/use-cases/index.d.ts +2 -2
- package/dist/use-cases/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -56,6 +56,7 @@ __export(src_exports, {
|
|
|
56
56
|
PERMISSION_LEVELS: () => PERMISSION_LEVELS,
|
|
57
57
|
PER_VALUE_ACCESS_WORDS: () => PER_VALUE_ACCESS_WORDS,
|
|
58
58
|
PIPELINE_RULE_KINDS: () => PIPELINE_RULE_KINDS,
|
|
59
|
+
PORTAL_ACCENTS: () => PORTAL_ACCENTS,
|
|
59
60
|
PORTAL_ARCHIVE_FILTERS: () => PORTAL_ARCHIVE_FILTERS,
|
|
60
61
|
REFUSALS_WORTH_REPEATING: () => REFUSALS_WORTH_REPEATING,
|
|
61
62
|
RELATION_BINDINGS: () => RELATION_BINDINGS,
|
|
@@ -90,6 +91,11 @@ __export(src_exports, {
|
|
|
90
91
|
coercionLabel: () => coercionLabel,
|
|
91
92
|
emptyArchiveLine: () => emptyArchiveLine,
|
|
92
93
|
emptyPortalArchiveLine: () => emptyPortalArchiveLine,
|
|
94
|
+
entityReferenceKinds: () => entityReferenceKinds,
|
|
95
|
+
entityReferenceKindsOf: () => entityReferenceKindsOf,
|
|
96
|
+
entityReferenceWords: () => entityReferenceWords,
|
|
97
|
+
entityRefsOf: () => entityRefsOf,
|
|
98
|
+
entityRefsToWrite: () => entityRefsToWrite,
|
|
93
99
|
err: () => err,
|
|
94
100
|
exampleSpec: () => exampleSpec,
|
|
95
101
|
exportPageXlsx: () => exportPageXlsx,
|
|
@@ -100,16 +106,24 @@ __export(src_exports, {
|
|
|
100
106
|
indexedDbStore: () => indexedDbStore,
|
|
101
107
|
isArchiveLane: () => isArchiveLane,
|
|
102
108
|
isDecided: () => isDecided,
|
|
109
|
+
isEntityReferenceConfig: () => isEntityReferenceConfig,
|
|
103
110
|
isOwnOp: () => isOwnOp,
|
|
111
|
+
isPortalAccent: () => isPortalAccent,
|
|
104
112
|
isPortalArchiveFilter: () => isPortalArchiveFilter,
|
|
105
113
|
isRecordsErr: () => isRecordsErr,
|
|
114
|
+
isRuleFilter: () => isRuleFilter,
|
|
106
115
|
isTheChosen: () => isTheChosen,
|
|
116
|
+
keptGroups: () => keptGroups,
|
|
117
|
+
keptOutOfSight: () => keptOutOfSight,
|
|
118
|
+
keptTableHref: () => keptTableHref,
|
|
107
119
|
looksLikeAnId: () => looksLikeAnId,
|
|
108
120
|
mayDrag: () => mayDrag,
|
|
109
121
|
measureKey: () => measureKey,
|
|
110
122
|
memoryStore: () => memoryStore,
|
|
111
123
|
mintClientKey: () => mintClientKey,
|
|
112
124
|
mintOpId: () => mintOpId,
|
|
125
|
+
moveInOrder: () => moveInOrder,
|
|
126
|
+
offeredAsContext: () => offeredAsContext,
|
|
113
127
|
ok: () => ok,
|
|
114
128
|
openCaptureQueue: () => openCaptureQueue,
|
|
115
129
|
optionKey: () => optionKey,
|
|
@@ -123,7 +137,10 @@ __export(src_exports, {
|
|
|
123
137
|
rememberedOpCount: () => rememberedOpCount,
|
|
124
138
|
sameDocument: () => sameDocument,
|
|
125
139
|
scopeChip: () => scopeChip,
|
|
126
|
-
|
|
140
|
+
sheetSyncSpec: () => sheetSyncSpec,
|
|
141
|
+
stableFilterKey: () => stableFilterKey,
|
|
142
|
+
withRowCounts: () => withRowCounts,
|
|
143
|
+
withTablePlacement: () => withTablePlacement
|
|
127
144
|
});
|
|
128
145
|
module.exports = __toCommonJS(src_exports);
|
|
129
146
|
|
|
@@ -305,6 +322,7 @@ var FIELD_KINDS = [
|
|
|
305
322
|
"currency",
|
|
306
323
|
"datetime",
|
|
307
324
|
"email",
|
|
325
|
+
"entity_reference",
|
|
308
326
|
"formula",
|
|
309
327
|
"json",
|
|
310
328
|
"long_text",
|
|
@@ -343,6 +361,7 @@ function fieldKindFor(field, kernel) {
|
|
|
343
361
|
case "list":
|
|
344
362
|
return field.multi ? "multi_select" : "select";
|
|
345
363
|
case "relation": {
|
|
364
|
+
if (isEntityReferenceConfig(config)) return "entity_reference";
|
|
346
365
|
const parity = String(config["parity"] ?? "");
|
|
347
366
|
if (parity === "attachment" || parity === "member") return parity;
|
|
348
367
|
if (kernel?.file && field.relation_target === kernel.file) return "attachment";
|
|
@@ -360,6 +379,14 @@ function fieldKindFor(field, kernel) {
|
|
|
360
379
|
}
|
|
361
380
|
}
|
|
362
381
|
var UUID_TEXT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
382
|
+
function isEntityReferenceConfig(config) {
|
|
383
|
+
const allowed = config?.["allowed_types"];
|
|
384
|
+
return Array.isArray(allowed) && allowed.length > 0;
|
|
385
|
+
}
|
|
386
|
+
function entityReferenceKindsOf(field) {
|
|
387
|
+
const allowed = field.config?.["allowed_types"];
|
|
388
|
+
return Array.isArray(allowed) ? allowed.map((k) => String(k).trim().toLowerCase()).filter(Boolean) : [];
|
|
389
|
+
}
|
|
363
390
|
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
364
391
|
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
365
392
|
function coercionLabel(field) {
|
|
@@ -475,6 +502,23 @@ function coerceTypedAnswer(field, raw, opts = {}) {
|
|
|
475
502
|
return {
|
|
476
503
|
refusal: `${label} points at another record, so it is chosen rather than typed. Open it and pick the record.`
|
|
477
504
|
};
|
|
505
|
+
// SC-R / P12. An entity reference names a platform thing by kind and id.
|
|
506
|
+
// An import or an agent may hand over `note:<id>` — or a bare id when the
|
|
507
|
+
// column allows exactly one kind; the store then decides whether the thing
|
|
508
|
+
// is there and whether the writer may open it. Words are chosen, not typed.
|
|
509
|
+
case "entity_reference": {
|
|
510
|
+
const allowed = entityReferenceKindsOf(field);
|
|
511
|
+
const [maybeToken, maybeId] = text.includes(":") ? text.split(/:(.*)/s, 2) : ["", text];
|
|
512
|
+
const token = (maybeToken ?? "").trim().toLowerCase() || (allowed.length === 1 ? allowed[0] : "");
|
|
513
|
+
const id = (maybeId ?? "").trim();
|
|
514
|
+
if (token && UUID_TEXT.test(id)) {
|
|
515
|
+
const ref = { token, id: id.toLowerCase() };
|
|
516
|
+
return { value: field.multi ? [ref] : ref };
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
refusal: `${label} points at something on the platform, so it is chosen rather than typed. Open it and pick it.`
|
|
520
|
+
};
|
|
521
|
+
}
|
|
478
522
|
case "formula":
|
|
479
523
|
case "lookup":
|
|
480
524
|
case "rollup":
|
|
@@ -531,6 +575,10 @@ function publicFormPath(formId) {
|
|
|
531
575
|
}
|
|
532
576
|
|
|
533
577
|
// src/portal.ts
|
|
578
|
+
var PORTAL_ACCENTS = ["slate", "green", "amber", "red", "blue", "violet", "teal"];
|
|
579
|
+
function isPortalAccent(word) {
|
|
580
|
+
return typeof word === "string" && PORTAL_ACCENTS.includes(word);
|
|
581
|
+
}
|
|
534
582
|
function portalPath(slug) {
|
|
535
583
|
return `/portal/c/${slug}`;
|
|
536
584
|
}
|
|
@@ -554,11 +602,17 @@ function emptyPortalArchiveLine() {
|
|
|
554
602
|
}
|
|
555
603
|
|
|
556
604
|
// src/aggregate.ts
|
|
605
|
+
function isRuleFilter(filter) {
|
|
606
|
+
if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
|
|
607
|
+
const node = filter;
|
|
608
|
+
return typeof node.op === "string" && Array.isArray(node.args);
|
|
609
|
+
}
|
|
557
610
|
function measureKey(measure) {
|
|
558
611
|
return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
|
|
559
612
|
}
|
|
560
613
|
function stableFilterKey(filter) {
|
|
561
614
|
if (!filter) return "{}";
|
|
615
|
+
if (isRuleFilter(filter)) return JSON.stringify(filter);
|
|
562
616
|
const keys = Object.keys(filter).sort();
|
|
563
617
|
if (keys.length === 0) return "{}";
|
|
564
618
|
const parts = keys.map((key) => {
|
|
@@ -654,6 +708,101 @@ function recordChangeTrigger(tableId, options = {}) {
|
|
|
654
708
|
...options.changedFields && options.changedFields.length > 0 ? { changed_fields: options.changedFields } : {}
|
|
655
709
|
};
|
|
656
710
|
}
|
|
711
|
+
function sheetSyncSpec(args) {
|
|
712
|
+
const [header = [], ...body] = args.cells;
|
|
713
|
+
const columns = header.map((c, i) => {
|
|
714
|
+
const name = c == null ? "" : String(c).trim();
|
|
715
|
+
return name === "" ? `Column ${i + 1}` : name;
|
|
716
|
+
});
|
|
717
|
+
if (columns.length === 0) {
|
|
718
|
+
throw new Error("The sheet has no header row, so there are no columns to sync. Nothing was sent.");
|
|
719
|
+
}
|
|
720
|
+
const seenCol = /* @__PURE__ */ new Set();
|
|
721
|
+
for (const c of columns) {
|
|
722
|
+
if (seenCol.has(c)) throw new Error(`The sheet has two columns named "${c}". Rename one and sync again.`);
|
|
723
|
+
seenCol.add(c);
|
|
724
|
+
}
|
|
725
|
+
const refIdx = args.refColumn == null ? -1 : columns.indexOf(args.refColumn);
|
|
726
|
+
if (args.refColumn != null && refIdx < 0) {
|
|
727
|
+
throw new Error(`The id column "${args.refColumn}" is not in the sheet's header. Nothing was sent.`);
|
|
728
|
+
}
|
|
729
|
+
const seen = /* @__PURE__ */ new Set();
|
|
730
|
+
const rows = [];
|
|
731
|
+
body.forEach((cells, i) => {
|
|
732
|
+
if (cells.every((v) => v == null || String(v).trim() === "")) return;
|
|
733
|
+
const ref = refIdx >= 0 ? String(cells[refIdx] ?? "").trim() : `row-${i + 2}`;
|
|
734
|
+
if (ref === "") throw new Error(`Sheet row ${i + 2} has no value in the id column "${args.refColumn}".`);
|
|
735
|
+
if (seen.has(ref)) throw new Error(`Two sheet rows share the id "${ref}"; each row needs its own.`);
|
|
736
|
+
seen.add(ref);
|
|
737
|
+
const values = {};
|
|
738
|
+
columns.forEach((c, j) => {
|
|
739
|
+
const v = cells[j];
|
|
740
|
+
values[c] = v === void 0 || v === "" ? null : v;
|
|
741
|
+
});
|
|
742
|
+
rows.push({ ref, values });
|
|
743
|
+
});
|
|
744
|
+
return { source: args.source, table_name: args.tableName, columns, rows };
|
|
745
|
+
}
|
|
746
|
+
function withRowCounts(tables, counts) {
|
|
747
|
+
if (!counts) return [...tables];
|
|
748
|
+
const byId = new Map(counts.map((c) => [c.table_id, Number(c.visible_rows)]));
|
|
749
|
+
return tables.map((t) => byId.has(t.id) ? { ...t, row_count: byId.get(t.id) } : t);
|
|
750
|
+
}
|
|
751
|
+
function moveInOrder(order, moved, toIndex) {
|
|
752
|
+
const rest = order.filter((id) => id !== moved);
|
|
753
|
+
const at = Math.max(0, Math.min(Math.trunc(toIndex), rest.length));
|
|
754
|
+
return [...rest.slice(0, at), moved, ...rest.slice(at)];
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// src/placement.ts
|
|
758
|
+
function keptOutOfSight(placement) {
|
|
759
|
+
return placement?.kept_by_the_app === true;
|
|
760
|
+
}
|
|
761
|
+
function offeredAsContext(placement) {
|
|
762
|
+
return placement?.offered_as_context === true;
|
|
763
|
+
}
|
|
764
|
+
function withTablePlacement(tables, facts) {
|
|
765
|
+
if (!facts) return [...tables];
|
|
766
|
+
const byId = new Map(facts.map((f) => [f.table_id, f]));
|
|
767
|
+
return tables.map((table) => {
|
|
768
|
+
const fact = byId.get(table.id);
|
|
769
|
+
if (!fact || fact.kept_by_the_app === void 0) return table;
|
|
770
|
+
return {
|
|
771
|
+
...table,
|
|
772
|
+
kept_by_the_app: fact.kept_by_the_app,
|
|
773
|
+
kept_for: fact.kept_for ?? null,
|
|
774
|
+
offered_as_context: fact.offered_as_context ?? false,
|
|
775
|
+
keeper_group: fact.keeper_group ?? null,
|
|
776
|
+
keeper_says: fact.keeper_says ?? null,
|
|
777
|
+
used_in_kind: fact.used_in_kind ?? null,
|
|
778
|
+
used_in_id: fact.used_in_id ?? null,
|
|
779
|
+
used_in_table_id: fact.used_in_table_id ?? null
|
|
780
|
+
};
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
function keptGroups(tables) {
|
|
784
|
+
const out = [];
|
|
785
|
+
const at = /* @__PURE__ */ new Map();
|
|
786
|
+
for (const table of tables) {
|
|
787
|
+
if (!keptOutOfSight(table)) continue;
|
|
788
|
+
const group = table.keeper_group?.trim() || "Kept by the app";
|
|
789
|
+
let i = at.get(group);
|
|
790
|
+
if (i === void 0) {
|
|
791
|
+
i = out.length;
|
|
792
|
+
at.set(group, i);
|
|
793
|
+
out.push({ group, tables: [] });
|
|
794
|
+
}
|
|
795
|
+
out[i].tables.push(table);
|
|
796
|
+
}
|
|
797
|
+
return out;
|
|
798
|
+
}
|
|
799
|
+
function keptTableHref(fact, hrefs) {
|
|
800
|
+
if (fact.used_in_kind === "scope" && fact.used_in_id) return hrefs.scope(fact.used_in_id);
|
|
801
|
+
if (fact.used_in_kind === "table" && (fact.used_in_table_id || fact.used_in_id)) {
|
|
802
|
+
return hrefs.table(fact.used_in_table_id || fact.used_in_id);
|
|
803
|
+
}
|
|
804
|
+
return hrefs.table(fact.table_id);
|
|
805
|
+
}
|
|
657
806
|
|
|
658
807
|
// src/capture-queue.ts
|
|
659
808
|
var DB_NAME = "matrx-capture";
|
|
@@ -941,6 +1090,182 @@ function isRecordsErr(result) {
|
|
|
941
1090
|
var ok = (data) => ({ ok: true, data });
|
|
942
1091
|
var err = (error) => ({ ok: false, error });
|
|
943
1092
|
|
|
1093
|
+
// src/core/pgError.ts
|
|
1094
|
+
var BY_SQLSTATE = {
|
|
1095
|
+
PT409: "stale_write",
|
|
1096
|
+
"42501": "door",
|
|
1097
|
+
"23514": "refused_by_rule",
|
|
1098
|
+
"22004": "invalid_argument",
|
|
1099
|
+
"22023": "invalid_argument",
|
|
1100
|
+
// 22P02 — a value does not fit the type the store holds for it. The class is
|
|
1101
|
+
// real and was hit live: an organization whose copy of a package table grew
|
|
1102
|
+
// `status` as a uuid-valued Field was sent the text "open", and the store
|
|
1103
|
+
// answered `invalid input syntax for type uuid: "open"`. It is the CALL that
|
|
1104
|
+
// is wrong for the shape the store holds, which is what `invalid_argument`
|
|
1105
|
+
// already means — the store's own sentence names the value and the type.
|
|
1106
|
+
"22P02": "invalid_argument",
|
|
1107
|
+
// 42703 — a column that is not there. The store raises it from
|
|
1108
|
+
// `custom.entity_table`, which is asked for a column by NAME, so the class is
|
|
1109
|
+
// exactly "the call named something the shape does not have": the same thing
|
|
1110
|
+
// `invalid_argument` already means, and the store's own sentence names the
|
|
1111
|
+
// column. Added 2026-09-20 (lane FORMS) because the package's live-door suite
|
|
1112
|
+
// caught it raised by a door this package did not know about — which is the
|
|
1113
|
+
// suite working, and is why the map is a census rather than a guess.
|
|
1114
|
+
"42703": "invalid_argument",
|
|
1115
|
+
// 22007 — a date or a time the store could not read as one. It is raised by
|
|
1116
|
+
// `custom.dashboard_window_sql`, which is handed a window a caller wrote
|
|
1117
|
+
// ("last 30 days", a literal date), so the class is again "the call named
|
|
1118
|
+
// something the shape does not accept" and the store's own sentence names the
|
|
1119
|
+
// text it could not read. Added 2026-09-20 (lane SCREEN-BREAK) after the
|
|
1120
|
+
// live-door census caught it — the same way 42703 arrived, which is the
|
|
1121
|
+
// census working rather than a guess.
|
|
1122
|
+
"22007": "invalid_argument",
|
|
1123
|
+
// 22003 — a number the store could not hold at the size it was handed. It is
|
|
1124
|
+
// raised by `custom.context_resolve`, which is given a window or a depth a
|
|
1125
|
+
// caller wrote, so the class is the same one 22P02, 42703 and 22007 already
|
|
1126
|
+
// are: the CALL named a value the shape does not accept, and the store's own
|
|
1127
|
+
// sentence names the number and the range. Added 2026-09-20 (lane GRID-TWO)
|
|
1128
|
+
// when the live-door census caught the release gate red on it — which is the
|
|
1129
|
+
// census working, and the fourth time it has been the thing that found a new
|
|
1130
|
+
// refusal class rather than a person guessing one.
|
|
1131
|
+
"22003": "invalid_argument",
|
|
1132
|
+
"02000": "not_found",
|
|
1133
|
+
"23503": "missing_reference",
|
|
1134
|
+
"23505": "already_exists",
|
|
1135
|
+
"0A000": "not_supported",
|
|
1136
|
+
"53400": "store_limit",
|
|
1137
|
+
"22012": "store_limit",
|
|
1138
|
+
// 54001 — `custom.record_delete` stops a cascade that nests past sixty-four
|
|
1139
|
+
// levels of containment, because that is a loop somebody built rather than a
|
|
1140
|
+
// hierarchy, and saying so beats recursing until the server runs out of
|
|
1141
|
+
// stack. It is a LIMIT of the store, and the store's own sentence names what
|
|
1142
|
+
// to do about it, so it reads as one.
|
|
1143
|
+
"54001": "store_limit",
|
|
1144
|
+
// 54000 — the grid primitives' organization ceilings (GRID-PRIMITIVES, 2026-09-23):
|
|
1145
|
+
// `custom.action_run` on a selection past its knob, `custom.table_decorate` past the
|
|
1146
|
+
// rule count, `custom.table_from_example` past `custom/example_rows_max`,
|
|
1147
|
+
// `custom.table_webhook_declare` past `custom/table_webhooks_max`, and
|
|
1148
|
+
// `custom.hub_changed_by`. Each names its knob in the hint and writes nothing, so it
|
|
1149
|
+
// reads exactly like 54001: a limit of the store, in the store's own sentence.
|
|
1150
|
+
"54000": "store_limit",
|
|
1151
|
+
// VIS: `custom.has_visibility_at` refuses to answer from a snapshot older
|
|
1152
|
+
// than a write this reader has already seen, rather than returning something
|
|
1153
|
+
// they just lost access to. It is retryable on a fresher connection, which is
|
|
1154
|
+
// a different instruction from every other refusal here.
|
|
1155
|
+
"40001": "stale_read",
|
|
1156
|
+
// 57014 — the store cancelled the statement at its own timeout. Like
|
|
1157
|
+
// `stale_read` and unlike every other refusal here, the call was never
|
|
1158
|
+
// refused on its merits: the same call on a smaller page, or once the
|
|
1159
|
+
// organization's kernel is not being rewritten, can succeed. It gets its own
|
|
1160
|
+
// code so a screen can offer "try again" honestly instead of showing a
|
|
1161
|
+
// failure sentence the caller cannot act on.
|
|
1162
|
+
"57014": "timed_out",
|
|
1163
|
+
// PostgREST's own two: the store is not being SERVED, which is a different
|
|
1164
|
+
// thing from the store refusing. `custom` absent from `pgrst.db_schemas`, or
|
|
1165
|
+
// the grants not copied, land here.
|
|
1166
|
+
PGRST202: "store_not_served",
|
|
1167
|
+
PGRST205: "store_not_served",
|
|
1168
|
+
PGRST301: "door",
|
|
1169
|
+
// PT428 — NOT A FAILURE, and the release gate's live census is what found it
|
|
1170
|
+
// missing: the store raises it and this package answered `internal`, which is
|
|
1171
|
+
// the one classification that tells a screen nothing. A stage gate whose
|
|
1172
|
+
// `on_fail` is `require_approval` files the request and leaves the record
|
|
1173
|
+
// where it was; the transaction is rolled back to the pipeline's own block, so
|
|
1174
|
+
// "nothing was written" is a fact rather than a promise. Landed by lane
|
|
1175
|
+
// STAGE-RULES; mapped here by STAGE-RULES-2 the day after, when the census
|
|
1176
|
+
// caught it — the sixth time that census has been the thing that found a
|
|
1177
|
+
// refusal class rather than a person guessing one.
|
|
1178
|
+
PT428: "needs_approval"
|
|
1179
|
+
};
|
|
1180
|
+
var MAPPED_SQLSTATES = Object.keys(BY_SQLSTATE);
|
|
1181
|
+
function parseDetail(details) {
|
|
1182
|
+
if (!details) return void 0;
|
|
1183
|
+
const trimmed = details.trim();
|
|
1184
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return details;
|
|
1185
|
+
try {
|
|
1186
|
+
return JSON.parse(trimmed);
|
|
1187
|
+
} catch {
|
|
1188
|
+
return details;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
function isNotASqlstate(code) {
|
|
1192
|
+
if (!code) return true;
|
|
1193
|
+
return /^[0-9]{3}$/.test(code);
|
|
1194
|
+
}
|
|
1195
|
+
function mapPgError(error, where) {
|
|
1196
|
+
const raw = error.code ?? void 0;
|
|
1197
|
+
const sqlstate = raw && raw !== "" ? raw : void 0;
|
|
1198
|
+
const mapped = {
|
|
1199
|
+
code: "internal",
|
|
1200
|
+
message: error.message,
|
|
1201
|
+
...error.hint ? { hint: error.hint } : {},
|
|
1202
|
+
...sqlstate ? { sqlstate } : {}
|
|
1203
|
+
};
|
|
1204
|
+
if (isNotASqlstate(sqlstate)) {
|
|
1205
|
+
mapped.code = "unreachable";
|
|
1206
|
+
} else {
|
|
1207
|
+
mapped.code = BY_SQLSTATE[sqlstate] ?? "internal";
|
|
1208
|
+
}
|
|
1209
|
+
const detail = parseDetail(error.details);
|
|
1210
|
+
if (detail !== void 0) mapped.detail = detail;
|
|
1211
|
+
if (mapped.code === "internal") {
|
|
1212
|
+
mapped.unmapped = true;
|
|
1213
|
+
mapped.diagnostic = `@ai-matrx/records did not recognise SQLSTATE ${sqlstate ?? "(none)"} from ${where}; the store's own message is the thing to act on.`;
|
|
1214
|
+
} else if (mapped.code === "unreachable") {
|
|
1215
|
+
mapped.unmapped = true;
|
|
1216
|
+
mapped.diagnostic = `@ai-matrx/records never reached the store from ${where}: ${raw ? `the transport answered ${raw}` : "no response"} \u2014 ${error.message}`;
|
|
1217
|
+
mapped.message = "We could not reach your data.";
|
|
1218
|
+
delete mapped.hint;
|
|
1219
|
+
}
|
|
1220
|
+
return mapped;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// src/relation.ts
|
|
1224
|
+
var ENTITY_REF_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1225
|
+
function isRefLike(value) {
|
|
1226
|
+
return typeof value === "object" && value !== null && "token" in value && "id" in value;
|
|
1227
|
+
}
|
|
1228
|
+
function entityRefsOf(value) {
|
|
1229
|
+
const items = Array.isArray(value) ? value : value == null ? [] : [value];
|
|
1230
|
+
const out = [];
|
|
1231
|
+
for (const item of items) {
|
|
1232
|
+
if (!isRefLike(item)) continue;
|
|
1233
|
+
const token = String(item.token ?? "").trim().toLowerCase();
|
|
1234
|
+
const id = String(item.id ?? "").trim();
|
|
1235
|
+
if (!token || !ENTITY_REF_ID.test(id)) continue;
|
|
1236
|
+
const label = item.label;
|
|
1237
|
+
out.push({ token, id: id.toLowerCase(), label: typeof label === "string" ? label : null });
|
|
1238
|
+
}
|
|
1239
|
+
return out;
|
|
1240
|
+
}
|
|
1241
|
+
function entityRefsToWrite(value, multi) {
|
|
1242
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1243
|
+
const refs = [];
|
|
1244
|
+
for (const ref of entityRefsOf(value)) {
|
|
1245
|
+
const k = `${ref.token}:${ref.id}`;
|
|
1246
|
+
if (seen.has(k)) continue;
|
|
1247
|
+
seen.add(k);
|
|
1248
|
+
refs.push({ token: ref.token, id: ref.id });
|
|
1249
|
+
}
|
|
1250
|
+
if (multi) return refs;
|
|
1251
|
+
return refs[0] ?? null;
|
|
1252
|
+
}
|
|
1253
|
+
async function entityReferenceKinds(source) {
|
|
1254
|
+
const { data, error } = await source.rpc("entity_reference_kinds", {}, { schema: "custom" });
|
|
1255
|
+
if (error) return err(mapPgError(error, "entityReferenceKinds"));
|
|
1256
|
+
return ok(Array.isArray(data) ? data : []);
|
|
1257
|
+
}
|
|
1258
|
+
async function entityReferenceWords(source, organizationId, refs) {
|
|
1259
|
+
if (refs.length === 0) return ok([]);
|
|
1260
|
+
const { data, error } = await source.rpc(
|
|
1261
|
+
"entity_reference_words",
|
|
1262
|
+
{ p_organization_id: organizationId, p_refs: refs.map((r) => ({ token: r.token, id: r.id })) },
|
|
1263
|
+
{ schema: "custom" }
|
|
1264
|
+
);
|
|
1265
|
+
if (error) return err(mapPgError(error, "entityReferenceWords"));
|
|
1266
|
+
return ok(entityRefsOf(data));
|
|
1267
|
+
}
|
|
1268
|
+
|
|
944
1269
|
// src/ops.ts
|
|
945
1270
|
var REMEMBER_MS = 3e4;
|
|
946
1271
|
var REMEMBER_MAX = 500;
|
|
@@ -1654,6 +1979,7 @@ var STORE_DOORS = [
|
|
|
1654
1979
|
{ name: "table_work_kind", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
|
|
1655
1980
|
{ name: "tables_at_home", args: "p_organization_id uuid, p_home_ids uuid[]", returns: "TABLE(table_id uuid, home_record_id uuid, kind text)", security: "definer" },
|
|
1656
1981
|
{ name: "tables_described_without_asking", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
|
|
1982
|
+
{ name: "tables_i_can_open", args: "", returns: "TABLE(table_id uuid, table_name text, organization_id uuid, organization_name text, member boolean, visibility text, updated_at timestamp with time zone)", security: "definer" },
|
|
1657
1983
|
{ name: "tables_shared_with_me", args: "", returns: "TABLE(table_id uuid, organization_id uuid, organization text, table_name text, level text, level_label text, shared_at timestamp with time zone, opens boolean, say text)", security: "definer" },
|
|
1658
1984
|
{ name: "trg_associations_bump_visibility", args: "", returns: "trigger", security: "definer" },
|
|
1659
1985
|
{ name: "undeclared_keys", args: "p_organization_id uuid, p_table_id uuid, p_data jsonb", returns: "text[]", security: "invoker" },
|
|
@@ -1678,6 +2004,7 @@ var STORE_DOORS = [
|
|
|
1678
2004
|
{ name: "visible_predicate_sql", args: "p_user uuid, p_organization_id uuid, p_table_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level, p_alias text DEFAULT 'r'::text", returns: "text", security: "definer" },
|
|
1679
2005
|
{ name: "visible_record_ids", args: "p_user_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level", returns: "TABLE(id uuid)", security: "definer" },
|
|
1680
2006
|
{ name: "visible_set", args: "p_user uuid, p_organization_id uuid, p_table_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level, OUT o_all_visible boolean, OUT o_true_visibility platform.visibility[], OUT o_granted_all uuid[], OUT o_granted_visible uuid[], OUT o_carried_visible uuid[], OUT o_ladder_calls integer, OUT o_fallback boolean, OUT o_note text", returns: "record", security: "definer" },
|
|
2007
|
+
{ name: "where_id_opens", args: "p_id uuid", returns: "jsonb", security: "definer" },
|
|
1681
2008
|
{ name: "widget_kernel_id", args: "", returns: "uuid", security: "invoker" },
|
|
1682
2009
|
{ name: "withheld_marker", args: "p_mask jsonb, p_key text", returns: "jsonb", security: "invoker" },
|
|
1683
2010
|
{ name: "withheld_sentence", args: "p_mask jsonb, p_key text", returns: "text", security: "invoker" },
|
|
@@ -1784,7 +2111,7 @@ var STORE_REFUSAL_CODES = [
|
|
|
1784
2111
|
{ code: "23505", raised_by: "_share_write_person,_unique_rule_holds,doc_sign,doc_signature_write,entity_field_declare,field_declare,home_add,inbound_declare,io_proposal_accept,relation_carry,relation_own,sign_request_cancel,sign_request_create,table_share_outside_resend,work_approval_decide,work_slot_hold" },
|
|
1785
2112
|
{ code: "23514", raised_by: "_checklist_instantiate,_checklist_step_guard,_containment_guard,_dated_values_guard,_derived_fields,_display_format_check,_display_spec_for,_entity_custom_fields_guard,_field_class_guard,_field_document_for,_field_shape_guard,_field_type_parity_guard,_merge_field_shape_guard,_merge_field_temporal_guard,_promoted_field_cap_guard,_record_rule_uses,_relation_halves_agree,_relation_kernel_targets,_resolve_choice_words,_rule_shape_guard,_rule_topology_guard,_store_relation_edge_names_its_field,_table_columns_word_guard,_table_shape_guard,_undeclared_key_guard,_value_envelope,_with_display,_work_shape_guard,_workdoors_approval_guard,action_run,assert_columns_are_defined,assert_entity_is_organization_scoped,booking_declare,capture_publish,capture_sheet_declare,checklist_declare,checklist_step_complete,doc_sign,doc_signature_write,doc_template_save,entity_field_declare,entity_field_retire,entity_field_update,entity_records_find,entity_table,field_declare,field_retire,field_update,home_add,io_comment_write,io_import_rows,migrate_merge,migrate_purge_hard,portal_archive,portal_restore,record_write_graph,relation_carry,relation_halves_repair,relation_own,sign_request_create,sign_request_sign,table_declare,table_from_example,validate_value_envelope,validate_values,work_set_state,work_slots_declare,work_take_assignment,work_template_instantiate" },
|
|
1786
2113
|
{ code: "40001", raised_by: "has_visibility_at" },
|
|
1787
|
-
{ code: "42501", raised_by: "_doc_render_immutable,_doc_signature_immutable,_field_definition_write,_field_write_door,_rule_definition_write,_store_door,agent_table_claim,anon_capture,anon_inbound_land,anon_publish,anon_token_issue,anon_token_verify,anon_write,assert_client_may_change,assert_client_may_open,assert_client_may_reach,assert_may_know_table,assert_organization_admin,assert_store_door,booking_confirm,booking_declare,booking_hold,capture_submit,checklist_run,comment_write,conversation_scope_bind,conversation_scope_unbind,doc_sign,enrich_declare,enrich_due,enrich_land,enrich_normalize,entity_field_declare,entity_field_retire,entity_field_update,entity_value_write,external_write_through,form_declare,form_submit,inbound_mail_land,io_comment_resolve,io_comment_write,io_import_begin,io_import_finish,io_restore,migrate_purge,migrate_purge_hard,migrate_purge_hard_request,migrate_reclass,my_levels,organization_clear,portal_declare,portal_invitation,portal_invite,portal_invite_accept,portal_principal_bind,promote_table,query_visibility_parity,read_record,read_records,read_records_archived,read_records_by_ids,read_records_matching,record_table,record_write_graph,relation_halves_disagreements,relation_halves_repair,share_grant,subscription_mute,subscription_preview,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,table_webhook_declare,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_person" },
|
|
2114
|
+
{ code: "42501", raised_by: "_doc_render_immutable,_doc_signature_immutable,_field_definition_write,_field_write_door,_rule_definition_write,_store_door,agent_table_claim,anon_capture,anon_inbound_land,anon_publish,anon_token_issue,anon_token_verify,anon_write,assert_client_may_change,assert_client_may_open,assert_client_may_reach,assert_may_know_table,assert_organization_admin,assert_store_door,booking_confirm,booking_declare,booking_hold,capture_submit,checklist_run,comment_write,conversation_scope_bind,conversation_scope_unbind,doc_sign,enrich_declare,enrich_due,enrich_land,enrich_normalize,entity_field_declare,entity_field_retire,entity_field_update,entity_value_write,external_write_through,form_declare,form_submit,inbound_mail_land,io_comment_resolve,io_comment_write,io_import_begin,io_import_finish,io_restore,migrate_purge,migrate_purge_hard,migrate_purge_hard_request,migrate_reclass,my_levels,organization_clear,organization_contents,portal_declare,portal_invitation,portal_invite,portal_invite_accept,portal_principal_bind,promote_table,query_visibility_parity,read_record,read_records,read_records_archived,read_records_by_ids,read_records_matching,record_table,record_write_graph,relation_halves_disagreements,relation_halves_repair,share_grant,subscription_mute,subscription_preview,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,table_webhook_declare,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_person" },
|
|
1788
2115
|
{ code: "42703", raised_by: "entity_table,portal_declare" },
|
|
1789
2116
|
{ code: "53400", raised_by: "anon_rate_take,delete_cascade_closure,enrich_due,enrich_land,promote_field" },
|
|
1790
2117
|
{ code: "54000", raised_by: "action_run,hub_changed_by,table_decorate,table_from_example,table_webhook_declare" },
|