@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.
@@ -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
- { p_organization_id: org, p_dashboard_id: dashboard_id, p_filter: filter ?? {} },
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 countOf(items) {
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(countOf(items), items);
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(countOf),
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