Commit 1f71a71
authored
ban Schema.Class, migrate all usage to Schema.Struct (#768)
Effect 4.x makes `Schema.Class` nominally typed at runtime — the encode
path does an `instanceof` check and rejects any plain object, regardless
of field shape. TypeScript's structural typing assigns plain objects to
Class-typed parameters happily, so the compiler can't catch the
mismatch. The result has bitten executor twice this week alone (Sentry
NODE-CLOUDFLARE-WORKERS-3N: Google user, Vercel user, and a fresh
SharePoint report today) — wire-decoded `oauth2` payloads reaching
`encodeSync` and crashing the txn with "Expected
OpenApiOAuth2SourceConfig, got {...}", surfacing to users as an opaque
`InternalError({ traceId })` after OAuth completes.
The Effect community has documented the same footgun for two years —
imagio and Patrick Roza in Feb 2024
(https://www.answeroverflow.com/m/1206705364288938064), and gcanti
himself in Nov 2025 confirming "TypeScript is structural" with the
explicit recommendation: "if you don't necessarily need the Schema.Class
features, then Schema.Struct is always a better option"
(https://www.answeroverflow.com/m/1268175268019830906). None of the
75-odd Class declarations in this repo had methods, getters, setters,
or any behavior beyond the schema — they were pure data shapes wearing
a class wrapper for no benefit.
This commit:
- Migrates every `Schema.Class<X>("X")(fields) {}` declaration to
`Schema.Struct(fields)` + `type X = typeof X.Type` via
`scripts/migrate-schema-class.ts`. The codemod is idempotent and
supports `--dry-run`.
- Migrates `Schema.TaggedClass` (2 sites) to `Schema.TaggedStruct`.
- Rewrites ~460 `new X(...)` call sites to `X.make(...)`, the equivalent
on Struct that applies constructor defaults and validates fields.
- `Schema.TaggedErrorClass` and `Schema.ErrorClass` are exempt — they're
how Effect models typed-error channels and `instanceof` for them is
by design.
- Consolidates the eight existing Struct/Class duality pairs
(`OAuth2SourceConfig`/`Schema`, `OpenApiSourceBindingInput`/`Schema`,
etc) — the Struct half was created to bridge the API boundary;
with Class gone there's only one schema per shape.
- Replaces `instanceof FormElicitation` and `_tag === "..."` checks
with hoisted `Schema.is(...)` predicates, satisfying the existing
`no-manual-tag-check` and `no-inline-schema-compile` rules.
- Adds `executor/no-schema-class` oxlint rule banning `Schema.Class`
and `Schema.TaggedClass` anywhere — `TaggedErrorClass`/`ErrorClass`
pass through. Supersedes `no-schema-class-http-payload`, which only
caught direct payload usage and missed nested-in-Struct cases (the
exact shape the OAuth2 bug took).
- Deletes the now-redundant `check-http-payload-schemas.ts` script and
its test — the new lint rule covers everything they did, more broadly.
Verified: full `bun run lint`, `bun run typecheck`, `bun run test`, and
`bun run format:check` clean.1 parent e49e66f commit 1f71a71
97 files changed
Lines changed: 1222 additions & 1555 deletions
File tree
- apps
- cloud/src
- services
- __test-harness__
- local/src/server
- examples
- all-plugins/src
- promise-sdk/src
- packages
- core
- api/src
- handlers
- execution/src
- sdk/src
- hosts/mcp/src
- kernel/ir/src
- plugins
- google-discovery/src
- api
- sdk
- graphql/src
- api
- react
- sdk
- keychain/src
- mcp/src
- api
- react
- sdk
- onepassword/src
- api
- sdk
- openapi/src
- api
- react
- sdk
- workos-vault/src/sdk
- scripts
- oxlint-plugin-executor/rules
- tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
52 | | - | |
| 52 | + | |
| 53 | + | |
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
| |||
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
63 | | - | |
| 64 | + | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
109 | | - | |
| 109 | + | |
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
| 76 | + | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
81 | | - | |
| 81 | + | |
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
| 74 | + | |
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
155 | | - | |
| 155 | + | |
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
160 | | - | |
| 160 | + | |
161 | 161 | | |
162 | 162 | | |
163 | 163 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
307 | 307 | | |
308 | 308 | | |
309 | 309 | | |
310 | | - | |
| 310 | + | |
311 | 311 | | |
312 | 312 | | |
313 | 313 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
246 | 246 | | |
247 | 247 | | |
248 | 248 | | |
249 | | - | |
| 249 | + | |
250 | 250 | | |
251 | 251 | | |
252 | 252 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
255 | | - | |
| 255 | + | |
256 | 256 | | |
257 | 257 | | |
258 | 258 | | |
| |||
265 | 265 | | |
266 | 266 | | |
267 | 267 | | |
268 | | - | |
| 268 | + | |
| 269 | + | |
269 | 270 | | |
270 | 271 | | |
271 | 272 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| |||
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
206 | | - | |
| 206 | + | |
207 | 207 | | |
208 | 208 | | |
209 | 209 | | |
| |||
0 commit comments