@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.js
CHANGED
|
@@ -2219,6 +2219,31 @@ function sameDocument(a, b) {
|
|
|
2219
2219
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
2220
2220
|
}
|
|
2221
2221
|
|
|
2222
|
+
// src/aggregate.ts
|
|
2223
|
+
function isRuleFilter(filter) {
|
|
2224
|
+
if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
|
|
2225
|
+
const node = filter;
|
|
2226
|
+
return typeof node.op === "string" && Array.isArray(node.args);
|
|
2227
|
+
}
|
|
2228
|
+
function measureKey(measure) {
|
|
2229
|
+
return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
|
|
2230
|
+
}
|
|
2231
|
+
function stableFilterKey(filter) {
|
|
2232
|
+
if (!filter) return "{}";
|
|
2233
|
+
if (isRuleFilter(filter)) return JSON.stringify(filter);
|
|
2234
|
+
const keys = Object.keys(filter).sort();
|
|
2235
|
+
if (keys.length === 0) return "{}";
|
|
2236
|
+
const parts = keys.map((key) => {
|
|
2237
|
+
const value = filter[key];
|
|
2238
|
+
if (value !== null && typeof value === "object") {
|
|
2239
|
+
const window2 = value;
|
|
2240
|
+
return `${JSON.stringify(key)}:{"from":${JSON.stringify(window2.from ?? null)},"to":${JSON.stringify(window2.to ?? null)}}`;
|
|
2241
|
+
}
|
|
2242
|
+
return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
|
|
2243
|
+
});
|
|
2244
|
+
return `{${parts.join(",")}}`;
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2222
2247
|
// src/ops.ts
|
|
2223
2248
|
var REMEMBER_MS = 3e4;
|
|
2224
2249
|
var REMEMBER_MAX = 500;
|
|
@@ -2258,6 +2283,116 @@ function rememberedOpCount() {
|
|
|
2258
2283
|
return ours.size;
|
|
2259
2284
|
}
|
|
2260
2285
|
|
|
2286
|
+
// src/placement.ts
|
|
2287
|
+
function keptOutOfSight(placement) {
|
|
2288
|
+
return placement?.kept_by_the_app === true;
|
|
2289
|
+
}
|
|
2290
|
+
function offeredAsContext(placement) {
|
|
2291
|
+
return placement?.offered_as_context === true;
|
|
2292
|
+
}
|
|
2293
|
+
function withTablePlacement(tables, facts) {
|
|
2294
|
+
if (!facts) return [...tables];
|
|
2295
|
+
const byId = new Map(facts.map((f) => [f.table_id, f]));
|
|
2296
|
+
return tables.map((table) => {
|
|
2297
|
+
const fact = byId.get(table.id);
|
|
2298
|
+
if (!fact || fact.kept_by_the_app === void 0) return table;
|
|
2299
|
+
return {
|
|
2300
|
+
...table,
|
|
2301
|
+
kept_by_the_app: fact.kept_by_the_app,
|
|
2302
|
+
kept_for: fact.kept_for ?? null,
|
|
2303
|
+
offered_as_context: fact.offered_as_context ?? false,
|
|
2304
|
+
keeper_group: fact.keeper_group ?? null,
|
|
2305
|
+
keeper_says: fact.keeper_says ?? null,
|
|
2306
|
+
used_in_kind: fact.used_in_kind ?? null,
|
|
2307
|
+
used_in_id: fact.used_in_id ?? null,
|
|
2308
|
+
used_in_table_id: fact.used_in_table_id ?? null
|
|
2309
|
+
};
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
function keptGroups(tables) {
|
|
2313
|
+
const out = [];
|
|
2314
|
+
const at = /* @__PURE__ */ new Map();
|
|
2315
|
+
for (const table of tables) {
|
|
2316
|
+
if (!keptOutOfSight(table)) continue;
|
|
2317
|
+
const group = table.keeper_group?.trim() || "Kept by the app";
|
|
2318
|
+
let i = at.get(group);
|
|
2319
|
+
if (i === void 0) {
|
|
2320
|
+
i = out.length;
|
|
2321
|
+
at.set(group, i);
|
|
2322
|
+
out.push({ group, tables: [] });
|
|
2323
|
+
}
|
|
2324
|
+
out[i].tables.push(table);
|
|
2325
|
+
}
|
|
2326
|
+
return out;
|
|
2327
|
+
}
|
|
2328
|
+
function keptTableHref(fact, hrefs) {
|
|
2329
|
+
if (fact.used_in_kind === "scope" && fact.used_in_id) return hrefs.scope(fact.used_in_id);
|
|
2330
|
+
if (fact.used_in_kind === "table" && (fact.used_in_table_id || fact.used_in_id)) {
|
|
2331
|
+
return hrefs.table(fact.used_in_table_id || fact.used_in_id);
|
|
2332
|
+
}
|
|
2333
|
+
return hrefs.table(fact.table_id);
|
|
2334
|
+
}
|
|
2335
|
+
function countOf(value) {
|
|
2336
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2337
|
+
}
|
|
2338
|
+
function wordsOf(value) {
|
|
2339
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
2340
|
+
}
|
|
2341
|
+
function parseTableHome(raw) {
|
|
2342
|
+
if (!raw || typeof raw !== "object") return null;
|
|
2343
|
+
const row = raw;
|
|
2344
|
+
const table = row.table;
|
|
2345
|
+
const org = row.organization;
|
|
2346
|
+
if (!table || !org || !wordsOf(table.id) || !wordsOf(org.id) || !wordsOf(org.name)) return null;
|
|
2347
|
+
const carries = row.carries ?? {};
|
|
2348
|
+
const destinations = Array.isArray(row.destinations) ? row.destinations : [];
|
|
2349
|
+
return {
|
|
2350
|
+
table: { id: String(table.id), name: wordsOf(table.name) ?? "This table", version: countOf(table.version) },
|
|
2351
|
+
organization: { id: String(org.id), name: String(org.name) },
|
|
2352
|
+
mayMove: row.may_move === true,
|
|
2353
|
+
whyNot: wordsOf(row.why_not),
|
|
2354
|
+
heldBy: Array.isArray(row.held_by) ? row.held_by.filter((s) => typeof s === "string") : [],
|
|
2355
|
+
destinations: destinations.filter((d) => !!d && typeof d === "object" && !!wordsOf(d.id)).map((d) => ({
|
|
2356
|
+
id: String(d.id),
|
|
2357
|
+
name: wordsOf(d.name) ?? "An organization",
|
|
2358
|
+
role: wordsOf(d.role) ?? "member",
|
|
2359
|
+
ok: d.ok === true,
|
|
2360
|
+
why: wordsOf(d.why)
|
|
2361
|
+
})),
|
|
2362
|
+
carries: {
|
|
2363
|
+
fields: countOf(carries.fields),
|
|
2364
|
+
records: countOf(carries.records),
|
|
2365
|
+
inTrash: countOf(carries.in_trash),
|
|
2366
|
+
choiceLists: countOf(carries.choice_lists),
|
|
2367
|
+
withIt: countOf(carries.with_it),
|
|
2368
|
+
tablesInside: countOf(carries.tables_inside),
|
|
2369
|
+
linksAcross: countOf(carries.links_across)
|
|
2370
|
+
}
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
function parseTableMoved(raw) {
|
|
2374
|
+
const row = raw ?? {};
|
|
2375
|
+
const to = row.to ?? {};
|
|
2376
|
+
const from = row.from ?? {};
|
|
2377
|
+
const table = row.table ?? {};
|
|
2378
|
+
if (row.moved !== true || !wordsOf(to.id)) return null;
|
|
2379
|
+
return {
|
|
2380
|
+
to: { id: String(to.id), name: wordsOf(to.name) ?? "the new organization" },
|
|
2381
|
+
from: { id: wordsOf(from.id) ?? "", name: wordsOf(from.name) ?? "its old organization" },
|
|
2382
|
+
tableName: wordsOf(table.name) ?? "The table"
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
function plural(n, one, many) {
|
|
2386
|
+
return `${n} ${n === 1 ? one : many}`;
|
|
2387
|
+
}
|
|
2388
|
+
function moveConsequence(home, to) {
|
|
2389
|
+
const c = home.carries;
|
|
2390
|
+
const parts = [plural(c.fields, "column", "columns"), plural(c.records, "row", "rows")];
|
|
2391
|
+
if (c.inTrash > 0) parts.push(`${c.inTrash} in the trash`);
|
|
2392
|
+
const extra = c.choiceLists + c.withIt;
|
|
2393
|
+
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.`;
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2261
2396
|
// src/level.ts
|
|
2262
2397
|
var PERMISSION_LEVELS = [
|
|
2263
2398
|
"viewer",
|
|
@@ -2374,6 +2509,51 @@ function recordChangeTrigger(tableId, options = {}) {
|
|
|
2374
2509
|
...options.changedFields && options.changedFields.length > 0 ? { changed_fields: options.changedFields } : {}
|
|
2375
2510
|
};
|
|
2376
2511
|
}
|
|
2512
|
+
function sheetSyncSpec(args) {
|
|
2513
|
+
const [header = [], ...body] = args.cells;
|
|
2514
|
+
const columns = header.map((c, i) => {
|
|
2515
|
+
const name = c == null ? "" : String(c).trim();
|
|
2516
|
+
return name === "" ? `Column ${i + 1}` : name;
|
|
2517
|
+
});
|
|
2518
|
+
if (columns.length === 0) {
|
|
2519
|
+
throw new Error("The sheet has no header row, so there are no columns to sync. Nothing was sent.");
|
|
2520
|
+
}
|
|
2521
|
+
const seenCol = /* @__PURE__ */ new Set();
|
|
2522
|
+
for (const c of columns) {
|
|
2523
|
+
if (seenCol.has(c)) throw new Error(`The sheet has two columns named "${c}". Rename one and sync again.`);
|
|
2524
|
+
seenCol.add(c);
|
|
2525
|
+
}
|
|
2526
|
+
const refIdx = args.refColumn == null ? -1 : columns.indexOf(args.refColumn);
|
|
2527
|
+
if (args.refColumn != null && refIdx < 0) {
|
|
2528
|
+
throw new Error(`The id column "${args.refColumn}" is not in the sheet's header. Nothing was sent.`);
|
|
2529
|
+
}
|
|
2530
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2531
|
+
const rows = [];
|
|
2532
|
+
body.forEach((cells, i) => {
|
|
2533
|
+
if (cells.every((v) => v == null || String(v).trim() === "")) return;
|
|
2534
|
+
const ref = refIdx >= 0 ? String(cells[refIdx] ?? "").trim() : `row-${i + 2}`;
|
|
2535
|
+
if (ref === "") throw new Error(`Sheet row ${i + 2} has no value in the id column "${args.refColumn}".`);
|
|
2536
|
+
if (seen.has(ref)) throw new Error(`Two sheet rows share the id "${ref}"; each row needs its own.`);
|
|
2537
|
+
seen.add(ref);
|
|
2538
|
+
const values = {};
|
|
2539
|
+
columns.forEach((c, j) => {
|
|
2540
|
+
const v = cells[j];
|
|
2541
|
+
values[c] = v === void 0 || v === "" ? null : v;
|
|
2542
|
+
});
|
|
2543
|
+
rows.push({ ref, values });
|
|
2544
|
+
});
|
|
2545
|
+
return { source: args.source, table_name: args.tableName, columns, rows };
|
|
2546
|
+
}
|
|
2547
|
+
function withRowCounts(tables, counts) {
|
|
2548
|
+
if (!counts) return [...tables];
|
|
2549
|
+
const byId = new Map(counts.map((c) => [c.table_id, Number(c.visible_rows)]));
|
|
2550
|
+
return tables.map((t) => byId.has(t.id) ? { ...t, row_count: byId.get(t.id) } : t);
|
|
2551
|
+
}
|
|
2552
|
+
function moveInOrder(order, moved, toIndex) {
|
|
2553
|
+
const rest = order.filter((id) => id !== moved);
|
|
2554
|
+
const at = Math.max(0, Math.min(Math.trunc(toIndex), rest.length));
|
|
2555
|
+
return [...rest.slice(0, at), moved, ...rest.slice(at)];
|
|
2556
|
+
}
|
|
2377
2557
|
|
|
2378
2558
|
// src/store.generated.ts
|
|
2379
2559
|
var ACTOR_VOCABULARY = ["user", "agent", "system"];
|
|
@@ -3049,6 +3229,7 @@ var STORE_DOORS = [
|
|
|
3049
3229
|
{ name: "table_work_kind", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
|
|
3050
3230
|
{ 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" },
|
|
3051
3231
|
{ name: "tables_described_without_asking", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
|
|
3232
|
+
{ 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" },
|
|
3052
3233
|
{ 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" },
|
|
3053
3234
|
{ name: "trg_associations_bump_visibility", args: "", returns: "trigger", security: "definer" },
|
|
3054
3235
|
{ name: "undeclared_keys", args: "p_organization_id uuid, p_table_id uuid, p_data jsonb", returns: "text[]", security: "invoker" },
|
|
@@ -3073,6 +3254,7 @@ var STORE_DOORS = [
|
|
|
3073
3254
|
{ 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" },
|
|
3074
3255
|
{ name: "visible_record_ids", args: "p_user_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level", returns: "TABLE(id uuid)", security: "definer" },
|
|
3075
3256
|
{ 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" },
|
|
3257
|
+
{ name: "where_id_opens", args: "p_id uuid", returns: "jsonb", security: "definer" },
|
|
3076
3258
|
{ name: "widget_kernel_id", args: "", returns: "uuid", security: "invoker" },
|
|
3077
3259
|
{ name: "withheld_marker", args: "p_mask jsonb, p_key text", returns: "jsonb", security: "invoker" },
|
|
3078
3260
|
{ name: "withheld_sentence", args: "p_mask jsonb, p_key text", returns: "text", security: "invoker" },
|
|
@@ -3179,7 +3361,7 @@ var STORE_REFUSAL_CODES = [
|
|
|
3179
3361
|
{ 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" },
|
|
3180
3362
|
{ 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" },
|
|
3181
3363
|
{ code: "40001", raised_by: "has_visibility_at" },
|
|
3182
|
-
{ 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" },
|
|
3364
|
+
{ 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" },
|
|
3183
3365
|
{ code: "42703", raised_by: "entity_table,portal_declare" },
|
|
3184
3366
|
{ code: "53400", raised_by: "anon_rate_take,delete_cascade_closure,enrich_due,enrich_land,promote_field" },
|
|
3185
3367
|
{ code: "54000", raised_by: "action_run,hub_changed_by,table_decorate,table_from_example,table_webhook_declare" },
|
|
@@ -4219,6 +4401,8 @@ var ENTITY_TOKENS = [
|
|
|
4219
4401
|
|
|
4220
4402
|
// src/core/doors.ts
|
|
4221
4403
|
var OWED_BY = {
|
|
4404
|
+
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",
|
|
4405
|
+
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",
|
|
4222
4406
|
metadata_search: "W5-SRV / W5-AGENT \u2014 the agent surface's eight verbs",
|
|
4223
4407
|
record_aggregate: "W5-SRV / W5-AGENT \u2014 `record_aggregate` is one of the eight verbs",
|
|
4224
4408
|
field_propose: "W5-AGENT \u2014 AGT-4/AGT-8, the proposal and its approvers",
|
|
@@ -4240,6 +4424,20 @@ var OWED_BY = {
|
|
|
4240
4424
|
table_webhook_archive: "GRID-PRIMITIVES G4 \u2014 gridprim_every_row_change_reaches_the_webhook.sql (chair's production apply)",
|
|
4241
4425
|
table_from_example: "GRID-PRIMITIVES G5 \u2014 gridprim_a_table_can_start_from_a_real_example.sql (chair's production apply)",
|
|
4242
4426
|
autonumber_backfill: "GRID-PRIMITIVES G5 \u2014 gridprim_a_table_can_start_from_a_real_example.sql (chair's production apply)",
|
|
4427
|
+
table_list_everywhere: "GRID-PRIMITIVES G9 \u2014 gridprim_every_picker_lists_both_stores.sql (chair's production apply)",
|
|
4428
|
+
table_sync: "GRID-PRIMITIVES G10 \u2014 gridprim_a_synced_sheet_is_one_table_that_refreshes.sql (chair's production apply)",
|
|
4429
|
+
scope_table_provision: "GRID-PRIMITIVES G11 \u2014 gridprim_a_scope_provisions_its_table_in_the_store.sql (chair's production apply)",
|
|
4430
|
+
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)",
|
|
4431
|
+
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)",
|
|
4432
|
+
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)",
|
|
4433
|
+
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)",
|
|
4434
|
+
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)",
|
|
4435
|
+
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)",
|
|
4436
|
+
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)",
|
|
4437
|
+
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)",
|
|
4438
|
+
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)",
|
|
4439
|
+
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)",
|
|
4440
|
+
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)",
|
|
4243
4441
|
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"
|
|
4244
4442
|
};
|
|
4245
4443
|
var TRUST_SCHEMA = "iam";
|
|
@@ -4443,6 +4641,8 @@ var DOORS = {
|
|
|
4443
4641
|
pipelineBoard: "pipeline_board",
|
|
4444
4642
|
pipelineTransitionRefusal: "pipeline_transition_refusal",
|
|
4445
4643
|
pipelineMove: "pipeline_move",
|
|
4644
|
+
/** Lane S4: many cards, one call, a verdict and a version per card. */
|
|
4645
|
+
pipelineMoveMany: "pipeline_move_many",
|
|
4446
4646
|
tableStageField: "table_stage_field",
|
|
4447
4647
|
// STAGE-RULES. A gate can refuse or it can hand the change to the approvals queue; the
|
|
4448
4648
|
// closed list is the store's, the knob is the organization's, and what is WAITING on a
|
|
@@ -4453,6 +4653,7 @@ var DOORS = {
|
|
|
4453
4653
|
pipelinePending: "pipeline_pending",
|
|
4454
4654
|
pipelineGatePreview: "pipeline_gate_preview",
|
|
4455
4655
|
ruleMembers: "rule_members",
|
|
4656
|
+
ruleMembersVisible: "rule_members_visible",
|
|
4456
4657
|
ruleMembership: "rule_membership",
|
|
4457
4658
|
ruleRun: "rule_run",
|
|
4458
4659
|
ruleEval: "rule_eval",
|
|
@@ -4467,6 +4668,12 @@ var DOORS = {
|
|
|
4467
4668
|
// are server-lane doors and a browser never calls them.
|
|
4468
4669
|
forms: "forms",
|
|
4469
4670
|
formDeclare: "form_declare",
|
|
4671
|
+
/**
|
|
4672
|
+
* WHICH QUESTIONS THE OWNER'S PREVIEW ASKS NEXT (lane FORMS-FIX-1). The same store answer a
|
|
4673
|
+
* stranger's form gets (`custom._form_questions_asked` → `custom.rule_eval`), behind the
|
|
4674
|
+
* organization wall and the caller's own rung on the Table — never `rule_eval` from a browser.
|
|
4675
|
+
*/
|
|
4676
|
+
formPreviewAsks: "form_preview_asks",
|
|
4470
4677
|
// PRODUCTS row 14 — "let clients book a 30-minute consult". A booking page IS an
|
|
4471
4678
|
// `anon_form`, so it is opened and closed by `anonPublish` like any other; this is
|
|
4472
4679
|
// the owner's list of them with the numbers that make it worth opening. The
|
|
@@ -4521,11 +4728,22 @@ var DOORS = {
|
|
|
4521
4728
|
// ask, under the same wall and visibility gate as `portals` itself.
|
|
4522
4729
|
portalTables: "portal_tables",
|
|
4523
4730
|
tableFacts: "table_facts",
|
|
4731
|
+
// WHERE A TABLE LIVES, AND MOVING IT (SC-1' / SC-1-TAILS). `table_home` answers only when the
|
|
4732
|
+
// caller may open the Table (custom.where_id_opens) and names its organization FROM THE TABLE;
|
|
4733
|
+
// `table_move` moves it into another organization the caller belongs to, with every Table
|
|
4734
|
+
// inside it, or refuses with one sentence.
|
|
4735
|
+
tableHome: "table_home",
|
|
4736
|
+
tableMove: "table_move",
|
|
4524
4737
|
portalCard: "portal_card",
|
|
4525
4738
|
portalDeclare: "portal_declare",
|
|
4526
4739
|
portalInvite: "portal_invite",
|
|
4527
4740
|
portalRevoke: "portal_revoke",
|
|
4528
4741
|
portalPreview: "portal_preview",
|
|
4742
|
+
// S6 — the CLIENT's two form doors. They are store doors (schema `custom`), called by a
|
|
4743
|
+
// signed-in portal principal, and each refuses anybody who is not a live principal of that
|
|
4744
|
+
// live portal — so, unlike the sign-in pair above, they belong in this table.
|
|
4745
|
+
portalForm: "portal_form",
|
|
4746
|
+
portalFormSubmit: "portal_form_submit",
|
|
4529
4747
|
// ORG-CLEANUP, 2026-09-22 — A PORTAL IS ARCHIVED, NEVER DELETED.
|
|
4530
4748
|
// `portals` keeps its signature and HIDES archived portals (the law's default
|
|
4531
4749
|
// is to hide); `list_portals(org, 'active'|'archived'|'all')` is the
|
|
@@ -4721,6 +4939,8 @@ var DOORS = {
|
|
|
4721
4939
|
workApprovalRequest: "work_approval_request",
|
|
4722
4940
|
workApprovalMayDecide: "work_approval_may_decide",
|
|
4723
4941
|
workApprovalDecide: "work_approval_decide",
|
|
4942
|
+
/** Lane S4: many inbox decisions, one call, a verdict per item. */
|
|
4943
|
+
workDecideMany: "work_decide_many",
|
|
4724
4944
|
workApprovalRead: "work_approval_read",
|
|
4725
4945
|
// PRODUCTS row 13 — checklists and SOP runs.
|
|
4726
4946
|
checklistRefusal: "checklist_refusal",
|
|
@@ -4746,6 +4966,14 @@ var DOORS = {
|
|
|
4746
4966
|
tableFromExample: "table_from_example",
|
|
4747
4967
|
autonumberBackfill: "autonumber_backfill",
|
|
4748
4968
|
ioExport: "io_export",
|
|
4969
|
+
tableListEverywhere: "table_list_everywhere",
|
|
4970
|
+
tableSync: "table_sync",
|
|
4971
|
+
scopeTableProvision: "scope_table_provision",
|
|
4972
|
+
tableRowCounts: "table_row_counts",
|
|
4973
|
+
recordHeaders: "record_headers",
|
|
4974
|
+
viewRecordOrderSet: "view_record_order_set",
|
|
4975
|
+
readRecordsInViewOrder: "read_records_in_view_order",
|
|
4976
|
+
tableShareOutsideGrant: "table_share_outside_grant",
|
|
4749
4977
|
// Declared here BECAUSE they do not exist yet: naming them is what makes the
|
|
4750
4978
|
// absence visible to `pnpm check:store-registry` and to the suite.
|
|
4751
4979
|
metadataSearch: "metadata_search",
|
|
@@ -5149,6 +5377,40 @@ function createRecordsClient(config) {
|
|
|
5149
5377
|
if (!doorExists(DOORS.tableFacts)) return ok(null);
|
|
5150
5378
|
return callDoor(DOORS.tableFacts, { p_organization_id: org }, "tableFacts");
|
|
5151
5379
|
},
|
|
5380
|
+
async tableHome({ table_id }) {
|
|
5381
|
+
const answered = await callDoor(DOORS.tableHome, { p_table_id: table_id }, "tableHome");
|
|
5382
|
+
if (!answered.ok) return answered;
|
|
5383
|
+
if (answered.data === null || answered.data === void 0) return ok(null);
|
|
5384
|
+
const home = parseTableHome(answered.data);
|
|
5385
|
+
if (!home) {
|
|
5386
|
+
const refusal = {
|
|
5387
|
+
code: "not_supported",
|
|
5388
|
+
message: "The record store answered where this table lives in a shape this client cannot read, so nothing is claimed about it.",
|
|
5389
|
+
hint: "Regenerate @ai-matrx/records against the store (pnpm records:generate) \u2014 the door and this client disagree."
|
|
5390
|
+
};
|
|
5391
|
+
scream({ code: refusal.code, message: refusal.message, ...refusal.hint ? { hint: refusal.hint } : {}, where: "tableHome" });
|
|
5392
|
+
return err(refusal);
|
|
5393
|
+
}
|
|
5394
|
+
return ok(home);
|
|
5395
|
+
},
|
|
5396
|
+
async tableMove({ table_id, to_organization_id, expected_version }) {
|
|
5397
|
+
const answered = await callDoor(
|
|
5398
|
+
DOORS.tableMove,
|
|
5399
|
+
{ p_table_id: table_id, p_to_organization_id: to_organization_id, p_expected_version: expected_version ?? null },
|
|
5400
|
+
"tableMove"
|
|
5401
|
+
);
|
|
5402
|
+
if (!answered.ok) return answered;
|
|
5403
|
+
const moved = parseTableMoved(answered.data);
|
|
5404
|
+
if (!moved) {
|
|
5405
|
+
const refusal = {
|
|
5406
|
+
code: "not_supported",
|
|
5407
|
+
message: "The record store answered the move in a shape this client cannot read. Look where the table lives before trying again."
|
|
5408
|
+
};
|
|
5409
|
+
scream({ code: refusal.code, message: refusal.message, where: "tableMove" });
|
|
5410
|
+
return err(refusal);
|
|
5411
|
+
}
|
|
5412
|
+
return ok(moved);
|
|
5413
|
+
},
|
|
5152
5414
|
async tableArchived({ table_id }) {
|
|
5153
5415
|
const kernel = await callDoor(DOORS.tableKernelId, {}, "tableArchived.kernel");
|
|
5154
5416
|
if (!kernel.ok) return err(kernel.error);
|
|
@@ -5525,10 +5787,11 @@ function createRecordsClient(config) {
|
|
|
5525
5787
|
"pipelineRead"
|
|
5526
5788
|
);
|
|
5527
5789
|
},
|
|
5528
|
-
async pipelineBoard({ table_id, measure }) {
|
|
5790
|
+
async pipelineBoard({ table_id, measure, filter }) {
|
|
5791
|
+
const asked = filter && stableFilterKey(filter) !== "{}";
|
|
5529
5792
|
return callDoor(
|
|
5530
5793
|
DOORS.pipelineBoard,
|
|
5531
|
-
{ p_organization_id: org, p_table_id: table_id, p_measure: measure ?? null },
|
|
5794
|
+
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 },
|
|
5532
5795
|
"pipelineBoard"
|
|
5533
5796
|
);
|
|
5534
5797
|
},
|
|
@@ -5552,6 +5815,13 @@ function createRecordsClient(config) {
|
|
|
5552
5815
|
"pipelineMove"
|
|
5553
5816
|
);
|
|
5554
5817
|
},
|
|
5818
|
+
async pipelineMoveMany({ moves }) {
|
|
5819
|
+
return callDoor(
|
|
5820
|
+
DOORS.pipelineMoveMany,
|
|
5821
|
+
{ p_organization_id: org, p_moves: moves },
|
|
5822
|
+
"pipelineMoveMany"
|
|
5823
|
+
);
|
|
5824
|
+
},
|
|
5555
5825
|
async pipelineDeclare({ table_id, spec }) {
|
|
5556
5826
|
return callDoor(
|
|
5557
5827
|
DOORS.pipelineDeclare,
|
|
@@ -5601,6 +5871,18 @@ function createRecordsClient(config) {
|
|
|
5601
5871
|
"pipelineGatePreview"
|
|
5602
5872
|
);
|
|
5603
5873
|
},
|
|
5874
|
+
async ruleMembersVisible({ rule_id, limit = 200, offset = 0 }) {
|
|
5875
|
+
const door = await callDoor(
|
|
5876
|
+
DOORS.ruleMembersVisible,
|
|
5877
|
+
{ p_organization_id: org, p_rule_id: rule_id, p_limit: limit, p_offset: offset },
|
|
5878
|
+
"ruleMembersVisible"
|
|
5879
|
+
);
|
|
5880
|
+
if (!door.ok) return err(door.error);
|
|
5881
|
+
return ok((door.data ?? []).map((row) => {
|
|
5882
|
+
const { document, hidden } = unfold(row.document);
|
|
5883
|
+
return { id: row.id, document, level: row.level, hidden };
|
|
5884
|
+
}));
|
|
5885
|
+
},
|
|
5604
5886
|
async ruleMembers({ rule_id }) {
|
|
5605
5887
|
return callDoor(
|
|
5606
5888
|
DOORS.ruleMembers,
|
|
@@ -5653,6 +5935,13 @@ function createRecordsClient(config) {
|
|
|
5653
5935
|
"bookingDeclare"
|
|
5654
5936
|
);
|
|
5655
5937
|
},
|
|
5938
|
+
async formPreviewAsks({ table_id, questions, values }) {
|
|
5939
|
+
return callDoor(
|
|
5940
|
+
DOORS.formPreviewAsks,
|
|
5941
|
+
{ p_organization_id: org, p_table_id: table_id, p_questions: questions, p_values: values },
|
|
5942
|
+
"formPreviewAsks"
|
|
5943
|
+
);
|
|
5944
|
+
},
|
|
5656
5945
|
async formDeclare(args) {
|
|
5657
5946
|
return callDoor(
|
|
5658
5947
|
DOORS.formDeclare,
|
|
@@ -5828,11 +6117,33 @@ function createRecordsClient(config) {
|
|
|
5828
6117
|
p_tables: args.tables,
|
|
5829
6118
|
p_portal_id: args.portal_id ?? null,
|
|
5830
6119
|
p_slug: args.slug ?? null,
|
|
5831
|
-
p_sign_in_method: args.sign_in_method ?? "magic_link"
|
|
6120
|
+
p_sign_in_method: args.sign_in_method ?? "magic_link",
|
|
6121
|
+
// S6: sent only when given, so a caller that says nothing about the look keeps it.
|
|
6122
|
+
...args.config !== void 0 ? { p_config: args.config } : {}
|
|
5832
6123
|
},
|
|
5833
6124
|
"portalDeclare"
|
|
5834
6125
|
);
|
|
5835
6126
|
},
|
|
6127
|
+
async portalForm({ portal_id, form_id }) {
|
|
6128
|
+
return callDoor(
|
|
6129
|
+
DOORS.portalForm,
|
|
6130
|
+
{ p_organization_id: org, p_portal_id: portal_id, p_form_id: form_id },
|
|
6131
|
+
"portalForm"
|
|
6132
|
+
);
|
|
6133
|
+
},
|
|
6134
|
+
async portalFormSubmit({ portal_id, form_id, answers, client_key }) {
|
|
6135
|
+
return callDoor(
|
|
6136
|
+
DOORS.portalFormSubmit,
|
|
6137
|
+
{
|
|
6138
|
+
p_organization_id: org,
|
|
6139
|
+
p_portal_id: portal_id,
|
|
6140
|
+
p_form_id: form_id,
|
|
6141
|
+
p_payload: answers,
|
|
6142
|
+
p_client_key: client_key ?? null
|
|
6143
|
+
},
|
|
6144
|
+
"portalFormSubmit"
|
|
6145
|
+
);
|
|
6146
|
+
},
|
|
5836
6147
|
async portalInvite(args) {
|
|
5837
6148
|
return callDoor(
|
|
5838
6149
|
DOORS.portalInvite,
|
|
@@ -6031,10 +6342,17 @@ function createRecordsClient(config) {
|
|
|
6031
6342
|
"dashboardDeclare"
|
|
6032
6343
|
);
|
|
6033
6344
|
},
|
|
6034
|
-
async dashboardRun({ dashboard_id, filter }) {
|
|
6345
|
+
async dashboardRun({ dashboard_id, filter, compare, grain }) {
|
|
6035
6346
|
return callDoor(
|
|
6036
6347
|
DOORS.dashboardRun,
|
|
6037
|
-
{
|
|
6348
|
+
{
|
|
6349
|
+
p_organization_id: org,
|
|
6350
|
+
p_dashboard_id: dashboard_id,
|
|
6351
|
+
p_filter: filter ?? {},
|
|
6352
|
+
// Sent only when asked, so a caller that never compares calls exactly what it did.
|
|
6353
|
+
...compare ? { p_compare: compare } : {},
|
|
6354
|
+
...grain ? { p_grain: grain } : {}
|
|
6355
|
+
},
|
|
6038
6356
|
"dashboardRun"
|
|
6039
6357
|
);
|
|
6040
6358
|
},
|
|
@@ -6059,7 +6377,7 @@ function createRecordsClient(config) {
|
|
|
6059
6377
|
"dashboardDelete"
|
|
6060
6378
|
);
|
|
6061
6379
|
},
|
|
6062
|
-
async recordAggregate({ table_id, groupBy, measures, bucket, filter, limit }) {
|
|
6380
|
+
async recordAggregate({ table_id, groupBy, measures, bucket, filter, limit, compare }) {
|
|
6063
6381
|
return callDoor(
|
|
6064
6382
|
DOORS.recordAggregate,
|
|
6065
6383
|
{
|
|
@@ -6069,7 +6387,8 @@ function createRecordsClient(config) {
|
|
|
6069
6387
|
p_measures: measures ?? [],
|
|
6070
6388
|
p_bucket: bucket ?? null,
|
|
6071
6389
|
p_filter: filter ?? {},
|
|
6072
|
-
p_limit: limit ?? 200
|
|
6390
|
+
p_limit: limit ?? 200,
|
|
6391
|
+
...compare ? { p_compare: compare } : {}
|
|
6073
6392
|
},
|
|
6074
6393
|
"recordAggregate"
|
|
6075
6394
|
);
|
|
@@ -6797,6 +7116,13 @@ function createRecordsClient(config) {
|
|
|
6797
7116
|
"workApprovalDecide"
|
|
6798
7117
|
);
|
|
6799
7118
|
},
|
|
7119
|
+
async workDecideMany({ decisions }) {
|
|
7120
|
+
return callDoor(
|
|
7121
|
+
DOORS.workDecideMany,
|
|
7122
|
+
{ p_organization_id: org, p_decisions: decisions },
|
|
7123
|
+
"workDecideMany"
|
|
7124
|
+
);
|
|
7125
|
+
},
|
|
6800
7126
|
async workApprovalRead({ approval_id }) {
|
|
6801
7127
|
return callDoor(
|
|
6802
7128
|
DOORS.workApprovalRead,
|
|
@@ -7000,6 +7326,69 @@ function createRecordsClient(config) {
|
|
|
7000
7326
|
"tableFromExample"
|
|
7001
7327
|
);
|
|
7002
7328
|
},
|
|
7329
|
+
async tableListEverywhere() {
|
|
7330
|
+
return callDoor(
|
|
7331
|
+
DOORS.tableListEverywhere,
|
|
7332
|
+
{ p_organization_id: org },
|
|
7333
|
+
"tableListEverywhere"
|
|
7334
|
+
);
|
|
7335
|
+
},
|
|
7336
|
+
async tableSync({ home_id, spec }) {
|
|
7337
|
+
return callDoor(
|
|
7338
|
+
DOORS.tableSync,
|
|
7339
|
+
{ p_organization_id: org, p_home_id: home_id, p_spec: spec },
|
|
7340
|
+
"tableSync"
|
|
7341
|
+
);
|
|
7342
|
+
},
|
|
7343
|
+
async scopeTableProvision({ home_id, item_id, scope_id }) {
|
|
7344
|
+
return callDoor(
|
|
7345
|
+
DOORS.scopeTableProvision,
|
|
7346
|
+
{ p_organization_id: org, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
|
|
7347
|
+
"scopeTableProvision"
|
|
7348
|
+
);
|
|
7349
|
+
},
|
|
7350
|
+
async tableRowCounts({ table_ids }) {
|
|
7351
|
+
return callDoor(
|
|
7352
|
+
DOORS.tableRowCounts,
|
|
7353
|
+
{ p_organization_id: org, p_table_ids: table_ids },
|
|
7354
|
+
"tableRowCounts"
|
|
7355
|
+
);
|
|
7356
|
+
},
|
|
7357
|
+
async recordHeaders({ ids }) {
|
|
7358
|
+
return callDoor(
|
|
7359
|
+
DOORS.recordHeaders,
|
|
7360
|
+
{ p_organization_id: org, p_ids: ids },
|
|
7361
|
+
"recordHeaders"
|
|
7362
|
+
);
|
|
7363
|
+
},
|
|
7364
|
+
async tableShareOutsideGrant({ table_id, person, level }) {
|
|
7365
|
+
return callDoor(
|
|
7366
|
+
DOORS.tableShareOutsideGrant,
|
|
7367
|
+
{ p_organization_id: org, p_table_id: table_id, p_person: person, p_level: level ?? "viewer" },
|
|
7368
|
+
"tableShareOutsideGrant"
|
|
7369
|
+
);
|
|
7370
|
+
},
|
|
7371
|
+
async viewRecordOrderSet({ view_id, record_ids }) {
|
|
7372
|
+
return callDoor(
|
|
7373
|
+
DOORS.viewRecordOrderSet,
|
|
7374
|
+
{ p_organization_id: org, p_view_id: view_id, p_record_ids: record_ids },
|
|
7375
|
+
"viewRecordOrderSet"
|
|
7376
|
+
);
|
|
7377
|
+
},
|
|
7378
|
+
async readInViewOrder({ view_id, limit, offset }) {
|
|
7379
|
+
const door = await callDoor(
|
|
7380
|
+
DOORS.readRecordsInViewOrder,
|
|
7381
|
+
{ p_organization_id: org, p_view_id: view_id, p_by_id: false, p_limit: limit ?? 200, p_offset: offset ?? 0 },
|
|
7382
|
+
"readInViewOrder"
|
|
7383
|
+
);
|
|
7384
|
+
if (!door.ok) return err(door.error);
|
|
7385
|
+
return ok(
|
|
7386
|
+
(door.data ?? []).map((row) => {
|
|
7387
|
+
const { document, hidden } = unfold(row.document);
|
|
7388
|
+
return { id: row.id, document, level: row.level, hidden, position: row.position ?? null };
|
|
7389
|
+
})
|
|
7390
|
+
);
|
|
7391
|
+
},
|
|
7003
7392
|
async autonumberBackfill({ field_id }) {
|
|
7004
7393
|
return callDoor(
|
|
7005
7394
|
DOORS.autonumberBackfill,
|
|
@@ -7094,27 +7483,6 @@ function useRecordsActor() {
|
|
|
7094
7483
|
|
|
7095
7484
|
// src/react/hooks.ts
|
|
7096
7485
|
import { useCallback, useEffect, useMemo as useMemo2, useRef, useState, useSyncExternalStore } from "react";
|
|
7097
|
-
|
|
7098
|
-
// src/aggregate.ts
|
|
7099
|
-
function measureKey(measure) {
|
|
7100
|
-
return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
|
|
7101
|
-
}
|
|
7102
|
-
function stableFilterKey(filter) {
|
|
7103
|
-
if (!filter) return "{}";
|
|
7104
|
-
const keys = Object.keys(filter).sort();
|
|
7105
|
-
if (keys.length === 0) return "{}";
|
|
7106
|
-
const parts = keys.map((key) => {
|
|
7107
|
-
const value = filter[key];
|
|
7108
|
-
if (value !== null && typeof value === "object") {
|
|
7109
|
-
const window2 = value;
|
|
7110
|
-
return `${JSON.stringify(key)}:{"from":${JSON.stringify(window2.from ?? null)},"to":${JSON.stringify(window2.to ?? null)}}`;
|
|
7111
|
-
}
|
|
7112
|
-
return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
|
|
7113
|
-
});
|
|
7114
|
-
return `{${parts.join(",")}}`;
|
|
7115
|
-
}
|
|
7116
|
-
|
|
7117
|
-
// src/react/hooks.ts
|
|
7118
7486
|
function useAsync(run, deps) {
|
|
7119
7487
|
const client = useRecordsClient();
|
|
7120
7488
|
const [state, setState] = useState(
|
|
@@ -7594,6 +7962,88 @@ function useMergeField(key, state) {
|
|
|
7594
7962
|
return resolution;
|
|
7595
7963
|
}
|
|
7596
7964
|
|
|
7965
|
+
// src/react/entity-reference.ts
|
|
7966
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
7967
|
+
|
|
7968
|
+
// src/relation.ts
|
|
7969
|
+
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;
|
|
7970
|
+
function isRefLike(value) {
|
|
7971
|
+
return typeof value === "object" && value !== null && "token" in value && "id" in value;
|
|
7972
|
+
}
|
|
7973
|
+
function entityRefsOf(value) {
|
|
7974
|
+
const items = Array.isArray(value) ? value : value == null ? [] : [value];
|
|
7975
|
+
const out = [];
|
|
7976
|
+
for (const item of items) {
|
|
7977
|
+
if (!isRefLike(item)) continue;
|
|
7978
|
+
const token = String(item.token ?? "").trim().toLowerCase();
|
|
7979
|
+
const id = String(item.id ?? "").trim();
|
|
7980
|
+
if (!token || !ENTITY_REF_ID.test(id)) continue;
|
|
7981
|
+
const label = item.label;
|
|
7982
|
+
out.push({ token, id: id.toLowerCase(), label: typeof label === "string" ? label : null });
|
|
7983
|
+
}
|
|
7984
|
+
return out;
|
|
7985
|
+
}
|
|
7986
|
+
function entityRefsToWrite(value, multi) {
|
|
7987
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7988
|
+
const refs = [];
|
|
7989
|
+
for (const ref of entityRefsOf(value)) {
|
|
7990
|
+
const k = `${ref.token}:${ref.id}`;
|
|
7991
|
+
if (seen.has(k)) continue;
|
|
7992
|
+
seen.add(k);
|
|
7993
|
+
refs.push({ token: ref.token, id: ref.id });
|
|
7994
|
+
}
|
|
7995
|
+
if (multi) return refs;
|
|
7996
|
+
return refs[0] ?? null;
|
|
7997
|
+
}
|
|
7998
|
+
async function entityReferenceKinds(source) {
|
|
7999
|
+
const { data, error } = await source.rpc("entity_reference_kinds", {}, { schema: "custom" });
|
|
8000
|
+
if (error) return err(mapPgError(error, "entityReferenceKinds"));
|
|
8001
|
+
return ok(Array.isArray(data) ? data : []);
|
|
8002
|
+
}
|
|
8003
|
+
async function entityReferenceWords(source, organizationId, refs) {
|
|
8004
|
+
if (refs.length === 0) return ok([]);
|
|
8005
|
+
const { data, error } = await source.rpc(
|
|
8006
|
+
"entity_reference_words",
|
|
8007
|
+
{ p_organization_id: organizationId, p_refs: refs.map((r) => ({ token: r.token, id: r.id })) },
|
|
8008
|
+
{ schema: "custom" }
|
|
8009
|
+
);
|
|
8010
|
+
if (error) return err(mapPgError(error, "entityReferenceWords"));
|
|
8011
|
+
return ok(entityRefsOf(data));
|
|
8012
|
+
}
|
|
8013
|
+
|
|
8014
|
+
// src/react/entity-reference.ts
|
|
8015
|
+
function useEntityReferenceKinds() {
|
|
8016
|
+
const client = useRecordsClient();
|
|
8017
|
+
const [state, setState] = useState2({ data: null, loading: true, error: null });
|
|
8018
|
+
useEffect2(() => {
|
|
8019
|
+
let live = true;
|
|
8020
|
+
void entityReferenceKinds(client.config.dataSource).then((res) => {
|
|
8021
|
+
if (!live) return;
|
|
8022
|
+
setState(res.ok ? { data: res.data, loading: false, error: null } : { data: null, loading: false, error: res.error });
|
|
8023
|
+
});
|
|
8024
|
+
return () => {
|
|
8025
|
+
live = false;
|
|
8026
|
+
};
|
|
8027
|
+
}, [client]);
|
|
8028
|
+
return state;
|
|
8029
|
+
}
|
|
8030
|
+
function useEntityReferenceWords(refs) {
|
|
8031
|
+
const client = useRecordsClient();
|
|
8032
|
+
const key = refs.map((r) => `${r.token}:${r.id}`).join(",");
|
|
8033
|
+
const [state, setState] = useState2({ data: null, loading: refs.length > 0, error: null });
|
|
8034
|
+
useEffect2(() => {
|
|
8035
|
+
let live = true;
|
|
8036
|
+
void entityReferenceWords(client.config.dataSource, client.config.organizationId, refs).then((res) => {
|
|
8037
|
+
if (!live) return;
|
|
8038
|
+
setState(res.ok ? { data: res.data, loading: false, error: null } : { data: null, loading: false, error: res.error });
|
|
8039
|
+
});
|
|
8040
|
+
return () => {
|
|
8041
|
+
live = false;
|
|
8042
|
+
};
|
|
8043
|
+
}, [client, key]);
|
|
8044
|
+
return state;
|
|
8045
|
+
}
|
|
8046
|
+
|
|
7597
8047
|
// src/vocabulary.ts
|
|
7598
8048
|
var TABLE_TYPES = [
|
|
7599
8049
|
"entity",
|
|
@@ -7705,6 +8155,7 @@ var FIELD_KINDS = [
|
|
|
7705
8155
|
"currency",
|
|
7706
8156
|
"datetime",
|
|
7707
8157
|
"email",
|
|
8158
|
+
"entity_reference",
|
|
7708
8159
|
"formula",
|
|
7709
8160
|
"json",
|
|
7710
8161
|
"long_text",
|
|
@@ -7743,6 +8194,7 @@ function fieldKindFor(field, kernel) {
|
|
|
7743
8194
|
case "list":
|
|
7744
8195
|
return field.multi ? "multi_select" : "select";
|
|
7745
8196
|
case "relation": {
|
|
8197
|
+
if (isEntityReferenceConfig(config)) return "entity_reference";
|
|
7746
8198
|
const parity = String(config["parity"] ?? "");
|
|
7747
8199
|
if (parity === "attachment" || parity === "member") return parity;
|
|
7748
8200
|
if (kernel?.file && field.relation_target === kernel.file) return "attachment";
|
|
@@ -7760,6 +8212,14 @@ function fieldKindFor(field, kernel) {
|
|
|
7760
8212
|
}
|
|
7761
8213
|
}
|
|
7762
8214
|
var UUID_TEXT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8215
|
+
function isEntityReferenceConfig(config) {
|
|
8216
|
+
const allowed = config?.["allowed_types"];
|
|
8217
|
+
return Array.isArray(allowed) && allowed.length > 0;
|
|
8218
|
+
}
|
|
8219
|
+
function entityReferenceKindsOf(field) {
|
|
8220
|
+
const allowed = field.config?.["allowed_types"];
|
|
8221
|
+
return Array.isArray(allowed) ? allowed.map((k) => String(k).trim().toLowerCase()).filter(Boolean) : [];
|
|
8222
|
+
}
|
|
7763
8223
|
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
7764
8224
|
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
7765
8225
|
function coercionLabel(field) {
|
|
@@ -7875,6 +8335,23 @@ function coerceTypedAnswer(field, raw, opts = {}) {
|
|
|
7875
8335
|
return {
|
|
7876
8336
|
refusal: `${label} points at another record, so it is chosen rather than typed. Open it and pick the record.`
|
|
7877
8337
|
};
|
|
8338
|
+
// SC-R / P12. An entity reference names a platform thing by kind and id.
|
|
8339
|
+
// An import or an agent may hand over `note:<id>` — or a bare id when the
|
|
8340
|
+
// column allows exactly one kind; the store then decides whether the thing
|
|
8341
|
+
// is there and whether the writer may open it. Words are chosen, not typed.
|
|
8342
|
+
case "entity_reference": {
|
|
8343
|
+
const allowed = entityReferenceKindsOf(field);
|
|
8344
|
+
const [maybeToken, maybeId] = text.includes(":") ? text.split(/:(.*)/s, 2) : ["", text];
|
|
8345
|
+
const token = (maybeToken ?? "").trim().toLowerCase() || (allowed.length === 1 ? allowed[0] : "");
|
|
8346
|
+
const id = (maybeId ?? "").trim();
|
|
8347
|
+
if (token && UUID_TEXT.test(id)) {
|
|
8348
|
+
const ref = { token, id: id.toLowerCase() };
|
|
8349
|
+
return { value: field.multi ? [ref] : ref };
|
|
8350
|
+
}
|
|
8351
|
+
return {
|
|
8352
|
+
refusal: `${label} points at something on the platform, so it is chosen rather than typed. Open it and pick it.`
|
|
8353
|
+
};
|
|
8354
|
+
}
|
|
7878
8355
|
case "formula":
|
|
7879
8356
|
case "lookup":
|
|
7880
8357
|
case "rollup":
|
|
@@ -7931,6 +8408,10 @@ function publicFormPath(formId) {
|
|
|
7931
8408
|
}
|
|
7932
8409
|
|
|
7933
8410
|
// src/portal.ts
|
|
8411
|
+
var PORTAL_ACCENTS = ["slate", "green", "amber", "red", "blue", "violet", "teal"];
|
|
8412
|
+
function isPortalAccent(word) {
|
|
8413
|
+
return typeof word === "string" && PORTAL_ACCENTS.includes(word);
|
|
8414
|
+
}
|
|
7934
8415
|
function portalPath(slug) {
|
|
7935
8416
|
return `/portal/c/${slug}`;
|
|
7936
8417
|
}
|
|
@@ -8021,7 +8502,7 @@ function memoryStore() {
|
|
|
8021
8502
|
setMeta: async (key, value) => void meta.set(key, value)
|
|
8022
8503
|
};
|
|
8023
8504
|
}
|
|
8024
|
-
function
|
|
8505
|
+
function countOf2(items) {
|
|
8025
8506
|
const c = { waiting: 0, sending: 0, refused: 0, landed: 0 };
|
|
8026
8507
|
for (const i of items) c[i.state] += 1;
|
|
8027
8508
|
return c;
|
|
@@ -8038,7 +8519,7 @@ function openCaptureQueue(opts) {
|
|
|
8038
8519
|
const announce = async () => {
|
|
8039
8520
|
if (!opts.onChange) return;
|
|
8040
8521
|
const items = await store.all();
|
|
8041
|
-
opts.onChange(
|
|
8522
|
+
opts.onChange(countOf2(items), items);
|
|
8042
8523
|
};
|
|
8043
8524
|
const oldestFirst = (items) => items.slice().sort((a, b) => a.captured_at.localeCompare(b.captured_at));
|
|
8044
8525
|
const queue = {
|
|
@@ -8067,7 +8548,7 @@ function openCaptureQueue(opts) {
|
|
|
8067
8548
|
return key;
|
|
8068
8549
|
},
|
|
8069
8550
|
list: () => store.all().then(oldestFirst),
|
|
8070
|
-
counts: () => store.all().then(
|
|
8551
|
+
counts: () => store.all().then(countOf2),
|
|
8071
8552
|
async sync() {
|
|
8072
8553
|
if (syncing) return syncing;
|
|
8073
8554
|
syncing = (async () => {
|
|
@@ -8263,6 +8744,7 @@ export {
|
|
|
8263
8744
|
PERMISSION_LEVELS,
|
|
8264
8745
|
PER_VALUE_ACCESS_WORDS,
|
|
8265
8746
|
PIPELINE_RULE_KINDS,
|
|
8747
|
+
PORTAL_ACCENTS,
|
|
8266
8748
|
PORTAL_ARCHIVE_FILTERS,
|
|
8267
8749
|
REFUSALS_WORTH_REPEATING,
|
|
8268
8750
|
RELATION_BINDINGS,
|
|
@@ -8298,6 +8780,11 @@ export {
|
|
|
8298
8780
|
coercionLabel,
|
|
8299
8781
|
emptyArchiveLine,
|
|
8300
8782
|
emptyPortalArchiveLine,
|
|
8783
|
+
entityReferenceKinds,
|
|
8784
|
+
entityReferenceKindsOf,
|
|
8785
|
+
entityReferenceWords,
|
|
8786
|
+
entityRefsOf,
|
|
8787
|
+
entityRefsToWrite,
|
|
8301
8788
|
err,
|
|
8302
8789
|
exampleSpec,
|
|
8303
8790
|
exportPageXlsx,
|
|
@@ -8308,20 +8795,31 @@ export {
|
|
|
8308
8795
|
indexedDbStore,
|
|
8309
8796
|
isArchiveLane,
|
|
8310
8797
|
isDecided,
|
|
8798
|
+
isEntityReferenceConfig,
|
|
8311
8799
|
isOwnOp,
|
|
8800
|
+
isPortalAccent,
|
|
8312
8801
|
isPortalArchiveFilter,
|
|
8313
8802
|
isRecordsErr,
|
|
8803
|
+
isRuleFilter,
|
|
8314
8804
|
isTheChosen,
|
|
8805
|
+
keptGroups,
|
|
8806
|
+
keptOutOfSight,
|
|
8807
|
+
keptTableHref,
|
|
8315
8808
|
looksLikeAnId,
|
|
8316
8809
|
mayDrag,
|
|
8317
8810
|
measureKey,
|
|
8318
8811
|
memoryStore,
|
|
8319
8812
|
mintClientKey,
|
|
8320
8813
|
mintOpId,
|
|
8814
|
+
moveConsequence,
|
|
8815
|
+
moveInOrder,
|
|
8816
|
+
offeredAsContext,
|
|
8321
8817
|
ok,
|
|
8322
8818
|
openCaptureQueue,
|
|
8323
8819
|
optionKey,
|
|
8324
8820
|
optionLabel,
|
|
8821
|
+
parseTableHome,
|
|
8822
|
+
parseTableMoved,
|
|
8325
8823
|
portalArchiveConsequence,
|
|
8326
8824
|
portalConfirmLine,
|
|
8327
8825
|
portalPath,
|
|
@@ -8331,12 +8829,15 @@ export {
|
|
|
8331
8829
|
rememberedOpCount,
|
|
8332
8830
|
sameDocument,
|
|
8333
8831
|
scopeChip,
|
|
8832
|
+
sheetSyncSpec,
|
|
8334
8833
|
stableFilterKey,
|
|
8335
8834
|
tableShapeChanged,
|
|
8336
8835
|
useEntityFieldMutation,
|
|
8337
8836
|
useEntityFieldRights,
|
|
8338
8837
|
useEntityFields,
|
|
8339
8838
|
useEntityRecord,
|
|
8839
|
+
useEntityReferenceKinds,
|
|
8840
|
+
useEntityReferenceWords,
|
|
8340
8841
|
useEntityTable,
|
|
8341
8842
|
useFieldMutation,
|
|
8342
8843
|
useFields,
|
|
@@ -8352,6 +8853,8 @@ export {
|
|
|
8352
8853
|
useRecordsClient,
|
|
8353
8854
|
useTable,
|
|
8354
8855
|
useTableArchive,
|
|
8355
|
-
useTables
|
|
8856
|
+
useTables,
|
|
8857
|
+
withRowCounts,
|
|
8858
|
+
withTablePlacement
|
|
8356
8859
|
};
|
|
8357
8860
|
//# sourceMappingURL=index.js.map
|