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
Copy file name to clipboardExpand all lines: packages/opencode/specs/effect/http-api.md
+58-19Lines changed: 58 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -189,10 +189,46 @@ Ordering for a route-group migration:
189
189
190
190
SDK shape rule:
191
191
192
-
- every schema migration must preserve the generated SDK output byte-for-byte
193
-
-`Schema.Class` emits a named `$ref` in OpenAPI via its identifier — use it only for types that already had `.meta({ ref })` in the old Zod schema
194
-
- inner / nested types that were anonymous in the old Zod schema should stay as `Schema.Struct` (not `Schema.Class`) to avoid introducing new named components in the OpenAPI spec
195
-
- if a diff appears in `packages/sdk/js/src/v2/gen/types.gen.ts`, the migration introduced an unintended API surface change — fix it before merging
192
+
- every schema migration must preserve the generated SDK output byte-for-byte **unless the new ref is intentional** (see Schema.Class vs Schema.Struct below)
193
+
- if an unintended diff appears in `packages/sdk/js/src/v2/gen/types.gen.ts`, the migration introduced an unintended API surface change — fix it before merging
194
+
195
+
### Schema.Class vs Schema.Struct
196
+
197
+
The pattern choice determines whether a schema becomes a **named** export in the SDK or stays **anonymous inline**.
198
+
199
+
**Schema.Class** emits a named `$ref` in OpenAPI via its identifier → produces a named `export type Foo = ...` in `types.gen.ts`:
**Schema.Struct** stays anonymous and is inlined everywhere it is referenced:
208
+
209
+
```ts
210
+
exportconst Info =Schema.Struct({ ... }).pipe(
211
+
withStatics((s) => ({ zod: zod(s) })),
212
+
)
213
+
exporttypeInfo=Schema.Schema.Type<typeofInfo>
214
+
```
215
+
216
+
When to use each:
217
+
218
+
- Use **Schema.Class** when:
219
+
- the original Zod had `.meta({ ref: ... })` (preserve the existing named SDK type byte-for-byte)
220
+
- the schema is a top-level endpoint request or response (SDK consumers benefit from a stable importable name)
221
+
- Use **Schema.Struct** when:
222
+
- the type is only used as a nested field inside another named schema
223
+
- the original Zod was anonymous and promoting it would bloat SDK types with no import value
224
+
225
+
Promoting a previously-anonymous schema to Schema.Class is acceptable when it is top-level or endpoint-facing, but call it out in the PR — it is an additive SDK change (`exporttypeFoo = ...` newly appears) even if it preserves the JSON shape.
226
+
227
+
Schemas that are **not** pure objects (enums, unions, records, tuples) cannot use Schema.Class. For those, add `.annotate({ identifier:"FooName" })` to get the same named-ref behavior:
0 commit comments