@affectively/aeon-pages 1.3.0

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 (124) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +625 -0
  3. package/examples/basic/aeon.config.ts +39 -0
  4. package/examples/basic/components/Cursor.tsx +86 -0
  5. package/examples/basic/components/OfflineIndicator.tsx +103 -0
  6. package/examples/basic/components/PresenceBar.tsx +77 -0
  7. package/examples/basic/package.json +20 -0
  8. package/examples/basic/pages/index.tsx +80 -0
  9. package/package.json +101 -0
  10. package/packages/analytics/README.md +309 -0
  11. package/packages/analytics/build.ts +35 -0
  12. package/packages/analytics/package.json +50 -0
  13. package/packages/analytics/src/click-tracker.ts +368 -0
  14. package/packages/analytics/src/context-bridge.ts +319 -0
  15. package/packages/analytics/src/data-layer.ts +302 -0
  16. package/packages/analytics/src/gtm-loader.ts +239 -0
  17. package/packages/analytics/src/index.ts +230 -0
  18. package/packages/analytics/src/merkle-tree.ts +489 -0
  19. package/packages/analytics/src/provider.tsx +300 -0
  20. package/packages/analytics/src/types.ts +320 -0
  21. package/packages/analytics/src/use-analytics.ts +296 -0
  22. package/packages/analytics/tsconfig.json +19 -0
  23. package/packages/benchmarks/src/benchmark.test.ts +691 -0
  24. package/packages/cli/dist/index.js +61899 -0
  25. package/packages/cli/package.json +43 -0
  26. package/packages/cli/src/commands/build.test.ts +682 -0
  27. package/packages/cli/src/commands/build.ts +890 -0
  28. package/packages/cli/src/commands/dev.ts +473 -0
  29. package/packages/cli/src/commands/init.ts +409 -0
  30. package/packages/cli/src/commands/start.ts +297 -0
  31. package/packages/cli/src/index.ts +105 -0
  32. package/packages/directives/src/use-aeon.ts +272 -0
  33. package/packages/mcp-server/package.json +51 -0
  34. package/packages/mcp-server/src/index.ts +178 -0
  35. package/packages/mcp-server/src/resources.ts +346 -0
  36. package/packages/mcp-server/src/tools/index.ts +36 -0
  37. package/packages/mcp-server/src/tools/navigation.ts +545 -0
  38. package/packages/mcp-server/tsconfig.json +21 -0
  39. package/packages/react/package.json +40 -0
  40. package/packages/react/src/Link.tsx +388 -0
  41. package/packages/react/src/components/InstallPrompt.tsx +286 -0
  42. package/packages/react/src/components/OfflineDiagnostics.tsx +677 -0
  43. package/packages/react/src/components/PushNotifications.tsx +453 -0
  44. package/packages/react/src/hooks/useAeonNavigation.ts +219 -0
  45. package/packages/react/src/hooks/useConflicts.ts +277 -0
  46. package/packages/react/src/hooks/useNetworkState.ts +209 -0
  47. package/packages/react/src/hooks/usePilotNavigation.ts +254 -0
  48. package/packages/react/src/hooks/useServiceWorker.ts +278 -0
  49. package/packages/react/src/hooks.ts +195 -0
  50. package/packages/react/src/index.ts +151 -0
  51. package/packages/react/src/provider.tsx +467 -0
  52. package/packages/react/tsconfig.json +19 -0
  53. package/packages/runtime/README.md +399 -0
  54. package/packages/runtime/build.ts +48 -0
  55. package/packages/runtime/package.json +71 -0
  56. package/packages/runtime/schema.sql +40 -0
  57. package/packages/runtime/src/api-routes.ts +465 -0
  58. package/packages/runtime/src/benchmark.ts +171 -0
  59. package/packages/runtime/src/cache.ts +479 -0
  60. package/packages/runtime/src/durable-object.ts +1341 -0
  61. package/packages/runtime/src/index.ts +360 -0
  62. package/packages/runtime/src/navigation.test.ts +421 -0
  63. package/packages/runtime/src/navigation.ts +422 -0
  64. package/packages/runtime/src/nextjs-adapter.ts +272 -0
  65. package/packages/runtime/src/offline/encrypted-queue.test.ts +607 -0
  66. package/packages/runtime/src/offline/encrypted-queue.ts +478 -0
  67. package/packages/runtime/src/offline/encryption.test.ts +412 -0
  68. package/packages/runtime/src/offline/encryption.ts +397 -0
  69. package/packages/runtime/src/offline/types.ts +465 -0
  70. package/packages/runtime/src/predictor.ts +371 -0
  71. package/packages/runtime/src/registry.ts +351 -0
  72. package/packages/runtime/src/router/context-extractor.ts +661 -0
  73. package/packages/runtime/src/router/esi-control-react.tsx +2053 -0
  74. package/packages/runtime/src/router/esi-control.ts +541 -0
  75. package/packages/runtime/src/router/esi-cyrano.ts +779 -0
  76. package/packages/runtime/src/router/esi-format-react.tsx +1744 -0
  77. package/packages/runtime/src/router/esi-react.tsx +1065 -0
  78. package/packages/runtime/src/router/esi-translate-observer.ts +476 -0
  79. package/packages/runtime/src/router/esi-translate-react.tsx +556 -0
  80. package/packages/runtime/src/router/esi-translate.ts +503 -0
  81. package/packages/runtime/src/router/esi.ts +666 -0
  82. package/packages/runtime/src/router/heuristic-adapter.test.ts +295 -0
  83. package/packages/runtime/src/router/heuristic-adapter.ts +557 -0
  84. package/packages/runtime/src/router/index.ts +298 -0
  85. package/packages/runtime/src/router/merkle-capability.ts +473 -0
  86. package/packages/runtime/src/router/speculation.ts +451 -0
  87. package/packages/runtime/src/router/types.ts +630 -0
  88. package/packages/runtime/src/router.test.ts +470 -0
  89. package/packages/runtime/src/router.ts +302 -0
  90. package/packages/runtime/src/server.ts +481 -0
  91. package/packages/runtime/src/service-worker-push.ts +319 -0
  92. package/packages/runtime/src/service-worker.ts +553 -0
  93. package/packages/runtime/src/skeleton-hydrate.ts +237 -0
  94. package/packages/runtime/src/speculation.test.ts +389 -0
  95. package/packages/runtime/src/speculation.ts +486 -0
  96. package/packages/runtime/src/storage.test.ts +1297 -0
  97. package/packages/runtime/src/storage.ts +1048 -0
  98. package/packages/runtime/src/sync/conflict-resolver.test.ts +528 -0
  99. package/packages/runtime/src/sync/conflict-resolver.ts +565 -0
  100. package/packages/runtime/src/sync/coordinator.test.ts +608 -0
  101. package/packages/runtime/src/sync/coordinator.ts +596 -0
  102. package/packages/runtime/src/tree-compiler.ts +295 -0
  103. package/packages/runtime/src/types.ts +728 -0
  104. package/packages/runtime/src/worker.ts +327 -0
  105. package/packages/runtime/tsconfig.json +20 -0
  106. package/packages/runtime/wasm/aeon_pages_runtime.d.ts +504 -0
  107. package/packages/runtime/wasm/aeon_pages_runtime.js +1657 -0
  108. package/packages/runtime/wasm/aeon_pages_runtime_bg.wasm +0 -0
  109. package/packages/runtime/wasm/aeon_pages_runtime_bg.wasm.d.ts +196 -0
  110. package/packages/runtime/wasm/package.json +21 -0
  111. package/packages/runtime/wrangler.toml +41 -0
  112. package/packages/runtime-wasm/Cargo.lock +436 -0
  113. package/packages/runtime-wasm/Cargo.toml +29 -0
  114. package/packages/runtime-wasm/pkg/aeon_pages_runtime.d.ts +480 -0
  115. package/packages/runtime-wasm/pkg/aeon_pages_runtime.js +1568 -0
  116. package/packages/runtime-wasm/pkg/aeon_pages_runtime_bg.wasm +0 -0
  117. package/packages/runtime-wasm/pkg/aeon_pages_runtime_bg.wasm.d.ts +192 -0
  118. package/packages/runtime-wasm/pkg/package.json +21 -0
  119. package/packages/runtime-wasm/src/hydrate.rs +352 -0
  120. package/packages/runtime-wasm/src/lib.rs +191 -0
  121. package/packages/runtime-wasm/src/render.rs +629 -0
  122. package/packages/runtime-wasm/src/router.rs +298 -0
  123. package/packages/runtime-wasm/src/skeleton.rs +430 -0
  124. package/rfcs/RFC-001-ZERO-DEPENDENCY-RENDERING.md +1446 -0
