They are our own superseded options, not a stale dependency. The recommended form is already what the showcase example uses; the blast radius is three test files inside packages/auth, and the rpId/origin options are already ignored at runtime. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
150 lines
12 KiB
Markdown
150 lines
12 KiB
Markdown
# Legacy, deprecated, and unused-config cleanup — Design
|
||
|
||
**Date:** 2026-08-19
|
||
**Status:** Approved for implementation
|
||
**Scope:** Remove the compatibility-flag surface, the `"legacy"` function runtime, dead migrations,
|
||
and deprecated APIs — before the framework's first public release.
|
||
|
||
## Goal
|
||
|
||
WRNexus carries compatibility machinery for a public it does not yet have. Every branch of it is
|
||
either switched off in the only apps that exist, or wired to nothing at all. Removing it now costs
|
||
almost nothing; removing it after release costs a major version and other people's time.
|
||
|
||
## Why this is safe now
|
||
|
||
Two pieces of evidence, both verified rather than assumed:
|
||
|
||
**The only consumers already run without it**, which matters for the config files themselves even
|
||
though the keys are inert. `D:\Company\wrnexus\apps\admin` and
|
||
`D:\Company\wrnexus\apps\web` — both test projects, neither deployed — set every compatibility flag
|
||
to `false` and `legacyDefaultRuntime: "current"`. They are already on the modern path; removing the
|
||
flags means deleting the lines that say "off".
|
||
|
||
**None of the seven keys change any behaviour.** Verified by tracing every reference, not by
|
||
reading the types. `legacyEmit`, `legacyEventProps`, `legacyComponentDiscovery`, `stringLayouts`,
|
||
and `legacyDefaultRuntime` appear in exactly three places each: the type declaration in
|
||
`config.ts`, the scaffolder in `create.ts`, and the insertion in `update.ts`. **No compiler,
|
||
codegen, or runtime code reads any of them.** They are written into every generated config and then
|
||
ignored.
|
||
|
||
The remaining two are the same story with more machinery. `resolveCompatibility` (`packages/styles/src/compatibility.ts`)
|
||
produces a report — an effective date, a behaviour number, and advisory strings. Tracing every
|
||
consumer: the `wrnexus compatibility` command prints it, and `config.ts` raises one validation error
|
||
when the configured date is _newer_ than the CLI supports. **No compiler branch and no runtime
|
||
behaviour reads `effectiveDate` or `effectiveBehaviour`.** The mechanism is scaffolding that was
|
||
never connected.
|
||
|
||
### Non-goals
|
||
|
||
- **The legacy `api` block forms.** Bare-body blocks using `with ($data)`, and `api` entries inside
|
||
`ssr {}` / `client {}`, are _replaced_ rather than deleted — that is the next spec's job. Removing
|
||
them here would leave a gap with no working mechanism.
|
||
- Adding any configuration key. This spec only removes them.
|
||
- Changing any behaviour that is currently switched on.
|
||
|
||
## What gets removed
|
||
|
||
| Item | Where | Why it goes |
|
||
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
|
||
| `compatibility: { legacyEmit, legacyEventProps, legacyComponentDiscovery, stringLayouts }` | `packages/styles/src/config.ts` (`CompatibilityConfig`) | Never read by any code |
|
||
| `functions: { legacyDefaultRuntime }` | `packages/styles/src/config.ts` (`FunctionsConfig`) | Never read by any code |
|
||
| `compatibilityDate` | `packages/styles/src/compatibility.ts` (`CompatibilityPolicy`) | Gates nothing |
|
||
| `frameworkBehaviour` | same | Gates nothing |
|
||
| `resolveCompatibility`, `CompatibilityReport`, `isCompatibilityDate`, `CURRENT_COMPATIBILITY_DATE`, `CURRENT_FRAMEWORK_BEHAVIOUR` | `packages/styles/src/compatibility.ts` | Whole module serves only the two dead keys |
|
||
| `wrnexus compatibility <check\|explain\|upgrade>` | `packages/cli/src/compatibility-command.ts`, dispatch at `packages/cli/src/index.ts:295`, help text at `:75` | Reports on removed keys |
|
||
| `"legacy"` variant of `FunctionRuntime` | `packages/syntax/src/v060.ts`, branches in `packages/compiler/src/client-codegen.ts` and `server-codegen.ts` | An unmarked function becomes `shared` (see below) |
|
||
| Migrations below `0.8.0` | `packages/cli/src/update.ts` | 111 migrations reach back to `0.2.8`; no project exists below `0.8.x` |
|
||
| Deprecated re-export shims | `packages/compiler/src/{parser,tokenizer,types}.ts` | Two lines each, re-exporting `@wrnexus/syntax` |
|
||
| Deprecated `@wrnexus/auth` options | `engine.ts` (4 sites), `http/index.ts` (2), `plugin.ts` (2), `types.ts` (1) | See "Deprecated auth options" |
|
||
|
||
## The `"legacy"` function runtime
|
||
|
||
`FunctionRuntime` is `"legacy" | "client" | "server" | "shared"`. `"legacy"` is what an _unmarked_
|
||
`function foo()` gets, and `legacyDefaultRuntime` decides how it behaves. Both codegens then test
|
||
membership: `["legacy", "client", "shared"]` for the browser and `["legacy", "server", "shared"]`
|
||
for the server — which is to say **an unmarked function is currently emitted into both bundles,
|
||
exactly like `shared`.**
|
||
|
||
`legacyDefaultRuntime` looks like it should modulate this, but it is never read (above), so the
|
||
mapping is unconditional: unmarked is always `"legacy"`, and `"legacy"` is always emitted to both
|
||
bundles.
|
||
|
||
So the removal is mechanical: delete the `"legacy"` variant, and parse an unmarked function as
|
||
`"shared"`. The emitted output for every existing unmarked function is unchanged, in every
|
||
configuration. `FunctionRuntime`
|
||
becomes `"client" | "server" | "shared"`, and the membership tests lose one element each.
|
||
|
||
This is the one item where behaviour could drift if done carelessly, so its test is explicit: an
|
||
unmarked function must still appear in both the browser and server modules.
|
||
|
||
## Deprecated re-export shims
|
||
|
||
`packages/compiler/src/parser.ts`, `tokenizer.ts`, and `types.ts` are two-line files re-exporting
|
||
`@wrnexus/syntax`. They are marked deprecated, but **`codegen.ts` and `native-codegen.ts` still
|
||
import from them**, so deleting the files is not enough — those imports must be repointed at
|
||
`@wrnexus/syntax` first. Removing the files without that step breaks the build.
|
||
|
||
## Deprecated auth options
|
||
|
||
`@wrnexus/auth` carries nine `@deprecated` markers. These are **our own superseded options**, not an
|
||
out-of-date dependency — there is no newer version to move to, only newer options we already added.
|
||
Removing them means deleting the old aliases and moving the few call sites that still use them.
|
||
|
||
| Group | Where | Replacement | Still used? |
|
||
| --------------------------------------------------------------------- | ---------------------------- | ------------------------------------------- | ----------------------------------------------------------- |
|
||
| `onSignedIn` / `onSignedOut` on HTTP route options and plugin options | `http/index.ts`, `plugin.ts` | the same names on `createAuthEngine({ … })` | only `packages/auth/test/http.test.ts` and `plugin.test.ts` |
|
||
| `onSuccessfullSignUp` (misspelled alias) | `types.ts` | `onSuccessfulSignUp` | nowhere — zero references |
|
||
| `rpId` / `origin` on passkey verification | `engine.ts` (4 sites) | values bound to the issued challenge | `packages/auth/test/engine.test.ts` |
|
||
|
||
Two things this table settles:
|
||
|
||
- **The recommended form is already in use.** `examples/auth-showcase/app/lib/auth.ts` passes
|
||
`onSignedIn` / `onSignedOut` to `createAuthEngine`, which is the _current_ API. The deprecated
|
||
members are the same names on different option objects, so the example needs no change.
|
||
- **Neither test app uses any of them.** Nothing in `D:\Company\wrnexuspps` references these
|
||
options.
|
||
|
||
So the blast radius is three test files inside `packages/auth`, which are exercising the deprecated
|
||
paths and are updated or removed alongside them. The `rpId` / `origin` options are already ignored at
|
||
runtime — verification uses the values bound to the issued challenge — so removing them changes no
|
||
behaviour, only the shape of the call.
|
||
|
||
## Migration
|
||
|
||
`examples/basic-app` and both test apps need one pass each:
|
||
|
||
1. Delete `compatibility`, `functions`, `compatibilityDate`, and `frameworkBehaviour` from
|
||
`wrnexus.config.ts` — seven lines per app.
|
||
2. `packages/cli/src/create.ts` stops scaffolding those keys, so new apps get a shorter config.
|
||
|
||
No `.wrn` source changes. Nothing in this spec alters page syntax.
|
||
|
||
The removed `0.2.x`–`0.7.x` migrations mean a project below `0.8.0` can no longer be upgraded by
|
||
`wrnexus update`. No such project exists, and rescuing one would be a manual job either way.
|
||
|
||
## Testing
|
||
|
||
- **The `"legacy"` runtime removal is behaviour-preserving**: an unmarked function still appears in
|
||
both the browser and server modules. This is the assertion most worth writing, because it is the
|
||
only removal that could silently change output.
|
||
- **Config rejects the removed keys** rather than ignoring them, so a stale config fails loudly with
|
||
a message naming the key. A silently-ignored key would leave someone believing a flag still
|
||
applies.
|
||
- **`create.ts` scaffolds a config without them**, asserted against the generated file.
|
||
- **`wrnexus update` still runs** with the pre-`0.8.0` migrations gone, and reports correctly for an
|
||
app already at the current version.
|
||
- **`examples/basic-app` builds and its suite passes** after its config is trimmed — the end-to-end
|
||
guard that nothing depended on the removed surface.
|
||
- **The full gate** (`bun run check:production`) passes, including the editor bundles, which embed
|
||
the compiler and must be rebuilt after `FunctionRuntime` changes.
|
||
|
||
## What we give up
|
||
|
||
Deleting `compatibilityDate` and `frameworkBehaviour` removes the standard escape hatch for changing
|
||
a default after going public — the mechanism that lets an existing app keep old behaviour by pinning
|
||
a date. Today it is wired to nothing, so it protects nobody, and an unused mechanism rots rather
|
||
than matures. If a gate is needed later it can be reintroduced deliberately, against a real
|
||
behaviour change, instead of being carried empty. This is a considered trade rather than a free
|
||
deletion.
|