Skip to content

fix(interface-dms)!: move to interface-data-api 0.7's StoredRow - #888

Open
Upd4ting wants to merge 7 commits into
mainfrom
fix/interface-dms-stored-row
Open

Upd4ting wants to merge 7 commits into
mainfrom
fix/interface-dms-stored-row

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

ANT-2384. interface-data-api 0.7.0 replaced the published RowFields with StoredRow. @antelopejs/interface-dms 0.13.3 still names RowFields in its published declarations and accepts data-api >=0.6.0 <1.0.0. A fresh project resolves data-api 0.7, so a module the Builder's Connect generates fails tsc.

⚠ sensitive: this changes the interface-dms contract (its published declarations and peer range).

tgz-pending: interface-data-api 0.8.0 is not released. It comes from data-api main (170f079: #129 decorators-0.5 declarations, #133 every DefaultRoutes query through .run(), #134 FilterValue holds a boolean) through .tgz-deps/antelopejs-interface-data-api-170f079.tgz, packed as 0.8.0. swap-tgz.sh restores >=0.8.0 <0.9.0 once 0.8.0 ships.

Summary

 @antelopejs/interface-dms
-  peer interface-data-api >=0.6.0 <1.0.0
+  peer interface-data-api >=0.8.0 <0.9.0
-  DataType.filter(…, value: string, …)
+  DataType.filter(…, value: FilterValue[0], …)   // string | boolean; compare modes get String(value)
   dist/base/table-view/routes.d.ts  (TableViewRoutes.Get, Edit, get, edit)
-    DataControllerCallback<…, import("@antelopejs/interface-data-api/metadata").RowFields, …>
+    DataControllerCallback<…, import("@antelopejs/interface-data-api/metadata").StoredRow, …>
   internal/column-conditions.ts
-    row: RowFields
+    row: GuardRow   // NonNullable<Awaited<ReturnType<typeof fetchRowForGuard>>>

 @antelopejs/dms
-  RowFields in guard-row, footer-summary, search-route, table-view, invite routes, export jobs, row rules
+  StoredRow
-  String(row[idField])
+  rowIdText(row[idField])   // same text for primitives and dates; refuses a row, list or document id
   interface-database-decorators >=0.3.1  ->  >=0.5.2

Why decorators move: data-api 0.8 declares its modifier keys as Class<ContainerModifier> and requires decorators >=0.5.0. Decorators 0.3.1's LocalizationModifier does not satisfy that type (TS2345 in src/test/attachment-host/native.ts). With decorators 0.5.2 the workspace typechecks on interface-database 0.3.1, and the unit suite passes on mongodb 1.6.2. The interface-database 0.4.0 move stays in its own PR (ANT-2382).

The ContainerModifier TS2635 in the task comes from data-api's own declarations: data-api 0.7.1 and 0.6.3 write typeof ContainerModifier<any>, which decorators 0.5.x refuses. data-api 0.8 fixes it, so the new floor covers it.

Why DataType.filter widens: data-api 0.8 types a filter value as string | boolean, because the archive filter hands its field's filter the boolean true. DataType.filter takes that type and hands its compare mode String(value), which the value parser reads back as the same boolean; the date type's override reads it as text. With the type honest, archiveFilter returns [true, mode], and its SAFETY: comment and true as unknown as string go (SAFETY: 37 → 36, no-chained-type-assertions 1 → 0). packages/interface-dms/UPGRADING.md has an Unreleased section with these changes.

Evidence

Consumer typecheck of a module the Builder generates. It is produced by the engine (MapResources on a two-table catalog with a relation, then scaffoldLocalModule) with the Builder's default compiler options and no hand edit. It is installed from public npm with interface-database 0.4.0, decorators 0.5.2, interface-core 0.5.1 and interface-api 0.3.2. Then npx tsc --noEmit -p .:

  • Before: published interface-dms 0.13.3 with data-api 0.7.1, exit 2:
    node_modules/@antelopejs/interface-data-api/dist/metadata.d.ts(39,48): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable.
    node_modules/@antelopejs/interface-data-api/dist/metadata.d.ts(166,74): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable.
    node_modules/@antelopejs/interface-data-api/dist/metadata.d.ts(278,76): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable.
    node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(12,115): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'.
    node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(44,117): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'.
    node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(77,122): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'.
    node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(86,124): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'.
    
    After: interface-dms packed from this branch with the data-api tarball (then 2def09c, packed as 0.7.2): tsc exits 0 with no output.
  • Forcing data-api 0.6.3 under this branch's interface-dms fails on StoredRow at the same four lines, so the floor is needed.
  • Workspace:
    • pnpm run typecheck passes.
    • pnpm --dir packages/dms test:unit (backend-checks included) passes 2629 and integration 419 on data-api 0.8.0, including the new rowIdText tests.
    • interface-dms node --test tests/*.test.mjs passed 180/180 before the decorators bump. After it, 179/180, with the one failure being the time-bound test payloads: 200000 fields in the body itself are accepted in time and in memory (2893 ms, under a host load average of 62).
  • CI on 2199302 (rebased on main after fix(test): split long unit test callbacks and resync the dms README #889): every check passes.

Merge Danger

Door: two-way in the repo. The published contract is one-way once released: interface-dms requires data-api >=0.8.0 <0.9.0, so a module on data-api 0.6 must move with it.

Blast Radius: wide. It covers every module that types against TableViewRoutes.Get or Edit, and every project's data-api and decorators versions. dms-saas and dms-database consume this branch.

@Upd4ting Upd4ting added the tgz-pending Waits for a release; holds a .tgz-deps tarball label Nov 13, 2026
@Upd4ting
Upd4ting force-pushed the fix/interface-dms-stored-row branch 3 times, most recently from 1a95aba to 36f5d06 Compare November 13, 2026 17:54
@Upd4ting
Upd4ting force-pushed the fix/interface-dms-stored-row branch from 36f5d06 to b672b01 Compare November 13, 2026 19:11
Upd4ting added a commit that referenced this pull request Nov 13, 2026
…ements them and break the table-view/data-types cycle (#904)

Part of ANT-1088: every suppression in `guardrails.suppressions.json`
goes, by fixing the code it hides. Some suppressions existed only
because a **published** type said something the runtime does not do.
Antony decided to fix those types in one **breaking** PR, together with
the last interface-dms import cycle (cycle A, table-view ↔ data-types).

⚠ sensitive: it changes the interface-dms contract (published
declarations, a required export-ownership schema) and module evaluation
order. Export access now refuses a stored context its schema rejects.

Every break is listed with its TypeScript error and migration in
`packages/interface-dms/UPGRADING.md` (Unreleased) and
`packages/dms/docs/02.building/18.migration-0-13-to-0-14.md`.

## Summary

| Change | Before | After | Suppression removed |
| --- | --- | --- | --- |
| Table-view data function receivers: `listWithSearch`,
`countWithSearch`, `summarizeWithSearch`, `startExport`,
`getExportStatus`, `downloadExport`, `validateRowsAgainstRule`,
`fetchRowForGuard`, `RowBulkOperationParams` | `DataControllerCallback
\| DataControllerCallbackWithOptions` | `DataControllerInstance` (what
every route passes as `this`) | nav-badges `SAFETY:` cast |
| `ExportJobGenerateContext.context` | `TContext` | `TContext \|
undefined` (a job may start without one) | `export-jobs-run.ts`
`SAFETY:` cast |
| Export ownership | `isOwnedBy(record, context: TContext)` on unparsed
stored JSON | `isOwnedBy` must come with `contextSchema` (zod); the
stored context is parsed through it, and a refused one answers 403 |
`export-jobs-run.ts` `no-unsafe-assignment` |
| `TableViewRoutes.ExportRoutes` | `Record<string,
DataControllerCallback \| …>` | its three typed routes, carried by
`TableViewRoutes.All`, members and roles | `no-known-value-widening` |
| `TableViewMeta.footerSummary` | `TableViewFooterSummary<any> \|
undefined` | `TableViewFooterSummary \| undefined`, checked when
declared | `routes.ts` `no-unsafe-assignment` |
| `DmsCascader` props, and the Cascader `fallback` option | six props
declared, never read; `fallback` forwarded to the picker | removed | — |
| Cycle A | `table-view/meta` ↔ data-types barrel ↔ `default-types`,
plus a lazy `require` in `relation-endpoints` | `default-types` no
longer imports `table-view/meta`; `relation-endpoints` reads the class
from a slot that `TableViewMeta` fills from its static block | 3
`import/no-cycle`, 1 `no-unsafe-assignment` |

```diff
 base/data-types/default-types
-  -> table-view/meta                        (the cycle edge)
 base/data-types/internal/relation-endpoints
-  require("table-view/meta")                (lazy require)
+  -> internal/table-view-meta-slot          (new @internal leaf, filled by TableViewMeta's static block)
```

Budget against main:
- `import/no-cycle` 3 → 0
- `typescript/no-unsafe-assignment` 5 → 2
- `anti-slop/no-known-value-widening` 2 → 1
- `SAFETY:` 37 → 35

Nothing rises.

## Evidence

- **Break forms, compiled.** A scratch consumer compiled against main
and against this branch confirms each break and its error code in the
upgrade notes: TS2345, TS2322, TS2558, TS2739, TS7053, TS18048, TS2312,
TS2422, TS2416, TS2425, TS2353.
- **Every new test fails on a wrong implementation**, each broken once
on purpose:
- `export-job-access.test.mjs` (interface-dms): fails when the schema is
skipped, and when raw JSON is read instead of the parsed context.
  - `table-view-export-access.test.ts` (integration):
- status and download refuse another table view's job with 403 and serve
the job's own table view;
- it fails with `isOwnedBy` always true, when the controller key is
ignored, and when `downloadExport` drops the access check.
- `built-in-data-type-registration.test.mjs` loads 11 entries, each in a
fresh process, and serializes 23 built-ins.
- **Before:** with `table-view/meta` importing `data-types/core` instead
of the barrel, 2 of 11 entries fail.
    - **After:** 11 of 11 pass.
    - Emptying the slot makes 3 existing dms relation tests fail.
- **Cycle A evaluation order.** A built probe runs the 34 entries that
reach the cycle, each in its own process.
- Proxy insertions, event proxies and identities are identical in all
34.
  - 31 half-evaluated reads disappear, and none appear.
  - The module moves are listed under Attention.
- The only registry change is that `default-types`, loaded alone, no
longer registers `status`.
- An independent check loaded all 337 dist modules alone on base and
head and found the same single change.
- **Suites:**
  - `pnpm run checks` 11 passed.
  - interface-dms tests 194.
  - `test:unit` 2627, integration 420.
- frontend-vue typecheck passes; vitest 3506 passed, 1 skipped. The
playground typechecks.
- **api-diff** `origin/main --allow-added '**/internal/**'` exits 1 by
design. The declaration differences are the changes in the table above,
in 24 subpath declaration files.
  - Auto-imports: 944 entries unchanged.
  - Added (allowed): `base/data-types/internal/table-view-meta-slot`.
- `readExportJobContext`, a new `@internal` function in the existing
internal module `base/internal/export-jobs`, shows as a runtime addition
rather than an allowed one; api-diff allows only additions in new
modules.
- `KeyValueType$1` moves between two declarations in the bundled
`base/index`: a bundler alias artefact, with the same exported type.
- The dms runtime comparison cannot complete: api-diff builds base's dms
against this branch's interface, which base's export options no longer
satisfy. That is the break itself.
- The output is 158 KB, too large for this body, so it is summarised
here.
- **Independent review** (claude-sonnet-5-5): no blocker. Its findings
are fixed here: the Cascader `fallback` option, the download test, and
the TS2422/TS2312 and `json_context` notes. The 500 for an untyped
caller is stated under Attention.

## Attention

- **Cascader attributes.** `FormFieldControl` still passes
`initialValue`, `loading`, `componentId`, `pageId` and `routeParams` to
every field component. On `DmsCascader` they now land on its root
`<div>` as attributes (`route-params="[object Object]"` among them), as
they already do on sibling field components that do not declare them.
The root cause, `FormFieldControl` passing them to everything, is a
follow-up.
- **`status` registration.** `base/data-types/default-types`, loaded
alone, no longer registers `status`. Every entry that serializes a type
(the barrel, any table-view entry) still registers all built-ins.
- **Evaluation order.** `base/index`, `data-controllers/*` and the dms
runtime now load `table-view/meta` inside `table-view/factory`. Some
`base/data-types` and `table-view/internal` entries no longer load
`table-view/meta` at all. Where `table-view/meta` finishes loading,
every built-in is now registered; on main, most were not yet.
- **Ownership check.**
- A job started without a context is stored as `"null"` and is now
refused under an object schema. The upgrade notes state this.
- A JavaScript caller that passes `isOwnedBy` without `contextSchema`
gets a 500 (`TypeError`) before its check runs. It still fails closed;
the types forbid that call.
  - `json_context` is now parsed only when an ownership check runs.
- **Not in this PR:**
- `RelationType`'s `fallback` option is never read either. It is the
same kind of lie, but outside this scope.
- The `runExportJobProxy` `SAFETY:` and the `authorizeAction(thisObj:
unknown)` directive could now take `DataControllerInstance`: a
follow-up.
- The `archiveFilter` cast went into #888, since it needs data-api 0.8.
- **Migration guide name.** It is named for the next interface release
line (0.13 → 0.14), following the existing guides' naming.

## Merge Danger

**Door:** one-way once released. Modules that implement export
ownership, type against the table-view data functions, `ExportRoutes` or
`footerSummary`, or pass the Cascader `fallback` must migrate. In the
repo it is two-way.

**Blast Radius:** wide. Every module on interface-dms that touches
table-view data functions, exports, footer summaries or Cascader fields,
plus the load order of interface-dms entries.
@Upd4ting
Upd4ting force-pushed the fix/interface-dms-stored-row branch from b672b01 to ca837f0 Compare November 13, 2026 19:30
interface-data-api 0.7 removed RowFields, which interface-dms 0.13.3 names in its published declarations, so a project that resolves data-api 0.7 fails tsc. interface-dms and dms now build against data-api 0.7 and name StoredRow. The guard-row read in column-conditions is typed from the published fetchRowForGuard, and dms reads a row id as text through rowIdText, which refuses an id holding a row, a list or a document.
…tarball

interface-data-api main (d70049c, #129) declares the decorators-0.5 ContainerModifier fix, packed as 0.7.2. The tarball stands in for the release until it ships; interface-dms requires >=0.7.2 <0.8.0.
interface-data-api 0.7.2 declares its modifier keys as Class<ContainerModifier> and requires decorators >=0.5.0; decorators 0.3.1's LocalizationModifier does not satisfy it. dms, the playground and interface-dms's development build move to decorators >=0.5.2.
… run every query

interface-data-api #133 runs each DefaultRoutes query through .run(), which interface-database 0.4 needs. Packed as 0.7.2 like the tarball it replaces.
…terValue holds a boolean

interface-data-api 0.8 types a filter value as string | boolean (ANT-2463). DataType.filter takes that value and hands its compare mode String(value), which the value parser reads back as the same boolean; the date type's override reads it as text. interface-dms and dms require data-api >=0.8.0 <0.9.0.
interface-data-api 0.8 types a filter value as string | boolean, so archiveFilter returns [true, mode] as typed and the SAFETY comment and chained assertion go.
@Upd4ting
Upd4ting force-pushed the fix/interface-dms-stored-row branch from ca837f0 to 42b25e5 Compare November 13, 2026 20:10

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tgz-pending Waits for a release; holds a .tgz-deps tarball

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant