Commit Graph
143 Commits
Author SHA1 Message Date
ClintchizandClaude Opus 5 aded2daab9 fix: restore the production gate after the migration tasks
- rebuild editors/vscode bundles, stale since the parser escape fix
- attach the caught ParseError as `cause` in both migration validators
- drop two unused test bindings flagged by eslint

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 12:19:53 +05:30
ClintchizandClaude Opus 5 0ed8351828 test: restore executed and real-tsc coverage lost when the old api-block tests were deleted
Fix round 1: the deleted api-block-*.test.ts files were not fully superseded
by the apis-* siblings as claimed. Ports back, using apis {} fixtures:
- brace-inside-a-string-literal response-section scanner regression test
- type erasure of response/error bodies before browser emission
- client-side response-error-not-swallowed / transport-failure-fallback,
  executed via dynamic import of a generated browser module
- the full SSR execution suite: response payload binding, error section
  status/message/data binding, {#each} failure propagation, all executed
  via dynamic import + a real load/api call chain (not string checks)
- the four real-tsc enforcement tests (matching/wrong-type/extra-field/
  missing-field), plus the B1 cross-page collision guard and the B6
  export-for-noUnusedLocals guard

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:14:16 +05:30
ClintchizandClaude Opus 5 890d6106b3 feat: replace the ssr/client data blocks with apis blocks
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 07:59:37 +05:30
ClintchizandClaude Opus 5 442c058d0c feat(compiler): support the three api render-binding forms
- Parse api="name", api="name()", and api="name({ ... })" render bindings
  for apis {} (mode "any") blocks, mirroring @click="fn()" syntax.
- Render-bind by calling Task 4's generated server `api` object directly
  (api.<name>(args)) rather than re-implementing the fetch/response
  transport, spliced into the SSR template via the existing loop/expression
  sentinel mechanism so the call runs inside the async render function with
  await support.
- A block that is both render-bound and called from code runs twice by
  design (no dedup); pinned with a test.
- Fix packages/syntax's attribute-value lexer (readQuoted) to honor
  backslash-escaped quotes, needed so an api="..." call expression can
  itself contain a quoted string/object literal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 07:38:32 +05:30
Clintchiz a08dfa5322 fix(compiler): reject dynamic api access in client functions
Usage-driven emission can only see api.<name> calls. api["name"]()
or passing api to a helper is invisible to it, silently drops the
block from the browser bundle, and fails at runtime instead of build
time. Detect that dynamic/indirect use (masking strings and comments
first, reusing the tokenizer's skipLiteralOrComment) and refuse to
compile instead, naming the offending function.
2026-08-20 07:25:02 +05:30
Clintchiz 712a6d3d8c feat(compiler): emit browser api bindings only where the client calls them 2026-08-20 07:19:55 +05:30
Clintchiz 9dec811069 fix(compiler): route the generated api object through the real buildApiRequest
Root-cause fix for the fix-round-1 review: the inlined query/body
assembly in __wrnexusCallApi was a third, unguarded copy of
buildApiRequest's rules. Restore the import of buildApiRequest from
@wrnexus/core in the generated module and delete the inline copy.

The four api-block-ssr.test.ts tests (and three in compiler.test.ts)
that dynamically import a generated module from an OS tmpdir were
failing against a stale globally-installed @wrnexus/core (v0.8.8,
predates buildApiRequest) because that tmpdir has no node_modules of
its own and bare-specifier resolution walked out of the workspace.
Fixed at the source: symlink the workspace @wrnexus/core into each
tmpdir root before the dynamic import, the same way every in-repo
package already resolves it.
2026-08-20 07:11:53 +05:30
Clintchiz 847b7010d1 feat(compiler): emit the server-side api object
Server module now declares `const api = { ... }` for apis {} blocks in
mode "any", dispatching in-process via requireRequestContext + the
existing __wrnexusCallApi transport helper. The try wraps only the
transport call; the response body runs after it, outside the try, so
a bug in the author's response code surfaces rather than being
mistaken for a request failure. A block with no error {} section
rethrows instead of resolving undefined.

Also closes the pageCtx.__wrnexusCallApi wiring gap in
dev-server/runtime.ts: it now forwards input through to
callApiFromContext instead of dropping it.
2026-08-20 07:03:11 +05:30
ClintchizandClaude Opus 5 97d60d0ba8 refactor: drop the deprecated compiler re-export shims
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 01:33:48 +05:30
ClintchizandClaude Opus 5 ec63090006 refactor: replace the legacy function runtime with shared
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:13:05 +05:30
ClintchizandClaude Opus 5 2f075df42c release: patch cli, compiler, core, csr, syntax, validation
Quality / quality (ubuntu-latest) (push) Failing after 9m55s
Quality / quality (windows-latest) (push) Canceled after 0s
Typed, callable api blocks for .wrn files: sectioned request/response/error,
callable from client code as api.name(input), type-checked by tsc against the
route contracts.

Also two fixes found along the way: defineEndpoint never received its input
through the real router, so every typed endpoint was validating undefined; and
v.boolean() silently coerced any unrecognised string to false.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 21:36:44 +05:30
Clintchiz 3ae5d7cf97 fix(compiler): stop error {} from swallowing response {} bugs in api blocks
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.
2026-08-19 21:11:26 +05:30
ClintchizandClaude Opus 5 b5029889a5 fix: address all seven final-gate findings for typed api blocks
B1: qualify each generated __wrn_api_check_* assertion name with a short
hash of the page's path (relative to app/, for reproducibility across
checkouts) so two pages declaring a same-named block no longer collide
with an identical type alias (TS2300).

B2: skip assertion emission for any block that is not client-mode, or
that has zero declared request fields. ssr sectioned blocks can never
declare a request and always fell back to Record<string, never>, whose
keyof is `string` -- making the key-exactness arm of AssertAssignable
evaluate to false unconditionally (TS2344) on every ssr sectioned block
regardless of correctness. Chose to skip both non-client blocks and
zero-field client blocks, since neither has anything meaningful to
assert type-safety about.

B3: only resolve the endpoint's input (query params / ctx.req.json())
when the endpoint declares an input schema. Previously the router-set
fix accidentally read the request body unconditionally, so a handler
with no input schema that parses the request itself hit
ERR_BODY_ALREADY_USED.

B4: run response/error bodies in client-mode api blocks through
eraseFunctionTypes, matching every other browser-bound body in
client-codegen.ts, so a TypeScript-only construct inside one (e.g. an
annotated locally-declared function) doesn't reach the .mjs artifact.

B5: only exclude "api" from state/prop destructuring in the generated
browser module when the page actually has client-mode api blocks (i.e.
there is a real `api` binding to shadow). Previously "api" was always
excluded, so a page with `state api` and no api blocks got an
undeclared `api` reference (ReferenceError) in client code.

B6: prefix each emitted assertion with `export`, so it isn't flagged as
an unused local under a downstream project's noUnusedLocals (TS6196).

B7: wrnexusCallApi now resolves with undefined for an ok 204/205
response, or an ok response with an empty/unparseable body, instead of
rejecting with "Response was not valid JSON" -- matching the spec's
failure table (error path only for non-2xx, network failure, or an
actually unparseable body on a non-empty response).

Regenerated examples/basic-app's generated types and editor bundles to
match. Confirmed the example's type gate still fails when an
unaccepted field is added to a request body, and passes cleanly
otherwise.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 20:38:22 +05:30
ClintchizandClaude Opus 5 3252b1b20e fix(compiler): type-check the emitted ssr binding array and share error handling across call sites
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 16:42:38 +05:30
ClintchizandClaude Opus 5 7601477f7d feat(compiler): run error section on ssr api call failure
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 16:24:20 +05:30
ClintchizandClaude Opus 5 847b6dbe59 feat(compiler): support sections in ssr api blocks
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 16:19:27 +05:30
ClintchizandClaude Opus 5 70777e4a45 fix(compiler): reserve api as a runtime binding to avoid client-scope collision
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 15:45:09 +05:30
ClintchizandClaude Opus 5 bd2f6ac5e3 feat(compiler): compile client api blocks into the browser module
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 15:41:13 +05:30
ClintchizandClaude Opus 5 2cbc3e43e1 release: patch compiler, cli, dev-server
Quality / quality (ubuntu-latest) (push) Failing after 9m51s
Quality / quality (windows-latest) (push) Canceled after 0s
Strips TypeScript from client function bodies when emitting browser
modules, so `wrnexus build` no longer fails on an annotated local.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 14:17:51 +05:30
ClintchizandClaude Opus 5 55fed2177a fix(compiler): strip TypeScript from client function bodies
Quality / quality (ubuntu-latest) (push) Failing after 9m53s
Quality / quality (windows-latest) (push) Canceled after 0s
`wrnexus build` failed on any client function whose body used TypeScript:

    const requestBody: Record<string, unknown> = {}
    error: Expected ";" but found ":"

Codegen copies a client function's body into the browser module verbatim.
It removes the types from the function's *signature*, which is what made
this easy to miss -- the emitted module looked transpiled, and only bodies
carried types through. The artifact is written as .mjs and read back as
plain JavaScript, so the failure surfaced as a syntax error in generated
code rather than at the .wrn line responsible.

Browser modules are now transpiled before they are written, at all three
sites that emit one (the production build and both dev-server paths).

Reproduced end to end: a page with an annotated body failed the build with
the reported errors, and after the fix builds, ships valid minified JS, and
runs -- the handler sets its state correctly in a browser.

Note: the same body is also embedded as a string for the CSP-safe fallback
interpreter, which still receives it untranspiled. The compiled module
shadows the fallback, so this is only reachable in the window before that
module loads. Left alone here because stripping it lives in codegen, which
also runs under Node in the editor bundle where the Bun transpiler is
unavailable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 14:03:14 +05:30
Clintchiz f199385204 Make if and each blocks reactive on the client
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-19 00:22:00 +05:30
ClintchizandClaude Opus 5 afa2a8c093 chore(deps): move packages to TypeScript 6.0.3
Raises the typescript devDependency across the workspace, bumps package
versions, re-adds ignoreDeprecations, and repoints the @wrnexus registry.

These were pre-existing working-tree changes, committed as-is rather than
authored here. The .npmrc change redirects @wrnexus publishes from
registry.npmjs.org to registry.workroot.in — confirm that is intended
before publishing from this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 19:16:34 +05:30
ClintchizandClaude Opus 5 843db2815f fix(islands): rebuild on .tsx edits and support islands inside components
Three bugs found by driving the dev server rather than reading code:

1. An island used inside a .wrn component still emitted a component mount
   — only the page and nested-page render paths were covered.

2. Editing an island .tsx never rebuilt in dev. The bundle cache was keyed
   on source path alone, and page modules are cached after the first
   request so no compile runs to notice the change. The cache key now
   includes mtime, and the file watcher rebuilds islands whose .tsx
   changed.

3. A .wrn cache hit skipped island building entirely, so after a restart
   with a warm cache no island bundle was ever produced. Island inputs are
   now persisted beside the other artifacts and rebuilt on a cache hit.

The islands manifest is deliberately excluded from the artifact
completeness check: only the async compile path writes it, so requiring it
made the sync path miss the cache on every call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 16:26:58 +05:30
ClintchizandClaude Opus 5 17aa3b98eb feat(islands): wire islands end to end
The island pieces existed but nothing connected .wrn compilation to island
emission. Now:

- codegen emits a data-wrn-island placeholder for component tags bound to
  .tsx imports, keeping .wrn components on the normal mount path
- the dev pipeline and static build resolve island imports, thread the
  names into codegen, and build the bundles
- collectScripts adds /__wrnexus/islands.js only when island markup is
  present, so island-free pages still ship nothing
- island routes classify as static-interactive via hasIslands

Three bugs found by driving a real page in the browser:

1. The mount runtime was never built anywhere, so the bootstrap 404'd and
   no island mounted.
2. Building the runtime separately from the islands gave each its own copy
   of React: "Cannot read properties of null (reading 'useState')". The
   runtime is now an entrypoint of the same build so React stays in one
   shared chunk. The existing single-React test only compared bundles
   within one build and could not see across build boundaries.
3. Island props arrived as attribute strings, so start={3} was "3" and
   incrementing produced "31" then "311". Props now follow JSX semantics:
   {…} parses as JSON, quoted values stay strings, and a runtime
   expression is a WRN-ISLAND-PROPS build error rather than a silent
   wrong value.

island-codegen.ts no longer imports @wrnexus/core. Compiler modules are
bundled into the Node-only VS Code extension, which contains no other
packages, so a runtime import of core broke the editor compiler; the two
helpers are implemented locally and the core dependency is dropped again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 16:16:03 +05:30
ClintchizandClaude Opus 5 442a3106ed test(islands): guard zero-JS routes and single-React bundling
Two guards protect the core promise: a route with no islands emits no
assets at all, and a page with several islands keeps React in one shared
chunk.

buildIslands now writes a generated entry per island instead of passing
component sources directly. Two islands sharing a source deduped to a
single entrypoint, and output order is not guaranteed to match input
order, so island names could bind to the wrong bundle.

Island modules are excluded from the editor compiler bundle: it globs
packages/compiler/src, and island-bundle.ts calls Bun.build while
island-codegen.ts imports @wrnexus/core — neither belongs in a Node-only
VS Code artifact.

Integration assertions share one build. bun test interferes with
Bun.build's module reads after several build calls in one process, while
the same calls succeed repeatedly outside the runner; production is
unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:50:26 +05:30
ClintchizandClaude Opus 5 01a3b3b4e9 feat(compiler): classify island routes as static-interactive
A route mounting an island ships JavaScript, so reporting it as zero-JS
static would make the framework's performance accounting wrong.

Adds a separate needsIslandRuntime flag rather than reusing
needsClientRuntime: an island needs the island runtime, not WRNexus's
reactive runtime, and conflating them would ship the wrong bundle.

analyzeRuntimeRequirements takes island presence as an optional second
argument, so existing callers are unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:30:19 +05:30
ClintchizandClaude Opus 5 06df9d66ae feat(compiler): bundle islands with a shared React chunk
splitting:true keeps React in one shared chunk so a page with several
islands does not ship react-dom repeatedly.

Island .tsx is compiled against React's JSX runtime via a Bun onLoad
plugin. The repo's root tsconfig sets jsxImportSource to @wrnexus/core,
so islands would otherwise compile to the HTML-string renderer and never
mount. A @jsxImportSource pragma only affects the file carrying it, so
injecting one into the generated entry is not enough — the injection has
to happen per source file. App-authored islands stay plain .tsx.

The JSX test asserts built output rather than generated entry text,
because the entry-text assertion passed while the mechanism did not work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:22:58 +05:30
ClintchizandClaude Opus 5 b405025f37 feat(compiler): resolve .tsx imports and tag them as islands
.wrn keeps resolution priority so existing components are unaffected
when a .tsx file shares their name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:15:08 +05:30
ClintchizandClaude Opus 5 cd07f0f8e2 feat(compiler): add island marker codegen and props contract
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>
2026-08-18 15:13:56 +05:30
Clintchiz f68f79786f fix: compile typed catches and reject event loop syntax
Quality / quality (ubuntu-latest) (push) Failing after 9m46s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-12 19:36:18 +05:30
Clintchiz 2c960fc1dc refactor: migrate legacy wire namespace to wrn
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-12 18:51:15 +05:30
Clintchiz feff30a2b5 release: prepare WRNexusJS 0.8.8
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-11 13:40:03 +05:30
Clintchiz 816594a58b release: prepare WRNexusJS 0.8.7
Quality / quality (ubuntu-latest) (push) Failing after 22s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-10 01:23:12 +05:30
Clintchiz 232d8e6734 complete performance and reliability follow-ups 2026-08-09 23:04:36 +05:30
Clintchiz 51286d0fa3 complete framework remediation validation 2026-08-09 14:39:22 +05:30
Clintchiz 09ebd44b6c fix compiler authoring traps and showcase generation order 2026-08-09 14:22:12 +05:30
Clintchiz fdf6282aed perf(compiler): share client function state closures 2026-08-09 13:38:55 +05:30
Clintchiz ca8aabf640 fix(compiler): avoid deferred helper name collisions 2026-08-09 13:34:17 +05:30
Clintchiz 8ef6233ef3 fix(compiler): reject malformed structured props 2026-08-09 13:24:18 +05:30
Clintchiz b2e83bc941 feat(compiler): commit deferred client state writes 2026-08-09 13:21:34 +05:30
Clintchiz a1f671ed5d feat(framework): make component props reactive 2026-08-09 13:17:36 +05:30
Clintchiz 35cd28aad4 revert(compiler): preserve inline structured component props 2026-08-09 13:00:18 +05:30
Clintchiz de8d792e37 fix(compiler): diagnose inline object component props 2026-08-09 12:58:02 +05:30
Clintchiz 64bb0e366a perf(compiler): deduplicate client peer state synchronization 2026-08-09 12:57:37 +05:30
ClintchizandClaude Opus 5 7a2b58652a chore(release): prepare 0.8.6
Quality / quality (ubuntu-latest) (push) Failing after 11m2s
Quality / quality (windows-latest) (push) Canceled after 0s
Bumps all 47 packages, the root manifest and the VS Code extension to 0.8.6,
and rebuilds the editor compiler, language server and extension bundles that
embed the version.

The release carries the output delivery fix: camelCase outputs now reach
parent bindings, and 18 components emit through output.* instead of
hand-built CustomEvents. See the 0.8.6 migration entry for what changes for
consumers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 01:54:44 +05:30
ClintchizandClaude Opus 5 1fb1a8d2d0 chore(release): prepare 0.8.5
Quality / quality (ubuntu-latest) (push) Failing after 12m21s
Quality / quality (windows-latest) (push) Canceled after 0s
Bumps every @wrnexus package 0.8.4 -> 0.8.5 and adds the matching update
migration. The migration is documentation only: moving off <Table> to
<DataTable> and off the @wrnexus/ui main entry to @wrnexus/ui/registry are
source changes no codemod can make safely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:08:05 +05:30
ClintchizandClaude Opus 5 949cf78636 feat(ui): add DataTable and Toaster, drop the legacy Table, fix overlay dialogs
Quality / quality (ubuntu-latest) (push) Failing after 13m40s
Quality / quality (windows-latest) (push) Canceled after 0s
DataTable replaces the 20-line Table scaffold entirely: columns, sorting,
filtering, pagination, selection, bulk actions, comparison layout, sticky
first column, custom HTML cells, and a remote source driven by a `request`
output rather than a function prop (props travel as HTML attributes, so a
function arrives as its own source text).

Toaster replaces the hand-rolled status div: tone icons, actions, hover
pause/resume and a progress bar.

Overlays audit -- Modal and Drawer declared aria-modal="true" but nothing
ever moved focus into the panel, so the @keydown handler on their root
never ran and closeOnEscape did nothing. Focus, focus restore, a Tab trap
and a body scroll lock now live in the reactive runtime, shared by both.

ContextMenu placed pointer menus by subtracting a guessed 340x420 from the
viewport, which pushed every menu that was not that size away from the
pointer; it now positions at the pointer and lets the anchored clamp pull
it back once it can be measured.

The reactive runtime size budget moves 150k -> 175k to cover anchored
overlays, dialog behaviour, the toaster and the DataTable client half.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 14:59:58 +05:30
Clintchiz 72e4d3eceb release: WRNexusJS 0.8.0
Quality / quality (ubuntu-latest) (push) Failing after 12m19s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-04 12:19:09 +05:30
Clintchiz 4cebacadfe release: WRNexusJS 0.8.3
Quality / quality (ubuntu-latest) (push) Failing after 12m9s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-03 19:47:30 +05:30
Clintchiz 4550a11460 release: WRNexusJS 0.8.2
Quality / quality (ubuntu-latest) (push) Failing after 22s
Quality / quality (windows-latest) (push) Canceled after 0s
2026-08-03 02:14:54 +05:30