@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
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Tree → TSX Compiler
3
+ *
4
+ * Converts component trees from the visual editor back to TSX source code.
5
+ */
6
+
7
+ interface TreeNode {
8
+ id: string;
9
+ type: string;
10
+ props?: Record<string, unknown>;
11
+ children?: string[] | TreeNode[];
12
+ text?: string;
13
+ }
14
+
15
+ interface CompilerOptions {
16
+ /** Route path for the page */
17
+ route: string;
18
+ /** Include 'use aeon' directive */
19
+ useAeon?: boolean;
20
+ /** Component imports to add */
21
+ imports?: Record<string, string>; // { 'Hero': '@/components/Hero' }
22
+ /** Whether to format output */
23
+ format?: boolean;
24
+ }
25
+
26
+ /**
27
+ * Compile a tree to TSX source code
28
+ */
29
+ export function compileTreeToTSX(
30
+ tree: TreeNode | TreeNode[],
31
+ options: CompilerOptions,
32
+ ): string {
33
+ const { route, useAeon = true, imports = {}, format = true } = options;
34
+
35
+ // Collect all component types used
36
+ const usedComponents = new Set<string>();
37
+ collectComponents(tree, usedComponents);
38
+
39
+ // Build imports
40
+ const importLines: string[] = [];
41
+
42
+ // React import (if needed)
43
+ importLines.push("import type { FC } from 'react';");
44
+
45
+ // Component imports
46
+ for (const component of usedComponents) {
47
+ if (imports[component]) {
48
+ importLines.push(`import { ${component} } from '${imports[component]}';`);
49
+ } else if (!isHTMLElement(component)) {
50
+ // Default import path for unknown components
51
+ importLines.push(
52
+ `import { ${component} } from '@/components/${component}';`,
53
+ );
54
+ }
55
+ }
56
+
57
+ // Generate component name from route
58
+ const componentName = routeToComponentName(route);
59
+
60
+ // Generate JSX
61
+ const jsx = nodeToJSX(tree, 2);
62
+
63
+ // Assemble the file
64
+ const lines: string[] = [];
65
+
66
+ if (useAeon) {
67
+ lines.push("'use aeon';");
68
+ lines.push('');
69
+ }
70
+
71
+ lines.push('/**');
72
+ lines.push(` * ${componentName}`);
73
+ lines.push(` * Route: ${route}`);
74
+ lines.push(' * ');
75
+ lines.push(' * @generated by aeon-flux visual editor');
76
+ lines.push(' */');
77
+ lines.push('');
78
+
79
+ lines.push(...importLines);
80
+ lines.push('');
81
+
82
+ lines.push(`const ${componentName}: FC = () => {`);
83
+ lines.push(' return (');
84
+ lines.push(jsx);
85
+ lines.push(' );');
86
+ lines.push('};');
87
+ lines.push('');
88
+ lines.push(`export default ${componentName};`);
89
+ lines.push('');
90
+
91
+ return lines.join('\n');
92
+ }
93
+
94
+ /**
95
+ * Collect all component types used in the tree
96
+ */
97
+ function collectComponents(
98
+ node: TreeNode | TreeNode[],
99
+ set: Set<string>,
100
+ ): void {
101
+ if (Array.isArray(node)) {
102
+ node.forEach((n) => collectComponents(n, set));
103
+ return;
104
+ }
105
+
106
+ if (node.type && !isHTMLElement(node.type)) {
107
+ set.add(node.type);
108
+ }
109
+
110
+ if (node.children) {
111
+ if (Array.isArray(node.children)) {
112
+ node.children.forEach((child) => {
113
+ if (typeof child === 'object') {
114
+ collectComponents(child, set);
115
+ }
116
+ });
117
+ }
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Convert a tree node to JSX string
123
+ */
124
+ function nodeToJSX(node: TreeNode | TreeNode[], indent: number = 0): string {
125
+ const spaces = ' '.repeat(indent);
126
+
127
+ if (Array.isArray(node)) {
128
+ if (node.length === 0) return `${spaces}{null}`;
129
+ if (node.length === 1) return nodeToJSX(node[0], indent);
130
+ return `${spaces}<>\n${node.map((n) => nodeToJSX(n, indent + 1)).join('\n')}\n${spaces}</>`;
131
+ }
132
+
133
+ const { type, props = {}, children, text } = node;
134
+
135
+ // Text node
136
+ if (type === 'text' || text) {
137
+ const content = text || props.content || props.text || '';
138
+ return `${spaces}${escapeJSX(String(content))}`;
139
+ }
140
+
141
+ // Component/element name
142
+ const tagName = isHTMLElement(type) ? type.toLowerCase() : type;
143
+
144
+ // Props string
145
+ const propsStr = propsToString(props);
146
+
147
+ // No children - self-closing
148
+ if (!children || (Array.isArray(children) && children.length === 0)) {
149
+ return `${spaces}<${tagName}${propsStr} />`;
150
+ }
151
+
152
+ // With children
153
+ const childrenJSX = Array.isArray(children)
154
+ ? children
155
+ .map((child) => {
156
+ if (typeof child === 'string') {
157
+ return `${spaces} ${escapeJSX(child)}`;
158
+ }
159
+ return nodeToJSX(child, indent + 1);
160
+ })
161
+ .join('\n')
162
+ : `${spaces} ${escapeJSX(String(children))}`;
163
+
164
+ return `${spaces}<${tagName}${propsStr}>\n${childrenJSX}\n${spaces}</${tagName}>`;
165
+ }
166
+
167
+ /**
168
+ * Convert props object to JSX props string
169
+ */
170
+ function propsToString(props: Record<string, unknown>): string {
171
+ const entries = Object.entries(props).filter(
172
+ ([key]) => !['children', 'id', 'text', 'content'].includes(key),
173
+ );
174
+
175
+ if (entries.length === 0) return '';
176
+
177
+ const propsArr = entries
178
+ .map(([key, value]) => {
179
+ // Handle different value types
180
+ if (typeof value === 'string') {
181
+ return `${key}="${escapeAttr(value)}"`;
182
+ }
183
+ if (typeof value === 'boolean') {
184
+ return value ? key : `${key}={false}`;
185
+ }
186
+ if (typeof value === 'number') {
187
+ return `${key}={${value}}`;
188
+ }
189
+ if (value === null || value === undefined) {
190
+ return null;
191
+ }
192
+ // Objects/arrays as JSX expressions
193
+ return `${key}={${JSON.stringify(value)}}`;
194
+ })
195
+ .filter(Boolean);
196
+
197
+ return propsArr.length > 0 ? ' ' + propsArr.join(' ') : '';
198
+ }
199
+
200
+ /**
201
+ * Convert route to component name
202
+ */
203
+ function routeToComponentName(route: string): string {
204
+ if (route === '/' || route === '') return 'IndexPage';
205
+
206
+ const parts = route
207
+ .replace(/^\/|\/$/g, '')
208
+ .split('/')
209
+ .map((part) => {
210
+ // Handle dynamic segments
211
+ if (part.startsWith('[') && part.endsWith(']')) {
212
+ return 'Dynamic' + capitalize(part.slice(1, -1));
213
+ }
214
+ return capitalize(part);
215
+ });
216
+
217
+ return parts.join('') + 'Page';
218
+ }
219
+
220
+ /**
221
+ * Check if a type is an HTML element
222
+ */
223
+ function isHTMLElement(type: string): boolean {
224
+ const htmlElements = [
225
+ 'div',
226
+ 'span',
227
+ 'p',
228
+ 'a',
229
+ 'button',
230
+ 'input',
231
+ 'form',
232
+ 'h1',
233
+ 'h2',
234
+ 'h3',
235
+ 'h4',
236
+ 'h5',
237
+ 'h6',
238
+ 'ul',
239
+ 'ol',
240
+ 'li',
241
+ 'nav',
242
+ 'header',
243
+ 'footer',
244
+ 'main',
245
+ 'section',
246
+ 'article',
247
+ 'aside',
248
+ 'img',
249
+ 'video',
250
+ 'audio',
251
+ 'canvas',
252
+ 'svg',
253
+ 'table',
254
+ 'thead',
255
+ 'tbody',
256
+ 'tr',
257
+ 'td',
258
+ 'th',
259
+ 'label',
260
+ 'select',
261
+ 'option',
262
+ 'textarea',
263
+ 'strong',
264
+ 'em',
265
+ 'code',
266
+ 'pre',
267
+ 'blockquote',
268
+ ];
269
+ return htmlElements.includes(type.toLowerCase());
270
+ }
271
+
272
+ /**
273
+ * Capitalize first letter
274
+ */
275
+ function capitalize(str: string): string {
276
+ return str.charAt(0).toUpperCase() + str.slice(1);
277
+ }
278
+
279
+ /**
280
+ * Escape string for JSX content
281
+ */
282
+ function escapeJSX(str: string): string {
283
+ return str
284
+ .replace(/\{/g, '&#123;')
285
+ .replace(/\}/g, '&#125;')
286
+ .replace(/</g, '&lt;')
287
+ .replace(/>/g, '&gt;');
288
+ }
289
+
290
+ /**
291
+ * Escape string for JSX attribute
292
+ */
293
+ function escapeAttr(str: string): string {
294
+ return str.replace(/"/g, '&quot;').replace(/'/g, '&#39;');
295
+ }