@ai-matrx/records 0.49.0 → 0.52.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.
@@ -9,6 +9,46 @@ import {
9
9
  useMemo
10
10
  } from "react";
11
11
 
12
+ // src/archive.ts
13
+ var ARCHIVE_LANES = ["mine", "org"];
14
+ var DEFAULT_ARCHIVE_LANE = "org";
15
+ var ARCHIVE_LANE_LABEL = {
16
+ mine: "Archived by me",
17
+ org: "Archived by anyone"
18
+ };
19
+ var ARCHIVE_LANE_MEANS = {
20
+ mine: "The records you archived yourself.",
21
+ org: "Everything anybody in this organization archived, including you."
22
+ };
23
+ function isArchiveLane(word) {
24
+ return typeof word === "string" && ARCHIVE_LANES.includes(word);
25
+ }
26
+ function archivedWhen(at, locale = "en-GB") {
27
+ const when = new Date(at);
28
+ if (Number.isNaN(when.getTime())) return "a moment nobody recorded";
29
+ return new Intl.DateTimeFormat(locale, {
30
+ day: "numeric",
31
+ month: "long",
32
+ year: "numeric",
33
+ hour: "2-digit",
34
+ minute: "2-digit"
35
+ }).format(when);
36
+ }
37
+ function archivedByLine(row, locale = "en-GB") {
38
+ const when = archivedWhen(row.archivedAt, locale);
39
+ const who = (row.archivedByName ?? "").trim();
40
+ if (who === "") {
41
+ return `Archived on ${when}. The store does not know who archived it \u2014 whoever did is no longer in this organization, or it happened before this table kept that.`;
42
+ }
43
+ return `Archived by ${who} on ${when}.`;
44
+ }
45
+ function emptyArchiveLine(lane) {
46
+ return lane === "mine" ? "You have not archived anything in this table. Switch to \u201CArchived by anyone\u201D to see what the rest of the organization has." : "Nothing in this table has been archived. Records you remove from the grid arrive here, and nothing is ever destroyed.";
47
+ }
48
+ function sameDocument(a, b) {
49
+ return JSON.stringify(a) === JSON.stringify(b);
50
+ }
51
+
12
52
  // src/ops.ts
13
53
  var REMEMBER_MS = 3e4;
14
54
  var REMEMBER_MAX = 500;
@@ -107,6 +147,27 @@ var PARITY_FIELD_TYPES = [
107
147
  { parity_type: "select", behavior: "list", made_of: "one choice from a Table shown as a list (FLD-5/FLD-6)" },
108
148
  { parity_type: "url", behavior: "text", made_of: "text whose format is url, with the pattern Rule that makes the format enforceable" }
109
149
  ];
