Skip to content

fix(metadata): declare modifier classes without type arguments for decorators 0.5 - #129

Merged
Upd4ting merged 1 commit into
mainfrom
fix/decorators-0-5-container-modifier
Nov 13, 2026
Merged

Upd4ting merged 1 commit into
mainfrom
fix/decorators-0-5-container-modifier

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

Why

@antelopejs/interface-database-decorators 0.5.0 dropped ContainerModifier's type parameters. interface-data-api up to 0.7.1 still emits typeof ContainerModifier<any> in dist/metadata.d.ts. Every project on decorators 0.5.x then fails to typecheck with TS2635, and skipLibCheck is forbidden in our projects. This PR makes the published declarations typecheck against decorators 0.5 and adds a test that checks them the way a consumer does.

What

  • DataAPIMeta.modifierKeys, DataAPIMeta.setModifierKey and the @ModifierKey decorator take a Class<ContainerModifier>, a construct signature with no type arguments, instead of typeof ContainerModifier<any>. LocalizationModifier and every other subclass are accepted. docs/9.modifiers.md shows the new signature.
  • No spelling types precisely under both decorators lines. Under 0.2, ContainerModifier's Meta parameter is contravariant through unlockrequest, so a plain construct signature rejects LocalizationModifier; a version-neutral form would have to widen to any TwoWayModifier. So the decorators peer range rises from >=0.1.10 <1.0.0 to >=0.5.0 <1.0.0.
  • Dev dependencies: decorators ^0.5.2, interface-database ^0.3.3. The test project's @antelopejs/mongodb module moves from 1.4.4 to 1.7.0, the release that implements interface-database 0.3 (Schema.list, which decorators 0.5 calls). The README peer table reads the new floor and the tested versions.
  • New src/tests/index/consumer_declarations.test.ts runs in pnpm test. It type-checks a consumer module against the built dist declarations, resolved through the package name, with skipLibCheck: false and the installed decorators 0.5.2. The consumer declares a DataController with @ModifierKey(LocalizationModifier) and uses Query, Validation and StoredRow.
flowchart LR
  consumer["consumer.ts (skipLibCheck: false)"] --> dts["dist/*.d.ts of interface-data-api"]
  dts --> dec["interface-database-decorators 0.5.2 declarations"]
  dts -- "before: typeof ContainerModifier<any>" --> err["TS2635"]
  dts -- "now: Class<ContainerModifier>" --> ok["no diagnostics"]
Loading

Attention

  • Peer floor. @antelopejs/interface-database-decorators must now be >=0.5.0. A project on decorators 0.2 to 0.4 has to upgrade its decorators with this release. The upgrade note for the docs(changelog) PR after the release:

    - `@antelopejs/interface-database-decorators` must be `>=0.5.0` ([#129](https://github.com/AntelopeJS/interface-data-api/pull/129)). `@ModifierKey`, `DataAPIMeta.setModifierKey` and `DataAPIMeta.modifierKeys` take a `Class<ContainerModifier>`; 0.7.1 and earlier fail to typecheck on decorators 0.5 with TS2635.
  • Declarations. Only the three signatures above change. Runtime exports are identical.

  • antelopejs-api-diff origin/main cannot build its base, because origin/main does not compile against decorators 0.5. The comparison below builds origin/main with its own lockfile instead.

Deprecated RowFields alias

@antelopejs/interface-data-api/metadata exports RowFields again, as type RowFields = StoredRow marked @deprecated. interface-dms 0.12 and 0.13 name RowFields in their published declarations, as the result type of their get and edit routes. The alias keeps them compiling against data-api 0.7.x until ANT-2384 lands. It is a real type, not unknown.

Checked both ways in a scratch project with this branch packed, @antelopejs/interface-dms 0.13.3, decorators 0.5.2 and interface-core 0.5.1, tsc with skipLibCheck: false over every interface-dms module that names RowFields. With the alias there are no diagnostics. With it removed from the packed declarations:

node_modules/@antelopejs/interface-dms/dist/base/table-view/internal/guards.d.ts(15,138): error TS2694: Namespace '"node_modules/@antelopejs/interface-data-api/dist/metadata"' has no exported member '
node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(12,115): error TS2694: Namespace '"node_modules/@antelopejs/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 '"node_modules/@antelopejs/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 '"node_modules/@antelopejs/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 '"node_modules/@antelopejs/interface-data-api/dist/metadata"' has no exported member 'RowFields

The consumer test also assigns a StoredRow to RowFields and checks that DefaultRoutes.Get answers a RowFields.

SAFETY comments added

None. The suppression budget is unchanged.

Proof

pnpm run checks: 11 passed, 0 failed, including 219 + 1 tests on decorators 0.5.2 and mongodb 1.7.0. pnpm exec tsc -p docs/tsconfig.json passes.

The new test, with the built dist/metadata.d.ts put back to typeof ContainerModifier<any>:

  Published declarations
    1) type-check in a consumer module with library checks on


  0 passing (6s)
  1 failing

  1) Published declarations
       type-check in a consumer module with library checks on:

      AssertionError: expected [ …(3) ] to deeply equal []
      + expected - actual

      -[
      -  "TS2635 dist/metadata.d.ts: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable."
      -  "TS2635 dist/metadata.d.ts: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable."
      -  "TS2635 dist/metadata.d.ts: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable."
      -]
      +[]
      



