Core perf, Kirewire rewrite, docs site, package hardening, vs-kire formatting#4
Merged
Conversation
Replace packages/wire from scratch with a server-driven reactive component system inspired by Livewire v3 but re-architected for TypeScript: built-in signal reactivity (no Alpine dependency), first-class SSE/WebSocket transport with server push/broadcast, and a single versioned wire protocol. Server core: contracts (snapshot/request/response/effects/push), synthesizers with allowlist, HMAC-signed snapshots, and the hydrate->update->call->render-> dehydrate pipeline. Class API via decorators (@Component/@prop/@locked/@computed/ @renderless/@on/@validate/@action/@lazy/@url) and a Feature/FeatureBus hook system (lifecycle, locked, validation, magic, lazy, url). Kire integration: @wire directive, <wire:*>/<kirewire:*>/<livewire:*> elements, @kirewireScripts, root wire:* attribute injection. Client: signal reactivity, $wire proxy + evaluator, standalone DOM morph, 5ms-buffered pooled requests, core directives (click/submit/model/init/poll/ loading), and HTTP/SSE/WebSocket transports. Server transport: in-memory broadcast Hub, framework-agnostic handleUpdate + node adapter, serveSse, serveWs. Security: tamper-rejected snapshots (419), method gating, @locked mass-assignment protection, @Validate rules, synth class allowlist. 44 tests passing (protocol, pipeline, features, SSR, JSDOM end-to-end, transport, v1.1); strict typecheck clean. Design: REACTIVE-DESIGN.md. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Finish the remaining Kirewire surface from REACTIVE-DESIGN.md phase 6: - Forms: WireForm base (validate/validateOrThrow/reset) driven by @Validate; nested wire:model writes through automatically. - Pagination: ORM-agnostic paginate() with full page metadata. - File uploads: WireFile + FileStore (MemoryFileStore), FileUploadSynth (serializes the reference, never bytes), FileUploadFeature (resolves wire-file tokens to WireFile in an update finisher), handleUpload; client $upload + file-input wire:model upload flow. - Synth helpers: modelSynth()/defineSynth() for class/model serialization behind the registry allowlist. - Client: $entangle two-way accessor, wire:confirm gating, runtime.upload/updateUrl. - Framework adapters: createFetchHandler (Web-standard Request/Response — Bun/Deno/ Hono/Elysia/Workers, serves update + multipart upload + SSE) and expressAdapter. - Build: build.ts produces server ESM/CJS and a minified, Node-free browser client bundle (verified); package build script; biome paths fixed. 54 wire tests (160 with core) pass; strict typecheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…re-rendered) Replace the sprawling wire-playground docs with a clean, Laravel-organized site rendered by Kire itself: - app/config (flat file per concern → composed), app/console (CLI + serve), app/http (kernel + Elysia controllers + html helper), app/providers/kire (configured engine + markdown plugin), app/routes/web (lazy controller table), app/services/content (frontmatter parse, nav groups, neighbors, search). - resources/views: DaisyUI shell (drawer sidebar + sticky navbar + theme toggle + live search), home / doc / not-found pages; markdown rendered to prose. - resources/content: the existing markdown docs, unchanged. - #app/* path alias (package.json imports + tsconfig paths). Styling via DaisyUI v4 + Tailwind Play CDN + typography. Verified live: home, all articles, /docs redirect, /search JSON, 404 — all 200/correct. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
New "Kirewire" section (10 pages) documenting the rewritten reactive package against its real API: overview, components & lifecycle, decorators, actions/$wire/ magic, validation & forms, events & broadcasting, client runtime & directives, transports (HTTP/SSE/WebSocket), file uploads, and security & synthesizers. - packages/wire.md reduced to a short package page pointing at the section. - config.docs.sectionOrder places Kirewire between Reference and Packages. Core-doc accuracy fixes (audited against source): document @attr/@attrs in the directives reference, make @csrf() consistent, document the use_global option. Package docs audited — verified accurate, no changes needed. All pages render live (200); search indexes the new content. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ssets tailwind — the core bug: `result.build(candidates)` was always called with an empty candidate list, so a <tailwind> block emitted base/preflight only and NONE of the utility classes used in the markup. Reworked: scan the fully-rendered HTML for class candidates and compile against them once per render (in the template epilogue), so every utility on the page is generated. Compiled CSS is cached by (css source + candidate set, bounded); @kirejs/assets offload + dedup restored. New extractCandidates() + renderTailwindBlocks(). Tests rewritten to cover the actual behavior (utilities generated, custom CSS kept, assets offload, caching). iconify — processSvgAttributes built a RegExp from caller-supplied attribute keys (ReDoS / malformed-regex). Rewritten to parse the <svg> opening tag with a fixed regex and rebuild it, escaping attribute values. fetchIcon now validates the prefix/name so an icon string can't inject path/query into the API URL. assets — $loadSVGAsset fetched any URL with no limits (SSRF). Added a guard that rejects loopback/private/link-local hosts and a 5s fetch timeout. docs — the layout's <style type="text/tailwindcss"> used `@apply bg-base-300/70` etc., which the Tailwind Play CDN can't resolve (DaisyUI colors), throwing CssSyntaxError in the browser. Replaced with plain CSS using DaisyUI variables. All package tests pass (tailwind 5, iconify 8, assets 7, markdown 12, utils 16, auth 7); changed tailwind src typechecks clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…code blocks
wire — add `wire:navigate` SPA link navigation to the client: intercept
`<a wire:navigate>` clicks (event delegation), fetch the page, morph its <body>
in, update history/title, re-bind components; popstate + hard-fallback handled.
Enabled by default in start({ navigate }).
docs —
- Live Kirewire playground: a Kirewire server (app/wire) with counter/todo/search
components, the /_wire update endpoint, kirewirePlugin on the engine, and a
@wire-mounted playground page surfaced in the Kirewire nav. Round-trip verified.
- Boot the bundled client (public/kirewire.js) so wire:navigate + components run;
wire:navigate added to sidebar/navbar/home/doc links.
- Markdown now emits clean <pre><code class="language-x"> (dropped the not-prose
wrapper) and is styled by Tailwind typography + highlight.js (re-highlights
after navigate).
- Layout: removed max-w-5xl/mx-auto (docs aren't centered); prose left-aligned at
a readable width; fixed the earlier @apply CssSyntaxError via DaisyUI variables.
54 wire tests pass; client typechecks clean; playground + /_wire verified live.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Two bugs made wire:navigate fall back to a full page reload:
1. The click delegation used `closest("a[wire\:navigate]")`. A colon-escaped
attribute selector is rejected as invalid by some selector engines (and is
fragile across browsers), so the link never matched and the browser performed
a normal navigation. Switched to `closest("a")` + `hasAttribute("wire:navigate")`.
2. Navigation morphed `document.body` from `<body>…</body>` HTML, but the HTML
parser strips `<body>` inside a <template>, leaving the body's first child as
the morph root → a tagName mismatch replaced <body>. Added morphInner(), which
patches an element's children from inner HTML, and use it for the body swap.
Verified end-to-end in JSDOM: click is intercepted (no reload), the page is
fetched, the body children are morphed in, and the title updates. Bundle rebuilt.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Run Kirewire inside a FiveM resource with NUI as the transport: - client FiveMTransport: posts updates to https://<resource>/_wire (resolving the name via GetParentResourceName) and receives server pushes on window 'message'. - server createFiveMHandler(wire): a RegisterNUICallback handler that runs the update pipeline and answers through the NUI callback (the fetch body). - FiveMBroadcaster(sendNuiMessage): a Broadcaster that pushes frames via SendNuiMessage, matching the client transport. No FiveM globals are imported — the host wires RegisterNuiCallback/SendNuiMessage in. 3 tests pass; docs page added (Kirewire › FiveM). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ntmatter vite — escape every URL interpolated into rendered <script>/<link> attributes (dev tags + manifest tags), reject directory-traversal asset paths from a poisoned manifest, validate the hot-file URL (no CRLF/junk into attributes), wrap bare IPv6 dev-server hosts in brackets (http://[::1]:5173), and wrap manifest JSON.parse with a clear error. utils/core — HtmlManager and the core Attributes class only escaped `"` in attribute values (invalid HTML, attribute-injection if user data flows through). Now full-escape attribute values, link href, and link text (XSS). markdown — mdrender/mdview now strip a leading YAML frontmatter block before parsing, so frontmatter no longer renders as visible content. (Route wildcard left as-is: `*` spanning segments is intended route-name matching, not a filesystem path.) All package + core tests pass (utils 16, markdown 12, vite 7, core 106); changed src typechecks clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- Remove vs-kire/tests/wire-schema.test.ts — it imported the deleted packages/wire/kire.schema.js (old wire) and asserted wire:navigate schema that no longer exists. - Add missing `example` fields to the new Kirewire Kire directives/element (@wire, @kirewireScripts, <wire:*>) so the schema-docs coverage guard passes and the VS Code extension can show usage examples. vs-kire tests 24/24, wire tests 57 — all green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- Remove vs-kire/tests/wire-schema.test.ts — it imported the deleted packages/wire/kire.schema.js (old wire) and asserted wire:navigate schema that no longer exists. - Add missing `example` fields to the new Kirewire Kire directives/element (@wire, @kirewireScripts, <wire:*>) so the schema-docs coverage guard passes and the VS Code extension can show usage examples. vs-kire tests 24/24, wire tests 57 — all green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The formatter previously only re-indented the body of <?js ?>, <script>, and <style> blocks (formatEmbeddedText was a no-op for actual code style). Now it runs the fragment through Prettier's standalone build (babel/typescript/postcss parsers), honoring the editor's tab width / spaces, and falls back to plain re-indentation when the fragment can't parse mid-edit. New src/utils/formatCode.ts (testable outside VS Code) + 6 unit tests; bundle includes Prettier. tsc clean, 30 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
| if ("push" in msg) { | ||
| for (const cb of this.listeners) cb(msg.push); | ||
| } else { | ||
| this.pending.get(msg.id)?.(msg.response); |
| this.listeners.add(onPush); | ||
| if (!this.bound) { | ||
| this.bound = true; | ||
| window.addEventListener("message", (event: MessageEvent) => { |
| const fn = new Function( | ||
| "$wire", | ||
| "$event", | ||
| `with($wire){ return (${expr}); }`, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Large multi-area branch. Highlights:
Core
Attributesclass.Kirewire (
packages/wire) — full rewrite@Component/@prop/@locked/@computed/@on/@validate/@renderless/@lazy/@url), HMAC-signed snapshots, synthesizers, pipeline, features.$wire, request batching.Hub; framework adapters (fetch/express); FiveM NUI transport + bridge.wire:navigateSPA nav.Docs site
wire:navigate.Packages
vs-kire
All package + core + wire + vs-kire test suites pass.
🤖 Generated with Claude Code