150
+ var DECLARABLE_FIELD_KINDS = [
151
+ { kind: "attachment", behavior: "relation", parity: true, made_of: "REC-31: a File record reached through a relation, target the kernel `File` Table" },
152
+ { kind: "checkbox", behavior: "boolean", parity: true, made_of: "a ticked or unticked answer, stored as a REAL boolean \u2014 and a record that never answered holds neither, so filters and group-by see three states, not two" },
153
+ { kind: "currency", behavior: "range", parity: true, made_of: "FLD-N-1: a number whose UNIT is the currency and whose format is currency \u2014 on the Field, never in presentation" },
154
+ { kind: "datetime", behavior: "range", parity: true, made_of: "a range of kind date or datetime \u2014 the dated modifier says the VALUES are dated, which is a different question" },
155
+ { kind: "email", behavior: "text", parity: true, made_of: "text whose format is email" },
156
+ { kind: "formula", behavior: "formula", parity: true, made_of: "FLD-9: a declared computation, on read or on write, evaluated by custom.rule_eval" },
157
+ { kind: "long_text", behavior: "text", parity: false, made_of: "behaviour text with format long and config.multiline, for several lines rather than one" },
158
+ { kind: "lookup", behavior: "formula", parity: true, made_of: "a Value read THROUGH a relation \u2014 config.via names the relation field, config.pick the Value on the far side" },
159
+ { kind: "member", behavior: "relation", parity: true, made_of: "a person: a relation whose target is the kernel `Person` Table" },
160
+ { kind: "multi_select", behavior: "list", parity: true, made_of: "many choices from the same Table \u2014 the multi modifier, never a second behaviour" },
161
+ { kind: "number", behavior: "range", parity: false, made_of: "a plain number: behaviour range with no date kind and neither the currency nor the percent format" },
162
+ { kind: "percent", behavior: "range", parity: true, made_of: "a number whose unit is % and whose format is percent" },
163
+ { kind: "phone", behavior: "text", parity: true, made_of: "text whose format is phone" },
164
+ { kind: "relation", behavior: "relation", parity: false, made_of: "REL / FLD-11: a relation a person aims themselves \u2014 relation_target names a Table of this organization, and it is a BEHAVIOUR, never a parity type of its own" },
165
+ { kind: "rollup", behavior: "formula", parity: true, made_of: "an aggregate ALONG a relation \u2014 config.via, config.of, config.agg; far-side ids are taken DISTINCT, so nothing is counted twice" },
166
+ { kind: "select", behavior: "list", parity: true, made_of: "one choice from a Table shown as a list (FLD-5/FLD-6)" },
167
+ { kind: "signature", behavior: "text", parity: false, made_of: "VAL-10: behaviour text whose format is signature \u2014 the one shape custom.doc_sign accepts, sealed by custom.doc_signature_write and checked by custom.doc_signature_intact" },
168
+ { kind: "text", behavior: "text", parity: false, made_of: "plain text: behaviour text with no format \u2014 it carries no parity type, which is exactly what custom.parity_type answers for it" },
169
+ { kind: "url", behavior: "text", parity: true, made_of: "text whose format is url, with the pattern Rule that makes the format enforceable" }
170
+ ];
110
171
  var RULE_NODE_KINDS = [
111
172
  { node: "actor_at_least", evaluated_by: "PIPELINES" },
112
173
  { node: "add", evaluated_by: "W1-RULE" },
@@ -342,6 +403,7 @@ var STORE_DOORS = [
342
403
  { name: "field_dependants", args: "p_organization_id uuid, p_field_id uuid", returns: "TABLE(kind text, dependant_id uuid, label text, how text)", security: "definer" },
343
404
  { name: "field_history", args: "p_organization_id uuid, p_table_id uuid, p_field_key text, p_limit integer DEFAULT 100, p_offset integer DEFAULT 0, p_record_id uuid DEFAULT NULL::uuid", returns: "TABLE(record_id uuid, record_title text, version integer, occurred_at timestamp with time zone, operation_label text, actor jsonb, before jsonb, after jsonb)", security: "definer" },
344
405
  { name: "field_kernel_id", args: "", returns: "uuid", security: "invoker" },
406
+ { name: "field_kinds", args: "", returns: "TABLE(kind text, behavior text, parity boolean, made_of text)", security: "invoker" },
345
407
  { name: "field_options", args: "p_organization_id uuid, p_field_id uuid", returns: "SETOF custom.record", security: "definer" },
346
408
  { name: "field_retire", args: "p_organization_id uuid, p_field_id uuid", returns: "boolean", security: "definer" },
347
409
  { name: "field_rules", args: "p_field_data jsonb", returns: "TABLE(kind text, spec jsonb)", security: "invoker" },
@@ -390,6 +452,7 @@ var STORE_DOORS = [
390
452
  { name: "io_export", args: "p_organization_id uuid, p_table_id uuid, p_columns text[] DEFAULT NULL::text[], p_limit integer DEFAULT 10000, p_required text DEFAULT 'viewer'::text", returns: "jsonb", security: "definer" },
391
453
  { name: "io_export_csv", args: "p_organization_id uuid, p_table_id uuid, p_columns text[] DEFAULT NULL::text[], p_limit integer DEFAULT 10000, p_delimiter text DEFAULT chr(44), p_required text DEFAULT 'viewer'::text", returns: "text", security: "definer" },
392
454
  { name: "io_import_begin", args: "p_organization_id uuid, p_table_id uuid, p_format text DEFAULT 'csv'::text, p_source_name text DEFAULT NULL::text, p_source_columns jsonb DEFAULT '[]'::jsonb, p_file_hash text DEFAULT NULL::text, p_policy jsonb DEFAULT '{}'::jsonb, p_dedupe_key text DEFAULT NULL::text, p_file_bytes bigint DEFAULT NULL::bigint, p_force boolean DEFAULT false", returns: "jsonb", security: "definer" },
455
+ { name: "io_import_declare_columns", args: "p_organization_id uuid, p_table_id uuid, p_rows jsonb, p_mapping jsonb DEFAULT '{}'::jsonb", returns: "jsonb", security: "definer" },
393
456
  { name: "io_import_finish", args: "p_organization_id uuid, p_import_id uuid, p_unmapped text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
394
457
  { name: "io_import_forget", args: "p_organization_id uuid, p_import_id uuid", returns: "boolean", security: "definer" },
395
458
  { name: "io_import_open", args: "p_organization_id uuid, p_table_id uuid, p_format text DEFAULT 'csv'::text, p_source_name text DEFAULT NULL::text, p_source_columns jsonb DEFAULT '[]'::jsonb", returns: "uuid", security: "definer" },
@@ -423,6 +486,7 @@ var STORE_DOORS = [
423
486
  { name: "levels_raised_by_a_less_specific_rung", args: "", returns: "TABLE(organization_id uuid, organization_name text, member_id uuid, member_email text, record_id uuid, addressed_level permission_level, answered_level permission_level)", security: "definer" },
424
487
  { name: "list_door_disagreements", args: "p_pretend text DEFAULT NULL::text, p_only_organization uuid DEFAULT NULL::uuid, p_sample integer DEFAULT 200", returns: "TABLE(organization_id uuid, organization_name text, member_id uuid, table_id uuid, record_id uuid, door text, why text)", security: "invoker" },
425
488
  { name: "list_door_disagreements", args: "p_pretend text, p_only_organization uuid, p_sample integer, p_exhaustive boolean", returns: "TABLE(organization_id uuid, organization_name text, member_id uuid, table_id uuid, record_id uuid, door text, why text)", security: "invoker" },
489
+ { name: "list_portals", args: "p_organization_id uuid, p_archived text DEFAULT 'active'::text", returns: "TABLE(portal_id uuid, title text, slug text, client_table_id uuid, client_table text, is_active boolean, tables integer, invited integer, signed_in integer, sign_in_method text, opened_at timestamp with time zone)", security: "definer" },
426
490
  { name: "lookup_value", args: "p_organization_id uuid, p_record_id uuid, p_field_data jsonb", returns: "jsonb", security: "invoker" },
427
491
  { name: "mask_document", args: "p_document jsonb, p_visible_keys text[], p_notices jsonb, p_by_id boolean DEFAULT false, p_key_ids jsonb DEFAULT '{}'::jsonb", returns: "jsonb", security: "invoker" },
428
492
  { name: "mask_document", args: "p_document jsonb, p_visible_keys text[], p_notices jsonb, p_by_id boolean DEFAULT false, p_key_ids jsonb DEFAULT '{}'::jsonb, p_declared_keys text[] DEFAULT NULL::text[]", returns: "jsonb", security: "invoker" },
@@ -472,16 +536,19 @@ var STORE_DOORS = [
472
536
  { name: "pipeline_read", args: "p_organization_id uuid, p_table_id uuid", returns: "jsonb", security: "definer" },
473
537
  { name: "pipeline_transition_refusal", args: "p_organization_id uuid, p_record_id uuid, p_to text", returns: "jsonb", security: "definer" },
474
538
  { name: "portal_admits", args: "p_organization_id uuid, p_user_id uuid DEFAULT NULL::uuid", returns: "boolean", security: "definer" },
539
+ { name: "portal_archive", args: "p_organization_id uuid, p_portal_id uuid, p_confirm_title text, p_reason text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
475
540
  { name: "portal_card", args: "p_organization_id uuid, p_portal_id uuid", returns: "jsonb", security: "definer" },
476
541
  { name: "portal_declare", args: "p_organization_id uuid, p_title text, p_client_table_id uuid, p_tables jsonb, p_portal_id uuid DEFAULT NULL::uuid, p_slug text DEFAULT NULL::text, p_sign_in_method text DEFAULT 'magic_link'::text", returns: "uuid", security: "definer" },
477
542
  { name: "portal_field_map", args: "p_organization_id uuid, p_table_id uuid", returns: "TABLE(field_id uuid, field_key text, field_type text, points_at uuid)", security: "definer" },
478
543
  { name: "portal_invitation", args: "p_slug text, p_email text", returns: "jsonb", security: "definer" },
479
544
  { name: "portal_invite", args: "p_organization_id uuid, p_portal_id uuid, p_client_record_id uuid, p_email text, p_user_id uuid DEFAULT NULL::uuid", returns: "jsonb", security: "definer" },
545
+ { name: "portal_invite_accept", args: "p_token text", returns: "jsonb", security: "definer" },
480
546
  { name: "portal_me", args: "", returns: "jsonb", security: "definer" },
481
547
  { name: "portal_preview", args: "p_organization_id uuid, p_portal_id uuid, p_principal_id uuid, p_table_id uuid", returns: "TABLE(record_id uuid, title text)", security: "definer" },
482
548
  { name: "portal_principal_bind", args: "p_organization_id uuid, p_principal_id uuid, p_user_id uuid", returns: "jsonb", security: "definer" },
483
549
  { name: "portal_public", args: "p_slug text", returns: "jsonb", security: "definer" },
484
550
  { name: "portal_record_title", args: "p_organization_id uuid, p_record_id uuid", returns: "text", security: "definer" },
551
+ { name: "portal_restore", args: "p_organization_id uuid, p_portal_id uuid, p_confirm_title text", returns: "jsonb", security: "definer" },
485
552
  { name: "portal_revoke", args: "p_organization_id uuid, p_portal_id uuid, p_principal_id uuid", returns: "jsonb", security: "definer" },
486
553
  { name: "portal_slug", args: "p_organization_id uuid, p_title text, p_portal_id uuid DEFAULT NULL::uuid", returns: "text", security: "definer" },
487
554
  { name: "portal_tables", args: "p_organization_id uuid", returns: "TABLE(portal_id uuid, table_id uuid, name text)", security: "definer" },
@@ -529,15 +596,18 @@ var STORE_DOORS = [
529
596
  { name: "read_paths_outside_the_door", args: "", returns: "TABLE(object_name text, why text)", security: "invoker" },
530
597
  { name: "read_record", args: "p_organization_id uuid, p_record_id uuid, p_by_id boolean DEFAULT false", returns: "jsonb", security: "definer" },
531
598
  { name: "read_records", args: "p_organization_id uuid, p_table_id uuid, p_by_id boolean DEFAULT false, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(id uuid, document jsonb, level permission_level)", security: "definer" },
599
+ { name: "read_records_archived", args: "p_organization_id uuid, p_table_id uuid, p_lane text DEFAULT 'org'::text, p_by_id boolean DEFAULT false, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(id uuid, document jsonb, level permission_level, archived_at timestamp with time zone, archived_by uuid, archived_by_name text)", security: "definer" },
532
600
  { name: "read_records_by_ids", args: "p_organization_id uuid, p_table_id uuid, p_record_ids uuid[], p_by_id boolean DEFAULT false", returns: "TABLE(id uuid, document jsonb, level permission_level)", security: "definer" },
533
601
  { name: "read_records_matching", args: "p_organization_id uuid, p_table_id uuid, p_filter jsonb DEFAULT '{}'::jsonb, p_by_id boolean DEFAULT false, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(id uuid, document jsonb, level permission_level)", security: "definer" },
534
602
  { name: "realtime_topic_admits", args: "p_topic text", returns: "boolean", security: "definer" },
535
603
  { name: "record_aggregate", args: "p_organization_id uuid, p_table_id uuid, p_group_by jsonb DEFAULT '[]'::jsonb, p_measures jsonb DEFAULT '[]'::jsonb, p_bucket jsonb DEFAULT NULL::jsonb, p_filter jsonb DEFAULT '{}'::jsonb, p_limit integer DEFAULT 200, p_required text DEFAULT 'viewer'::text", returns: "TABLE(groups jsonb, measures jsonb, row_count bigint)", security: "definer" },
536
604
  { name: "record_applicability", args: "p_organization_id uuid, p_record_id uuid", returns: "TABLE(rule_id uuid, rule_name text, rule_version integer, applies boolean, answer jsonb)", security: "invoker" },
605
+ { name: "record_archiver", args: "p_organization_id uuid, p_record_id uuid", returns: "uuid", security: "definer" },
537
606
  { name: "record_as_of", args: "p_organization_id uuid, p_record_id uuid, p_at timestamp with time zone", returns: "TABLE(state jsonb, replayed boolean)", security: "definer" },
538
607
  { name: "record_card", args: "p_viewer uuid, p_organization_id uuid, p_record_id uuid", returns: "jsonb", security: "definer" },
539
608
  { name: "record_carrying_edges", args: "p_id uuid, p_data_class text, p_data jsonb, p_deleted_at timestamp with time zone", returns: "TABLE(container_id uuid, item_id uuid, edge_role text)", security: "invoker" },
540
609
  { name: "record_delete", args: "p_organization_id uuid, p_record_id uuid", returns: "timestamp with time zone", security: "definer" },
610
+ { name: "record_filter_sql", args: "p_filter jsonb", returns: "text", security: "invoker" },
541
611
  { name: "record_history", args: "p_organization_id uuid, p_record_id uuid, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(version integer, occurred_at timestamp with time zone, operation text, operation_label text, actor jsonb, changes jsonb, migration_id uuid, undoable boolean)", security: "definer" },
542
612
  { name: "record_platform_keys", args: "", returns: "text[]", security: "invoker" },
543
613
  { name: "record_relation_edges", args: "p_organization_id uuid, p_id uuid, p_table_id uuid, p_data_class text, p_data jsonb, p_deleted_at timestamp with time zone", returns: "TABLE(target_id uuid, edge_role text, field_id uuid, ord integer)", security: "invoker" },
@@ -626,6 +696,7 @@ var STORE_DOORS = [
626
696
  { name: "subscription_mute", args: "p_organization_id uuid, p_rule_id uuid, p_muted boolean DEFAULT true", returns: "boolean", security: "definer" },
627
697
  { name: "subscription_preview", args: "p_organization_id uuid, p_rule_id uuid", returns: "jsonb", security: "definer" },
628
698
  { name: "subscriptions", args: "p_organization_id uuid, p_table_id uuid DEFAULT NULL::uuid", returns: "TABLE(rule_id uuid, name text, table_id uuid, saved_view_id uuid, cadence text, schedule text, quiet_hours jsonb, channel text, recipient_user_id uuid, event_key text, muted boolean, mine boolean, i_may_mute boolean, last_sent_at timestamp with time zone, next_digest_at timestamp with time zone)", security: "definer" },
699
+ { name: "table_archive", args: "p_organization_id uuid, p_table_id uuid, p_chunk integer DEFAULT 50, p_include_table boolean DEFAULT true", returns: "jsonb", security: "definer" },
629
700
  { name: "table_capacity", args: "p_organization_id uuid, p_table_id uuid", returns: "jsonb", security: "definer" },
630
701
  { name: "table_carries_its_rows", args: "p_user_id uuid, p_table_id uuid, p_required permission_level DEFAULT 'viewer'::permission_level", returns: "boolean", security: "definer" },
631
702
  { name: "table_column_source", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
@@ -758,18 +829,18 @@ var STORE_KNOBS = [
758
829
  { key: "world_publish_enabled", value: "false", type: "boolean" }
759
830
  ];
760
831
  var STORE_REFUSAL_CODES = [
761
- { code: "02000", raised_by: "_checklist_instantiate,_table_share_invite_payload,checklist_declare,checklist_run,checklist_step_complete,checklist_step_refusal,checklist_template_shape,conversation_scope_bind,dashboard_delete,dashboard_run,doc_letterhead,doc_render_body,doc_render_document,doc_render_read,doc_sign,doc_signature_intact,doc_signature_read,doc_template_delete,doc_template_read,doc_template_save,enrich_pin,entity_field_retire,entity_field_update,entity_record_read,entity_value_write,external_history_event,external_rows,external_stub_upsert,external_writes_set,io_restore,migrate_delete,migrate_extract_parent,migrate_merge,migrate_reclass,migrate_rename,migrate_reparent,migrate_retype,migrate_split,migrate_undo,organization_clear,portal_card,portal_declare,portal_invite,portal_preview,portal_principal_bind,portal_revoke,read_record,record_delete,record_restore,record_restore_preview,record_table,record_update,relation_uncarry,share_access,share_grant,share_lane_set,share_people,share_revoke,sign_request_cancel,sign_request_create,sign_request_remind,sign_request_unchanged,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,table_share_outside_revoke,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_assign,work_record_states,work_set_state" },
832
+ { code: "02000", raised_by: "_checklist_instantiate,_portal_invite_payload,_share_write_person,_table_share_invite_payload,checklist_declare,checklist_run,checklist_step_complete,checklist_step_refusal,checklist_template_shape,conversation_scope_bind,dashboard_delete,dashboard_run,doc_letterhead,doc_render_body,doc_render_document,doc_render_read,doc_sign,doc_signature_intact,doc_signature_read,doc_template_delete,doc_template_read,doc_template_save,enrich_pin,entity_field_retire,entity_field_update,entity_record_read,entity_value_write,external_history_event,external_rows,external_stub_upsert,external_writes_set,io_restore,migrate_delete,migrate_extract_parent,migrate_merge,migrate_reclass,migrate_rename,migrate_reparent,migrate_retype,migrate_split,migrate_undo,organization_clear,portal_archive,portal_card,portal_declare,portal_invite,portal_invite_accept,portal_preview,portal_principal_bind,portal_restore,portal_revoke,read_record,record_delete,record_restore,record_restore_preview,record_table,record_update,relation_uncarry,share_access,share_grant,share_lane_set,share_people,share_revoke,sign_request_cancel,sign_request_create,sign_request_remind,sign_request_unchanged,table_archive,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,table_share_outside_revoke,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_assign,work_record_states,work_set_state" },
762
833
  { code: "0A000", raised_by: "checklist_step_complete,external_rows,external_source_declare,external_write_through,promote_field,promoted_index_expr,promoted_query_sql,promoted_read,rule_eval,work_assign" },
763
834
  { code: "22003", raised_by: "context_resolve" },
764
- { code: "22004", raised_by: "_entity_custom_fields_guard,_value_envelope,actor_word,agg_assert_key,agg_sql,anon_capture,anon_token_issue,anon_write,assert_client_may_reach,booking_declare,capture_submit,checklist_declare,context_resolve,dashboard_block_normalize,dashboard_declare,dashboard_window_sql,doc_render_write,doc_sign,doc_signature_write,doc_template_save,enrich_land,enrich_normalize,external_history_event,external_rows,external_source_declare,external_stub_upsert,external_write_through,external_writes_set,field_history,form_declare,form_submit,home_add,io_comment_write,io_import_begin,io_infer_column,io_outbox_drain,io_restore,migrate_choice_keys,migrate_purge,migrate_reclass,migrate_split,migrate_undo,organization_clear,organization_contents,pipeline_declare,pipeline_gate_preview,portal_declare,portal_invite,portal_principal_bind,provenance_retention_days,provenance_write,query_across_homes,query_by_coordinates,query_rollup,record_delete,record_reparent,record_resolve,record_restore,record_update,record_write,record_write_many,relation_carry,relation_own,rule_declare,share_grant,sign_request_create,sign_request_sign,subscription_declare,table_declare,table_share_outside_invite,value_restore,view_declare,work_approval_decide,work_approval_request,work_template_declare" },
835
+ { code: "22004", raised_by: "_entity_custom_fields_guard,_share_write_person,_value_envelope,actor_word,agg_assert_key,agg_sql,anon_capture,anon_token_issue,anon_write,assert_client_may_reach,booking_declare,capture_submit,checklist_declare,context_resolve,dashboard_block_normalize,dashboard_declare,dashboard_window_sql,doc_render_write,doc_sign,doc_signature_write,doc_template_save,enrich_land,enrich_normalize,external_history_event,external_rows,external_source_declare,external_stub_upsert,external_write_through,external_writes_set,field_history,form_declare,form_submit,home_add,io_comment_write,io_import_begin,io_infer_column,io_outbox_drain,io_restore,migrate_choice_keys,migrate_purge,migrate_reclass,migrate_split,migrate_undo,organization_clear,organization_contents,pipeline_declare,pipeline_gate_preview,portal_declare,portal_invite,portal_principal_bind,provenance_retention_days,provenance_write,query_across_homes,query_by_coordinates,query_rollup,record_delete,record_reparent,record_resolve,record_restore,record_update,record_write,record_write_many,relation_carry,relation_own,rule_declare,share_grant,sign_request_create,sign_request_sign,subscription_declare,table_archive,table_declare,table_share_outside_invite,value_restore,view_declare,work_approval_decide,work_approval_request,work_template_declare" },
765
836
  { code: "22007", raised_by: "dashboard_window_sql" },
766
837
  { code: "22012", raised_by: "rule_eval" },
767
- { code: "22023", raised_by: "_booking_availability,_entity_custom_fields_guard,_take_op_id,_value_envelope,_work_shape_guard,actor_word,agg_assert_key,agg_sql,anon_token_issue,booking_declare,containment_parent,dashboard_block_normalize,dashboard_window_sql,doc_render_body,doc_render_write,doc_signature_write,enrich_declare,enrich_land,enrich_normalize,enrich_pin,entity_value_write,external_history_event,external_source_declare,external_stub_upsert,external_write_through,field_history,field_update,io_export,io_import_begin,io_import_finish,io_import_plan,io_import_report,io_proposal_accept,migrate_merge,migrate_reclass,my_levels,organization_clear,page_size,pin_agent_cells,pipeline_move,portal_declare,provenance_write,query_by_coordinates,query_rollup,record_update,record_write_many,relation_carry,rule_eval,rule_members,share_grant,share_lane_set,sign_request_create,sign_request_sign,subscription_declare,table_rules,visibility_as_of,work_approval_request,work_list,work_slot_hold" },
768
- { code: "23503", raised_by: "_booking_availability,_checklist_instantiate,_containment_guard,_display_spec_for,_field_document_for,_pipeline_stage_key,_record_rule_uses,agg_digest_assemble,anon_publish,anon_rate_take,anon_token_issue,anon_write,assert_organization_wall,booking_cancel,booking_confirm,booking_declare,booking_hold,booking_reschedule,capture_publish,checklist_declare,checklist_steps_table,comment_write,dashboard_declare,delete_rule,doc_sign,doc_template_save,enrich_declare,enrich_due,enrich_land,form_declare,form_submit,home_add,inbound_declare,inbound_mail_land,inbound_set,io_comment_write,io_import_begin,io_import_finish,io_import_report,io_import_rows,io_proposal_accept,migrate_demote,migrate_promote,pipeline_board,pipeline_declare,pipeline_move,pipeline_read,pipeline_transition_refusal,promote_field,promote_table,record_applicability,record_reparent,relation_carry,relation_own,resolve_first_match,rule_applies,rule_declare,rule_eval,rule_members,rule_run,sign_request_create,subscription_mute,subscription_preview,view_declare,work_set_state,work_take_assignment,work_template_instantiate" },
769
- { code: "23505", raised_by: "_unique_rule_holds,doc_sign,doc_signature_write,entity_field_declare,field_declare,home_add,inbound_declare,io_proposal_accept,relation_carry,relation_own,share_grant,sign_request_cancel,sign_request_create,table_share_outside_invite,table_share_outside_resend,work_approval_decide,work_slot_hold" },
770
- { code: "23514", raised_by: "_checklist_instantiate,_checklist_step_guard,_containment_guard,_dated_values_guard,_derived_fields,_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,_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,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_import_rows,migrate_merge,relation_carry,relation_own,sign_request_create,sign_request_sign,table_declare,validate_value_envelope,validate_values,work_set_state,work_slots_declare,work_take_assignment,work_template_instantiate" },
838
+ { code: "22023", raised_by: "_booking_availability,_entity_custom_fields_guard,_take_op_id,_value_envelope,_work_shape_guard,actor_word,agg_assert_key,agg_sql,anon_token_issue,booking_declare,containment_parent,dashboard_block_normalize,dashboard_window_sql,doc_render_body,doc_render_write,doc_signature_write,enrich_declare,enrich_land,enrich_normalize,enrich_pin,entity_value_write,external_history_event,external_source_declare,external_stub_upsert,external_write_through,field_history,field_update,io_export,io_import_begin,io_import_finish,io_import_plan,io_import_report,io_proposal_accept,list_portals,migrate_merge,migrate_reclass,my_levels,organization_clear,page_size,pin_agent_cells,pipeline_move,portal_declare,provenance_write,query_by_coordinates,query_rollup,read_records_archived,record_update,record_write_many,relation_carry,rule_eval,rule_members,share_grant,share_lane_set,sign_request_create,sign_request_sign,subscription_declare,table_rules,visibility_as_of,work_approval_request,work_list,work_slot_hold" },
839
+ { code: "23503", raised_by: "_booking_availability,_checklist_instantiate,_containment_guard,_display_spec_for,_field_document_for,_field_type_parity_guard,_pipeline_stage_key,_record_rule_uses,agg_digest_assemble,anon_publish,anon_rate_take,anon_token_issue,anon_write,assert_organization_wall,booking_cancel,booking_confirm,booking_declare,booking_hold,booking_reschedule,capture_publish,checklist_declare,checklist_steps_table,comment_write,dashboard_declare,delete_rule,doc_sign,doc_template_save,enrich_declare,enrich_due,enrich_land,form_declare,form_submit,home_add,inbound_declare,inbound_mail_land,inbound_set,io_comment_write,io_import_begin,io_import_finish,io_import_report,io_import_rows,io_proposal_accept,migrate_demote,migrate_promote,pipeline_board,pipeline_declare,pipeline_move,pipeline_read,pipeline_transition_refusal,promote_field,promote_table,record_applicability,record_reparent,relation_carry,relation_own,resolve_first_match,rule_applies,rule_declare,rule_eval,rule_members,rule_run,sign_request_create,subscription_mute,subscription_preview,view_declare,work_set_state,work_take_assignment,work_template_instantiate" },
840
+ { 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" },
841
+ { code: "23514", raised_by: "_checklist_instantiate,_checklist_step_guard,_containment_guard,_dated_values_guard,_derived_fields,_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,_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,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,portal_archive,portal_restore,relation_carry,relation_own,sign_request_create,sign_request_sign,table_declare,validate_value_envelope,validate_values,work_set_state,work_slots_declare,work_take_assignment,work_template_instantiate" },
771
842
  { code: "40001", raised_by: "has_visibility_at" },
772
- { code: "42501", raised_by: "_doc_render_immutable,_doc_signature_immutable,_field_definition_write,_field_write_door,_rule_definition_write,_store_door,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,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_reclass,my_levels,organization_clear,portal_declare,portal_invitation,portal_invite,portal_principal_bind,promote_table,query_visibility_parity,read_record,read_records,read_records_by_ids,record_table,share_grant,subscription_mute,subscription_preview,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_person" },
843
+ { 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_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,share_grant,subscription_mute,subscription_preview,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_person" },
773
844
  { code: "42703", raised_by: "entity_table,portal_declare" },
774
845
  { code: "53400", raised_by: "anon_rate_take,delete_cascade_closure,enrich_due,enrich_land,promote_field" },
775
846
  { code: "54001", raised_by: "record_delete" },
@@ -1665,6 +1736,7 @@ var ENTITY_TOKENS = [
1665
1736
  "template_scope_types",
1666
1737
  "templates",
1667
1738
  "test_handset_inbox",
1739
+ "test_handset_verification",
1668
1740
  "thread",
1669
1741
  "tool",
1670
1742
  "tool_binding",
@@ -1869,6 +1941,14 @@ var DOORS = {
1869
1941
  // `custom.record_filter_sql`, the one body `custom.agg_sql` also calls, so the
1870
1942
  // rows it opens are the rows the number counted.
1871
1943
  readRecordsMatching: "read_records_matching",
1944
+ // THE SAME READ DOOR, ADDRESSED BY ABSENCE. Every door above answers LIVE rows
1945
+ // only — each of them hard-codes `and r.deleted_at is null` — so until this one
1946
+ // existed no screen could list an archived record however it was written, and
1947
+ // `record_restore` below had nothing that could reach it (VERIFIER-10 F4).
1948
+ // `custom.read_records_archived` is that body with the sign of one comparison
1949
+ // flipped, plus the two facts only an archive needs: who archived it and when.
1950
+ // A separate NAME for the same reason as its two siblings above.
1951
+ readRecordsArchived: "read_records_archived",
1872
1952
  // DOOR-8, the two clocks. `p_recorded_at` is what the store SAID then;
1873
1953
  // `p_world_on` is what was TRUE of the world on that date, read out of dated
1874
1954
  // values. A client that answered either one itself would be guessing.
@@ -2015,6 +2095,7 @@ var DOORS = {
2015
2095
  // ways to start an import from one client is how they drift.
2016
2096
  importPlan: "io_import_plan",
2017
2097
  importBegin: "io_import_begin",
2098
+ importDeclareColumns: "io_import_declare_columns",
2018
2099
  importRows: "io_import_rows",
2019
2100
  importFinish: "io_import_finish",
2020
2101
  importReport: "io_import_report",
@@ -2051,6 +2132,17 @@ var DOORS = {
2051
2132
  portalInvite: "portal_invite",
2052
2133
  portalRevoke: "portal_revoke",
2053
2134
  portalPreview: "portal_preview",
2135
+ // ORG-CLEANUP, 2026-09-22 — A PORTAL IS ARCHIVED, NEVER DELETED.
2136
+ // `portals` keeps its signature and HIDES archived portals (the law's default
2137
+ // is to hide); `list_portals(org, 'active'|'archived'|'all')` is the
2138
+ // archive-aware reader, taking the platform archive filter's own three values
2139
+ // so one door serves both lanes and no screen has to invent a second control.
2140
+ // `portal_archive` / `portal_restore` are the way out and the way back; both
2141
+ // take the portal's own title typed back, because ten portals can carry one
2142
+ // title and the title alone is not what picks this one.
2143
+ listPortals: "list_portals",
2144
+ portalArchive: "portal_archive",
2145
+ portalRestore: "portal_restore",
2054
2146
  // SCR-16 — the canvas. A dashboard is a record in the presentation kernel
2055
2147
  // whose blocks are saved SPECS for the eighth verb; `dashboardRun` walks them
2056
2148
  // under the CALLER'S principal, so nothing here is precomputed and nothing is
@@ -2163,7 +2255,14 @@ var DOORS = {
2163
2255
  docTokens: "doc_tokens",
2164
2256
  docUnresolvedTokens: "doc_unresolved_tokens",
2165
2257
  docSign: "doc_sign",
2166
- docSignatureIntact: "doc_signature_intact",
2258
+ // THE SEAL IS ASKED THROUGH ITS OWN DOOR. `custom.doc_signature_intact` is the INTERNAL
2259
+ // half of this pair — SECURITY INVOKER over a doors-only table, so a browser that calls it
2260
+ // gets `42501 permission denied for table doc_signature`, which is what every SignBlock
2261
+ // seal check got until 2026-09-22 (FIX-10B). `custom.doc_signature_read` is the definer
2262
+ // door built for a client: it asks may_reach and may_open on the RECORD by name and
2263
+ // returns the seal AND the verdict in one answer, because a seal a person can read and a
2264
+ // verdict they cannot is how a changed agreement keeps wearing somebody's signature.
2265
+ docSignatureRead: "doc_signature_read",
2167
2266
  // THE PLURAL ACTS. Until 2026-09-20 this package read `custom.doc_template`,
2168
2267
  // `custom.doc_render` and `custom.doc_signature` with a direct PostgREST
2169
2268
  // `.from()`, and all three hold NO client SELECT — so every list in product #5
@@ -2560,6 +2659,34 @@ function createRecordsClient(config) {
2560
2659
  })
2561
2660
  );
2562
2661
  },
2662
+ async listArchived({ table_id, lane = DEFAULT_ARCHIVE_LANE, limit = 50, offset = 0 }) {
2663
+ const door = await callDoor(
2664
+ DOORS.readRecordsArchived,
2665
+ {
2666
+ p_organization_id: org,
2667
+ p_table_id: table_id,
2668
+ p_lane: lane,
2669
+ p_limit: limit,
2670
+ p_offset: offset
2671
+ },
2672
+ "listArchived"
2673
+ );
2674
+ if (!door.ok) return err(door.error);
2675
+ const rows = (door.data ?? []).map((row) => {
2676
+ const { document, hidden } = unfold(row.document);
2677
+ return {
2678
+ id: row.id,
2679
+ document,
2680
+ level: row.level,
2681
+ hidden,
2682
+ archivedAt: row.archived_at,
2683
+ archivedBy: row.archived_by ?? null,
2684
+ archivedByName: row.archived_by_name ?? null
2685
+ };
2686
+ });
2687
+ const total = rows.length < limit ? offset + rows.length : null;
2688
+ return ok({ rows, total });
2689
+ },
2563
2690
  async list({ table_id, filter, limit = 50, offset = 0 }) {
2564
2691
  const door = await callDoor(
2565
2692
  DOORS.readRecordsMatching,
@@ -3049,6 +3176,18 @@ function createRecordsClient(config) {
3049
3176
  "importBegin"
3050
3177
  );
3051
3178
  },
3179
+ async importDeclareColumns(args) {
3180
+ return callDoor(
3181
+ DOORS.importDeclareColumns,
3182
+ {
3183
+ p_organization_id: org,
3184
+ p_table_id: args.table_id,
3185
+ p_rows: args.rows,
3186
+ p_mapping: args.mapping ?? {}
3187
+ },
3188
+ "importDeclareColumns"
3189
+ );
3190
+ },
3052
3191
  async importRows(args) {
3053
3192
  return callDoor(
3054
3193
  DOORS.importRows,
@@ -3119,6 +3258,36 @@ function createRecordsClient(config) {
3119
3258
  async portals() {
3120
3259
  return callDoor(DOORS.portals, { p_organization_id: org }, "portals");
3121
3260
  },
3261
+ async listPortals(args) {
3262
+ return callDoor(
3263
+ DOORS.listPortals,
3264
+ { p_organization_id: org, p_archived: args?.archived ?? "active" },
3265
+ "listPortals"
3266
+ );
3267
+ },
3268
+ async portalArchive(args) {
3269
+ return callDoor(
3270
+ DOORS.portalArchive,
3271
+ {
3272
+ p_organization_id: org,
3273
+ p_portal_id: args.portal_id,
3274
+ p_confirm_title: args.confirm_title,
3275
+ p_reason: args.reason ?? null
3276
+ },
3277
+ "portalArchive"
3278
+ );
3279
+ },
3280
+ async portalRestore(args) {
3281
+ return callDoor(
3282
+ DOORS.portalRestore,
3283
+ {
3284
+ p_organization_id: org,
3285
+ p_portal_id: args.portal_id,
3286
+ p_confirm_title: args.confirm_title
3287
+ },
3288
+ "portalRestore"
3289
+ );
3290
+ },
3122
3291
  async portalTables() {
3123
3292
  return callDoor(DOORS.portalTables, { p_organization_id: org }, "portalTables");
3124
3293
  },
@@ -3707,11 +3876,11 @@ function createRecordsClient(config) {
3707
3876
  "commentResolve"
3708
3877
  );
3709
3878
  },
3710
- async docSignatureIntact({ signature_id }) {
3879
+ async docSignatureRead({ signature_id }) {
3711
3880
  return callDoor(
3712
- DOORS.docSignatureIntact,
3881
+ DOORS.docSignatureRead,
3713
3882
  { p_organization_id: org, p_signature_id: signature_id },
3714
- "docSignatureIntact"
3883
+ "docSignatureRead"
3715
3884
  );
3716
3885
  },
3717
3886
  // ── the anonymous lane ───────────────────────────────────────────────
@@ -5007,6 +5176,24 @@ function publicFormPath(formId) {
5007
5176
  function portalPath(slug) {
5008
5177
  return `/portal/c/${slug}`;
5009
5178
  }
5179
+ var PORTAL_ARCHIVE_FILTERS = ["active", "archived", "all"];
5180
+ var DEFAULT_PORTAL_ARCHIVE_FILTER = "active";
5181
+ function isPortalArchiveFilter(word) {
5182
+ return typeof word === "string" && PORTAL_ARCHIVE_FILTERS.includes(word);
5183
+ }
5184
+ function portalArchiveConsequence(title, signedIn, invited) {
5185
+ const people = invited === 0 ? "Nobody is invited to it" : signedIn === 0 ? `The ${invited} ${invited === 1 ? "person" : "people"} invited to it will not be able to sign in` : `The ${signedIn} ${signedIn === 1 ? "person" : "people"} signed in to it, and the ${invited - signedIn} still invited, will not be able to sign in`;
5186
+ return `\u201C${title}\u201D will leave your portal list. ${people}, and their invitation links will say this portal was archived and can be restored. Nothing is deleted \u2014 every Table it shows and everyone invited to it is kept exactly as it is, and you can restore it at any time.`;
5187
+ }
5188
+ function portalConfirmLine(title) {
5189
+ return `Type the portal\u2019s title \u2014 ${title} \u2014 to confirm you mean this one.`;
5190
+ }
5191
+ function portalTitleTypedBack(typed, title) {
5192
+ return typed.trim() === (title ?? "").trim();
5193
+ }
5194
+ function emptyPortalArchiveLine() {
5195
+ 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.";
5196
+ }
5010
5197
 
5011
5198
  // src/capture-queue.ts
5012
5199
  var DB_NAME = "matrx-capture";
@@ -5294,8 +5481,14 @@ function scopeChip(scope) {
5294
5481
  export {
5295
5482
  ABSENCE_REASONS,
5296
5483
  ACTOR_VOCABULARY,
5484
+ ARCHIVE_LANES,
5485
+ ARCHIVE_LANE_LABEL,
5486
+ ARCHIVE_LANE_MEANS,
5297
5487
  COMPUTE_ON,
5298
5488
  CONTEXT_POLICIES,
5489
+ DECLARABLE_FIELD_KINDS,
5490
+ DEFAULT_ARCHIVE_LANE,
5491
+ DEFAULT_PORTAL_ARCHIVE_FILTER,
5299
5492
  DELIVERIES,
5300
5493
  ENTITY_TOKENS,
5301
5494
  FIELD_KINDS,
@@ -5312,6 +5505,7 @@ export {
5312
5505
  PERMISSION_LEVELS,
5313
5506
  PER_VALUE_ACCESS_WORDS,
5314
5507
  PIPELINE_RULE_KINDS,
5508
+ PORTAL_ARCHIVE_FILTERS,
5315
5509
  REFUSALS_WORTH_REPEATING,
5316
5510
  RELATION_BINDINGS,
5317
5511
  RELATION_CARDINALITIES,
@@ -5331,6 +5525,8 @@ export {
5331
5525
  TABLE_TYPES,
5332
5526
  VALUE_ALTERNATE_KEYS,
5333
5527
  VALUE_ENVELOPE_KEYS,
5528
+ archivedByLine,
5529
+ archivedWhen,
5334
5530
  asPermissionLevel,
5335
5531
  atLeast,
5336
5532
  bookingPath,
@@ -5340,14 +5536,18 @@ export {
5340
5536
  coerceTypedAnswer,
5341
5537
  coerceTypedAnswers,
5342
5538
  coercionLabel,
5539
+ emptyArchiveLine,
5540
+ emptyPortalArchiveLine,
5343
5541
  err,
5344
5542
  fieldKindFor,
5345
5543
  forgetAllOps,
5346
5544
  highestLevel,
5347
5545
  holdsARetiredChoice,
5348
5546
  indexedDbStore,
5547
+ isArchiveLane,
5349
5548
  isDecided,
5350
5549
  isOwnOp,
5550
+ isPortalArchiveFilter,
5351
5551
  isRecordsErr,
5352
5552
  isTheChosen,
5353
5553
  looksLikeAnId,
@@ -5360,9 +5560,13 @@ export {
5360
5560
  openCaptureQueue,
5361
5561
  optionKey,
5362
5562
  optionLabel,
5563
+ portalArchiveConsequence,
5564
+ portalConfirmLine,
5363
5565
  portalPath,
5566
+ portalTitleTypedBack,
5364
5567
  publicFormPath,
5365
5568
  rememberedOpCount,
5569
+ sameDocument,
5366
5570
  scopeChip,
5367
5571
  stableFilterKey,
5368
5572
  tableShapeChanged,