On this branch:

  Published declarations
    ✔ type-check in a consumer module with library checks on (4064ms)

  1 passing (4s)

Declarations, origin/main built with its own lockfile against HEAD. Every other .d.ts is identical:

--- dist/metadata.d.ts	2026-11-13 12:15:09.635900447 +0000
+++ dist/metadata.d.ts	2026-11-13 12:14:45.943498026 +0000
@@ -36,7 +36,7 @@
     /** Key of the DataAPI class containing a database table instance. */
     modelKey?: string;
     /** Keys of the DataAPI class containing database modifier keys. */
-    modifierKeys: Map<typeof ContainerModifier<any>, string>;
+    modifierKeys: Map<Class<ContainerModifier>, string>;
     /** Schema name where the table is registered. */
     schemaName: string;
     /** Database Schema class. */
@@ -163,7 +163,7 @@
      * @param name Field name
      * @param modifierClass Modifier
      */
-    setModifierKey(name: string, modifierClass: typeof ContainerModifier<any>): this;
+    setModifierKey(name: string, modifierClass: Class<ContainerModifier>): this;
     /**
      * Adds the given endpoint to the DataAPI
      *
@@ -275,5 +275,5 @@
  *
  * @param modifierClass Modifier
  */
-export declare const ModifierKey: (modifierClass: typeof ContainerModifier<any>) => import("@antelopejs/interface-core/decorators").PropertyDecorator;
+export declare const ModifierKey: (modifierClass: Class<ContainerModifier>) => import("@antelopejs/interface-core/decorators").PropertyDecorator;
 export declare function GetDataControllerMeta(thisObj: DataControllerInstance): DataAPIMeta;

Runtime exports of index, metadata and components (names and typeof), compared the same way: identical, 27 names.

@Upd4ting
Upd4ting merged commit d70049c into main Nov 13, 2026
8 checks passed
@Upd4ting
Upd4ting deleted the fix/decorators-0-5-container-modifier branch November 13, 2026 12:17
Upd4ting added a commit that referenced this pull request Nov 13, 2026
## Why

The verify-interface harness compiled the consumer shop with
`--skipLibCheck`. The packed interface is linked into the shop's
`node_modules`, so its declarations were never checked. A declaration
error like the TS2635 fixed in #129 passed every journey. Consumers on
decorators 0.5 hit it, and in our projects `skipLibCheck` is forbidden.
The shop is now type-checked the way those consumers compile it.

## What

- `.agents/skills/verify-interface/harness.ts`: `TSC_FLAGS` drops
`--skipLibCheck`. Every journey that compiles the shop,
`metadata/consumer-compiles` included, now checks the packed
declarations and the declarations of the interfaces they import. The
shop compile cache key includes the flags, so no compile from the old
flags is reused.
- The harness's `@antelopejs/mongodb` module moves from 1.4.4 to 1.7.0.
Since #129 the repository runs on decorators 0.5, which calls
`Schema.list`. mongodb 1.4.4 lacks it, so every shop journey failed to
start (`TypeError: interface_database_1.Schema.list is not a function`).
#129 made the same move for `pnpm test`, and I missed the verify harness
there.

```mermaid
flowchart LR
  pack["packed interface-data-api"] --> link["linked into shop/node_modules"]
  link --> tsc["tsc shop.ts (no --skipLibCheck)"]
  tsc -- "declaration error" --> fail["consumer-compiles FAIL"]
  tsc -- "clean" --> run["shop starts on mongodb 1.7.0"]
```

