@adukiorg/anza 0.2.0 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +90 -4
  2. package/README.md +97 -133
  3. package/bin/anza/anza-linux-arm64 +0 -0
  4. package/bin/anza/anza-linux-x64 +0 -0
  5. package/bin/anza/anza-macos-arm64 +0 -0
  6. package/bin/anza/anza-macos-x64 +0 -0
  7. package/bin/anza/anza-windows-x64.exe +0 -0
  8. package/bin/anza/find.js +35 -0
  9. package/bin/anza/index.js +34 -0
  10. package/bin/anza/launch.js +19 -0
  11. package/bin/common/index.js +7 -0
  12. package/bin/common/logs.js +62 -0
  13. package/bin/create/copy.js +18 -0
  14. package/bin/create/index.js +45 -0
  15. package/bin/create/run.js +210 -0
  16. package/bin/create/write.js +19 -0
  17. package/importmap.json +4 -0
  18. package/package.json +16 -10
  19. package/src/core/offline/{usage.md → notes/usage.md} +11 -1
  20. package/src/core/router/boot.js +82 -0
  21. package/src/core/router/cascade.js +76 -0
  22. package/src/core/router/container.js +63 -72
  23. package/src/core/router/graph.js +144 -0
  24. package/src/core/router/index.js +12 -2
  25. package/src/core/router/intercept.js +26 -7
  26. package/src/core/router/lca.js +58 -0
  27. package/src/core/router/match.js +49 -36
  28. package/src/core/router/notes/audit-old.md +887 -0
  29. package/src/core/router/notes/audti.md +773 -0
  30. package/src/core/router/notes/tasks.md +473 -0
  31. package/src/core/router/{usage.md → notes/usage.md} +57 -35
  32. package/src/core/router/sync/tab.js +6 -4
  33. package/src/core/router/transitions.js +35 -8
  34. package/src/core/router/trie.js +130 -0
  35. package/src/core/security/{usage.md → notes/usage.md} +1 -2
  36. package/src/core/storage/{usage.md → notes/usage.md} +6 -6
  37. package/src/core/theme/index.js +78 -0
  38. package/src/core/ui/define/index.js +2 -1
  39. package/src/core/ui/define/orchestrator.js +10 -4
  40. package/src/core/ui/defs/dock.js +134 -0
  41. package/src/core/ui/defs/index.js +20 -0
  42. package/src/core/ui/defs/page.js +89 -0
  43. package/src/core/ui/defs/part.js +28 -0
  44. package/src/core/ui/defs/spec.js +96 -0
  45. package/src/core/ui/defs/view.js +23 -0
  46. package/src/core/ui/index.js +16 -3
  47. package/src/core/ui/notes/definations.md +979 -0
  48. package/src/tokens/index.css +1 -0
  49. package/src/tokens/semantic/contrast.css +18 -0
  50. package/src/tokens/semantic/transitions.css +32 -0
  51. package/types/core/platform/index.d.ts +39 -10
  52. package/types/core/router/index.d.ts +9 -0
  53. package/types/core/theme/index.d.ts +18 -0
  54. package/types/core/ui/index.d.ts +11 -0
  55. package/types/index.d.ts +1 -0
  56. package/bin/anza.js +0 -63
  57. package/bin/create.js +0 -150
  58. package/src/core/api/plan.md +0 -209
  59. package/src/core/events/missing.md +0 -103
  60. package/src/core/events/plan.md +0 -177
  61. package/src/core/offline/missing.md +0 -89
  62. package/src/core/offline/plan.md +0 -143
  63. package/src/core/platform/missing.md +0 -119
  64. package/src/core/platform/platform.d.ts +0 -88
  65. package/src/core/router/missing.md +0 -716
  66. package/src/core/router/outlet.js +0 -139
  67. package/src/core/router/plan.md +0 -370
  68. package/src/core/security/missing.md +0 -97
  69. package/src/core/state/missing.md +0 -165
  70. package/src/core/storage/missing.md +0 -165
  71. package/src/core/storage/plan.md +0 -69
  72. package/src/core/ui/implementation.md +0 -170
  73. package/src/core/ui/plan.md +0 -510
  74. package/src/core/ui/ui.types.md +0 -890
  75. /package/src/core/animations/{usage.md → notes/usage.md} +0 -0
  76. /package/src/core/api/{usage.md → notes/usage.md} +0 -0
  77. /package/src/core/events/{usage.md → notes/usage.md} +0 -0
  78. /package/src/core/platform/{usage.md → notes/usage.md} +0 -0
  79. /package/src/core/state/{usage.md → notes/usage.md} +0 -0
  80. /package/src/core/ui/{usage.md → notes/usage.md} +0 -0
  81. /package/src/core/ui/{watch.md → notes/watch.md} +0 -0
  82. /package/src/core/workers/{plan.md → notes/plan.md} +0 -0
  83. /package/src/core/workers/{usage.md → notes/usage.md} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  All notable changes to `@adukiorg/anza` will be documented here.
