@ai-matrx/records 0.57.3 → 0.58.1
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 +122 -0
- package/dist/core/index.cjs +733 -154
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +295 -7
- package/dist/core/index.d.ts +295 -7
- package/dist/core/index.js +733 -154
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +395 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +887 -197
- package/dist/index.d.ts +887 -197
- package/dist/index.js +395 -5
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +536 -33
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1096 -191
- package/dist/react/index.d.ts +1096 -191
- package/dist/react/index.js +536 -33
- 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/react/index.cjs
CHANGED
|
@@ -2222,6 +2222,7 @@ __export(react_exports, {
|
|
|
2222
2222
|
PERMISSION_LEVELS: () => PERMISSION_LEVELS,
|
|
2223
2223
|
PER_VALUE_ACCESS_WORDS: () => PER_VALUE_ACCESS_WORDS,
|
|
2224
2224
|
PIPELINE_RULE_KINDS: () => PIPELINE_RULE_KINDS,
|
|
2225
|
+
PORTAL_ACCENTS: () => PORTAL_ACCENTS,
|
|
2225
2226
|
PORTAL_ARCHIVE_FILTERS: () => PORTAL_ARCHIVE_FILTERS,
|
|
2226
2227
|
REFUSALS_WORTH_REPEATING: () => REFUSALS_WORTH_REPEATING,
|
|
2227
2228
|
RELATION_BINDINGS: () => RELATION_BINDINGS,
|
|
@@ -2257,6 +2258,11 @@ __export(react_exports, {
|
|
|
2257
2258
|
coercionLabel: () => coercionLabel,
|
|
2258
2259
|
emptyArchiveLine: () => emptyArchiveLine,
|
|
2259
2260
|
emptyPortalArchiveLine: () => emptyPortalArchiveLine,
|
|
2261
|
+
entityReferenceKinds: () => entityReferenceKinds,
|
|
2262
|
+
entityReferenceKindsOf: () => entityReferenceKindsOf,
|
|
2263
|
+
entityReferenceWords: () => entityReferenceWords,
|
|
2264
|
+
entityRefsOf: () => entityRefsOf,
|
|
2265
|
+
entityRefsToWrite: () => entityRefsToWrite,
|
|
2260
2266
|
err: () => err,
|
|
2261
2267
|
exampleSpec: () => exampleSpec,
|
|
2262
2268
|
exportPageXlsx: () => exportPageXlsx,
|
|
@@ -2267,20 +2273,31 @@ __export(react_exports, {
|
|
|
2267
2273
|
indexedDbStore: () => indexedDbStore,
|
|
2268
2274
|
isArchiveLane: () => isArchiveLane,
|
|
2269
2275
|
isDecided: () => isDecided,
|
|
2276
|
+
isEntityReferenceConfig: () => isEntityReferenceConfig,
|
|
2270
2277
|
isOwnOp: () => isOwnOp,
|
|
2278
|
+
isPortalAccent: () => isPortalAccent,
|
|
2271
2279
|
isPortalArchiveFilter: () => isPortalArchiveFilter,
|
|
2272
2280
|
isRecordsErr: () => isRecordsErr,
|
|
2281
|
+
isRuleFilter: () => isRuleFilter,
|
|
2273
2282
|
isTheChosen: () => isTheChosen,
|
|
2283
|
+
keptGroups: () => keptGroups,
|
|
2284
|
+
keptOutOfSight: () => keptOutOfSight,
|
|
2285
|
+
keptTableHref: () => keptTableHref,
|
|
2274
2286
|
looksLikeAnId: () => looksLikeAnId,
|
|
2275
2287
|
mayDrag: () => mayDrag,
|
|
2276
2288
|
measureKey: () => measureKey,
|
|
2277
2289
|
memoryStore: () => memoryStore,
|
|
2278
2290
|
mintClientKey: () => mintClientKey,
|
|
2279
2291
|
mintOpId: () => mintOpId,
|
|
2292
|
+
moveConsequence: () => moveConsequence,
|
|
2293
|
+
moveInOrder: () => moveInOrder,
|
|
2294
|
+
offeredAsContext: () => offeredAsContext,
|
|
2280
2295
|
ok: () => ok,
|
|
2281
2296
|
openCaptureQueue: () => openCaptureQueue,
|
|
2282
2297
|
optionKey: () => optionKey,
|
|
2283
2298
|
optionLabel: () => optionLabel,
|
|
2299
|
+
parseTableHome: () => parseTableHome,
|
|
2300
|
+
parseTableMoved: () => parseTableMoved,
|
|
2284
2301
|
portalArchiveConsequence: () => portalArchiveConsequence,
|
|
2285
2302
|
portalConfirmLine: () => portalConfirmLine,
|
|
2286
2303
|
portalPath: () => portalPath,
|
|
@@ -2290,12 +2307,15 @@ __export(react_exports, {
|
|
|
2290
2307
|
rememberedOpCount: () => rememberedOpCount,
|
|
2291
2308
|
sameDocument: () => sameDocument,
|
|
2292
2309
|
scopeChip: () => scopeChip,
|
|
2310
|
+
sheetSyncSpec: () => sheetSyncSpec,
|
|
2293
2311
|
stableFilterKey: () => stableFilterKey,
|
|
2294
2312
|
tableShapeChanged: () => tableShapeChanged,
|
|
2295
2313
|
useEntityFieldMutation: () => useEntityFieldMutation,
|
|
2296
2314
|
useEntityFieldRights: () => useEntityFieldRights,
|
|
2297
2315
|
useEntityFields: () => useEntityFields,
|
|
2298
2316
|
useEntityRecord: () => useEntityRecord,
|
|
2317
|
+
useEntityReferenceKinds: () => useEntityReferenceKinds,
|
|
2318
|
+
useEntityReferenceWords: () => useEntityReferenceWords,
|
|
2299
2319
|
useEntityTable: () => useEntityTable,
|
|
2300
2320
|
useFieldMutation: () => useFieldMutation,
|
|
2301
2321
|
useFields: () => useFields,
|
|
@@ -2311,7 +2331,9 @@ __export(react_exports, {
|
|
|
2311
2331
|
useRecordsClient: () => useRecordsClient,
|
|
2312
2332
|
useTable: () => useTable,
|
|
2313
2333
|
useTableArchive: () => useTableArchive,
|
|
2314
|
-
useTables: () => useTables
|
|
2334
|
+
useTables: () => useTables,
|
|
2335
|
+
withRowCounts: () => withRowCounts,
|
|
2336
|
+
withTablePlacement: () => withTablePlacement
|
|
2315
2337
|
});
|
|
2316
2338
|
module.exports = __toCommonJS(react_exports);
|
|
2317
2339
|
|
|
@@ -2358,6 +2380,31 @@ function sameDocument(a, b) {
|
|
|
2358
2380
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
2359
2381
|
}
|
|
2360
2382
|
|
|
2383
|
+
// src/aggregate.ts
|
|
2384
|
+
function isRuleFilter(filter) {
|
|
2385
|
+
if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
|
|
2386
|
+
const node = filter;
|
|
2387
|
+
return typeof node.op === "string" && Array.isArray(node.args);
|
|
2388
|
+
}
|
|
2389
|
+
function measureKey(measure) {
|
|
2390
|
+
return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
|
|
2391
|
+
}
|
|
2392
|
+
function stableFilterKey(filter) {
|
|
2393
|
+
if (!filter) return "{}";
|
|
2394
|
+
if (isRuleFilter(filter)) return JSON.stringify(filter);
|
|
2395
|
+
const keys = Object.keys(filter).sort();
|
|
2396
|
+
if (keys.length === 0) return "{}";
|
|
2397
|
+
const parts = keys.map((key) => {
|
|
2398
|
+
const value = filter[key];
|
|
2399
|
+
if (value !== null && typeof value === "object") {
|
|
2400
|
+
const window2 = value;
|
|
2401
|
+
return `${JSON.stringify(key)}:{"from":${JSON.stringify(window2.from ?? null)},"to":${JSON.stringify(window2.to ?? null)}}`;
|
|
2402
|
+
}
|
|
2403
|
+
return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
|
|
2404
|
+
});
|
|
2405
|
+
return `{${parts.join(",")}}`;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2361
2408
|
// src/ops.ts
|
|
2362
2409
|
var REMEMBER_MS = 3e4;
|
|
2363
2410
|
var REMEMBER_MAX = 500;
|
|
@@ -2397,6 +2444,116 @@ function rememberedOpCount() {
|
|
|
2397
2444
|
return ours.size;
|
|
2398
2445
|
}
|
|
2399
2446
|
|
|
2447
|
+
// src/placement.ts
|
|
2448
|
+
function keptOutOfSight(placement) {
|
|
2449
|
+
return placement?.kept_by_the_app === true;
|
|
2450
|
+
}
|
|
2451
|
+
function offeredAsContext(placement) {
|
|
2452
|
+
return placement?.offered_as_context === true;
|
|
2453
|
+
}
|
|
2454
|
+
function withTablePlacement(tables, facts) {
|
|
2455
|
+
if (!facts) return [...tables];
|
|
2456
|
+
const byId = new Map(facts.map((f) => [f.table_id, f]));
|
|
2457
|
+
return tables.map((table) => {
|
|
2458
|
+
const fact = byId.get(table.id);
|
|
2459
|
+
if (!fact || fact.kept_by_the_app === void 0) return table;
|
|
2460
|
+
return {
|
|
2461
|
+
...table,
|
|
2462
|
+
kept_by_the_app: fact.kept_by_the_app,
|
|
2463
|
+
kept_for: fact.kept_for ?? null,
|
|
2464
|
+
offered_as_context: fact.offered_as_context ?? false,
|
|
2465
|
+
keeper_group: fact.keeper_group ?? null,
|
|
2466
|
+
keeper_says: fact.keeper_says ?? null,
|
|
2467
|
+
used_in_kind: fact.used_in_kind ?? null,
|
|
2468
|
+
used_in_id: fact.used_in_id ?? null,
|
|
2469
|
+
used_in_table_id: fact.used_in_table_id ?? null
|
|
2470
|
+
};
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
function keptGroups(tables) {
|
|
2474
|
+
const out = [];
|
|
2475
|
+
const at = /* @__PURE__ */ new Map();
|
|
2476
|
+
for (const table of tables) {
|
|
2477
|
+
if (!keptOutOfSight(table)) continue;
|
|
2478
|
+
const group = table.keeper_group?.trim() || "Kept by the app";
|
|
2479
|
+
let i = at.get(group);
|
|
2480
|
+
if (i === void 0) {
|
|
2481
|
+
i = out.length;
|
|
2482
|
+
at.set(group, i);
|
|
2483
|
+
out.push({ group, tables: [] });
|
|
2484
|
+
}
|
|
2485
|
+
out[i].tables.push(table);
|
|
2486
|
+
}
|
|
2487
|
+
return out;
|
|
2488
|
+
}
|
|
2489
|
+
function keptTableHref(fact, hrefs) {
|
|
2490
|
+
if (fact.used_in_kind === "scope" && fact.used_in_id) return hrefs.scope(fact.used_in_id);
|
|
2491
|
+
if (fact.used_in_kind === "table" && (fact.used_in_table_id || fact.used_in_id)) {
|
|
2492
|
+
return hrefs.table(fact.used_in_table_id || fact.used_in_id);
|
|
2493
|
+
}
|
|
2494
|
+
return hrefs.table(fact.table_id);
|
|
2495
|
+
}
|
|
2496
|
+
function countOf(value) {
|
|
2497
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2498
|
+
}
|
|
2499
|
+
function wordsOf(value) {
|
|
2500
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
2501
|
+
}
|
|
2502
|
+
function parseTableHome(raw) {
|
|
2503
|
+
if (!raw || typeof raw !== "object") return null;
|
|
2504
|
+
const row = raw;
|
|
2505
|
+
const table = row.table;
|
|
2506
|
+
const org = row.organization;
|
|
2507
|
+
if (!table || !org || !wordsOf(table.id) || !wordsOf(org.id) || !wordsOf(org.name)) return null;
|
|
2508
|
+
const carries = row.carries ?? {};
|
|
2509
|
+
const destinations = Array.isArray(row.destinations) ? row.destinations : [];
|
|
2510
|
+
return {
|
|
2511
|
+
table: { id: String(table.id), name: wordsOf(table.name) ?? "This table", version: countOf(table.version) },
|
|
2512
|
+
organization: { id: String(org.id), name: String(org.name) },
|
|
2513
|
+
mayMove: row.may_move === true,
|
|
2514
|
+
whyNot: wordsOf(row.why_not),
|
|
2515
|
+
heldBy: Array.isArray(row.held_by) ? row.held_by.filter((s) => typeof s === "string") : [],
|
|
2516
|
+
destinations: destinations.filter((d) => !!d && typeof d === "object" && !!wordsOf(d.id)).map((d) => ({
|
|
2517
|
+
id: String(d.id),
|
|
2518
|
+
name: wordsOf(d.name) ?? "An organization",
|
|
2519
|
+
role: wordsOf(d.role) ?? "member",
|
|
2520
|
+
ok: d.ok === true,
|
|
2521
|
+
why: wordsOf(d.why)
|
|
2522
|
+
})),
|
|
2523
|
+
carries: {
|
|
2524
|
+
fields: countOf(carries.fields),
|
|
2525
|
+
records: countOf(carries.records),
|
|
2526
|
+
inTrash: countOf(carries.in_trash),
|
|
2527
|
+
choiceLists: countOf(carries.choice_lists),
|
|
2528
|
+
withIt: countOf(carries.with_it),
|
|
2529
|
+
tablesInside: countOf(carries.tables_inside),
|
|
2530
|
+
linksAcross: countOf(carries.links_across)
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
function parseTableMoved(raw) {
|
|
2535
|
+
const row = raw ?? {};
|
|
2536
|
+
const to = row.to ?? {};
|
|
2537
|
+
const from = row.from ?? {};
|
|
2538
|
+
const table = row.table ?? {};
|
|
2539
|
+
if (row.moved !== true || !wordsOf(to.id)) return null;
|
|
2540
|
+
return {
|
|
2541
|
+
to: { id: String(to.id), name: wordsOf(to.name) ?? "the new organization" },
|
|
2542
|
+
from: { id: wordsOf(from.id) ?? "", name: wordsOf(from.name) ?? "its old organization" },
|
|
2543
|
+
tableName: wordsOf(table.name) ?? "The table"
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
function plural(n, one, many) {
|
|
2547
|
+
return `${n} ${n === 1 ? one : many}`;
|
|
2548
|
+
}
|
|
2549
|
+
function moveConsequence(home, to) {
|
|
2550
|
+
const c = home.carries;
|
|
2551
|
+
const parts = [plural(c.fields, "column", "columns"), plural(c.records, "row", "rows")];
|
|
2552
|
+
if (c.inTrash > 0) parts.push(`${c.inTrash} in the trash`);
|
|
2553
|
+
const extra = c.choiceLists + c.withIt;
|
|
2554
|
+
return `${home.table.name} moves to ${to.name} with its ${parts.join(", ")}` + (c.tablesInside > 0 ? `, the ${plural(c.tablesInside, "table", "tables")} that live${c.tablesInside === 1 ? "s" : ""} inside it or its rows (with their own rows)` : "") + (extra > 0 ? `, and ${plural(extra, "thing", "things")} built only on it (choice lists, rules, dashboards, templates)` : "") + `, its comments, forms, saved views and history. ` + (c.linksAcross > 0 ? `${plural(c.linksAcross, "link", "links")} to rows that stay in ${home.organization.name} keep${c.linksAcross === 1 ? "s" : ""} pointing there, across the two organizations. ` : "") + `People who see it only because they are in ${home.organization.name} stop seeing it; people it was shared with by name keep it. You can move it back from the same place.`;
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2400
2557
|
// src/level.ts
|
|
2401
2558
|
var PERMISSION_LEVELS = [
|
|
2402
2559
|
"viewer",
|
|
@@ -2513,6 +2670,51 @@ function recordChangeTrigger(tableId, options = {}) {
|
|
|
2513
2670
|
...options.changedFields && options.changedFields.length > 0 ? { changed_fields: options.changedFields } : {}
|
|
2514
2671
|
};
|
|
2515
2672
|
}
|
|
2673
|
+
function sheetSyncSpec(args) {
|
|
2674
|
+
const [header = [], ...body] = args.cells;
|
|
2675
|
+
const columns = header.map((c, i) => {
|
|
2676
|
+
const name = c == null ? "" : String(c).trim();
|
|
2677
|
+
return name === "" ? `Column ${i + 1}` : name;
|
|
2678
|
+
});
|
|
2679
|
+
if (columns.length === 0) {
|
|
2680
|
+
throw new Error("The sheet has no header row, so there are no columns to sync. Nothing was sent.");
|
|
2681
|
+
}
|
|
2682
|
+
const seenCol = /* @__PURE__ */ new Set();
|
|
2683
|
+
for (const c of columns) {
|
|
2684
|
+
if (seenCol.has(c)) throw new Error(`The sheet has two columns named "${c}". Rename one and sync again.`);
|
|
2685
|
+
seenCol.add(c);
|
|
2686
|
+
}
|
|
2687
|
+
const refIdx = args.refColumn == null ? -1 : columns.indexOf(args.refColumn);
|
|
2688
|
+
if (args.refColumn != null && refIdx < 0) {
|
|
2689
|
+
throw new Error(`The id column "${args.refColumn}" is not in the sheet's header. Nothing was sent.`);
|
|
2690
|
+
}
|
|
2691
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2692
|
+
const rows = [];
|
|
2693
|
+
body.forEach((cells, i) => {
|
|
2694
|
+
if (cells.every((v) => v == null || String(v).trim() === "")) return;
|
|
2695
|
+
const ref = refIdx >= 0 ? String(cells[refIdx] ?? "").trim() : `row-${i + 2}`;
|
|
2696
|
+
if (ref === "") throw new Error(`Sheet row ${i + 2} has no value in the id column "${args.refColumn}".`);
|
|
2697
|
+
if (seen.has(ref)) throw new Error(`Two sheet rows share the id "${ref}"; each row needs its own.`);
|
|
2698
|
+
seen.add(ref);
|
|
2699
|
+
const values = {};
|
|
2700
|
+
columns.forEach((c, j) => {
|
|
2701
|
+
const v = cells[j];
|
|
2702
|
+
values[c] = v === void 0 || v === "" ? null : v;
|
|
2703
|
+
});
|
|
2704
|
+
rows.push({ ref, values });
|
|
2705
|
+
});
|
|
2706
|
+
return { source: args.source, table_name: args.tableName, columns, rows };
|
|
2707
|
+
}
|
|
2708
|
+
function withRowCounts(tables, counts) {
|
|
2709
|
+
if (!counts) return [...tables];
|
|
2710
|
+
const byId = new Map(counts.map((c) => [c.table_id, Number(c.visible_rows)]));
|
|
2711
|
+
return tables.map((t) => byId.has(t.id) ? { ...t, row_count: byId.get(t.id) } : t);
|
|
2712
|
+
}
|
|
2713
|
+
function moveInOrder(order, moved, toIndex) {
|
|
2714
|
+
const rest = order.filter((id) => id !== moved);
|
|
2715
|
+
const at = Math.max(0, Math.min(Math.trunc(toIndex), rest.length));
|
|
2716
|
+
return [...rest.slice(0, at), moved, ...rest.slice(at)];
|
|
2717
|
+
}
|
|
2516
2718
|
|
|
2517
2719
|
// src/store.generated.ts
|
|
2518
2720
|
var ACTOR_VOCABULARY = ["user", "agent", "system"];
|
|
@@ -3188,6 +3390,7 @@ var STORE_DOORS = [
|
|
|
3188
3390
|
{ name: "table_work_kind", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
|
|
3189
3391
|
{ 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" },
|
|
3190
3392
|
{ name: "tables_described_without_asking", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
|
|
3393
|
+
{ 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" },
|
|
3191
3394
|
{ 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" },
|
|
3192
3395
|
{ name: "trg_associations_bump_visibility", args: "", returns: "trigger", security: "definer" },
|
|
3193
3396
|
{ name: "undeclared_keys", args: "p_organization_id uuid, p_table_id uuid, p_data jsonb", returns: "text[]", security: "invoker" },
|
|
@@ -3212,6 +3415,7 @@ var STORE_DOORS = [
|
|
|
3212
3415
|
{ 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" },
|
|
3213
3416
|
{ name: "visible_record_ids", args: "p_user_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level", returns: "TABLE(id uuid)", security: "definer" },
|
|
3214
3417
|
{ 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" },
|
|
3418
|
+
{ name: "where_id_opens", args: "p_id uuid", returns: "jsonb", security: "definer" },
|
|
3215
3419
|
{ name: "widget_kernel_id", args: "", returns: "uuid", security: "invoker" },
|
|
3216
3420
|
{ name: "withheld_marker", args: "p_mask jsonb, p_key text", returns: "jsonb", security: "invoker" },
|
|
3217
3421
|
{ name: "withheld_sentence", args: "p_mask jsonb, p_key text", returns: "text", security: "invoker" },
|
|
@@ -3318,7 +3522,7 @@ var STORE_REFUSAL_CODES = [
|
|
|
3318
3522
|
{ 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" },
|
|
3319
3523
|
{ 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" },
|
|
3320
3524
|
{ code: "40001", raised_by: "has_visibility_at" },
|
|
3321
|
-
{ 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" },
|
|
3525
|
+
{ 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" },
|
|
3322
3526
|
{ code: "42703", raised_by: "entity_table,portal_declare" },
|
|
3323
3527
|
{ code: "53400", raised_by: "anon_rate_take,delete_cascade_closure,enrich_due,enrich_land,promote_field" },
|
|
3324
3528
|
{ code: "54000", raised_by: "action_run,hub_changed_by,table_decorate,table_from_example,table_webhook_declare" },
|
|
@@ -4358,6 +4562,8 @@ var ENTITY_TOKENS = [
|
|
|
4358
4562
|
|
|
4359
4563
|
// src/core/doors.ts
|
|
4360
4564
|
var OWED_BY = {
|
|
4565
|
+
table_home: "SC-1' \u2014 matrx-frontend migrations/campaign/sc1p_a_table_says_where_it_lives_and_its_owner_can_move_it.sql (and its grant file), applied by the chair",
|
|
4566
|
+
table_move: "SC-1' / SC-1-TAILS \u2014 sc1p_a_table_says_where_it_lives_and_its_owner_can_move_it.sql, then sc1t_a_table_moves_with_the_tables_inside_it.sql, applied by the chair",
|
|
4361
4567
|
metadata_search: "W5-SRV / W5-AGENT \u2014 the agent surface's eight verbs",
|
|
4362
4568
|
record_aggregate: "W5-SRV / W5-AGENT \u2014 `record_aggregate` is one of the eight verbs",
|
|
4363
4569
|
field_propose: "W5-AGENT \u2014 AGT-4/AGT-8, the proposal and its approvers",
|
|
@@ -4379,6 +4585,20 @@ var OWED_BY = {
|
|
|
4379
4585
|
table_webhook_archive: "GRID-PRIMITIVES G4 \u2014 gridprim_every_row_change_reaches_the_webhook.sql (chair's production apply)",
|
|
4380
4586
|
table_from_example: "GRID-PRIMITIVES G5 \u2014 gridprim_a_table_can_start_from_a_real_example.sql (chair's production apply)",
|
|
4381
4587
|
autonumber_backfill: "GRID-PRIMITIVES G5 \u2014 gridprim_a_table_can_start_from_a_real_example.sql (chair's production apply)",
|
|
4588
|
+
table_list_everywhere: "GRID-PRIMITIVES G9 \u2014 gridprim_every_picker_lists_both_stores.sql (chair's production apply)",
|
|
4589
|
+
table_sync: "GRID-PRIMITIVES G10 \u2014 gridprim_a_synced_sheet_is_one_table_that_refreshes.sql (chair's production apply)",
|
|
4590
|
+
scope_table_provision: "GRID-PRIMITIVES G11 \u2014 gridprim_a_scope_provisions_its_table_in_the_store.sql (chair's production apply)",
|
|
4591
|
+
table_row_counts: "GRID-PRIMITIVES G12 \u2014 gridprim_every_table_counts_its_rows_and_every_row_shows_its_header.sql + its grant file (chair's production apply)",
|
|
4592
|
+
view_record_order_set: "GRID-PRIMITIVES G13 \u2014 gridprim_a_view_keeps_the_order_a_person_dragged.sql + its grant file (chair's production apply)",
|
|
4593
|
+
table_share_outside_grant: "GRID-PRIMITIVES G14 \u2014 gridprim_a_known_outsider_is_granted_at_once.sql + gridprim_a_signed_in_person_may_share_with_a_known_outsider.sql (chair's production apply)",
|
|
4594
|
+
read_records_in_view_order: "GRID-PRIMITIVES G13 \u2014 gridprim_a_view_keeps_the_order_a_person_dragged.sql + its grant file (chair's production apply)",
|
|
4595
|
+
rule_members_visible: "S2-PRIME FILTER-GROUPS \u2014 filtergroups_a_views_nested_question_is_one_where_clause.sql + its grant file (chair's production apply)",
|
|
4596
|
+
record_headers: "GRID-PRIMITIVES G12 \u2014 gridprim_every_table_counts_its_rows_and_every_row_shows_its_header.sql + its grant file (chair's production apply)",
|
|
4597
|
+
pipeline_move_many: "UI-CHAMPIONS S4 \u2014 uichamp_s4_a_selection_moves_and_decides_in_one_call.sql + its grant file (chair's production apply)",
|
|
4598
|
+
work_decide_many: "UI-CHAMPIONS S4 \u2014 uichamp_s4_a_selection_moves_and_decides_in_one_call.sql + its grant file (chair's production apply)",
|
|
4599
|
+
portal_form: "UI-CHAMPIONS S6 \u2014 uichamp_s6_a_portal_carries_its_look_and_its_forms.sql + uichamp_s6_a_signed_in_person_may_open_a_portals_look_and_forms.sql (chair's production apply)",
|
|
4600
|
+
portal_form_submit: "UI-CHAMPIONS S6 \u2014 uichamp_s6_a_portal_carries_its_look_and_its_forms.sql + uichamp_s6_a_signed_in_person_may_open_a_portals_look_and_forms.sql (chair's production apply)",
|
|
4601
|
+
form_preview_asks: "FORMS-FIX-1 \u2014 formsfix1_the_owners_preview_asks_the_store_the_same_question.sql + its grant file (chair's production apply)",
|
|
4382
4602
|
rule_declare: "W1-RULE \u2014 `custom.record_write` writes `data_class = 'record'`, so the ONE write door cannot make a Rule record; declaring a Rule (and therefore a DOOR-18 subscription) needs a door of its own"
|
|
4383
4603
|
};
|
|
4384
4604
|
var TRUST_SCHEMA = "iam";
|
|
@@ -4582,6 +4802,8 @@ var DOORS = {
|
|
|
4582
4802
|
pipelineBoard: "pipeline_board",
|
|
4583
4803
|
pipelineTransitionRefusal: "pipeline_transition_refusal",
|
|
4584
4804
|
pipelineMove: "pipeline_move",
|
|
4805
|
+
/** Lane S4: many cards, one call, a verdict and a version per card. */
|
|
4806
|
+
pipelineMoveMany: "pipeline_move_many",
|
|
4585
4807
|
tableStageField: "table_stage_field",
|
|
4586
4808
|
// STAGE-RULES. A gate can refuse or it can hand the change to the approvals queue; the
|
|
4587
4809
|
// closed list is the store's, the knob is the organization's, and what is WAITING on a
|
|
@@ -4592,6 +4814,7 @@ var DOORS = {
|
|
|
4592
4814
|
pipelinePending: "pipeline_pending",
|
|
4593
4815
|
pipelineGatePreview: "pipeline_gate_preview",
|
|
4594
4816
|
ruleMembers: "rule_members",
|
|
4817
|
+
ruleMembersVisible: "rule_members_visible",
|
|
4595
4818
|
ruleMembership: "rule_membership",
|
|
4596
4819
|
ruleRun: "rule_run",
|
|
4597
4820
|
ruleEval: "rule_eval",
|
|
@@ -4606,6 +4829,12 @@ var DOORS = {
|
|
|
4606
4829
|
// are server-lane doors and a browser never calls them.
|
|
4607
4830
|
forms: "forms",
|
|
4608
4831
|
formDeclare: "form_declare",
|
|
4832
|
+
/**
|
|
4833
|
+
* WHICH QUESTIONS THE OWNER'S PREVIEW ASKS NEXT (lane FORMS-FIX-1). The same store answer a
|
|
4834
|
+
* stranger's form gets (`custom._form_questions_asked` → `custom.rule_eval`), behind the
|
|
4835
|
+
* organization wall and the caller's own rung on the Table — never `rule_eval` from a browser.
|
|
4836
|
+
*/
|
|
4837
|
+
formPreviewAsks: "form_preview_asks",
|
|
4609
4838
|
// PRODUCTS row 14 — "let clients book a 30-minute consult". A booking page IS an
|
|
4610
4839
|
// `anon_form`, so it is opened and closed by `anonPublish` like any other; this is
|
|
4611
4840
|
// the owner's list of them with the numbers that make it worth opening. The
|
|
@@ -4660,11 +4889,22 @@ var DOORS = {
|
|
|
4660
4889
|
// ask, under the same wall and visibility gate as `portals` itself.
|
|
4661
4890
|
portalTables: "portal_tables",
|
|
4662
4891
|
tableFacts: "table_facts",
|
|
4892
|
+
// WHERE A TABLE LIVES, AND MOVING IT (SC-1' / SC-1-TAILS). `table_home` answers only when the
|
|
4893
|
+
// caller may open the Table (custom.where_id_opens) and names its organization FROM THE TABLE;
|
|
4894
|
+
// `table_move` moves it into another organization the caller belongs to, with every Table
|
|
4895
|
+
// inside it, or refuses with one sentence.
|
|
4896
|
+
tableHome: "table_home",
|
|
4897
|
+
tableMove: "table_move",
|
|
4663
4898
|
portalCard: "portal_card",
|
|
4664
4899
|
portalDeclare: "portal_declare",
|
|
4665
4900
|
portalInvite: "portal_invite",
|
|
4666
4901
|
portalRevoke: "portal_revoke",
|
|
4667
4902
|
portalPreview: "portal_preview",
|
|
4903
|
+
// S6 — the CLIENT's two form doors. They are store doors (schema `custom`), called by a
|
|
4904
|
+
// signed-in portal principal, and each refuses anybody who is not a live principal of that
|
|
4905
|
+
// live portal — so, unlike the sign-in pair above, they belong in this table.
|
|
4906
|
+
portalForm: "portal_form",
|
|
4907
|
+
portalFormSubmit: "portal_form_submit",
|
|
4668
4908
|
// ORG-CLEANUP, 2026-09-22 — A PORTAL IS ARCHIVED, NEVER DELETED.
|
|
4669
4909
|
// `portals` keeps its signature and HIDES archived portals (the law's default
|
|
4670
4910
|
// is to hide); `list_portals(org, 'active'|'archived'|'all')` is the
|
|
@@ -4860,6 +5100,8 @@ var DOORS = {
|
|
|
4860
5100
|
workApprovalRequest: "work_approval_request",
|
|
4861
5101
|
workApprovalMayDecide: "work_approval_may_decide",
|
|
4862
5102
|
workApprovalDecide: "work_approval_decide",
|
|
5103
|
+
/** Lane S4: many inbox decisions, one call, a verdict per item. */
|
|
5104
|
+
workDecideMany: "work_decide_many",
|
|
4863
5105
|
workApprovalRead: "work_approval_read",
|
|
4864
5106
|
// PRODUCTS row 13 — checklists and SOP runs.
|
|
4865
5107
|
checklistRefusal: "checklist_refusal",
|
|
@@ -4885,6 +5127,14 @@ var DOORS = {
|
|
|
4885
5127
|
tableFromExample: "table_from_example",
|
|
4886
5128
|
autonumberBackfill: "autonumber_backfill",
|
|
4887
5129
|
ioExport: "io_export",
|
|
5130
|
+
tableListEverywhere: "table_list_everywhere",
|
|
5131
|
+
tableSync: "table_sync",
|
|
5132
|
+
scopeTableProvision: "scope_table_provision",
|
|
5133
|
+
tableRowCounts: "table_row_counts",
|
|
5134
|
+
recordHeaders: "record_headers",
|
|
5135
|
+
viewRecordOrderSet: "view_record_order_set",
|
|
5136
|
+
readRecordsInViewOrder: "read_records_in_view_order",
|
|
5137
|
+
tableShareOutsideGrant: "table_share_outside_grant",
|
|
4888
5138
|
// Declared here BECAUSE they do not exist yet: naming them is what makes the
|
|
4889
5139
|
// absence visible to `pnpm check:store-registry` and to the suite.
|
|
4890
5140
|
metadataSearch: "metadata_search",
|
|
@@ -5288,6 +5538,40 @@ function createRecordsClient(config) {
|
|
|
5288
5538
|
if (!doorExists(DOORS.tableFacts)) return ok(null);
|
|
5289
5539
|
return callDoor(DOORS.tableFacts, { p_organization_id: org }, "tableFacts");
|
|
5290
5540
|
},
|
|
5541
|
+
async tableHome({ table_id }) {
|
|
5542
|
+
const answered = await callDoor(DOORS.tableHome, { p_table_id: table_id }, "tableHome");
|
|
5543
|
+
if (!answered.ok) return answered;
|
|
5544
|
+
if (answered.data === null || answered.data === void 0) return ok(null);
|
|
5545
|
+
const home = parseTableHome(answered.data);
|
|
5546
|
+
if (!home) {
|
|
5547
|
+
const refusal = {
|
|
5548
|
+
code: "not_supported",
|
|
5549
|
+
message: "The record store answered where this table lives in a shape this client cannot read, so nothing is claimed about it.",
|
|
5550
|
+
hint: "Regenerate @ai-matrx/records against the store (pnpm records:generate) \u2014 the door and this client disagree."
|
|
5551
|
+
};
|
|
5552
|
+
scream({ code: refusal.code, message: refusal.message, ...refusal.hint ? { hint: refusal.hint } : {}, where: "tableHome" });
|
|
5553
|
+
return err(refusal);
|
|
5554
|
+
}
|
|
5555
|
+
return ok(home);
|
|
5556
|
+
},
|
|
5557
|
+
async tableMove({ table_id, to_organization_id, expected_version }) {
|
|
5558
|
+
const answered = await callDoor(
|
|
5559
|
+
DOORS.tableMove,
|
|
5560
|
+
{ p_table_id: table_id, p_to_organization_id: to_organization_id, p_expected_version: expected_version ?? null },
|
|
5561
|
+
"tableMove"
|
|
5562
|
+
);
|
|
5563
|
+
if (!answered.ok) return answered;
|
|
5564
|
+
const moved = parseTableMoved(answered.data);
|
|
5565
|
+
if (!moved) {
|
|
5566
|
+
const refusal = {
|
|
5567
|
+
code: "not_supported",
|
|
5568
|
+
message: "The record store answered the move in a shape this client cannot read. Look where the table lives before trying again."
|
|
5569
|
+
};
|
|
5570
|
+
scream({ code: refusal.code, message: refusal.message, where: "tableMove" });
|
|
5571
|
+
return err(refusal);
|
|
5572
|
+
}
|
|
5573
|
+
return ok(moved);
|
|
5574
|
+
},
|
|
5291
5575
|
async tableArchived({ table_id }) {
|
|
5292
5576
|
const kernel = await callDoor(DOORS.tableKernelId, {}, "tableArchived.kernel");
|
|
5293
5577
|
if (!kernel.ok) return err(kernel.error);
|
|
@@ -5664,10 +5948,11 @@ function createRecordsClient(config) {
|
|
|
5664
5948
|
"pipelineRead"
|
|
5665
5949
|
);
|
|
5666
5950
|
},
|
|
5667
|
-
async pipelineBoard({ table_id, measure }) {
|
|
5951
|
+
async pipelineBoard({ table_id, measure, filter }) {
|
|
5952
|
+
const asked = filter && stableFilterKey(filter) !== "{}";
|
|
5668
5953
|
return callDoor(
|
|
5669
5954
|
DOORS.pipelineBoard,
|
|
5670
|
-
{ p_organization_id: org, p_table_id: table_id, p_measure: measure ?? null },
|
|
5955
|
+
asked ? { p_organization_id: org, p_table_id: table_id, p_measure: measure ?? null, p_filter: filter } : { p_organization_id: org, p_table_id: table_id, p_measure: measure ?? null },
|
|
5671
5956
|
"pipelineBoard"
|
|
5672
5957
|
);
|
|
5673
5958
|
},
|
|
@@ -5691,6 +5976,13 @@ function createRecordsClient(config) {
|
|
|
5691
5976
|
"pipelineMove"
|
|
5692
5977
|
);
|
|
5693
5978
|
},
|
|
5979
|
+
async pipelineMoveMany({ moves }) {
|
|
5980
|
+
return callDoor(
|
|
5981
|
+
DOORS.pipelineMoveMany,
|
|
5982
|
+
{ p_organization_id: org, p_moves: moves },
|
|
5983
|
+
"pipelineMoveMany"
|
|
5984
|
+
);
|
|
5985
|
+
},
|
|
5694
5986
|
async pipelineDeclare({ table_id, spec }) {
|
|
5695
5987
|
return callDoor(
|
|
5696
5988
|
DOORS.pipelineDeclare,
|
|
@@ -5740,6 +6032,18 @@ function createRecordsClient(config) {
|
|
|
5740
6032
|
"pipelineGatePreview"
|
|
5741
6033
|
);
|
|
5742
6034
|
},
|
|
6035
|
+
async ruleMembersVisible({ rule_id, limit = 200, offset = 0 }) {
|
|
6036
|
+
const door = await callDoor(
|
|
6037
|
+
DOORS.ruleMembersVisible,
|
|
6038
|
+
{ p_organization_id: org, p_rule_id: rule_id, p_limit: limit, p_offset: offset },
|
|
6039
|
+
"ruleMembersVisible"
|
|
6040
|
+
);
|
|
6041
|
+
if (!door.ok) return err(door.error);
|
|
6042
|
+
return ok((door.data ?? []).map((row) => {
|
|
6043
|
+
const { document, hidden } = unfold(row.document);
|
|
6044
|
+
return { id: row.id, document, level: row.level, hidden };
|
|
6045
|
+
}));
|
|
6046
|
+
},
|
|
5743
6047
|
async ruleMembers({ rule_id }) {
|
|
5744
6048
|
return callDoor(
|
|
5745
6049
|
DOORS.ruleMembers,
|
|
@@ -5792,6 +6096,13 @@ function createRecordsClient(config) {
|
|
|
5792
6096
|
"bookingDeclare"
|
|
5793
6097
|
);
|
|
5794
6098
|
},
|
|
6099
|
+
async formPreviewAsks({ table_id, questions, values }) {
|
|
6100
|
+
return callDoor(
|
|
6101
|
+
DOORS.formPreviewAsks,
|
|
6102
|
+
{ p_organization_id: org, p_table_id: table_id, p_questions: questions, p_values: values },
|
|
6103
|
+
"formPreviewAsks"
|
|
6104
|
+
);
|
|
6105
|
+
},
|
|
5795
6106
|
async formDeclare(args) {
|
|
5796
6107
|
return callDoor(
|
|
5797
6108
|
DOORS.formDeclare,
|
|
@@ -5967,11 +6278,33 @@ function createRecordsClient(config) {
|
|
|
5967
6278
|
p_tables: args.tables,
|
|
5968
6279
|
p_portal_id: args.portal_id ?? null,
|
|
5969
6280
|
p_slug: args.slug ?? null,
|
|
5970
|
-
p_sign_in_method: args.sign_in_method ?? "magic_link"
|
|
6281
|
+
p_sign_in_method: args.sign_in_method ?? "magic_link",
|
|
6282
|
+
// S6: sent only when given, so a caller that says nothing about the look keeps it.
|
|
6283
|
+
...args.config !== void 0 ? { p_config: args.config } : {}
|
|
5971
6284
|
},
|
|
5972
6285
|
"portalDeclare"
|
|
5973
6286
|
);
|
|
5974
6287
|
},
|
|
6288
|
+
async portalForm({ portal_id, form_id }) {
|
|
6289
|
+
return callDoor(
|
|
6290
|
+
DOORS.portalForm,
|
|
6291
|
+
{ p_organization_id: org, p_portal_id: portal_id, p_form_id: form_id },
|
|
6292
|
+
"portalForm"
|
|
6293
|
+
);
|
|
6294
|
+
},
|
|
6295
|
+
async portalFormSubmit({ portal_id, form_id, answers, client_key }) {
|
|
6296
|
+
return callDoor(
|
|
6297
|
+
DOORS.portalFormSubmit,
|
|
6298
|
+
{
|
|
6299
|
+
p_organization_id: org,
|
|
6300
|
+
p_portal_id: portal_id,
|
|
6301
|
+
p_form_id: form_id,
|
|
6302
|
+
p_payload: answers,
|
|
6303
|
+
p_client_key: client_key ?? null
|
|
6304
|
+
},
|
|
6305
|
+
"portalFormSubmit"
|
|
6306
|
+
);
|
|
6307
|
+
},
|
|
5975
6308
|
async portalInvite(args) {
|
|
5976
6309
|
return callDoor(
|
|
5977
6310
|
DOORS.portalInvite,
|
|
@@ -6170,10 +6503,17 @@ function createRecordsClient(config) {
|
|
|
6170
6503
|
"dashboardDeclare"
|
|
6171
6504
|
);
|
|
6172
6505
|
},
|
|
6173
|
-
async dashboardRun({ dashboard_id, filter }) {
|
|
6506
|
+
async dashboardRun({ dashboard_id, filter, compare, grain }) {
|
|
6174
6507
|
return callDoor(
|
|
6175
6508
|
DOORS.dashboardRun,
|
|
6176
|
-
{
|
|
6509
|
+
{
|
|
6510
|
+
p_organization_id: org,
|
|
6511
|
+
p_dashboard_id: dashboard_id,
|
|
6512
|
+
p_filter: filter ?? {},
|
|
6513
|
+
// Sent only when asked, so a caller that never compares calls exactly what it did.
|
|
6514
|
+
...compare ? { p_compare: compare } : {},
|
|
6515
|
+
...grain ? { p_grain: grain } : {}
|
|
6516
|
+
},
|
|
6177
6517
|
"dashboardRun"
|
|
6178
6518
|
);
|
|
6179
6519
|
},
|
|
@@ -6198,7 +6538,7 @@ function createRecordsClient(config) {
|
|
|
6198
6538
|
"dashboardDelete"
|
|
6199
6539
|
);
|
|
6200
6540
|
},
|
|
6201
|
-
async recordAggregate({ table_id, groupBy, measures, bucket, filter, limit }) {
|
|
6541
|
+
async recordAggregate({ table_id, groupBy, measures, bucket, filter, limit, compare }) {
|
|
6202
6542
|
return callDoor(
|
|
6203
6543
|
DOORS.recordAggregate,
|
|
6204
6544
|
{
|
|
@@ -6208,7 +6548,8 @@ function createRecordsClient(config) {
|
|
|
6208
6548
|
p_measures: measures ?? [],
|
|
6209
6549
|
p_bucket: bucket ?? null,
|
|
6210
6550
|
p_filter: filter ?? {},
|
|
6211
|
-
p_limit: limit ?? 200
|
|
6551
|
+
p_limit: limit ?? 200,
|
|
6552
|
+
...compare ? { p_compare: compare } : {}
|
|
6212
6553
|
},
|
|
6213
6554
|
"recordAggregate"
|
|
6214
6555
|
);
|
|
@@ -6936,6 +7277,13 @@ function createRecordsClient(config) {
|
|
|
6936
7277
|
"workApprovalDecide"
|
|
6937
7278
|
);
|
|
6938
7279
|
},
|
|
7280
|
+
async workDecideMany({ decisions }) {
|
|
7281
|
+
return callDoor(
|
|
7282
|
+
DOORS.workDecideMany,
|
|
7283
|
+
{ p_organization_id: org, p_decisions: decisions },
|
|
7284
|
+
"workDecideMany"
|
|
7285
|
+
);
|
|
7286
|
+
},
|
|
6939
7287
|
async workApprovalRead({ approval_id }) {
|
|
6940
7288
|
return callDoor(
|
|
6941
7289
|
DOORS.workApprovalRead,
|
|
@@ -7139,6 +7487,69 @@ function createRecordsClient(config) {
|
|
|
7139
7487
|
"tableFromExample"
|
|
7140
7488
|
);
|
|
7141
7489
|
},
|
|
7490
|
+
async tableListEverywhere() {
|
|
7491
|
+
return callDoor(
|
|
7492
|
+
DOORS.tableListEverywhere,
|
|
7493
|
+
{ p_organization_id: org },
|
|
7494
|
+
"tableListEverywhere"
|
|
7495
|
+
);
|
|
7496
|
+
},
|
|
7497
|
+
async tableSync({ home_id, spec }) {
|
|
7498
|
+
return callDoor(
|
|
7499
|
+
DOORS.tableSync,
|
|
7500
|
+
{ p_organization_id: org, p_home_id: home_id, p_spec: spec },
|
|
7501
|
+
"tableSync"
|
|
7502
|
+
);
|
|
7503
|
+
},
|
|
7504
|
+
async scopeTableProvision({ home_id, item_id, scope_id }) {
|
|
7505
|
+
return callDoor(
|
|
7506
|
+
DOORS.scopeTableProvision,
|
|
7507
|
+
{ p_organization_id: org, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
|
|
7508
|
+
"scopeTableProvision"
|
|
7509
|
+
);
|
|
7510
|
+
},
|
|
7511
|
+
async tableRowCounts({ table_ids }) {
|
|
7512
|
+
return callDoor(
|
|
7513
|
+
DOORS.tableRowCounts,
|
|
7514
|
+
{ p_organization_id: org, p_table_ids: table_ids },
|
|
7515
|
+
"tableRowCounts"
|
|
7516
|
+
);
|
|
7517
|
+
},
|
|
7518
|
+
async recordHeaders({ ids }) {
|
|
7519
|
+
return callDoor(
|
|
7520
|
+
DOORS.recordHeaders,
|
|
7521
|
+
{ p_organization_id: org, p_ids: ids },
|
|
7522
|
+
"recordHeaders"
|
|
7523
|
+
);
|
|
7524
|
+
},
|
|
7525
|
+
async tableShareOutsideGrant({ table_id, person, level }) {
|
|
7526
|
+
return callDoor(
|
|
7527
|
+
DOORS.tableShareOutsideGrant,
|
|
7528
|
+
{ p_organization_id: org, p_table_id: table_id, p_person: person, p_level: level ?? "viewer" },
|
|
7529
|
+
"tableShareOutsideGrant"
|
|
7530
|
+
);
|
|
7531
|
+
},
|
|
7532
|
+
async viewRecordOrderSet({ view_id, record_ids }) {
|
|
7533
|
+
return callDoor(
|
|
7534
|
+
DOORS.viewRecordOrderSet,
|
|
7535
|
+
{ p_organization_id: org, p_view_id: view_id, p_record_ids: record_ids },
|
|
7536
|
+
"viewRecordOrderSet"
|
|
7537
|
+
);
|
|
7538
|
+
},
|
|
7539
|
+
async readInViewOrder({ view_id, limit, offset }) {
|
|
7540
|
+
const door = await callDoor(
|
|
7541
|
+
DOORS.readRecordsInViewOrder,
|
|
7542
|
+
{ p_organization_id: org, p_view_id: view_id, p_by_id: false, p_limit: limit ?? 200, p_offset: offset ?? 0 },
|
|
7543
|
+
"readInViewOrder"
|
|
7544
|
+
);
|
|
7545
|
+
if (!door.ok) return err(door.error);
|
|
7546
|
+
return ok(
|
|
7547
|
+
(door.data ?? []).map((row) => {
|
|
7548
|
+
const { document, hidden } = unfold(row.document);
|
|
7549
|
+
return { id: row.id, document, level: row.level, hidden, position: row.position ?? null };
|
|
7550
|
+
})
|
|
7551
|
+
);
|
|
7552
|
+
},
|
|
7142
7553
|
async autonumberBackfill({ field_id }) {
|
|
7143
7554
|
return callDoor(
|
|
7144
7555
|
DOORS.autonumberBackfill,
|
|
@@ -7233,27 +7644,6 @@ function useRecordsActor() {
|
|
|
7233
7644
|
|
|
7234
7645
|
// src/react/hooks.ts
|
|
7235
7646
|
var import_react2 = require("react");
|
|
7236
|
-
|
|
7237
|
-
// src/aggregate.ts
|
|
7238
|
-
function measureKey(measure) {
|
|
7239
|
-
return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
|
|
7240
|
-
}
|
|
7241
|
-
function stableFilterKey(filter) {
|
|
7242
|
-
if (!filter) return "{}";
|
|
7243
|
-
const keys = Object.keys(filter).sort();
|
|
7244
|
-
if (keys.length === 0) return "{}";
|
|
7245
|
-
const parts = keys.map((key) => {
|
|
7246
|
-
const value = filter[key];
|
|
7247
|
-
if (value !== null && typeof value === "object") {
|
|
7248
|
-
const window2 = value;
|
|
7249
|
-
return `${JSON.stringify(key)}:{"from":${JSON.stringify(window2.from ?? null)},"to":${JSON.stringify(window2.to ?? null)}}`;
|
|
7250
|
-
}
|
|
7251
|
-
return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
|
|
7252
|
-
});
|
|
7253
|
-
return `{${parts.join(",")}}`;
|
|
7254
|
-
}
|
|
7255
|
-
|
|
7256
|
-
// src/react/hooks.ts
|
|
7257
7647
|
function useAsync(run, deps) {
|
|
7258
7648
|
const client = useRecordsClient();
|
|
7259
7649
|
const [state, setState] = (0, import_react2.useState)(
|
|
@@ -7733,6 +8123,88 @@ function useMergeField(key, state) {
|
|
|
7733
8123
|
return resolution;
|
|
7734
8124
|
}
|
|
7735
8125
|
|
|
8126
|
+
// src/react/entity-reference.ts
|
|
8127
|
+
var import_react3 = require("react");
|
|
8128
|
+
|
|
8129
|
+
// src/relation.ts
|
|
8130
|
+
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;
|
|
8131
|
+
function isRefLike(value) {
|
|
8132
|
+
return typeof value === "object" && value !== null && "token" in value && "id" in value;
|
|
8133
|
+
}
|
|
8134
|
+
function entityRefsOf(value) {
|
|
8135
|
+
const items = Array.isArray(value) ? value : value == null ? [] : [value];
|
|
8136
|
+
const out = [];
|
|
8137
|
+
for (const item of items) {
|
|
8138
|
+
if (!isRefLike(item)) continue;
|
|
8139
|
+
const token = String(item.token ?? "").trim().toLowerCase();
|
|
8140
|
+
const id = String(item.id ?? "").trim();
|
|
8141
|
+
if (!token || !ENTITY_REF_ID.test(id)) continue;
|
|
8142
|
+
const label = item.label;
|
|
8143
|
+
out.push({ token, id: id.toLowerCase(), label: typeof label === "string" ? label : null });
|
|
8144
|
+
}
|
|
8145
|
+
return out;
|
|
8146
|
+
}
|
|
8147
|
+
function entityRefsToWrite(value, multi) {
|
|
8148
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8149
|
+
const refs = [];
|
|
8150
|
+
for (const ref of entityRefsOf(value)) {
|
|
8151
|
+
const k = `${ref.token}:${ref.id}`;
|
|
8152
|
+
if (seen.has(k)) continue;
|
|
8153
|
+
seen.add(k);
|
|
8154
|
+
refs.push({ token: ref.token, id: ref.id });
|
|
8155
|
+
}
|
|
8156
|
+
if (multi) return refs;
|
|
8157
|
+
return refs[0] ?? null;
|
|
8158
|
+
}
|
|
8159
|
+
async function entityReferenceKinds(source) {
|
|
8160
|
+
const { data, error } = await source.rpc("entity_reference_kinds", {}, { schema: "custom" });
|
|
8161
|
+
if (error) return err(mapPgError(error, "entityReferenceKinds"));
|
|
8162
|
+
return ok(Array.isArray(data) ? data : []);
|
|
8163
|
+
}
|
|
8164
|
+
async function entityReferenceWords(source, organizationId, refs) {
|
|
8165
|
+
if (refs.length === 0) return ok([]);
|
|
8166
|
+
const { data, error } = await source.rpc(
|
|
8167
|
+
"entity_reference_words",
|
|
8168
|
+
{ p_organization_id: organizationId, p_refs: refs.map((r) => ({ token: r.token, id: r.id })) },
|
|
8169
|
+
{ schema: "custom" }
|
|
8170
|
+
);
|
|
8171
|
+
if (error) return err(mapPgError(error, "entityReferenceWords"));
|
|
8172
|
+
return ok(entityRefsOf(data));
|
|
8173
|
+
}
|
|
8174
|
+
|
|
8175
|
+
// src/react/entity-reference.ts
|
|
8176
|
+
function useEntityReferenceKinds() {
|
|
8177
|
+
const client = useRecordsClient();
|
|
8178
|
+
const [state, setState] = (0, import_react3.useState)({ data: null, loading: true, error: null });
|
|
8179
|
+
(0, import_react3.useEffect)(() => {
|
|
8180
|
+
let live = true;
|
|
8181
|
+
void entityReferenceKinds(client.config.dataSource).then((res) => {
|
|
8182
|
+
if (!live) return;
|
|
8183
|
+
setState(res.ok ? { data: res.data, loading: false, error: null } : { data: null, loading: false, error: res.error });
|
|
8184
|
+
});
|
|
8185
|
+
return () => {
|
|
8186
|
+
live = false;
|
|
8187
|
+
};
|
|
8188
|
+
}, [client]);
|
|
8189
|
+
return state;
|
|
8190
|
+
}
|
|
8191
|
+
function useEntityReferenceWords(refs) {
|
|
8192
|
+
const client = useRecordsClient();
|
|
8193
|
+
const key = refs.map((r) => `${r.token}:${r.id}`).join(",");
|
|
8194
|
+
const [state, setState] = (0, import_react3.useState)({ data: null, loading: refs.length > 0, error: null });
|
|
8195
|
+
(0, import_react3.useEffect)(() => {
|
|
8196
|
+
let live = true;
|
|
8197
|
+
void entityReferenceWords(client.config.dataSource, client.config.organizationId, refs).then((res) => {
|
|
8198
|
+
if (!live) return;
|
|
8199
|
+
setState(res.ok ? { data: res.data, loading: false, error: null } : { data: null, loading: false, error: res.error });
|
|
8200
|
+
});
|
|
8201
|
+
return () => {
|
|
8202
|
+
live = false;
|
|
8203
|
+
};
|
|
8204
|
+
}, [client, key]);
|
|
8205
|
+
return state;
|
|
8206
|
+
}
|
|
8207
|
+
|
|
7736
8208
|
// src/vocabulary.ts
|
|
7737
8209
|
var TABLE_TYPES = [
|
|
7738
8210
|
"entity",
|
|
@@ -7844,6 +8316,7 @@ var FIELD_KINDS = [
|
|
|
7844
8316
|
"currency",
|
|
7845
8317
|
"datetime",
|
|
7846
8318
|
"email",
|
|
8319
|
+
"entity_reference",
|
|
7847
8320
|
"formula",
|
|
7848
8321
|
"json",
|
|
7849
8322
|
"long_text",
|
|
@@ -7882,6 +8355,7 @@ function fieldKindFor(field, kernel) {
|
|
|
7882
8355
|
case "list":
|
|
7883
8356
|
return field.multi ? "multi_select" : "select";
|
|
7884
8357
|
case "relation": {
|
|
8358
|
+
if (isEntityReferenceConfig(config)) return "entity_reference";
|
|
7885
8359
|
const parity = String(config["parity"] ?? "");
|
|
7886
8360
|
if (parity === "attachment" || parity === "member") return parity;
|
|
7887
8361
|
if (kernel?.file && field.relation_target === kernel.file) return "attachment";
|
|
@@ -7899,6 +8373,14 @@ function fieldKindFor(field, kernel) {
|
|
|
7899
8373
|
}
|
|
7900
8374
|
}
|
|
7901
8375
|
var UUID_TEXT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8376
|
+
function isEntityReferenceConfig(config) {
|
|
8377
|
+
const allowed = config?.["allowed_types"];
|
|
8378
|
+
return Array.isArray(allowed) && allowed.length > 0;
|
|
8379
|
+
}
|
|
8380
|
+
function entityReferenceKindsOf(field) {
|
|
8381
|
+
const allowed = field.config?.["allowed_types"];
|
|
8382
|
+
return Array.isArray(allowed) ? allowed.map((k) => String(k).trim().toLowerCase()).filter(Boolean) : [];
|
|
8383
|
+
}
|
|
7902
8384
|
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
7903
8385
|
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
7904
8386
|
function coercionLabel(field) {
|
|
@@ -8014,6 +8496,23 @@ function coerceTypedAnswer(field, raw, opts = {}) {
|
|
|
8014
8496
|
return {
|
|
8015
8497
|
refusal: `${label} points at another record, so it is chosen rather than typed. Open it and pick the record.`
|
|
8016
8498
|
};
|
|
8499
|
+
// SC-R / P12. An entity reference names a platform thing by kind and id.
|
|
8500
|
+
// An import or an agent may hand over `note:<id>` — or a bare id when the
|
|
8501
|
+
// column allows exactly one kind; the store then decides whether the thing
|
|
8502
|
+
// is there and whether the writer may open it. Words are chosen, not typed.
|
|
8503
|
+
case "entity_reference": {
|
|
8504
|
+
const allowed = entityReferenceKindsOf(field);
|
|
8505
|
+
const [maybeToken, maybeId] = text.includes(":") ? text.split(/:(.*)/s, 2) : ["", text];
|
|
8506
|
+
const token = (maybeToken ?? "").trim().toLowerCase() || (allowed.length === 1 ? allowed[0] : "");
|
|
8507
|
+
const id = (maybeId ?? "").trim();
|
|
8508
|
+
if (token && UUID_TEXT.test(id)) {
|
|
8509
|
+
const ref = { token, id: id.toLowerCase() };
|
|
8510
|
+
return { value: field.multi ? [ref] : ref };
|
|
8511
|
+
}
|
|
8512
|
+
return {
|
|
8513
|
+
refusal: `${label} points at something on the platform, so it is chosen rather than typed. Open it and pick it.`
|
|
8514
|
+
};
|
|
8515
|
+
}
|
|
8017
8516
|
case "formula":
|
|
8018
8517
|
case "lookup":
|
|
8019
8518
|
case "rollup":
|
|
@@ -8070,6 +8569,10 @@ function publicFormPath(formId) {
|
|
|
8070
8569
|
}
|
|
8071
8570
|
|
|
8072
8571
|
// src/portal.ts
|
|
8572
|
+
var PORTAL_ACCENTS = ["slate", "green", "amber", "red", "blue", "violet", "teal"];
|
|
8573
|
+
function isPortalAccent(word) {
|
|
8574
|
+
return typeof word === "string" && PORTAL_ACCENTS.includes(word);
|
|
8575
|
+
}
|
|
8073
8576
|
function portalPath(slug) {
|
|
8074
8577
|
return `/portal/c/${slug}`;
|
|
8075
8578
|
}
|
|
@@ -8160,7 +8663,7 @@ function memoryStore() {
|
|
|
8160
8663
|
setMeta: async (key, value) => void meta.set(key, value)
|
|
8161
8664
|
};
|
|
8162
8665
|
}
|
|
8163
|
-
function
|
|
8666
|
+
function countOf2(items) {
|
|
8164
8667
|
const c = { waiting: 0, sending: 0, refused: 0, landed: 0 };
|
|
8165
8668
|
for (const i of items) c[i.state] += 1;
|
|
8166
8669
|
return c;
|
|
@@ -8177,7 +8680,7 @@ function openCaptureQueue(opts) {
|
|
|
8177
8680
|
const announce = async () => {
|
|
8178
8681
|
if (!opts.onChange) return;
|
|
8179
8682
|
const items = await store.all();
|
|
8180
|
-
opts.onChange(
|
|
8683
|
+
opts.onChange(countOf2(items), items);
|
|
8181
8684
|
};
|
|
8182
8685
|
const oldestFirst = (items) => items.slice().sort((a, b) => a.captured_at.localeCompare(b.captured_at));
|
|
8183
8686
|
const queue = {
|
|
@@ -8206,7 +8709,7 @@ function openCaptureQueue(opts) {
|
|
|
8206
8709
|
return key;
|
|
8207
8710
|
},
|
|
8208
8711
|
list: () => store.all().then(oldestFirst),
|
|
8209
|
-
counts: () => store.all().then(
|
|
8712
|
+
counts: () => store.all().then(countOf2),
|
|
8210
8713
|
async sync() {
|
|
8211
8714
|
if (syncing) return syncing;
|
|
8212
8715
|
syncing = (async () => {
|