You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(rest)!: ImportProtocolLike declares the request each of its three required members receives (#17420)
* wip: type ImportProtocolLike's three required members
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DapQyvYrFb1MxSYe7BL2nt
* wip: converge doubles and add pins
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DapQyvYrFb1MxSYe7BL2nt
* wip: test layer green
* changeset + pins
* changeset: adr-0087 disposition
* changeset: symbol path
* probe no-migration-prescription
* probe runtime-interface-only packages/rest/src/import-runner.ts#ImportProtocolLike
* changeset: no-migration-prescription disposition
---------
Co-authored-by: Claude <noreply@anthropic.com>
refactor(rest)!: `ImportProtocolLike` declares the request each of its three required members receives, instead of `args: any` (#16952)
6
+
7
+
The exported extension point `runImport` accepts a protocol through now states its own contract.
8
+
9
+
**FROM** — every required member erased its parameter, so the interface declared nothing about the request it would hand an implementor:
10
+
11
+
```ts
12
+
exportinterfaceImportProtocolLike {
13
+
findData(args:any):Promise<any>;
14
+
createData(args:any):Promise<any>;
15
+
updateData(args:any):Promise<any>;
16
+
}
17
+
```
18
+
19
+
**TO** — each member names the declared spec request, wrapped in the server-scoped envelope the runner adds (`ImportProtocolRequest`, exported alongside):
**Why this is breaking-ish, and released as `minor`.** This is a narrowing of a published surface: an implementor that compiles today may stop compiling. Nothing about the values the runner sends changes — the request objects are byte-for-byte the ones #16638 already made canonical — so no runtime behaviour moves. What changes is that the compiler now holds an implementor to the same `QuerySchema` the runner is held to: `where` / `limit` / `offset` / `fields` / `orderBy` / `expand` are declared, and the wire spellings `$filter` / `$top` are not.
32
+
33
+
**Migration for implementors.** If your `findData` / `createData` / `updateData` reads a wire alias, it will now fail to compile — that diagnostic is the point of this change, and the fix is to read the canonical key:
34
+
35
+
```ts
36
+
// before — compiles, and silently degrades to match-everything when `$filter` is absent
37
+
asyncfindData(args: any) {
38
+
const where =args?.query?.$filter?? {};
39
+
const limit =args?.query?.$top??2;
40
+
}
41
+
42
+
// after — drop your own annotation and let the declaration type the parameter
43
+
asyncfindData(args) {
44
+
const where =args.query!.where;
45
+
const limit =args.query!.limit;
46
+
}
47
+
```
48
+
49
+
⛔ An implementor that keeps an explicit `args: any` annotation of its own opts back out: the annotation wins over the contextual type, and the contract reaches nothing. Leave the parameter unannotated, or name `ImportProtocolRequest<FindDataRequest>` explicitly.
50
+
51
+
⚠️ The `?? {}` shape in the "before" is the mechanism that made a dialect mismatch silent rather than loud: an unrecognised query does not throw, it degrades into a filter that constrains nothing, so a duplicate probe stops discriminating and an upsert updates the wrong record. Prefer a read that throws.
52
+
53
+
<!-- adr-0087: not-required (no-migration-prescription) Nothing authorable is renamed, retired or re-typed: `packages/spec` is untouched, no metadata key changes its name, type or optionality, and no stored `sys_metadata` shape moves — every request body and every authored file parses byte-identically to before, so `objectstack migrate meta`, `spec-changes.json` and the generated upgrade guide have nothing to rewrite. What narrows is a TypeScript parameter annotation on one exported interface, so the affected party is a source-code implementor and the delivery channel is the compiler at their own call site. The FROM/TO block in this body is a prescription for THAT reader, not for a metadata upgrader. -->
0 commit comments