Skip to content

fix(metadata): build DataAPIMeta from a DecoratorTarget for interface-core 0.5 - #128

Merged
Upd4ting merged 3 commits into
mainfrom
fix/interface-core-0-5-metadata
Nov 13, 2026
Merged

Upd4ting merged 3 commits into
mainfrom
fix/interface-core-0-5-metadata

Conversation

@Upd4ting

Copy link
Copy Markdown
Member

Why

ANT-2370. interface-core 0.5 types GetMetadata's metadata class as Class<T, [DecoratorTarget]>, because GetMetadata also builds metadata for the prototypes it walks above a class. DataAPIMeta's constructor took a Class, so this package stopped compiling against interface-core 0.5. This PR makes it compile and moves the dev dependencies to the released @antelopejs/core 1.22.0 and @antelopejs/interface-core 0.5.1, with a single interface-core copy in the lockfile.

What

  • DataAPIMeta's constructor takes a DecoratorTarget. It keeps the target when it is a class. target stays typed Class<object>, now as a getter, and throws No controller class. only for the metadata GetMetadata builds for Function.prototype and Object.prototype above the controller classes. Nothing reads target on those.
  • Dev dependencies: @antelopejs/core ~1.22.0, @antelopejs/interface-core ^0.5.1, deduped so the lockfile resolves interface-core at 0.5.1 only. The peer range stays >=0.2.4 <1.0.0, because the runtime works with every version in it. The README's tested-with column reads 0.5.1.
  • src/metadata.ts would have gone 230 bytes over the 20,000-byte ceiling. recomputeAccess's body moved into a new @internal module, src/internal/access-lists.ts (rebuildAccess, DEFAULT_ACTION). The method still runs on its own instance and passes rebuildAccess its own records. The access rules stay in metadata.ts and reach it through a callback, so no import cycle forms. metadata.ts is now 19,182 bytes.
flowchart LR
  gm["GetMetadata(Child, DataAPIMeta)"] --> c["new DataAPIMeta(Child): target = Child"]
  gm --> p["new DataAPIMeta(Base): target = Base"]
  gm --> r["new DataAPIMeta(Function.prototype / Object.prototype): target throws"]
Loading

Attention

  • Declarations. DataAPIMeta's constructor parameter widens from Class to DecoratorTarget; every Class is a DecoratorTarget. readonly target: Class<object> becomes get target(): Class<object>, with the same read type. The class gains a #private member, so an object literal can no longer stand in for a DataAPIMeta.
  • Runtime. target is an accessor on the prototype, so Object.keys(meta) no longer lists it. Reading target on the metadata of a prototype above the controller classes throws instead of returning that prototype. Runtime exports are unchanged.
  • antelopejs-api-diff origin/main cannot build its base: origin/main does not compile against the new dependencies, which is what this PR fixes. The declaration and runtime-export comparison against origin/main built with its own lockfile is shown below. The api-diff block proves that the size split and the dependency bump preserve the API.

SAFETY comments added

None. The suppression budget is unchanged.

Proof

pnpm run checks: 11 passed, 0 failed. pnpm exec tsc -p docs/tsconfig.json passes.

origin/main typechecked against this PR's lockfile (interface-core 0.5.1):

src/index.ts(67,31): error TS2345: Argument of type 'typeof DataAPIMeta' is not assignable to parameter of type 'Class<DataAPIMeta, [DecoratorTarget]> & { key: symbol; }'.
  Type 'typeof DataAPIMeta' is not assignable to type 'Class<DataAPIMeta, [DecoratorTarget]>'.
    Types of construct signatures are incompatible.
      Type 'new (target: Class) => DataAPIMeta' is not assignable to type 'new (args_0: DecoratorTarget) => DataAPIMeta'.
        Types of parameters 'target' and 'args_0' are incompatible.
          Type 'DecoratorTarget' is not assignable to type 'Class'.
            Type 'DecoratorTarget' provides no match for the signature 'new (...args: any[]): object'.
src/index.ts(96,38): error TS2345: Argument of type 'typeof DataAPIMeta' is not assignable to parameter of type 'Class<DataAPIMeta, [DecoratorTarget]> & { key: symbol; }'.

The new src/tests/index/metadata_target.test.ts, on origin/main:

    ✔ answers the controller class GetMetadata builds it for, through the prototype walk
    1) refuses to answer a target for a prototype above the controller classes
  1 passing (3ms)
  1 failing
  1) DataAPIMeta - target
     AssertionError: expected [Function] to throw TypeError
      at Context.<anonymous> (dist/tests/index/metadata_target.test.js:18:95)
      at process.processImmediate (node:internal/timers:574:21)

On this branch both tests pass, inside the 11/11 checks.

Declarations, origin/main built with its own lockfile against HEAD. Every other .d.ts is identical, and internal/access-lists.d.ts is new:

--- dist/metadata.d.ts	2026-11-13 11:18:15.538437880 +0000
+++ dist/metadata.d.ts	2026-11-13 11:18:19.374499920 +0000
@@ -1,6 +1,6 @@
 import type { ContainerModifier } from "@antelopejs/interface-database-decorators/modifiers/common";
 import { type Table } from "@antelopejs/interface-database-decorators";
-import { type Class } from "@antelopejs/interface-core/decorators";
+import { type Class, type DecoratorTarget } from "@antelopejs/interface-core/decorators";
 import type { DataControllerCallbackWithOptions, DataControllerInstance } from "./internal/controller-types";
 import type { FieldValidator, FieldData, ComputedExpression, ComputedOptions, FilterFunction, ForeignOptions, ReadableAccessFields, WritableAccessFields } from "./internal/field-types";
 export { FilterValuesOf } from "./internal/filters";
@@ -25,6 +25,7 @@
  * Metadata Class containing the DataAPI information.
  */
 export declare class DataAPIMeta {
+    #private;
     /** Key symbol. */
     static key: symbol;
     readonly filters: Record<string, FilterFunction<any, any>>;
@@ -48,9 +49,10 @@
     readonly writable: Record<string, WritableAccessFields>;
     /** Registered DataAPI endpoints. */
     readonly endpoints: Record<string, DataControllerCallbackWithOptions>;
-    /** The controller class. */
-    readonly target: Class<object>;
-    constructor(target: Class);
+    /** @param target The controller class, or a prototype above it. */
+    constructor(target: DecoratorTarget);
+    /** The controller class; throws for a prototype above it. */
+    get target(): Class<object>;
     inherit(parent: DataAPIMeta): void;
     private field;
     private recomputeListable;

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

Size split and dependency bump, against the constructor commit 0ad9572 (both sides build on interface-core 0.5.1):

API: 1 packages, 26 entries unchanged against 0ad9572 (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, 23 entries unchanged against 0ad9572 (committed HEAD).
Runtime API: skipped test-helper entry ./dist/*.js in .; test helpers need a test runner and are outside both proof halves.
Added (allowed): 1
  .: ./internal/access-lists
No behavioural probe ran.

Suppressions in authored code files (0ad9572 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=0ad9572a5d122e54e24c0b7a3ef465e54edd124c head=eb83d805a2488b8f4c2ca55e9c119f9ec644a41f lines=17 digest=e4e362d366640aa8 command: antelopejs-api-diff 0ad9572 --allow-added '**/internal/**' -->

@Upd4ting
Upd4ting merged commit e60ec06 into main Nov 13, 2026
8 checks passed
@Upd4ting
Upd4ting deleted the fix/interface-core-0-5-metadata branch November 13, 2026 11:24
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