@ai-matrx/records 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,652 @@
1
+ import { Timestamp, Uuid, RelationCoordinate, RecordsConfig, RecordDocument, RecordsResult, RecordRead, ReadRow, Table, Field, StoredRecord, TableCapacity, AggregateMeasure, AggregateBucket, AggregateRow, Subscription, DocToken, DocUnresolvedToken, DocTemplateRow, DocRenderRow, DocSignatureRow, RecordRevision, ReadValue, AnonTokenBinding, WorkState, WorkGraph, WorkInstantiation, WorkTurn, WorkAssignmentField, WorkSlotHold, ExternalPrincipalCard, PublishBinding, ResolvedPublishBinding, FieldProposal, TableProposal, RecordsError, WriteConflict, PgError, StaleWriteDetail, PredictedRefusal } from '../index.js';
2
+ export { ABSENCE_REASONS, ACTOR_VOCABULARY, AbsenceReason, Actor, AggregateOperation, COMPUTE_ON, CONTEXT_POLICIES, ComputeOn, ContextPolicy, DELIVERIES, Delivery, DocSignatureCheck, ENTITY_TOKENS, EntityToken, FIELD_SENSITIVITIES, FIELD_SOURCES, FRESHNESS, FieldBehavior, FieldRule, FieldSensitivity, FieldSource, ForbiddenEnvelopeWord, Freshness, HiddenFieldNotice, Home, KERNEL_TABLES, KernelTableName, MERGE_FIELD_MODIFIERS, MERGE_FIELD_SEMANTIC_TYPES, MERGE_FIELD_SOURCES, MergeField, MergeFieldModifier, MergeFieldProvenance, MergeFieldResolution, MergeFieldSemanticType, MergeFieldSource, MergeFieldTransform, MissingBehavior, ON_DELETE, OVERRIDE_POLICIES, OnDelete, OverridePolicy, PARITY_FIELD_TYPES, PER_VALUE_ACCESS_WORDS, ParityFieldType, ParityFieldTypeDescriptor, PerValueAccessWord, ProvenancePointer, RELATION_BINDINGS, RELATION_CARDINALITIES, RELATION_FLAVORS, RETIRED_ACTOR_WORDS, RULE_NODE_KINDS, RULE_USES, RecordsActor, RecordsDataSource, RecordsErrorCode, RecordsErrorSink, RecordsFilter, RecordsRealtimePort, RecordsResolverPort, RecordsResponse, RecordsTableQuery, RegisteredTable, Relation, RelationBinding, RelationCardinality, RelationCarries, RelationFlavor, RelationProperties, RelationTarget, ResolutionTriple, RetiredActorWord, Rule, RuleAnswer, RuleExpression, RuleNodeKind, RuleUse, STORAGE_MODES, STORE_DOORS, STORE_KNOBS, STORE_REFUSAL_CODES, StorageMode, StoreDoorName, StoreRefusalCode, SubscriptionBlock, SubscriptionCadence, TABLE_DISPLAYS, TABLE_ORIGINS, TABLE_TYPES, TableDisplay, TableOrigin, TableType, VALUE_ALTERNATE_KEYS, VALUE_ENVELOPE_KEYS, ValueAlternate, ValueAlternateKey, ValueEnvelope, ValueEnvelopeKey, ValueSource, WorkTemplateNode, WorkTemplateRelation, err, isRecordsErr, measureKey, ok } from '../index.js';
3
+
4
+ /**
5
+ * DOOR-8. As-of on EITHER clock, and they are different questions:
6
+ * · `record` — the record clock: what this record looked like at version time.
7
+ * · `world` — the world clock: which values were true of the world then
8
+ * (the Field's `dated` modifier).
9
+ */
10
+ interface AsOf {
11
+ clock: "record" | "world";
12
+ at: Timestamp;
13
+ }
14
+ /** A predicate over a PROMOTED field (REC-5: promotion light -> heavy). */
15
+ interface PromotedPredicate {
16
+ field_key: string;
17
+ /** The value as text, exactly as `custom.promoted_read` takes it. */
18
+ equals: string;
19
+ }
20
+ interface RecordQuery {
21
+ table_id: Uuid;
22
+ /** DOOR-6. Any combination, any subset. An empty list means "no relation constraint". */
23
+ relations?: RelationCoordinate[];
24
+ /** Predicates the store can answer from an index. */
25
+ promoted?: PromotedPredicate[];
26
+ /** DOOR-8. */
27
+ asOf?: AsOf;
28
+ /** DOOR-9. Ask across EVERY Home of this Table in one answer. */
29
+ acrossHomes?: boolean;
30
+ /** REC-23. Soft-deleted rows are out unless you say otherwise. */
31
+ includeDeleted?: boolean;
32
+ /** FLD-10. */
33
+ recordType?: string;
34
+ orderBy?: {
35
+ column: "created_at" | "updated_at";
36
+ ascending?: boolean;
37
+ };
38
+ limit?: number;
39
+ offset?: number;
40
+ }
41
+ /**
42
+ * What a query decomposes into: a set of door calls whose answers INTERSECT,
43
+ * then one filtered read. Kept as data rather than hidden inside the client so
44
+ * the suite can assert the plan as well as the answer — a query that quietly
45
+ * stopped applying one of its coordinates is otherwise invisible.
46
+ */
47
+ interface QueryPlan {
48
+ /** One `relation_targets` call per coordinate; the id sets are intersected. */
49
+ relationCalls: Array<{
50
+ door: "relation_targets";
51
+ record_id: Uuid;
52
+ via_key: string | null;
53
+ }>;
54
+ /** One `promoted_read` call per predicate; intersected with the above. */
55
+ promotedCalls: Array<{
56
+ door: "promoted_read";
57
+ field_key: string;
58
+ value: string;
59
+ }>;
60
+ /** The filtered read over `custom.record`, which the store's policies gate. */
61
+ read: {
62
+ table_id: Uuid;
63
+ includeDeleted: boolean;
64
+ recordType: string | null;
65
+ asOf: AsOf | null;
66
+ acrossHomes: boolean;
67
+ orderBy: {
68
+ column: string;
69
+ ascending: boolean;
70
+ };
71
+ limit: number;
72
+ offset: number;
73
+ };
74
+ /**
75
+ * Stated so nobody has to guess: when this is true the answer is the
76
+ * intersection of the id sets above, and when it is false the read stands
77
+ * alone.
78
+ */
79
+ intersects: boolean;
80
+ }
81
+ declare const DEFAULT_PAGE_SIZE = 50;
82
+ declare function planQuery(query: RecordQuery): QueryPlan;
83
+ /** The intersection of the id sets a plan's calls produced. Order is preserved from the first set. */
84
+ declare function intersectIds(sets: Uuid[][]): Uuid[];
85
+
86
+ interface RecordsClient {
87
+ /** The config this client was built with, so a screen can show who it is acting as. */
88
+ readonly config: RecordsConfig;
89
+ recordWrite(args: {
90
+ table_id: Uuid;
91
+ data: RecordDocument;
92
+ }): Promise<RecordsResult<Uuid>>;
93
+ recordUpdate(args: {
94
+ record_id: Uuid;
95
+ patch: Record<string, unknown>;
96
+ /** Leave it out and the last writer wins; supply it and a loser is TOLD. */
97
+ expectedVersion?: number;
98
+ }): Promise<RecordsResult<number>>;
99
+ /** REC-23. Soft, and reversible within `retention`. */
100
+ recordDelete(args: {
101
+ record_id: Uuid;
102
+ }): Promise<RecordsResult<Timestamp>>;
103
+ recordRestore(args: {
104
+ record_id: Uuid;
105
+ }): Promise<RecordsResult<void>>;
106
+ recordRead(args: {
107
+ record_id: Uuid;
108
+ withComputed?: boolean;
109
+ }): Promise<RecordsResult<RecordRead>>;
110
+ /**
111
+ * DOOR-1. A page of one Table's records THROUGH `custom.read_records`: the
112
+ * store decides which rows this reader may see and which fields of them, and
113
+ * a field it masked comes back present-and-null with its reason in `hidden`.
114
+ * `total` is null because the door counts nothing it has not read — a count
115
+ * of rows a person may not see is a leak with a number on it.
116
+ */
117
+ list(args: {
118
+ table_id: Uuid;
119
+ limit?: number;
120
+ offset?: number;
121
+ }): Promise<RecordsResult<{
122
+ rows: ReadRow[];
123
+ total: number | null;
124
+ }>>;
125
+ query(query: RecordQuery): Promise<RecordsResult<{
126
+ rows: ReadRow[];
127
+ total: number | null;
128
+ }>>;
129
+ tableList(): Promise<RecordsResult<Table[]>>;
130
+ fields(args: {
131
+ table_id: Uuid;
132
+ recordType?: string;
133
+ }): Promise<RecordsResult<Field[]>>;
134
+ /**
135
+ * FLD-5 / FLD-6: a list field stores the id of an option RECORD, because
136
+ * every pick-list is already a Table. These are that Table's records — the
137
+ * store resolves which Table from the Field's own config, so no caller has to
138
+ * know it.
139
+ */
140
+ fieldOptions(args: {
141
+ field_id: Uuid;
142
+ }): Promise<RecordsResult<StoredRecord[]>>;
143
+ tableCapacity(args: {
144
+ table_id: Uuid;
145
+ }): Promise<RecordsResult<TableCapacity>>;
146
+ /**
147
+ * REC-1: a Table has to live somewhere, so a Home comes first — and a Home is
148
+ * an ordinary record in the person kernel. `homeId` is therefore required and
149
+ * `personKernelId()` is how a caller gets a Table to write one into.
150
+ */
151
+ tableDeclare(args: {
152
+ spec: Record<string, unknown>;
153
+ homeId: Uuid;
154
+ }): Promise<RecordsResult<Uuid>>;
155
+ /** The kernel Tables a caller writes a Home, a Field or a Rule into. */
156
+ personKernelId(): Promise<RecordsResult<Uuid>>;
157
+ fieldKernelId(): Promise<RecordsResult<Uuid>>;
158
+ ruleKernelId(): Promise<RecordsResult<Uuid>>;
159
+ /** Every record the Rule says is a member. A saved view's list is this, not a filter a screen ran. */
160
+ ruleMembers(args: {
161
+ rule_id: Uuid;
162
+ }): Promise<RecordsResult<StoredRecord[]>>;
163
+ /** Is this one record a member, and WHY — the store's own answer. */
164
+ ruleMembership(args: {
165
+ rule_id: Uuid;
166
+ record_id: Uuid;
167
+ }): Promise<RecordsResult<unknown>>;
168
+ /** Run a stored Rule against a document. */
169
+ ruleRun(args: {
170
+ rule_id: Uuid;
171
+ values: Record<string, unknown>;
172
+ context?: Record<string, unknown>;
173
+ }): Promise<RecordsResult<unknown>>;
174
+ /** Evaluate a Rule expression that has not been stored — the conditional logic a form runner asks about. */
175
+ ruleEval(args: {
176
+ expr: unknown;
177
+ values: Record<string, unknown>;
178
+ context?: Record<string, unknown>;
179
+ }): Promise<RecordsResult<unknown>>;
180
+ /**
181
+ * Group, bucket, filter and measure INSIDE `custom.record_aggregate`. The
182
+ * aggregate node sits above the visibility join, so what a chart draws is
183
+ * exactly what this person may see — the rest is never fetched, let alone
184
+ * summed and then hidden.
185
+ */
186
+ recordAggregate(args: {
187
+ table_id: Uuid;
188
+ /** Field keys whose values become the groups. */
189
+ groupBy?: string[];
190
+ /** `count` needs no key; every other operation reads one Field. */
191
+ measures?: AggregateMeasure[];
192
+ /** A date Field truncated to a period — a group whose expression is a date_trunc. */
193
+ bucket?: {
194
+ key: string;
195
+ by: AggregateBucket;
196
+ } | null;
197
+ /** Equality only, and it lands in the SAME WHERE as visibility. */
198
+ filter?: Record<string, string>;
199
+ limit?: number;
200
+ }): Promise<RecordsResult<AggregateRow[]>>;
201
+ /** The measures the store itself offers. Asked, never hardcoded in a picker. */
202
+ aggOperations(): Promise<RecordsResult<string[]>>;
203
+ /** The periods the store itself buckets by. */
204
+ aggBuckets(): Promise<RecordsResult<string[]>>;
205
+ /**
206
+ * Every subscription in this organization, optionally narrowed to one saved
207
+ * view or one cadence. There is no subscription table: each one is a Rule
208
+ * record carrying a `subscription` block, so a subscription is readable,
209
+ * historied and agent-writable like anything else.
210
+ */
211
+ aggSubscriptions(args?: {
212
+ saved_view_id?: Uuid | null;
213
+ cadence?: string | null;
214
+ }): Promise<RecordsResult<Subscription[]>>;
215
+ /** The cadences the store itself offers. Asked, never hardcoded in a picker. */
216
+ aggSubscriptionCadences(): Promise<RecordsResult<string[]>>;
217
+ docTemplateSave(args: {
218
+ table_id: Uuid;
219
+ name: string;
220
+ body: string;
221
+ template_id?: Uuid | null;
222
+ }): Promise<RecordsResult<Uuid>>;
223
+ /** The body with every token resolved against one record. Read-only, no render row. */
224
+ docRenderBody(args: {
225
+ template_id: Uuid;
226
+ record_id: Uuid;
227
+ }): Promise<RecordsResult<string>>;
228
+ /** Write the render — frozen bytes a signature can be checked against. */
229
+ docRenderDocument(args: {
230
+ template_id: Uuid;
231
+ record_id: Uuid;
232
+ }): Promise<RecordsResult<Uuid>>;
233
+ /** Every token in a body, in order, with the Field id each one points at. */
234
+ docTokens(args: {
235
+ body: string;
236
+ }): Promise<RecordsResult<DocToken[]>>;
237
+ /** The tokens this Table cannot answer, each with the store's own reason. */
238
+ docUnresolvedTokens(args: {
239
+ table_id: Uuid;
240
+ body: string;
241
+ }): Promise<RecordsResult<DocUnresolvedToken[]>>;
242
+ docSign(args: {
243
+ render_id: Uuid;
244
+ field_key: string;
245
+ signer_name: string;
246
+ signer_user_id?: Uuid | null;
247
+ }): Promise<RecordsResult<Uuid>>;
248
+ /** Is what was signed still what is there? The store answers, never the screen. */
249
+ docSignatureIntact(args: {
250
+ signature_id: Uuid;
251
+ }): Promise<RecordsResult<unknown>>;
252
+ /** Every template that renders one Table. */
253
+ docTemplates(args: {
254
+ table_id: Uuid;
255
+ }): Promise<RecordsResult<DocTemplateRow[]>>;
256
+ /** Every frozen render of one record, newest first. */
257
+ docRenders(args: {
258
+ record_id: Uuid;
259
+ }): Promise<RecordsResult<DocRenderRow[]>>;
260
+ /** Every signature on one record. */
261
+ docSignatures(args: {
262
+ record_id: Uuid;
263
+ }): Promise<RecordsResult<DocSignatureRow[]>>;
264
+ /**
265
+ * DOOR-11. One record's revisions, newest first. The read door answers
266
+ * documents and deliberately not versions, so a screen that wants to save
267
+ * optimistically reads the version of the record it LOADED from here — for
268
+ * the one record being edited, never for a list.
269
+ */
270
+ revisions(args: {
271
+ record_id: Uuid;
272
+ }): Promise<RecordsResult<RecordRevision[]>>;
273
+ /**
274
+ * Every value of one record WITH its envelope — its own version, who wrote
275
+ * it, who they were acting for and when. The timeline IS the record (REC-19);
276
+ * there is no second history table.
277
+ */
278
+ recordValuesVersioned(args: {
279
+ record_id: Uuid;
280
+ }): Promise<RecordsResult<ReadValue[]>>;
281
+ metadataSearch(args: {
282
+ text: string;
283
+ }): Promise<RecordsResult<never>>;
284
+ /**
285
+ * Mint an embed token. `mode` is `read` OR `write` and never both — the store
286
+ * refuses a token carrying two decisions. The secret comes back ONCE, because
287
+ * only its digest is stored: a database read cannot produce a working token.
288
+ * `allowedOrigins` is required and matched EXACTLY, so `example.com.evil.test`
289
+ * fails a check that a suffix match would pass.
290
+ */
291
+ anonTokenIssue(args: {
292
+ mode: "read" | "write";
293
+ allowedOrigins: string[];
294
+ formId?: Uuid | null;
295
+ savedViewId?: Uuid | null;
296
+ recordId?: Uuid | null;
297
+ expiresAt?: Timestamp | null;
298
+ }): Promise<RecordsResult<{
299
+ token_id: Uuid;
300
+ secret: string;
301
+ }>>;
302
+ /** What a secret is good for, from an origin. The store's sentence when it is not. */
303
+ anonTokenVerify(args: {
304
+ secret: string;
305
+ origin: string;
306
+ requiredMode?: "read" | "write" | null;
307
+ }): Promise<RecordsResult<AnonTokenBinding>>;
308
+ anonTokenRevoke(args: {
309
+ token_id: Uuid;
310
+ }): Promise<RecordsResult<boolean>>;
311
+ /**
312
+ * A STRANGER'S WRITE. The token supplies the organization, so this call names
313
+ * none — and what it produces is a QUARANTINED SUBMISSION, not a record:
314
+ * `custom.record` is never touched here. `clientKey` makes a replay free and
315
+ * idempotent, which is what lets a flaky phone retry safely.
316
+ */
317
+ anonWrite(args: {
318
+ secret: string;
319
+ origin: string;
320
+ payload: Record<string, unknown>;
321
+ clientKey?: string | null;
322
+ rawPayload?: Record<string, unknown>;
323
+ }): Promise<RecordsResult<Uuid>>;
324
+ /**
325
+ * SCR-30, and it is the SIGNED-IN offline path, not the stranger's. The client
326
+ * mints `clientKey` BEFORE the first attempt, offline, and the store's own
327
+ * replay ledger dedupes on it — so a reconnect that fires the same capture
328
+ * thirty times writes one record and returns the same id every time.
329
+ */
330
+ anonCapture(args: {
331
+ table_id: Uuid;
332
+ clientKey: string;
333
+ payload: Record<string, unknown>;
334
+ device?: string | null;
335
+ capturedAt?: Timestamp | null;
336
+ }): Promise<RecordsResult<Uuid>>;
337
+ /** Open or close a form to strangers. An admin act on the Table, never an editor one. */
338
+ anonPublish(args: {
339
+ form_id: Uuid;
340
+ published?: boolean;
341
+ }): Promise<RecordsResult<Timestamp | null>>;
342
+ /** The five states and what each one may become. Asked, never hardcoded in a picker. */
343
+ workStates(): Promise<RecordsResult<WorkState[]>>;
344
+ /** Why this graph would be refused — asked BEFORE it is written. `null` means it is fine. */
345
+ workTemplateRefusal(args: {
346
+ graph: WorkGraph;
347
+ }): Promise<RecordsResult<string | null>>;
348
+ workTemplateDeclare(args: {
349
+ name: string;
350
+ graph: WorkGraph;
351
+ }): Promise<RecordsResult<Uuid>>;
352
+ /**
353
+ * REC-70: the WHOLE graph is created in one act, judged before any of it is
354
+ * written, so a half-made checklist is not a state this store can be in.
355
+ */
356
+ workTemplateInstantiate(args: {
357
+ template_id: Uuid;
358
+ overrides?: Record<string, Record<string, unknown>>;
359
+ }): Promise<RecordsResult<WorkInstantiation>>;
360
+ workTemplateShape(args: {
361
+ template_id: Uuid;
362
+ }): Promise<RecordsResult<unknown>>;
363
+ workInstantiationShape(args: {
364
+ instantiation_id: Uuid;
365
+ }): Promise<RecordsResult<unknown>>;
366
+ /** Whose turn each record is, with its state and whether that state is terminal. */
367
+ workWhoseTurn(args: {
368
+ table_id: Uuid;
369
+ includeFinished?: boolean;
370
+ }): Promise<RecordsResult<WorkTurn[]>>;
371
+ /** Does this Table carry assignment at all? A screen asks before it offers one. */
372
+ workHasAssignment(args: {
373
+ table_id: Uuid;
374
+ }): Promise<RecordsResult<boolean>>;
375
+ /** The Fields assignment is made of, so nothing here invents a column name. */
376
+ workAssignmentFields(args?: {
377
+ options_table_id?: Uuid | null;
378
+ }): Promise<RecordsResult<WorkAssignmentField[]>>;
379
+ /** Add assignment to a Table. */
380
+ workTakeAssignment(args: {
381
+ table_id: Uuid;
382
+ }): Promise<RecordsResult<unknown>>;
383
+ /** Why this move would be refused. `null` means it is allowed. */
384
+ workTransitionRefusal(args: {
385
+ from_state_id: Uuid;
386
+ to_state_id: Uuid;
387
+ }): Promise<RecordsResult<string | null>>;
388
+ /** Declare the Table slots are held in. Idempotent — a second call finds the first. */
389
+ workSlotsDeclare(args: {
390
+ name: string;
391
+ slug: string;
392
+ homeId?: Uuid | null;
393
+ }): Promise<RecordsResult<unknown>>;
394
+ /**
395
+ * SCR-29. Take a slot for a while. THE STORE decides, under a unique index —
396
+ * two people racing for the same slot do not both get it, whatever either
397
+ * screen believed a moment earlier.
398
+ */
399
+ workSlotHold(args: {
400
+ table_id: Uuid;
401
+ slotKey: string;
402
+ holder: string;
403
+ ttl?: string;
404
+ }): Promise<RecordsResult<unknown>>;
405
+ workSlotRelease(args: {
406
+ hold_id: Uuid;
407
+ }): Promise<RecordsResult<boolean>>;
408
+ /** Every hold on this Table, with whether it has already lapsed. */
409
+ workSlotHolds(args: {
410
+ table_id: Uuid;
411
+ }): Promise<RecordsResult<WorkSlotHold[]>>;
412
+ workSlotExpire(args: {
413
+ table_id: Uuid;
414
+ }): Promise<RecordsResult<number>>;
415
+ /** VIS-31. Is this account a signed-in outsider — no NON-personal organization? */
416
+ isExternalPrincipal(args?: {
417
+ user_id?: Uuid | null;
418
+ }): Promise<RecordsResult<boolean>>;
419
+ /** The same answer WITH the plain-English reason a screen shows. */
420
+ externalPrincipalCard(args?: {
421
+ user_id?: Uuid | null;
422
+ }): Promise<RecordsResult<ExternalPrincipalCard>>;
423
+ /** Exactly the resource ids Visibility gave that outsider. Never an organization's list. */
424
+ externalPrincipalReach(args: {
425
+ resourceType: string;
426
+ user_id?: Uuid | null;
427
+ }): Promise<RecordsResult<Array<{
428
+ resource_id: Uuid;
429
+ }>>>;
430
+ /** VIS-32. Bind a record or a view to a public address with a declared render mode. */
431
+ publishBindingCreate(args: {
432
+ slug: string;
433
+ resourceType: string;
434
+ resource_id: Uuid;
435
+ renderMode?: string;
436
+ }): Promise<RecordsResult<PublishBinding>>;
437
+ publishBindingRevoke(args: {
438
+ slug: string;
439
+ }): Promise<RecordsResult<unknown>>;
440
+ /** What a SIGNED-OUT visitor resolves. Empty for an invented, revoked or unpublished address. */
441
+ resolvePublishBinding(args: {
442
+ slug: string;
443
+ }): Promise<RecordsResult<ResolvedPublishBinding[]>>;
444
+ /** D-15. The ONE sentence admitting nothing was scanned, so four surfaces cannot drift. */
445
+ worldPublishGapNotice(): Promise<RecordsResult<string>>;
446
+ /** Put a resource in the world lane. Refuses by name while the lane is closed. */
447
+ publishToWorld(args: {
448
+ resourceType: string;
449
+ resource_id: Uuid;
450
+ discoverable?: boolean;
451
+ }): Promise<RecordsResult<unknown>>;
452
+ /**
453
+ * Declare a Rule. It is NOT `recordWrite` into the rule kernel, and that is
454
+ * the whole point: `custom.record_write` inserts `data_class = 'record'`, so a
455
+ * document written that way is not a Rule and the store's own rule doors
456
+ * (`custom.rule_members`, `custom.agg_subscriptions`) never see it. Writing
457
+ * one through the record door and calling it a Rule would be a silent
458
+ * failure — a screen that looked like it had subscribed you to something.
459
+ */
460
+ ruleDeclare(args: {
461
+ spec: Record<string, unknown>;
462
+ }): Promise<RecordsResult<never>>;
463
+ fieldPropose(proposal: FieldProposal): Promise<RecordsResult<never>>;
464
+ tablePropose(proposal: TableProposal): Promise<RecordsResult<never>>;
465
+ promoteTable(args: {
466
+ table_id: Uuid;
467
+ }): Promise<RecordsResult<unknown>>;
468
+ promoteField(args: {
469
+ table_id: Uuid;
470
+ field_id: Uuid;
471
+ }): Promise<RecordsResult<unknown>>;
472
+ /** Is the store switched on for this organization? A product switch, never the boundary. */
473
+ storeIsOpen(): Promise<RecordsResult<boolean>>;
474
+ }
475
+ declare function createRecordsClient(config: RecordsConfig): RecordsClient;
476
+ /**
477
+ * Turn a refusal into the conflict a screen can SHOW: which version you wrote
478
+ * against, which one won, and every field you touched as it stands now. Returns
479
+ * null when the refusal was not a stale write.
480
+ */
481
+ declare function asWriteConflict(error: RecordsError, recordId: Uuid): WriteConflict | null;
482
+
483
+ declare function doorExists(name: string): boolean;
484
+ /** The refusal a missing door gets. It always says who owes it. */
485
+ declare function doorAbsent(name: string): RecordsError;
486
+ /** The doors this package calls, one place, so the suite can walk them. */
487
+ declare const DOORS: {
488
+ readonly readRecord: "read_record";
489
+ readonly readRecords: "read_records";
490
+ readonly queryRecordAsOf: "query_record_as_of";
491
+ readonly queryTableAsOf: "query_table_as_of";
492
+ readonly recordWrite: "record_write";
493
+ readonly recordUpdate: "record_update";
494
+ readonly recordDelete: "record_delete";
495
+ readonly recordRestore: "record_restore";
496
+ readonly recordValues: "record_values";
497
+ readonly recordValuesVersioned: "record_values_versioned";
498
+ readonly valueRead: "value_read";
499
+ readonly computedProvenance: "computed_provenance";
500
+ readonly recordApplicability: "record_applicability";
501
+ readonly applicableFields: "applicable_fields";
502
+ readonly fieldOptions: "field_options";
503
+ readonly parityValues: "parity_values";
504
+ readonly tableDeclare: "table_declare";
505
+ readonly tableCapacity: "table_capacity";
506
+ readonly tableStorage: "table_storage";
507
+ readonly promoteTable: "promote_table";
508
+ readonly promoteField: "promote_field";
509
+ readonly promotedFields: "promoted_fields";
510
+ readonly promotedRead: "promoted_read";
511
+ readonly relationTargets: "relation_targets";
512
+ readonly relationOwn: "relation_own";
513
+ readonly homeAdd: "home_add";
514
+ readonly recordReparent: "record_reparent";
515
+ readonly containmentChain: "containment_chain";
516
+ readonly storeIsOpen: "store_is_open";
517
+ readonly ioRevisions: "io_revisions";
518
+ readonly resolveFirstMatch: "resolve_first_match";
519
+ readonly personKernelId: "person_kernel_id";
520
+ readonly fieldKernelId: "field_kernel_id";
521
+ readonly ruleKernelId: "rule_kernel_id";
522
+ readonly tableKernelId: "table_kernel_id";
523
+ readonly ruleMembers: "rule_members";
524
+ readonly ruleMembership: "rule_membership";
525
+ readonly ruleRun: "rule_run";
526
+ readonly ruleEval: "rule_eval";
527
+ readonly recordAggregate: "record_aggregate";
528
+ readonly aggOperations: "agg_operations";
529
+ readonly aggBuckets: "agg_buckets";
530
+ readonly aggSubscriptions: "agg_subscriptions";
531
+ readonly aggSubscriptionCadences: "agg_subscription_cadences";
532
+ readonly docTemplateSave: "doc_template_save";
533
+ readonly docRenderBody: "doc_render_body";
534
+ readonly docRenderDocument: "doc_render_document";
535
+ readonly docTokens: "doc_tokens";
536
+ readonly docUnresolvedTokens: "doc_unresolved_tokens";
537
+ readonly docSign: "doc_sign";
538
+ readonly docSignatureIntact: "doc_signature_intact";
539
+ readonly anonTokenIssue: "anon_token_issue";
540
+ readonly anonTokenVerify: "anon_token_verify";
541
+ readonly anonTokenRevoke: "anon_token_revoke";
542
+ /** The stranger's write. The TOKEN names the organization; a caller never does. */
543
+ readonly anonWrite: "anon_write";
544
+ /** SCR-30. The signed-in OFFLINE path: the client mints the key, the store dedupes on it. */
545
+ readonly anonCapture: "anon_capture";
546
+ readonly anonPublish: "anon_publish";
547
+ readonly workStates: "work_states";
548
+ readonly workTemplateDeclare: "work_template_declare";
549
+ readonly workTemplateInstantiate: "work_template_instantiate";
550
+ readonly workTemplateShape: "work_template_shape";
551
+ /** Why a graph would be refused — asked BEFORE it is written, never after. */
552
+ readonly workTemplateRefusal: "work_template_refusal";
553
+ readonly workWhoseTurn: "work_whose_turn";
554
+ readonly workTakeAssignment: "work_take_assignment";
555
+ readonly workHasAssignment: "work_has_assignment";
556
+ readonly workAssignmentFields: "work_assignment_fields";
557
+ readonly workTransitionRefusal: "work_transition_refusal";
558
+ readonly workInstantiationShape: "work_instantiation_shape";
559
+ readonly workSlotsDeclare: "work_slots_declare";
560
+ readonly workSlotHold: "work_slot_hold";
561
+ readonly workSlotRelease: "work_slot_release";
562
+ readonly workSlotHolds: "work_slot_holds";
563
+ readonly workSlotExpire: "work_slot_expire";
564
+ readonly metadataSearch: "metadata_search";
565
+ readonly ruleDeclare: "rule_declare";
566
+ readonly fieldPropose: "field_propose";
567
+ readonly tablePropose: "table_propose";
568
+ readonly mergeFieldResolve: "merge_field_resolve";
569
+ };
570
+ type DoorKey = keyof typeof DOORS;
571
+ /** Which of this package's doors the live store actually has, and which it does not. */
572
+ declare function doorCensus(): {
573
+ present: string[];
574
+ absent: string[];
575
+ };
576
+
577
+ /** The SQLSTATEs this package claims to understand. Exported for the guard. */
578
+ declare const MAPPED_SQLSTATES: string[];
579
+ /** Map a PostgREST/supabase-js failure into the package's refusal shape. */
580
+ declare function mapPgError(error: PgError, where: string): RecordsError;
581
+ /** Pull the conflict out of a `stale_write`, when the store sent one. */
582
+ declare function staleWriteDetail(error: RecordsError): StaleWriteDetail | null;
583
+
584
+ /** The published defaults, which are also what the store falls back to when it cannot read a knob. */
585
+ declare const DEFAULT_VALUE_MAX_BYTES = 100000;
586
+ declare const DEFAULT_DOCUMENT_MAX_BYTES = 1048576;
587
+ interface MirrorLimits {
588
+ value_max_bytes?: number;
589
+ document_max_bytes?: number;
590
+ }
591
+ /**
592
+ * Predict `custom.validate_values`. Everything it checks WITHOUT a query is
593
+ * mirrored; option membership and relation targets are deliberately left to the
594
+ * door, and the mirror says nothing about them.
595
+ */
596
+ declare function predictValueRefusals(fields: Field[], values: Record<string, unknown>, recordType?: string): PredictedRefusal[];
597
+ /** Predict `custom.size_refusal`, with the same two ceilings and the same sentences. */
598
+ declare function predictSizeRefusal(document: RecordDocument, limits?: MirrorLimits): PredictedRefusal | null;
599
+ /**
600
+ * Predict `custom.value_envelope_refusal`. The store returns the FIRST problem
601
+ * it finds and stops; so does this, key order included, so the two agree on
602
+ * which sentence a person sees.
603
+ */
604
+ declare function predictEnvelopeRefusal(document: RecordDocument): PredictedRefusal | null;
605
+ /** Everything the mirror can see about one write, in the order the store sees it. */
606
+ declare function predictWriteRefusals(args: {
607
+ fields: Field[];
608
+ document: RecordDocument;
609
+ recordType?: string;
610
+ limits?: MirrorLimits;
611
+ }): PredictedRefusal[];
612
+
613
+ /** One exportable row: the values of one record, keyed by field key. */
614
+ type ExportRow = Record<string, ReadValue | undefined>;
615
+ /**
616
+ * The same stringification: a string stays itself, everything else becomes its
617
+ * JSON, and an absent value becomes the store's own absence WORD rather than an
618
+ * empty cell. A blank cell would be the silent failure VAL-2 exists to prevent —
619
+ * "we never asked" and "they refused" are different facts and the export says
620
+ * which.
621
+ */
622
+ declare function cellText(value: ReadValue | undefined): string;
623
+ declare function exportCsv(fields: Field[], rows: ExportRow[]): string;
624
+ /** The header row plus every cell, as the sheet writer takes it. */
625
+ declare function toAoa(fields: Field[], rows: ExportRow[]): string[][];
626
+ /**
627
+ * The XLSX bytes. The `xlsx` import is dynamic so a consumer that only ever
628
+ * exports CSV never pays for the library — the design-system module is loaded
629
+ * the same way, and for the same reason.
630
+ */
631
+ declare function exportXlsx(fields: Field[], rows: ExportRow[], sheetLabel?: string): Promise<Uint8Array>;
632
+ /** A parsed import: the header row mapped onto field keys, and the rows. */
633
+ interface ParsedImport {
634
+ /** Header text -> the Field it matched, or null when nothing matched. */
635
+ columns: Array<{
636
+ header: string;
637
+ field: Field | null;
638
+ }>;
639
+ rows: Array<Record<string, string>>;
640
+ /**
641
+ * DOOR-14 / AGT-N-7. Headers that matched no Field. They are NEVER dropped
642
+ * quietly: an unmapped key becomes a field proposal a person approves, and the
643
+ * import surface shows this list.
644
+ */
645
+ unmapped: string[];
646
+ }
647
+ /** RFC-4180 enough for what the canonical table writes, quotes and embedded newlines included. */
648
+ declare function parseCsv(text: string): string[][];
649
+ declare function importCsv(fields: Field[], text: string): ParsedImport;
650
+ declare function importXlsx(fields: Field[], bytes: ArrayBuffer | Uint8Array): Promise<ParsedImport>;
651
+
652
+ export { AggregateBucket, AggregateMeasure, AggregateRow, AnonTokenBinding, type AsOf, DEFAULT_DOCUMENT_MAX_BYTES, DEFAULT_PAGE_SIZE, DEFAULT_VALUE_MAX_BYTES, DOORS, DocRenderRow, DocSignatureRow, DocTemplateRow, DocToken, DocUnresolvedToken, type DoorKey, type ExportRow, ExternalPrincipalCard, Field, FieldProposal, MAPPED_SQLSTATES, type MirrorLimits, type ParsedImport, PgError, PredictedRefusal, type PromotedPredicate, PublishBinding, type QueryPlan, ReadRow, ReadValue, RecordDocument, type RecordQuery, RecordRead, RecordRevision, type RecordsClient, RecordsConfig, RecordsError, RecordsResult, RelationCoordinate, ResolvedPublishBinding, StaleWriteDetail, StoredRecord, Subscription, Table, TableCapacity, TableProposal, Timestamp, Uuid, WorkAssignmentField, WorkGraph, WorkInstantiation, WorkSlotHold, WorkState, WorkTurn, WriteConflict, asWriteConflict, cellText, createRecordsClient, doorAbsent, doorCensus, doorExists, exportCsv, exportXlsx, importCsv, importXlsx, intersectIds, mapPgError, parseCsv, planQuery, predictEnvelopeRefusal, predictSizeRefusal, predictValueRefusals, predictWriteRefusals, staleWriteDetail, toAoa };