This repository is the organization Pages repository rust-proxy.github.io, whose Pages site root is https://rust-proxy.github.io/. Each project is an independent static site under its own subpath; the root provides a portal page.
- TUIC documentation: rust-proxy.github.io/tuic.
- Configuration editor (renders TUIC configuration by default): rust-proxy.github.io/config-editor/. It has its own HTML, CSS, WebAssembly, and theme, and runs standalone on any static server without depending on a documentation site or backend.
- Wind documentation: rust-proxy.github.io/wind, with English specifications at rust-proxy.github.io/wind/specs.
The sites are built with Zensical; the configuration editor is built with Rust WASM + Svelte 5.
Requires Rust stable, the wasm32-unknown-unknown target, and Node.js 22.12+ (CI uses 24). Run all of the following commands from this repository's root:
rustup target add wasm32-unknown-unknown
npm ci --prefix config-editor
npm run dev --prefix config-editorOpen http://127.0.0.1:8080/. No Python or Zensical server is needed. Its application-schema selector currently provides independent TUIC server and client editors, covering multiple users, three certificate modes, SOCKS5 authentication, logging, connections, TCP/UDP forwarding, Quinn/quiche backends, outbound and ACL routing, DNS/GeoData, RESTful management, and HTTP/3 masquerading. The page uses a responsive workbench: a keyboard-accessible section directory with active-section and error indicators, a searchable card-based editor form, and a sticky preview region that renders the live generated config with syntax highlighting, per-line XML explanations on hover or keyboard focus, validation, and copy/download. Medium screens use a compact section selector; narrow screens switch between editing and preview/export while retaining input and scroll positions. Search matches visible field labels, hints, and paths without indexing input values. Error links switch back to editing before focusing the field. Invalid inputs keep the preview available: flagged values are shown as <placeholder> alongside the validation warnings, while copy and download stay disabled until every field is valid.
When just is installed, the repository root provides shortcuts:
just setup # install locked dependencies for the first time
just dev # compile WASM and start the editor
just dev-ui # skip the WASM build when only changing Svelte/CSS
just wasm # recompile Rust/XML while Vite is running
just check # Rust, WASM, and Svelte checksRun just to see all build, preview, and browser-regression commands.
Standalone build:
npm run build --prefix config-editornpm run build compiles the Rust library with the locked wasm-pack, runs the Svelte/TypeScript checks and the frontend unit tests, and then bundles the local JS/CSS/WASM with Vite. The first build downloads the wasm-bindgen tool matching the Cargo lock file. npm run dev compiles WASM first and then starts Vite; Svelte/CSS supports hot reloading. After changing Rust or XML, run npm run wasm --prefix config-editor in another terminal and refresh the browser.
The default build embeds every application schema listed in config-editor/schema/schemas.txt; the browser switches between them without fetching XML. CONFIG_SCHEMA still selects one XML for isolated reuse tests; paths are relative to config-editor/ (or absolute). Alternative builds should output to a separate directory, and the environment and default WASM must be restored afterward; see the editor's DSL guide.
Artifacts live in config-editor/dist/. Hand the entire directory to a static server; it uses relative asset paths by default and supports either the root path or a subpath with a trailing /. The server must return application/wasm for .wasm; do not open the files over file://. For a fixed prefix, use npm run build --prefix config-editor -- --base /your-prefix/.
Credentials are generated with the browser Crypto API. All input, validation, and serialization happen locally in WASM; no third-party analytics scripts are loaded, inputs, themes, and credentials are not saved, and configuration is never submitted over the network. Copy and download include plaintext passwords, while the preview hides passwords by default.
The page accepts a schema query parameter for direct links; it is an application-schema ID from schema/schemas.txt (currently tuic-server or tuic-client). The selector keeps this parameter synchronized without discarding unrelated query parameters or the URL fragment. The legacy mode parameter is still read but no longer switches views. Unknown schemas safely fall back to the first registered schema.
Requires uv; uvx fetches the pinned Zensical and Python on demand, so no project virtual environment is created.
just docs
just docs-windEach documentation site has its own zensical.toml and docs/; the development server serves only one site at a time, and the configuration editor runs separately with the Vite server above. When adding a documentation site, create <project>/zensical.toml and <project>/docs/, and add it to the build recipe in justfile and to the portal links.
# Rust core logic, DSL, configuration, and security boundaries
cargo test --workspace --locked
cargo +nightly fmt --all --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo clippy --target wasm32-unknown-unknown --lib --locked -- -D warnings
# Check Svelte/TypeScript and run frontend unit tests after building WASM (build also runs this)
npm run check --prefix config-editor
npm run test --prefix config-editor
# Build all documentation sites and the standalone editor into site/; no publishing
just build
uvx python tests/config-editor/check-site.py
# Assemble a site preview (/, /tuic/, /wind/)
uvx python tests/config-editor/preview-server.pyPreview: http://127.0.0.1:8765/, http://127.0.0.1:8765/tuic/, http://127.0.0.1:8765/config-editor/, http://127.0.0.1:8765/wind/. Run npm ci --prefix config-editor first to install the frontend dependencies; the combined build clean-builds each documentation site, places the standalone editor under site/config-editor/, and copies portal/index.html to site/index.html. Stop the documentation development servers before a clean build to avoid cache conflicts.
# Generate test credentials and configuration dynamically; writes only to the ignored .cache/
cargo run --locked --example fixtures -- .cache/config-editor-fixtures
# Python 3.11+ independent parsers for tomllib, json, and PyYAML
uvx --with 'PyYAML>=6,<7' python tests/config-editor/roundtrip.py .cache/config-editor-fixtures/roundtrip.json
# Call the neighboring TUIC's real parsing functions and run a local SOCKS5 -> TUIC -> TCP echo
uvx python tests/config-editor/check-rust.py --offlineThe real parsing check requires the neighboring ../tuic, its submodules, cached dependencies, and the corresponding build tools; omit --offline when the dependency cache is missing. The auxiliary Cargo project writes only to .cache/, starts from TUIC's lock file, and does not modify TUIC manifests, sources, lock files, or submodules. The loopback allowance applies only to the in-memory test configuration, and error diagnostics never print configuration contents.
The browser tests use a separate npm manifest and lock file; test dependencies are not bundled into the application. Start the assembled preview above, then run (locally this uses the installed Edge by default):
npm ci --prefix tests/config-editor
node tests/config-editor/browser.mjs
# Test the built standalone artifact; the temporary local server shuts down with the test
uvx python tests/config-editor/run-browser.py
# Use the deployment prefix for the assembled site build
uvx python tests/config-editor/run-browser.py --directory site/config-editor --prefix /config-editor/
# Alternatively use Playwright's bundled Chromium, matching CI
npm exec --prefix tests/config-editor -- playwright install chromium
BROWSER_CHANNEL=chromium node tests/config-editor/browser.mjsPLAYWRIGHT_MODULE_PATH can point to an existing Playwright module directory; BROWSER_CHANNEL accepts msedge, chrome, and chromium, with CI defaulting to chromium. The standalone Vite development server uses PREVIEW_URL=http://127.0.0.1:8080/. The tests cover WASM loading, standalone page structure, pairing consistency, user removal, TLS switching, input validation, forwarding edits, copy/download, escaping, mobile, theming, no external requests, and no input persistence; screenshots go to .cache/. The reuse check builds with schema/example.xml into .cache/generic-site and runs uvx python tests/config-editor/run-browser.py --directory .cache/generic-site --script tests/config-editor/browser-generic.mjs; see the DSL documentation for the full command. CI likewise keeps the default site artifacts for later publishing.
Config DSL v5 uses independent XML files to statically describe inputs, defaults, enums, conditions, lists, mappings, per-line output descriptions, and sensitive fields, deserialized with quick-xml + Serde; configuration descriptions are not written with Rust macros or closures. schema/schemas.txt registers the XML files embedded in the production selector. The Rust session produces the form view, and Svelte renders it; generic projection and redaction live in dsl.rs, generic validation and field linkage in dsl/rules.rs, and basic address checks in validation.rs. TUIC branding, page sections, hints, cross-field rules, random-value generation declarations, and export commands are also entirely provided by XML. Adding a target application requires a new XML file and one manifest entry; schema/example.xml provides a reuse example with no TUIC fields.
Configuration state is modified only by the Rust Session. Svelte submits generic field/collection operations and reads field display values, visibility, errors, and previews from Snapshot; per-line preview explanations are read from the declared output descriptions in Rust (Snapshot.preview_lines), so the frontend only highlights and displays them. It does not parse XML, evaluate conditions, or keep a second mutable copy of the configuration. JSON strings cross the WASM boundary, and both field display values and stable row identities are strings, avoiding JavaScript number precision loss. ui/types.ts corresponds to the display contract in session/view.rs; when changing the contract, update both sides and run the session tests plus both browser test suites. Copy and download obtain the original text through a separate export operation rather than reading the redacted preview.
| Path | Contents |
|---|---|
Cargo.toml / Cargo.lock |
Editor Rust workspace and locked dependencies |
tuic/zensical.toml / tuic/docs/ |
TUIC Chinese documentation, navigation, field descriptions, and DSL documentation |
tuic/overrides/ |
TUIC theme overrides and 404 page |
config-editor/ |
Independently buildable Rust WASM + Svelte single-page application |
config-editor/ui/ |
Layered frontend: bridge/ (WASM/JSON boundary), state/ (session, workbench, theme, viewport, URL), lib/ (DOM and Prism helpers), components/, styles/, and the types.ts display contract; unit tests use Vitest + jsdom |
config-editor/src/session.rs / session/view.rs |
Natively testable editing operations, form view, and preview export |
config-editor/src/wasm.rs |
WASM interface and browser Crypto API randomness adapter |
config-editor/package.json / vite.config.js |
Locked frontend tooling and static asset bundling |
config-editor/schema/schemas.txt |
Application-schema IDs, selector labels, and embedded XML sources |
config-editor/schema/tuic-server.xml / tuic-client.xml |
Independent TUIC server and client definitions |
config-editor/src/dsl/xml.rs / dsl/wire.rs / dsl/parser.rs |
XML subset checks, Serde data model, and semantic validation |
config-editor/src/dsl.rs |
Data projection, type checking, and redaction |
config-editor/src/schema.rs |
Embedded XML, cached parse results, generic state, and stable row identities |
config-editor/src/dsl/metadata.rs / dsl/rules.rs |
Page metadata, random-value declarations, validation, and field linkage |
config-editor/schema/example.xml |
Complete application reuse example with no TUIC fields |
config-editor/src/model.rs |
Configuration generation entry point and three-format serialization |
config-editor/tests/ |
XML DSL and configuration regression tests |
wind/zensical.toml / wind/docs/ |
Wind Chinese protocol specifications and design documents (single publishing source) |
wind/docs/specs/ |
Wind English specifications and RFC template, published under /wind/specs/ and kept in sync with the Chinese editions |
portal/index.html |
Site root portal page |
justfile |
Build, check, and preview recipes; the build recipe assembles all documentation sites and the editor into site/ without publishing |
tests/config-editor/ |
Standalone parser, real TUIC, site, and browser checks |
.github/workflows/deploy.yml |
GitHub Pages build and publish workflow |
The main documentation is maintained only in Simplified Chinese; the English specifications and RFC template under wind/docs/specs/ are the exception, published alongside their Chinese counterparts under /wind/specs/, with section numbering and requirements kept in sync. After updating TUIC or Wind, verify the editor's version baseline and the actual runtime behavior of fields, and do not expose configuration that is not yet wired into client runtime logic as usable functionality. Examples use placeholder domains and test credentials generated at runtime, and do not include real deployment data.
The CI and Pages workflow runs on pull requests, pushes to main, and manual triggers:
check: nightly rustfmt, stable native and WASM Clippy, Rust/XML DSL tests, and independent TOML/JSON/YAML parsing round trips. Python is pinned to 3.13 viaUV_PYTHON, and tools run on demand withuvx.build: builds the standalone SPA with wasm-pack, the Svelte checker, and Vite, assembles all documentation sites, checks site links and assets, and then runs the TUIC and no-TUIC-field XML reuse browser regressions through the locked Playwright/Chromium. Rust, uv, and npm use dependency caching.deploy: depends oncheckandbuildsucceeding, and publishes only on pushes tomainor manual runs; Pages write and OIDC permissions are granted only to this job, while pull requests only validate and build.
The published artifact is assembled in a temporary directory whose root is https://rust-proxy.github.io/: the portal page is at /, TUIC documentation at /tuic/, the standalone editor at /config-editor/, Wind Chinese documentation at /wind/, and the Wind English specifications at /wind/specs/. No custom domain or CNAME is used, and the Pages source should be set to GitHub Actions. Real TUIC parsing and loopback tests still run in an environment with the neighboring repositories as described above.
The documentation has migrated from MkDocs to Zensical and no longer uses the i18n plugin. The old /tuic/zh/ path does not generate a redirect; external links should be updated under /tuic/. A passing site build and configuration parse does not mean remote DNS, certificates, firewalls, or proxy connections have been verified.