@ai-matrx/records 0.87.32 → 0.92.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +115 -0
  3. package/dist/{client-E0VQ0NPO.d.ts → client-Cn3odIIB.d.cts} +10 -5
  4. package/dist/{client-C3ZZNfGH.d.cts → client-Dzd8gtAo.d.ts} +10 -5
  5. package/dist/core/index.cjs +28 -10
  6. package/dist/core/index.cjs.map +1 -1
  7. package/dist/core/index.d.cts +23 -12
  8. package/dist/core/index.d.ts +23 -12
  9. package/dist/core/index.js +28 -10
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/data/index.cjs +22 -10
  12. package/dist/data/index.cjs.map +1 -1
  13. package/dist/data/index.d.cts +12 -142
  14. package/dist/data/index.d.ts +12 -142
  15. package/dist/data/index.js +22 -10
  16. package/dist/data/index.js.map +1 -1
  17. package/dist/{declareTable-BK3zufr7.d.cts → declareTable-CrL6AZKB.d.cts} +4 -4
  18. package/dist/{declareTable-B12XybRp.d.ts → declareTable-ZRW5EsTQ.d.ts} +4 -4
  19. package/dist/entity/index.cjs +984 -0
  20. package/dist/entity/index.cjs.map +1 -0
  21. package/dist/entity/index.d.cts +36 -0
  22. package/dist/entity/index.d.ts +36 -0
  23. package/dist/entity/index.js +964 -0
  24. package/dist/entity/index.js.map +1 -0
  25. package/dist/entity/react.cjs +1024 -0
  26. package/dist/entity/react.cjs.map +1 -0
  27. package/dist/entity/react.d.cts +511 -0
  28. package/dist/entity/react.d.ts +511 -0
  29. package/dist/entity/react.js +1015 -0
  30. package/dist/entity/react.js.map +1 -0
  31. package/dist/{field-BanTVGK2.d.cts → field-CCY1rG9l.d.cts} +1 -1
  32. package/dist/{field-BPABOJ2Y.d.ts → field-enufS5ry.d.ts} +1 -1
  33. package/dist/forms/index.cjs +984 -0
  34. package/dist/forms/index.cjs.map +1 -0
  35. package/dist/forms/index.d.cts +333 -0
  36. package/dist/forms/index.d.ts +333 -0
  37. package/dist/forms/index.js +961 -0
  38. package/dist/forms/index.js.map +1 -0
  39. package/dist/index.cjs +10 -1
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +11 -8
  42. package/dist/index.d.ts +11 -8
  43. package/dist/index.js +10 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/memory/index.d.cts +7 -6
  46. package/dist/memory/index.d.ts +7 -6
  47. package/dist/port-C54ykAOv.d.ts +301 -0
  48. package/dist/port-Drioh9al.d.cts +301 -0
  49. package/dist/portal-DRdmZ-xv.d.cts +331 -0
  50. package/dist/portal-or_f7BkT.d.ts +331 -0
  51. package/dist/{ports-TMWX-t9l.d.ts → ports-BeOgjwYl.d.ts} +2 -2
  52. package/dist/{ports-D8-iuY1P.d.cts → ports-s0D2jvqn.d.cts} +2 -2
  53. package/dist/react/index.cjs +58 -526
  54. package/dist/react/index.cjs.map +1 -1
  55. package/dist/react/index.d.cts +16 -1
  56. package/dist/react/index.d.ts +16 -1
  57. package/dist/react/index.js +55 -530
  58. package/dist/react/index.js.map +1 -1
  59. package/dist/realtime/index.d.cts +2 -2
  60. package/dist/realtime/index.d.ts +2 -2
  61. package/dist/{record-DpB2QgAZ.d.cts → record-BwCf9wKW.d.cts} +7 -1
  62. package/dist/{record-DpB2QgAZ.d.ts → record-BwCf9wKW.d.ts} +7 -1
  63. package/dist/relation-8vAWCa67.d.cts +230 -0
  64. package/dist/relation-eLMgv_dV.d.ts +230 -0
  65. package/dist/rule-D9yNiorf.d.ts +250 -0
  66. package/dist/rule-wHI5B0Ka.d.cts +250 -0
  67. package/dist/search/index.cjs +283 -0
  68. package/dist/search/index.cjs.map +1 -0
  69. package/dist/search/index.d.cts +44 -0
  70. package/dist/search/index.d.ts +44 -0
  71. package/dist/search/index.js +260 -0
  72. package/dist/search/index.js.map +1 -0
  73. package/dist/setup/index.cjs +6854 -0
  74. package/dist/setup/index.cjs.map +1 -0
  75. package/dist/setup/index.d.cts +87 -0
  76. package/dist/setup/index.d.ts +87 -0
  77. package/dist/setup/index.js +6829 -0
  78. package/dist/setup/index.js.map +1 -0
  79. package/dist/{subscription-D7KQBHXN.d.ts → subscription-BynsG1K6.d.ts} +3 -249
  80. package/dist/{subscription-BD9DnJxX.d.cts → subscription-CdoI-UaB.d.cts} +3 -249
  81. package/dist/{table-kind-BZu8mtND.d.cts → table-kind-DzctQ7dO.d.cts} +3 -558
  82. package/dist/{table-kind-xKxTHtrV.d.ts → table-kind-i3lZJa3f.d.ts} +3 -558
  83. package/dist/templates/index.d.cts +10 -9
  84. package/dist/templates/index.d.ts +10 -9
  85. package/dist/typed-table/index.cjs +22 -10
  86. package/dist/typed-table/index.cjs.map +1 -1
  87. package/dist/typed-table/index.d.cts +10 -7
  88. package/dist/typed-table/index.d.ts +10 -7
  89. package/dist/typed-table/index.js +22 -10
  90. package/dist/typed-table/index.js.map +1 -1
  91. package/dist/types-BKYEeFt4.d.cts +139 -0
  92. package/dist/{types-Dv61jStB.d.ts → types-BvL_oKFl.d.ts} +2 -2
  93. package/dist/{types-CLP5H4Wk.d.cts → types-D8qdG3Lg.d.cts} +2 -2
  94. package/dist/{types-C2uspRtf.d.cts → types-DAFP6XFe.d.cts} +2 -2
  95. package/dist/{types-DmPkWQic.d.ts → types-DYzXhD7j.d.ts} +2 -2
  96. package/dist/types-cpKY7Pjb.d.ts +139 -0
  97. package/dist/use-cases/index.d.cts +5 -5
  98. package/dist/use-cases/index.d.ts +5 -5
  99. package/dist/{validate-CWVToe1T.d.ts → validate-DbvAParj.d.ts} +1 -1
  100. package/dist/{validate-DEB_mn4Y.d.cts → validate-DfNMxjmU.d.cts} +1 -1
  101. package/dist/versions/index.cjs +375 -0
  102. package/dist/versions/index.cjs.map +1 -0
  103. package/dist/versions/index.d.cts +160 -0
  104. package/dist/versions/index.d.ts +160 -0
  105. package/dist/versions/index.js +353 -0
  106. package/dist/versions/index.js.map +1 -0
  107. package/package.json +62 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,105 @@