## Proof

Verify run on this head (`antelopejs-verify journey <run> --features`
with all 13 features): 55 of 55 journeys pass.

`metadata/consumer-compiles` with the run's packed `dist/metadata.d.ts`
put back to the 0.7.1 declaration (`typeof ContainerModifier<any>`):

```
FAIL metadata/consumer-compiles (14.9 s)
    07-compile-the-shop-against-the-packed-declarations: the shop compiles against the packed declarations (../../../pack/package/dist/metadata.d.ts(39,48): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable.
../../../pack/package/dist/metadata.d.ts(166,74): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable.
../../../pack/package/dist/metadata.d.ts(278,76): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable.
)
    critical step 07-compile-the-shop-against-the-packed-declarations failed
```

With the packed declaration restored:

```
PASS metadata/consumer-compiles (10.7 s)
```

The same bad declaration under the old flags (`--skipLibCheck` restored
in the harness, uncommitted, on an earlier run of this branch):

```
PASS metadata/consumer-compiles (3.9 s)
```

Before the mongodb move, on the first run of this branch, every shop
journey failed at `ready`, with `TypeError:
interface_database_1.Schema.list is not a function` in the `ajs project
dev` stderr. After it, all 55 pass.

`pnpm run checks`: 11 passed, 0 failed. The harness is not part of the
published package:

```
API: 1 packages, 27 entries unchanged against origin/main (committed HEAD).
API: skipped .agents/skills/formal-field-access, private.
API: skipped .agents/skills/verify-interface, private.
API: skipped test-helper entry ./dist/*.d.ts in .; test helpers need a test runner and are outside both proof halves.
Runtime API: 1 packages, 24 entries unchanged against origin/main (committed HEAD).
Runtime API: skipped test-helper entry ./dist/*.js in .; test helpers need a test runner and are outside both proof halves.
No behavioural probe ran.

Suppressions in authored code files (origin/main and committed HEAD). A lint directive counts once per rule it names; `*` is a directive naming none.
| Suppressions | base | HEAD |
| --- | ---: | ---: |
| Lint suppressions, all rules | 0 | 0 |
| `@ts-expect-error` | 0 | 0 |
| `@ts-ignore` | 0 | 0 |
| `SAFETY:` comments | 3 | 3 |
| Lint config rule-offs, all rules | 0 | 0 |
<!-- antelopejs-proof base=d70049cabad1dbbc12372aedf4de8c149ff3451a head=ae6e8f7bea3a7468008895453b9f3f4976592d13 lines=15 digest=a25aa94954cad44a command: antelopejs-api-diff origin/main -->
```
Upd4ting added a commit that referenced this pull request Nov 13, 2026
## Why

