@ai-matrx/records 0.98.8 → 0.98.9

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.
Files changed (92) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{table-kind-CboiMJuE.d.cts → client-9fzhCPD5.d.cts} +2771 -4
  3. package/dist/{table-kind-B4sdlvHf.d.ts → client-DcWZjmg2.d.ts} +2771 -4
  4. package/dist/core/index.cjs +100 -3
  5. package/dist/core/index.cjs.map +1 -1
  6. package/dist/core/index.d.cts +19 -17
  7. package/dist/core/index.d.ts +19 -17
  8. package/dist/core/index.js +100 -3
  9. package/dist/core/index.js.map +1 -1
  10. package/dist/data/index.cjs +52 -0
  11. package/dist/data/index.cjs.map +1 -1
  12. package/dist/data/index.d.cts +11 -12
  13. package/dist/data/index.d.ts +11 -12
  14. package/dist/data/index.js +52 -0
  15. package/dist/data/index.js.map +1 -1
  16. package/dist/{declareTable-BIuPJ3Vj.d.ts → declareTable-B6ic3leL.d.ts} +3 -4
  17. package/dist/{declareTable-d-HxRmF0.d.cts → declareTable-_GwN-ERY.d.cts} +3 -4
  18. package/dist/{doors-Bx3Shs3z.d.cts → doors-Dm5q9H8Y.d.cts} +1 -1
  19. package/dist/{doors-BTifsjNv.d.ts → doors-t-Oc2l9E.d.ts} +1 -1
  20. package/dist/entity/index.d.cts +7 -7
  21. package/dist/entity/index.d.ts +7 -7
  22. package/dist/{field-CJtssH3q.d.ts → field-BIRNApm1.d.ts} +2 -2
  23. package/dist/{field-DoVl2I9K.d.cts → field-BLy8drjM.d.cts} +2 -2
  24. package/dist/forms/index.d.cts +3 -3
  25. package/dist/forms/index.d.ts +3 -3
  26. package/dist/index.cjs +45 -0
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +30 -13
  29. package/dist/index.d.ts +30 -13
  30. package/dist/index.js +45 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/memory/index.d.cts +7 -7
  33. package/dist/memory/index.d.ts +7 -7
  34. package/dist/{objectOrganization-Crk9gJUM.d.ts → objectOrganization-D5Ytjah7.d.ts} +1 -1
  35. package/dist/{objectOrganization-CUa6jjhV.d.cts → objectOrganization-zgpoUAH1.d.cts} +1 -1
  36. package/dist/{port-CRP5g9l9.d.cts → port-B9glCG2h.d.cts} +3 -3
  37. package/dist/{port-CtnELAJQ.d.ts → port-C-p-_lAu.d.ts} +3 -3
  38. package/dist/{portal-DW5NGBT0.d.ts → portal-B9HCNPTc.d.ts} +2 -2
  39. package/dist/{portal-C4N9ByaY.d.cts → portal-C_LgvDeh.d.cts} +2 -2
  40. package/dist/{ports-WwHHNwge.d.ts → ports-BE_5jz-c.d.ts} +2 -2
  41. package/dist/{ports-YIh9jrCZ.d.cts → ports-BIdYUS-C.d.cts} +2 -2
  42. package/dist/questions/index.d.cts +9 -10
  43. package/dist/questions/index.d.ts +9 -10
  44. package/dist/react/index.cjs +97 -0
  45. package/dist/react/index.cjs.map +1 -1
  46. package/dist/react/index.d.cts +86 -1
  47. package/dist/react/index.d.ts +86 -1
  48. package/dist/react/index.js +97 -0
  49. package/dist/react/index.js.map +1 -1
  50. package/dist/realtime/index.d.cts +3 -3
  51. package/dist/realtime/index.d.ts +3 -3
  52. package/dist/{record-CxGK1OEK.d.cts → record-BrJNCmH1.d.cts} +1 -1
  53. package/dist/{record-CxGK1OEK.d.ts → record-BrJNCmH1.d.ts} +1 -1
  54. package/dist/{relation-Dh-lCkkh.d.ts → relation-BxGXLRaG.d.ts} +3 -3
  55. package/dist/{relation-DSGhM3tO.d.cts → relation-R10qQyQU.d.cts} +3 -3
  56. package/dist/{rule-DQpC7WqT.d.cts → rule-BGtYd6Pf.d.cts} +2 -2
  57. package/dist/{rule-xNwJF6Qo.d.ts → rule-BtjrE42J.d.ts} +2 -2
  58. package/dist/scopes/index.d.cts +3 -3
  59. package/dist/scopes/index.d.ts +3 -3
  60. package/dist/search/index.d.cts +1 -1
  61. package/dist/search/index.d.ts +1 -1
  62. package/dist/setup/index.cjs +52 -0
  63. package/dist/setup/index.cjs.map +1 -1
  64. package/dist/setup/index.d.cts +12 -13
  65. package/dist/setup/index.d.ts +12 -13
  66. package/dist/setup/index.js +52 -0
  67. package/dist/setup/index.js.map +1 -1
  68. package/dist/{subscription-BVCn1PVe.d.cts → subscription-BEM4B4dR.d.cts} +3 -3
  69. package/dist/{subscription-DQzPVKBR.d.ts → subscription-Ca15Z7Gu.d.ts} +3 -3
  70. package/dist/templates/index.d.cts +10 -10
  71. package/dist/templates/index.d.ts +10 -10
  72. package/dist/typed-table/index.cjs +52 -0
  73. package/dist/typed-table/index.cjs.map +1 -1
  74. package/dist/typed-table/index.d.cts +10 -11
  75. package/dist/typed-table/index.d.ts +10 -11
  76. package/dist/typed-table/index.js +52 -0
  77. package/dist/typed-table/index.js.map +1 -1
  78. package/dist/{types-3lM5f6b0.d.cts → types-5ql9_q-o.d.cts} +2 -2
  79. package/dist/{types-04kFNi3-.d.ts → types-BALEbMc8.d.ts} +2 -2
  80. package/dist/{types-DKJO83lQ.d.cts → types-BhnjvJ8U.d.cts} +2 -2
  81. package/dist/{types-SUAmeBId.d.ts → types-CURw95qc.d.ts} +2 -2
  82. package/dist/{types-DKeGkHpE.d.cts → types-DRMeL0uW.d.cts} +2 -2
  83. package/dist/{types-DJVccwh0.d.ts → types-_odOqLOe.d.ts} +2 -2
  84. package/dist/use-cases/index.d.cts +5 -5
  85. package/dist/use-cases/index.d.ts +5 -5
  86. package/dist/{validate-BIJtP2KB.d.cts → validate-Cdtk0y18.d.cts} +1 -1
  87. package/dist/{validate--y-pPc-c.d.ts → validate-ChibJPPI.d.ts} +1 -1
  88. package/dist/views/index.d.cts +9 -10
  89. package/dist/views/index.d.ts +9 -10
  90. package/package.json +3 -3
  91. package/dist/client-C1B-MNzb.d.ts +0 -2704
  92. package/dist/client-D2jAgJNn.d.cts +0 -2704