1
1
  # Changelog — @ai-matrx/records
2
2
 
3
+ ## 0.92.1
4
+
5
+ **`recordRead`'s version is opt-in: `recordRead({ record_id, withVersion: true })`.** 0.92.0 read the header on
6
+ every call, so a screen that draws first and versions later (the record form) waited for the slower of the two.
7
+
8
+ **Consumer action:** none for screens; a host that wants the version with the read passes `withVersion: true`.
9
+
10
+ ## 0.92.0
11
+
12
+ **A member of an archived organization is told so.** Every store door used to refuse an archived organization with
13
+ "You are not a member of that organization", even to its members. The store now says "This organization is archived"
14
+ (same refusal code `door`, the store's sentence and restore hint carried verbatim) with DETAIL
15
+ `organization_archived:<organization id>`. New `archivedOrganizationId(error)` (from `@ai-matrx/records` and
16
+ `@ai-matrx/records/core`) reads that organization out so a screen can offer "Restore" (the owner's
17
+ `iam.organization_restore` door). A non-member still gets the old sentence and `null` from it.
18
+
19
+ **The withheld note is said once.** For a reader who may not see a confidential measure, `custom.record_aggregate`
20
+ used to repeat the same `_withheld` explanation on every group row; the store now says it once (first row) and
21
+ `liftWithheld` puts it on every row's `row.withheld`, so totals and charts read exactly what they read before.
22
+
23
+ **Consumer action:** none. Hosts that read `measures._withheld` off the raw door (not through the client) must read it
24
+ from the first row.
25
+
26
+ ## 0.92.0
27
+
28
+ **New section `@ai-matrx/records/versions`** — the version rule for any screen a company builds, moved whole
29
+ from `@ai-matrx/records-ui`: `useRecordVersions` / `useTableVersion`, the write doors that carry the version
30
+ the person saw (`updateRecordAt`, `changeRecordsAt`, `movePipelineCardAt(s)`, `restoreAt`,
31
+ `updateOnTheWinningVersion`), `askOnce` (one question in flight per client) and `refusal` (a refusal shaped
32
+ like the store's own). React is the only peer it needs.
33
+
34
+ **`recordRead({ record_id, withVersion: true })` answers `version`.** The read asks the record's header in the
35
+ same round of requests, so a safe edit (`recordUpdate` with `expected_version`) needs no second call. `null`
36
+ when the version could not be read (the record still comes back). Off by default, so a screen that draws
37
+ before its version lands is never held back.
38
+
39
+ **Consumer action:** none. Hosts that read a record and then asked `recordHeaders` for its version can use
40
+ `read.data.version` instead.
41
+
42
+ ## 0.91.0
43
+
44
+ **`typedAnswersFor(fields, values)` in `@ai-matrx/records/forms`** — what a stranger typed on a public form or
45
+ booking page, turned into values against the Fields that page published, with one refusal sentence in question
46
+ order (moved whole from the website's `features/unified-data/typedAnswers.ts`). Every public door a company builds
47
+ coerces the same way the grid, the import and our own pages do.
48
+
49
+ **Consumer action:** hosts with their own copy (the website's `typedAnswers.ts`) import
50
+ `typedAnswersFor` from `@ai-matrx/records/forms` and delete the copy.
51
+
52
+ ## 0.90.0
53
+
54
+ **New section `@ai-matrx/records/setup`** — `createRecords({ auth: sessionAuth(supabase), organizationId })`:
55
+ one call that composes the typed client, live changes (one realtime manager over the session), search
56
+ across tables, platform records and a slot for the host's associations store. Signing in is a port
57
+ (`RecordsAuthPort`); an organization API key will plug in as a second mode without changing anything else.
58
+ The README opens with a quick start a company follows to list, create, edit, archive and watch records.
59
+
60
+ **Consumer action:** none.
61
+
62
+ ## 0.89.0
63
+
64
+ **New section `@ai-matrx/records/forms`** — the form document (flows, looks, endings, jumps, embeds,
65
+ the form doors' arguments) and which read a public address does, moved whole from `@ai-matrx/records-ui`
66
+ (`forms.ts`, `publicBinding.ts`), so a company's own screens can build and run forms without ours.
67
+
68
+ **New section `@ai-matrx/records/search`** — `searchRecords(dataSource, { search, tableIds?, organizationIds? })`
69
+ and `listStoreRecordCandidates(dataSource, { search })`: search across every table the person can see
70
+ through `custom.records_search` (never narrowed by the active organization), moved from the website.
71
+
72
+ **Consumer action:** `@ai-matrx/records-ui` users need none. Hosts with their own copy of record search
73
+ (the website's `storeRecordCandidates.ts`) call `listStoreRecordCandidates(supabase, args)` instead.
74
+
75
+ ## 0.88.1
76
+
77
+ **One data engine instance across sections.** `records/react` carried its own private copy of
78
+ `records/data/react` (its `DataPortContext` and host-event bus) because the build copies every module
79
+ into each entry that reaches it. It now imports the published `records/data/react`, as `records/entity/react`
80
+ does, so a `DataPortProvider` mounted from either section is the one every hook reads. The shared-state
81
+ gate gained a census: each module that holds React context or page-local state (data-engine provider,
82
+ seed provider, shape revisions) must live in exactly one section's dist files — proven red on a planted copy.
83
+
84
+ **Consumer action:** none.
85
+
86
+ ## 0.88.0
87
+
88
+ **New sections `@ai-matrx/records/entity` and `@ai-matrx/records/entity/react`** — the former
89
+ `@ai-matrx/entity-data` package, moved in whole (same API, same behaviour): platform records (contacts,
90
+ projects, tasks) through the entity doors, the entity `DataPort`, entity live notices, and the
91
+ token-first hooks (`EntityDataProvider`, `useEntityList`, `useEntityWrite`, …). `records/entity/react`
92
+ imports the published `records/react` and `records/data/react` instead of carrying a private copy, so
93
+ the providers a host mounted are the ones it reads.
94
+
95
+ The shared-state gate (`scripts/check-shared-state.mjs`, run on the packed tarball) now also proves an
96
+ entity write's op id lands in the one op ledger (ESM and CJS) and that `entity/react` holds no private
97
+ copy of the data-engine or seed providers.
98
+
99
+ **Consumer action:** replace `@ai-matrx/entity-data`, `@ai-matrx/entity-data/core` and
100
+ `@ai-matrx/entity-data/port` with `@ai-matrx/records/entity`, and `@ai-matrx/entity-data/react` with
101
+ `@ai-matrx/records/entity/react`; then drop the `@ai-matrx/entity-data` dependency.
102
+
3
103
  ## 0.87.32
4
104
 
5
105
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/README.md CHANGED
@@ -24,6 +24,69 @@ import {
24
24
  } from "@ai-matrx/records";
25
25
  ```
26
26
 
27
+ ## Quick start — our record store inside your own system
28
+
29
+ Everything a company needs to list, create, edit, archive and watch records from its own screens or
30
+ scripts, with none of ours. One package; each section loads only when imported.
31
+
32
+ ```sh
33
+ npm install @ai-matrx/records @supabase/supabase-js
34
+ ```
35
+
36
+ ```ts
37
+ import { createClient } from "@supabase/supabase-js";
38
+ import { createRecords, sessionAuth } from "@ai-matrx/records/setup";
39
+ import { ensureTable } from "@ai-matrx/records/core";
40
+
41
+ // 1. Sign in. The database address is https://db.matrxserver.com; the publishable key is on your
42
+ // AI Matrx account page. Any supabase-js sign-in works (password, magic link, SSO, server cookies).
43
+ const supabase = createClient("https://db.matrxserver.com", PUBLISHABLE_KEY);
44
+ await supabase.auth.signInWithPassword({ email, password });
45
+
46
+ // 2. One call. You choose the organization new records are saved in; reads span all of yours.
47
+ const matrx = await createRecords({ auth: sessionAuth(supabase), organizationId: (orgs) => orgs[0] ?? null });
48
+
49
+ // 3. A table (found by its slug, or made the first time), then records.
50
+ const table = await ensureTable(matrx.records, { name: "Service callbacks", slug: "service_callbacks",
51
+ fields: [{ key: "caller", label: "Caller", type: "text" }, { key: "phone", label: "Phone", type: "phone" }] });
52
+ if (!table.ok) throw new Error(table.error.message);
53
+ const tableId = table.data; // the table id
54
+
55
+ const created = await matrx.records.recordWrite({ table_id: tableId, data: { caller: "Marcus Delgado", phone: "+14155550178" } });
56
+ const page = await matrx.records.list({ table_id: tableId, limit: 50 }); // { rows, total }
57
+ const record_id = created.ok ? created.data : "";
58
+ const read = await matrx.records.recordRead({ record_id }); // .data.document
59
+ const heads = await matrx.records.recordHeaders({ ids: [record_id] }); // .data[0].version
60
+ const expectedVersion = heads.ok ? heads.data[0]?.version : undefined;
61
+ const edited = await matrx.records.recordUpdate({ record_id, patch: { phone: "+14155550199" }, expectedVersion }); // answers the new version
62
+ // Always send expectedVersion: a colleague's newer edit is then refused (`stale_write`, field by field), never overwritten.
63
+ const archived = await matrx.records.recordDelete({ record_id }); // soft: recordRestore brings it back
64
+
65
+ // 4. Live: other people's changes to this table (this setup's own writes are not echoed back).
66
+ const stop = matrx.watch(tableId, { records: (ids) => console.log("changed", ids) });
67
+
68
+ // 5. Search across every table you can see; platform records (contacts…) through matrx.entities.
69
+ const hits = await matrx.search({ search: "Delgado" });
70
+
71
+ stop(); matrx.close(); // a script closes the live socket before it exits
72
+ ```
73
+
74
+ Every call answers `{ ok: true, data } | { ok: false, error }` — the store's own sentence, never a
75
+ throw. React hosts add `@ai-matrx/records/react` or `@ai-matrx/records/data/react` hooks on the same
76
+ client; `@ai-matrx/records-ui` is our optional set of screens. Organization API keys plug into `auth`
77
+ as a second mode (planned); today `auth` is a signed-in session.
78
+
79
+ | Section | What |
80
+ |---|---|
81
+ | `records/setup` | `createRecords`, `sessionAuth` — the one call above |
82
+ | `records/core` | the typed client over every door (tables, records, versions, views, forms, totals) |
83
+ | `records/realtime` | the live-changes port setup uses |
84
+ | `records/search` | `searchRecords`, `listStoreRecordCandidates` |
85
+ | `records/forms` | the form document, embeds and which read a public address does |
86
+ | `records/entity`, `records/entity/react` | platform records (contacts, projects, tasks) |
87
+ | `records/data`, `records/data/react` | one data port and TanStack hooks over custom tables and entities |
88
+ | `records/react` | provider + hooks over the client |
89
+
27
90
  ## /core — the typed client over the doors
28
91
 
29
92
  ```ts
@@ -278,6 +341,58 @@ const { write, update, remove, conflict } = useRecordMutation();
278
341
  `live` is never quietly false: when realtime is not bound, `liveOffReason` says
279
342
  why in a sentence a screen can show.
280
343
 
344
+ ## /entity — platform records (contacts, projects, tasks) through the same port
345
+ Platform records (contacts, projects, tasks…) through the same `DataPort` an Applet reads a custom
346
+ table with. A thin typed client over the store's entity doors, and a host `DataPort` for entity
347
+ aliases, and token-first React hooks over records' one data engine (`@ai-matrx/records/data/react`).
348
+
349
+ **Reads and writes.** `create` saves into the active organization the host names (none → refused
350
+ `organization_required`), `update` sends the version the person saw (a stale one is refused with the
351
+ store's sentence), `archive` / `restore` move a row to the trash and back. **Lists are live** when the host passes `realtime: createEntityRealtime({ manager })`
352
+ (and `organization`, the active one): other people's changes arrive as `rows:<alias>` events naming the ids.
353
+
354
+ ```ts
355
+ import { createEntityDataPort } from "@ai-matrx/records/entity";
356
+ import { DataPortProvider, hostEvents, useDataRows } from "@ai-matrx/records/data/react";
357
+
358
+ const port = createEntityDataPort({
359
+ dataSource: supabase, // the signed-in person's supabase-js client
360
+ aliases: { contacts: { kind: "entity", token: "party", organizationId } },
361
+ });
362
+
363
+ // in React:
364
+ // <DataPortProvider port={port} events={hostEvents(port)} portKey="applet-1" queryClient={qc}>
365
+ // const { rows, hasMore, loadMore, error } = useDataRows("contacts", { org: organizationId, sort: [{ column: "display_name" }] });
366
+ ```
367
+
368
+ In a React app, name the type and let the engine do the rest:
369
+
370
+ ```tsx
371
+ import { EntityDataProvider, useEntityList, useEntityWrite } from "@ai-matrx/records/entity/react";
372
+
373
+ // once, high: <EntityDataProvider dataSource={supabase} activeOrganizationId={activeOrg}>…
374
+ const contacts = useEntityList("party", { where: [{ column: "last_name", op: "eq", value: "Ellis" }] });
375
+ const write = useEntityWrite("party");
376
+ await write.update(contacts.rows[0]._id, { first_name: "Ada" }); // drawn at once, rolled back on refusal
377
+ ```
378
+
379
+ ### Entries
380
+
381
+ | Entry | What |
382
+ |---|---|
383
+ | `@ai-matrx/records/entity` | `createEntityClient({ dataSource })` → `list`, `get`, `columns`, `insert`, `update`, `archive`, `unarchive`; `toWire`; `mapEntityError`; `createEntityDataPort({ client \| dataSource, aliases, activeOrganizationId })` → `HostDataPort` + `describe`; `createEntityRealtime` |
384
+ | `@ai-matrx/records/entity/react` | `EntityDataProvider`, `useEntityList`, `useEntityColumns`, `useEntityType`, `useEntityRow`, `useEntityWrite` |
385
+
386
+ ### Behaviour worth knowing
387
+
388
+ - The lane defaults to the type's own landing lane, decided by the store; `org` is a filter and never a lock.
389
+ - Paging is keyset: the cursor is the store's `next_after`.
390
+ - A filter or sort the store does not offer yet is refused by name with the store's sentence, never emulated in the browser.
391
+ - Custom fields read from `row._custom` and filter as `_custom.<key>`; a field the person may not read arrives `null`.
392
+ - A total that stopped at the store's count cap is reported as `null` (unknown), never as a wrong number.
393
+
394
+ Local mechanics: `src/entity/FEATURE.md`. Formerly the package `@ai-matrx/entity-data` (deprecated; same API, renamed imports: `/core` and `/port` → `records/entity`, `/react` → `records/entity/react`).
395
+
281
396
  ## Drill-down — declared definitions
282
397
 
283
398
  A server drill (`platform.drill_describe` / `platform.drill_ask`) answers a standard table from
@@ -1,8 +1,11 @@
1
- import { R as RelationCoordinate, 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, o as RecordsMerged, M as MigrationUndone, p as RelationWordsManyArgs, q as RelationIcons, r as ReverseColumn, s as ReverseLinksManyArgs, t as ReverseLinks, u as ReverseLinksFieldsArgs, S as SourceArchived, v as TableKindFacts, w as TableLevelFacts, x as TableReaderRule, y as TableLevelSet, E as EntityTableFacts, z as EntityFieldsAcross, N as NewEntityFieldDeclaration, B as EntityFieldRights, D as EntityRecordRead, G as EntityBackLinks, H as EntityRowWritten, I as EntityRecordsFound, P as Pipeline, J as PipelineColumn, K as PipelineVerdict, L as PipelineMoveResult, O as PipelineMoveManyItem, Q as PipelineMoveMany, U as PipelineSpec, V as PipelineDeclared, W as StageRuleOnFail, X as StageRuleEnforcement, Y as StagePending, Z as StagePendingOnBoard, _ as PipelineGate, $ as PipelineGatePreview, a0 as FormLookOptions, a1 as ImportPlan, a2 as ImportPolicy, a3 as ImportOpened, a4 as ImportColumnsDeclared, a5 as ImportBatchResult, a6 as ImportFinished, a7 as ImportReport, a8 as ImportRun, a9 as InboundDeclared, aa as InboundAddress, ab as PortalSummary, ac as PortalArchiveFilter, ad as PortalArchiveAnswer, ae as FormArchiveAnswer, af as ArchivedForm, ag as ArchivedChecklistTemplate, ah as TableRowDefaults, ai as TableRowDefaultsPatch, aj as RowDefaultsApplied, ak as RecordRowControls, al as PortalTableRef, am as PortalCard, an as PortalConfigInput, ao as PortalFormSpec, ap as PortalFormAnswer, aq as PortalInvitation, ar as PortalRevocation, as as PortalPreviewRow, at as CaptureSheetSummary, au as CaptureSheetFace, av as CaptureFileRef, aw as CaptureOutcome, ax as EnrichmentSummary, ay as EnrichDeclared, az as EnrichDueRow, aA as EnrichCell, aB as EnrichRun, aC as DrillSource, aD as DrillDefinition, aE as DrillQuestion, aF as DrillAnswer, aG as DrillRowsPage, aH as DocToken, aI as DocUnresolvedToken, aJ as DocTemplateRow, aK as DocRenderRow, aL as DocSignatureRow, aM as RecordHistoryEntry, aN as RecordScopeContext, aO as ConversationScope, aP as ConversationScopeContext, aQ as FieldHistoryEntry, aR as RestorePreview, aS as RestoreResult, aT as CommentThreadRead, aU as CommentWritten, aV as AnonTokenBinding, aW as ChecklistSpec, aX as ChecklistDeclared, aY as ChecklistTemplateSummary, aZ as ChecklistTemplateShape, a_ as ChecklistRunStarted, a$ as ChecklistRunStep, b0 as ChecklistRunSummary, b1 as ChecklistStepCompleted, b2 as WorkState, b3 as WorkGraph, b4 as WorkInstantiation, b5 as WorkTurn, b6 as WorkAssignmentField, b7 as WorkSlotHold, b8 as WorkInboxView, b9 as WorkInboxItem, ba as InboxStateChange, bb as InboxCounts, bc as WorkListFlavour, bd as WorkListItem, be as WorkAssignment, bf as WorkRecordState, bg as WorkApprover, bh as WorkChange, bi as WorkApprovalFiled, bj as WorkApprovalDecision, bk as WorkDecideManyItem, bl as WorkDecideMany, bm as ExternalPrincipalCard, bn as PublishBinding, bo as ResolvedPublishBinding, bp as ResolvedPublishBindingKind, bq as MyLevel, br as DecorationPath, bs as TableDecorations, bt as GridLayout, bu as FormulaParse, bv as FormulaPreview, bw as RowAction, bx as ActionRunResult, by as AutomationSpec, bz as AutomationDeclared, bA as AutomationList, bB as AutomationFlipped, bC as AutomationRuns, bD as RecordEvent, bE as TableWebhookDeclared, bF as TableWebhook, bG as IoExportPage, bH as TableListEntry, bI as DataHomeTable, bJ as TableSyncSpec, bK as TableSyncResult, bL as TableRowCount, bM as RecordHeader, bN as OutsideShareAnswer, bO as ViewOrderSet } from './table-kind-xKxTHtrV.js';
2
- import { d as StoreFilter, F as FormSummary, B as BookingSummary, e as BookingAvailability, f as BookingDeclared, g as FormRoute, h as FormResults, i as DashboardSummary, j as DashboardBlock, R as RecordFilter, k as AggregateCompare, c as AggregateBucket, l as DashboardRunResult, m as StuckRow, b as AggregateMeasure, n as AggregateRow, o as Subscription, M as MySubscription, p as SubscriptionSpec, q as DigestPreview, r as SavedViewRow, s as SavedViewSpecIn, t as RowTemplateRow } from './subscription-D7KQBHXN.js';
3
- import { b 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-BPABOJ2Y.js';
4
- import { f as Timestamp, U as Uuid, g as RecordsErrorCode, h as RecordDocument, i as RecordsResult, j as RecordChange, k as RecordChangeResult, l as RecordGraphWritten, m as RecordRead, n as ReadRow, o as RecordPageSort, p as RecordPage, q as RecordKeysetPage, r as StoredRecord, s as RecordRevision, t as ReadValue, R as RecordsError, W as WriteConflict } from './record-DpB2QgAZ.js';
5
- import { a as RecordsConfig } from './ports-TMWX-t9l.js';
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 MyLevel, b7 as DecorationPath, b8 as TableDecorations, b9 as GridLayout, ba as FormulaParse, bb as FormulaPreview, bc as RowAction, bd as ActionRunResult, be as AutomationSpec, bf as AutomationDeclared, bg as AutomationList, bh as AutomationFlipped, bi as AutomationRuns, bj as RecordEvent, bk as TableWebhookDeclared, bl as TableWebhook, bm as IoExportPage, bn as TableListEntry, bo as DataHomeTable, bp as TableSyncSpec, bq as TableSyncResult, br as TableRowCount, bs as RecordHeader, bt as OutsideShareAnswer, bu as ViewOrderSet } from './table-kind-DzctQ7dO.cjs';
2
+ import { d as StoreFilter, e as DashboardSummary, f as DashboardBlock, R as RecordFilter, g as AggregateCompare, c as AggregateBucket, h as DashboardRunResult, i as StuckRow, b 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-CdoI-UaB.cjs';
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-8vAWCa67.cjs';
4
+ import { b 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-CCY1rG9l.cjs';
5
+ import { F as FormSummary, B as BookingSummary, a as BookingAvailability, b as BookingDeclared, c as FormRoute, d as FormResults } from './rule-wHI5B0Ka.cjs';
6
+ 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-DRdmZ-xv.cjs';
7
+ import { T 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-BwCf9wKW.cjs';
8
+ import { a as RecordsConfig } from './ports-s0D2jvqn.cjs';
6
9
 
7
10
  /**
8
11
  * DOOR-8. As-of on EITHER clock, and they are different questions:
@@ -372,6 +375,8 @@ interface RecordsClient {
372
375
  recordRead(args: {
373
376
  record_id: Uuid;
374
377
  withComputed?: boolean;
378
+ /** Also answer `version` (read in the same round, so the read takes as long as the slower of the two). */
379
+ withVersion?: boolean;
375
380
  organization_id?: Uuid | null;
376
381
  }): Promise<RecordsResult<RecordRead>>;
377
382
  /**
@@ -1,8 +1,11 @@
1
- import { R as RelationCoordinate, 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, o as RecordsMerged, M as MigrationUndone, p as RelationWordsManyArgs, q as RelationIcons, r as ReverseColumn, s as ReverseLinksManyArgs, t as ReverseLinks, u as ReverseLinksFieldsArgs, S as SourceArchived, v as TableKindFacts, w as TableLevelFacts, x as TableReaderRule, y as TableLevelSet, E as EntityTableFacts, z as EntityFieldsAcross, N as NewEntityFieldDeclaration, B as EntityFieldRights, D as EntityRecordRead, G as EntityBackLinks, H as EntityRowWritten, I as EntityRecordsFound, P as Pipeline, J as PipelineColumn, K as PipelineVerdict, L as PipelineMoveResult, O as PipelineMoveManyItem, Q as PipelineMoveMany, U as PipelineSpec, V as PipelineDeclared, W as StageRuleOnFail, X as StageRuleEnforcement, Y as StagePending, Z as StagePendingOnBoard, _ as PipelineGate, $ as PipelineGatePreview, a0 as FormLookOptions, a1 as ImportPlan, a2 as ImportPolicy, a3 as ImportOpened, a4 as ImportColumnsDeclared, a5 as ImportBatchResult, a6 as ImportFinished, a7 as ImportReport, a8 as ImportRun, a9 as InboundDeclared, aa as InboundAddress, ab as PortalSummary, ac as PortalArchiveFilter, ad as PortalArchiveAnswer, ae as FormArchiveAnswer, af as ArchivedForm, ag as ArchivedChecklistTemplate, ah as TableRowDefaults, ai as TableRowDefaultsPatch, aj as RowDefaultsApplied, ak as RecordRowControls, al as PortalTableRef, am as PortalCard, an as PortalConfigInput, ao as PortalFormSpec, ap as PortalFormAnswer, aq as PortalInvitation, ar as PortalRevocation, as as PortalPreviewRow, at as CaptureSheetSummary, au as CaptureSheetFace, av as CaptureFileRef, aw as CaptureOutcome, ax as EnrichmentSummary, ay as EnrichDeclared, az as EnrichDueRow, aA as EnrichCell, aB as EnrichRun, aC as DrillSource, aD as DrillDefinition, aE as DrillQuestion, aF as DrillAnswer, aG as DrillRowsPage, aH as DocToken, aI as DocUnresolvedToken, aJ as DocTemplateRow, aK as DocRenderRow, aL as DocSignatureRow, aM as RecordHistoryEntry, aN as RecordScopeContext, aO as ConversationScope, aP as ConversationScopeContext, aQ as FieldHistoryEntry, aR as RestorePreview, aS as RestoreResult, aT as CommentThreadRead, aU as CommentWritten, aV as AnonTokenBinding, aW as ChecklistSpec, aX as ChecklistDeclared, aY as ChecklistTemplateSummary, aZ as ChecklistTemplateShape, a_ as ChecklistRunStarted, a$ as ChecklistRunStep, b0 as ChecklistRunSummary, b1 as ChecklistStepCompleted, b2 as WorkState, b3 as WorkGraph, b4 as WorkInstantiation, b5 as WorkTurn, b6 as WorkAssignmentField, b7 as WorkSlotHold, b8 as WorkInboxView, b9 as WorkInboxItem, ba as InboxStateChange, bb as InboxCounts, bc as WorkListFlavour, bd as WorkListItem, be as WorkAssignment, bf as WorkRecordState, bg as WorkApprover, bh as WorkChange, bi as WorkApprovalFiled, bj as WorkApprovalDecision, bk as WorkDecideManyItem, bl as WorkDecideMany, bm as ExternalPrincipalCard, bn as PublishBinding, bo as ResolvedPublishBinding, bp as ResolvedPublishBindingKind, bq as MyLevel, br as DecorationPath, bs as TableDecorations, bt as GridLayout, bu as FormulaParse, bv as FormulaPreview, bw as RowAction, bx as ActionRunResult, by as AutomationSpec, bz as AutomationDeclared, bA as AutomationList, bB as AutomationFlipped, bC as AutomationRuns, bD as RecordEvent, bE as TableWebhookDeclared, bF as TableWebhook, bG as IoExportPage, bH as TableListEntry, bI as DataHomeTable, bJ as TableSyncSpec, bK as TableSyncResult, bL as TableRowCount, bM as RecordHeader, bN as OutsideShareAnswer, bO as ViewOrderSet } from './table-kind-BZu8mtND.cjs';
2
- import { d as StoreFilter, F as FormSummary, B as BookingSummary, e as BookingAvailability, f as BookingDeclared, g as FormRoute, h as FormResults, i as DashboardSummary, j as DashboardBlock, R as RecordFilter, k as AggregateCompare, c as AggregateBucket, l as DashboardRunResult, m as StuckRow, b as AggregateMeasure, n as AggregateRow, o as Subscription, M as MySubscription, p as SubscriptionSpec, q as DigestPreview, r as SavedViewRow, s as SavedViewSpecIn, t as RowTemplateRow } from './subscription-BD9DnJxX.cjs';
3
- import { b 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-BanTVGK2.cjs';
4
- import { f as Timestamp, U as Uuid, g as RecordsErrorCode, h as RecordDocument, i as RecordsResult, j as RecordChange, k as RecordChangeResult, l as RecordGraphWritten, m as RecordRead, n as ReadRow, o as RecordPageSort, p as RecordPage, q as RecordKeysetPage, r as StoredRecord, s as RecordRevision, t as ReadValue, R as RecordsError, W as WriteConflict } from './record-DpB2QgAZ.cjs';
5
- import { a as RecordsConfig } from './ports-D8-iuY1P.cjs';
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 MyLevel, b7 as DecorationPath, b8 as TableDecorations, b9 as GridLayout, ba as FormulaParse, bb as FormulaPreview, bc as RowAction, bd as ActionRunResult, be as AutomationSpec, bf as AutomationDeclared, bg as AutomationList, bh as AutomationFlipped, bi as AutomationRuns, bj as RecordEvent, bk as TableWebhookDeclared, bl as TableWebhook, bm as IoExportPage, bn as TableListEntry, bo as DataHomeTable, bp as TableSyncSpec, bq as TableSyncResult, br as TableRowCount, bs as RecordHeader, bt as OutsideShareAnswer, bu as ViewOrderSet } from './table-kind-i3lZJa3f.js';
2
+ import { d as StoreFilter, e as DashboardSummary, f as DashboardBlock, R as RecordFilter, g as AggregateCompare, c as AggregateBucket, h as DashboardRunResult, i as StuckRow, b 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-BynsG1K6.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-eLMgv_dV.js';
4
+ import { b 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-enufS5ry.js';
5
+ import { F as FormSummary, B as BookingSummary, a as BookingAvailability, b as BookingDeclared, c as FormRoute, d as FormResults } from './rule-D9yNiorf.js';
6
+ 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-or_f7BkT.js';
7
+ import { T 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-BwCf9wKW.js';
8
+ import { a as RecordsConfig } from './ports-BeOgjwYl.js';
6
9
 
7
10
  /**
8
11
  * DOOR-8. As-of on EITHER clock, and they are different questions:
@@ -372,6 +375,8 @@ interface RecordsClient {
372
375
  recordRead(args: {
373
376
  record_id: Uuid;
374
377
  withComputed?: boolean;
378
+ /** Also answer `version` (read in the same round, so the read takes as long as the slower of the two). */
379
+ withVersion?: boolean;
375
380
  organization_id?: Uuid | null;
376
381
  }): Promise<RecordsResult<RecordRead>>;
377
382
  /**
@@ -120,6 +120,7 @@ __export(core_exports, {
120
120
  announceRecordChanged: () => announceRecordChanged,
121
121
  announceTableStructureChanged: () => announceTableStructureChanged,
122
122
  archivedByLine: () => archivedByLine,
123
+ archivedOrganizationId: () => archivedOrganizationId,
123
124
  archivedWhen: () => archivedWhen,
124
125
  asChoiceNudge: () => asChoiceNudge,
125
126
  asPermissionLevel: () => asPermissionLevel,
@@ -1627,9 +1628,18 @@ function stableFilterKey(filter) {
1627
1628
  return `{${parts.join(",")}}`;
1628
1629
  }
1629
1630
  function liftWithheld(rows2) {
1631
+ let shared;
1632
+ for (const row of rows2) {
1633
+ const m = (row.measures ?? {})["_withheld"];
1634
+ if (m !== void 0 && m !== null && typeof m === "object") {
1635
+ shared = m;
1636
+ break;
1637
+ }
1638
+ }
1630
1639
  return rows2.map((row) => {
1631
1640
  const measures = row.measures ?? {};
1632
- const marker = measures["_withheld"];
1641
+ const own = measures["_withheld"];
1642
+ const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
1633
1643
  const rowCount = row.row_count ?? 0;
1634
1644
  if (marker === void 0 || marker === null || typeof marker !== "object") {
1635
1645
  return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
@@ -2472,6 +2482,11 @@ function staleWriteDetail(error) {
2472
2482
  contested_fields: detail.contested_fields ?? {}
2473
2483
  };
2474
2484
  }
2485
+ function archivedOrganizationId(error) {
2486
+ if (error.code !== "door" || typeof error.detail !== "string") return null;
2487
+ const m = /^organization_archived:([0-9a-f-]{36})$/i.exec(error.detail.trim());
2488
+ return m ? m[1] : null;
2489
+ }
2475
2490
 
2476
2491
  // src/relation.ts
2477
2492
  var import_uuid4 = require("@ai-matrx/kit/uuid");
@@ -6883,24 +6898,27 @@ function createRecordsClient(given) {
6883
6898
  if (!pass.ok) return pass;
6884
6899
  return carryOnCopy(pass.data, onProgress);
6885
6900
  },
6886
- async recordRead({ record_id, withComputed = false, organization_id }) {
6901
+ async recordRead({ record_id, withComputed = false, withVersion = false, organization_id }) {
6887
6902
  if (organization_id && organization_id !== org) {
6888
- return clientFor(organization_id).recordRead({ record_id, withComputed, organization_id });
6903
+ return clientFor(organization_id).recordRead({ record_id, withComputed, withVersion, organization_id });
6889
6904
  }
6890
6905
  if (readOrgs(organization_id).length > 1) {
6891
6906
  return openInOwnOrg(
6892
6907
  record_id,
6893
6908
  organization_id,
6894
- (sub) => sub.recordRead({ record_id, withComputed, organization_id: sub.config.organizationId }),
6909
+ (sub) => sub.recordRead({ record_id, withComputed, withVersion, organization_id: sub.config.organizationId }),
6895
6910
  () => true
6896
6911
  );
6897
6912
  }
6898
- const door = await callDoor(
6899
- DOORS.readRecord,
6900
- { p_organization_id: org, p_record_id: record_id },
6901
- "recordRead"
6902
- );
6913
+ const [door, header] = await Promise.all([
6914
+ callDoor(DOORS.readRecord, { p_organization_id: org, p_record_id: record_id }, "recordRead"),
6915
+ // A version that cannot be read never takes the record away: it comes back as null.
6916
+ withVersion ? callDoor(DOORS.recordHeaders, { p_organization_id: org, p_ids: [record_id] }, "recordRead.version").catch(
6917
+ () => null
6918
+ ) : Promise.resolve(null)
6919
+ ]);
6903
6920
  if (!door.ok) return err(door.error);
6921
+ const version = header && header.ok ? header.data?.find((h) => h.id === record_id)?.version ?? null : null;
6904
6922
  const { document, hidden } = unfold(door.data);
6905
6923
  let computed = [];
6906
6924
  let computedUnavailable = null;
@@ -6913,7 +6931,7 @@ function createRecordsClient(given) {
6913
6931
  if (provenance.ok) computed = provenance.data ?? [];
6914
6932
  else computedUnavailable = provenance.error;
6915
6933
  }
6916
- return ok({ record_id, document, hidden, computed, computedUnavailable });
6934
+ return ok({ record_id, document, hidden, computed, computedUnavailable, ...withVersion ? { version } : {} });
6917
6935
  },
6918
6936
  async listByIds({ table_id, ids }) {
6919
6937
  if (ids.length === 0) return ok([]);