Both drew small text in the raw accent, which misses the contrast floor on
a dark surface. They now blend the accent toward the text colour, as the
unselected tab already does.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A Button rendered as a link emitted aria-pressed="", which is not allowed
on a link and fails an accessibility check on every page that uses one
for a secondary action. A link has no pressed state, so the attribute is
gone from that branch; a real button still carries it.
An unselected tab used the muted text colour, which does not reach 4.5:1
against the tab strip at this size. It now blends back toward the text
colour, and the selected tab still reads as selected through its surface,
accent and shadow.
The visual contract manifest is regenerated to match.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gateways are adapters behind one interface, with capabilities DECLARED rather
than assumed -- because gateways are not interchangeable. Some have no
authorize-then-capture, some cannot refund partially, some have no vault. An
interface that pretends otherwise fails at the moment money should have moved.
So capabilities are declared, refused loudly when absent, and checked at build
time where the gateway is statically known.
Tier 1 is sandbox, Stripe, Razorpay and PayPal. Stripe and Razorpay are
deliberately the first real pair because they DIFFER on capture model, currency
spread and refund semantics -- one gateway does not prove an abstraction, and
two similar ones prove it badly. Tier 2 and a regional Tier 3 follow, and
defineGateway() makes a third-party adapter a first-class citizen held to the
same shared contract suite.
Two rules shape the package: it never touches a raw card number (hosted fields
keep an application in PCI SAQ-A rather than SAQ-D), and the signed webhook is
the source of truth rather than the browser redirect, which is a claim from an
untrusted client.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A parent writing @focus on a component tag never heard that component's
own input or button take focus. The runtime bound every output-named DOM
fallback listener in the bubble phase, and focus and blur do not bubble,
so the event fired on the descendant and stopped there. Nothing errored --
the binding simply did nothing.
That made a whole class of declared outputs undeliverable: button.focus,
button.blur, TextLink.focus, TextLink.blur, WysiwygEditor.focus and
WysiwygEditor.blur all advertised events they could never send.
The ui ratchet for outputs nothing emits excluded natively-named outputs
on the grounds that a native event reaches the root anyway. That holds for
click and change, which bubble, and was wrong for focus and blur. Binding
those two in the capture phase makes the exclusion honest rather than
convenient; the ratchet's comment now says so.
Also documents WysiwygEditor as the chrome shell it is: it emits none of
its four outputs itself, it forwards whatever the slotted control raises.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Hover fired on whatever word was under the cursor, so a local variable
colliding with a declared block name reported the block's method and path
instead of its own hover info. Completion was already gated this way.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
cd0dffa8 changed StrongPassword, TogglePassword and button but left the
hash manifest untouched, so check:ui-visual has been red since. The three
hashes here are exactly those components -- no unrelated drift.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mode-functions writes without a parse check when a mode wrapper survives
holding api entries, since that intermediate state is unparseable until
move-api-blocks runs later in the same pass. Brace balance is the invariant
a bad splice offset would break, so check that instead; nothing downstream
could tell a corrupted wrapper from an untouched one.
Also records that Task 5's example-app migration ran against an already-
migrated target and so did not prove end-to-end behaviour.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- generate-complete-framework-report.mjs no longer claims legacyEmit/
legacyEventProps/legacyComponentDiscovery/stringLayouts/
functions.legacyDefaultRuntime are usable compatibility flags; they were
removed before the first public release and a config setting them is now
rejected. Regenerated docs/WRNEXUS-COMPLETE-FEATURE-REPORT.md.
- Restored the update.test.ts coverage lost in the sub-0.8.0 migration
cleanup: a 0.8.x fixture now asserts refreshFrameworkFiles' still-live
behaviour (public/llms.txt and CLAUDE.md creation) and that
pkg.wrnexus.version stays at its old value after an unverified update.
The .gitignore refresh and build/start/production script backfill were
themselves removed as part of dropping the sub-0.8.0 migrations that
implemented them, so there is nothing left to cover for those two.
- updateApp now logs a clear warning when the detected project version is
below 0.8.0, naming the version and stating that automated migration from
below 0.8.0 is no longer supported, without failing the command (a
marker-less app, like examples/basic-app, is benign and must still
upgrade cleanly).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- regenerate docs/public-api-0.8.json (removals only: CompatibilityPolicy,
CompatibilityReport, CURRENT_COMPATIBILITY_DATE, CURRENT_FRAMEWORK_BEHAVIOUR,
isCompatibilityDate, resolveCompatibility from @wrnexus/styles)
- regenerate docs/WRNEXUS-COMPLETE-FEATURE-REPORT.md
- remove the deleted 'wrnexus compatibility' command row and its config-pinning
sentence from packages/cli/README.md
- drop compatibilityDate/frameworkBehaviour example fields from docs/GUIDE.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Three specs completing the set, each depending on the one before it:
- apis {}: one container, mode-less declarations, api.<name>() callable
anywhere with build-time dispatch, AsyncLocalStorage for server context,
usage-driven emission, three render-binding forms. Replaces the ssr {} /
client {} data blocks and the untypeable with($data) legacy body.
- update: migrations to the new syntax. The legacy bare-body rewrite is
deliberately manual -- which free identifiers are payload fields is not
knowable from the source, so an automatic guess would compile and be wrong.
- editor tooling: grammar, completions for api. and the api= attribute,
diagnostics for removed constructs, and resolving by observation whether
generated type errors surface inline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
All seven compatibility keys are dead configuration: traced every reference
and none is read by any compiler, codegen, or runtime code. They are written
into every generated config and ignored.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Client codegen chained .then().catch(), so a .catch() after .then()
caught exceptions thrown by the response body too. Switched to the
two-argument then(onFulfilled, onRejected) form, whose rejection
handler cannot see errors from the fulfilment handler.
SSR codegen wrapped both the transport call and the response-body eval
in the same try; only __wrnexusCallApi is now inside the try, and
__wrnexusEvalData runs after it, outside.
Also verifies (and locks in with a regression test) that GET query
numbers already coerce correctly through defineEndpoint + checkField,
and documents that in the typed-api-block spec.
- Add examples/basic-app/app/api/directory.ts and app/pages/api-block-demo.wrn
as the end-to-end worked example for typed api blocks (Task 6).
- Add **/*.generated.api-checks.ts to .prettierignore: this generated file
must match the CLI's raw output byte-for-byte for check:generated-types,
and prettier was reformatting it.
- Fix packages/csr/test/api-call.test.ts: no-unsafe-function-type lint error
from the raw Function type, uncovered while running the full gate.
- Rebuild editors/vscode bundles (packages/compiler and packages/syntax
changed in Tasks 1-5).
- Regenerate docs/public-api-0.8.json (additive: isIdentPart, isIdentStart,
skipLiteralOrComment newly exported from packages/syntax).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>