@@ -1,2704 +0,0 @@
1
- import { C as ChoiceNudge, T as TableArchiveProgress, a as TableRestoreProgress, b as TableDuplicateProgress, c as TableDuplicated, d as TableCopyInProgress, A as ArchiveLane, e as ArchivedRow, f as Table, g as TableHome, h as TableMoved, i as ChoiceUsage, j as ChoiceRehome, k as ChoiceCellBack, l as ChoicesRehomed, m as TableCapacity, F as FieldDrift, n as FieldRetyped, R as RecordsMerged, M as MigrationUndone, o as TableKindFacts, p as TableLevelFacts, q as TableReaderRule, r as TableLevelSet, E as EntityTableFacts, s as EntityFieldsAcross, N as NewEntityFieldDeclaration, t as EntityFieldRights, u as EntityRecordRead, v as EntityBackLinks, w as EntityRowWritten, x as EntityRecordsFound, P as Pipeline, y as PipelineColumn, z as PipelineVerdict, B as PipelineMoveResult, D as PipelineMoveManyItem, G as PipelineMoveMany, H as PipelineSpec, I as PipelineDeclared, S as StageRuleOnFail, J as StageRuleEnforcement, K as StagePending, L as StagePendingOnBoard, O as PipelineGate, Q as PipelineGatePreview, U as ImportPlan, V as ImportPolicy, W as ImportOpened, X as ImportColumnsDeclared, Y as ImportBatchResult, Z as ImportFinished, _ as ImportReport, $ as ImportRun, a0 as InboundDeclared, a1 as InboundAddress, a2 as FormArchiveAnswer, a3 as ArchivedForm, a4 as ArchivedChecklistTemplate, a5 as TableRowDefaults, a6 as TableRowDefaultsPatch, a7 as RowDefaultsApplied, a8 as RecordRowControls, a9 as CaptureSheetSummary, aa as CaptureSheetFace, ab as CaptureFileRef, ac as CaptureOutcome, ad as EnrichmentSummary, ae as EnrichDeclared, af as EnrichDueRow, ag as EnrichCell, ah as EnrichRun, ai as DrillSource, aj as DrillDefinition, ak as DrillQuestion, al as DrillAnswer, am as DrillRowsPage, an as DocToken, ao as DocUnresolvedToken, ap as DocTemplateRow, aq as DocRenderRow, ar as DocSignatureRow, as as RecordHistoryEntry, at as RecordScopeContext, au as ConversationScope, av as ConversationScopeContext, aw as FieldHistoryEntry, ax as RestorePreview, ay as RestoreResult, az as CommentThreadRead, aA as CommentWritten, aB as AnonTokenBinding, aC as ChecklistSpec, aD as ChecklistDeclared, aE as ChecklistTemplateSummary, aF as ChecklistTemplateShape, aG as ChecklistRunStarted, aH as ChecklistRunStep, aI as ChecklistRunSummary, aJ as ChecklistStepCompleted, aK as WorkState, aL as WorkGraph, aM as WorkInstantiation, aN as WorkTurn, aO as WorkAssignmentField, aP as WorkSlotHold, aQ as WorkInboxView, aR as WorkInboxItem, aS as InboxStateChange, aT as InboxCounts, aU as WorkListFlavour, aV as WorkListItem, aW as WorkAssignment, aX as WorkRecordState, aY as WorkApprover, aZ as WorkChange, a_ as WorkApprovalFiled, a$ as WorkApprovalDecision, b0 as WorkDecideManyItem, b1 as WorkDecideMany, b2 as ExternalPrincipalCard, b3 as PublishBinding, b4 as ResolvedPublishBinding, b5 as ResolvedPublishBindingKind, b6 as DecorationPath, b7 as TableDecorations, b8 as GridLayout, b9 as FormulaParse, ba as FormulaPreview, bb as RowAction, bc as ActionRunResult, bd as AutomationSpec, be as AutomationDeclared, bf as AutomationList, bg as AutomationFlipped, bh as AutomationRuns, bi as RecordEvent, bj as TableWebhookDeclared, bk as TableWebhook, bl as IoExportPage, bm as TableListEntry, bn as DataHomeTable, bo as AdminTable, bp as TableSyncSpec, bq as TableSyncResult, br as TableRowCount, bs as RecordHeader, bt as OutsideShareAnswer, bu as ViewOrderSet } from './table-kind-B4sdlvHf.js';
2
- import { d as StoreFilter, e as DashboardSummary, f as DashboardBlock, R as RecordFilter, g as AggregateCompare, A as AggregateBucket, h as DashboardRunResult, i as StuckRow, c as AggregateMeasure, j as AggregateRow, k as Subscription, M as MySubscription, l as SubscriptionSpec, m as DigestPreview, n as SavedViewRow, o as SavedViewSpecIn, p as RowTemplateRow } from './subscription-DQzPVKBR.js';
3
- import { R as RelationCoordinate, a as RelationWordsManyArgs, b as RelationIcons, c as ReverseColumn, d as ReverseLinksManyArgs, e as ReverseLinks, f as ReverseLinksFieldsArgs, S as SourceArchived } from './relation-Dh-lCkkh.js';
4
- import { F as Field, c as FieldPatch, N as NewFieldDeclaration, R as RelationNamesAnswer, d as FieldDuplicated, e as FieldProposal, T as TableProposal, B as ButtonPressed } from './field-CJtssH3q.js';
5
- import { s as ScopeDoors } from './doors-BTifsjNv.js';
6
- import { F as FormSummary, B as BookingSummary, a as BookingAvailability, b as BookingDeclared, c as FormRoute, d as FormResults } from './rule-xNwJF6Qo.js';
7
- import { F as FormLookOptions, P as PortalSummary, a as PortalArchiveFilter, b as PortalArchiveAnswer, c as PortalTableRef, d as PortalCard, e as PortalConfigInput, f as PortalFormSpec, g as PortalFormAnswer, h as PortalInvitation, i as PortalRevocation, j as PortalPreviewRow } from './portal-DW5NGBT0.js';
8
- import { a as RecordsConfig, M as MyLevel } from './ports-WwHHNwge.js';
9
- import { h as Timestamp, U as Uuid, k as RecordsErrorCode, l as RecordDocument, R as RecordsResult, m as RecordChange, n as RecordChangeResult, o as RecordGraphWritten, p as RecordRead, q as ReadRow, r as RecordPageSort, s as RecordPage, t as RecordKeysetPage, u as StoredRecord, v as RecordRevision, w as ReadValue, a as RecordsError, W as WriteConflict } from './record-CxGK1OEK.js';
10
-
11
- /**
12
- * DOOR-8. As-of on EITHER clock, and they are different questions:
13
- * · `record` — the record clock: what this record looked like at version time.
14
- * · `world` — the world clock: which values were true of the world then
15
- * (the Field's `dated` modifier).
16
- */
17
- interface AsOf {
18
- clock: "record" | "world";
19
- at: Timestamp;
20
- }
21
- /** A predicate over a PROMOTED field (REC-5: promotion light -> heavy). */
22
- interface PromotedPredicate {
23
- field_key: string;
24
- /** The value as text, exactly as `custom.promoted_read` takes it. */
25
- equals: string;
26
- }
27
- interface RecordQuery {
28
- table_id: Uuid;
29
- /** DOOR-6. Any combination, any subset. An empty list means "no relation constraint". */
30
- relations?: RelationCoordinate[];
31
- /** Predicates the store can answer from an index. */
32
- promoted?: PromotedPredicate[];
33
- /** DOOR-8. */
34
- asOf?: AsOf;
35
- /** DOOR-9. Ask across EVERY Home of this Table in one answer. */
36
- acrossHomes?: boolean;
37
- /** REC-23. Soft-deleted rows are out unless you say otherwise. */
38
- includeDeleted?: boolean;
39
- /** FLD-10. */
40
- recordType?: string;
41
- orderBy?: {
42
- column: "created_at" | "updated_at";
43
- ascending?: boolean;
44
- };
45
- limit?: number;
46
- offset?: number;
47
- }
48
- /**
49
- * What a query decomposes into: a set of door calls whose answers INTERSECT,
50
- * then one filtered read. Kept as data rather than hidden inside the client so
51
- * the suite can assert the plan as well as the answer — a query that quietly
52
- * stopped applying one of its coordinates is otherwise invisible.
53
- */
54
- interface QueryPlan {
55
- /** One `relation_targets` call per coordinate; the id sets are intersected. */
56
- relationCalls: Array<{
57
- door: "relation_targets";
58
- record_id: Uuid;
59
- via_key: string | null;
60
- }>;
61
- /** One `promoted_read` call per predicate; intersected with the above. */
62
- promotedCalls: Array<{
63
- door: "promoted_read";
64
- field_key: string;
65
- value: string;
66
- }>;
67
- /** The filtered read over `custom.record`, which the store's policies gate. */
68
- read: {
69
- table_id: Uuid;
70
- includeDeleted: boolean;
71
- recordType: string | null;
72
- asOf: AsOf | null;
73
- acrossHomes: boolean;
74
- orderBy: {
75
- column: string;
76
- ascending: boolean;
77
- };
78
- limit: number;
79
- offset: number;
80
- };
81
- /**
82
- * Stated so nobody has to guess: when this is true the answer is the
83
- * intersection of the id sets above, and when it is false the read stands
84
- * alone.
85
- */
86
- intersects: boolean;
87
- }
88
- declare const DEFAULT_PAGE_SIZE = 50;
89
- declare function planQuery(query: RecordQuery): QueryPlan;
90
- /** The intersection of the id sets a plan's calls produced. Order is preserved from the first set. */
91
- declare function intersectIds(sets: Uuid[][]): Uuid[];
92
-
93
- /**
94
- * 🚨 A REFUSAL IS NOT AN APP ERROR (lane RECORDS-UI-FIX, guide re-walk 2026-09-23).
95
- *
96
- * A person typing `-3` into a column that takes "at least 0" is the store WORKING: the
97
- * rule said no, the screen said so in the one notice, and the person fixed it. The default
98
- * sink printed every one of those through `console.error`, and the app's error capture
99
- * (matrx-frontend `lib/diagnostics/globalErrorCapture.ts`) counts every `console.error` —
100
- * so one refused value lit a red "2 errors" pill in the corner, telling an admin the
101
- * product had failed when a person had simply been told no.
102
- *
103
- * These are the codes a PERSON causes by what they typed or when they typed it; each one
104
- * is already drawn on the screen that asked. They are still said (`console.info`), never
105
- * silenced. Everything else — a door, the store switched off, a timeout, a class this
106
- * package did not recognise — is a failure of the system and stays `console.error`.
107
- */
108
- declare const A_PERSONS_REFUSAL: ReadonlySet<RecordsErrorCode>;
109
- declare function isAPersonsRefusal(code: RecordsErrorCode | string): boolean;
110
- /** One organization the client could not use, with the sentence that says why. */
111
- interface OrganizationUnavailable {
112
- organization_id: Uuid;
113
- reason: string;
114
- }
115
- /** `organizationsOpen`: the organizations whose store answers, and those that do not (with why). */
116
- interface OrganizationsOpenAnswer {
117
- open: Uuid[];
118
- unavailable: OrganizationUnavailable[];
119
- }
120
- /** `metadataSearch`: every match, each carrying the organization it came from. */
121
- interface MetadataSearchAnswer {
122
- matches: Array<Record<string, unknown> & {
123
- organization_id: Uuid | null;
124
- }>;
125
- /** Organizations asked in order (the ones that answered). */
126
- organizations_covered: Uuid[];
127
- unavailable: OrganizationUnavailable[];
128
- }
129
- interface RecordsClient {
130
- /** The config this client was built with, so a screen can show who it is acting as. */
131
- readonly config: RecordsConfig;
132
- /**
133
- * THE SCOPE DOORS (`custom.context_*`): scope types are Tables kept for context, scopes Records,
134
- * context fields Fields, values cells. Built from this client's own door path. `@ai-matrx/records/scopes`.
135
- */
136
- readonly scopes: ScopeDoors;
137
- recordWrite(args: {
138
- table_id: Uuid;
139
- data: RecordDocument;
140
- }): Promise<RecordsResult<Uuid>>;
141
- /**
142
- * WRITE THE RECORD THIS KEY NAMES, OR UPDATE IT WHEN IT IS ALREADY THERE — one call, race-safe
143
- * (`custom.record_upsert`). `key` is the column key (or keys) that say which record this is,
144
- * and every one must carry a `unique` rule: the store refuses any other column by its name.
145
- * Two concurrent calls with the same key leave ONE record. An update goes through
146
- * `record_update` (with `expectedVersion`, its stale-write refusal); a new record through
147
- * `record_write`. Answers the record's id either way.
148
- */
149
- recordUpsert(args: {
150
- table_id: Uuid;
151
- key: string | string[];
152
- data: RecordDocument;
153
- expectedVersion?: number;
154
- }): Promise<RecordsResult<Uuid>>;
155
- /**
156
- * Write MANY new records of one Table in one call.
157
- *
158
- * `custom.record_write_many` asks the switch, the organization and the Table
159
- * ONCE for the whole batch and inserts the rows in one statement — which is
160
- * why a paste of 120 lines is one round trip per chunk instead of 120. It
161
- * CREATES only: there is no bulk update door, because an update carries a
162
- * per-row optimistic version and a batch would have to either drop that or
163
- * fail the whole batch for one stale row.
164
- *
165
- * It returns the new ids IN THE ORDER THE ROWS WERE HANDED IN, so a caller
166
- * can tie each id back to the line of the spreadsheet it came from. Hand in
167
- * `ids` to choose them yourself; hand in none and the door mints them.
168
- */
169
- recordWriteMany(args: {
170
- table_id: Uuid;
171
- rows: RecordDocument[];
172
- ids?: Uuid[];
173
- }): Promise<RecordsResult<Uuid[]>>;
174
- /**
175
- * DOOR-SPEED. MANY CHANGES TO ONE TABLE IN ONE TRANSACTION, through
176
- * `custom.record_change_many`: inserts, updates (each with an optional `expected_version`)
177
- * and archives. Every update lands in ONE statement, so the store's change notice, history and
178
- * activity fire once for the batch while every row trigger still judges every row. ONE REFUSED
179
- * CHANGE REFUSES THE BATCH and nothing is saved; the store's own sentence comes back with the
180
- * change's position in the hint. The answer is one result per change, in order.
181
- */
182
- recordChangeMany(args: {
183
- table_id: Uuid;
184
- changes: readonly RecordChange[];
185
- }): Promise<RecordsResult<RecordChangeResult[]>>;
186
- /**
187
- * A PARENT, THE EDGES IT STANDS ON AND THE ROWS THAT BELONG TO IT — ALL OR NOTHING.
188
- *
189
- * `recordWrite` and `recordWriteMany` are each ONE statement. A screen or a
190
- * server path whose unit of work is a GRAPH — an AI artifact and the lines
191
- * it produced, an order and its items, a research note and its citations —
192
- * could therefore not save it as one thing: a loop is N transactions, and a
193
- * failure on row nineteen leaves a parent standing without the lines it
194
- * promised.
195
- *
196
- * `custom.record_write_graph` is one statement, so it is one transaction. It
197
- * is NOT a second write path: it calls `custom.record_write_many` for the
198
- * rows, `public.assoc_add` for an edge that points OUT of the store (the
199
- * message a record was produced by), and `platform.relation_set` for the
200
- * parent's own declared relation to its children. Same store switch, same
201
- * editor rung on the Table, same value envelope, same undeclared-key guard,
202
- * same history rows, same realtime notice.
203
- *
204
- * ONE REFUSAL REFUSES THE WHOLE GRAPH, BY NAME — the answer says which member
205
- * failed and carries the store's own sentence about it, and nothing is
206
- * written.
207
- *
208
- * Every child MUST name a `role`: it is the key of a declared RELATION field
209
- * on the parent's Table, and an edge out of a record that names no field is
210
- * refused by the store (REL-10 / T7) because without it nothing can read the
211
- * relation's delete rule, its cardinality or its organization wall. The order
212
- * children are handed in IS the order of the relation.
213
- */
214
- recordWriteGraph(args: {
215
- table_id: Uuid;
216
- parent: RecordDocument;
217
- /** Each child: its document, the parent FIELD it fills, and optionally its own Table. */
218
- children?: Array<{
219
- data: RecordDocument;
220
- role: string;
221
- table_id?: Uuid;
222
- position?: number;
223
- }>;
224
- /** Edges to things OUTSIDE the store. `direction` defaults to `"in"` — that thing produced this record. */
225
- edges?: Array<{
226
- entity: string;
227
- id: Uuid;
228
- direction?: "in" | "out";
229
- label?: string;
230
- role?: string;
231
- position?: number;
232
- metadata?: Record<string, unknown>;
233
- }>;
234
- }): Promise<RecordsResult<RecordGraphWritten>>;
235
- recordUpdate(args: {
236
- record_id: Uuid;
237
- patch: Record<string, unknown>;
238
- /** Leave it out and the last writer wins; supply it and a loser is TOLD. */
239
- expectedVersion?: number;
240
- }): Promise<RecordsResult<number>>;
241
- /**
242
- * A CELL THAT TAKES WORDS WHICH ARE NOT YET A CHOICE — the words become a choice of that
243
- * column everywhere and the cell takes it, in ONE transaction (lane CHOICE-COLUMN-EDIT,
244
- * `custom.record_update_adding_choices`). `add` is `{ "<column key>": ["words", ...] }`; the
245
- * cell's value in `patch` is the words, and the store turns them into the new choice's key.
246
- * Adding a choice changes the table's columns, so it needs that right; a refusal names it.
247
- * Answers the new version, like `recordUpdate`, and announces the record changed.
248
- */
249
- recordUpdateAddingChoices(args: {
250
- record_id: Uuid;
251
- patch: Record<string, unknown>;
252
- add: Record<string, string[]>;
253
- expectedVersion?: number;
254
- }): Promise<RecordsResult<number>>;
255
- /**
256
- * The Feature Knob `custom/choice_nudge` for the signed-in person in this client's
257
- * organization: what a choice cell does with typed words that are not a choice
258
- * (`decideTypedChoice` in `choice.ts` is the one place that acts on it).
259
- */
260
- choiceNudge(): Promise<RecordsResult<ChoiceNudge>>;
261
- /**
262
- * REC-23. Soft, and reversible within `retention`.
263
- *
264
- * 🚨 NOT FOR A TABLE. A Table is a record, so this door accepts one — and
265
- * then recurses through every record the Table contains inside a single
266
- * transaction, which is unbounded by construction and dies on `57014` at a
267
- * size the product's own import reaches in half a minute. Use
268
- * `tableArchive` below, which does the same work in resumable passes.
269
- */
270
- recordDelete(args: {
271
- record_id: Uuid;
272
- }): Promise<RecordsResult<Timestamp>>;
273
- recordRestore(args: {
274
- record_id: Uuid;
275
- }): Promise<RecordsResult<void>>;
276
- /**
277
- * ARCHIVING A WHOLE TABLE — ONE PASS OF IT (VERIFIER-11 F3).
278
- *
279
- * One call archives at most `chunk` of the table's live records through
280
- * `custom.record_delete` (so every guard, history capture and outbox row
281
- * still happens; nothing is hard-deleted) and comes back with the numbers a
282
- * screen draws progress from. The CALLER LOOPS until `done` — that loop is
283
- * the fix, because the one thing a single statement cannot be made to do is
284
- * finish.
285
- *
286
- * `chunk: 0` changes nothing and only reports, so a screen can say "1,430
287
- * records will be archived" BEFORE a person commits to it. `includeTable:
288
- * false` empties the table and leaves it standing.
289
- *
290
- * RESUMABLE, WITHOUT A JOB ROW: what remains is read off the records
291
- * themselves every call. A pass that fails, a closed tab or a deploy mid-run
292
- * leaves a half-archived table and a next call that continues from exactly
293
- * there. A caller must therefore never report "nothing happened" after a
294
- * failed pass — `archived_total` says what really landed.
295
- */
296
- tableArchive(args: {
297
- table_id: Uuid;
298
- /**
299
- * How many records this pass takes on. The door clamps it; it answers with what it
300
- * took. Default 50 — measured: ~35ms a record against an 8s statement timeout, so
301
- * 200 dies on `57014` and is the original defect one level up.
302
- */
303
- chunk?: number;
304
- /** Archive the Table record itself once nothing live is left in it. Default true. */
305
- includeTable?: boolean;
306
- }): Promise<RecordsResult<TableArchiveProgress>>;
307
- /**
308
- * ONE PASS OF ARCHIVING, ON PURPOSE, A TABLE THE APP'S CODE DEPENDS ON
309
- * (`custom.table_archive_deliberately`, lane 12 P5). Such a table (`code_depends: true`) refuses
310
- * `tableArchive`, `recordDelete`, a slug / kept_for rename, `tableMove` and removal of the mark.
311
- * This door takes the table's slug TYPED by the person and a reason, refuses an agent, and then
312
- * archives through `custom.table_archive` (same progress answer; the caller loops until `done`).
313
- * Use `archiveTypedTableDeliberately` (`@ai-matrx/records/typed-table`), which loops.
314
- */
315
- tableArchiveDeliberately(args: {
316
- table_id: Uuid;
317
- typed_slug: string;
318
- reason: string;
319
- }): Promise<RecordsResult<TableArchiveProgress>>;
320
- /**
321
- * BRINGING A WHOLE TABLE BACK — ONE PASS OF IT (`custom.table_restore`, lane TABLE-ACTIONS).
322
- *
323
- * 🚨 NOT `recordRestore` FOR A TABLE: that door brings the Table, its structure, every record
324
- * and everything built on it back in one statement and dies on `57014` (the clone's "Referral
325
- * Intake Queue 2026-Q4 (copy 7)"). This pass brings back the Table and its structure first, then
326
- * at most `chunk` records, then what was built on it — all from the one archive event — and
327
- * answers `done` when nothing the archive took is still waiting. Use {@link tableRestoreWhole}.
328
- */
329
- tableRestore(args: {
330
- table_id: Uuid;
331
- chunk?: number;
332
- }): Promise<RecordsResult<TableRestoreProgress>>;
333
- /**
334
- * THE WHOLE RESTORE OF A TABLE — the loop every caller needs: `tableRestore` until `done`,
335
- * halving the pass on a statement timeout (a pass that timed out changed nothing). `onPass`
336
- * hears every pass's numbers. Answers the last pass, or the refusal that stopped it (what the
337
- * passes before it brought back stays back; the next call carries on from there).
338
- */
339
- tableRestoreWhole(args: {
340
- table_id: Uuid;
341
- onPass?: (progress: TableRestoreProgress) => void;
342
- }): Promise<RecordsResult<TableRestoreProgress>>;
343
- /**
344
- * DUPLICATE A TABLE — `custom.table_duplicate` (lane TABLE-ACTIONS).
345
- *
346
- * Makes a NEW Table from one the caller may open: its settings and look, every live column (new
347
- * ids), every choice list as a new list (same words, colours, keys and order), every saved view
348
- * (filters, sorts, layouts, every id inside them pointing at the copy), and with `withRecords`
349
- * every live record (a link to another row of the same table follows to the copy's row; a link
350
- * to another table stays). `name` defaults to "<name> (copy)", "(copy 2)", …;
351
- * `organizationId` defaults to the source's organization and must be one the caller belongs to.
352
- * The source is never written. The copy is made in passes of a few seconds (any size; the
353
- * store answers "copying" until "done"), and this call loops them. Refused before anything is
354
- * made, the refusal carries the store's one sentence (not given / archived / not a member there
355
- * / a column linking across organizations).
356
- */
357
- tableDuplicate(args: {
358
- tableId: Uuid;
359
- withRecords?: boolean;
360
- name?: string | null;
361
- organizationId?: Uuid | null;
362
- /** Called after every pass with what is copied so far (a progress bar is made of it). */
363
- onProgress?: (progress: TableDuplicateProgress) => void;
364
- }): Promise<RecordsResult<TableDuplicated>>;
365
- /**
366
- * CARRY ON A COPY — `custom.table_duplicate_continue` (lane TABLE-ACTIONS). The copy is made in
367
- * passes of a few seconds each; `tableDuplicate` loops them, and this resumes one that a closed
368
- * tab or a lost connection left unfinished (the copy is kept out of every table list until it
369
- * is done). Only the person who started it; it answers the finished copy, or refuses.
370
- */
371
- tableDuplicateContinue(args: {
372
- copyId: Uuid;
373
- onProgress?: (progress: TableDuplicateProgress) => void;
374
- }): Promise<RecordsResult<TableDuplicated>>;
375
- /**
376
- * THE CALLER'S UNFINISHED COPIES — `custom.table_copies_in_progress` (lane TABLE-ACTIONS). Each
377
- * is still being made (carry it on with `tableDuplicateContinue`) or stopped because its source
378
- * was archived meanwhile (discard it: `tableArchive` on the copy). Nobody else can see them.
379
- */
380
- tableCopiesInProgress(): Promise<RecordsResult<TableCopyInProgress[]>>;
381
- recordRead(args: {
382
- record_id: Uuid;
383
- withComputed?: boolean;
384
- /** Also answer `version` (read in the same round, so the read takes as long as the slower of the two). */
385
- withVersion?: boolean;
386
- organization_id?: Uuid | null;
387
- }): Promise<RecordsResult<RecordRead>>;
388
- /**
389
- * DOOR-1. A page of one Table's records THROUGH `custom.read_records`: the
390
- * store decides which rows this reader may see and which fields of them, and
391
- * a field it masked comes back present-and-null with its reason in `hidden`.
392
- * `total` is null because the door counts nothing it has not read — a count
393
- * of rows a person may not see is a leak with a number on it.
394
- */
395
- list(args: {
396
- table_id: Uuid;
397
- /**
398
- * THE STORE'S ONE FILTER SHAPE (`RecordFilter`). Left out, this is the
399
- * whole page. Supplied, the store narrows INSIDE its own query — never the
400
- * browser, which can only ever filter the rows it was already allowed to
401
- * see and would silently drop the rest of the answer.
402
- *
403
- * It is the same object a saved view stores as `filters` and the same one
404
- * `recordAggregate` counts with, so the rows a drill-through opens are the
405
- * rows the number on the dashboard counted.
406
- */
407
- filter?: StoreFilter;
408
- limit?: number;
409
- offset?: number;
410
- }): Promise<RecordsResult<{
411
- rows: ReadRow[];
412
- total: number | null;
413
- locked?: number;
414
- }>>;
415
- /**
416
- * DOOR-SPEED. ONE PAGE THE STORE SORTED, SEARCHED, FILTERED AND COUNTED, through
417
- * `custom.read_records_page` — the same wall, ladder, field mask and filter as `list`, with the
418
- * order (`sort`, or a hand-ordered view's positions via `view_id`), a text `search` over the
419
- * columns this reader may see (and the words of choice options), and the `total` of the
420
- * matching visible set. It is what a grid pages with: nothing reads the whole table to draw one
421
- * page. A sort on a column this reader cannot see (gone, or masked) is SKIPPED and named in
422
- * `sort_ignored` — the page still loads; one worked out on every read is refused by name.
423
- */
424
- listPage(args: {
425
- table_id: Uuid;
426
- filter?: StoreFilter;
427
- search?: string | null;
428
- sort?: readonly RecordPageSort[];
429
- view_id?: Uuid | null;
430
- limit?: number;
431
- offset?: number;
432
- }): Promise<RecordsResult<RecordPage>>;
433
- /**
434
- * AP3-KEYSET-DOOR. THE SAME PAGE AS `listPage`, PAGED BY A CURSOR, through
435
- * `custom.read_records_keyset`: the same wall, ladder, field mask, filter, search and sort (no
436
- * hand-ordered view), the same rows in the same order — but the next page starts after the last
437
- * row's sort values and id, so a write landing mid-read never skips or repeats a row. Pass back
438
- * `cursor` as `after` (it is opaque; `null` on the last page). A cursor handed to a different
439
- * sort, filter or search is refused by name ("start from the first page"), never reinterpreted.
440
- *
441
- * Every row carries the `version` and `organization_id` it was read at, in the same statement as
442
- * its values. With `ids`, it re-reads exactly those rows among the ones the reader may see (in the
443
- * page's order; `after` ignored, `cursor` and `total` null) — get-by-id, the re-read after a write,
444
- * and the changed ids of a realtime notice.
445
- */
446
- listKeyset(args: {
447
- table_id: Uuid;
448
- filter?: StoreFilter;
449
- search?: string | null;
450
- sort?: readonly RecordPageSort[];
451
- after?: string | null;
452
- ids?: readonly Uuid[];
453
- limit?: number;
454
- }): Promise<RecordsResult<RecordKeysetPage>>;
455
- /**
456
- * DOOR-1 FOR AN ID SET. Exactly these records of this Table, through
457
- * `custom.read_records_by_ids` — the same ladder, the same level, the same
458
- * field masking and the same page ceiling as `list`, addressed by id instead
459
- * of by page. An id the reader may not see simply does not come back, which
460
- * is the same answer `list` gives by omission.
461
- *
462
- * It exists because a realtime notice has always named the exact ids that
463
- * moved and no door could take them: three cells changing re-read a fifty-row
464
- * page in every watching browser.
465
- */
466
- listByIds(args: {
467
- table_id: Uuid;
468
- ids: readonly Uuid[];
469
- }): Promise<RecordsResult<ReadRow[]>>;
470
- /**
471
- * DOOR-1 FOR THE ROWS THAT LEFT: a page of one Table's ARCHIVED records,
472
- * through `custom.read_records_archived` — the same ladder, the same level,
473
- * the same field masking and the same page ceiling as `list`, with the sign
474
- * of the `deleted_at` test flipped, plus who archived each one and when.
475
- *
476
- * 🚨 IT EXISTS BECAUSE ARCHIVING WAS A ONE-WAY DOOR (VERIFIER-10 F4). The
477
- * store has always had `record_restore`, and it has always done exactly the
478
- * right thing; what it did not have was any door that could LIST the records
479
- * it would act on, because every read door answers live rows only. So an
480
- * archived record was unreachable from every screen in the platform.
481
- *
482
- * `lane` is the archived-items law's two lanes — "mine" (what I archived) and
483
- * "org" (what anybody in this organization archived), which is the default.
484
- */
485
- listArchived(args: {
486
- table_id: Uuid;
487
- lane?: ArchiveLane;
488
- limit?: number;
489
- offset?: number;
490
- }): Promise<RecordsResult<{
491
- rows: ArchivedRow[];
492
- total: number | null;
493
- }>>;
494
- query(query: RecordQuery): Promise<RecordsResult<{
495
- rows: ReadRow[];
496
- total: number | null;
497
- }>>;
498
- /**
499
- * Every Table the person can see across ALL their organizations
500
- * (`config.organizationIds`); `organization_id` is the page's optional filter
501
- * (absent = all). Each Table carries its own `organization_id`.
502
- */
503
- tableList(args?: {
504
- organization_id?: Uuid | null;
505
- }): Promise<RecordsResult<Table[]>>;
506
- /**
507
- * ONE Table's declaration by id — `null` when this reader may not see it or it is not a Table.
508
- * The same kernel record `tableList` lists, read through `read_records_by_ids` for exactly
509
- * that id, so a screen that opens one table never lists every table to find it (a list capped
510
- * at 500 answered "no table" past the 500th).
511
- */
512
- tableRead(args: {
513
- table_id: Uuid;
514
- organization_id?: Uuid | null;
515
- }): Promise<RecordsResult<Table | null>>;
516
- /**
517
- * ONE Table of THIS organization found by its slug — or, with no slug, by its name — in ONE
518
- * request (`custom.table_find`). `null` when there is none or this reader may not see it: the
519
- * store reads the candidates through the same read door `tableRead` uses, so a table she may
520
- * not see answers exactly like one nobody made. Where several share a slug, the oldest she may
521
- * see answers, every time (the same pick `ensureTable` makes). Never list every table to find one.
522
- *
523
- * `keptFor` (an app's table): the slug AND what the table is kept for must match — a person's own
524
- * table of the same slug is a different table and never answers. With `keptFor` and no live
525
- * match, an ARCHIVED match is answered as `{ id, organization_id, archived_at }` (no document), so
526
- * a caller says "archived — restore it", never "missing".
527
- */
528
- tableFind(args: ({
529
- slug: string;
530
- name?: never;
531
- } | {
532
- name: string;
533
- slug?: never;
534
- }) & {
535
- keptFor?: string;
536
- }): Promise<RecordsResult<Table | null>>;
537
- /**
538
- * IS THIS TABLE IN THE ARCHIVE? (lane HUB-FIX, 2026-09-23.) The archived row for one
539
- * Table of this organization, or `null` when the archive does not hold it — which
540
- * is an ANSWER, never "it may have been deleted". A table page that cannot find a
541
- * Table asks this before saying anything: an archived Table's own address used to
542
- * read "…or it may have been deleted" when it was archived and one click from back.
543
- */
544
- tableArchived(args: {
545
- table_id: Uuid;
546
- }): Promise<RecordsResult<ArchivedRow | null>>;
547
- /**
548
- * WHO CAN SEE EACH TABLE, AND WHETHER THE CALLER MADE IT — `custom.table_facts`
549
- * (lane HUB-FIX). `visibility` and `created_by` are record COLUMNS the Table document
550
- * never carried, so a screen that sorts Tables into lanes asks this and folds the
551
- * answer onto `tableList()`'s Tables with `withTableFacts`.
552
- *
553
- * 🚨 IT IS ITS OWN CALL, NOT PART OF `tableList()` (0.57.3). 0.57.2 folded it into
554
- * every table list, so every screen that merely LISTS tables (the field editor's
555
- * relation target, the import wizard, settings) paid a second round trip it never
556
- * used — and every test double that answers a table list had to answer it too
557
- * (records-ui 0.84.5's gate: 47 tests in 15 files red). Only the lane-sorting
558
- * screens ask.
559
- *
560
- * The door-presence pattern: when the store's catalogue does not carry the door the
561
- * answer is `null` — nothing asked, nothing invented.
562
- */
563
- tableFacts(args?: {
564
- organization_id?: Uuid | null;
565
- }): Promise<RecordsResult<TableFact[] | null>>;
566
- /**
567
- * WHICH STORE CURRENTLY WRITES each table — `custom.where_tables_live`.
568
- *
569
- * This is a batch cutover decision, not a Table's home address: during COPY
570
- * mode an older table and its record-store copy share an id, and only this
571
- * door knows which one the organization is still using. It is intentionally
572
- * unbound from this client's organization because the door derives the answer
573
- * from each supplied table and the caller's authority.
574
- */
575
- tablesLiveWhere(args: {
576
- table_ids: Uuid[];
577
- }): Promise<RecordsResult<TableLiveLocation[]>>;
578
- /**
579
- * WHICH ORGANIZATION A TABLE LIVES IN, BY NAME, AND WHERE IT MAY GO — `custom.table_home`
580
- * (SC-1' / SC-1-TAILS). Read FROM THE TABLE, never from the organization the client is bound
581
- * to, so it answers for a table shared from outside too. `null` = not given to this person,
582
- * or not there (the store says the same for both, on purpose). A store without the door
583
- * refuses `door_absent` — never a guessed organization.
584
- */
585
- tableHome(args: {
586
- table_id: Uuid;
587
- }): Promise<RecordsResult<TableHome | null>>;
588
- /**
589
- * MOVE A TABLE into another organization the caller belongs to — `custom.table_move`. It
590
- * carries every Table inside it or its rows and writes the change events; refused, NOTHING
591
- * moved and the refusal carries the store's one sentence. `expected_version` is the Table's
592
- * version the caller decided on (a concurrent change refuses with "look again").
593
- */
594
- tableMove(args: {
595
- table_id: Uuid;
596
- to_organization_id: Uuid;
597
- expected_version?: number | null;
598
- }): Promise<RecordsResult<TableMoved>>;
599
- /**
600
- * The Fields that apply. NOTION-PROPS: a two-way link's reverse Field (`isReverseField`) is left out
601
- * unless `withReverse` — every screen draws it as the table's reverse column (`reverseColumns`, with
602
- * `read_only: false`), which reads and writes its links; listed as a Field too it would draw twice.
603
- */
604
- fields(args: {
605
- table_id: Uuid;
606
- recordType?: string;
607
- withReverse?: boolean;
608
- }): Promise<RecordsResult<Field[]>>;
609
- /**
610
- * FLD-5 / FLD-6: a list field stores the id of an option RECORD, because
611
- * every pick-list is already a Table. These are that Table's records — the
612
- * store resolves which Table from the Field's own config, so no caller has to
613
- * know it.
614
- */
615
- fieldOptions(args: {
616
- field_id: Uuid;
617
- }): Promise<RecordsResult<StoredRecord[]>>;
618
- /**
619
- * How many records hold each choice of one choice column, keyed by the option's id
620
- * (`custom.field_choice_usage`; counts only records the caller may see). What a column editor
621
- * says before a choice that records still hold is removed: "3 records use “X-ray”."
622
- */
623
- fieldChoiceUsage(args: {
624
- field_id: Uuid;
625
- }): Promise<RecordsResult<Record<string, ChoiceUsage>>>;
626
- /**
627
- * A column's choices saved AND the records of each removed choice moved to another choice,
628
- * kept as other values, or cleared — ONE transaction (`custom.field_update_rehoming_choices`).
629
- * `rehome` is keyed by the removed option's id. The answer carries `undo`; sending
630
- * `{ patch: { options: undo.options }, cells_back: undo.cells_back }` back through this same
631
- * call puts the list and every cell back, again in one transaction.
632
- */
633
- fieldUpdateRehomingChoices(args: {
634
- field_id: Uuid;
635
- patch: FieldPatch;
636
- rehome?: Record<string, ChoiceRehome> | undefined;
637
- cells_back?: readonly ChoiceCellBack[] | undefined;
638
- }): Promise<RecordsResult<ChoicesRehomed>>;
639
- tableCapacity(args: {
640
- table_id: Uuid;
641
- }): Promise<RecordsResult<TableCapacity>>;
642
- /**
643
- * REC-1: a Table has to live somewhere, so a Home comes first — and a Home is
644
- * an ordinary record in the person kernel. `homeId` is therefore required and
645
- * `personKernelId()` is how a caller gets a Table to write one into.
646
- */
647
- tableDeclare(args: {
648
- spec: Record<string, unknown>;
649
- homeId: Uuid;
650
- }): Promise<RecordsResult<Uuid>>;
651
- /**
652
- * FIND THIS TABLE BY ITS SLUG, OR MAKE IT — ONE call, ONE transaction (`custom.table_ensure`).
653
- * The store holds a lock on (organization, slug) across the find and the make, so two tabs
654
- * saving their first record at once get the SAME table; a second call adds any column the spec
655
- * names that the table lacks and never retypes or drops one. `spec.fields` are full
656
- * `custom.field_declare` specs. Prefer `ensureTable(client, NewTableSpec)`, which builds them.
657
- *
658
- * `drift` names every column the table already has whose stored shape differs from the spec
659
- * (type, format, label, multi, required, unique) — reported, never applied. `[]` when nothing
660
- * differs; `null` only from a store too old to compare (see `FieldDrift`).
661
- */
662
- tableEnsure(args: {
663
- spec: Record<string, unknown>;
664
- }): Promise<RecordsResult<{
665
- table_id: Uuid;
666
- home_id: Uuid | null;
667
- created: boolean;
668
- drift: FieldDrift[] | null;
669
- }>>;
670
- /**
671
- * ADD A FIELD TO A TABLE. One call, and the store does the three things no
672
- * client can do for itself: it turns a parity type into the behaviour,
673
- * modifiers, format, unit, relation target and Rules its own guards demand;
674
- * it tells the TABLE about the field (REC-1 / FLD-8 — a definition for a
675
- * field the table never declared is refused, which is the sentence every
676
- * "Add field" used to end on); and it stores the definition as a FIELD
677
- * rather than as a plain record, so the delete rules and the
678
- * formula-dependency check can see it.
679
- *
680
- * A choice list carries its `options` as words. The store keeps them the only
681
- * way FLD-5 / FLD-6 allows — as the records of a Table it declares for them —
682
- * so nobody is made to build a table before they can have a dropdown.
683
- */
684
- fieldDeclare(args: {
685
- table_id: Uuid;
686
- spec: NewFieldDeclaration;
687
- }): Promise<RecordsResult<Uuid>>;
688
- /** One field's own settings. What it HOLDS is a conversion and is refused here by name. */
689
- fieldUpdate(args: {
690
- field_id: Uuid;
691
- patch: FieldPatch;
692
- }): Promise<RecordsResult<Uuid>>;
693
- /**
694
- * CHANGE WHAT A COLUMN HOLDS, through `custom.migrate_retype` (FLD-4 / T12). `to` is the store's
695
- * behaviour word — `text`, `range` (numbers and dates), `boolean`, `list`, `relation`. Every value
696
- * that converts is converted; every value that does not is kept in that record's `_retired`
697
- * with the reason, never coerced and never deleted. The answer counts both.
698
- */
699
- migrateRetype(args: {
700
- field_id: Uuid;
701
- to: string;
702
- note?: string;
703
- }): Promise<RecordsResult<FieldRetyped>>;
704
- /**
705
- * MERGE ONE RECORD INTO ANOTHER, through `custom.migrate_merge` (T5 / REC-21). The loser's values
706
- * the winner did not hold move across, the ones that differ are kept as ranked alternates, every
707
- * link to the loser now points at the winner, and the loser is archived with its id resolving to
708
- * the winner. Editor on BOTH records is decided first. The answer's `migration_id` is what
709
- * `migrateUndo` takes.
710
- */
711
- migrateMerge(args: {
712
- winner_id: Uuid;
713
- loser_id: Uuid;
714
- note?: string | null;
715
- }): Promise<RecordsResult<RecordsMerged>>;
716
- /** Put a recorded Migration back (`custom.migrate_undo`): a retype or a merge, by its id. */
717
- migrateUndo(args: {
718
- migration_id: Uuid;
719
- }): Promise<RecordsResult<MigrationUndone>>;
720
- /**
721
- * REL-DISP. THE WORDS ONE RELATION CELL SHOWS, resolved by the store through
722
- * that column's own display spec — one column or several, joined by its
723
- * separator. Never resolve a relation label any other way: the store's
724
- * `custom._words_for` is the one body that decides what a record is called, it
725
- * asks the read-access ladder BEFORE it reads the name, and a record this reader
726
- * may not open comes back as the withheld sentence rather than its name or id.
727
- * A value that is not an id is handed straight back — it is already words.
728
- */
729
- relationWords(args: {
730
- field_id: Uuid;
731
- value: string;
732
- }): Promise<RecordsResult<string | null>>;
733
- /**
734
- * The same answer for a WHOLE PAGE of cells in one round trip. Prefer this
735
- * wherever a grid, board, list or picker resolves more than one chip: the
736
- * per-id lane is what made a page of relation cells a page of requests.
737
- */
738
- relationWordsMany(args: RelationWordsManyArgs): Promise<RecordsResult<Record<string, string>> & {
739
- archived?: readonly string[];
740
- icons?: Record<string, RelationIcons>;
741
- }>;
742
- /**
743
- * VISION-REACH G1. Which records of `table_id` each name names — its name column, case and
744
- * spacing ignored, only records this reader may see. Hand the answer to `relationNameIndexOf`
745
- * and pass that to the coercion as `relationNames`. Up to 5,000 names a call; more are sent in
746
- * groups by this method.
747
- */
748
- relationNamesMatch(args: {
749
- table_id: Uuid;
750
- names: string[];
751
- }): Promise<RecordsResult<RelationNamesAnswer>>;
752
- /**
753
- * VIEWS-AND-FIELDS BL (REL-9). The REVERSE COLUMNS of a Table: one per relation column of another
754
- * table (or this one) that links here, read-only, virtual — never a Field of this Table, so
755
- * `applicableFields` does not list them. A linking table this reader may not know is left out.
756
- */
757
- reverseColumns(args: {
758
- table_id: Uuid;
759
- }): Promise<RecordsResult<ReverseColumn[]>>;
760
- /**
761
- * A page of records' links through ONE reverse column, in one round trip per 200 records:
762
- * `{ [record id]: { total, links: [{ id, words }] } }`, only linking records this reader may see.
763
- * `limit` (1–50) and `offset` page one record's links — a record with thousands of links costs
764
- * one count and one page. A record with no links answers `{ total: 0, links: [] }`.
765
- */
766
- reverseLinksMany(args: ReverseLinksManyArgs): Promise<RecordsResult<Record<string, ReverseLinks>>>;
767
- /**
768
- * The same, through SEVERAL reverse columns in ONE call (`custom.reverse_links_many_fields`):
769
- * `{ [source field id]: { [record id]: { total, links } } }`. A store without the door answers
770
- * `door_absent` — ask `reverseLinksMany` per column then.
771
- */
772
- reverseLinksFields(args: ReverseLinksFieldsArgs): Promise<RecordsResult<Record<string, Record<string, ReverseLinks>>>>;
773
- /**
774
- * NOTION-PROPS. A TWO-WAY LINK: makes (or returns) the reverse Field of relation `field_id` on its
775
- * target table (`custom.relation_reverse_field`), so the link is a column there that edits the same
776
- * links. Its key is the reverse column's key; `label` defaults to the linking table's name.
777
- */
778
- relationReverseField(args: {
779
- field_id: Uuid;
780
- label?: string;
781
- }): Promise<RecordsResult<Uuid>>;
782
- /**
783
- * NOTION-PROPS. Adds and removes links from the reverse side of a two-way link
784
- * (`custom.relation_reverse_set`): each id becomes a write of THAT record's forward Field.
785
- * Answers how many records changed.
786
- */
787
- relationReverseSet(args: {
788
- record_id: Uuid;
789
- field_id: Uuid;
790
- add?: readonly Uuid[];
791
- remove?: readonly Uuid[];
792
- }): Promise<RecordsResult<number>>;
793
- /** Take a field off a table. Refuses the title field, the last field, and one another field reads through. */
794
- fieldRetire(args: {
795
- field_id: Uuid;
796
- }): Promise<RecordsResult<boolean>>;
797
- /**
798
- * Bring a removed column back (`custom.field_restore`): the set that was retired with it, the
799
- * Table's declaration of those columns, and the links they made. The values never left.
800
- */
801
- fieldRestore(args: {
802
- field_id: Uuid;
803
- }): Promise<RecordsResult<boolean>>;
804
- /**
805
- * DUPLICATE PROPERTY (Notion N5) — `custom.field_duplicate`: a new column right after this one, named
806
- * "<name> (1)", the same kind (choices with their colours, unit, link, formula, rules, sensitivity), and
807
- * every record's value copied into it in one statement. A link column copies its definition only (its
808
- * values are links); a formula, lookup or roll-up works its answer out itself. Needs the table's
809
- * add-a-column rung, the same as `fieldDeclare`.
810
- */
811
- fieldDuplicate(args: {
812
- field_id: Uuid;
813
- }): Promise<RecordsResult<FieldDuplicated>>;
814
- /**
815
- * CHAIR-ROLLUP-HONEST. Is a column this lookup or roll-up reads archived — the link it reads
816
- * through, a back-link's linking column, or the far column it totals (`custom.field_source_archived`)?
817
- * `null` while every source is live. Bring it back with `fieldRestore({ field_id })`.
818
- */
819
- fieldSourceArchived(args: {
820
- field_id: Uuid;
821
- }): Promise<RecordsResult<SourceArchived | null>>;
822
- /**
823
- * A TABLE AS A KIND (KINDS-GLUE wave 3, N1): `custom.table_kind_facts` verbatim — the Table's
824
- * live Fields, choices and stamp, as the asking person. The door finds the Table's organization
825
- * itself, so this works for a Table in any organization the person may open; anything else is
826
- * refused (`42501`, the store's sentence).
827
- */
828
- tableKindFacts(args: {
829
- table_id: Uuid;
830
- }): Promise<RecordsResult<TableKindFacts>>;
831
- /**
832
- * A TABLE'S ACCESS LEVEL (CONFIDENTIAL-BY-ORG-ADMIN): `custom.table_level_facts` verbatim - its level,
833
- * readers, who approves a change (`set_by`) and whether THIS person may (`can_set`). Draw the control only
834
- * when `can_set` is true; anyone who may know the table may ask.
835
- */
836
- tableLevelFacts(args: {
837
- table_id: Uuid;
838
- }): Promise<RecordsResult<TableLevelFacts>>;
839
- /**
840
- * MAKE A CUSTOM TABLE CONFIDENTIAL, or change whom it names (`custom.set_table_confidential`). Succeeds
841
- * only for an owner/admin of the table's own organization on an ordinary custom table; the approver, seat,
842
- * reason and date are recorded. `readers` is the list of `{field, level}` rules (a person field of the
843
- * table); `reason` is required.
844
- */
845
- setTableConfidential(args: {
846
- table_id: Uuid;
847
- readers: TableReaderRule[];
848
- reason: string;
849
- }): Promise<RecordsResult<TableLevelSet>>;
850
- /** THE WAY BACK: the same caller rule, the table is Organization again (`custom.set_table_organization`). */
851
- setTableOrganization(args: {
852
- table_id: Uuid;
853
- reason: string;
854
- }): Promise<RecordsResult<TableLevelSet>>;
855
- /**
856
- * THE COLUMNS THIS TABLE HAD AND NO LONGER HAS (grids review 3): its retired Field records,
857
- * newest first, through the same archived door the Table archive uses — addressed at the Field
858
- * kernel (every Field is a record in it) and paged until the door answers short.
859
- */
860
- fieldsRetired(args: {
861
- table_id: Uuid;
862
- }): Promise<RecordsResult<ArchivedRow[]>>;
863
- /** What the registry says about a token, and whether it can hold a value at all. */
864
- entityTable(args: {
865
- token: string;
866
- }): Promise<RecordsResult<EntityTableFacts>>;
867
- /** The fields THIS organization added to that standard table. */
868
- entityFields(args: {
869
- token: string;
870
- }): Promise<RecordsResult<Field[]>>;
871
- /** The fields EVERY named organization added to that standard table, with their choices, in one read. */
872
- entityFieldsAcross(args: {
873
- token: string;
874
- organization_ids: Uuid[];
875
- }): Promise<RecordsResult<EntityFieldsAcross>>;
876
- /** Add a column to a standard table. An organization admin's right - it changes the table for everybody. */
877
- entityFieldDeclare(args: {
878
- token: string;
879
- spec: NewEntityFieldDeclaration;
880
- }): Promise<RecordsResult<Uuid>>;
881
- /** One field's own settings. A TYPE change is refused here by name, as it is on a custom table. */
882
- entityFieldUpdate(args: {
883
- field_id: Uuid;
884
- patch: Record<string, unknown>;
885
- }): Promise<RecordsResult<Uuid>>;
886
- /** Take a custom field off a standard table. The values already written stay in each row. */
887
- entityFieldRetire(args: {
888
- field_id: Uuid;
889
- }): Promise<RecordsResult<Uuid>>;
890
- /** May this person add a column here - and if not, the store's own sentence saying why. */
891
- entityFieldRights(args: {
892
- token: string;
893
- }): Promise<RecordsResult<EntityFieldRights>>;
894
- /** REC-53 in one answer: the row's real columns AND its custom values AND the definitions. */
895
- entityRecordRead(args: {
896
- token: string;
897
- record_id: Uuid;
898
- }): Promise<RecordsResult<EntityRecordRead>>;
899
- /**
900
- * AP-4: the custom rows that link to one platform record, by which field and in which table.
901
- * Keyed by the ROW's organization (`organization_id`), never the client's active one. Paged:
902
- * pass the previous answer's `next_cursor` as `cursor`.
903
- */
904
- entityBackLinks(args: {
905
- token: string;
906
- record_id: Uuid;
907
- organization_id: Uuid;
908
- limit?: number;
909
- cursor?: string | null;
910
- }): Promise<RecordsResult<EntityBackLinks>>;
911
- /**
912
- * THE one write door for a standard row (`custom.entity_row_write`, as the person): custom values
913
- * as a patch (a key left out is left alone, a key set to null is cleared with its envelope),
914
- * archive / restore, and real columns only where the store lists them. The row's own organization
915
- * governs; `expected_version` refuses a stale write; a change that changes nothing writes nothing.
916
- */
917
- entityRowWrite(args: {
918
- token: string;
919
- /**
920
- * null ADDS a row (chairblk3_a): only for a token whose API facts say `create_via: "insert"`
921
- * (`drill_describe(...).api.create_via` — task and project), as one insert AS THE PERSON in
922
- * `organization_id` (default: this client's organization); the answer carries `created: true`
923
- * and the new `id`. Every other token refuses in its own words.
924
- */
925
- record_id: Uuid | null;
926
- /** A change by id: only to say which organization the row must belong to. A new row: where it goes. */
927
- organization_id?: Uuid | null;
928
- custom?: Record<string, unknown>;
929
- columns?: Record<string, unknown>;
930
- expected_version?: number | null;
931
- archive?: boolean | null;
932
- }): Promise<RecordsResult<EntityRowWritten>>;
933
- /** Rows of that standard table with this custom value. Refuses a field nobody declared. */
934
- entityRecordsFind(args: {
935
- token: string;
936
- key: string;
937
- value?: unknown;
938
- limit?: number;
939
- offset?: number;
940
- }): Promise<RecordsResult<EntityRecordsFound>>;
941
- /** The kernel Tables a caller writes a Home, a Field or a Rule into. */
942
- personKernelId(): Promise<RecordsResult<Uuid>>;
943
- fieldKernelId(): Promise<RecordsResult<Uuid>>;
944
- ruleKernelId(): Promise<RecordsResult<Uuid>>;
945
- /** Every record the Rule says is a member. A saved view's list is this, not a filter a screen ran. */
946
- /** PRODUCTS row 7 — the whole board: its stage column, its stages in the declared
947
- * order, and every Rule WITH the sentence it says when it refuses. */
948
- pipelineRead(args: {
949
- table_id: Uuid;
950
- }): Promise<RecordsResult<Pipeline>>;
951
- /** The store's own count and total per column, over what this person may see. */
952
- pipelineBoard(args: {
953
- table_id: Uuid;
954
- measure?: string | null;
955
- /**
956
- * S2-PRIME — the view's question, either shape (`StoreFilter`). Given, the headings count and
957
- * total exactly the cards the same filter puts on the board (`custom.pipeline_board`'s
958
- * four-argument door); left out, the whole table this person may see, as before.
959
- */
960
- filter?: StoreFilter | null;
961
- }): Promise<RecordsResult<PipelineColumn[]>>;
962
- /** Whether this card may go to that column — asked BEFORE the finger lets go. */
963
- pipelineTransitionRefusal(args: {
964
- record_id: Uuid;
965
- to: string;
966
- }): Promise<RecordsResult<PipelineVerdict>>;
967
- /**
968
- * Move a record to a stage. An ORDINARY record write, judged by the same Rules.
969
- *
970
- * It answers an OBJECT on every path. A gate whose `on_fail` is `require_approval`
971
- * comes back `applied: false` with the wait it filed — the record has NOT moved, and a
972
- * screen that treated the call's success as the move's success would show the card in
973
- * the wrong column while somebody is still deciding.
974
- */
975
- pipelineMove(args: {
976
- record_id: Uuid;
977
- to: string;
978
- also?: Record<string, unknown>;
979
- expected_version?: number | null;
980
- }): Promise<RecordsResult<PipelineMoveResult>>;
981
- /**
982
- * MOVE MANY CARDS IN ONE CALL (lane S4, `custom.pipeline_move_many`). Each card is judged by
983
- * `pipeline_move` exactly as one is, in its own savepoint: a refused card writes nothing and the
984
- * others still land. `expected_version` is required per card — a card that changed since the
985
- * board loaded answers `changed_since_loaded` and is never overwritten. A refusal of the WHOLE
986
- * call (a stranger, an empty batch, more than the `custom/batch_items_max` knob) is the error.
987
- */
988
- pipelineMoveMany(args: {
989
- moves: PipelineMoveManyItem[];
990
- }): Promise<RecordsResult<PipelineMoveMany>>;
991
- /** Declare (or re-state) a pipeline: the stage column and its transition Rules. */
992
- pipelineDeclare(args: {
993
- table_id: Uuid;
994
- spec: PipelineSpec;
995
- }): Promise<RecordsResult<PipelineDeclared>>;
996
- /** Which column of this table holds its stage, or null when it is not a board. */
997
- tableStageField(args: {
998
- table_id: Uuid;
999
- }): Promise<RecordsResult<string | null>>;
1000
- /** The closed list of what a gate does when it says no — the store is the authority. */
1001
- stageRuleOnFailKinds(): Promise<RecordsResult<{
1002
- behaviour: StageRuleOnFail;
1003
- note: string;
1004
- }[]>>;
1005
- /** Whether this organization's gates refuse or warn. One opinion, asked once. */
1006
- stageRuleEnforcement(): Promise<RecordsResult<StageRuleEnforcement>>;
1007
- /** What is waiting on this card: approvals filed against its own stage column. */
1008
- recordStagePending(args: {
1009
- record_id: Uuid;
1010
- }): Promise<RecordsResult<StagePending[]>>;
1011
- /** The same question for a whole board, in ONE call — what a Kanban badges cards from. */
1012
- pipelinePending(args: {
1013
- table_id: Uuid;
1014
- }): Promise<RecordsResult<StagePendingOnBoard[]>>;
1015
- /**
1016
- * WHAT THIS GATE WOULD DO TO THIS BOARD TODAY — for a gate that has not been saved.
1017
- *
1018
- * The settings screen calls it on every edit of the condition, which is why it takes
1019
- * the gate rather than a rule id: no saved-rule door can answer about a rule that does
1020
- * not exist yet. The store compiles it with the same compiler `pipelineDeclare` uses,
1021
- * so the number here and the refusal at the door are the same rule — a preview with its
1022
- * own compiler would be wrong exactly at the edge of the condition, which is the only
1023
- * place anybody looks.
1024
- *
1025
- * A gate that does not say what it demands is REFUSED, not answered zero: "no cards
1026
- * would be stopped" beside a half-written rule is the sentence that gets it saved.
1027
- */
1028
- pipelineGatePreview(args: {
1029
- table_id: Uuid;
1030
- stage: string;
1031
- gate: PipelineGate | Record<string, unknown>;
1032
- }): Promise<RecordsResult<PipelineGatePreview>>;
1033
- /**
1034
- * SERVER LANE ONLY. `custom.rule_members` walks the whole scope table through the evaluator and
1035
- * returns STORED rows — no read-access ladder, no masking — so no browser role holds EXECUTE on it
1036
- * and it answers 42501 from a signed-in seat. A screen reads a Rule's members through
1037
- * `ruleMembersVisible`.
1038
- */
1039
- ruleMembers(args: {
1040
- rule_id: Uuid;
1041
- }): Promise<RecordsResult<StoredRecord[]>>;
1042
- /**
1043
- * S2-PRIME — THE MEMBERS OF A MEMBERSHIP RULE THIS PERSON MAY SEE, a page at a time
1044
- * (`custom.rule_members_visible`): the list door asked the Rule's own test, so the rows are the
1045
- * read door's — the same ladder, masked documents, the same page ceiling.
1046
- */
1047
- ruleMembersVisible(args: {
1048
- rule_id: Uuid;
1049
- limit?: number;
1050
- offset?: number;
1051
- }): Promise<RecordsResult<ReadRow[]>>;
1052
- /** Is this one record a member, and WHY — the store's own answer. */
1053
- ruleMembership(args: {
1054
- rule_id: Uuid;
1055
- record_id: Uuid;
1056
- }): Promise<RecordsResult<unknown>>;
1057
- /** Run a stored Rule against a document. */
1058
- ruleRun(args: {
1059
- rule_id: Uuid;
1060
- values: Record<string, unknown>;
1061
- context?: Record<string, unknown>;
1062
- }): Promise<RecordsResult<unknown>>;
1063
- /** Evaluate a Rule expression that has not been stored — the conditional logic a form runner asks about. */
1064
- ruleEval(args: {
1065
- expr: unknown;
1066
- values: Record<string, unknown>;
1067
- context?: Record<string, unknown>;
1068
- }): Promise<RecordsResult<unknown>>;
1069
- /**
1070
- * Write ONE Rule as a real Rule. `recordWrite` into the Rule kernel makes a
1071
- * valid Rule document that carries `data_class = 'record'`, and every reader
1072
- * that looks for a Rule looks for the class — `custom.agg_subscriptions`
1073
- * selects `where data_class = 'rule'` — so a subscription written that way
1074
- * fires at nobody. This is the door that closes it.
1075
- */
1076
- /** This organization's forms, with how many answers arrived and how many are in the table. */
1077
- forms(args?: {
1078
- table_id?: Uuid | null;
1079
- }): Promise<RecordsResult<FormSummary[]>>;
1080
- /**
1081
- * THIS ORGANIZATION'S BOOKING PAGES (PRODUCTS row 14), with the numbers that make
1082
- * the list worth opening: how many are booked, cancelled, still ahead, and how many
1083
- * slots somebody is holding right now. A booking page is an `anon_form`, so it is
1084
- * opened and closed with `anonPublish` exactly as a form is.
1085
- */
1086
- bookings(args?: {
1087
- table_id?: Uuid | null;
1088
- }): Promise<RecordsResult<BookingSummary[]>>;
1089
- /**
1090
- * CREATE OR RE-STATE ONE BOOKING PAGE over one Table. `admin` on the Table,
1091
- * because a booking page decides what a stranger may write into it and which
1092
- * hours of the organization's week are on offer.
1093
- *
1094
- * `slot`, `status` and `booked_with` are the store's to fill in: a question
1095
- * naming any of the three is refused BY NAME, so a page cannot be built that
1096
- * lets a visitor choose their own status. It does NOT publish — `anonPublish`
1097
- * is the one act that opens a public surface, for a booking page exactly as
1098
- * for a form.
1099
- *
1100
- * Until 2026-09-21 this door had no client method, so the ONLY way to a
1101
- * booking page was to ask an agent for one. The agent path is the faster one,
1102
- * never the only one.
1103
- */
1104
- bookingDeclare(args: {
1105
- table_id: Uuid;
1106
- title: string;
1107
- questions: unknown[];
1108
- availability?: Partial<BookingAvailability> | null;
1109
- presentation?: Record<string, unknown> | null;
1110
- submission_cap?: number | null;
1111
- quarantine_rule_id?: Uuid | null;
1112
- notify_rule_id?: Uuid | null;
1113
- form_id?: Uuid | null;
1114
- slug?: string | null;
1115
- home_id?: Uuid | null;
1116
- }): Promise<RecordsResult<BookingDeclared>>;
1117
- /** Create or re-state one form. A question naming no Field of that Table is refused BY NAME. */
1118
- formDeclare(args: {
1119
- table_id: Uuid;
1120
- title: string;
1121
- questions: unknown[];
1122
- presentation?: Record<string, unknown> | null;
1123
- submission_cap?: number | null;
1124
- quarantine_rule_id?: Uuid | null;
1125
- notify_rule_id?: Uuid | null;
1126
- form_id?: Uuid | null;
1127
- slug?: string | null;
1128
- }): Promise<RecordsResult<Uuid>>;
1129
- /**
1130
- * WHICH OF A FORM'S QUESTIONS ARE ASKED, given the answers so far — for the OWNER's preview of
1131
- * a draft (`custom.form_preview_asks`). One row per question in order; `asked` is false only
1132
- * when the store's own Rule said so. Undecided and unworkable conditions are asked, the second
1133
- * with the store's sentence in `said`.
1134
- */
1135
- formPreviewAsks(args: {
1136
- table_id: Uuid;
1137
- questions: unknown[];
1138
- values: Record<string, unknown>;
1139
- }): Promise<RecordsResult<Array<{
1140
- field_key: string;
1141
- asked: boolean;
1142
- decided: boolean;
1143
- said: string | null;
1144
- }>>>;
1145
- /**
1146
- * WHAT A FORM'S LOOK MAY BE, AND WHAT IT WOULD LOOK LIKE (`custom.form_look_options`): the
1147
- * organization's public pictures (the same list a portal's look offers), the colours, and the
1148
- * look a stranger would see for the draft `presentation` — the builder's preview draws that.
1149
- */
1150
- formLookOptions(args?: {
1151
- presentation?: Record<string, unknown> | null;
1152
- }): Promise<RecordsResult<FormLookOptions>>;
1153
- /**
1154
- * THE ROUTE THROUGH A DRAFT FORM (`custom.form_preview_route`, lane TYPEFORM-DUP): which questions
1155
- * are asked given the answers so far (showIf AND logic jumps), the ending reached and the score —
1156
- * the store's walk, the one the stranger's page and `custom.form_submit` read too.
1157
- */
1158
- formPreviewRoute(args: {
1159
- table_id: Uuid;
1160
- questions: unknown[];
1161
- endings?: unknown[] | null;
1162
- values: Record<string, unknown>;
1163
- }): Promise<RecordsResult<FormRoute>>;
1164
- /** A form's results (`custom.form_results`): views, starts, completions, drop-off, answers. */
1165
- formResults(args: {
1166
- form_id: Uuid;
1167
- }): Promise<RecordsResult<FormResults>>;
1168
- /** TYPEFORM-2: the organization's form knobs (`custom.form_knobs`): owner header, choice auto-advance. */
1169
- formKnobs(): Promise<RecordsResult<{
1170
- show_owner_header: boolean;
1171
- choice_auto_advance: boolean;
1172
- }>>;
1173
- /**
1174
- * What the store makes of a file's columns, before anything is written.
1175
- * `columns` is `[{header, samples}]` — the first page of the file is plenty.
1176
- */
1177
- importPlan(args: {
1178
- table_id: Uuid;
1179
- columns: Array<{
1180
- header: string;
1181
- samples: unknown[];
1182
- }>;
1183
- }): Promise<RecordsResult<ImportPlan>>;
1184
- /**
1185
- * Open a run. `file_hash` is the run's IDENTITY: the same bytes into the same
1186
- * table a second time answer the FIRST run with `already: true` and write
1187
- * nothing, so a re-import doubles nothing. `force` re-opens deliberately.
1188
- */
1189
- importBegin(args: {
1190
- table_id: Uuid;
1191
- format?: "csv" | "xlsx";
1192
- source_name?: string | null;
1193
- source_columns?: unknown[];
1194
- file_hash?: string | null;
1195
- policy?: ImportPolicy;
1196
- /** A Field key. A row whose value for it is already here is a duplicate. */
1197
- dedupe_key?: string | null;
1198
- file_bytes?: number | null;
1199
- force?: boolean;
1200
- }): Promise<RecordsResult<ImportOpened>>;
1201
- /**
1202
- * IMPORT-2. ADD THE COLUMNS THIS FILE HAS AND THIS TABLE HAS NOT — a step of
1203
- * its own, BEFORE the run is opened, so the screen can show "8 columns added"
1204
- * and the person can then name one of them as the file's duplicate key
1205
- * (`importBegin` refuses a key naming a column that does not exist yet).
1206
- * Answers the mapping the file should be sent with. Admin on the Table.
1207
- */
1208
- importDeclareColumns(args: {
1209
- table_id: Uuid;
1210
- rows: Array<Record<string, unknown>>;
1211
- /** Header -> Field key the person already mapped by hand; never declared. */
1212
- mapping?: Record<string, string>;
1213
- }): Promise<RecordsResult<ImportColumnsDeclared>>;
1214
- /**
1215
- * One BATCH of rows. The batch is PLANNED and then written as ONE statement
1216
- * through the batched write door, so 250 round trips became one; a batch a
1217
- * guard refuses falls back to one write a row, and the answer says which it
1218
- * was. Send `ImportOpened.rows_per_call` the first time and
1219
- * `ImportBatchResult.rows_per_call` — measured — every time after that.
1220
- */
1221
- importRows(args: {
1222
- import_id: Uuid;
1223
- rows: Array<Record<string, unknown>>;
1224
- /** Header -> Field key. A header that already spells a key needs no entry. */
1225
- mapping?: Record<string, string>;
1226
- }): Promise<RecordsResult<ImportBatchResult>>;
1227
- /**
1228
- * Close the run and decide the columns the file had and the table did not:
1229
- * `propose` (the ONE approvals inbox, and the only choice a non-admin has),
1230
- * `create` (an admin adds them outright) or `ignore`.
1231
- */
1232
- importFinish(args: {
1233
- import_id: Uuid;
1234
- unmapped?: "propose" | "create" | "ignore";
1235
- }): Promise<RecordsResult<ImportFinished>>;
1236
- /** The refused rows, or the ones already here, WITH the source row on each. */
1237
- importReport(args: {
1238
- import_id: Uuid;
1239
- state?: "refused" | "duplicate";
1240
- limit?: number;
1241
- offset?: number;
1242
- }): Promise<RecordsResult<ImportReport>>;
1243
- /** This organization's import runs, newest first. How you find yesterday's. */
1244
- imports(args?: {
1245
- table_id?: Uuid | null;
1246
- limit?: number;
1247
- }): Promise<RecordsResult<ImportRun[]>>;
1248
- /**
1249
- * Forget the RECEIPT for a file so the same bytes can be imported again
1250
- * deliberately. Never touches the records that import wrote.
1251
- */
1252
- importForget(args: {
1253
- import_id: Uuid;
1254
- }): Promise<RecordsResult<boolean>>;
1255
- /**
1256
- * Give a table its own address. The answer carries `mail_route`: the one
1257
- * sentence saying what has to exist in DNS before anything arrives. Show it
1258
- * wherever the address is shown — an address that silently swallows mail is
1259
- * the failure this whole door is against.
1260
- */
1261
- inboundDeclare(args: {
1262
- table_id: Uuid;
1263
- label?: string | null;
1264
- }): Promise<RecordsResult<InboundDeclared>>;
1265
- inboundAddresses(args?: {
1266
- table_id?: Uuid | null;
1267
- }): Promise<RecordsResult<InboundAddress[]>>;
1268
- inboundSet(args: {
1269
- inbound_id: Uuid;
1270
- enabled: boolean;
1271
- }): Promise<RecordsResult<{
1272
- inbound_id: Uuid;
1273
- address: string;
1274
- enabled: boolean;
1275
- message: string;
1276
- }>>;
1277
- /** Every portal over this organization the caller may know about, with its numbers. */
1278
- portals(): Promise<RecordsResult<PortalSummary[]>>;
1279
- /**
1280
- * The SAME list, archive-aware. `custom.portals` keeps its signature and hides
1281
- * archived portals, because the archived-items law's default is to hide;
1282
- * this is the one door that also answers the other lane, so a rail gets the
1283
- * law's one-click reveal without inventing a second control or a second door.
1284
- * A fourth word is refused `22023` — there is no fourth answer on any surface.
1285
- */
1286
- listPortals(args?: {
1287
- archived?: PortalArchiveFilter;
1288
- }): Promise<RecordsResult<PortalSummary[]>>;
1289
- /**
1290
- * PUT ONE PORTAL AWAY. Nothing is deleted and there is no purge: every Table
1291
- * it exposes and every person invited to it is kept exactly as it is, and
1292
- * `portalRestore` hands it all back. `confirm_title` is the portal's own title
1293
- * typed back — ten portals can carry one title, so the title is not what picks
1294
- * this one and the door refuses `23514` when it does not match.
1295
- */
1296
- portalArchive(args: {
1297
- portal_id: Uuid;
1298
- confirm_title: string;
1299
- reason?: string | null;
1300
- }): Promise<RecordsResult<PortalArchiveAnswer>>;
1301
- /** The way back. Everyone invited signs in exactly as before, and it shows the same Tables. */
1302
- portalRestore(args: {
1303
- portal_id: Uuid;
1304
- confirm_title: string;
1305
- }): Promise<RecordsResult<PortalArchiveAnswer>>;
1306
- /**
1307
- * PUT ONE FORM OR BOOKING PAGE AWAY (`custom.form_archive`, admin on its table). Its address stops
1308
- * answering; everything it collected is kept. `formRestore` brings it back.
1309
- */
1310
- formArchive(args: {
1311
- form_id: Uuid;
1312
- }): Promise<RecordsResult<FormArchiveAnswer>>;
1313
- formRestore(args: {
1314
- form_id: Uuid;
1315
- }): Promise<RecordsResult<FormArchiveAnswer>>;
1316
- /** The archived forms and booking pages, newest first; `table_id` narrows to one table. */
1317
- formsArchived(args?: {
1318
- table_id?: Uuid | null;
1319
- limit?: number;
1320
- }): Promise<RecordsResult<ArchivedForm[]>>;
1321
- /**
1322
- * The archived checklist templates. A template is a record: `recordDelete` archives it and
1323
- * `recordRestore` brings it back.
1324
- */
1325
- checklistTemplatesArchived(args?: {
1326
- about_table_id?: Uuid | null;
1327
- limit?: number;
1328
- }): Promise<RecordsResult<ArchivedChecklistTemplate[]>>;
1329
- /** What a table's NEW rows start with (Shown to, and the web half once it lands). */
1330
- tableRowDefaults(args: {
1331
- table_id: Uuid;
1332
- }): Promise<RecordsResult<TableRowDefaults>>;
1333
- /** Set them (the table's maker or an admin of it). A key left out is left alone; null = the default. */
1334
- tableRowDefaultsSet(args: {
1335
- table_id: Uuid;
1336
- defaults: TableRowDefaultsPatch;
1337
- }): Promise<RecordsResult<TableRowDefaults>>;
1338
- /**
1339
- * ONE PASS of "apply to existing rows": rows nobody set by hand follow the table's defaults.
1340
- * `done: false` → call again with `after: next_after`. `rowDefaultsApplyAll` walks every pass.
1341
- */
1342
- tableRowDefaultsApply(args: {
1343
- table_id: Uuid;
1344
- after?: Uuid | null;
1345
- }): Promise<RecordsResult<RowDefaultsApplied>>;
1346
- /** Every pass of `tableRowDefaultsApply`, summed; the last pass's sentence when it took one pass. */
1347
- rowDefaultsApplyAll(args: {
1348
- table_id: Uuid;
1349
- maxPasses?: number;
1350
- }): Promise<RecordsResult<RowDefaultsApplied>>;
1351
- /** One row's Shown to (and web half), with who may change it. */
1352
- recordRowControls(args: {
1353
- record_id: Uuid;
1354
- }): Promise<RecordsResult<RecordRowControls>>;
1355
- recordRowControlsSet(args: {
1356
- record_id: Uuid;
1357
- controls: {
1358
- shown_to?: string | null;
1359
- published_to_web?: boolean;
1360
- indexed?: boolean | null;
1361
- };
1362
- }): Promise<RecordsResult<RecordRowControls>>;
1363
- /**
1364
- * Which Tables each portal of this organization exposes.
1365
- *
1366
- * The one question a TABLE-scoped Portals rail has to ask: "is the table I
1367
- * am standing on in any portal?" Same wall and same read-access gate as
1368
- * `portals`, so a pair here is always a portal `portals` also returned.
1369
- */
1370
- portalTables(): Promise<RecordsResult<PortalTableRef[]>>;
1371
- /** ONE portal in full: what it shows, and who it was opened to. */
1372
- portalCard(args: {
1373
- portal_id: Uuid;
1374
- }): Promise<RecordsResult<PortalCard>>;
1375
- /**
1376
- * Create or RE-STATE one portal. Re-stating REPLACES what it exposes — a
1377
- * Table left out of `tables` stops being exposed in the same act — and leaves
1378
- * the people alone: who is invited is not part of what the portal shows.
1379
- */
1380
- portalDeclare(args: {
1381
- title: string;
1382
- client_table_id: Uuid;
1383
- tables: Array<{
1384
- table_id: Uuid;
1385
- names_via: string;
1386
- visible_fields?: string[];
1387
- editable_fields?: string[];
1388
- comments?: boolean;
1389
- }>;
1390
- portal_id?: Uuid | null;
1391
- slug?: string | null;
1392
- sign_in_method?: string | null;
1393
- /**
1394
- * S6 — the portal's own look and its forms. A key given REPLACES that key; a key not given
1395
- * is KEPT (leave `config` out and both stay exactly as they are). The store judges it and
1396
- * refuses by name: a logo that is not a public picture of this organization's Files, an
1397
- * accent that is not a design-system colour name, a form whose Table the portal does not show.
1398
- */
1399
- config?: PortalConfigInput | null;
1400
- }): Promise<RecordsResult<Uuid>>;
1401
- /**
1402
- * S6 — THE CLIENT'S SIDE: one form of HER portal (`custom.portal_form`). Refused unless the
1403
- * caller is a live principal of that live portal and the form is on its list; the Field that
1404
- * names the client is never one of the questions — the portal fills it.
1405
- */
1406
- portalForm(args: {
1407
- portal_id: Uuid;
1408
- form_id: Uuid;
1409
- }): Promise<RecordsResult<PortalFormSpec>>;
1410
- /**
1411
- * S6 — send one form of her portal (`custom.portal_form_submit`). The store fills the Field
1412
- * that names the client with her own record, and the answer reaches her own list at once
1413
- * (`accepted`) or waits for the office (`held`, with the store's sentence). `client_key`
1414
- * makes a retry the same submission.
1415
- */
1416
- portalFormSubmit(args: {
1417
- portal_id: Uuid;
1418
- form_id: Uuid;
1419
- answers: Record<string, unknown>;
1420
- client_key?: string | null;
1421
- }): Promise<RecordsResult<PortalFormAnswer>>;
1422
- /**
1423
- * Invite one person, as one record of the portal's client Table.
1424
- *
1425
- * `user_id` is deliberately NOT a parameter here. From a screen it is always
1426
- * null: an invitation confers NOTHING until the person follows their sign-in
1427
- * link and the platform gives them an identity, and the door's own `say`
1428
- * sentence states exactly that. A screen that passed an id would be granting
1429
- * access on somebody else's behalf.
1430
- */
1431
- portalInvite(args: {
1432
- portal_id: Uuid;
1433
- client_record_id: Uuid;
1434
- email: string;
1435
- }): Promise<RecordsResult<PortalInvitation>>;
1436
- /** Take one person's way in away. The answer's `say` names the consequence. */
1437
- portalRevoke(args: {
1438
- portal_id: Uuid;
1439
- principal_id: Uuid;
1440
- }): Promise<RecordsResult<PortalRevocation>>;
1441
- /**
1442
- * VIEW AS THIS CLIENT. The door asks `custom.visible_set` for HER user id —
1443
- * the same call `custom.read_records` makes when she opens the page — so this
1444
- * cannot disagree with what she sees. It REFUSES with `02000` and a sentence
1445
- * when she has not signed in yet; show the sentence, never an empty list.
1446
- */
1447
- portalPreview(args: {
1448
- portal_id: Uuid;
1449
- principal_id: Uuid;
1450
- table_id: Uuid;
1451
- }): Promise<RecordsResult<PortalPreviewRow[]>>;
1452
- /** This organization's dashboards, optionally only those whose subject is one Table. */
1453
- dashboards(args?: {
1454
- table_id?: Uuid | null;
1455
- }): Promise<RecordsResult<DashboardSummary[]>>;
1456
- /**
1457
- * Create or re-state one dashboard. Every block is judged on the way IN —
1458
- * a block naming a field this Table does not have is refused BY NAME, with
1459
- * the table's own field list in the hint — so a canvas cannot be saved broken.
1460
- */
1461
- dashboardDeclare(args: {
1462
- table_id: Uuid;
1463
- name: string;
1464
- blocks?: DashboardBlock[];
1465
- presentation?: Record<string, unknown> | null;
1466
- dashboard_id?: Uuid | null;
1467
- }): Promise<RecordsResult<Uuid>>;
1468
- /**
1469
- * Run every block and answer the numbers. `filter` is the ONE filter bar
1470
- * across the canvas: it is merged UNDER each block's own filter, so a block
1471
- * deliberately scoped to one stage stays scoped while the bar moves the rest.
1472
- * A block that refuses carries the store's sentence and the others still answer.
1473
- */
1474
- dashboardRun(args: {
1475
- dashboard_id: Uuid;
1476
- filter?: RecordFilter;
1477
- /**
1478
- * S3 — compare every block that does not carry its own comparison (the
1479
- * block's own wins, as its own filter does). A block with no date to
1480
- * compare along answers alone and says so in `compare_refused`.
1481
- */
1482
- compare?: AggregateCompare | null;
1483
- /** S3 — re-cut every bucketed block to one date grain (the canvas's picker). */
1484
- grain?: AggregateBucket | null;
1485
- }): Promise<RecordsResult<DashboardRunResult>>;
1486
- /** The seventh block kind on its own: records that have sat on the same value too long. */
1487
- dashboardStuck(args: {
1488
- table_id: Uuid;
1489
- state_key: string;
1490
- days?: number;
1491
- filter?: RecordFilter;
1492
- limit?: number;
1493
- }): Promise<RecordsResult<StuckRow[]>>;
1494
- /**
1495
- * Declare or re-state a crew capture sheet over a Table. Admin on the Table.
1496
- * Closed to the crew until `capturePublish`, like every publishing act here.
1497
- */
1498
- captureSheetDeclare(args: {
1499
- table_id: Uuid;
1500
- title: string;
1501
- questions: Array<Record<string, unknown>>;
1502
- presentation?: Record<string, unknown> | null;
1503
- sheet_id?: Uuid | null;
1504
- notify_rule_id?: Uuid | null;
1505
- }): Promise<RecordsResult<Uuid>>;
1506
- /** Open the sheet to the crew, or close it. Admin on the Table. */
1507
- capturePublish(args: {
1508
- sheet_id: Uuid;
1509
- open?: boolean;
1510
- }): Promise<RecordsResult<string | null>>;
1511
- /** The crew sheets of this organization, with what has come in through each. */
1512
- captureSheets(args?: {
1513
- table_id?: Uuid | null;
1514
- }): Promise<RecordsResult<CaptureSheetSummary[]>>;
1515
- /**
1516
- * Everything a phone needs to run one sheet OFFLINE — the questions, the Fields
1517
- * with their ids and parity types, and an honest `may_capture` with a sentence.
1518
- * Load it once on a signal; it is the last network call before the walk.
1519
- */
1520
- captureOpen(args: {
1521
- sheet_id: Uuid;
1522
- }): Promise<RecordsResult<CaptureSheetFace | null>>;
1523
- /**
1524
- * One capture: the answers, the file references, the device, the moment the phone
1525
- * took it and the place. Idempotent on `client_key`, which the PHONE mints when
1526
- * the capture is taken, offline, before its first attempt — send the same key on
1527
- * every retry and the answer comes back `replay: true` with the first record's id.
1528
- */
1529
- captureSubmit(args: {
1530
- sheet_id: Uuid;
1531
- client_key: string;
1532
- answers: Record<string, unknown>;
1533
- files?: CaptureFileRef[];
1534
- device?: string | null;
1535
- captured_at?: string | null;
1536
- location?: Record<string, unknown> | null;
1537
- }): Promise<RecordsResult<CaptureOutcome | null>>;
1538
- /** Every agent-owned column, with how many cells are filled, stale or pinned, and what it has cost. */
1539
- enrichments(args?: {
1540
- table_id?: Uuid | null;
1541
- }): Promise<RecordsResult<EnrichmentSummary[]>>;
1542
- /**
1543
- * Define, change or TURN ON an Enrichment on one Field. Admin on the Table.
1544
- * `{enabled: true}` on its own turns an existing one on without resetting it —
1545
- * and turning it on is what authorises every value it writes afterwards.
1546
- */
1547
- enrichDeclare(args: {
1548
- field_id: Uuid;
1549
- spec: Record<string, unknown>;
1550
- }): Promise<RecordsResult<EnrichDeclared>>;
1551
- /**
1552
- * The rows that need this column filled in, each with what the instruction may
1553
- * read. A cell somebody pinned is never returned. This is what a PREVIEW shows
1554
- * before anybody enables anything.
1555
- */
1556
- enrichDue(args: {
1557
- field_id: Uuid;
1558
- limit?: number;
1559
- include_fresh?: boolean;
1560
- }): Promise<RecordsResult<EnrichDueRow[]>>;
1561
- /**
1562
- * THE BADGE DATA FOR A WHOLE PAGE, in one call. Who wrote each value, when, out
1563
- * of what source, its candidates, whether a person pinned it and whether it is
1564
- * past its freshness date. Asked per cell this would be one round trip per badge.
1565
- */
1566
- enrichCells(args: {
1567
- table_id: Uuid;
1568
- field_keys?: string[] | null;
1569
- record_ids?: Uuid[] | null;
1570
- }): Promise<RecordsResult<EnrichCell[]>>;
1571
- /** Hold one cell against the model that fills its column, or hand it back. */
1572
- enrichPin(args: {
1573
- record_id: Uuid;
1574
- field_key: string;
1575
- pinned?: boolean;
1576
- }): Promise<RecordsResult<{
1577
- pinned: boolean;
1578
- says: string;
1579
- }>>;
1580
- /** What this column has cost, run by run. */
1581
- enrichRuns(args?: {
1582
- field_id?: Uuid | null;
1583
- limit?: number;
1584
- }): Promise<RecordsResult<EnrichRun[]>>;
1585
- /** Take a dashboard away. The records it counted are untouched — a canvas owns nothing. */
1586
- dashboardDelete(args: {
1587
- dashboard_id: Uuid;
1588
- }): Promise<RecordsResult<boolean>>;
1589
- /**
1590
- * Group, bucket, filter and measure INSIDE `custom.record_aggregate`. The
1591
- * aggregate node sits above the read-access join, so what a chart draws is
1592
- * exactly what this person may see — the rest is never fetched, let alone
1593
- * summed and then hidden.
1594
- */
1595
- recordAggregate(args: {
1596
- table_id: Uuid;
1597
- /**
1598
- * OPTIONAL FILTER (active-org law): with `config.organizationIds` set, the table is looked
1599
- * up across all the person's organizations and the aggregate runs in the one that OWNS it
1600
- * (each row then carries that `organization_id`); this narrows the lookup to one. Absent and
1601
- * no `organizationIds` ⇒ this client's own organization, exactly as before.
1602
- */
1603
- organization_id?: Uuid | null;
1604
- /** Field keys whose values become the groups. */
1605
- groupBy?: string[];
1606
- /** `count` needs no key; every other operation reads one Field. */
1607
- measures?: AggregateMeasure[];
1608
- /** A date Field truncated to a period — a group whose expression is a date_trunc. */
1609
- bucket?: {
1610
- key: string;
1611
- by: AggregateBucket;
1612
- } | null;
1613
- /**
1614
- * A scalar is an equality and an object is a half-open moment window, and
1615
- * either way it lands in the SAME WHERE as read access.
1616
- */
1617
- filter?: StoreFilter;
1618
- limit?: number;
1619
- /**
1620
- * S3 — answer the same question over a prior window too (previous period,
1621
- * same period last year, or a fixed baseline). Each row then carries
1622
- * `prior_measures`, `delta` and the two `compare` windows. Buckets are cut
1623
- * in the organization's calendar (knobs `custom/time_zone`, `custom/week_start`).
1624
- */
1625
- compare?: AggregateCompare | null;
1626
- /**
1627
- * The grid's search, narrowing the answer to the rows `listPage`'s search would show (the
1628
- * same predicate, `custom.record_search_sql`). Blank or absent: nothing changes.
1629
- */
1630
- search?: string | null;
1631
- /** The reader's time zone for the search's date matches (absent = the organization's calendar). */
1632
- time_zone?: string | null;
1633
- }): Promise<RecordsResult<AggregateRow[]>>;
1634
- /** Historical aggregate computed by the store at its recorded-time read door. */
1635
- recordAggregateAsOf(args: {
1636
- table_id: Uuid;
1637
- recorded_at: string;
1638
- measure?: string;
1639
- field_key?: string | null;
1640
- group_by?: string | null;
1641
- match?: Record<string, unknown>;
1642
- }): Promise<RecordsResult<Array<{
1643
- bucket: string | null;
1644
- result: number | null;
1645
- row_count: number;
1646
- not_numbers: number;
1647
- a_non_number: string | null;
1648
- }>>>;
1649
- /** The measures the store itself offers. Asked, never hardcoded in a picker. */
1650
- aggOperations(): Promise<RecordsResult<string[]>>;
1651
- /** The periods the store itself buckets by. */
1652
- aggBuckets(): Promise<RecordsResult<string[]>>;
1653
- /**
1654
- * The organization's calendar (knobs `custom/time_zone`, `custom/week_start`), cut by the SAME door the
1655
- * relative date filters and the chart buckets use. A calendar or timeline reads its first day of the week
1656
- * from here, never from a constant of its own (lane NOTION-SMALL-4).
1657
- */
1658
- aggCalendar(): Promise<RecordsResult<{
1659
- time_zone: string;
1660
- week_start: string;
1661
- }>>;
1662
- /**
1663
- * A source's drill definition — its Dimensions, Measures, drill paths and first screen.
1664
- * `{kind: "table", id}` is a custom Table; `{kind: "entity", token}` a standard table by its
1665
- * registry token or a declared definition by its key.
1666
- */
1667
- drillDescribe(args: {
1668
- source: DrillSource;
1669
- }): Promise<RecordsResult<DrillDefinition>>;
1670
- /**
1671
- * Ask a source a question: grouped, bucketed (day…year in the organization's calendar),
1672
- * compared, pivoted. A standard table is counted AS THE PERSON (its own row security decides
1673
- * every row); groups past the cap fold into one Other row and the total row says so.
1674
- */
1675
- drillAsk(args: {
1676
- source: DrillSource;
1677
- question?: DrillQuestion;
1678
- }): Promise<RecordsResult<DrillAnswer>>;
1679
- /** The records behind a number, through the same filter, read as the person. */
1680
- drillRows(args: {
1681
- source: DrillSource;
1682
- where?: DrillQuestion["where"];
1683
- window?: DrillQuestion["window"];
1684
- sort?: DrillQuestion["sort"];
1685
- lane?: DrillQuestion["lane"];
1686
- columns?: string[];
1687
- limit?: number;
1688
- offset?: number;
1689
- /** The viewer's search term, asked of the door (`platform._drill_compile` reads `question.search`). */
1690
- search?: string;
1691
- }): Promise<RecordsResult<DrillRowsPage>>;
1692
- /**
1693
- * Every subscription in this organization, optionally narrowed to one saved
1694
- * view or one cadence. There is no subscription table: each one is a Rule
1695
- * record carrying a `subscription` block, so a subscription is readable,
1696
- * historied and agent-writable like anything else.
1697
- */
1698
- aggSubscriptions(args?: {
1699
- saved_view_id?: Uuid | null;
1700
- cadence?: string | null;
1701
- }): Promise<RecordsResult<Subscription[]>>;
1702
- /** The cadences the store itself offers. Asked, never hardcoded in a picker. */
1703
- aggSubscriptionCadences(): Promise<RecordsResult<string[]>>;
1704
- /**
1705
- * The same cadences, through the door a PERSON may call.
1706
- * `aggSubscriptionCadences` is the notifier's own and holds no client grant,
1707
- * so a screen that asked for it was refused and fell back to a list typed
1708
- * into the picker — which drifts from what the digest runner honours. This
1709
- * one delegates to the same array, so there is exactly one list.
1710
- */
1711
- subscriptionCadences(): Promise<RecordsResult<string[]>>;
1712
- /**
1713
- * WHAT THIS PERSON IS BEING TOLD ABOUT, and what they may switch off.
1714
- *
1715
- * Mine, plus anyone's over a Table I hold admin on — narrowed to Tables I can
1716
- * already open, so the list never reveals one. `aggSubscriptions` above is the
1717
- * NOTIFIER's reader and no client can call it; this is the owner's.
1718
- */
1719
- subscriptions(args?: {
1720
- table_id?: Uuid | null;
1721
- }): Promise<RecordsResult<MySubscription[]>>;
1722
- /**
1723
- * Switch one on or off. Muting is honoured in ONE place — the reader every
1724
- * consumer goes through — so a screen can never say a subscription is off
1725
- * while it keeps firing.
1726
- */
1727
- subscriptionMute(args: {
1728
- rule_id: Uuid;
1729
- muted: boolean;
1730
- }): Promise<RecordsResult<boolean>>;
1731
- /**
1732
- * WRITE ONE. The store refuses a cadence no runner acts on, a channel this
1733
- * platform does not send on and quiet hours nobody can parse — by name — then
1734
- * declares the Rule through `rule_declare`, because a Rule written as a record
1735
- * carries `data_class = 'record'` and every reader that goes looking for a Rule
1736
- * steps straight past it (REC-72).
1737
- */
1738
- subscriptionDeclare(args: {
1739
- table_id: Uuid;
1740
- spec: SubscriptionSpec;
1741
- }): Promise<RecordsResult<Uuid>>;
1742
- /**
1743
- * SHOW ME ONE NOW. The summary this subscription would send at this moment, with
1744
- * what entered, left and changed NAMED. It assembles only: nothing is delivered,
1745
- * nothing is recorded and the watermark does not move.
1746
- */
1747
- subscriptionPreview(args: {
1748
- rule_id: Uuid;
1749
- }): Promise<RecordsResult<DigestPreview>>;
1750
- /**
1751
- * THE SAVED VIEWS OF A TABLE — what a subscription may be written over. Narrowed
1752
- * in SQL as the definer to Tables this caller can already open, so the list can
1753
- * never reveal a Table.
1754
- */
1755
- views(args?: {
1756
- table_id?: Uuid | null;
1757
- }): Promise<RecordsResult<SavedViewRow[]>>;
1758
- /**
1759
- * SAVE ONE VIEW. VIEWER on the Table, not editor: writing down a question about a
1760
- * Table is not changing it, and requiring editor would mean the people who read a
1761
- * Table could not subscribe to anything in it.
1762
- */
1763
- viewDeclare(args: {
1764
- table_id: Uuid;
1765
- spec: SavedViewSpecIn;
1766
- }): Promise<RecordsResult<Uuid>>;
1767
- /** A Table's row templates ("New from template"). VIEWER on the Table. */
1768
- rowTemplates(args: {
1769
- table_id: Uuid;
1770
- }): Promise<RecordsResult<RowTemplateRow[]>>;
1771
- /**
1772
- * SAVE ONE ROW TEMPLATE — `{name, values}` by Field key; the same name again changes it, and
1773
- * `{template_id, archived: true}` archives it. EDITOR on the Table: it is how everyone's new rows start.
1774
- */
1775
- rowTemplateDeclare(args: {
1776
- table_id: Uuid;
1777
- spec: {
1778
- name?: string;
1779
- values?: Record<string, unknown>;
1780
- template_id?: Uuid;
1781
- archived?: boolean;
1782
- };
1783
- }): Promise<RecordsResult<Uuid>>;
1784
- /**
1785
- * DESIGNATE HOW A TABLE OPENS — "Make this the default". EDITOR on the Table: the named view
1786
- * becomes the table's only default and, when `layout` is given, that is the layout everyone opens
1787
- * it in. A layout press never designates (`viewDeclare` refuses the default view's layout and
1788
- * is_default by name — VIEW-SWITCH-NOT-DESIGNATION, VERIFIER-21).
1789
- */
1790
- viewDesignate(args: {
1791
- table_id: Uuid;
1792
- view_id: Uuid;
1793
- layout?: string | null;
1794
- }): Promise<RecordsResult<Uuid>>;
1795
- /**
1796
- * ARCHIVE ONE SAVED VIEW (lane TABLE-ACTIONS, T3.5). The soft delete of the `platform.saved_view`
1797
- * row behind it — `public.saved_view_archive('custom/records', id)`, which asks its own ladder
1798
- * (the view's creator, or admin on the view) and clears a default it held. The records are
1799
- * untouched. `null` when the view was already gone. `viewRestore` (or Trash) brings it back.
1800
- */
1801
- viewArchive(args: {
1802
- view_id: Uuid;
1803
- }): Promise<RecordsResult<Record<string, unknown> | null>>;
1804
- /** PUT AN ARCHIVED VIEW BACK — the platform's one restore door, `public.entity_undelete('platform_saved_view', id)`. */
1805
- viewRestore(args: {
1806
- view_id: Uuid;
1807
- }): Promise<RecordsResult<boolean>>;
1808
- /**
1809
- * THE CALLER'S OWN LOOK AT EACH SAVED VIEW OF A TABLE — `{ "<view id>": { look, updated_at } }`.
1810
- * A look is the view settings one person chose while looking (a board's grouping, a calendar's
1811
- * date field, a sort, a filter, hidden columns, widths, the layout), kept for her alone until an
1812
- * editor saves it onto the view with `viewDeclare` ("Save to view"). Viewer on the Table.
1813
- */
1814
- viewLookRead(args: {
1815
- table_id: Uuid;
1816
- }): Promise<RecordsResult<Record<string, {
1817
- look: Record<string, unknown>;
1818
- updated_at: string;
1819
- }>>>;
1820
- /**
1821
- * KEEP THE CALLER'S OWN LOOK AT ONE VIEW — the whole look, as definition keys (`group_field`,
1822
- * `date_field`, `sorts`, `where`, `presentation`, `layout`, …; a key set to null hides the view's
1823
- * own). `look: null` is "Reset to view". The shared view row is never written. Answers the look
1824
- * as kept (null after a reset).
1825
- */
1826
- viewLookSet(args: {
1827
- table_id: Uuid;
1828
- view_id: Uuid;
1829
- look: Record<string, unknown> | null;
1830
- }): Promise<RecordsResult<Record<string, unknown> | null>>;
1831
- docTemplateSave(args: {
1832
- table_id: Uuid;
1833
- name: string;
1834
- body: string;
1835
- template_id?: Uuid | null;
1836
- }): Promise<RecordsResult<Uuid>>;
1837
- /** The body with every token resolved against one record. Read-only, no render row. */
1838
- docRenderBody(args: {
1839
- template_id: Uuid;
1840
- record_id: Uuid;
1841
- }): Promise<RecordsResult<string>>;
1842
- /** Write the render — frozen bytes a signature can be checked against. */
1843
- docRenderDocument(args: {
1844
- template_id: Uuid;
1845
- record_id: Uuid;
1846
- }): Promise<RecordsResult<Uuid>>;
1847
- /** Every token in a body, in order, with the Field id each one points at. */
1848
- docTokens(args: {
1849
- body: string;
1850
- }): Promise<RecordsResult<DocToken[]>>;
1851
- /** The tokens this Table cannot answer, each with the store's own reason. */
1852
- docUnresolvedTokens(args: {
1853
- table_id: Uuid;
1854
- body: string;
1855
- }): Promise<RecordsResult<DocUnresolvedToken[]>>;
1856
- docSign(args: {
1857
- render_id: Uuid;
1858
- field_key: string;
1859
- signer_name: string;
1860
- signer_user_id?: Uuid | null;
1861
- }): Promise<RecordsResult<Uuid>>;
1862
- /**
1863
- * One signature: the seal AND whether what was signed is still what is there.
1864
- * The store answers both, in one call, never the screen. Viewer on the record.
1865
- */
1866
- docSignatureRead(args: {
1867
- signature_id: Uuid;
1868
- }): Promise<RecordsResult<unknown>>;
1869
- /** Every template that renders one Table. Viewer on the Table. */
1870
- docTemplates(args: {
1871
- table_id: Uuid;
1872
- }): Promise<RecordsResult<DocTemplateRow[]>>;
1873
- /**
1874
- * Retire one template. EDITOR on the Table it renders, because a template is
1875
- * that Table's wording. Documents already rendered keep their frozen bytes
1876
- * and their seals, so this can never invalidate a signature.
1877
- */
1878
- docTemplateDelete(args: {
1879
- template_id: Uuid;
1880
- }): Promise<RecordsResult<boolean>>;
1881
- /** Every frozen render of one record, newest first. Viewer on the record. */
1882
- docRenders(args: {
1883
- record_id: Uuid;
1884
- }): Promise<RecordsResult<DocRenderRow[]>>;
1885
- /** Every signature on one record. Viewer on the record. */
1886
- docSignatures(args: {
1887
- record_id: Uuid;
1888
- }): Promise<RecordsResult<DocSignatureRow[]>>;
1889
- /**
1890
- * DOOR-11. One record's revisions, newest first. The read door answers
1891
- * documents and deliberately not versions, so a screen that wants to save
1892
- * optimistically reads the version of the record it LOADED from here — for
1893
- * the one record being edited, never for a list.
1894
- */
1895
- revisions(args: {
1896
- record_id: Uuid;
1897
- }): Promise<RecordsResult<RecordRevision[]>>;
1898
- /**
1899
- * PRODUCTS row 4. One record's version list, newest first: who (a person, or
1900
- * an agent AND the person it acted for), when, the operation in the word
1901
- * somebody used, and every field that moved with its before, its after, the
1902
- * Rule version that produced a derived value and its source pointer. Viewer
1903
- * on the record — reading how something got to be the way it is is reading.
1904
- */
1905
- recordHistory(args: {
1906
- record_id: Uuid;
1907
- limit?: number;
1908
- offset?: number;
1909
- }): Promise<RecordsResult<RecordHistoryEntry[]>>;
1910
- /**
1911
- * AGT-N-9 — EVERYTHING A CHAT OPENED ON THIS RECORD MAY KNOW, IN ONE ROUND TRIP.
1912
- *
1913
- * The Fields with their `(record, field, value version)` triples, the relations one hop
1914
- * out, the history, the comments and the Table's other records — assembled INSIDE the
1915
- * database, every piece through the read door, under this person's own field-level
1916
- * security. A Field the store masks comes back in `withheld` with the store's own
1917
- * sentence and no value; a Field the organization keeps out of conversations comes back
1918
- * there too, saying which of the two it is.
1919
- */
1920
- recordScopeContext(args: {
1921
- record_id: Uuid;
1922
- relations?: number;
1923
- history?: number;
1924
- siblings?: number;
1925
- }): Promise<RecordsResult<RecordScopeContext>>;
1926
- /** What is this conversation about? */
1927
- conversationScope(args: {
1928
- conversation_id: Uuid;
1929
- }): Promise<RecordsResult<ConversationScope>>;
1930
- /** Point a conversation at one record. Refused unless this person may open it. */
1931
- conversationScopeBind(args: {
1932
- conversation_id: Uuid;
1933
- record_id: Uuid;
1934
- }): Promise<RecordsResult<ConversationScope>>;
1935
- /** This conversation is no longer about a particular record. */
1936
- conversationScopeUnbind(args: {
1937
- conversation_id: Uuid;
1938
- }): Promise<RecordsResult<ConversationScope>>;
1939
- /** The binding AND the context of a bound conversation, in one round trip. */
1940
- conversationScopeContext(args: {
1941
- conversation_id: Uuid;
1942
- relations?: number;
1943
- history?: number;
1944
- siblings?: number;
1945
- }): Promise<RecordsResult<ConversationScopeContext>>;
1946
- /**
1947
- * "Who changed the price on ANY record?" One column's history across a whole
1948
- * Table, narrowed to the records this person may see by a predicate in the
1949
- * same statement. A column that names no Field is refused BY NAME, never
1950
- * answered empty.
1951
- */
1952
- fieldHistory(args: {
1953
- table_id: Uuid;
1954
- field_key: string;
1955
- limit?: number;
1956
- offset?: number;
1957
- record_id?: Uuid;
1958
- }): Promise<RecordsResult<FieldHistoryEntry[]>>;
1959
- /**
1960
- * WHAT A RESTORE WOULD CHANGE, BEFORE IT DOES. Editor on the record: this is
1961
- * the first half of an act, and somebody who may not perform it is not shown
1962
- * its preview. Pass `field_key` for one column.
1963
- */
1964
- restorePreview(args: {
1965
- record_id: Uuid;
1966
- version: number;
1967
- field_key?: string;
1968
- }): Promise<RecordsResult<RestorePreview>>;
1969
- /** Put the whole record back to a version, as a NEW version. Editor. */
1970
- restoreVersion(args: {
1971
- record_id: Uuid;
1972
- version: number;
1973
- }): Promise<RecordsResult<RestoreResult>>;
1974
- /** Put ONE column back to what it said at a version, as a NEW version (HIS-N-2). Editor. */
1975
- valueRestore(args: {
1976
- record_id: Uuid;
1977
- field_key: string;
1978
- version: number;
1979
- }): Promise<RecordsResult<RestoreResult>>;
1980
- /**
1981
- * SCR-18. The record's comment thread with everybody named, plus what THIS
1982
- * person may do in it — decided by the store, in the same call, so a screen
1983
- * never draws a composer the write door will refuse.
1984
- */
1985
- commentThread(args: {
1986
- record_id: Uuid;
1987
- include_resolved?: boolean;
1988
- }): Promise<RecordsResult<CommentThreadRead>>;
1989
- /**
1990
- * Write a comment at the `commenter` rung, optionally naming people. A
1991
- * mention is a reference and not a regex over the body: the ids come from the
1992
- * picker and the store refuses one who is not in the organization, or who
1993
- * cannot open the record — because that notification would be a dead end.
1994
- */
1995
- commentWrite(args: {
1996
- record_id: Uuid;
1997
- body: string;
1998
- field_key?: string;
1999
- parent_comment_id?: Uuid;
2000
- mentions?: Uuid[];
2001
- }): Promise<RecordsResult<CommentWritten>>;
2002
- /** Resolve (or re-open) a thread. `commenter` — resolution is not a delete. */
2003
- commentResolve(args: {
2004
- comment_id: Uuid;
2005
- resolved?: boolean;
2006
- }): Promise<RecordsResult<boolean>>;
2007
- /**
2008
- * Every value of one record WITH its envelope — its own version, who wrote
2009
- * it, who they were acting for and when. The timeline IS the record (REC-19);
2010
- * there is no second history table.
2011
- */
2012
- recordValuesVersioned(args: {
2013
- record_id: Uuid;
2014
- organization_id?: Uuid | null;
2015
- }): Promise<RecordsResult<ReadValue[]>>;
2016
- /**
2017
- * Metadata search across EVERY organization the person belongs to (`config.organizationIds`;
2018
- * `organization_id` narrows to one): the Tables and Fields whose name, key, label or description
2019
- * holds `text` (case-insensitive; structure, never rows). Each match is `{id, kind: "table" |
2020
- * "field", name, description, organization_id}` (a Field adds `key`, `table_id`, `field_type`).
2021
- * An organization whose read door refuses is listed in `unavailable` WITH its reason and
2022
- * never hides the rest. Only when NO organization answers is the whole search a failure (the
2023
- * first refusal).
2024
- */
2025
- metadataSearch(args: {
2026
- text: string;
2027
- organization_id?: Uuid | null;
2028
- }): Promise<RecordsResult<MetadataSearchAnswer>>;
2029
- /**
2030
- * WHICH of the person's organizations can this client use right now? Asks every organization
2031
- * in scope (`organization_id` narrows to one) whether its record store is open, so a host can
2032
- * say "organization X is unavailable: <reason>" instead of silently dropping it. Organization
2033
- * order is the person's own, never completion order.
2034
- */
2035
- organizationsOpen(args?: {
2036
- organization_id?: Uuid | null;
2037
- }): Promise<RecordsResult<OrganizationsOpenAnswer>>;
2038
- /**
2039
- * The organization that OWNS a table or record — the one a write to it must run in. A
2040
- * `table_id` is looked up across all the person's organizations; a `record_id` is opened in its
2041
- * own. `null` = found in none of them. Never a permission: the store's doors still decide.
2042
- */
2043
- ownerOrganization(args: {
2044
- table_id?: Uuid | null;
2045
- record_id?: Uuid | null;
2046
- organization_id?: Uuid | null;
2047
- }): Promise<RecordsResult<Uuid | null>>;
2048
- /**
2049
- * Mint an embed token. `mode` is `read` OR `write` and never both — the store
2050
- * refuses a token carrying two decisions. The secret comes back ONCE, because
2051
- * only its digest is stored: a database read cannot produce a working token.
2052
- * `allowedOrigins` is required and matched EXACTLY, so `example.com.evil.test`
2053
- * fails a check that a suffix match would pass.
2054
- */
2055
- anonTokenIssue(args: {
2056
- mode: "read" | "write";
2057
- allowedOrigins: string[];
2058
- formId?: Uuid | null;
2059
- savedViewId?: Uuid | null;
2060
- recordId?: Uuid | null;
2061
- expiresAt?: Timestamp | null;
2062
- }): Promise<RecordsResult<{
2063
- token_id: Uuid;
2064
- secret: string;
2065
- }>>;
2066
- /** What a secret is good for, from an origin. The store's sentence when it is not. */
2067
- anonTokenVerify(args: {
2068
- secret: string;
2069
- origin: string;
2070
- requiredMode?: "read" | "write" | null;
2071
- }): Promise<RecordsResult<AnonTokenBinding>>;
2072
- anonTokenRevoke(args: {
2073
- token_id: Uuid;
2074
- }): Promise<RecordsResult<boolean>>;
2075
- /**
2076
- * A STRANGER'S WRITE. The token supplies the organization, so this call names
2077
- * none — and what it produces is a QUARANTINED SUBMISSION, not a record:
2078
- * `custom.record` is never touched here. `clientKey` makes a replay free and
2079
- * idempotent, which is what lets a flaky phone retry safely.
2080
- */
2081
- anonWrite(args: {
2082
- secret: string;
2083
- origin: string;
2084
- payload: Record<string, unknown>;
2085
- clientKey?: string | null;
2086
- rawPayload?: Record<string, unknown>;
2087
- }): Promise<RecordsResult<Uuid>>;
2088
- /**
2089
- * SCR-30, and it is the SIGNED-IN offline path, not the stranger's. The client
2090
- * mints `clientKey` BEFORE the first attempt, offline, and the store's own
2091
- * replay ledger dedupes on it — so a reconnect that fires the same capture
2092
- * thirty times writes one record and returns the same id every time.
2093
- */
2094
- anonCapture(args: {
2095
- table_id: Uuid;
2096
- clientKey: string;
2097
- payload: Record<string, unknown>;
2098
- device?: string | null;
2099
- capturedAt?: Timestamp | null;
2100
- }): Promise<RecordsResult<Uuid>>;
2101
- /** Open or close a form to strangers. An admin act on the Table, never an editor one. */
2102
- anonPublish(args: {
2103
- form_id: Uuid;
2104
- published?: boolean;
2105
- }): Promise<RecordsResult<Timestamp | null>>;
2106
- /**
2107
- * What is wrong with a checklist somebody is writing, in the words they would
2108
- * use. `null` means it is fine. Pure — it reads no row and writes nothing —
2109
- * so an editor may ask it on every keystroke and the refusal arrives BEFORE
2110
- * the save rather than after it.
2111
- */
2112
- checklistRefusal(args: {
2113
- spec: ChecklistSpec;
2114
- }): Promise<RecordsResult<string | null>>;
2115
- /**
2116
- * Store a checklist, whole: ordered steps, who each belongs to by role, how
2117
- * many days in each is due, what each waits for, what each asks for, and what
2118
- * starts a run. Pass `template_id` to change the checklist that already
2119
- * exists rather than making a second one.
2120
- */
2121
- checklistDeclare(args: {
2122
- spec: ChecklistSpec;
2123
- template_id?: Uuid | null;
2124
- }): Promise<RecordsResult<ChecklistDeclared>>;
2125
- checklistTemplates(args?: {
2126
- about_table_id?: Uuid | null;
2127
- limit?: number;
2128
- }): Promise<RecordsResult<ChecklistTemplateSummary[]>>;
2129
- checklistTemplateShape(args: {
2130
- template_id: Uuid;
2131
- }): Promise<RecordsResult<ChecklistTemplateShape>>;
2132
- /**
2133
- * Run a checklist for one record: one work item per step in the ONE work
2134
- * layer, assigned by role to real people, dated from the offsets,
2135
- * dependencies carried across. `roles` names who stands in each role for THIS
2136
- * run, over whatever the checklist says by default.
2137
- */
2138
- checklistStart(args: {
2139
- template_id: Uuid;
2140
- about_record_id?: Uuid | null;
2141
- roles?: Record<string, Uuid>;
2142
- startingAt?: Timestamp | null;
2143
- }): Promise<RecordsResult<ChecklistRunStarted>>;
2144
- checklistRun(args: {
2145
- run_id: Uuid;
2146
- }): Promise<RecordsResult<ChecklistRunStep[]>>;
2147
- checklistRuns(args?: {
2148
- about_table_id?: Uuid | null;
2149
- about_record_id?: Uuid | null;
2150
- includeClosed?: boolean;
2151
- limit?: number;
2152
- }): Promise<RecordsResult<ChecklistRunSummary[]>>;
2153
- /**
2154
- * Tick a step off with whatever it asked for. Refused by name while a step it
2155
- * waits for is open, or while what it asks for is missing — and the same
2156
- * refusal meets `workSetState`, because the rule lives in the store and not
2157
- * in this door.
2158
- */
2159
- checklistStepComplete(args: {
2160
- step_id: Uuid;
2161
- evidence?: Record<string, unknown>;
2162
- }): Promise<RecordsResult<ChecklistStepCompleted>>;
2163
- /** Why this step cannot be finished right now. `null` means it can. */
2164
- checklistStepRefusal(args: {
2165
- step_id: Uuid;
2166
- }): Promise<RecordsResult<string | null>>;
2167
- /** The five states and what each one may become. Asked, never hardcoded in a picker. */
2168
- workStates(): Promise<RecordsResult<WorkState[]>>;
2169
- /** Why this graph would be refused — asked BEFORE it is written. `null` means it is fine. */
2170
- workTemplateRefusal(args: {
2171
- graph: WorkGraph;
2172
- }): Promise<RecordsResult<string | null>>;
2173
- workTemplateDeclare(args: {
2174
- name: string;
2175
- graph: WorkGraph;
2176
- }): Promise<RecordsResult<Uuid>>;
2177
- /**
2178
- * REC-70: the WHOLE graph is created in one act, judged before any of it is
2179
- * written, so a half-made checklist is not a state this store can be in.
2180
- */
2181
- workTemplateInstantiate(args: {
2182
- template_id: Uuid;
2183
- overrides?: Record<string, Record<string, unknown>>;
2184
- }): Promise<RecordsResult<WorkInstantiation>>;
2185
- workTemplateShape(args: {
2186
- template_id: Uuid;
2187
- }): Promise<RecordsResult<unknown>>;
2188
- workInstantiationShape(args: {
2189
- instantiation_id: Uuid;
2190
- }): Promise<RecordsResult<unknown>>;
2191
- /** Whose turn each record is, with its state and whether that state is terminal. */
2192
- workWhoseTurn(args: {
2193
- table_id: Uuid;
2194
- includeFinished?: boolean;
2195
- }): Promise<RecordsResult<WorkTurn[]>>;
2196
- /** Does this Table carry assignment at all? A screen asks before it offers one. */
2197
- workHasAssignment(args: {
2198
- table_id: Uuid;
2199
- }): Promise<RecordsResult<boolean>>;
2200
- /** The Fields assignment is made of, so nothing here invents a column name. */
2201
- workAssignmentFields(args?: {
2202
- options_table_id?: Uuid | null;
2203
- }): Promise<RecordsResult<WorkAssignmentField[]>>;
2204
- /** Add assignment to a Table. */
2205
- workTakeAssignment(args: {
2206
- table_id: Uuid;
2207
- }): Promise<RecordsResult<unknown>>;
2208
- /** Why this move would be refused. `null` means it is allowed. */
2209
- workTransitionRefusal(args: {
2210
- from_state_id: Uuid;
2211
- to_state_id: Uuid;
2212
- }): Promise<RecordsResult<string | null>>;
2213
- /** Declare the Table slots are held in. Idempotent — a second call finds the first. */
2214
- workSlotsDeclare(args: {
2215
- name: string;
2216
- slug: string;
2217
- homeId?: Uuid | null;
2218
- }): Promise<RecordsResult<unknown>>;
2219
- /**
2220
- * SCR-29. Take a slot for a while. THE STORE decides, under a unique index —
2221
- * two people racing for the same slot do not both get it, whatever either
2222
- * screen believed a moment earlier.
2223
- */
2224
- workSlotHold(args: {
2225
- table_id: Uuid;
2226
- slotKey: string;
2227
- holder: string;
2228
- ttl?: string;
2229
- }): Promise<RecordsResult<unknown>>;
2230
- workSlotRelease(args: {
2231
- hold_id: Uuid;
2232
- }): Promise<RecordsResult<boolean>>;
2233
- /** Every hold on this Table, with whether it has already lapsed. */
2234
- workSlotHolds(args: {
2235
- table_id: Uuid;
2236
- }): Promise<RecordsResult<WorkSlotHold[]>>;
2237
- workSlotExpire(args: {
2238
- table_id: Uuid;
2239
- }): Promise<RecordsResult<number>>;
2240
- /**
2241
- * THE ONE INBOX. Assignments, approvals and the agent's proposals, in one
2242
- * ordered list with ONE row shape — PRODUCTS.md row 6. A second queue for the
2243
- * agent's suggestions is the thing this replaces.
2244
- */
2245
- workInbox(args?: {
2246
- limit?: number;
2247
- offset?: number;
2248
- includeDecided?: boolean;
2249
- /** Lane S5-PRIME-2: "inbox" (default), "snoozed" or "done" — this person's own views. */
2250
- view?: WorkInboxView;
2251
- }): Promise<RecordsResult<WorkInboxItem[]>>;
2252
- /**
2253
- * SNOOZE ONE ITEM OF MY INBOX UNTIL A TIME (lane S5-PRIME-2, `custom.inbox_snooze`). Only my
2254
- * inbox changes; the approval or record is never written. A time already past, a snooze past a
2255
- * year, and a decided item are refused by name.
2256
- */
2257
- inboxSnooze(args: {
2258
- item_id: Uuid;
2259
- until: Timestamp;
2260
- }): Promise<RecordsResult<InboxStateChange>>;
2261
- /** Take my snooze off: it is back in my inbox now. */
2262
- inboxUnsnooze(args: {
2263
- item_id: Uuid;
2264
- }): Promise<RecordsResult<InboxStateChange>>;
2265
- /**
2266
- * CLEAR (mark done) ONE ITEM OF MY INBOX. A decision still owed is refused ("This one needs a
2267
- * decision"). It comes back if somebody else changes it.
2268
- */
2269
- inboxClear(args: {
2270
- item_id: Uuid;
2271
- }): Promise<RecordsResult<InboxStateChange>>;
2272
- /** Put a cleared item back in my inbox. */
2273
- inboxUnclear(args: {
2274
- item_id: Uuid;
2275
- }): Promise<RecordsResult<InboxStateChange>>;
2276
- /**
2277
- * WHAT WAITS ON ME, COUNTED (`custom.inbox_counts`) — the same predicate the inbox lists with.
2278
- * `everyOrganization` counts every organization I belong to (the shell badge: what waits on a
2279
- * person is theirs, not the selected organization's).
2280
- */
2281
- inboxCounts(args?: {
2282
- everyOrganization?: boolean;
2283
- }): Promise<RecordsResult<InboxCounts[]>>;
2284
- /** "My work", "work I assigned", "waiting on somebody being chosen". */
2285
- workList(args?: {
2286
- flavour?: WorkListFlavour;
2287
- includeFinished?: boolean;
2288
- limit?: number;
2289
- offset?: number;
2290
- }): Promise<RecordsResult<WorkListItem[]>>;
2291
- /**
2292
- * Give one record to one person: the Assignee value AND editor access, in one
2293
- * transaction. Passing no `user_id` un-assigns and says plainly that nobody's
2294
- * access was taken away.
2295
- */
2296
- workAssign(args: {
2297
- record_id: Uuid;
2298
- user_id?: Uuid | null;
2299
- dueDate?: string | null;
2300
- clearDue?: boolean;
2301
- }): Promise<RecordsResult<WorkAssignment>>;
2302
- /** The states this record may be moved to, and the sentence for each it may not. */
2303
- workRecordStates(args: {
2304
- record_id: Uuid;
2305
- }): Promise<RecordsResult<WorkRecordState[]>>;
2306
- /** Move it. The store refuses a move the model forbids, in its own words. */
2307
- workSetState(args: {
2308
- record_id: Uuid;
2309
- state_id: Uuid | null;
2310
- }): Promise<RecordsResult<unknown>>;
2311
- /** The person-kernel record standing for a signed-in person here. */
2312
- workPerson(args: {
2313
- user_id: Uuid;
2314
- create?: boolean;
2315
- }): Promise<RecordsResult<Uuid | null>>;
2316
- /** The templates this person may run, so a picker has ids to offer. */
2317
- workTemplates(args?: {
2318
- limit?: number;
2319
- }): Promise<RecordsResult<Array<{
2320
- template_id: Uuid;
2321
- name: string;
2322
- nodes: number;
2323
- relations: number;
2324
- created_at: string;
2325
- }>>>;
2326
- /** Who may decide a change about this subject, and why each of them may. */
2327
- workApprovalApprovers(args: {
2328
- subject_id: Uuid | null;
2329
- approver_id?: Uuid | null;
2330
- }): Promise<RecordsResult<WorkApprover[]>>;
2331
- /** Ask for a change instead of making it. Viewer on the subject is enough to ASK. */
2332
- workApprovalRequest(args: {
2333
- subject_id: Uuid;
2334
- change: WorkChange;
2335
- note?: string | null;
2336
- approver_id?: Uuid | null;
2337
- origin?: "person" | "agent";
2338
- conversation_id?: Uuid | null;
2339
- }): Promise<RecordsResult<WorkApprovalFiled>>;
2340
- /** Whether THIS person may decide THIS one — so a screen never draws a dead button. */
2341
- workApprovalMayDecide(args: {
2342
- approval_id: Uuid;
2343
- }): Promise<RecordsResult<boolean>>;
2344
- /** Approve or decline. Approving APPLIES the change, as the person approving. */
2345
- workApprovalDecide(args: {
2346
- approval_id: Uuid;
2347
- approve: boolean;
2348
- note?: string | null;
2349
- }): Promise<RecordsResult<WorkApprovalDecision>>;
2350
- /**
2351
- * DECIDE MANY INBOX ITEMS IN ONE CALL (lane S4, `custom.work_decide_many`). Each is judged by
2352
- * `work_approval_decide` exactly as one is, in its own savepoint: a refused decision leaves that
2353
- * item waiting and the others still stand. Verdicts: approved, declined, already_decided,
2354
- * no_right, refused — each with the store's own sentence.
2355
- */
2356
- workDecideMany(args: {
2357
- decisions: WorkDecideManyItem[];
2358
- }): Promise<RecordsResult<WorkDecideMany>>;
2359
- /** One waiting change in full, for the person deciding it or the one who asked. */
2360
- workApprovalRead(args: {
2361
- approval_id: Uuid;
2362
- }): Promise<RecordsResult<Record<string, unknown>>>;
2363
- /** VIS-31. Is this account a signed-in outsider — no NON-personal organization? */
2364
- isExternalPrincipal(args?: {
2365
- user_id?: Uuid | null;
2366
- }): Promise<RecordsResult<boolean>>;
2367
- /** The same answer WITH the plain-English reason a screen shows. */
2368
- externalPrincipalCard(args?: {
2369
- user_id?: Uuid | null;
2370
- }): Promise<RecordsResult<ExternalPrincipalCard>>;
2371
- /** Exactly the resource ids Visibility gave that outsider. Never an organization's list. */
2372
- externalPrincipalReach(args: {
2373
- resourceType: string;
2374
- user_id?: Uuid | null;
2375
- }): Promise<RecordsResult<Array<{
2376
- resource_id: Uuid;
2377
- }>>>;
2378
- /** VIS-32. Bind a record or a view to a public address with a declared render mode. */
2379
- publishBindingCreate(args: {
2380
- slug: string;
2381
- resourceType: string;
2382
- resource_id: Uuid;
2383
- renderMode?: string;
2384
- }): Promise<RecordsResult<PublishBinding>>;
2385
- publishBindingRevoke(args: {
2386
- slug: string;
2387
- }): Promise<RecordsResult<unknown>>;
2388
- /** What a SIGNED-OUT visitor resolves. Empty for an invented, revoked or unpublished address. */
2389
- resolvePublishBinding(args: {
2390
- slug: string;
2391
- }): Promise<RecordsResult<ResolvedPublishBinding[]>>;
2392
- /** The same resolution plus what the address holds (table | record | dashboard | page | view). */
2393
- resolvePublishBindingKind(args: {
2394
- slug: string;
2395
- }): Promise<RecordsResult<ResolvedPublishBindingKind[]>>;
2396
- /** D-15. The ONE sentence admitting nothing was scanned, so four surfaces cannot drift. */
2397
- worldPublishGapNotice(): Promise<RecordsResult<string>>;
2398
- /** Put a resource in the world lane. Refuses by name while the lane is closed. */
2399
- publishToWorld(args: {
2400
- resourceType: string;
2401
- resource_id: Uuid;
2402
- discoverable?: boolean;
2403
- }): Promise<RecordsResult<unknown>>;
2404
- /**
2405
- * Declare a Rule. It is NOT `recordWrite` into the rule kernel, and that is
2406
- * the whole point: `custom.record_write` inserts `data_class = 'record'`, so a
2407
- * document written that way is not a Rule and the store's own rule doors
2408
- * (`custom.rule_members`, `custom.agg_subscriptions`) never see it. Writing
2409
- * one through the record door and calling it a Rule would be a silent
2410
- * failure — a screen that looked like it had subscribed you to something.
2411
- */
2412
- ruleDeclare(args: {
2413
- spec: Record<string, unknown>;
2414
- rule_id?: Uuid | null;
2415
- }): Promise<RecordsResult<Uuid>>;
2416
- fieldPropose(proposal: FieldProposal): Promise<RecordsResult<never>>;
2417
- tablePropose(proposal: TableProposal): Promise<RecordsResult<never>>;
2418
- promoteTable(args: {
2419
- table_id: Uuid;
2420
- }): Promise<RecordsResult<unknown>>;
2421
- promoteField(args: {
2422
- table_id: Uuid;
2423
- field_id: Uuid;
2424
- }): Promise<RecordsResult<unknown>>;
2425
- /**
2426
- * @deprecated The record store is never off (owner ruling, 2026-10-03: everything is on by
2427
- * default). This answers `true` whenever the door answers; a refusal means the store could not
2428
- * be reached, never that it is off. Do not gate a screen on it.
2429
- */
2430
- storeIsOpen(): Promise<RecordsResult<boolean>>;
2431
- /**
2432
- * WHAT THIS PERSON MAY DO TO THESE THINGS — asked once, for a whole page.
2433
- *
2434
- * There is no principal argument, on purpose: the door resolves the caller
2435
- * from the session, so a person can ask about their OWN access and about
2436
- * nobody else's. A subject they hold nothing on answers `level: null`, which
2437
- * is an answer; the row is never omitted, because a screen that could not
2438
- * tell "no access" from "not asked yet" would draw one of them as the other.
2439
- */
2440
- myLevels(args: {
2441
- ids: Uuid[];
2442
- subject?: "record";
2443
- }): Promise<RecordsResult<MyLevel[]>>;
2444
- /** G1. Write ONE leaf of a Table's colors, or clear it with `null`. Editor on the Table. */
2445
- tableDecorate(args: {
2446
- table_id: Uuid;
2447
- path: DecorationPath;
2448
- value: unknown;
2449
- }): Promise<RecordsResult<TableDecorations>>;
2450
- /** G1. A Table's colors as a screen paints them, with what went stale named. */
2451
- tableDecorations(args: {
2452
- table_id: Uuid;
2453
- }): Promise<RecordsResult<TableDecorations>>;
2454
- /** G1. The layout a grid opens with: platform → organization knob → the view's own. */
2455
- gridLayout(args: {
2456
- table_id: Uuid;
2457
- view_id?: Uuid | null;
2458
- }): Promise<RecordsResult<GridLayout>>;
2459
- /** G3. The older grid's formula text → the store's expression. Never refuses a typo: answers ok:false. */
2460
- formulaParse(args: {
2461
- table_id: Uuid;
2462
- text: string;
2463
- }): Promise<RecordsResult<FormulaParse>>;
2464
- /**
2465
- * NOTION-PROPS. The formula being typed, parsed AND worked out for one record of the table
2466
- * (`custom.formula_preview`): the parse, plus `value` — what a saved formula column would show on
2467
- * that record — or `error` when it parses and cannot be worked out there. Writes nothing.
2468
- */
2469
- formulaPreview(args: {
2470
- table_id: Uuid;
2471
- record_id: Uuid | null;
2472
- text: string;
2473
- }): Promise<RecordsResult<FormulaPreview>>;
2474
- /** G2. Declare a Table's row actions — the whole list. Editor on the Table. */
2475
- actionDeclare(args: {
2476
- table_id: Uuid;
2477
- actions: RowAction[];
2478
- }): Promise<RecordsResult<RowAction[]>>;
2479
- /** G2. A Table's row actions, each saying whether it can run here. */
2480
- rowActions(args: {
2481
- table_id: Uuid;
2482
- }): Promise<RecordsResult<{
2483
- actions: RowAction[];
2484
- stale: unknown[];
2485
- }>>;
2486
- /**
2487
- * G2. Run one action on a selection, in ONE transaction. A refusal changed NOTHING; read
2488
- * every record and field that refused with `actionRefusals(result.error)`.
2489
- */
2490
- actionRun(args: {
2491
- action_id: Uuid;
2492
- record_ids: Uuid[];
2493
- }): Promise<RecordsResult<ActionRunResult>>;
2494
- /**
2495
- * AUTOMATION-DOOR. Declare (or, with `automation_id`, replace) one automation on a Table — editor on the Table.
2496
- * A spec the store refuses comes back as `data.ok === false` with `_errors`, one sentence per path.
2497
- */
2498
- automationDeclare(args: {
2499
- table_id: Uuid;
2500
- spec: AutomationSpec;
2501
- automation_id?: Uuid | null;
2502
- }): Promise<RecordsResult<AutomationDeclared>>;
2503
- /** AUTOMATION-DOOR. A Table's automations with their last run; archived ones only when asked. */
2504
- automations(args: {
2505
- table_id: Uuid;
2506
- include_archived?: boolean;
2507
- }): Promise<RecordsResult<AutomationList>>;
2508
- /** AUTOMATION-DOOR. Archive one (it switches off and keeps its history). Editor on the Table. */
2509
- automationArchive(args: {
2510
- automation_id: Uuid;
2511
- }): Promise<RecordsResult<AutomationFlipped>>;
2512
- /** AUTOMATION-DOOR. Bring an archived one back (it stays off until `automationSetEnabled`). */
2513
- automationRestore(args: {
2514
- automation_id: Uuid;
2515
- }): Promise<RecordsResult<AutomationFlipped>>;
2516
- /** AUTOMATION-DOOR. Switch one on or off. */
2517
- automationSetEnabled(args: {
2518
- automation_id: Uuid;
2519
- enabled: boolean;
2520
- }): Promise<RecordsResult<AutomationFlipped>>;
2521
- /** AUTOMATION-DOOR. Run history, newest first: status, the store's own sentence, every step. */
2522
- automationRuns(args: {
2523
- automation_id: Uuid;
2524
- limit?: number;
2525
- cursor?: string | null;
2526
- }): Promise<RecordsResult<AutomationRuns>>;
2527
- /** G4. Send every change to this Table's records to an https webhook. Admin. The secret is shown once. */
2528
- tableWebhookDeclare(args: {
2529
- table_id: Uuid;
2530
- target_url: string;
2531
- events?: RecordEvent[] | null;
2532
- description?: string | null;
2533
- }): Promise<RecordsResult<TableWebhookDeclared>>;
2534
- /** G4. The webhooks a Table sends to, with their delivery health — never the secret. */
2535
- tableWebhooks(args: {
2536
- table_id: Uuid;
2537
- }): Promise<RecordsResult<TableWebhook[]>>;
2538
- /** G4. Switch one off. It is never deleted. */
2539
- tableWebhookArchive(args: {
2540
- webhook_id: Uuid;
2541
- }): Promise<RecordsResult<boolean>>;
2542
- /** G5. Number the records an autonumber column found already there, in creation order. */
2543
- autonumberBackfill(args: {
2544
- field_id: Uuid;
2545
- }): Promise<RecordsResult<{
2546
- numbered: number;
2547
- highest: number | null;
2548
- says: string;
2549
- }>>;
2550
- /**
2551
- * NOTION-PROPS-3. PRESS A BUTTON COLUMN ON ONE ROW (`custom.button_press`): a link comes back filled from
2552
- * the row for the screen to open; a row action or an automation runs in the store and its result comes
2553
- * back. A button with nothing set up is refused by name (22023).
2554
- */
2555
- buttonPress(args: {
2556
- record_id: Uuid;
2557
- field_id: Uuid;
2558
- }): Promise<RecordsResult<ButtonPressed>>;
2559
- /**
2560
- * NOTION-PROPS-3. The knob `data/timeline_dependency_shift` for the signed-in person in this organization:
2561
- * whether moving a record on a timeline moves the records waiting on it (default true).
2562
- */
2563
- timelineDependencyShift(): Promise<RecordsResult<boolean>>;
2564
- /** G5. One page of the export door — exactly the rows and columns the read door serves this person. */
2565
- ioExport(args: {
2566
- table_id: Uuid;
2567
- columns?: string[] | null;
2568
- limit?: number;
2569
- }): Promise<RecordsResult<IoExportPage>>;
2570
- /** G5. That page as an .xlsx; a withheld column is named on its own sheet. */
2571
- /**
2572
- * G9. Every table a picker may offer here, from BOTH stores, each saying which store opens it.
2573
- * A table the app keeps out of default lists (`custom.table_kept_out_of_lists`: an agent's
2574
- * outputs) is left out unless `include_platform_tables` is true — the "Show platform tables" switch.
2575
- */
2576
- tableListEverywhere(args?: {
2577
- include_platform_tables?: boolean;
2578
- }): Promise<RecordsResult<{
2579
- success: boolean;
2580
- tables: TableListEntry[];
2581
- }>>;
2582
- /**
2583
- * Every table the person reaches (`custom.data_home_tables`), as the data home lists them.
2584
- * `organization_id` names one organization; `null` asks for every organization the person
2585
- * reaches — never the client's bound organization by default. A table the app keeps out of
2586
- * default lists (an agent's outputs) is answered only with `include_platform_tables: true`.
2587
- */
2588
- dataHomeTables(args: {
2589
- organization_id: Uuid | null;
2590
- include_platform_tables?: boolean;
2591
- }): Promise<RecordsResult<DataHomeTable[]>>;
2592
- /**
2593
- * Every table of EVERY organization (`custom.admin_all_tables`) — the admin section's list. The
2594
- * store's walls admit a platform admin to system organizations only, so this is a separate door that
2595
- * answers only on the admin lane for a platform admin; anyone else gets a refusal, not an empty list.
2596
- */
2597
- adminAllTables(): Promise<RecordsResult<AdminTable[]>>;
2598
- /**
2599
- * G10. Refresh a synced source (a sheet tab) into ONE Table under `home_id`: new rows added,
2600
- * changed rows updated, rows the source dropped archived — never destroyed; columns the
2601
- * person added in Matrx survive. Build the spec with `sheetSyncSpec`.
2602
- */
2603
- tableSync(args: {
2604
- home_id: Uuid;
2605
- spec: TableSyncSpec;
2606
- }): Promise<RecordsResult<TableSyncResult>>;
2607
- /**
2608
- * G11. The record-store Table a context scope's template-bound item provisions — one per item
2609
- * and scope. A scope provisioned before the move answers with its moved Table (same id); the
2610
- * Home defaults to the organization's own.
2611
- */
2612
- scopeTableProvision(args: {
2613
- item_id: Uuid;
2614
- scope_id: Uuid;
2615
- home_id?: Uuid | null;
2616
- }): Promise<RecordsResult<Uuid>>;
2617
- /** G12. The rows of each Table this reader may see, in one call (fold with `withRowCounts`). A Table she may not know gets no row. */
2618
- tableRowCounts(args: {
2619
- table_ids: Uuid[];
2620
- }): Promise<RecordsResult<TableRowCount[]>>;
2621
- /** G12. Each live record's own header (created, updated, version) that the read door does not answer. */
2622
- recordHeaders(args: {
2623
- ids: Uuid[];
2624
- }): Promise<RecordsResult<RecordHeader[]>>;
2625
- /**
2626
- * G14. Share a Table with a person by email or account id: an existing account outside the
2627
- * organization is granted at once and notified (never made a member); an address with no
2628
- * account is invited. The organization's outside-sharing setting decides first.
2629
- */
2630
- tableShareOutsideGrant(args: {
2631
- table_id: Uuid;
2632
- person: string;
2633
- level?: "viewer" | "commenter" | "editor" | "admin";
2634
- }): Promise<RecordsResult<OutsideShareAnswer>>;
2635
- /** G13. Keep a hand-set order on a saved view: the named rows first, in this order (build it with `moveInOrder`). */
2636
- viewRecordOrderSet(args: {
2637
- view_id: Uuid;
2638
- record_ids: Uuid[];
2639
- }): Promise<RecordsResult<ViewOrderSet>>;
2640
- /**
2641
- * G13 + ORDER-FILTER. A page of a hand-ordered view: placed rows by position, then the rest by
2642
- * created time. `filter` is the list door's question (`StoreFilter`: a flat map or a nested
2643
- * Rule — the view's own `where`, or a number clicked on a dashboard); given, the store reads
2644
- * exactly the rows that match, in their places, and `limit`/`offset` page THAT order. Each row
2645
- * answers the position stored for it; rows the filter hides keep theirs.
2646
- */
2647
- readInViewOrder(args: {
2648
- view_id: Uuid;
2649
- filter?: StoreFilter | null | undefined;
2650
- limit?: number;
2651
- offset?: number;
2652
- }): Promise<RecordsResult<Array<ReadRow & {
2653
- position: number | null;
2654
- }>>>;
2655
- exportXlsx(args: {
2656
- table_id: Uuid;
2657
- columns?: string[] | null;
2658
- limit?: number;
2659
- labels?: Record<string, string>;
2660
- sheetLabel?: string;
2661
- }): Promise<RecordsResult<Uint8Array>>;
2662
- }
2663
- /** One Table's two lane facts, as `custom.table_facts` answers them. */
2664
- interface TableFact {
2665
- table_id: Uuid;
2666
- /**
2667
- * The old lane word (personal · internal · public), now worked out by the store from `shown_to`
2668
- * and `published_to_web` (access ladder). Read those two; this stays for older stores.
2669
- */
2670
- visibility: string;
2671
- /** Whether the person signed in MADE this Table. Never who did. */
2672
- mine: boolean;
2673
- /** Access ladder "Shown to": only_me · my_team · everyone · everyone_on_ai_matrx; null = the default. */
2674
- shown_to?: string | null;
2675
- /** Access ladder "Published to the web": the only way anyone outside the organization opens it. */
2676
- published_to_web?: boolean;
2677
- }
2678
- /**
2679
- * WHERE A TABLE IS CURRENTLY READ AND WRITTEN during the older-table cutover.
2680
- * `tableHome` is an address read from one Table record; this applies the
2681
- * organization's migration switch to a batch of ids, including same-id copies.
2682
- */
2683
- interface TableLiveLocation {
2684
- table_id: Uuid;
2685
- lives_in: "record" | "older";
2686
- why: string | null;
2687
- }
2688
- /**
2689
- * The facts folded onto a table list: `visibility` on every Table the facts name,
2690
- * `created_by` ONLY as the caller's own id and only on the Tables the caller made.
2691
- * Pure — returns new objects and leaves the list it was given alone.
2692
- */
2693
- declare function withTableFacts<T extends {
2694
- id: Uuid;
2695
- }>(tables: readonly T[], facts: readonly TableFact[] | null | undefined, me: Uuid | null | undefined): T[];
2696
- declare function createRecordsClient(given: RecordsConfig): RecordsClient;
2697
- /**
2698
- * Turn a refusal into the conflict a screen can SHOW: which version you wrote
2699
- * against, which one won, and every field you touched as it stands now. Returns
2700
- * null when the refusal was not a stale write.
2701
- */
2702
- declare function asWriteConflict(error: RecordsError, recordId: Uuid): WriteConflict | null;
2703
-
2704
- export { A_PERSONS_REFUSAL as A, DEFAULT_PAGE_SIZE as D, type PromotedPredicate as P, type QueryPlan as Q, type RecordsClient as R, type TableFact as T, type AsOf as a, type RecordQuery as b, type TableLiveLocation as c, asWriteConflict as d, createRecordsClient as e, isAPersonsRefusal as f, intersectIds as i, planQuery as p, withTableFacts as w };