Emits the data-wrn-island placeholder, parses client:* strategies, and
rejects non-serializable props at compile time via WRN-ISLAND-PROPS so
the serialization boundary fails where it is cheapest to fix.
Island names become URL path segments when the browser fetches the
island bundle, so they are validated with core's existing
isSafeIslandName rather than relying on escaping alone. This adds
@wrnexus/core to the compiler's dependencies; core has no dependencies
of its own, so no cycle is introduced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolves WRNexus stores from inside islands, reading through the cached
snapshot so React sees a stable reference. Unknown store names throw
with the list of registered stores rather than failing opaquely.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
useSyncExternalStore requires getSnapshot to return an identical
reference when unchanged; @wrnexus/store's readonlySnapshot returns a
fresh clone per call. The cache lives here rather than in the store
package so existing consumers are untouched.
createSelectorCache takes an optional equality function: the Object.is
default can never stabilize a selector that allocates, which is the
usual source of infinite re-renders.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Twelve TDD tasks covering the approved spec: snapshot cache, store
bridge, marker codegen, .tsx resolution, error boundary, island runtime,
bundling with a shared React chunk, asset serving, route classification,
integration guards, the write-during-render guard, and HMR remount.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds the approved design for consuming npm React components as
client-only islands inside WRNexus, without changing the SSR-first
rendering model.
Key decisions:
- New isolated @wrnexus/react package; react/react-dom as optional peers
- Client-only by default, SSR deferred to v2
- Islands declared via .tsx imports in .wrn frontmatter
- Store access via useSyncExternalStore, with the snapshot cache in the
adapter so @wrnexus/store stays untouched
- Bundling extends the existing Bun pipeline; React as a shared chunk
- Routes with no islands must still ship zero framework JavaScript
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The test profile pointed at ./test.db in the app directory, so a run inherited
whatever schema an earlier run left behind. On a machine with a stale file,
0003_add_password re-applied ALTER TABLE ADD COLUMN over a column that already
existed; fail-on-test-warnings turned the warning into a failure, and
check:production failed for environment reasons rather than code.
Each run now uses a fresh database under the OS temp directory. Verified by
restoring the stale dev.db and test.db that reproduced the failure: the suite
passes with them present.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
.publish/ is already listed in .gitignore, but 119 files were committed before
that rule existed, so they stayed tracked. The release prepare step clears and
restages the directory, which meant a routine `git add -A` during a release
would stage the deletion of every package it had not just staged.
Nothing reads the committed contents: publish-packages.ts writes the directory,
test-staged-consumers.mjs reads it after staging, and check-component-imports
skips it. Untracking leaves the release flow unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An over-broad `git add -A` in the previous commit swept a local dev-server
entry for an unrelated application into .claude/launch.json. It pointed at a
path outside this repository and was not Prettier-formatted, so it failed
format:check. Restored to the version on main.
Also runs Prettier over migrate.ts, which the dead-code removal left unformatted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The contract tracks a content hash per component source. Rewording the comment
in Typography.wrn changed its hash, so the check failed on an edit that alters
no rendered output. Regenerated intentionally; only that one entry moves.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
check-component-imports scans sources for <Component> tags and requires each to
be imported. The explanatory comment added with the prose-scoping fix wrote
<Blockquote> literally, so the checker demanded an import for a component the
file never renders. Naming it without angle brackets keeps the explanation and
clears the gate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
hasExecutableSql returns as soon as it meets a quote character, so the quote
variable was assigned and never read: the `if (quote)` branch could never run.
eslint reported it as a useless assignment and the error blocks the release
gate on main. Removing the variable and the unreachable branch keeps behaviour
identical, since encountering a quote already means the SQL is executable.
Also drops an eslint-disable directive in csr's output error reporter that
suppressed nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The lockfile recorded @wrnexus/ui at 0.8.13 while its manifest is 0.8.15, so
validate:0.8 failed its workspace version check. The drift predates this branch
and is present on main; bun install does not rewrite workspace metadata that is
already satisfied, so this applies the same targeted rewrite the release
tooling performs in syncWorkspaceLock. No version is bumped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The committed snapshot had drifted from source on main: dev-server exports
validateRpcCsrf, and styles exports the browser-cookie configuration types and
resolveBrowserCookieOptions. All six are additions, so the surface stays
backward compatible.
This unblocks check:production, which fails on main for the same reason.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The checked-in bundles predated the typecheck fix that resolves @wrnexus/ui
imports as component contracts, so VS Code reported "has no exported member"
for components such as Grid while the CLI typechecker passed. The package
exports nothing by design — components resolve by directory scan — so the
stale bundle was the whole defect.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pagination reported the requested page only through its change output, so on a
server-rendered page the controls did nothing: the parent had to own client
state to react, and the emitted page never became a URL. An optional
hrefTemplate now renders the steps and page numbers as anchors, which work
before hydration and without JavaScript and give each page a crawlable URL.
Buttons remain the default for client-owned lists. End steps are clamped and
marked disabled rather than linking past the first or last page.
Output handler errors are no longer swallowed. Nothing awaits invokeOutput, so
a handler that threw became an unhandled rejection that never reached the
console and presented as a control that silently does nothing. Handler errors
are now reported as WRN-DEV-OUTPUT-HANDLER-ERROR.
Regenerates the component reference and the UI visual contract.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Typography styled every descendant element, including those inside nested UI
components. A <Blockquote variant="bordered"> placed inside <Typography> drew
two left borders: its own, plus the one these prose rules apply to any
<blockquote>. The same leak applied to headings, links, lists and code.
Prose rules now exclude the subtree of any nested `.wrn-component`, so they
style raw markup only. The exclusion sits inside :where() so specificity stays
at zero and applications can still override these rules with a plain class.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>