diff --git a/AGENTS.md b/AGENTS.md index 8a14c7f..38979b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,74 +1,59 @@ -# hemx — AGENTS.md +# AGENTS.md -## Purpose +## Authority and workflow -This file tells coding agents how to work in this repository. It is a durable operating contract, not a generated inventory. +Repository-root `INTENT.tsv` and `SPEC.tsv` are the sole product authorities. `INTENT.tsv` owns `PROBLEM`, `FOR`, and `OUTCOME`; `SPEC.tsv` owns falsifiable `RULE` records and their `INTENTS` edges. Code, tests, runtime observations, public documentation, `handoff.md`, and history are evidence, not parallel canon. Durable behavior changes update the canonical TSV first. `PLAN.md` is the disposable current execution surface. -Keep it stable. Prefer pointers to canonical sources over copied structure, file lists, metrics, architecture maps, command inventories, or status snapshots. +Use `# intent: ` and `# spec: ` with the Redgate roles `impl`, `check`, `doc`, and `exception`. Put `check` only on the local executable assertion or focused command that would fail for that rule. Other roles provide traceability but do not satisfy `redgate check`; exceptions expose debt and never make strict checks pass. Feed findings back into authority, implementation, or proof rather than weakening checks. -## Agent workflow +Run `redgate list`, `redgate refs`, `redgate lint`, and `redgate check` before completion. Broad or risky completion claims also require an independent fresh-context conformance review after deterministic checks pass. -- Start from product intent and requirements; inspect code only after the target behavior is clear. -- For v1 work, read `docs/v1-product-evidence.md`, then `REQUIREMENTS.md`; use `PLAN.md` only as the mutable implementation cursor. -- Read `REQUIREMENTS.md` before changing behavior. -- If behavior changes, update `REQUIREMENTS.md` in the same change. -- If implementation work does not change durable product obligations, acceptance, safety/recovery behavior, or verification duties, say `REQUIREMENT IMPACT: none` in the handoff and why. -- Cite relevant requirements in code, tests, or docs as `req: /001`. -- Do not add citation-only padding to satisfy tooling; cite only where the requirement constrains the text. -- Use requirement tags consistently: stable area tags like `[parser]`, `[auth]`, `[ui]`; temporary planning tags like `[bootstrap]`, `[mvp]`, or `[milestone-1]` only while they are useful. -- Run `redgate list`, `redgate refs`, and `redgate health` when requirements change; include `redgate lint` when the change is meant to reduce requirement maintainability warnings. +Final handoffs include `INTENT IMPACT` and `SPECIFICATION IMPACT`: changed IDs, proof, and any unresolved gap. -## Git workflow +## Workspace ownership -- Commit complete, coherent slices only; do not commit broken work or temporary debug output. -- Use Conventional Commits: `type(scope): summary`. -- Keep commit subjects readable; requirement IDs do not have to be in the subject. -- Every behavior-changing or requirement-changing commit should cite relevant requirement IDs in the commit body or trailers using `req: /001`. -- Use commit history for evolution: `git log --grep 'req: parser/012'` should find the commits that changed that behavior. -- Use the current tree for state: `REQUIREMENTS.md`, citations, tests, and `redgate health` describe what is true now. -- Before committing requirement or behavior changes, run relevant tests and the strongest `redgate health` mode supported by the installed tool. Do not invent an unsupported `--strict` flag; report a tool/format mismatch explicitly. +The public core consists of seven packages: -## Requirements-first TDD +```text +hemx-core +hemx-derive +hemx-js +hemx-build +hemx-axum +hemx +hemx-test +``` -- Write requirements as desired behavior, not as a snapshot of current behavior. -- Keep each requirement row to one checkable obligation with an explicit redgate ring field; shorten near-limit rows or split oversized examples, escape hatches, or negative cases into separate stable IDs while preserving the original ID's main intent. -- First split intent into broad error classes: what can go wrong, and what outcome must hold. -- Test the largest risky classes before narrow examples. -- Add adversarial tests for malformed, hostile, ambiguous, missing, duplicated, and boundary inputs. -- When changing generated lowering, prove dynamic rendered attributes at the consumer boundary; literal lowering fixtures alone are insufficient. -- Do not over-codify existing behavior while direction is still moving. -- Add narrow concrete tests only after requirements converge into a stable direction. +`hemx-core` owns effects, typed resources, wire encoding, and fingerprints. `hemx-build` inspects Hemplate templates and emits generated resource metadata. `hemx-derive` owns macros. `hemx-js` owns the generic browser runtime. `hemx-axum` owns Axum transport. `hemx` is the facade. `hemx-test` owns public testing utilities. -## Redgate CLI +Server-side Wasm uses normal `hemx` and the portable Hemplate runtime. Host parser and Tree-sitter dependencies must not enter its target normal dependency graph. -- `redgate list` — show requirements as TSV. -- `redgate refs` — show `req:` citations found in the repo. -- `redgate health` — show uncited requirements, duplicate IDs, and stale citations. -- `redgate lint` — show maintainability warnings such as missing rings and oversized requirement rows; when fixing one row in a section, normalize nearby rows with the same warning if it stays a requirement-only cleanup. -- `redgate refs` — with the installed CLI, parse the elected requirement format and audit repository citations; `redgate health` additionally enforces a newer prescriptive-row style not yet elected by this requirements corpus. -- `redgate agents` — print this starter template; review, shrink, and edit before committing. +The public GitHub mirror is release output. Keep `INTENT.tsv`, `SPEC.tsv`, `PLAN.md`, `.redgate/`, requirement checks, and private workflow text out of it while preserving the tested product tree. Experimental browser-local host, Wasm, and synchronization work belongs in the separate private Labs repository and must not be copied into this core. -## Local guidance +## Required proof -- Add only durable style, ownership, gotchas, and at most a few stable commands agents should actually run. -- Prefer links or pointers to canonical sources over copied lists. -- Avoid project trees, architecture maps, generated inventories, current file sizes, issue lists, TODO inventories, and other snapshots that will rot. -- Stable commands: `cargo run -p hemx-xtask -- test`, `cargo run -p hemx-xtask -- mutation [PACKAGE] [SHARD/TOTAL]`, `cargo run -p hemx-xtask -- html-examples-smoke`, `cargo check --workspace`, `redgate refs`. Use the xtask runner for full verification so jobs are capped from local CPU and memory and commands resolve the workspace independently of the caller's directory; use the html_examples smoke for focused repo-owned browser verification of the HTML pattern gallery, no-reload dynamic interactions, and no `/tmp` scripts. Keep fast crate tests, focused browser smoke, and full xtask authority distinct; mutation shards use one-based `1..=TOTAL` numbering, allow the wrapper's 120-second floor for compiler probes, and rely on the wrapper's package-specific nested concurrency rather than direct `mutest` invocation. The full path should stay within a documented 10 minute local timeout or use every deterministic mutation shard under the same wrapper. req: test/004 req: test/006 req: test/012 req: test/013 req: test/014 req: test/015 req: test/016 req: test/020 req: test/022 req: test/023 -- Example behavior tests should prefer `hemx_test` generated-resource assertion methods over raw slot constants, raw effect/payload matching, or boolean predicates wrapped in opaque `assert!`; failures should include the expectation and actual effects, while rendered target/handle assertions should name the generated resource. Keep browser selector helpers as test adapters only, not authoring APIs. Process-backed tests use the RAII `TestProcess` harness rather than duplicating readiness loops and child cleanup. req: test/008 req: test/009 req: test/010 req: test/017 req: test/018 req: test/019 -- Run the workout product exemplar with `cargo run -p hemx-xtask -- workout dev` and open `http://127.0.0.1:3028`; set `HEMX_WORKOUT_ADDR=127.0.0.1:3030` if the default port is busy. Its durable visual direction and recovery expectations live in `examples/workout/DESIGN.md`. req: examples/008 -- Use the same Workout command surface for tests, production build, and mobile release: `cargo run -p hemx-xtask -- workout test`, `cargo run -p hemx-xtask -- workout build`, `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-release`, and `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-verify`; Android/iOS SDKs, store submission targets, and signing remain external blockers, not repo-owned secrets, and do not imply a broad `hemx-mobile` framework. req: examples/006 req: examples/011 req: examples/013 -- hemx core stays small: effects, typed ids, registries, and wire schema only; keep features in core only when they fit typed resources plus the closed EffectBatch op set, and treat DOM details as runtime lowering. Workspace crates stay separated, stable-Rust-compatible, and free of kitchen-sink boundaries; new primitives must delete special cases. Public identifiers should flow through typed wrappers over internal `ResourceId`/`ResourceRef`, not special-case opcodes. Wire output lowers symbolic authoring names to compact metadata, the versioned canonical hemx `EffectBatch` codec, postcard surface facts, and form-encoded public requests—not JSON. ABI/schema versions and build fingerprints must guard runtime/server compatibility. v0 scope is the checked hypermedia core plus page/runtime/wire/diagnostic/test/axum proof, not optional sync/wasm/query/auth/router breadth. req: v0_scope/001 req: v0_scope/002 req: v0_scope/005 req: laws/001 req: invariant/001 req: invariant/005 req: typed_id/001 req: typed_id/003 req: effect_algebra/001 req: effect_algebra/006 req: wire/001 req: wire/002 req: wire/003 req: wire/004 req: wire/005 req: wire/006 req: abi/001 req: abi/002 req: abi/003 req: abi/004 req: abi/005 req: misc/001 req: misc/002 req: misc/003 req: misc/004 req: misc/005 req: misc/006 req: misc/007 req: misc/008 req: misc/009 req: misc/010 -- Routing, auth, sessions, transport, transitions, sync, async data helpers, multipart parsing/uploads, and storage belong in integration/user crates; hemx-axum preserves normal HTTP auth, credentials, CSRF, multipart/browser fallback, and progressive-enhancement semantics rather than defining policy in core. Sync is optional integration state reconciliation over push/transport, not core. req: auth/001 req: auth/002 req: auth/003 req: auth/004 req: auth/005 req: async_data/001 req: async_data/002 req: async_data/003 req: multipart/001 req: multipart/002 req: multipart/003 req: sync/001 req: sync/008 -- The SaaS production reference must use real links/URLs for navigation and an ongoing server-owned canonical SSE stream; bounded one-event behavior is a test probe, not the public transport contract. Browser history restores saved generated page snapshots and scroll position when available, with partial-fetch fallback, and restored revealed bindings must re-arm. req: nav/001 req: nav/002 req: nav/005 req: convention/014 req: push/003 req: examples/014 -- Public examples and beginner APIs should use templates plus Rust, generated component APIs, resources, view wrappers, render/page helpers, `#[hemx::app]`, plain `#[hemx::handler]` functions, and `IntoEffect`, not atoms, raw ids, selectors, wire formats, runtime opcodes, manual registries, `$OUT_DIR` includes, raw render/lower calls, raw HTML construction, imperative DOM mutation, or raw effect constructors; keep advanced layers out of starters. req: canonical_authoring/001 req: canonical_authoring/004 req: canonical_authoring/006 req: canonical_authoring/010 req: canonical_authoring/015 req: invariant/003 req: dx/001 req: dx/002 req: dx/010 req: component/003 req: component/004 req: component/005 req: view/001 req: view/002 req: view/003 req: html_safety/001 req: html_safety/003 req: html_safety/005 req: public_api/001 req: public_api/002 req: public_api/003 req: public_api/005 req: public_api/006 req: progressive_disclosure/001 req: progressive_disclosure/002 req: progressive_disclosure/003 req: derive_app/001 req: derive_app/002 req: derive_handler/001 req: derive_handler/002 req: derive_handler/003 req: derive_handler/004 req: derive_handler/005 -- Typed partial swaps should stay expressed as generated target plus rendered partial plus swap kind, not selector-driven rerendering or response-side selector retargeting; HTTP, page navigation, push, and island behavior adapt around that loop, and docs should layer new primitives progressively. Navigation is an effect/page-swap concern, not a core router framework; enhanced links and GET forms preserve real URL/history semantics so page state stays reloadable/shareable without a client state graph. Push streams carry canonical versioned hemx `EffectBatch` bytes over server-owned SSE/WebSocket transport and keep `data-hemx-sse` and `data-hemx-ws` root-scoped/same-origin by default. A Cloudflare Durable Object proof keeps stable named-object authority and persisted Rust domain state, uses WebSocket hibernation for eviction recovery, and broadcasts rendered effects without storing DOM patches or effects as domain truth. Preserve keyed/optional scope identity for addressable loop nodes, reconcile filtered keyed collections without clearing retained rows, prefer generated keyed-slot helpers over low-level keyed calls, and route self/row-update diagnostics toward local `data-hemx-slot`/`h-key` targets. req: canonical_authoring/002 req: canonical_authoring/014 req: modes/001 req: scope/001 req: list/001 req: list/002 req: list/003 req: list/004 req: list/005 req: list/006 req: nav/001 req: nav/002 req: nav/003 req: nav/004 req: nav/005 req: push/001 req: push/002 req: push/003 req: push/004 req: push/005 req: push/006 req: push/007 req: push/009 req: push/010 req: push/011 req: progressive_disclosure/004 req: page_swap/001 req: page_swap/002 req: page_swap/003 req: locality/001 req: locality/002 req: target_policy/001 req: target_policy/002 -- `examples/html_examples` is the copy-paste HTML pattern gallery for htmx-style examples; keep exact htmx URL slugs visible while translating behavior to boring `.heml`, generated resources, and server-owned Rust state, not HTMX syntax, selector targeting, or user-authored browser JavaScript. Shared runtime loading and declarative `data-hemx-*` are allowed. Boost containers enhance same-origin descendants only and preserve native external/download/new-tab behavior. req: htmx_equivalents/001 req: htmx_equivalents/003 req: htmx_equivalents/005 req: examples/005 req: examples/007 req: examples/012 req: page_swap/007 req: page_swap/008 -- Use `cargo run -p hemx-xtask -- app new PATH` for the generic page/form/keyed-row/notice starter, and `cargo run -p hemx-xtask -- app new --mobile PATH` for the phone-first starter with host capabilities, recovery truth, and release-kit commands; do not treat it as a mobile framework or store-submission bot. req: ceremony/005 req: ceremony/006 req: ceremony/007 -- The public component-reuse explanation lives in `docs/recipes/reusable-partials.md`; do not grow a client component framework to explain partial composition. -- The stable public `.heml` authoring surface lives in `docs/hemplate-syntax.md`; Hemlate examples must use that real hemplate syntax, not Vue/Handlebars sketches. hemx-build consumes hemplate Surface facts and must not grow an independent `.heml` parser or CSS-path identity model. Plain CSS/SCSS owns appearance; generated class constants are ergonomic references, not a styling framework or behavior selector system. Generated resources, form/handle metadata, atoms, and event constants come from hemx-build facts, not hand-written app plumbing. Forms remain HTML-shaped, checked against user-authored Rust domain types, parsed through `FormValue`, and manipulated through generated form/control ids rather than selectors. Proc-macros stay local/side-effect-free while build.rs owns global codegen and hard build failures. No-op global codegen must preserve generated artifact timestamps so downstream Rust compilation remains fresh only when canonical output changes. req: boundary/001 req: boundary/002 req: boundary/003 req: boundary/004 req: surface/001 req: surface/002 req: surface/003 req: surface/004 req: surface/005 req: surface/006 req: surface/007 req: surface/008 req: surface/009 req: surface/010 req: codegen/001 req: codegen/003 req: codegen/004 req: codegen/005 req: codegen/006 req: form/001 req: form/004 req: form/007 req: form/008 req: form_effects/001 req: form_effects/002 req: form_effects/003 req: build/001 req: build/002 req: build/003 req: build/004 req: build/005 req: build/006 req: build/007 req: build/008 req: build/009 req: style/001 req: style/002 req: style/003 req: style/004 req: style/005 req: style/006 -- Optional `.heml` editor overlays must share authority with `hemx-build` diagnostics and `docs/hemplate-syntax.md`; `hemx-lsp` owns editor protocol glue for diagnostics/completion/hover and derive-known template facts, while VS Code/Cursor/Neovim keep normal HTML/tree-sitter tooling. Simple `h-for` completion facts cover one Rust identifier bound directly to a `self` vector field; malformed bindings and non-vector fields must not fabricate locals. Do not create a second template language, selector model, formatter, Rust type system, or custom editor framework. Compiler diagnostics with directive/target metadata select that source attribute instead of line 0 column 0. Cross-file template/handler references visible to build validation must fail at `cargo check` with useful spans; global completeness checks stay component-scoped unless caught at mount/tests. req: diagnostics/004 req: diagnostics/005 req: diagnostics/006 req: diagnostics/007 req: diagnostics/008 req: diag/009 req: diag/010 req: invariant/004 req: invariant/006 req: check/001 req: check/003 -- JS runtime changes must preserve root-scoped lookup, delegated listeners, canonical hemx `EffectBatch` application, dynamic polling and viewport-aware revealed binding, fail-closed request handling, transactional/recoverable failure behavior, root-scoped error outlets, and tiny pending/failure/trigger-timing conventions without selectors, handler-name parsing, VDOM, expressions, or per-node listeners. Runtime `.d.ts` types are developer convenience only, not core tooling authority. req: invariant/002 req: runtime/001 req: runtime/002 req: runtime/003 req: runtime/005 req: runtime/006 req: runtime/007 req: failure/001 req: failure/002 req: failure/003 req: failure/004 req: failure/005 req: failure/006 req: convention/001 req: convention/002 req: convention/003 req: convention/004 req: convention/005 req: convention/006 req: convention/007 req: convention/008 req: convention/009 req: convention/010 req: convention/011 req: convention/012 req: convention/013 req: convention/014 req: convention/015 req: convention/016 req: convention/017 req: ts/001 -- Opaque island JavaScript is a leaf adapter for high-frequency local behavior only; client-local handlers keep the server-handler shape while `hemx-wasm` owns concrete opt-in syntax. Use native events/generated helpers at the boundary and do not introduce a component runtime, client state graph, VDOM, selector interop, or second UI model. req: canonical_authoring/017 req: client_local/001 req: client_local/003 req: client_local/004 req: interop/001 req: interop/002 req: interop/003 req: interop/006 req: interop/007 req: interop/008 req: interop/009 req: interop/010 req: interop/011 req: interop/012 -- Host capability adapters must stay at the `hemx-host` boundary: typed capabilities use fire/request/stream/schedule shapes; adapters may call host APIs and return host events, but they must not mutate DOM or own app/domain state. req: host/001 req: host/002 -- Local/offline app behavior should be commands/events/projections; do not add `hemx-local`, stored DOM patches, stored `EffectBatch` truth, or a core client state graph without a proven reusable contract. Atoms are explicit addressable/bootstrap/sync resources, not the default state container or a reactive framework. Replay, reconciliation, export, and deletion rules stay explicit product decisions, and exemplars should show UI effects as app-state output. The local-first multiplayer kanban remains an advanced north-star integration milestone, not beginner/API surface scope. req: canonical_authoring/018 req: canonical_authoring/019 req: state/001 req: state/002 req: state/003 req: state/004 req: state/005 req: state/006 req: state/007 req: local/001 req: local/002 req: local/003 req: local/004 req: milestone/001 req: milestone/002 req: milestone/003 -- Axum 0.8 apps should serve and load the shared runtime through hemx-axum helpers such as `runtime_js_path()` and `runtime_js()`, not hard-coded `/hemx.js` URLs or app-owned cache-busting strings; keep hemx-axum as route/runtime/handler adapter around generated partial swaps, not a routing owner. req: axum/002 req: axum_integration/001 req: axum_integration/002 req: axum_integration/003 req: axum_integration/005 req: axum_integration/006 +Run the narrowest relevant test while editing. Before completion run: + +```console +redgate list +redgate refs +redgate lint +redgate check +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test --workspace --all-targets --all-features +cargo deny check licenses sources +cargo check -p hemx-server-wasm-test --target wasm32-unknown-unknown +cargo tree -p hemx-server-wasm-test --target wasm32-unknown-unknown --edges normal,no-proc-macro +``` + +The target tree must contain neither `tree-sitter` nor `hemplate-parser`. Publishable package changes also require archive-based `cargo package --list` and `cargo package` checks for all seven packages. + +## Product constraints + +- The server owns effects and behavior; generated typed resources connect templates to handlers and effects. +- Raw HTML remains explicit and typed. +- Canonical wire bytes and ABI compatibility remain deterministic. +- Framework behavior stays in `hemx-axum`; browser runtime behavior stays in `hemx-js`. +- Public docs change with APIs, package boundaries, or compatibility. +- Preserve licenses; do not commit archives, `target/`, coverage, fuzz, mutation, local editor, or private governance output to the public mirror. diff --git a/Cargo.lock b/Cargo.lock index f909616..2bd129a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,47 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "arc-swap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" -dependencies = [ - "rustversion", -] - -[[package]] -name = "async-trait" -version = "0.1.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" - [[package]] name = "axum" version = "0.8.9" @@ -60,30 +19,24 @@ checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "bytes", - "form_urlencoded", "futures-util", "http", "http-body", "http-body-util", - "hyper", "hyper-util", "itoa", - "matchit 0.8.4", + "matchit", "memchr", "mime", "multer", "percent-encoding", "pin-project-lite", "serde_core", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", "sync_wrapper", "tokio", "tower", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -102,15 +55,8 @@ dependencies = [ "sync_wrapper", "tower-layer", "tower-service", - "tracing", ] -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "bitflags" version = "2.13.1" @@ -126,18 +72,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bumpalo" -version = "3.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.12.1" @@ -146,9 +80,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.4.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "shlex", @@ -160,62 +94,13 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" - -[[package]] -name = "chacha20" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core", -] - -[[package]] -name = "chrono" -version = "0.4.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" -dependencies = [ - "js-sys", - "num-traits", - "wasm-bindgen", -] - [[package]] name = "cobs" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.20", -] - -[[package]] -name = "const_format" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" -dependencies = [ - "const_format_proc_macros", - "konst", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "thiserror", ] [[package]] @@ -227,21 +112,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crypto-common" version = "0.1.7" @@ -306,17 +176,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "displaydoc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - [[package]] name = "dtoa" version = "1.0.11" @@ -365,16 +224,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "fastrand" version = "2.5.0" @@ -383,18 +232,9 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "find-msvc-tools" -version = "0.1.11" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "futf" @@ -406,62 +246,26 @@ dependencies = [ "new_debug_unreachable", ] -[[package]] -name = "futures-channel" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" -dependencies = [ - "futures-core", -] - [[package]] name = "futures-core" -version = "0.3.34" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" - -[[package]] -name = "futures-io" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" - -[[package]] -name = "futures-macro" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "futures-sink" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-task" -version = "0.3.34" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-util" -version = "0.3.34" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "slab", ] @@ -485,82 +289,38 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "rand_core", - "wasm-bindgen", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin 0.9.8", - "stable_deref_trait", -] - [[package]] name = "hemplate" -version = "0.1.0" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbe24674c08ea9cb50edc015ebd364785a7e3985259dc02de1a20b7b2ba6365" dependencies = [ - "hemplate-core", "hemplate-derive", + "hemplate-runtime", ] [[package]] name = "hemplate-core" -version = "0.1.0" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afe08241413edd4646684b396061b67e7fd17856f7e28d6765689612e2085303" dependencies = [ "hemplate-parser", - "thiserror 2.0.20", + "thiserror", "tree-sitter", ] [[package]] name = "hemplate-derive" -version = "0.1.0" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed77b2cc320137a6a68866f7aa8231292638f0b7c02f65cef221fe713fc2bad" dependencies = [ "hemplate-core", "proc-macro2", @@ -571,6 +331,8 @@ dependencies = [ [[package]] name = "hemplate-parser" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5418a7a1c7640f287133c512d400e2d1d2e083c86f9a6cb16501f36dd98636a2" dependencies = [ "tree-sitter", "tree-sitter-hemplate", @@ -579,20 +341,24 @@ dependencies = [ [[package]] name = "hemplate-runtime" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e235b36e44fe1174267df3ad0952a728afe4305edfbc8804a972b5f0121c06" +dependencies = [ + "thiserror", +] [[package]] name = "hemx" -version = "0.1.0" +version = "0.3.0" dependencies = [ "hemplate", "hemx-core", "hemx-derive", - "hemx-wasm", ] [[package]] name = "hemx-axum" -version = "0.1.0" +version = "0.3.0" dependencies = [ "axum", "futures-util", @@ -605,41 +371,17 @@ dependencies = [ [[package]] name = "hemx-build" -version = "0.1.0" +version = "0.3.0" dependencies = [ "hemplate-core", "hemx-core", "quote", - "serde_json", "syn 2.0.119", ] -[[package]] -name = "hemx-client-local-example" -version = "0.1.0" -dependencies = [ - "hemplate", - "hemx", - "hemx-build", -] - -[[package]] -name = "hemx-cloudflare-do-example" -version = "0.1.0" -dependencies = [ - "hemplate-derive", - "hemplate-runtime", - "hemx", - "hemx-build", - "hemx-js", - "postcard", - "serde", - "worker", -] - [[package]] name = "hemx-core" -version = "0.1.0" +version = "0.3.0" dependencies = [ "postcard", "serde", @@ -647,175 +389,40 @@ dependencies = [ [[package]] name = "hemx-derive" -version = "0.1.0" +version = "0.3.0" dependencies = [ "proc-macro2", "quote", "syn 2.0.119", ] -[[package]] -name = "hemx-host" -version = "0.1.0" -dependencies = [ - "hemx-core", - "serde", -] - -[[package]] -name = "hemx-html-examples" -version = "0.1.0" -dependencies = [ - "axum", - "hemplate", - "hemx", - "hemx-axum", - "hemx-build", - "hemx-test", - "scraper", - "tokio", -] - [[package]] name = "hemx-js" -version = "0.1.0" +version = "0.3.0" dependencies = [ "sha2", ] [[package]] -name = "hemx-kanban-example" +name = "hemx-server-wasm-test" version = "0.1.0" dependencies = [ - "axum", - "futures-util", "hemplate", "hemx", - "hemx-axum", "hemx-build", - "hemx-sync", - "hemx-test", - "scraper", - "serde", - "serde_json", - "thirtyfour 0.35.0", - "tokio", - "tower", -] - -[[package]] -name = "hemx-lsp" -version = "0.1.0" -dependencies = [ - "hemx-build", - "serde_json", -] - -[[package]] -name = "hemx-saas-example" -version = "0.1.0" -dependencies = [ - "axum", - "futures-util", - "hemplate", - "hemx", - "hemx-axum", - "hemx-build", - "hemx-test", - "scraper", - "tokio", -] - -[[package]] -name = "hemx-sync" -version = "0.1.0" -dependencies = [ - "hemx-core", - "hemx-sync-macros", - "serde", - "serde_json", -] - -[[package]] -name = "hemx-sync-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "hemx-techdemo" -version = "0.1.0" -dependencies = [ - "axum", - "futures-util", - "hemplate", - "hemx", - "hemx-axum", - "hemx-build", - "hemx-host", - "hemx-test", - "scraper", - "thirtyfour 0.35.0", - "tokio", ] [[package]] name = "hemx-test" -version = "0.1.0" -dependencies = [ - "hemx-build", - "hemx-core", -] - -[[package]] -name = "hemx-v0-examples" -version = "0.1.0" +version = "0.4.0" dependencies = [ "axum", - "futures-util", - "hemplate", - "hemx", "hemx-axum", "hemx-build", - "hemx-test", + "hemx-core", "scraper", "tokio", -] - -[[package]] -name = "hemx-wasm" -version = "0.1.0" -dependencies = [ - "hemx-core", - "serde_json", - "thirtyfour 0.36.1", - "tokio", - "wasm-bindgen", -] - -[[package]] -name = "hemx-workout-example" -version = "0.1.0" -dependencies = [ - "axum", - "hemplate", - "hemx", - "hemx-axum", - "hemx-build", - "hemx-host", - "hemx-test", - "thirtyfour 0.36.1", - "tokio", -] - -[[package]] -name = "hemx-xtask" -version = "0.1.0" -dependencies = [ - "hemx-js", + "tower", ] [[package]] @@ -850,9 +457,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" dependencies = [ "bytes", "futures-core", @@ -879,35 +486,13 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" dependencies = [ - "atomic-waker", "bytes", - "futures-channel", - "futures-core", "http", "http-body", - "httparse", "httpdate", - "itoa", "pin-project-lite", "smallvec", "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", ] [[package]] @@ -916,125 +501,13 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", "bytes", - "futures-channel", - "futures-util", "http", "http-body", "hyper", - "ipnet", - "libc", - "percent-encoding", "pin-project-lite", - "socket2", "tokio", "tower-service", - "tracing", -] - -[[package]] -name = "icu_collections" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" - -[[package]] -name = "icu_properties" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" - -[[package]] -name = "icu_provider" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", ] [[package]] @@ -1047,56 +520,18 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "ipnet" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" - [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" -[[package]] -name = "js-sys" -version = "0.3.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" -dependencies = [ - "cfg-if", - "futures-util", - "wasm-bindgen", -] - -[[package]] -name = "konst" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" -dependencies = [ - "konst_macro_rules", -] - -[[package]] -name = "konst_macro_rules" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" - [[package]] name = "libc" version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" -[[package]] -name = "litemap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" - [[package]] name = "lock_api" version = "0.4.14" @@ -1112,12 +547,6 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "mac" version = "0.1.1" @@ -1135,12 +564,6 @@ dependencies = [ "web_atoms", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "matchit" version = "0.8.4" @@ -1167,7 +590,7 @@ checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "wasi", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1183,7 +606,7 @@ dependencies = [ "httparse", "memchr", "mime", - "spin 0.9.8", + "spin", "version_check", ] @@ -1193,21 +616,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - [[package]] name = "parking_lot" version = "0.12.5" @@ -1231,19 +639,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "paste" -version = "1.0.15" -dependencies = [ - "pastey", -] - -[[package]] -name = "pastey" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -1303,26 +698,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1338,19 +713,9 @@ dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", - "heapless", "serde", ] -[[package]] -name = "potential_utf" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" -dependencies = [ - "zerovec", -] - [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1366,62 +731,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quinn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.20", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" -dependencies = [ - "bytes", - "getrandom 0.4.3", - "lru-slab", - "rand", - "rand_pcg", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.20", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.61.2", -] - [[package]] name = "quote" version = "1.0.47" @@ -1431,38 +740,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "rand" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" -dependencies = [ - "chacha20", - "getrandom 0.4.3", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - -[[package]] -name = "rand_pcg" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -1501,58 +778,6 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" -[[package]] -name = "reqwest" -version = "0.12.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64", - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rustc-hash" version = "2.1.3" @@ -1568,53 +793,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustls" -version = "0.23.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - [[package]] name = "scopeguard" version = "1.2.0" @@ -1671,17 +849,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - [[package]] name = "serde_core" version = "1.0.229" @@ -1716,40 +883,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" -dependencies = [ - "itoa", - "serde", - "serde_core", -] - -[[package]] -name = "serde_repr" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "servo_arc" version = "0.4.3" @@ -1766,7 +899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "digest", ] @@ -1776,16 +909,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - [[package]] name = "siphasher" version = "1.0.3" @@ -1811,21 +934,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] name = "spin" -version = "0.9.8" -dependencies = [ - "spin 0.12.2", -] - -[[package]] -name = "spin" -version = "0.12.2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8abadc99fd9c7bbb7d0ca2b31d72a067d0c0dcd7aad25ab8cac71ba91417694b" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" [[package]] name = "stable_deref_trait" @@ -1863,21 +979,6 @@ dependencies = [ "quote", ] -[[package]] -name = "stringmatch" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aadc0801d92f0cdc26127c67c4b8766284f52a5ba22894f285e3101fa57d05d" -dependencies = [ - "regex", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "syn" version = "2.0.119" @@ -1905,20 +1006,6 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] [[package]] name = "tendril" @@ -1931,152 +1018,38 @@ dependencies = [ "utf-8", ] -[[package]] -name = "thirtyfour" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d1dd5271076f9cf5cb6a673497d1476cda2633e6cf2523edd00ac16218d651" -dependencies = [ - "arc-swap", - "async-trait", - "base64", - "bytes", - "cfg-if", - "const_format", - "futures-util", - "http", - "indexmap", - "paste", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "stringmatch", - "thirtyfour-macros", - "thiserror 1.0.69", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "thirtyfour" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f1edfb88bbdf0365c6dc161e8694ce8414c0b79d0d3a3663b4baac62236be0" -dependencies = [ - "arc-swap", - "async-trait", - "base64", - "bytes", - "cfg-if", - "const_format", - "futures-util", - "http", - "indexmap", - "paste", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "stringmatch", - "thirtyfour-macros", - "thiserror 2.0.20", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "thirtyfour-macros" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf0ffc3ba4368e99597bd6afd83f4ff6febad66d9ae541ab46e697d32285fc0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" -dependencies = [ - "thiserror-impl 2.0.20", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" dependencies = [ "proc-macro2", "quote", "syn 3.0.3", ] -[[package]] -name = "tinystr" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ - "bytes", "libc", "mio", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -2090,16 +1063,6 @@ dependencies = [ "syn 3.0.3", ] -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - [[package]] name = "tower" version = "0.5.3" @@ -2113,25 +1076,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", - "url", ] [[package]] @@ -2146,38 +1090,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - [[package]] name = "tree-sitter" version = "0.25.10" @@ -2195,6 +1107,8 @@ dependencies = [ [[package]] name = "tree-sitter-hemplate" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "270b8e8df72e7eb7e35b0ecae814a068da5218f482d48c867054792502bfd3b8" dependencies = [ "cc", "tree-sitter-language", @@ -2206,12 +1120,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782" -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typenum" version = "1.20.1" @@ -2230,156 +1138,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasm-bindgen" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.119", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "web_atoms" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" dependencies = [ "phf", "phf_codegen", @@ -2387,30 +1168,12 @@ dependencies = [ "string_cache_codegen", ] -[[package]] -name = "webpki-roots" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -2420,217 +1183,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "worker" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7267f3baa986254a8dace6f6a7c6ab88aef59f00c03aaad6749e048b5faaf6f6" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "futures-channel", - "futures-util", - "http", - "http-body", - "js-sys", - "matchit 0.7.3", - "pin-project", - "serde", - "serde-wasm-bindgen", - "serde_json", - "serde_urlencoded", - "tokio", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "worker-macros", - "worker-sys", -] - -[[package]] -name = "worker-macros" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7410081121531ec2fa111ab17b911efc601d7b6d590c0a92b847874ebeff0030" -dependencies = [ - "async-trait", - "proc-macro2", - "quote", - "syn 2.0.119", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-macro-support", - "worker-sys", -] - -[[package]] -name = "worker-sys" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4777582bf8a04174a034cb336f3702eb0e5cb444a67fdaa4fd44454ff7e2dd95" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "writeable" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" - -[[package]] -name = "yoke" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" - -[[package]] -name = "zerotrie" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47402523226a02bfe5230160dc3ccc089aa6f6f19e7fcbb4e6f824bbb1b4aa62" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - [[package]] name = "zmij" version = "1.0.23" diff --git a/Cargo.toml b/Cargo.toml index 7241acf..64f545f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,14 @@ [workspace] resolver = "2" -members = ["hemplate-runtime", "hemx", "hemx-core", "hemx-host", "hemx-derive", "hemx-js", "hemx-axum", "hemx-build", "hemx-test", "hemx-sync", "hemx-sync-macros", "hemx-wasm", "hemx-lsp", "hemx-xtask", "examples/v0", "examples/html_examples", "examples/kanban", "examples/client_local", "examples/techdemo", "examples/saas", "examples/workout", "examples/cloudflare_do"] +members = ["hemx", "hemx-core", "hemx-derive", "hemx-js", "hemx-axum", "hemx-build", "hemx-test", "tests/server-wasm"] [workspace.package] -version = "0.1.0" +version = "0.3.0" edition = "2021" +rust-version = "1.88" +license = "MIT" +repository = "https://github.com/tmk241/hemx" [profile.release] opt-level = "z" lto = true - -# Upstreams still request retired package identities. These tiny bridges re-export -# the maintained successors without introducing a second implementation. -[patch.crates-io] -paste = { path = "compat/paste" } -spin = { path = "compat/spin" } diff --git a/INTENT.tsv b/INTENT.tsv new file mode 100644 index 0000000..cee57c1 --- /dev/null +++ b/INTENT.tsv @@ -0,0 +1,7 @@ +ID PROBLEM FOR OUTCOME +server/001 Browser frameworks duplicate authoritative application state and policy Rust teams building ordinary server-owned web applications Keep state, authorization, validation, and recovery on the server +resource/001 Copied selectors and protocol identifiers drift away from rendered templates Template and handler authors Use generated typed resources and actions for every interaction boundary +protocol/001 Ad hoc browser commands create ambiguous ordering and compatibility Framework adapters and browser runtimes Apply one deterministic ordered effect protocol within an owned root +web/001 Framework abstractions often replace native web semantics unnecessarily People using Hemx applications Retain semantic HTML, accessibility, URLs, forms, and browser fallback +portable/001 Host-only parsing dependencies prevent portable server-side rendering Rust applications targeting Wasm and constrained servers Render through normal Hemx APIs without host parser dependencies +scope/001 Universal extension systems turn a small interaction layer into a client framework Maintainers and application authors Compose ordinary behavior from a small kernel, direct adapters, and explicit islands diff --git a/PLAN.md b/PLAN.md index e519eec..c591d02 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1,31 +1,53 @@ -# PLAN — Cloudflare Durable Objects proof +# Current plan -Parent outcome: prove that hemx keeps its semantic `.heml` authoring, generated typed resources, compile-time target checking, canonical `EffectBatch` wire format, and tiny runtime while a Cloudflare Durable Object owns one durable collaborative room and hibernating WebSocket fan-out. +## Slice HMX-001 — Closed typed effect path -Non-goals: a generic Cloudflare framework, Cloudflare-owned auth policy, RPC/alarm/queue abstractions, global object discovery, offline reconciliation, deployment automation, or treating stored HTML/effects as business truth. +Outcome: A handler can build the complete closed effect algebra with generated resource types, encode it canonically, and have one owned browser root apply it in order with defined failure behavior. +Delta: kernel/001–016, resource/001–004, resource/006, runtime/001, runtime/005, axum/001, axum/005. +Path: generated resource API -> typed effect batch -> canonical Axum response -> root-scoped browser decoder and executor -> DOM, focus, scroll, history, or dispatch result. +Build: Reconcile `hemx-core` effect/resource types and wire format, `hemx-build`/`hemx-derive` generated capabilities, `hemx-axum` response boundary, and `hemx-js` execution semantics as one compatibility break. +Risk: Partial migration can make server and browser disagree about opcodes, targets, ordering, or failure, causing wrong-root mutation or partial application. +Checks: Focused core round-trip/rejection tests; generated capability compile-pass/fail tests; Axum byte/status tests; browser scenarios for all eight effects, ordering, created-resource reuse, move identity, and stop-on-failure; `tests/redgate_test.sh`; `redgate check` for the slice IDs. +Non-goals: Request-policy attributes, optional transport adapters, islands, or public release publication. +Residual risk: Native interaction policy and adapter lifecycle remain in later slices. +State: Done +Blocked by: none -## Slice CF-1 — Canonical WebSocket push +## Slice HMX-002 — Native interaction and recovery -Outcome: a hemx root can receive binary `EffectBatch` updates over a same-origin WebSocket with the same ABI/fingerprint and root-scoped failure behavior as HTTP/SSE. -Delta: push/001, push/003, push/005, push/009; runtime/001; failure/001. -Path: `data-hemx-ws` on generated root -> runtime WebSocket -> binary frame -> existing `applyBatch` -> generated target or root error outlet. -Build: validate the root declaration in hemx-build; add runtime bind/cleanup/error behavior and focused consumer-boundary tests. -Risk: accepting text, cross-origin, malformed, or stale-build messages could bypass the canonical compatibility boundary or mutate the wrong root. -Proof: `cargo test -p hemx-build -p hemx-js` plus `cargo check --target wasm32-unknown-unknown -p hemx`. -Non-goals: client command protocol, reconnect/replay policy beyond the browser WebSocket primitive, multiplexing, or a general transport trait. -Residual risk: a real Cloudflare hibernation journey remains for CF-2. -State: Ready. -Blocked by: none. +Outcome: Generated semantic HTML submits forms and navigation through the closed effect path while preserving accessibility and ordinary browser recovery. +Delta: html/001–007, runtime/003–004, axum/003–004. +Path: generated marker and native anchor/form -> request policy and Axum boundary -> rendered validation or navigation response -> accessible browser result or native fallback. +Build: Align generated marker vocabulary, native-event defaults, bounded request policies, form encoding, validation markup, partial navigation metadata, and full-navigation recovery. +Risk: Enhancement can suppress native input, accessibility, or fallback behavior and leave users unable to submit, navigate, or recover. +Checks: Generated-markup assertions for every marker and policy value; browser scenarios with enhancement enabled and unavailable; form encoding and body-limit integration tests; validation accessibility assertions; partial/full navigation recovery scenarios; `redgate check` for the slice IDs. +Non-goals: SSE, WebSocket, timers, reveal behavior, or island-owned local state. +Residual risk: Optional adapter and island lifecycle remains open. +State: Ready +Blocked by: none -## Slice CF-2 — Durable room exemplar +## Slice HMX-003 — Direct adapters and explicit islands -Outcome: two browser clients in one named room see a counter mutation rendered from durable Rust state without reload, and reopening the room after object restart/eviction restores the persisted count. -Delta: push/001, push/002, push/003, push/009, push/010, push/011; canonical_authoring/001; state/001; abi/004. -Path: Worker room URL -> stable Durable Object name -> `.heml` page -> WebSocket upgrade -> typed increment command -> persisted counter -> generated counter partial -> canonical `EffectBatch` -> hibernating sockets -> both roots update. -Build: add one `examples/cloudflare_do` worker-rs exemplar with build-time hemx generation, one semantic template, one Durable Object class, Wrangler migration/binding, and focused pure tests for command/state/render output. -Risk: target-toolchain incompatibility, using an in-memory socket registry, persisting UI output instead of state, or emitting noncanonical WebSocket bytes would invalidate the proof. -Proof: native tests for command/render behavior; `cargo check --target wasm32-unknown-unknown -p hemx-cloudflare-do-example`; then `wrangler dev` browser smoke when Wrangler is available. -Non-goals: production auth/CSRF/tenancy, alarms, queues, RPC wrappers, multi-object transactions, deployment, billing, or a public `hemx-cloudflare` crate. -Residual risk: hosted Cloudflare deployment, jurisdiction policy, and production credentials remain external. -State: Ready for local build; hosted runtime proof is Blocked. -Blocked by: Wrangler runtime availability and Cloudflare account credentials for hosted verification. +Outcome: Optional transports and local islands compose with the generic runtime without adding effect schemas, a plugin registry, or mirrored client application state. +Delta: runtime/006–008, boundary/001–004, axum/002. +Path: root-owned adapter or explicit island marker -> direct bind/scan/cleanup lifecycle -> unchanged effect batch or island-owned subtree -> deterministic ownership result. +Build: Keep generic runtime behavior in `hemx-js`, framework transport in `hemx-axum`, direct adapter lifecycle beside each adapter, and explicit morph boundaries around islands. +Risk: Duplicate binding, leaked cleanup, or ambiguous ownership can apply effects twice, cross roots, or overwrite island state. +Checks: Browser lifecycle scenarios for bind-once, inserted fragments, removal cleanup, wrong-root rejection, and island preservation; static/public-API checks excluding plugin registries, extra core effects, and client stores; unchanged-byte transport tests; `redgate check` for the slice IDs. +Non-goals: New transports, a general extension API, or application-specific island frameworks. +Residual risk: Adapter-specific network behavior remains owned by each optional adapter. +State: Ready +Blocked by: none + +## Slice HMX-004 — Deterministic generation and portable server build + +Outcome: Template inspection and macros produce stable, actionable generated contracts, and normal server-side Hemx APIs compile for wasm32 without host parser dependencies. +Delta: resource/005, build/001–003, derive/001–004, wasm/001. +Path: Hemplate template input -> build inspection and macro expansion -> generated contract artifact -> unchanged rebuild or actionable compile failure -> portable server target. +Build: Tighten semantic fingerprinting and no-op writes, source-path diagnostics, macro preservation and compile failures, and the target dependency boundary. +Risk: Nondeterministic artifacts cause rebuild churn and ABI drift; leaked host parsers make the promised server target unusable. +Checks: Existing deterministic/no-op build and compile-fail tests; source I/O diagnostic test; wasm32 check plus normal dependency-tree exclusion; `tests/redgate_test.sh`; `redgate check` for the slice IDs. +Non-goals: Changing Hemplate syntax, parser internals, or package publication. +Residual risk: None after focused checks and the repository’s required workspace gates pass. +State: Ready +Blocked by: none diff --git a/README.md b/README.md index b30721d..cadd77b 100644 --- a/README.md +++ b/README.md @@ -1,210 +1,94 @@ -# hemx +# Hemx -hemx is checked hypermedia for Rust: write hemplate templates, write typed Rust -handlers, and return generated UI commands. The browser receives checked UI -commands; ordinary server-first apps do not need a frontend framework, -handwritten UI JavaScript, selector targeting, or raw runtime primitives. req: pitch/001 req: canonical_authoring/001 +Hemx is checked hypermedia for Rust. Applications render Hemplate views, handle +events in typed Rust functions, and return generated UI effects. The browser runs +a small effect interpreter instead of a virtual DOM, hydration framework, or +client-side expression language. The same core compiles for native servers and +server-side Wasm isolates; platform storage, sockets, and lifecycle remain +application concerns. -Status: the evidence-backed v1 behavior slices are implemented and browser-proven: -server-first/page-enhanced behavior, client-local WASM, durable offline/sync, the -multiplayer Kanban milestone, and the production reference. Local workspace, -browser, performance, documentation, and canonical-example gates pass. The -warning-denied vulnerability and source audits are clean; strict license closure -awaits a repository license allowlist. See `docs/v1-product-evidence.md` for the -product boundary, `REQUIREMENTS.md` for authority, `PLAN.md` for execution state, -and `docs/v1-readiness.md` for evidence. No publishing is implied. +## How it works -Template authoring: `.heml` is HTML plus a small hemplate overlay for escaped -text, trusted HTML, dynamic attributes, Rust-shaped control directives, generated -slots/forms/handles, and keyed partial targets. See `docs/hemplate-syntax.md`. -Editor setup for VS Code, Cursor, and Neovim lives in `docs/editor-support.md`; -VS Code/Cursor share the repo extension in `editors/vscode-hemx`, while all -editors keep normal HTML/tree-sitter highlighting and layer `hemx-build` -diagnostics on top. +1. `.heml` templates declare page roots, slots, forms, handles, and keyed targets. +2. `hemx-build` generates typed Rust helpers from that surface. +3. `#[hemx::handler]` functions accept ordinary Rust inputs and return typed effects. +4. `hemx-axum` serves pages, assets, handler routes, and effect responses. +5. The browser runtime validates the build fingerprint and applies effects within the current root. -Local checkout note: until the hemplate crates are published, this repository -expects `hemplate` checked out next to `hemx` as `../hemplate/hemplate`. The app -scaffolder fails with that exact path if the prerequisite is missing, instead of -creating an app that fails later with a vague Cargo path-dependency error. - -## The normal path - -For beginner and production-shaped app code, stay on this path. req: public_api/001 req: public_api/005 - -1. **Templates declare the surface.** `.heml` files declare roots, slots, - forms, handles, keys, page targets, optional pending states, and explicit - leaf islands with `data-hemx-*` attributes. The stable syntax surface lives in - `docs/hemplate-syntax.md`. -2. **Build generates typed helpers.** `hemx_build::app().run()` consumes the - hemplate Surface and emits generated Rust helpers for slots, forms, handles, - page targets, classes, and events. req: ceremony/003 req: build/001 -3. **Handlers are plain Rust.** App code uses `#[hemx::handler]` functions with - ordinary domain types, framework extractors, generated `Form` inputs, - explicit `data-*` params, and `impl IntoEffect` or fallible returns. req: derive_handler/001 req: derive_handler/002 req: derive_handler/003 req: derive_handler/004 req: derive_handler/005 -4. **Handlers return generated commands.** Common handlers return helpers such - as `todos.append(todo)`, `todo_row.replace(row)`, `new_todo.error("title", - "Required")`, `new_todo.clear()`, `page.replace(view)`, or tuples of those - commands. req: dx/006 req: dx/007 -5. **The runtime only applies effects.** The JavaScript runtime is a small, - root-scoped effect interpreter: no VDOM, no hydration framework, no client - expression engine, no selector retargeting, and no app state store. req: runtime/003 req: invariant/002 - -## Mental model: render → slot/key → effect → runtime - -- **Render:** hemplate renders Rust view structs into checked HTML. App code - normally reaches rendering through generated `ui::page(...)` helpers at a - server page boundary, with explicit `SafeHtml` only for already-rendered - fragments, not raw HTML construction. req: html_safety/002 req: html_safety/004 req: view/001 -- **Slot/key:** a generated slot names the target, and a generated keyed slot - also carries the stable row key. A list target inside `h-for` must have a - stable `h-key`, so row updates are addressable without CSS selectors. req: list/001 -- **Effect:** handlers return typed commands that become a checked effect - response. Tuple composition is the normal fixed batch syntax; arrays and - `Vec` cover fixed or dynamic repeated partial updates. -- **Reuse:** the hemx answer to framework components is reusable hemplate - partials plus generated helpers, app-owned state, `IntoEffect` composition, - and explicit leaf islands when browser-owned behavior is necessary. See - `docs/recipes/reusable-partials.md`. -- **Runtime:** the browser checks the build fingerprint, resolves targets within - the current `data-hemx-root`, and applies compatible batches. Mismatched - server/runtime builds fail closed instead of silently mutating the wrong DOM. - req: abi/002 req: check/004 req: failure/005 - -## Forms and errors - -Forms remain HTML forms. hemx checks the generated form contract against a -user-authored Rust form type, so domain newtypes such as `Email`, `TodoId`, and -`Title` parse through ordinary Rust traits rather than generated DTOs. req: form/001 - -Use validation effects for expected user mistakes, and `Result` for fallible domain, database, or infrastructure work. Integration crates map -`E` to generated UI effects, redirects, events, or HTTP responses; the canonical -app code still uses the same handler shape for plain and fallible handlers. See -`docs/diagnostics.md` for common compile/build/runtime mistakes and fixes. -req: failure/004 req: derive_handler/004 - -## Pages, push, CSS, and islands - -- Page navigation is a specialized generated page/slot effect around real - anchors and ordinary HTTP routes. hemx does not own routing. req: modes/002 req: axum_integration/002 -- Server push streams send checked effect responses over framework-managed - transports such as SSE; auth and connection policy stay in the server - integration. req: wire/004 req: push/002 -- Appearance is plain CSS. Generated class tokens can make dynamic classes - checked, but hemx does not introduce a styling runtime. req: style/001 req: style/002 req: style/003 req: style/004 req: style/005 req: style/006 -- Custom JavaScript belongs at explicit opaque leaf boundaries: charts, maps, - editors, Web Components, or similar widgets. Islands communicate through - generated handles/events and do not create a second UI model. req: canonical_authoring/007 req: canonical_authoring/017 req: interop/003 - -## Production boundary - -hemx is not a SaaS platform. Production concerns stay in normal Rust/web crates -and integrate at explicit boundaries. req: laws/002 req: auth/001 - -- **Persistence:** use SQLx or another storage adapter in your application - state/handlers. hemx should see ordinary domain values and generated UI - commands, not own the database layer. See `docs/recipes/sqlx-persistence.md`. -- **Auth/session:** use Axum/Tower extractors and middleware. Handlers may accept - typed auth/session context and return ordinary HTTP failures or generated UI - failures. See `docs/recipes/auth-session-csrf.md`. req: auth/002 -- **CSRF:** keep CSRF policy in middleware/extractors with hidden form fields, - cookies, and normal SameSite/browser semantics. hemx preserves submitted form - fields and credentials semantics. See `docs/recipes/auth-session-csrf.md`. req: auth/004 req: auth/005 -- **Observability, feature flags, killswitches, deploy:** use explicit platform - integrations around handlers, routes, runtime assets, and mobile shells. Core - hemx must not vendor providers or add framework-specific magic. See - `docs/recipes/observability-flags.md`, `docs/recipes/deploy-versioning.md`, - and `docs/recipes/mobile-release.md`. req: examples/011 -- **Mobile starter:** create the phone-first path with `cargo run -p - hemx-xtask -- app new --mobile PATH`. The starter carries a real app flow, - typed host capabilities, command/event/projection recovery truth, and - inspectable mobile release-kit commands without adding a native UI framework. - Use it for Rust-owned hypermedia apps; use explicit native shells/islands for - heavy native UI, games, camera-heavy flows, deep OS integration, or complex - offline sync. req: ceremony/006 req: host/002 -- **PWA/offline/sync:** optional adapters may reuse generated targets/effects, - but core hemx must not gain a mandatory client state graph or local app - runtime. Local truth is commands/events/projections, not stored DOM patches or - stored `EffectBatch` payloads. See `docs/recipes/pwa-offline.md` and - `docs/recipes/local-command-log.md`. req: canonical_authoring/008 req: canonical_authoring/018 req: canonical_authoring/019 req: local/001 req: local/002 -- **Host capabilities:** browser, PWA, WebView, and native-shell capabilities use - `hemx-host` manifests/calls/events. Adapters return host facts to app code; - UI still changes through normal hemx effects. See - `docs/recipes/host-capabilities.md`. req: host/001 req: host/002 req: host/005 - -## Escape hatches - -Advanced APIs are named and isolated. Raw effects, low-level ids, manual -registries, raw HTML/render/target construction, runtime hooks, SSE internals, -and island internals are for integration crates, tests, migrations, or explicit -leaf boundaries. They should not appear in beginner examples or ordinary handler -docs. req: public_api/002 req: public_api/005 - -## Versioning and deploy compatibility - -The generated API, symbols, effect wire schema, and JavaScript runtime carry -schema/ABI versions. Deploy a matching server, generated output, and runtime -asset together. Build fingerprints are derived from the generated surface and ABI -parts; the runtime refuses incompatible effect responses and integrations should -fall back to a full page reload when possible. See `docs/recipes/deploy-versioning.md`. req: abi/001 req: abi/002 req: failure/005 - -Before a v1 release, the semver policy and upgrade notes should explicitly state -which surfaces are stable: beginner generated helpers and handler shapes; the -wire/runtime ABI; and advanced escape hatches that may remain integration-level. -See `docs/versioning.md`. - -## Examples - -- `examples/v0`: canonical beginner path covering counter, typed todo CRUD, - form wizard, auth action, page swaps, SSE notifications, and keyed list - updates. Create the generic starter with `cargo run -p hemx-xtask -- app new - PATH`; it includes a page, form, keyed row partial, notice slot, handlers, - tests, and generated append/replace/remove/dynamic-batch updates. Start here. - req: ceremony/005 -- `examples/html_examples`: copy-paste HTML pattern gallery for htmx-style - CRUD/form/search/load UX patterns. It proves the hemx idiom for click-to-edit, - edit row, delete row, inline validation, click-to-load, and active search with - `.heml`, generated resources, server-owned Rust state, and tiny runtime - behavior. req: htmx_equivalents/001 req: htmx_equivalents/005 req: examples/001 -- `examples/saas`: compile-tested v1 tutorial app covering auth/session, - CSRF-safe mutation, local persistence, generated swaps, page/push shape, plain - CSS, and one explicit island without provider-heavy platform scope. Read the - walkthrough in `docs/tutorial-saas.md`; the SQLx persistence recipe in - `docs/recipes/sqlx-persistence.md` shows the provider boundary without moving - SQL into core. -- `examples/workout`: phone-first local-first product exemplar. Create a starter - with `cargo run -p hemx-xtask -- workout new PATH`; run the exemplar with - `cargo run -p hemx-xtask -- workout dev` and open `http://127.0.0.1:3028`. - It keeps workout truth as commands/events/projections and routes export - through the host capability boundary; `examples/workout/README.md` documents - the canonical dev, test, production build, mobile release, verification, and - failure-mode paths. req: examples/001 req: examples/006 req: local/001 req: host/005 -- `examples/kanban`: advanced / north-star milestone boundary sketch. It may - expose manual registry or render escape hatches while exploring product limits. -- `examples/techdemo`: advanced integration demo with a leaf island and broader - product interactions. - -## Local checks - -```sh -# Fast compile/regression pass for the crate you touched. -cargo test -p - -# Focused real-browser smoke for the HTML pattern gallery. -cargo run -p hemx-xtask -- html-examples-smoke - -# Full local authority check; keep this green before shipping broad slices. -cargo run -p hemx-xtask -- test - -cargo check --workspace -redgate health --strict +```rust,ignore +#[hemx::handler] +async fn add_todo(form: NewTodo) -> impl IntoEffect { + ui::todos().append(TodoRow::from(form)) +} ``` -Use `cargo run -p hemx-xtask -- test` for the full local verification path so -jobs stay capped for local CPU and memory. The focused browser tier is -`cargo run -p hemx-xtask -- html-examples-smoke`; it owns dynamic html_examples -browser behavior and should complete in about 30 seconds locally. The full tier -should complete within a 10 minute local timeout; if it grows beyond that, split -it into deterministic repo-owned shards that together cover the same behavior, -with `cargo run -p hemx-xtask -- test` remaining the full authority wrapper. -req: test/004 req: test/006 req: test/015 req: test/016 +```html +
+ + +
+
    +``` + +## Design boundary + +Hemx owns checked UI effects and their browser runtime. It does not own routing, +databases, authentication, CSS, or application state. Those remain ordinary +Rust and web concerns. Browser-specific behavior belongs in explicit leaf islands +rather than a second application model. + +The normal application path is: + +- `hemx` for handler and effect APIs; +- `hemx-build` for generated resources; +- `hemx-axum` for Axum integration; +- `hemx-js` for the browser effect runtime. + +Server-side Wasm uses the same core crates and canonical effect batches; it does +not require a separate Hemx Wasm runtime package. + +## Workspace + +| Package | Purpose | +| --- | --- | +| `hemx` | Application-facing facade and handler macro export | +| `hemx-core` | Effect types, protocol values, validation, and runtime primitives | +| `hemx-derive` | Procedural macros | +| `hemx-build` | Build-time template analysis and generated resources | +| `hemx-axum` | Axum routes, responses, assets, and server push | +| `hemx-js` | Browser runtime source | +| `hemx-test` | Test support for applications | + +## Agent skill + +The optional [`idiomatic-hemx`](https://github.com/tmk241/hemx-skills) skill +helps coding agents apply Hemx's generated-resource and server-owned effect +model: + +```console +npx skills@latest add tmk241/hemx-skills --skill idiomatic-hemx +``` + +## Development + +```console +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test --workspace --all-targets --all-features +cargo deny check licenses sources +``` + +## Related projects and acknowledgements + +[htmx](https://htmx.org/) helped popularize the HTML-over-the-wire, +hypermedia-driven approach that inspired Hemx. Hemx is an independent +implementation and does not bundle htmx. + +Hemx builds on [Hemplate](https://github.com/tmk241/hemplate), +[Tokio](https://github.com/tokio-rs/tokio), +[Axum](https://github.com/tokio-rs/axum), and the Rust procedural-macro +ecosystem. Thank you to their maintainers and contributors. + +## License + +MIT diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md deleted file mode 100644 index bc4cd93..0000000 --- a/REQUIREMENTS.md +++ /dev/null @@ -1,1146 +0,0 @@ -# hemx — Semantic, Laterally HX - -hemx makes server-rendered HTML feel like it grew just enough interactivity. -App authors change state in Rust, render hemplate partials, and return generated -UI intent; the runtime swaps generated slots without selectors, a VDOM, or a -client app state framework. - -> **hemplate owns syntax. hemplate emits surface. hemx consumes surface. hemx owns semantics. JS applies effects.** - ---- - -## law - -001 A feature belongs in core only if it can be expressed as typed resources plus EffectBatch ops. [north_star] - -002 A feature belongs in an integration crate if it depends on transport, framework, auth, storage, browser capability, or deployment policy. [north_star] - -003 A feature belongs in generated API if it improves author ergonomics without adding runtime semantics. [north_star] - -004 A feature belongs in user code if it is business logic, domain validation, routing policy, authorization policy, persistence, or layout choice. [north_star] - -005 Add one primitive only if it removes at least five special cases. [north_star] - ---- - -## pitch - -001 hemx is checked hypermedia for Rust: authors write `.heml`, write Rust handlers, and return generated UI commands while the compiler checks every cross-file reference. [north_star] - -005 For ordinary server-first apps, no app-owned JavaScript is required: the browser runtime only sees lowered ids and effect bytes. [north_star] - -002 No CSS selectors. No hx-* strings. No virtual DOM. No client framework. No hidden global proxy magic. No component hydration. SSR state bootstrap via `data-hemx-st` is allowed, but the browser never reconstructs a component tree. [north_star] - -003 hemx replaces React/Vue not with a UI framework, but with a compiler contract: hemplate knows the surface, Rust knows the types, hemx knows the effects, the browser only executes commands. [north_star] - -004 The north-star feel: **boring server-rendered HTML with typed, selectorless partial swaps.** Short handler bodies, compile-checked HTML contracts, plain Rust state changes, hemplate-rendered partials, and a tiny runtime that applies effects. [north_star] - ---- - -## canonical - -001 The canonical app shape is templates plus Rust, not a frontend folder: `.heml` files declare roots, slots, handles, forms, keys, and optional pending/page/island facts; handlers return generated UI commands. [north_star] - -010 Ordinary app code avoids selectors, numeric ids, raw effects, wire formats, manual registries/form parsing, raw `SafeHtml`, and raw render calls. [north_star] - -011 Plain CSS owns appearance. [north_star] - -002 Typed partial swaps are the primary UX, not an advanced feature: handlers change domain state in Rust, convert domain values into view values, render hemplate partials, and place them into generated targets. [north_star] - -014 The partial-swap primitive is generated target plus rendered partial plus swap kind. [north_star] - -003 Canonical keyed-row CRUD reads like ordinary Rust intent: create appends a rendered row partial, update/toggle replaces a keyed row partial, and delete removes a keyed row. [north_star] - -015 Summary, text, and form effects compose in tuples, arrays, or `Vec` for dynamic batches, and no handler chooses a target with a CSS selector. [north_star] - -004 Generated helpers may compose only facts uniquely known from templates and checked Rust types: template, slot, optional key, form/control, class token, explicit island/event marker, and effect kind. [north_star] - -016 If a handler parameter, key, form, target, raw route, or legacy target would require guessing, the user must say it explicitly and diagnostics must point to the Rust and hemplate spans. [north_star] - -005 Generated helpers name UI intent without mixing domain work: helpers read as UI effects such as `replace`, `append`, `remove`, `set`, `clear`, `focus`, `set_attr`, or `emit` on generated page, slot, form, class, attribute, or island handles. [north_star] - -009 Generated helpers must not combine persistence, routing, rendering, target selection, or domain policy into generic commands such as `refresh`, `save_and_update`, `sync_component`, or `rerender`. [north_star] - -006 There is no separate beginner API and expert API; the simple generated shape is canonical. [north_star] - -012 Generated slots, partials, forms, class constants, islands/events, and page helpers are normal authoring surfaces. [north_star] - -013 Explicit primitives, raw targets, raw HTML, raw effects, manual registries/form parsing, low-level ids/opcodes, wire formats, and raw routes remain named escape hatches or internals around the same render/target/effect/transport model. [north_star] - -007 Opaque islands are explicit leaf adapters: templates declare `data-hemx-island` and optional generated handles/events; server code may emit snapshots/events such as `ui::game.emit(event)`. [north_star] - -017 Island JavaScript owns only high-frequency local behavior and must not introduce a component runtime, client state graph, VDOM, or second UI model. [north_star] - -008 Offline/PWA support is opt-in adapter territory; server-first hemx may fail interactions while offline. [north_star] - -018 Cached shells and local-sync queues live in crates such as `hemx-pwa` or `hemx-sync`; they reuse generated slots/effects, queue explicit patches, and reconcile with server-canonical effects. [north_star] - -019 Core hemx must not gain a mandatory client state graph, scheduler, CRDT, or local app runtime. [north_star] - ---- - -## mode - -001 hemx has one core authoring loop: render a partial and place it into a generated target with a swap kind. HTTP handlers, page navigation, push streams, and island events are transport/adapters around that loop. [north_star] - -002 Page Enhancer is navigation as partial swap: it updates generated page/content/title/nav targets, history, scroll, shell, and fallback behavior. Authors use `data-hemx-nav`/`data-hemx-boost` anchors; ordinary navigation needs no handler. [north_star] - -003 Interaction Handler mode handles forms, buttons, typed params, and generated partial/text/form/island effects through Rust handlers. [north_star] - -004 Beginner docs teach server-first typed partial swaps first, Page Enhancer around the same slot/effect model, explicit leaf-widget islands, client-local/WASM only for high-frequency local behavior, and sync/offline last as opt-in adapters. [north_star] - ---- - -## dx - -001 Common apps feel like HTML plus tiny Rust handlers: templates, state, hemplate partials, and generated UI swaps. Basic apps hide Surface IR, ResourceId, EffectWriter, postcard, runtime opcodes, selectors, and registries. [north_star] - -002 Happy path: write `.heml`, write a Rust handler, return generated partial/text/form/page/island commands. Ordinary app UI uses no manual ids, registry, serialization, selector targets, raw render calls, or JavaScript. [north_star] - -003 Public APIs are generated around the user's names. If the template declares `data-hemx-slot="todo_list"`, the user gets `slots::todo_list`, not `SlotId(12)`. - -004 Common handlers fit in a small function. Advanced contexts (`EffectWriter`, raw ops, custom encoders) exist but are not part of the beginner path. - -005 Error messages explain fixes in author language, not internal language. Say “add `h-key="todo.id"` to this `h-for`”, not “missing ScopeKey for ResourceRef”. - -006 Generated object-like helpers are the preferred authoring API and are re-exported at the component root, including `todos.append(todo)`, `todo_row.replace(todo)`, `summary.set(text)`, `new_todo.clear()`, and `page.replace(view)`. [north_star] - -009 Generated object-like helpers hide hemplate rendering and resource lowering in the common path. [north_star] - -010 Namespaced `targets`/`handles`/`forms`, raw `advanced::slots`, explicit render/target/html/lower helpers, and raw effect constructors are compatibility surfaces, not beginner-prelude exports, canonical examples, or ordinary docs. [north_star] - -007 Tuple composition of `IntoEffect` is the canonical batch syntax: `(a, b, c)` implements `IntoEffect` up to arity 12. `Effect::batch((...))` is available but not required for the happy path. - -008 User-authored JavaScript is never required for standard forms, lists, navigation, optimistic actions, or server push. Custom JS is only needed at opaque leaf boundaries such as charts, maps, editors, and Web Components. - ---- - -## ceremony - -001 A minimal counter app requires one `.heml` file, one Rust state struct, and one handler function. No manual registry, route table, or JS; under 50 lines of Rust plus one template. - -002 Generated modules are imported through a prelude or component namespace. Normal apps do not manually include `$OUT_DIR` files. - -003 `build.rs` must be a one-liner for the common case: `fn main() { hemx_build::app().run().unwrap(); }` - -004 No API may require users to write numeric ids, raw ResourceIds, raw opcodes, or serialized payloads in normal code. - -005 `cargo run -p hemx-xtask -- app new PATH` creates a generic scaffold with page, form, keyed row partial, notice slot, handlers, and tests using generated helpers instead of raw ids, opcodes, selector UI JavaScript, or manual registries. [north_star] - -006 `cargo run -p hemx-xtask -- app new --mobile PATH` creates a phone-first starter with page/form/keyed partial/notice flow, typed host capability round trip, app-owned recovery truth, and inspectable mobile release/verify metadata. [north_star] - -007 The phone-first starter adds no hemx mobile framework, client store, signing-secret owner, or store-submission bot. [north_star] - ---- - -## pd - -001 A beginner can build CRUD with only: `.heml`, Rust handlers, `Form` or typed params, generated object-like UI helpers, and `impl IntoEffect`. - -002 Atoms are not required for basic server-first apps. They appear only when client-local state, SSR bootstrapped state, or WASM handlers are used. - -003 Sync, transitions, resources/queries, islands, capabilities, and raw EffectWriter are advanced layers. They must not appear in starter examples. - -004 Docs present levels as adapters around the same core: server-first partial swaps; cached Page/PWA shell; leaf islands or client-local handlers for high-frequency behavior; hybrid sync/offline queues last. Each level introduces only its new primitive. - ---- - -## page_swap - -001 Page swapping specializes partial swapping: render page partials into generated targets, then apply history/title/scroll/shell behavior. `data-hemx-nav` anchors keep valid `href` and work without JS; missing/empty static `href` fails build. [north_star] - -002 A `data-hemx-nav` click fetches the target URL as a hemx partial request. The response is `ui::content.replace(page)` plus optional generated nav/title targets and `Navigate`; it must not add selector targeting or a second page UI model. [north_star] - -003 Page swapping uses generated targets, not CSS selectors. Default content target is generated slot `content`, not `#content`; page helpers like `ui::content.page(...)` or `request.page_html(...)` adapt the same partial-swap primitive. [north_star] - -004 Ordinary page navigation must not require user-authored handlers. Explicit navigation handlers are available only when custom application logic is needed, and they still return generated target/page commands. [north_star] - -005 Browser back/forward restores a saved generated page snapshot and scroll position when available, otherwise fetches the URL as a partial request without pushing a new entry. [north_star] - -006 If a page lacks the expected `content` slot, hemx-axum falls back to normal browser navigation in production and emits a diagnostic in development. [north_star] - -007 `data-hemx-boost` progressively enhances descendant same-origin anchors and forms as a container convention, not a replacement for anchor `data-hemx-nav` or form `data-hemx-handle`; direct static-anchor/form use is a build error. [north_star] - -008 Boosted links behave like `data-hemx-nav`; boosted forms behave like hemx form submissions. External links, downloads, new-tab links, and modified-clicks preserve native browser behavior. [north_star] - -009 Enhanced GET navigation treats the URL as shareable page state: native successful GET controls serialize into the request URL, history updates by intent, and reload/bookmark/back/forward reconstruct the same view. [north_star] - -010 URL-as-state support remains a page/navigation convention, not a router, omnisearch framework, selector include system, or client state graph. [north_star] - ---- - -## htmx - -001 hemx replaces common HTMX use-cases through typed equivalents, not HTMX syntax. [north_star] - -002 Easy equivalents must exist for generated target replacement, append/prepend/remove, form submit, loading indicators, confirmation, debounce/throttle, drag/drop payloads, validation errors, and form error regions. [north_star] - -006 Easy component-shape equivalents must exist for modals, toasts, table rows, and SVG fragments. [north_star] - -004 Navigation and live-update equivalents must exist for boosted links/forms, page swap, polling, history navigation, multi-target updates, response events, and SSE/push. [north_star] - -005 The copy-paste HTML pattern gallery must cover core CRUD/form/search/load patterns through boring `.heml`, generated targets/forms/handles, and server-owned Rust state before adding plugin-shaped or browser-policy-heavy patterns. [north_star] - -003 hemx core does not clone HTMX selectors (`hx-target`, `hx-select`, `hx-include`, `closest/find/this`) or trigger mini-languages. Equivalents use generated targets, typed params, forms, explicit handlers, and page/push adapters. [north_star] - ---- - -## component - -001 The primary authoring unit is a hemplate component plus adjacent Rust handlers. A component owns a template root, generated slots, generated handles, generated form checks, and source spans. [north_star] - -002 hemx supports colocated layout: `todo_list.heml` beside `todo_list.rs`, with generated APIs namespaced by component to avoid global symbol soup. [north_star] - -003 Generated APIs are component-namespaced by default. [north_star] -`ui::todo_list::todo_row`, `ui::todo_list::create`, `ui::todo_list::new_todo`, and `ui::todo_list::COMPONENT` as a checked `ComponentRef`. -Category modules such as `targets`, `handles`, and `forms` remain available for organization/compatibility, while raw slot constants live under `advanced::slots`; global exports (`ui::slots::*`, `ui::handles::*`, `ui::components::*`) are opt-in only. - -004 `#[hemx::surface]` bridges generated code into a user module. Users write `#[hemx::surface] mod ui {}` instead of direct `$OUT_DIR` includes; hemx-build emits `hemx.generated.rs` for the macro to expand in place. [north_star] - -005 Optional `#[hemx::component]` validates that each template Surface handle has a corresponding `#[hemx::handler]` within the annotated module. It is strictly module-local, with cross-handler visibility only inside that module; unknown scopes report the available generated component names. [north_star] - -007 Missing handlers without `#[hemx::component]` are caught at app mount or test time, not `cargo check`. [north_star] - -006 `#[derive(Hemplate)]` structs are natural component boundaries. hemx_build discovers them automatically; no additional configuration is required for most apps. [north_star] - ---- - -## surface - -001 `hemplate_build` scans `.heml` and emits versioned postcard Surface facts at `$OUT_DIR/hemplate.surface.postcard`. `hemx_build` may take precomputed facts or ask hemplate to extract them, but hemx owns no independent `.heml` parser. [north_star] - -002 The Surface contains: nodes (NodeId, parent, scope, element, attrs, source span), scopes (ScopeKind: Root | If | Match | Case | For { binding, key_expr }), forms (controls with raw HTML types), and component uses. [north_star] - -003 Node identity is `NodeId` in a parent/scope graph. No `css_path` is used as a primary identifier. An optional `debug_path` string may exist for diagnostics only. [north_star] - -004 Form controls in the Surface carry raw HTML facts: `ControlKind::Text`, `ControlKind::Number { min, max, step }`, `ControlKind::Checkbox`, `ControlKind::Select { multiple, options }`, etc. No Rust type mapping lives in hemplate. [north_star] - -005 Loop scopes expose the binding name and optional `key_expr` such as `todo.id`. hemplate only records key usage; hemx_build enforces key presence when a hemx-addressable node appears inside the loop. [north_star] - -006 Surface schema is versioned (`schema_version: u32`). Postcard encoding, no JSON. `no_std`-compatible schema definition so any tool can read it without heavy dependencies. [north_star] - -007 `hemplate-derive` does not write Surface files. Surface generation is a `build.rs` / `hemplate_build` concern, proc-macro side-effect free. [north_star] - -008 The Surface records hemplate structural directives as first-class facts: [north_star] -`h-for`, `h-key`, `h-if`, `h-else-if`, `h-else`, `h-match`, `h-case`, -dynamic `+attr` bindings, and interpolated attr/text expressions. hemx consumes -these facts; if a build script points hemx_build at `.heml` files, hemplate still performs parsing and Surface extraction. - -009 Raw/pre-rendered HTML insertions are opaque Surface holes. The parent -element is present; hemx_build emits the appropriate rendering call. [north_star] - -010 Attribute values preserve their origin: static literal, dynamic `+attr` -binding, or interpolated expression. hemx-build uses this to determine whether -a `data-*` handle param is statically known or runtime-extracted. [north_star] - ---- - -## codegen - -001 `hemx_build` generates `hemx.generated.rs` resource modules, `hemx.syms` proc-macro facts, and runtime id-lowering tables from Surface IR. It interprets `data-hemx-*`, `h-for`, `h-key`, and form-control conventions from Surface. [north_star] - -002 Generated view modules expose ergonomic root-level target objects and commands that hide render/lower details for text, partial, and keyed collection slots. [north_star] - -009 Generated form targets provide `clear()`, `clear(field)`, and `focus(field)` commands. [north_star] - -007 String-keyed generated target objects accept displayable domain ids without caller-side `.to_string()` noise. [north_star] - -008 Generated commands return `impl IntoEffect`, compose in plain Rust, preserve generated lowering, and fail to generate when the template lacks facts needed to infer the slot, key, form, or renderable view type. [north_star] - -003 Generated module `handles` exports typed constants: `Handle` where `I` is `Form`, a param type, or `()`. Users rarely reference handles directly; they are consumed by `#[hemx::handler]` for validation. [north_star] - -004 Generated module `forms` exports `FormContract` metadata (field names, HTML control kinds, required). `#[hemx::handler]` compares `Form` against the contract. Domain types remain user-authored; no auto-generated structs. [north_star] - -005 Generated module `atoms` exports `Atom` for values that must be addressable, bootstrapped, or synced. Ordinary Rust fields on app/components are not automatically atoms. [north_star] - -006 `hemx-build` discovers `data-hemx-on` event names from Surface inputs and emits `hemx::EventName` constants for checked Rust authoring and diagnostics. Constants do not create a trigger mini-language or new browser semantics. [north_star] - ---- - -## public_api - -001 The generated API is the primary public authoring API. User code returns generated partial, text, keyed-row, form, page, nav, or island/event commands, not raw `Effect` constructors or raw render/lower calls. [north_star] - -002 `Effect`, `EffectWriter`, `ResourceId`, `ResourceRef`, and raw opcodes are advanced APIs. They must not appear in beginner docs, generated examples, or common diagnostics. [north_star] - -003 Every generated command returns `impl IntoEffect` and composes through tuple composition. [north_star] - -004 If a common UI operation requires raw `EffectWriter`, the public API is incomplete. [north_star] - -005 Beginner-facing page/template composition uses generated render or page helpers. Direct `SafeHtml`, raw `html(...)`, `target(...)`, route fragments, `hemx::advanced::render(...)`, and explicit `ui::render(...)` are advanced escape hatches. [north_star] - -006 Server-rendered page boundaries may use `hemx::page(...)`; handlers and ordinary partial updates must use generated target/form/page commands. [north_star] - ---- - -## effect_algebra - -001 The canonical op set is minimal and closed: `Put`, `Insert`, `Remove`, `Move`, `Focus`, `Navigate`, `Emit`. [north_star] - -002 `Put` replaces the payload of a resource. For a Slot, this means replacing its rendered contents. For an Atom, this means replacing its stored value. [north_star] - -003 `Insert`, `Remove`, and `Move` operate on keyed collection resources. They require a key type checked by generated `KeyedSlot` wrappers. [north_star] - -004 `Navigate` changes browser history or represents a server redirect. Route matching remains outside hemx core. [north_star] - -005 `Emit` dispatches a native `CustomEvent` and is the only raw JS interop primitive in core. [north_star] - -006 DOM-specific operations such as `innerHTML`, `textContent`, class toggles, or keyed node lookup are runtime lowering details, not separate author-facing concepts. [north_star] - ---- - -## typed_id - -001 Public cross-page identifiers (`Slot`, `Atom`, `Handle`, `Form`) share one internal primitive: `ResourceId { kind: ResourceKind, id: u32 }`. Typed wrappers enforce kind safety at compile time. [north_star] - -002 `ResourceKind` is an internal closed enum (Slot, Atom, Handle, Form). [north_star] -Navigation is represented by `Navigate` effects, not by route resources. -External crates may not add variants. Extensibility comes via `Effect::event` -or custom `IntoEffect` implementations, never via new `ResourceKind` variants -in core. `Effect::event` lowers to the canonical `Emit` opcode. - -003 A concrete runtime target is a `ResourceRef { resource: ResourceId, scope: Option }`. Effects address resources uniformly, with no special-case opcodes per resource kind. [north_star] - ---- - -## scope - -001 `Scope` is a first-class primitive. Keyed loops (`h-for`) create keyed -dynamic scopes and require `h-key` for hemx-addressable nodes. Conditional -branches (`h-if`, `h-else-if`, `h-else`, `h-match`, `h-case`) create optional -presence scopes. Component instances, modals, tabs, and nested forms are scoped -resources. Concrete runtime targets are addressed through `ResourceRef` -`{ resource: ResourceId, scope: Option }`. [north_star] - ---- - -## list - -001 Any `data-hemx-slot` or `data-hemx-handle` inside a hemplate `h-for` scope requires a stable key. Use syntax such as ``. [north_star] - -004 Without a key, hemx-addressable nodes inside a loop are rejected at build time. Keyed identity is `ResourceRef { resource: ResourceId, scope: Some(ScopeKey::KeyValue(...)) }`. [north_star] - -002 Slots inside a keyed loop receive a composite identity. hemplate records `key_expr` in the Surface; hemx implements keyed slot lookups and lowers rendered `h-key` identity to its private `data-key` runtime marker. [north_star] - -003 Generated helpers for keyed slots are `append(view)`, `prepend(view)`, `replace(view)`, and `remove(key_or_view)` when the template and view type provide an unambiguous `h-key`. [north_star] - -005 Compatibility functions such as `append(keyed_slot, key, view)` may exist as explicit low-level forms. Key type mismatches are compile-time errors; missing/ambiguous keys are build errors with template spans. [north_star] - -006 Filtered keyed collections reconcile by removing filtered-out keys, replacing retained keys, and appending newly visible keys rather than clearing and re-adding every row. [north_star] - ---- - -## form - -001 Forms are source of truth in HTML. hemplate Surface exports form shape (controls, names, required, types). hemx checks Rust `Form` compatibility through user-authored `#[hemx::form("...")]` domain structs and generated form metadata. [north_star] - -007 Form support generates no domain structs. Domain types such as `Email` are user-authored and first-class; the Surface describes, Rust owns, and hemx checks. [north_star] - -002 The handle id is carried as `__h` in POST `application/x-www-form-urlencoded`. A JSON body is allowed at the integration boundary (`application/json`) only if the handler accepts it; core uses form encoding. [north_star] - -003 Handler receives `form: Form`. Validation errors target `(FormId, field_name)` or generated control ids. The runtime maps them to originating form controls via control ids derived from Surface `NodeId`, not via slot ids. [north_star] - -004 Form compatibility checks validate field presence, optionality, multiplicity, and parser availability, including raw Rust identifiers for reserved HTML control names. [north_star] - -008 Parser availability means the submitted value type implements `hemx::FormValue`, via `FromStr` blanket support or explicit custom parsers. Domain validation remains Rust logic (`TryFrom`, custom validators, or handler code). [north_star] - -005 HTML control facts are lower bounds, not complete domain semantics. -`type="email"` may require a Rust `Email` parser, but hemplate never defines -what a valid business email is. [north_star] - -006 Generated diagnostics distinguish structure errors from validation errors: missing field / wrong optionality are compile-time issues; invalid submitted values are runtime form errors. [north_star] - ---- - -## form_effects - -001 Generated form APIs provide common commands: `clear()`, `clear(field)`, `reset()`, `error(field, message)`, `focus(field)`, and `disable_while_pending()`. `form.clear()` clears the generated form without raw control ids. [north_star] - -002 Form effects target generated form/control ids, not CSS selectors. [north_star] - -003 Templates may declare error display targets with `data-hemx-error-for="field"`. Generated form error effects render into those targets when present and fall back to control validity APIs otherwise. [north_star] - ---- - -## wire - -001 Authoring HTML uses symbolic `data-hemx-*` attributes. Runtime HTML lowers them to compact metadata: `data-hid`, `data-sid`, optional `data-key`, atom ids, form/control ids, and `data-hemx-st`. The browser never sees handler or slot names. [north_star] - -006 `data-hemx-root` marks a scoped root boundary. [north_star] - -002 POST bodies carry `application/x-www-form-urlencoded` with distinguished field `__h` (handle id). Server routes by numeric id, not by URL path. [north_star] - -003 HTTP interaction responses may be `text/html` fragments containing `