interface-dms 0.12 and 0.13 name `RowFields` from
`@antelopejs/interface-data-api/metadata` in their published
declarations, as the result type of their `get` and `edit` routes. 0.7.0
removed that name in favour of `StoredRow` (#126). Every consumer
type-checking interface-dms against data-api 0.7.x then fails with
TS2694. This PR brings the name back as a deprecated alias, so
interface-dms 0.13.3 type-checks as it is until ANT-2384 moves it to
`StoredRow`. It is the alias commit that reached #129's branch after
that PR merged, cherry-picked onto main.

## What

- `src/internal/field-types.ts`: `export type RowFields = StoredRow`,
documented `@deprecated Use StoredRow`. It is a real type, not
`unknown`.
- `src/metadata.ts` exports it next to `StoredRow`.
- `src/tests/index/consumer_declarations.test.ts`: the consumer module
also imports `RowFields`, assigns a `StoredRow` to it, and checks that
`DefaultRoutes.Get` answers a `RowFields`.

## Attention

One addition to the published declarations, no removal: `RowFields` in
`metadata` (and in its `@internal` source module). Runtime exports are
unchanged. `antelopejs-api-diff` reports the addition as a difference;
the output is below.

## Proof

**Both ways, against interface-dms 0.13.3.** A scratch project with this
head packed, `@antelopejs/interface-dms` 0.13.3, decorators 0.5.2 and
interface-core 0.5.1, one copy of each. It runs `tsc` with
`skipLibCheck: false` over every interface-dms module that names
`RowFields`: the index, `data-controllers/roles`,
`data-controllers/members`, `base/table-view/routes` and
`base/table-view/internal/guards`.

With the alias: no diagnostics, exit 0.

With `RowFields` removed from the packed `dist/metadata.d.ts`:

```
node_modules/@antelopejs/interface-dms/dist/base/table-view/internal/guards.d.ts(15,138): error TS2694: Namespace '"node_modules/@antelopejs/interface-data-api/dist/metadata"' has no exported member '
node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(12,115): error TS2694: Namespace '"node_modules/@antelopejs/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 '"node_modules/@antelopejs/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 '"node_modules/@antelopejs/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 '"node_modules/@antelopejs/interface-data-api/dist/metadata"' has no exported member 'RowFields
```

**In-repo consumer test**, with `RowFields` removed from the built
`dist/metadata.d.ts`:

```
  Published declarations
    1) type-check in a consumer module with library checks on
  0 passing (6s)
  1 failing
  1) Published declarations
       type-check in a consumer module with library checks on:
      AssertionError: expected [ Array(1) ] to deeply equal []
      + expected - actual
      -[
      -  "TS2305 consumer-check/consumer.ts: Module '\"@antelopejs/interface-data-api/metadata\"' has no exported member 'RowFields'."
      -]
      +[]
```

On this head it passes, inside `pnpm run checks`: 11 passed, 0 failed.

```
API: differences against origin/main (committed HEAD).
diff --git a/base/_root/exports/subpath/internal%2Ffield-types.d.ts b/head/_root/exports/subpath/internal%2Ffield-types.d.ts
index d897d49..24e6da8 100644
--- a/base/_root/exports/subpath/internal%2Ffield-types.d.ts
+++ b/head/_root/exports/subpath/internal%2Ffield-types.d.ts
@@ -159,6 +159,7 @@ export interface ReadableAccessFields {
         FieldData
     ][];
 }
+export type RowFields = StoredRow;
 export interface StoredRow {
     [field: string]: StoredValue;
 }
diff --git a/base/_root/exports/subpath/metadata.d.ts b/head/_root/exports/subpath/metadata.d.ts
index 05e8c4f..844ba45 100644
--- a/base/_root/exports/subpath/metadata.d.ts
+++ b/head/_root/exports/subpath/metadata.d.ts
@@ -185,6 +185,7 @@ export interface ReadableAccessFields {
         FieldData
     ][];
 }
+export type RowFields = StoredRow;
 export declare const Sortable: (options?: undefined | {
     noIndex?: boolean;
 }) => import("@antelopejs/interface-core/decorators").PropertyDecorator & import("@antelopejs/interface-core/decorators").MethodDecorator;
diff --git a/base/_root/typesVersions/%2A/metadata/0.d.ts b/head/_root/typesVersions/%2A/metadata/0.d.ts
index 05e8c4f..844ba45 100644
--- a/base/_root/typesVersions/%2A/metadata/0.d.ts
+++ b/head/_root/typesVersions/%2A/metadata/0.d.ts
@@ -185,6 +185,7 @@ export interface ReadableAccessFields {
         FieldData
     ][];
 }
+export type RowFields = StoredRow;
 export declare const Sortable: (options?: undefined | {
     noIndex?: boolean;
 }) => import("@antelopejs/interface-core/decorators").PropertyDecorator & import("@antelopejs/interface-core/decorators").MethodDecorator;
API: skipped .agents/skills/formal-field-access, private.
API: skipped .agents/skills/verify-interface, private.
API: skipped test-helper entry ./dist/*.d.ts in .; test helpers need a test runner and are outside both proof halves.
Runtime API: 1 packages, 24 entries unchanged against origin/main (committed HEAD).
Runtime API: skipped test-helper entry ./dist/*.js in .; test helpers need a test runner and are outside both proof halves.
No behavioural probe ran.

Suppressions in authored code files (origin/main and committed HEAD). A lint directive counts once per rule it names; `*` is a directive naming none.
| Suppressions | base | HEAD |
| --- | ---: | ---: |
| Lint suppressions, all rules | 0 | 0 |
| `@ts-expect-error` | 0 | 0 |
| `@ts-ignore` | 0 | 0 |
| `SAFETY:` comments | 3 | 3 |
| Lint config rule-offs, all rules | 0 | 0 |
<!-- antelopejs-proof base=f781ade226fe1f97d9db1c11ed751834625d8dca head=4a391aeb5e616aaf2db89e7f1d9e4221e7eecb36 lines=51 digest=f771e836cce49b4e command: antelopejs-api-diff origin/main -->
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant