@ai-matrx/records 0.57.3 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,16 +2273,24 @@ __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
+ moveInOrder: () => moveInOrder,
2293
+ offeredAsContext: () => offeredAsContext,
2280
2294
  ok: () => ok,
2281
2295
  openCaptureQueue: () => openCaptureQueue,
2282
2296
  optionKey: () => optionKey,
@@ -2290,12 +2304,15 @@ __export(react_exports, {
2290
2304
  rememberedOpCount: () => rememberedOpCount,
2291
2305
  sameDocument: () => sameDocument,
2292
2306
  scopeChip: () => scopeChip,
2307
+ sheetSyncSpec: () => sheetSyncSpec,
2293
2308
  stableFilterKey: () => stableFilterKey,
2294
2309
  tableShapeChanged: () => tableShapeChanged,
2295
2310
  useEntityFieldMutation: () => useEntityFieldMutation,
2296
2311
  useEntityFieldRights: () => useEntityFieldRights,
2297
2312
  useEntityFields: () => useEntityFields,
2298
2313
  useEntityRecord: () => useEntityRecord,
2314
+ useEntityReferenceKinds: () => useEntityReferenceKinds,
2315
+ useEntityReferenceWords: () => useEntityReferenceWords,
2299
2316
  useEntityTable: () => useEntityTable,
2300
2317
  useFieldMutation: () => useFieldMutation,
2301
2318
  useFields: () => useFields,
@@ -2311,7 +2328,9 @@ __export(react_exports, {
2311
2328
  useRecordsClient: () => useRecordsClient,
2312
2329
  useTable: () => useTable,
2313
2330
  useTableArchive: () => useTableArchive,
2314
- useTables: () => useTables
2331
+ useTables: () => useTables,
2332
+ withRowCounts: () => withRowCounts,
2333
+ withTablePlacement: () => withTablePlacement
2315
2334
  });
2316
2335
  module.exports = __toCommonJS(react_exports);
2317
2336
 
@@ -2358,6 +2377,31 @@ function sameDocument(a, b) {
2358
2377
  return JSON.stringify(a) === JSON.stringify(b);
2359
2378
  }
2360
2379
 
2380
+ // src/aggregate.ts
2381
+ function isRuleFilter(filter) {
2382
+ if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
2383
+ const node = filter;
2384
+ return typeof node.op === "string" && Array.isArray(node.args);
2385
+ }
2386
+ function measureKey(measure) {
2387
+ return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
2388
+ }
2389
+ function stableFilterKey(filter) {
2390
+ if (!filter) return "{}";
2391
+ if (isRuleFilter(filter)) return JSON.stringify(filter);
2392
+ const keys = Object.keys(filter).sort();
2393
+ if (keys.length === 0) return "{}";
2394
+ const parts = keys.map((key) => {
2395
+ const value = filter[key];
2396
+ if (value !== null && typeof value === "object") {
2397
+ const window2 = value;
2398
+ return `${JSON.stringify(key)}:{"from":${JSON.stringify(window2.from ?? null)},"to":${JSON.stringify(window2.to ?? null)}}`;
2399
+ }
2400
+ return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
2401
+ });
2402
+ return `{${parts.join(",")}}`;
2403
+ }
2404
+
2361
2405
  // src/ops.ts
2362
2406
  var REMEMBER_MS = 3e4;
2363
2407
  var REMEMBER_MAX = 500;
@@ -2513,6 +2557,51 @@ function recordChangeTrigger(tableId, options = {}) {
2513
2557
  ...options.changedFields && options.changedFields.length > 0 ? { changed_fields: options.changedFields } : {}
2514
2558
  };
2515
2559
  }
2560
+ function sheetSyncSpec(args) {
2561
+ const [header = [], ...body] = args.cells;
2562
+ const columns = header.map((c, i) => {
2563
+ const name = c == null ? "" : String(c).trim();
2564
+ return name === "" ? `Column ${i + 1}` : name;
2565
+ });
2566
+ if (columns.length === 0) {
2567
+ throw new Error("The sheet has no header row, so there are no columns to sync. Nothing was sent.");
2568
+ }
2569
+ const seenCol = /* @__PURE__ */ new Set();
2570
+ for (const c of columns) {
2571
+ if (seenCol.has(c)) throw new Error(`The sheet has two columns named "${c}". Rename one and sync again.`);
2572
+ seenCol.add(c);
2573
+ }
2574
+ const refIdx = args.refColumn == null ? -1 : columns.indexOf(args.refColumn);
2575
+ if (args.refColumn != null && refIdx < 0) {
2576
+ throw new Error(`The id column "${args.refColumn}" is not in the sheet's header. Nothing was sent.`);
2577
+ }
2578
+ const seen = /* @__PURE__ */ new Set();
2579
+ const rows = [];
2580
+ body.forEach((cells, i) => {
2581
+ if (cells.every((v) => v == null || String(v).trim() === "")) return;
2582
+ const ref = refIdx >= 0 ? String(cells[refIdx] ?? "").trim() : `row-${i + 2}`;
2583
+ if (ref === "") throw new Error(`Sheet row ${i + 2} has no value in the id column "${args.refColumn}".`);
2584
+ if (seen.has(ref)) throw new Error(`Two sheet rows share the id "${ref}"; each row needs its own.`);
2585
+ seen.add(ref);
2586
+ const values = {};
2587
+ columns.forEach((c, j) => {
2588
+ const v = cells[j];
2589
+ values[c] = v === void 0 || v === "" ? null : v;
2590
+ });
2591
+ rows.push({ ref, values });
2592
+ });
2593
+ return { source: args.source, table_name: args.tableName, columns, rows };
2594
+ }
2595
+ function withRowCounts(tables, counts) {
2596
+ if (!counts) return [...tables];
2597
+ const byId = new Map(counts.map((c) => [c.table_id, Number(c.visible_rows)]));
2598
+ return tables.map((t) => byId.has(t.id) ? { ...t, row_count: byId.get(t.id) } : t);
2599
+ }
2600
+ function moveInOrder(order, moved, toIndex) {
2601
+ const rest = order.filter((id) => id !== moved);
2602
+ const at = Math.max(0, Math.min(Math.trunc(toIndex), rest.length));
2603
+ return [...rest.slice(0, at), moved, ...rest.slice(at)];
2604
+ }
2516
2605
 
2517
2606
  // src/store.generated.ts
2518
2607
  var ACTOR_VOCABULARY = ["user", "agent", "system"];
@@ -3188,6 +3277,7 @@ var STORE_DOORS = [
3188
3277
  { name: "table_work_kind", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
3189
3278
  { 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
3279
  { name: "tables_described_without_asking", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
3280
+ { 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
3281
  { 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
3282
  { name: "trg_associations_bump_visibility", args: "", returns: "trigger", security: "definer" },
3193
3283
  { name: "undeclared_keys", args: "p_organization_id uuid, p_table_id uuid, p_data jsonb", returns: "text[]", security: "invoker" },
@@ -3212,6 +3302,7 @@ var STORE_DOORS = [
3212
3302
  { 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
3303
  { name: "visible_record_ids", args: "p_user_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level", returns: "TABLE(id uuid)", security: "definer" },
3214
3304
  { 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" },
3305
+ { name: "where_id_opens", args: "p_id uuid", returns: "jsonb", security: "definer" },
3215
3306
  { name: "widget_kernel_id", args: "", returns: "uuid", security: "invoker" },
3216
3307
  { name: "withheld_marker", args: "p_mask jsonb, p_key text", returns: "jsonb", security: "invoker" },
3217
3308
  { name: "withheld_sentence", args: "p_mask jsonb, p_key text", returns: "text", security: "invoker" },
@@ -3318,7 +3409,7 @@ var STORE_REFUSAL_CODES = [
3318
3409
  { 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
3410
  { 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
3411
  { 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" },
3412
+ { 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
3413
  { code: "42703", raised_by: "entity_table,portal_declare" },
3323
3414
  { code: "53400", raised_by: "anon_rate_take,delete_cascade_closure,enrich_due,enrich_land,promote_field" },
3324
3415
  { code: "54000", raised_by: "action_run,hub_changed_by,table_decorate,table_from_example,table_webhook_declare" },
@@ -4379,6 +4470,20 @@ var OWED_BY = {
4379
4470
  table_webhook_archive: "GRID-PRIMITIVES G4 \u2014 gridprim_every_row_change_reaches_the_webhook.sql (chair's production apply)",
4380
4471
  table_from_example: "GRID-PRIMITIVES G5 \u2014 gridprim_a_table_can_start_from_a_real_example.sql (chair's production apply)",
4381
4472
  autonumber_backfill: "GRID-PRIMITIVES G5 \u2014 gridprim_a_table_can_start_from_a_real_example.sql (chair's production apply)",
4473
+ table_list_everywhere: "GRID-PRIMITIVES G9 \u2014 gridprim_every_picker_lists_both_stores.sql (chair's production apply)",
4474
+ table_sync: "GRID-PRIMITIVES G10 \u2014 gridprim_a_synced_sheet_is_one_table_that_refreshes.sql (chair's production apply)",
4475
+ scope_table_provision: "GRID-PRIMITIVES G11 \u2014 gridprim_a_scope_provisions_its_table_in_the_store.sql (chair's production apply)",
4476
+ 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)",
4477
+ 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)",
4478
+ 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)",
4479
+ 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)",
4480
+ 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)",
4481
+ 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)",
4482
+ 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)",
4483
+ 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)",
4484
+ 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)",
4485
+ 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)",
4486
+ 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
4487
  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
4488
  };
4384
4489
  var TRUST_SCHEMA = "iam";
@@ -4582,6 +4687,8 @@ var DOORS = {
4582
4687
  pipelineBoard: "pipeline_board",
4583
4688
  pipelineTransitionRefusal: "pipeline_transition_refusal",
4584
4689
  pipelineMove: "pipeline_move",
4690
+ /** Lane S4: many cards, one call, a verdict and a version per card. */
4691
+ pipelineMoveMany: "pipeline_move_many",
4585
4692
  tableStageField: "table_stage_field",
4586
4693
  // STAGE-RULES. A gate can refuse or it can hand the change to the approvals queue; the
4587
4694
  // closed list is the store's, the knob is the organization's, and what is WAITING on a
@@ -4592,6 +4699,7 @@ var DOORS = {
4592
4699
  pipelinePending: "pipeline_pending",
4593
4700
  pipelineGatePreview: "pipeline_gate_preview",
4594
4701
  ruleMembers: "rule_members",
4702
+ ruleMembersVisible: "rule_members_visible",
4595
4703
  ruleMembership: "rule_membership",
4596
4704
  ruleRun: "rule_run",
4597
4705
  ruleEval: "rule_eval",
@@ -4606,6 +4714,12 @@ var DOORS = {
4606
4714
  // are server-lane doors and a browser never calls them.
4607
4715
  forms: "forms",
4608
4716
  formDeclare: "form_declare",
4717
+ /**
4718
+ * WHICH QUESTIONS THE OWNER'S PREVIEW ASKS NEXT (lane FORMS-FIX-1). The same store answer a
4719
+ * stranger's form gets (`custom._form_questions_asked` → `custom.rule_eval`), behind the
4720
+ * organization wall and the caller's own rung on the Table — never `rule_eval` from a browser.
4721
+ */
4722
+ formPreviewAsks: "form_preview_asks",
4609
4723
  // PRODUCTS row 14 — "let clients book a 30-minute consult". A booking page IS an
4610
4724
  // `anon_form`, so it is opened and closed by `anonPublish` like any other; this is
4611
4725
  // the owner's list of them with the numbers that make it worth opening. The
@@ -4665,6 +4779,11 @@ var DOORS = {
4665
4779
  portalInvite: "portal_invite",
4666
4780
  portalRevoke: "portal_revoke",
4667
4781
  portalPreview: "portal_preview",
4782
+ // S6 — the CLIENT's two form doors. They are store doors (schema `custom`), called by a
4783
+ // signed-in portal principal, and each refuses anybody who is not a live principal of that
4784
+ // live portal — so, unlike the sign-in pair above, they belong in this table.
4785
+ portalForm: "portal_form",
4786
+ portalFormSubmit: "portal_form_submit",
4668
4787
  // ORG-CLEANUP, 2026-09-22 — A PORTAL IS ARCHIVED, NEVER DELETED.
4669
4788
  // `portals` keeps its signature and HIDES archived portals (the law's default
4670
4789
  // is to hide); `list_portals(org, 'active'|'archived'|'all')` is the
@@ -4860,6 +4979,8 @@ var DOORS = {
4860
4979
  workApprovalRequest: "work_approval_request",
4861
4980
  workApprovalMayDecide: "work_approval_may_decide",
4862
4981
  workApprovalDecide: "work_approval_decide",
4982
+ /** Lane S4: many inbox decisions, one call, a verdict per item. */
4983
+ workDecideMany: "work_decide_many",
4863
4984
  workApprovalRead: "work_approval_read",
4864
4985
  // PRODUCTS row 13 — checklists and SOP runs.
4865
4986
  checklistRefusal: "checklist_refusal",
@@ -4885,6 +5006,14 @@ var DOORS = {
4885
5006
  tableFromExample: "table_from_example",
4886
5007
  autonumberBackfill: "autonumber_backfill",
4887
5008
  ioExport: "io_export",
5009
+ tableListEverywhere: "table_list_everywhere",
5010
+ tableSync: "table_sync",
5011
+ scopeTableProvision: "scope_table_provision",
5012
+ tableRowCounts: "table_row_counts",
5013
+ recordHeaders: "record_headers",
5014
+ viewRecordOrderSet: "view_record_order_set",
5015
+ readRecordsInViewOrder: "read_records_in_view_order",
5016
+ tableShareOutsideGrant: "table_share_outside_grant",
4888
5017
  // Declared here BECAUSE they do not exist yet: naming them is what makes the
4889
5018
  // absence visible to `pnpm check:store-registry` and to the suite.
4890
5019
  metadataSearch: "metadata_search",
@@ -5664,10 +5793,11 @@ function createRecordsClient(config) {
5664
5793
  "pipelineRead"
5665
5794
  );
5666
5795
  },
5667
- async pipelineBoard({ table_id, measure }) {
5796
+ async pipelineBoard({ table_id, measure, filter }) {
5797
+ const asked = filter && stableFilterKey(filter) !== "{}";
5668
5798
  return callDoor(
5669
5799
  DOORS.pipelineBoard,
5670
- { p_organization_id: org, p_table_id: table_id, p_measure: measure ?? null },
5800
+ 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
5801
  "pipelineBoard"
5672
5802
  );
5673
5803
  },
@@ -5691,6 +5821,13 @@ function createRecordsClient(config) {
5691
5821
  "pipelineMove"
5692
5822
  );
5693
5823
  },
5824
+ async pipelineMoveMany({ moves }) {
5825
+ return callDoor(
5826
+ DOORS.pipelineMoveMany,
5827
+ { p_organization_id: org, p_moves: moves },
5828
+ "pipelineMoveMany"
5829
+ );
5830
+ },
5694
5831
  async pipelineDeclare({ table_id, spec }) {
5695
5832
  return callDoor(
5696
5833
  DOORS.pipelineDeclare,
@@ -5740,6 +5877,18 @@ function createRecordsClient(config) {
5740
5877
  "pipelineGatePreview"
5741
5878
  );
5742
5879
  },
5880
+ async ruleMembersVisible({ rule_id, limit = 200, offset = 0 }) {
5881
+ const door = await callDoor(
5882
+ DOORS.ruleMembersVisible,
5883
+ { p_organization_id: org, p_rule_id: rule_id, p_limit: limit, p_offset: offset },
5884
+ "ruleMembersVisible"
5885
+ );
5886
+ if (!door.ok) return err(door.error);
5887
+ return ok((door.data ?? []).map((row) => {
5888
+ const { document, hidden } = unfold(row.document);
5889
+ return { id: row.id, document, level: row.level, hidden };
5890
+ }));
5891
+ },
5743
5892
  async ruleMembers({ rule_id }) {
5744
5893
  return callDoor(
5745
5894
  DOORS.ruleMembers,
@@ -5792,6 +5941,13 @@ function createRecordsClient(config) {
5792
5941
  "bookingDeclare"
5793
5942
  );
5794
5943
  },
5944
+ async formPreviewAsks({ table_id, questions, values }) {
5945
+ return callDoor(
5946
+ DOORS.formPreviewAsks,
5947
+ { p_organization_id: org, p_table_id: table_id, p_questions: questions, p_values: values },
5948
+ "formPreviewAsks"
5949
+ );
5950
+ },
5795
5951
  async formDeclare(args) {
5796
5952
  return callDoor(
5797
5953
  DOORS.formDeclare,
@@ -5967,11 +6123,33 @@ function createRecordsClient(config) {
5967
6123
  p_tables: args.tables,
5968
6124
  p_portal_id: args.portal_id ?? null,
5969
6125
  p_slug: args.slug ?? null,
5970
- p_sign_in_method: args.sign_in_method ?? "magic_link"
6126
+ p_sign_in_method: args.sign_in_method ?? "magic_link",
6127
+ // S6: sent only when given, so a caller that says nothing about the look keeps it.
6128
+ ...args.config !== void 0 ? { p_config: args.config } : {}
5971
6129
  },
5972
6130
  "portalDeclare"
5973
6131
  );
5974
6132
  },
6133
+ async portalForm({ portal_id, form_id }) {
6134
+ return callDoor(
6135
+ DOORS.portalForm,
6136
+ { p_organization_id: org, p_portal_id: portal_id, p_form_id: form_id },
6137
+ "portalForm"
6138
+ );
6139
+ },
6140
+ async portalFormSubmit({ portal_id, form_id, answers, client_key }) {
6141
+ return callDoor(
6142
+ DOORS.portalFormSubmit,
6143
+ {
6144
+ p_organization_id: org,
6145
+ p_portal_id: portal_id,
6146
+ p_form_id: form_id,
6147
+ p_payload: answers,
6148
+ p_client_key: client_key ?? null
6149
+ },
6150
+ "portalFormSubmit"
6151
+ );
6152
+ },
5975
6153
  async portalInvite(args) {
5976
6154
  return callDoor(
5977
6155
  DOORS.portalInvite,
@@ -6170,10 +6348,17 @@ function createRecordsClient(config) {
6170
6348
  "dashboardDeclare"
6171
6349
  );
6172
6350
  },
6173
- async dashboardRun({ dashboard_id, filter }) {
6351
+ async dashboardRun({ dashboard_id, filter, compare, grain }) {
6174
6352
  return callDoor(
6175
6353
  DOORS.dashboardRun,
6176
- { p_organization_id: org, p_dashboard_id: dashboard_id, p_filter: filter ?? {} },
6354
+ {
6355
+ p_organization_id: org,
6356
+ p_dashboard_id: dashboard_id,
6357
+ p_filter: filter ?? {},
6358
+ // Sent only when asked, so a caller that never compares calls exactly what it did.
6359
+ ...compare ? { p_compare: compare } : {},
6360
+ ...grain ? { p_grain: grain } : {}
6361
+ },
6177
6362
  "dashboardRun"
6178
6363
  );
6179
6364
  },
@@ -6198,7 +6383,7 @@ function createRecordsClient(config) {
6198
6383
  "dashboardDelete"
6199
6384
  );
6200
6385
  },
6201
- async recordAggregate({ table_id, groupBy, measures, bucket, filter, limit }) {
6386
+ async recordAggregate({ table_id, groupBy, measures, bucket, filter, limit, compare }) {
6202
6387
  return callDoor(
6203
6388
  DOORS.recordAggregate,
6204
6389
  {
@@ -6208,7 +6393,8 @@ function createRecordsClient(config) {
6208
6393
  p_measures: measures ?? [],
6209
6394
  p_bucket: bucket ?? null,
6210
6395
  p_filter: filter ?? {},
6211
- p_limit: limit ?? 200
6396
+ p_limit: limit ?? 200,
6397
+ ...compare ? { p_compare: compare } : {}
6212
6398
  },
6213
6399
  "recordAggregate"
6214
6400
  );
@@ -6936,6 +7122,13 @@ function createRecordsClient(config) {
6936
7122
  "workApprovalDecide"
6937
7123
  );
6938
7124
  },
7125
+ async workDecideMany({ decisions }) {
7126
+ return callDoor(
7127
+ DOORS.workDecideMany,
7128
+ { p_organization_id: org, p_decisions: decisions },
7129
+ "workDecideMany"
7130
+ );
7131
+ },
6939
7132
  async workApprovalRead({ approval_id }) {
6940
7133
  return callDoor(
6941
7134
  DOORS.workApprovalRead,
@@ -7139,6 +7332,69 @@ function createRecordsClient(config) {
7139
7332
  "tableFromExample"
7140
7333
  );
7141
7334
  },
7335
+ async tableListEverywhere() {
7336
+ return callDoor(
7337
+ DOORS.tableListEverywhere,
7338
+ { p_organization_id: org },
7339
+ "tableListEverywhere"
7340
+ );
7341
+ },
7342
+ async tableSync({ home_id, spec }) {
7343
+ return callDoor(
7344
+ DOORS.tableSync,
7345
+ { p_organization_id: org, p_home_id: home_id, p_spec: spec },
7346
+ "tableSync"
7347
+ );
7348
+ },
7349
+ async scopeTableProvision({ home_id, item_id, scope_id }) {
7350
+ return callDoor(
7351
+ DOORS.scopeTableProvision,
7352
+ { p_organization_id: org, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
7353
+ "scopeTableProvision"
7354
+ );
7355
+ },
7356
+ async tableRowCounts({ table_ids }) {
7357
+ return callDoor(
7358
+ DOORS.tableRowCounts,
7359
+ { p_organization_id: org, p_table_ids: table_ids },
7360
+ "tableRowCounts"
7361
+ );
7362
+ },
7363
+ async recordHeaders({ ids }) {
7364
+ return callDoor(
7365
+ DOORS.recordHeaders,
7366
+ { p_organization_id: org, p_ids: ids },
7367
+ "recordHeaders"
7368
+ );
7369
+ },
7370
+ async tableShareOutsideGrant({ table_id, person, level }) {
7371
+ return callDoor(
7372
+ DOORS.tableShareOutsideGrant,
7373
+ { p_organization_id: org, p_table_id: table_id, p_person: person, p_level: level ?? "viewer" },
7374
+ "tableShareOutsideGrant"
7375
+ );
7376
+ },
7377
+ async viewRecordOrderSet({ view_id, record_ids }) {
7378
+ return callDoor(
7379
+ DOORS.viewRecordOrderSet,
7380
+ { p_organization_id: org, p_view_id: view_id, p_record_ids: record_ids },
7381
+ "viewRecordOrderSet"
7382
+ );
7383
+ },
7384
+ async readInViewOrder({ view_id, limit, offset }) {
7385
+ const door = await callDoor(
7386
+ DOORS.readRecordsInViewOrder,
7387
+ { p_organization_id: org, p_view_id: view_id, p_by_id: false, p_limit: limit ?? 200, p_offset: offset ?? 0 },
7388
+ "readInViewOrder"
7389
+ );
7390
+ if (!door.ok) return err(door.error);
7391
+ return ok(
7392
+ (door.data ?? []).map((row) => {
7393
+ const { document, hidden } = unfold(row.document);
7394
+ return { id: row.id, document, level: row.level, hidden, position: row.position ?? null };
7395
+ })
7396
+ );
7397
+ },
7142
7398
  async autonumberBackfill({ field_id }) {
7143
7399
  return callDoor(
7144
7400
  DOORS.autonumberBackfill,
@@ -7233,27 +7489,6 @@ function useRecordsActor() {
7233
7489
 
7234
7490
  // src/react/hooks.ts
7235
7491
  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
7492
  function useAsync(run, deps) {
7258
7493
  const client = useRecordsClient();
7259
7494
  const [state, setState] = (0, import_react2.useState)(
@@ -7733,6 +7968,88 @@ function useMergeField(key, state) {
7733
7968
  return resolution;
7734
7969
  }
7735
7970
 
7971
+ // src/react/entity-reference.ts
7972
+ var import_react3 = require("react");
7973
+
7974
+ // src/relation.ts
7975
+ 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;
7976
+ function isRefLike(value) {
7977
+ return typeof value === "object" && value !== null && "token" in value && "id" in value;
7978
+ }
7979
+ function entityRefsOf(value) {
7980
+ const items = Array.isArray(value) ? value : value == null ? [] : [value];
7981
+ const out = [];
7982
+ for (const item of items) {
7983
+ if (!isRefLike(item)) continue;
7984
+ const token = String(item.token ?? "").trim().toLowerCase();
7985
+ const id = String(item.id ?? "").trim();
7986
+ if (!token || !ENTITY_REF_ID.test(id)) continue;
7987
+ const label = item.label;
7988
+ out.push({ token, id: id.toLowerCase(), label: typeof label === "string" ? label : null });
7989
+ }
7990
+ return out;
7991
+ }
7992
+ function entityRefsToWrite(value, multi) {
7993
+ const seen = /* @__PURE__ */ new Set();
7994
+ const refs = [];
7995
+ for (const ref of entityRefsOf(value)) {
7996
+ const k = `${ref.token}:${ref.id}`;
7997
+ if (seen.has(k)) continue;
7998
+ seen.add(k);
7999
+ refs.push({ token: ref.token, id: ref.id });
8000
+ }
8001
+ if (multi) return refs;
8002
+ return refs[0] ?? null;
8003
+ }
8004
+ async function entityReferenceKinds(source) {
8005
+ const { data, error } = await source.rpc("entity_reference_kinds", {}, { schema: "custom" });
8006
+ if (error) return err(mapPgError(error, "entityReferenceKinds"));
8007
+ return ok(Array.isArray(data) ? data : []);
8008
+ }
8009
+ async function entityReferenceWords(source, organizationId, refs) {
8010
+ if (refs.length === 0) return ok([]);
8011
+ const { data, error } = await source.rpc(
8012
+ "entity_reference_words",
8013
+ { p_organization_id: organizationId, p_refs: refs.map((r) => ({ token: r.token, id: r.id })) },
8014
+ { schema: "custom" }
8015
+ );
8016
+ if (error) return err(mapPgError(error, "entityReferenceWords"));
8017
+ return ok(entityRefsOf(data));
8018
+ }
8019
+
8020
+ // src/react/entity-reference.ts
8021
+ function useEntityReferenceKinds() {
8022
+ const client = useRecordsClient();
8023
+ const [state, setState] = (0, import_react3.useState)({ data: null, loading: true, error: null });
8024
+ (0, import_react3.useEffect)(() => {
8025
+ let live = true;
8026
+ void entityReferenceKinds(client.config.dataSource).then((res) => {
8027
+ if (!live) return;
8028
+ setState(res.ok ? { data: res.data, loading: false, error: null } : { data: null, loading: false, error: res.error });
8029
+ });
8030
+ return () => {
8031
+ live = false;
8032
+ };
8033
+ }, [client]);
8034
+ return state;
8035
+ }
8036
+ function useEntityReferenceWords(refs) {
8037
+ const client = useRecordsClient();
8038
+ const key = refs.map((r) => `${r.token}:${r.id}`).join(",");
8039
+ const [state, setState] = (0, import_react3.useState)({ data: null, loading: refs.length > 0, error: null });
8040
+ (0, import_react3.useEffect)(() => {
8041
+ let live = true;
8042
+ void entityReferenceWords(client.config.dataSource, client.config.organizationId, refs).then((res) => {
8043
+ if (!live) return;
8044
+ setState(res.ok ? { data: res.data, loading: false, error: null } : { data: null, loading: false, error: res.error });
8045
+ });
8046
+ return () => {
8047
+ live = false;
8048
+ };
8049
+ }, [client, key]);
8050
+ return state;
8051
+ }
8052
+
7736
8053
  // src/vocabulary.ts
7737
8054
  var TABLE_TYPES = [
7738
8055
  "entity",
@@ -7844,6 +8161,7 @@ var FIELD_KINDS = [
7844
8161
  "currency",
7845
8162
  "datetime",
7846
8163
  "email",
8164
+ "entity_reference",
7847
8165
  "formula",
7848
8166
  "json",
7849
8167
  "long_text",
@@ -7882,6 +8200,7 @@ function fieldKindFor(field, kernel) {
7882
8200
  case "list":
7883
8201
  return field.multi ? "multi_select" : "select";
7884
8202
  case "relation": {
8203
+ if (isEntityReferenceConfig(config)) return "entity_reference";
7885
8204
  const parity = String(config["parity"] ?? "");
7886
8205
  if (parity === "attachment" || parity === "member") return parity;
7887
8206
  if (kernel?.file && field.relation_target === kernel.file) return "attachment";
@@ -7899,6 +8218,14 @@ function fieldKindFor(field, kernel) {
7899
8218
  }
7900
8219
  }
7901
8220
  var UUID_TEXT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8221
+ function isEntityReferenceConfig(config) {
8222
+ const allowed = config?.["allowed_types"];
8223
+ return Array.isArray(allowed) && allowed.length > 0;
8224
+ }
8225
+ function entityReferenceKindsOf(field) {
8226
+ const allowed = field.config?.["allowed_types"];
8227
+ return Array.isArray(allowed) ? allowed.map((k) => String(k).trim().toLowerCase()).filter(Boolean) : [];
8228
+ }
7902
8229
  var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
7903
8230
  var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
7904
8231
  function coercionLabel(field) {
@@ -8014,6 +8341,23 @@ function coerceTypedAnswer(field, raw, opts = {}) {
8014
8341
  return {
8015
8342
  refusal: `${label} points at another record, so it is chosen rather than typed. Open it and pick the record.`
8016
8343
  };
8344
+ // SC-R / P12. An entity reference names a platform thing by kind and id.
8345
+ // An import or an agent may hand over `note:<id>` — or a bare id when the
8346
+ // column allows exactly one kind; the store then decides whether the thing
8347
+ // is there and whether the writer may open it. Words are chosen, not typed.
8348
+ case "entity_reference": {
8349
+ const allowed = entityReferenceKindsOf(field);
8350
+ const [maybeToken, maybeId] = text.includes(":") ? text.split(/:(.*)/s, 2) : ["", text];
8351
+ const token = (maybeToken ?? "").trim().toLowerCase() || (allowed.length === 1 ? allowed[0] : "");
8352
+ const id = (maybeId ?? "").trim();
8353
+ if (token && UUID_TEXT.test(id)) {
8354
+ const ref = { token, id: id.toLowerCase() };
8355
+ return { value: field.multi ? [ref] : ref };
8356
+ }
8357
+ return {
8358
+ refusal: `${label} points at something on the platform, so it is chosen rather than typed. Open it and pick it.`
8359
+ };
8360
+ }
8017
8361
  case "formula":
8018
8362
  case "lookup":
8019
8363
  case "rollup":
@@ -8070,6 +8414,10 @@ function publicFormPath(formId) {
8070
8414
  }
8071
8415
 
8072
8416
  // src/portal.ts
8417
+ var PORTAL_ACCENTS = ["slate", "green", "amber", "red", "blue", "violet", "teal"];
8418
+ function isPortalAccent(word) {
8419
+ return typeof word === "string" && PORTAL_ACCENTS.includes(word);
8420
+ }
8073
8421
  function portalPath(slug) {
8074
8422
  return `/portal/c/${slug}`;
8075
8423
  }
@@ -8092,6 +8440,56 @@ function emptyPortalArchiveLine() {
8092
8440
  return "No portal of this organization has been archived. A portal you put away waits here until somebody restores it, and nothing is ever destroyed.";
8093
8441
  }
8094
8442
 
8443
+ // src/placement.ts
8444
+ function keptOutOfSight(placement) {
8445
+ return placement?.kept_by_the_app === true;
8446
+ }
8447
+ function offeredAsContext(placement) {
8448
+ return placement?.offered_as_context === true;
8449
+ }
8450
+ function withTablePlacement(tables, facts) {
8451
+ if (!facts) return [...tables];
8452
+ const byId = new Map(facts.map((f) => [f.table_id, f]));
8453
+ return tables.map((table) => {
8454
+ const fact = byId.get(table.id);
8455
+ if (!fact || fact.kept_by_the_app === void 0) return table;
8456
+ return {
8457
+ ...table,
8458
+ kept_by_the_app: fact.kept_by_the_app,
8459
+ kept_for: fact.kept_for ?? null,
8460
+ offered_as_context: fact.offered_as_context ?? false,
8461
+ keeper_group: fact.keeper_group ?? null,
8462
+ keeper_says: fact.keeper_says ?? null,
8463
+ used_in_kind: fact.used_in_kind ?? null,
8464
+ used_in_id: fact.used_in_id ?? null,
8465
+ used_in_table_id: fact.used_in_table_id ?? null
8466
+ };
8467
+ });
8468
+ }
8469
+ function keptGroups(tables) {
8470
+ const out = [];
8471
+ const at = /* @__PURE__ */ new Map();
8472
+ for (const table of tables) {
8473
+ if (!keptOutOfSight(table)) continue;
8474
+ const group = table.keeper_group?.trim() || "Kept by the app";
8475
+ let i = at.get(group);
8476
+ if (i === void 0) {
8477
+ i = out.length;
8478
+ at.set(group, i);
8479
+ out.push({ group, tables: [] });
8480
+ }
8481
+ out[i].tables.push(table);
8482
+ }
8483
+ return out;
8484
+ }
8485
+ function keptTableHref(fact, hrefs) {
8486
+ if (fact.used_in_kind === "scope" && fact.used_in_id) return hrefs.scope(fact.used_in_id);
8487
+ if (fact.used_in_kind === "table" && (fact.used_in_table_id || fact.used_in_id)) {
8488
+ return hrefs.table(fact.used_in_table_id || fact.used_in_id);
8489
+ }
8490
+ return hrefs.table(fact.table_id);
8491
+ }
8492
+
8095
8493
  // src/capture-queue.ts
8096
8494
  var DB_NAME = "matrx-capture";
8097
8495
  var DB_VERSION = 1;