4
4
 
5
- Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
  Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
@@ -16,11 +16,94 @@ Versioning follows [Semantic Versioning](https://semver.org/).
16
16
 
17
17
  ---
18
18
 
19
+ ## [0.2.3] — 2026-06-09
20
+
21
+ ### Fixed
22
+
23
+ - CI release workflow artifact naming to prevent binary overwrites
24
+ - Windows runner shell compatibility (`shell: bash`)
25
+
26
+ ---
27
+
28
+ ## [0.2.2] — 2026-06-09
29
+
30
+ ### Added
31
+
32
+ - CI/CD workflows for GitHub Actions (build, typecheck, verify scaffolding, cross-platform release)
33
+ - Comprehensive documentation for all modules (animations, api, events, platform, router, security, state, storage, sw, ui, workers)
34
+ - `library/bin/` CLI wrappers for Node.js distribution
35
+
36
+ ---
37
+
38
+ ## [0.2.1] — 2026-06-09
39
+
40
+ ### Added
41
+
42
+ #### Service Worker Toolkit — `@adukiorg/anza/sw`
43
+
44
+ - **New subpath export** `@adukiorg/anza/sw` — caching strategies, route interception, background sync, and push notifications
45
+ - **Seven caching strategies**: CacheFirst, NetworkFirst, StaleRevalidate, CacheThenNetwork, NetworkOnly, CacheOnly, OfflineFallback
46
+ - **URLPattern routing** inside the Service Worker via `router()` and `Router`
47
+ - **Install/activate helpers**: `precache()`, `pruneStale()`, `claim()`, `enableNavPreload()`
48
+ - **TTL expiry**: `pruneExpired()`, `setupAutoPrune()` with `x-expires-at` headers
49
+ - **Background sync**: `replayQueue()`, `requeueFailed()` with dead-letter queue
50
+ - **Request serialization**: `serializeRequest()`, `deserializeRequest()` for IndexedDB storage
51
+ - **Push notifications**: `subscribe()`, `notify()` with VAPID support
52
+ - **Scaffolded `src/sw.js`** generated by both `anza create` and `anza-create`
53
+
54
+ #### Theme Switching — `@adukiorg/anza/theme`
55
+
56
+ - **New subpath export** `@adukiorg/anza/theme`
57
+ - **Auto-init on import** — reads saved preference from `localStorage` or respects `prefers-color-scheme`
58
+ - **Attaches to `window.theme`** via `Object.defineProperty` (non-enumerable, non-configurable)
59
+ - **API**: `theme.get()`, `theme.set()`, `theme.toggle()` — all update the same global instance
60
+ - **No manual init required** — importing `@adukiorg/anza/ui` triggers it automatically
61
+
62
+ #### View Transition Tokens — `tokens/semantic/transitions.css`
63
+
64
+ - **New semantic token layer** connecting the CSS View Transitions API to the design token system
65
+ - **Tokens**: `--transition-bg`, `--transition-duration`, `--transition-easing`, `--transition-push`, `--transition-pop`, `--transition-replace`
66
+ - **Router `transitions.run()`** injects a token-aware stylesheet on first use
67
+ - **Dock `swap()`** reads directional easing from tokens (`--transition-push` vs `--transition-pop`) for physically different forward/back feel
68
+ - **High-contrast theme morphing** — `contrast.css` now declares `transition:` for smooth token interpolation
69
+
70
+ #### Documentation
71
+
72
+ - **Comprehensive `docs/index.md`** — master docs entry with all modules listed by usefulness
73
+ - **`docs/sw/`** — complete SW documentation: `index.md`, `start.md`, `strategies.md`, `routes.md`, `sync.md`, `api.md`
74
+ - **Updated `docs/intro/`** — SW toolkit in feature list, build output includes `dist/sw.js`
75
+ - **View Transition token docs** added to `docs/ui/transitions.md`, `docs/router/transitions.md`, `docs/animations/tokens.md`
76
+
77
+ #### Tooling
78
+
79
+ - **`tools/src/build/graph.rs` split** into focused modules:
80
+ - `cache.rs` — incremental build cache (`.anzacache.json`)
81
+ - `parse.rs` — ESM AST parsing with swc
82
+ - `entries.rs` — entry point discovery from HTML and `src/sw.js`
83
+ - `resolve.rs` — import map and filesystem resolution
84
+ - `html.rs` — HTML injection (importmap link, HMR script)
85
+ - `sw.rs` — Service Worker bare-specifier rewriting
86
+ - **Auto-discovery of `src/sw.js`** as a build entry point
87
+ - **Bare specifier rewriting in `dist/sw.js`** — `@adukiorg/anza/sw` → `./sw/index.js` (SW does not support import maps)
88
+
89
+ ### Changed
90
+
91
+ - **Cache file renamed** from `.anza-build-cache.json` to `.anzacache.json`
92
+ - **Scaffolded `src/app.js`** now imports and auto-registers the Service Worker
93
+ - **Scaffolded `src/sw.js`** included in both Node.js and Rust `create` commands
94
+
95
+ ### Fixed
96
+
97
+ - High-contrast theme (`contrast.css`) now animates token changes instead of snapping instantly
98
+
99
+ ---
100
+
19
101
  ## [0.2.0] — 2026-06-07
20
102
 
21
103
  ### Added
22
104
 
23
105
  #### Compiler — `anza`
106
+
24
107
  - **Dependency Graph Walking**: Automated dependency resolution of ESM imports/exports.
25
108
  - **Tree-Shaking**: Outputs only referenced files to `dist/`, excluding unused code.
26
109
  - **Automatic Inline Importmaps**: Optimal `<script type="importmap">` generated and injected inline into HTML entry points.
@@ -30,9 +113,11 @@ Versioning follows [Semantic Versioning](https://semver.org/).
30
113
  - **Nested /dist Routing**: Added router nested service mapping in Axum dev server for development path parity.
31
114
 
32
115
  #### Structure
116
+
33
117
  - **Monorepo Split**: Reorganized files into `/library` (NPM package), `/sample` (demo application), and `/tools` (Rust compiler).
34
118
 
35
119
  #### Sample
120
+
36
121
  - **Cyberpunk Blog SPA**: Features reactive store, category filters, instant search, likes count persistence, details page with lightweight custom markdown renderer, post publishing, and post deletion.
37
122
 
38
123
  ---
@@ -132,6 +217,7 @@ Versioning follows [Semantic Versioning](https://semver.org/).
132
217
  - `blog/` — sample SPA demonstrating state, storage, offline queue, and animations
133
218
  - Import map mirrors the published `@adukiorg/anza/*` subpath exports exactly
134
219
 
135
- [Unreleased]: https://github.com/aduki-org/native/compare/v0.2.0...HEAD
136
- [0.2.0]: https://github.com/aduki-org/native/compare/v0.1.0...v0.2.0
137
- [0.1.0]: https://github.com/aduki-org/native/releases/tag/v0.1.0
220
+ [Unreleased]: https://github.com/aduki-org/anza/compare/v0.2.1...HEAD
221
+ [0.2.1]: https://github.com/aduki-org/anza/compare/v0.2.0...v0.2.1
222
+ [0.2.0]: https://github.com/aduki-org/anza/compare/v0.1.0...v0.2.0
223
+ [0.1.0]: https://github.com/aduki-org/anza/releases/tag/v0.1.0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @adukiorg/anza
2
2
 
3
- > Anza web platform library. Pure browser ESM no bundler, no framework lock-in. A small local Rust toolchain resolves your import graph into a minimal, browser-native `dist/`.
3
+ > The browser already knows how to render, route, cache, and animate. We just stopped getting in its way.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@adukiorg/anza)](https://www.npmjs.com/package/@adukiorg/anza)
6
6
  [![license](https://img.shields.io/npm/l/@adukiorg/anza)](./LICENSE)
@@ -8,206 +8,170 @@
8
8
 
9
9
  ---
10
10
 
11
- ## What is this?
11
+ ## What This Is (and What It Is Not)
12
12
 
13
- `@adukiorg/anza` is a modular, zero-dependency platform library built entirely on top of browser-native APIs:
13
+ **This is** a web platform library that treats the browser as the runtime. It gives you reactive state, client-side routing, custom elements, offline sync, and animations — all as plain ES modules the browser resolves directly. No bundler. No virtual DOM. No framework lock-in.
14
14
 
15
- | Module | What it wraps |
16
- | --- | --- |
17
- | `/api` | `fetch`, Streams API, `scheduler.postTask` |
18
- | `/state` | ES Proxy, `queueMicrotask`, `BroadcastChannel` |
19
- | `/events` | Custom pub/sub with AbortSignal cleanup |
20
- | `/router` | Navigation API, History API |
21
- | `/storage` | IndexedDB, Cache API, OPFS, LRU memory |
22
- | `/offline` | IDB-backed operation queue, `navigator.onLine` |
23
- | `/animations` | WAAPI (`element.animate`), stagger groups |
24
- | `/workers` | Web Locks API, Web Workers pool |
25
- | `/security` | Web Crypto API, `DOMParser` XSS sanitizer |
26
- | `/platform` | Feature detection for 30+ browser APIs |
27
- | `/ui` | Shadow DOM base element, design token cascade |
28
- | `/elements` | Custom element library |
15
+ **This is NOT** another React competitor. If you love JSX, useEffect cleanup races, and wondering why your bundle is 400KB, Anza is not for you. We are not trying to replace React. React is fine. React is great. React is for people who enjoy debugging `useMemo` dependency arrays at 2am. We are for people who want to write `.js` files and let the browser do what it was built to do.
29
16
 
30
- No virtual DOM. No transpilation. The library is authored as plain `.js` files in `library/src/`. The bundled-in Rust toolchain (`tools/`) walks your ESM `import` graph from your entry points and emits **only the modules you actually use** into `dist/`, preserving a folder structure the browser resolves natively.
17
+ **This is NOT** Angular. We do not have a CLI that generates fourteen files to render a button. We have `element('my-button', { template: '<button>Click me</button>' })`. That is the whole API.
31
18
 
32
- ---
33
-
34
- ## Installation
35
-
36
- To install `@adukiorg/anza` in your project:
37
-
38
- ```bash
39
- npm install @adukiorg/anza
40
- ```
19
+ **This is NOT** Vue. We do not have a template compiler. We do not have a virtual DOM diffing algorithm that runs in JavaScript to figure out what the browser should have already figured out. We write HTML. The browser parses HTML. It has been doing this since 1993. It is pretty good at it.
41
20
 
42
21
  ---
43
22
 
44
- ## Workspace Structure
23
+ ## The Pitch
45
24
 
46
- The codebase is organized as a monorepo containing:
25
+ Anza is built on browser-native APIs. Every module wraps something the browser already ships:
47
26
 
48
- - **`library/`**: The core package codebase (`src/`, `tests/`, `package.json`, etc.).
49
- - **`sample/`**: A sample application demonstrating reactive state, routing, and component separation in action.
50
- - **`tools/`**: The Rust compiler toolchain codebase (`anza`).
51
- - **`scripts/`**: Toolchain build and release helper scripts.
27
+ | Module | What it wraps | What we did to it |
28
+ | --- | --- | --- |
29
+ | `/api` | `fetch`, Streams API, `scheduler.postTask` | Added retries, caching, and a pipeline. The browser did the hard part. |
30
+ | `/state` | ES Proxy, `queueMicrotask`, `BroadcastChannel` | Reactive stores with batched updates. No getters/setters boilerplate. |
31
+ | `/events` | `CustomEvent`, `AbortSignal` | Pub/sub with cleanup that actually works. |
32
+ | `/router` | Navigation API, History API, `URLPattern` | Routes that match URLs and render views. Shocking, we know. |
33
+ | `/storage` | IndexedDB, Cache API, OPFS | Tiered persistence: memory → IDB → disk. You pick the tier. |
34
+ | `/offline` | `navigator.onLine`, IndexedDB | Queue failed requests, replay them later. Like a polite retry system. |
35
+ | `/animations` | WAAPI (`element.animate`) | Stagger groups and scroll-driven animations. The GPU does the work. |
36
+ | `/workers` | Web Locks API, Web Workers | A worker pool with concurrency limits. Because tabs deserve boundaries. |
37
+ | `/security` | Web Crypto API, `DOMParser` | Encrypt, hash, sanitize. The browser has a crypto lab. We use it. |
38
+ | `/platform` | 30+ browser APIs | Feature detection so you know what you are working with. |
39
+ | `/ui` | Custom Elements, Shadow DOM, CSS Layers | Declarative components with reactive props and lifecycle hooks. No classes. |
40
+ | `/sw` | Service Worker, Cache API, Background Sync | Caching strategies, route interception, and push notifications. |
41
+ | `/theme` | `data-theme`, `localStorage`, `matchMedia` | Auto theme switching with persistence. Light, dark, or high-contrast. |
52
42
 
53
- ---
43
+ The Rust CLI (`anza`) resolves your ESM import graph and copies only the modules you actually use into `dist/`. It generates type declarations, serves with HMR, and gets out of your way.
54
44
 
55
- ## Building the Toolchain & Running the Sample
45
+ ---
56
46
 
57
- The compiler (`anza`) is a native Rust CLI that manages the build pipeline.
47
+ ## Quick Start
58
48
 
59
- ### 1. Build the compiler
60
- From the workspace root directory:
61
49
  ```bash
62
- node scripts/build.js
50
+ npx anza-create myapp
51
+ cd myapp
52
+ npm install
53
+ npm run dev
63
54
  ```
64
- This builds the release binary into `tools/target/release/anza`.
65
55
 
66
- ### 2. Run the Sample Application
67
- Navigate into the sample project:
68
- ```bash
69
- cd sample
70
- npm install # Links to the local library package
71
- npm run build # Performs graph resolution and emits output to dist/
72
- npm run dev # Starts dev server on port 8080 with HMR and routing fallbacks
73
- ```
56
+ That is it. Your browser loads `dist/app.js` natively. No webpack. No vite. No `npm run build` that takes forty seconds.
74
57
 
75
58
  ---
76
59
 
77
- ## What the Toolchain Does
60
+ ## What You Actually Write
78
61
 
79
- - **Graph Walking**: Resolves the full import graph starting from your entry points (`src/index.js` by default, plus module scripts found in HTML templates).
80
- - **Tree-Shaking**: Copies only the reached modules into `dist/`. Unreferenced files and assets are completely excluded.
81
- - **Automatic Inline Importmap**: Analyzes import references and automatically generates/injects an optimal `<script type="importmap">` tag inline in your HTML files.
82
- - **Static Asset Copying**: Automatically copies templates (`.html`) and stylesheets (`.css`) referenced by your components.
83
- - **Strict Validation**: Fails the build on unresolved imports, syntax errors, or invalid component prop declarations.
84
- - **HMR Dev Server**: Serves your files with a SSE live-reload listener. Modifying a CSS file hot-swaps it in place; HTML/JS modifications trigger a fast page reload.
62
+ ### A Component
85
63
 
86
- ---
64
+ ```javascript
65
+ import { view } from '@adukiorg/anza/defs';
87
66
 
88
- ## Splitting a Component Across Files
67
+ view('user-card', {
68
+ props: {
69
+ name: { type: String, default: 'Guest' },
70
+ active: { type: Boolean }
71
+ },
72
+ template: `
73
+ <div class="card">
74
+ <h2 ref="title">{{ name }}</h2>
75
+ <span class="badge" hidden="">{{ active }}</span>
76
+ </div>
77
+ `,
78
+ on: {
79
+ connect({ refs }) {
80
+ refs.title.textContent = this.name;
81
+ },
82
+ change({ name, val, refs }) {
83
+ if (name === 'name') refs.title.textContent = val;
84
+ }
85
+ }
86
+ });
87
+ ```
89
88
 
90
- You can separate a component's logical code, templates, and styles into separate files for clean maintainability. The compiler resolves the relative template and stylesheet paths, processes them, and emits them to `dist/`:
89
+ Use it:
91
90
 
92
- ### `ui-button/template.html`
93
91
  ```html
94
- <button class="btn" ref="button">
95
- <slot></slot>
96
- </button>
92
+ <user-card name="Alice" active></user-card>
97
93
  ```
98
94
 
99
- ### `ui-button/style.css`
100
- ```css
101
- :host { display: inline-block; }
102
- .btn { background: var(--color-primary); color: white; border: none; }
103
- ```
95
+ No build step. No JSX transform. No virtual DOM reconciliation. The browser parses the template, creates the DOM, and updates it when props change. Because that is literally what browsers are for.
104
96
 
105
- ### `ui-button/index.js`
106
- ```js
107
- import { ui } from '@adukiorg/anza/ui';
97
+ ### A Route
108
98
 
109
- ui.element('ui-button', {
110
- template: './template.html',
111
- style: './style.css',
112
- props: {
113
- disabled: { type: Boolean, default: false }
114
- },
115
- mount({ el, refs, on }) {
116
- on.click('[ref="button"]', () => {
117
- console.log('Button clicked!');
118
- });
119
- }
99
+ ```javascript
100
+ import { page, dock } from '@adukiorg/anza/defs';
101
+
102
+ dock('main', { parent: 'body' });
103
+
104
+ page('/', {
105
+ tag: 'page-home',
106
+ via: ['main'],
107
+ template: { html: './home.html', css: './home.css' }
120
108
  }, import.meta.url);
121
109
  ```
122
110
 
123
- ---
124
-
125
- ## Quick Examples
111
+ Click `<a href="/about">`. The router intercepts it. The view transitions. No full page reload. The Navigation API has been in Chrome since 2022. We use it.
126
112
 
127
113
  ### Reactive State
128
114
 
129
- ```js
115
+ ```javascript
130
116
  import { state } from '@adukiorg/anza/state';
131
117
 
132
- const store = state.create({ count: 0, theme: 'dark' });
118
+ const store = state.create({ count: 0 });
133
119
 
134
120
  store.subscribe('count', () => {
135
121
  console.log('count changed to', store.get('count'));
136
122
  });
137
123
 
138
- store.set('count', 1); // fires after microtask flush
139
- store.set('count', 2); // batched — only one notification fires
124
+ store.set('count', 1);
140
125
  ```
141
126
 
142
- ### Network Requests
127
+ Proxy-based reactivity. Batched updates. Cross-tab sync via `BroadcastChannel`. No reducers. No actions. No sagas. Just a store that notifies subscribers when data changes. Revolutionary, we know.
143
128
 
144
- ```js
145
- import { api, PlatformError } from '@adukiorg/anza/api';
129
+ ### Theme Switching (Automatic)
146
130
 
147
- try {
148
- const data = await api.get('https://api.example.com/posts');
149
- console.log(data);
150
- } catch (err) {
151
- if (err instanceof PlatformError) {
152
- console.error(err.code, err.message); // 'NETWORK_TIMEOUT', 'HTTP_ERROR', etc.
153
- }
154
- }
155
- ```
131
+ ```javascript
132
+ import { theme } from '@adukiorg/anza/theme';
156
133
 
157
- ### IndexedDB Storage
134
+ theme.toggle(); // light ↔ dark
135
+ theme.set('contrast'); // high-contrast mode
136
+ ```
158
137
 
159
- ```js
160
- import { Database } from '@adukiorg/anza/storage';
138
+ No init call needed. It auto-restores from `localStorage` on import. Respects `prefers-color-scheme` if no saved preference exists. Attaches to `window.theme` for devtools access. Because theme toggles are not rocket science.
161
139
 
162
- const db = new Database('myapp', 1, [
163
- (db) => db.createObjectStore('posts')
164
- ]);
140
+ ---
165
141
 
166
- await db.open();
167
- await db.set('posts', 'post-1', { title: 'Hello', content: '...' });
168
- const post = await db.get('posts', 'post-1');
169
- ```
142
+ ## The Token System
170
143
 
171
- ### Animations
144
+ Anza ships with a complete design token layer:
172
145
 
173
- ```js
174
- import { animate, stagger } from '@adukiorg/anza/animations';
146
+ - **Primitives** — OKLCH color scales, spacing, motion, radius, shadow, z-index
147
+ - **Semantic** — light, dark, high-contrast themes with GPU-accelerated token morphing
148
+ - **Components** — form controls, feedback, overlays, layout tokens
149
+ - **Transitions** — View Transition timing and backdrop tokens
175
150
 
176
- // Single element
177
- animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 300 });
151
+ You own `src/tokens/` after scaffolding. Change a primitive, every component updates. Change a semantic mapping, the whole theme shifts. Override anything in `@layer overrides`. The cascade handles the rest.
178
152
 
179
- // Staggered group
180
- const cards = document.querySelectorAll('.card');
181
- stagger(Array.from(cards), [
182
- { transform: 'translateY(20px)', opacity: 0 },
183
- { transform: 'translateY(0)', opacity: 1 }
184
- ], { duration: 250, staggerDelay: 60 });
185
- ```
153
+ ---
186
154
 
187
- ### Client-Side Router
155
+ ## Philosophy
188
156
 
189
- ```js
190
- import { register, navigate } from '@adukiorg/anza/router';
157
+ **Native first.** If the browser has an API for it, we use it. If it doesn't, we build the smallest possible wrapper. We do not reimplement the browser inside JavaScript.
191
158
 
192
- register('/posts/:id', async ({ params }) => {
193
- const post = await fetchPost(params.id);
194
- renderPost(post);
195
- });
159
+ **Zero build.** The browser resolves ESM imports natively. Our Rust CLI copies the files you use into `dist/`. That is the whole build step. No bundling. No tree-shaking algorithms. The browser is single-threaded anyway.
196
160
 
197
- navigate('/posts/42');
198
- ```
161
+ **You own your code.** Scaffolding copies starter files into `src/`. The library never touches them again. No hidden configs. No magic globals. No runtime injection of framework internals.
199
162
 
200
163
  ---
201
164
 
202
165
  ## Testing
203
166
 
204
- Tests run in **real Chromium** via `@web/test-runner` — no jsdom or node mocks.
167
+ Tests run in **real Chromium** via `@web/test-runner` — no jsdom, no node mocks, no pretend browser.
205
168
 
206
169
  ```bash
207
- cd library
208
170
  npm test
209
171
  ```
210
172
 
173
+ If it passes in Chromium, it passes in Chrome. If it passes in Chrome, it probably works everywhere else. (We said probably. Safari is Safari.)
174
+
211
175
  ---
212
176
 
213
177
  ## License
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,35 @@
1
+ /**
2
+ * bin/anza/find.js
3
+ *
4
+ * Resolves the anza Rust binary path for the current platform.
5
+ */
6
+
7
+ import { join } from 'path';
8
+ import { existsSync } from 'fs';
9
+
10
+ const PLATFORMS = {
11
+ darwin: { x64: 'anza-macos-x64', arm64: 'anza-macos-arm64' },
12
+ linux: { x64: 'anza-linux-x64', arm64: 'anza-linux-arm64' },
13
+ win32: { x64: 'anza-windows-x64.exe', arm64: 'anza-windows-arm64.exe' },
14
+ };
15
+
16
+ export function resolve(root, here) {
17
+ const dev = join(root, 'tools', 'target', 'release', 'anza');
18
+ if (existsSync(dev)) return dev;
19
+
20
+ const platform = process.platform;
21
+ const arch = process.arch;
22
+ const name = PLATFORMS[platform]?.[arch];
23
+
24
+ if (!name) {
25
+ throw new Error(`Unsupported platform: ${platform} ${arch}`);
26
+ }
27
+
28
+ const prebuilt = join(here, name);
29
+ if (existsSync(prebuilt)) return prebuilt;
30
+
31
+ throw new Error(
32
+ 'anza binary not found.\n' +
33
+ 'Run: node tasks/build.js (from the repo root)'
34
+ );
35
+ }
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bin/anza/index.js
4
+ *
5
+ * Node.js wrapper for the anza Rust binary.
6
+ * Re-exports find and launch for programmatic use.
7
+ */
8
+
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, join } from 'path';
11
+ import { resolve } from './find.js';
12
+ import { start } from './launch.js';
13
+
14
+ export { resolve } from './find.js';
15
+ export { start } from './launch.js';
16
+
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = dirname(__filename);
19
+
20
+ const library = join(__dirname, '..', '..');
21
+ const root = join(library, '..');
22
+
23
+ // CLI entry only when executed directly
24
+ const isCli = process.argv[1] === __filename;
25
+
26
+ if (isCli) {
27
+ try {
28
+ const path = resolve(root, __dirname);
29
+ start(path, process.argv.slice(2));
30
+ } catch (err) {
31
+ console.error(err.message);
32
+ process.exit(1);
33
+ }
34
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * bin/anza/launch.js
3
+ *
4
+ * Spawns the anza Rust binary with forwarded args.
5
+ */
6
+
7
+ import { spawn } from 'child_process';
8
+ import * as logs from '../common/index.js';
9
+
10
+ export function start(path, args) {
11
+ const child = spawn(path, args, { stdio: 'inherit' });
12
+
13
+ child.on('error', (err) => {
14
+ logs.error(`Failed to spawn anza: ${err.message}`);
15
+ process.exit(1);
16
+ });
17
+
18
+ child.on('exit', (code) => process.exit(code ?? 0));
19
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * bin/common/index.js
3
+ *
4
+ * Re-exports the logs module for cleaner imports.
5
+ */
6
+
7
+ export * from './logs.js';
@@ -0,0 +1,62 @@
1
+ /**
2
+ * bin/common/logs.js
3
+ *
4
+ * Colored category logger matching the Rust logs crate.
5
+ * Categories: info, debug, success, error, warn, compiler, server, hmr, watcher, sync.
6
+ */
7
+
8
+ const RESET = '\x1b[0m';
9
+ const GRAY = '\x1b[90m';
10
+ const BLUE = '\x1b[34m';
11
+ const CYAN = '\x1b[36m';
12
+ const GREEN = '\x1b[1m\x1b[32m';
13
+ const RED = '\x1b[1m\x1b[31m';
14
+ const YELLOW = '\x1b[1m\x1b[33m';
15
+ const BYELLOW = '\x1b[93m';
16
+ const BBLUE = '\x1b[94m';
17
+ const BGREEN = '\x1b[92m';
18
+
19
+ function stamp() {
20
+ const d = new Date();
21
+ return `${GRAY}[${d.toISOString().slice(0, 19).replace('T', ' ')}]${RESET} `;
22
+ }
23
+
24
+ export function info(msg) {
25
+ console.log(`${stamp()}${BLUE}INFO:${RESET} ${msg}`);
26
+ }
27
+
28
+ export function debug(msg) {
29
+ console.log(`${stamp()}${GRAY}DEBUG:${RESET} ${msg}`);
30
+ }
31
+
32
+ export function success(msg) {
33
+ console.log(`${stamp()}${GREEN}SUCCESS:${RESET} ${msg}`);
34
+ }
35
+
36
+ export function error(msg) {
37
+ console.error(`${stamp()}${RED}ERROR:${RESET} ${msg}`);
38
+ }
39
+
40
+ export function warn(msg) {
41
+ console.warn(`${stamp()}${YELLOW}WARN:${RESET} ${msg}`);
42
+ }
43
+
44
+ export function compiler(msg) {
45
+ console.log(`${stamp()}${CYAN}COMPILER:${RESET} ${msg}`);
46
+ }
47
+
48
+ export function server(msg) {
49
+ console.log(`${stamp()}${BBLUE}SERVER:${RESET} ${msg}`);
50
+ }
51
+
52
+ export function hmr(msg) {
53
+ console.log(`${stamp()}${BGREEN}HMR:${RESET} ${msg}`);
54
+ }
55
+
56
+ export function watcher(msg) {
57
+ console.log(`${stamp()}${BYELLOW}WATCHER:${RESET} ${msg}`);
58
+ }
59
+
60
+ export function sync(msg) {
61
+ console.log(`${stamp()}${GRAY}SYNC:${RESET} ${msg}`);
62
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * bin/create/copy.js
3
+ *
4
+ * Recursively copies a directory tree.
5
+ */
6
+
7
+ import { cpSync } from 'fs';
8
+ import * as logs from '../common/index.js';
9
+
10
+ export function copy(src, dst) {
11
+ try {
12
+ cpSync(src, dst, { recursive: true });
13
+ return true;
14
+ } catch (e) {
15
+ logs.warn(`Could not copy ${src} -> ${dst}: ${e.message}`);
16
+ return false;
17
+ }
18
+ }