package/README.md ADDED
@@ -0,0 +1,625 @@
1
+ # @affectively/aeon-flux
2
+
3
+ **The CMS IS the website.** Collaborative page framework with CRDT-based flux state and hyperpersonalized routing.
4
+
5
+ ```
6
+ 'use aeon'; // One directive enables everything
7
+ ```
8
+
9
+ ## What is Aeon Flux?
10
+
11
+ Aeon Flux is a lightweight, collaborative page framework that unifies:
12
+
13
+ - **CMS = Website** - No separate admin panel, edit in place
14
+ - **Editor = Viewer** - Click to edit, changes are live
15
+ - **Backend = Frontend** - One runtime, runs on edge
16
+ - **Pages from D1** - No file system, pure database
17
+ - **AI Everywhere** - Edge Side Inference (ESI) brings AI to any component
18
+
19
+ The name comes from:
20
+ 1. **Flux** - CRDT-based data model for conflict-free collaboration
21
+ 2. **Aeon Flux** - The classic anime (a syzygy of human and machine)
22
+
23
+ ## Key Features
24
+
25
+ | Feature | Description |
26
+ |---------|-------------|
27
+ | **Zero-Dependency Rendering** | Single HTML with inline CSS, assets, fonts |
28
+ | **Hyperpersonalized Routing** | The website comes to the person |
29
+ | **Edge Side Inference (ESI)** | AI inference at render time |
30
+ | **Pages from D1** | No file system in production |
31
+ | **~20KB WASM runtime** | vs 500KB+ Next.js |
32
+ | **Multi-layer caching** | KV (1ms) → D1 (5ms) → Session (50ms) |
33
+ | **Speculative pre-rendering** | Zero-latency navigation |
34
+ | **Built-in collaboration** | Real-time editing with presence |
35
+ | **GitHub PR Publishing** | Visual edits → TSX → Git → Deploy |
36
+ | **Lazy hydration** | Only hydrate interactive components on visibility |
37
+
38
+ ## Live Infrastructure
39
+
40
+ ```
41
+ https://aeon-flux.taylorbuley.workers.dev
42
+ ```
43
+
44
+ | Endpoint | Description |
45
+ |----------|-------------|
46
+ | `/health` | Health check |
47
+ | `/session/:id` | WebSocket for real-time collab |
48
+ | `/session/:id/session` | Session state (GET/PUT) |
49
+ | `/session/:id/presence` | Active users |
50
+ | `/routes` | Route registry |
51
+
52
+ ## Quick Start
53
+
54
+ ```bash
55
+ # Install
56
+ bun add @affectively/aeon-pages-runtime
57
+
58
+ # Or use the worker directly
59
+ curl https://aeon-flux.taylorbuley.workers.dev/health
60
+ ```
61
+
62
+ ## Hyperpersonalized Routing
63
+
64
+ **"The website comes to the person"** - Routes adapt based on user context.
65
+
66
+ ```typescript
67
+ import { HeuristicAdapter, extractUserContext } from '@affectively/aeon-pages-runtime';
68
+
69
+ const adapter = new HeuristicAdapter({
70
+ defaultPaths: ['/', '/chat', '/settings'],
71
+ signals: {
72
+ deriveTheme: (ctx) => ctx.localHour > 18 ? 'dark' : 'light',
73
+ deriveAccent: (ctx) => ctx.emotionState?.primary === 'happy' ? '#FFD700' : '#6366f1',
74
+ },
75
+ });
76
+
77
+ // Route decision includes personalization
78
+ const decision = await adapter.route('/dashboard', userContext, componentTree);
79
+ // { theme: 'dark', accent: '#FFD700', prefetch: ['/chat'], density: 'comfortable', ... }
80
+ ```
81
+
82
+ ### Performance
83
+
84
+ | Operation | 100 nodes | 500 nodes |
85
+ |-----------|-----------|-----------|
86
+ | `route()` | 0.014ms | 0.05ms |
87
+ | `speculate()` | 0.003ms | 0.007ms |
88
+ | `personalizeTree()` | 0.026ms | 0.109ms |
89
+
90
+ Sub-millisecond routing on every request.
91
+
92
+ ## Edge Side Inference (ESI)
93
+
94
+ Bring AI to any component at render time. Like Varnish ESI, but for inference.
95
+
96
+ ```tsx
97
+ import { ESI, ESIProvider } from '@affectively/aeon-pages-runtime/router';
98
+
99
+ // Basic inference
100
+ <ESI.Infer model="llm" cache={300}>
101
+ Summarize this page for {user.name}
102
+ </ESI.Infer>
103
+
104
+ // Structured output with Zod
105
+ <ESI.Structured schema={z.object({ sentiment: z.enum(['positive', 'negative']) })}>
106
+ Analyze: {userMessage}
107
+ </ESI.Structured>
108
+
109
+ // Conditional rendering
110
+ <ESI.If
111
+ prompt="Should we show a discount?"
112
+ schema={z.object({ show: z.boolean() })}
113
+ when={(r) => r.show}
114
+ >
115
+ <DiscountBanner />
116
+ </ESI.If>
117
+
118
+ // Presence-aware (adapts for multiple viewers)
119
+ <ESI.Collaborative schema={summarySchema}>
120
+ Summarize for {presence.length} viewers: {content}
121
+ </ESI.Collaborative>
122
+
123
+ // Self-optimizing (improves when user is alone)
124
+ <ESI.Optimize
125
+ schema={contentSchema}
126
+ maxIterations={3}
127
+ goal="Improve clarity and engagement"
128
+ >
129
+ {draftContent}
130
+ </ESI.Optimize>
131
+
132
+ // Format transformations - wrap any ESI output
133
+ <ESI.Markdown gfm>
134
+ <ESI.Infer>Generate API documentation</ESI.Infer>
135
+ </ESI.Markdown>
136
+
137
+ <ESI.Latex displayMode>
138
+ <ESI.Infer>Write the quadratic formula</ESI.Infer>
139
+ </ESI.Latex>
140
+
141
+ <ESI.Json indent={4} copyable>
142
+ <ESI.Structured schema={dataSchema}>Analyze this</ESI.Structured>
143
+ </ESI.Json>
144
+
145
+ // Text-to-code with coding models
146
+ <ESI.Code
147
+ generateFrom="A debounce utility function"
148
+ language="typescript"
149
+ model="codestral"
150
+ lineNumbers
151
+ copyable
152
+ />
153
+ ```
154
+
155
+ ### ESI Format Components
156
+
157
+ Transform inference output before rendering:
158
+
159
+ | Component | Purpose |
160
+ |-----------|---------|
161
+ | `ESI.Markdown` | Render markdown as HTML (GFM support) |
162
+ | `ESI.Latex` | Render LaTeX math expressions |
163
+ | `ESI.Json` | Pretty-print JSON with syntax highlighting |
164
+ | `ESI.Plaintext` | Plain text with whitespace control |
165
+ | `ESI.Code` | Code blocks with text-to-code generation |
166
+ | `ESI.Semantic` | Extract topics/entities → structured HTML/microdata |
167
+
168
+ ### ESI.Code with Coding Models
169
+
170
+ `ESI.Code` supports specialized coding models for text-to-code generation:
171
+
172
+ ```tsx
173
+ // Text-to-code: generate from natural language
174
+ <ESI.Code
175
+ generateFrom="A React hook that fetches user data with loading state"
176
+ language="typescript"
177
+ model="codestral"
178
+ lineNumbers
179
+ copyable
180
+ />
181
+
182
+ // Available models
183
+ type CodeModel =
184
+ | 'codestral' // Mistral Codestral (default)
185
+ | 'deepseek' // DeepSeek Coder
186
+ | 'starcoder' // StarCoder
187
+ | 'codellama' // Code Llama
188
+ | 'qwen-coder' // Qwen Coder
189
+ | 'claude' // Claude
190
+ | 'gpt-4'; // GPT-4
191
+
192
+ // Auto-detect language
193
+ <ESI.Code autoDetect model="deepseek">
194
+ {someCodeString}
195
+ </ESI.Code>
196
+ ```
197
+
198
+ ### ESI.Semantic - Embeddings to Structured HTML
199
+
200
+ Extract semantic topics, entities, and emotions → generate Schema.org microdata:
201
+
202
+ ```tsx
203
+ // Extract topics as JSON-LD structured data
204
+ <ESI.Semantic format="jsonld" schemaType="Article" extractEntities extractEmotion>
205
+ {articleText}
206
+ </ESI.Semantic>
207
+
208
+ // Display as interactive tags
209
+ <ESI.Semantic format="tags" maxTopics={5} extractEmotion>
210
+ <ESI.Infer>Summarize this news article</ESI.Infer>
211
+ </ESI.Semantic>
212
+
213
+ // Output formats: microdata | jsonld | rdfa | tags
214
+ // Uses: embed model (embeddings), classify model (entities), emotion model
215
+ ```
216
+
217
+ ## Zero-Dependency Rendering
218
+
219
+ Every page is a **completely self-contained HTML document**. No external requests needed.
220
+
221
+ ```
222
+ Single Request → Instant Render
223
+ ├── Inline CSS (tree-shaken, only used classes)
224
+ ├── Inline assets (SVG, images as data URIs)
225
+ ├── Inline fonts (@font-face with embedded data)
226
+ ├── Minimal hydration script (lazy, on visibility)
227
+ └── WASM-rendered at edge (~7ms total)
228
+ ```
229
+
230
+ ### Multi-Layer Caching
231
+
232
+ ```
233
+ Request → KV Cache (1ms) → D1 Cache (5ms) → Session Render (50ms)
234
+ ↓ ↓ ↓
235
+ Return HTML Cache to KV Cache to KV + D1
236
+ ```
237
+
238
+ All pages are pre-rendered at build time and cached. First request for any route is a cache hit.
239
+
240
+ ### Speculative Pre-Rendering
241
+
242
+ Pages are pre-rendered **before the user clicks**, based on:
243
+ - Link visibility (IntersectionObserver)
244
+ - Hover intent
245
+ - Navigation prediction (Markov chain, community patterns)
246
+ - Browser Speculation Rules API
247
+
248
+ ```typescript
249
+ import { initSpeculativeRendering } from '@affectively/aeon-pages-runtime';
250
+
251
+ // Enable instant navigation
252
+ initSpeculativeRendering({
253
+ maxCachedPages: 5,
254
+ prerenderOnHover: true,
255
+ });
256
+ ```
257
+
258
+ ### Performance
259
+
260
+ | Metric | Before | After |
261
+ |--------|--------|-------|
262
+ | Requests | 15-30 | 1 |
263
+ | Total bytes | ~655KB | ~110KB |
264
+ | TTFB | 100ms | 50ms |
265
+ | First Paint | 500ms | <100ms |
266
+ | Time to Interactive | 2000ms | <300ms |
267
+ | CLS | 0.05 | 0 |
268
+
269
+ ## GitHub PR Publishing
270
+
271
+ Visual edits compile to TSX and create PRs automatically.
272
+
273
+ ```
274
+ Edit in browser → Durable Object → "Publish" → TSX → PR → CI deploys
275
+ ```
276
+
277
+ ### WebSocket Commands
278
+
279
+ ```javascript
280
+ const ws = new WebSocket('wss://aeon-flux.taylorbuley.workers.dev/session/my-page?userId=user1');
281
+
282
+ // Publish current tree → creates PR
283
+ ws.send(JSON.stringify({ type: 'publish' }));
284
+ // Response: { type: 'publish', payload: { prNumber: 123, autoMerged: false } }
285
+
286
+ // Merge a PR
287
+ ws.send(JSON.stringify({ type: 'merge', payload: { prNumber: 123 } }));
288
+ ```
289
+
290
+ ### Generated TSX
291
+
292
+ ```tsx
293
+ 'use aeon';
294
+
295
+ /**
296
+ * AboutPage
297
+ * Route: /about
298
+ *
299
+ * @generated by aeon-flux visual editor
300
+ */
301
+
302
+ import type { FC } from 'react';
303
+ import { Hero } from '@/components/Hero';
304
+ import { Section } from '@/components/Section';
305
+
306
+ const AboutPage: FC = () => {
307
+ return (
308
+ <Page>
309
+ <Hero title="About Us" />
310
+ <Section>
311
+ <Text>We believe in...</Text>
312
+ </Section>
313
+ </Page>
314
+ );
315
+ };
316
+
317
+ export default AboutPage;
318
+ ```
319
+
320
+ ### Configuration
321
+
322
+ ```toml
323
+ # wrangler.toml
324
+ [vars]
325
+ GITHUB_REPO = "owner/repo"
326
+ GITHUB_TREE_PATH = "apps/web/pages"
327
+ GITHUB_BASE_BRANCH = "staging"
328
+ GITHUB_DEV_BRANCH = "development"
329
+ GITHUB_AUTO_MERGE = "false"
330
+ ```
331
+
332
+ ## Production Architecture
333
+
334
+ ```
335
+ ┌─────────────────────────────────────────────────────────────────────────┐
336
+ │ AEON FLUX ARCHITECTURE │
337
+ ├─────────────────────────────────────────────────────────────────────────┤
338
+ │ │
339
+ │ Request + User Context │
340
+ │ │ │
341
+ │ ▼ │
342
+ │ ┌──────────────────┐ ┌──────────────────┐ │
343
+ │ │ HeuristicAdapter │ │ ESI │ │
344
+ │ │ (personalize) │ │ (inference) │ │
345
+ │ └────────┬─────────┘ └────────┬─────────┘ │
346
+ │ │ │ │
347
+ │ ▼ ▼ │
348
+ │ ┌──────────────────────────────────────────────────┐ │
349
+ │ │ Durable Objects │ │
350
+ │ │ (sessions, presence, real-time sync) │ │
351
+ │ └──────────────────────────────────────────────────┘ │
352
+ │ │ │ │
353
+ │ ▼ ▼ │
354
+ │ ┌──────────────┐ ┌──────────────┐ │
355
+ │ │ D1 │ │ GitHub │ │
356
+ │ │ (storage) │ │ (publish) │ │
357
+ │ └──────────────┘ └──────────────┘ │
358
+ │ │
359
+ │ Edit visually → Sync via DO → Publish → TSX → PR → Deploy │
360
+ │ │
361
+ └─────────────────────────────────────────────────────────────────────────┘
362
+ ```
363
+
364
+ ## Local-First with Dash
365
+
366
+ Data lives client-side. No backend services needed.
367
+
368
+ ```typescript
369
+ import { DashStorageAdapter } from '@affectively/aeon-pages-runtime';
370
+
371
+ const storage = new DashStorageAdapter(dashClient, {
372
+ routesCollection: 'aeon-routes',
373
+ sessionsCollection: 'aeon-sessions',
374
+ });
375
+
376
+ // Reads: instant (local)
377
+ // Writes: instant (local), syncs via DO
378
+ // Collab: Durable Objects
379
+ // AI: ESI at edge
380
+ ```
381
+
382
+ ## Speculation & Prefetching
383
+
384
+ Predict and prefetch likely next pages.
385
+
386
+ ```typescript
387
+ import { SpeculationManager, createSpeculationHook } from '@affectively/aeon-pages-runtime/router';
388
+
389
+ // Client-side
390
+ const manager = new SpeculationManager({
391
+ maxPrefetch: 5,
392
+ hoverDelay: 100,
393
+ });
394
+
395
+ // Prefetch on hover
396
+ manager.observeLinks();
397
+
398
+ // Or use the hook
399
+ const useSpeculation = createSpeculationHook(manager);
400
+ ```
401
+
402
+ Supports [Speculation Rules API](https://developer.chrome.com/docs/web-platform/prerender-pages) with link prefetch fallback.
403
+
404
+ ## Zero-Instrumentation Analytics
405
+
406
+ Automatic click tracking with Merkle tree node identification. Every click tracked without writing a single line of instrumentation code.
407
+
408
+ ```typescript
409
+ import {
410
+ initClickTracker,
411
+ initContextBridgeWithRetry,
412
+ pushPageView,
413
+ } from '@affectively/aeon-pages-analytics';
414
+
415
+ // Initialize on client
416
+ initContextBridgeWithRetry({ maxRetries: 3, retryDelayMs: 500 });
417
+ initClickTracker({
418
+ debounceMs: 100,
419
+ maxTextLength: 150,
420
+ excludeSelectors: ['.no-track'],
421
+ });
422
+ pushPageView();
423
+ ```
424
+
425
+ ### What Gets Tracked
426
+
427
+ Every click automatically includes:
428
+
429
+ | Data | Description |
430
+ |------|-------------|
431
+ | **Merkle Hash** | Content-addressable ID (stable across renders) |
432
+ | **Tree Path** | `['root', 'layout', 'header', 'nav', 'button']` |
433
+ | **ESI Context** | User tier, emotion state, features, session |
434
+ | **Element Info** | Tag, text, aria-label, role, href |
435
+ | **Position** | Viewport and document coordinates |
436
+
437
+ ### DataLayer Events
438
+
439
+ ```javascript
440
+ // Click event pushed to dataLayer
441
+ {
442
+ event: 'aeon.click',
443
+ click: {
444
+ merkleHash: 'a1b2c3d4e5f6',
445
+ treePath: ['root', 'layout', 'header', 'settings-btn'],
446
+ element: { tagName: 'BUTTON', text: 'Settings' }
447
+ },
448
+ context: {
449
+ userTier: 'pro',
450
+ emotionState: { primary: 'focused', valence: 0.3 }
451
+ }
452
+ }
453
+ ```
454
+
455
+ Works with GTM + GA4 out of the box. Set `GTM_CONTAINER_ID` in your environment.
456
+
457
+ ## The `'use aeon'` Directive
458
+
459
+ ```tsx
460
+ 'use aeon';
461
+
462
+ export default function Page() {
463
+ const {
464
+ presence, // Who's viewing/editing
465
+ sync, // Sync state and controls
466
+ version, // Schema version info
467
+ data, // Collaborative data store
468
+ setData, // Update data
469
+ } = useAeonPage();
470
+
471
+ return <div>...</div>;
472
+ }
473
+ ```
474
+
475
+ ## Hooks
476
+
477
+ | Hook | Purpose |
478
+ |------|---------|
479
+ | `useAeonPage()` | Full page context |
480
+ | `usePresence()` | Who's here, cursors, editing |
481
+ | `useAeonData<T>(key)` | Collaborative typed data |
482
+ | `useCollaborativeInput(key)` | Ready-to-use collab input |
483
+ | `useOfflineStatus()` | Offline awareness |
484
+ | `useESI()` | ESI context |
485
+ | `useESIInfer()` | Programmatic inference |
486
+ | `useESITier()` | User tier for feature gating |
487
+ | `useESIEmotionState()` | Current emotional context |
488
+ | `useESIFeature(name)` | Check feature availability |
489
+ | `useIsAdmin()` | Check if user is admin |
490
+ | `useMeetsTierRequirement(tier)` | Check if user meets tier |
491
+ | `useGlobalESIState()` | Full ESI state object |
492
+
493
+ ## ESI Global State Injection
494
+
495
+ For zero-CLS tier-aware rendering, inject ESI state in the `<head>`:
496
+
497
+ ```html
498
+ <script>
499
+ window.__AEON_ESI_STATE__ = {
500
+ userTier: 'pro', // free | starter | pro | enterprise
501
+ emotionState: {
502
+ primary: 'focused',
503
+ valence: 0.3,
504
+ arousal: 0.6
505
+ },
506
+ preferences: {
507
+ theme: 'dark',
508
+ reducedMotion: false
509
+ },
510
+ sessionId: 'abc123',
511
+ localHour: 14,
512
+ timezone: 'America/New_York'
513
+ };
514
+ </script>
515
+ ```
516
+
517
+ Then use in components:
518
+
519
+ ```tsx
520
+ import { useESITier } from '@affectively/aeon-flux/esi';
521
+
522
+ function PremiumFeature() {
523
+ const tier = useESITier();
524
+
525
+ if (tier === 'free') {
526
+ return <UpgradePrompt />;
527
+ }
528
+
529
+ return <AdvancedAnalytics />;
530
+ }
531
+
532
+ ## Configuration
533
+
534
+ ```typescript
535
+ // aeon.config.ts
536
+ export default {
537
+ pagesDir: './pages',
538
+ runtime: 'cloudflare',
539
+
540
+ router: {
541
+ adapter: 'heuristic',
542
+ speculation: {
543
+ enabled: true,
544
+ depth: 2,
545
+ prerenderTop: 1,
546
+ },
547
+ personalization: {
548
+ featureGating: true,
549
+ emotionTheming: true,
550
+ componentOrdering: true,
551
+ },
552
+ },
553
+
554
+ esi: {
555
+ enabled: true,
556
+ endpoint: process.env.ESI_ENDPOINT,
557
+ timeout: 5000,
558
+ defaultCacheTtl: 300,
559
+ },
560
+
561
+ github: {
562
+ repo: 'owner/repo',
563
+ treePath: 'apps/web/pages',
564
+ baseBranch: 'staging',
565
+ devBranch: 'development',
566
+ autoMerge: false,
567
+ },
568
+ };
569
+ ```
570
+
571
+ ## Packages
572
+
573
+ | Package | Description |
574
+ |---------|-------------|
575
+ | `@affectively/aeon-flux` | Main package (npm) |
576
+ | `@affectively/aeon-flux/esi` | ESI hooks for tier gating |
577
+ | `@affectively/aeon-flux/react` | React bindings |
578
+ | `@affectively/aeon-flux/server` | Server utilities |
579
+ | `@affectively/aeon-pages-runtime` | Runtime (npm) |
580
+ | `@affectively/aeon-pages-runtime/router` | Personalized routing + ESI |
581
+ | `@affectively/aeon-pages-runtime/server` | Server utilities |
582
+ | `@affectively/aeon-pages-analytics` | Zero-instrumentation analytics with Merkle tree tracking |
583
+
584
+ ## Deploy Your Own
585
+
586
+ ```bash
587
+ cd packages/runtime
588
+
589
+ # Deploy worker
590
+ wrangler deploy
591
+
592
+ # Set GitHub token
593
+ wrangler secret put GITHUB_TOKEN
594
+
595
+ # Create D1 database (optional)
596
+ wrangler d1 create aeon-flux
597
+ wrangler d1 execute aeon-flux --file=./schema.sql
598
+ ```
599
+
600
+ ## vs Next.js
601
+
602
+ | | Next.js | Aeon Flux |
603
+ |-|---------|-----------|
604
+ | **Runtime** | ~500KB | ~187KB |
605
+ | **Routing** | Static | Personalized |
606
+ | **AI** | Add-on | ESI built-in |
607
+ | **CMS** | Separate | It IS the site |
608
+ | **Collaboration** | Add-on | Built-in |
609
+ | **Publish** | Manual | Visual → PR |
610
+ | **Edge** | Partial | Full |
611
+
612
+ ## Requirements
613
+
614
+ - Bun >= 1.0.0
615
+ - React >= 18.0.0
616
+ - Zod >= 3.0.0
617
+ - Cloudflare account (for production)
618
+
619
+ ## License
620
+
621
+ MIT
622
+
623
+ ---
624
+
625
+ *The CMS is the website. The website comes to the person. Visual edits become code.*
@@ -0,0 +1,39 @@
1
+ import type { AeonConfig } from '@affectively/aeon-pages';
2
+
3
+ export default {
4
+ pagesDir: './pages',
5
+ componentsDir: './components',
6
+ runtime: 'bun',
7
+ port: 3000,
8
+
9
+ aeon: {
10
+ sync: {
11
+ mode: 'distributed',
12
+ replicationFactor: 3,
13
+ consistencyLevel: 'strong',
14
+ },
15
+ versioning: {
16
+ enabled: true,
17
+ autoMigrate: true,
18
+ },
19
+ presence: {
20
+ enabled: true,
21
+ cursorTracking: true,
22
+ inactivityTimeout: 60000,
23
+ },
24
+ offline: {
25
+ enabled: true,
26
+ maxQueueSize: 1000,
27
+ },
28
+ },
29
+
30
+ components: {
31
+ autoDiscover: true,
32
+ },
33
+
34
+ nextCompat: true,
35
+
36
+ output: {
37
+ dir: '.aeon',
38
+ },
39
+ } satisfies AeonConfig;