@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,300 @@
1
+ /**
2
+ * Aeon Analytics Provider
3
+ *
4
+ * React context provider for analytics configuration.
5
+ * Wraps useAeonAnalytics in a provider pattern for easier usage.
6
+ */
7
+
8
+ import React, { createContext, useContext, useMemo } from 'react';
9
+ import type { AnalyticsConfig, MerkleTree } from './types';
10
+ import { useAeonAnalytics, type UseAnalyticsReturn } from './use-analytics';
11
+
12
+ // ============================================================================
13
+ // Context
14
+ // ============================================================================
15
+
16
+ interface AnalyticsContextValue extends UseAnalyticsReturn {
17
+ config: AnalyticsConfig;
18
+ }
19
+
20
+ const AnalyticsContext = createContext<AnalyticsContextValue | null>(null);
21
+
22
+ // ============================================================================
23
+ // Provider Props
24
+ // ============================================================================
25
+
26
+ export interface AeonAnalyticsProviderProps extends AnalyticsConfig {
27
+ children: React.ReactNode;
28
+ }
29
+
30
+ // ============================================================================
31
+ // Provider Component
32
+ // ============================================================================
33
+
34
+ /**
35
+ * Aeon Analytics Provider
36
+ *
37
+ * Wrap your app with this provider to enable automatic click tracking.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * import { AeonAnalyticsProvider } from '@affectively/aeon-pages-analytics/react';
42
+ *
43
+ * export default function App({ Component, pageProps }) {
44
+ * return (
45
+ * <AeonAnalyticsProvider
46
+ * gtmContainerId="GTM-XXXXXX"
47
+ * trackClicks={true}
48
+ * syncESIContext={true}
49
+ * >
50
+ * <Component {...pageProps} />
51
+ * </AeonAnalyticsProvider>
52
+ * );
53
+ * }
54
+ * ```
55
+ */
56
+ export function AeonAnalyticsProvider({
57
+ children,
58
+ ...config
59
+ }: AeonAnalyticsProviderProps): React.JSX.Element {
60
+ // Initialize analytics
61
+ const analytics = useAeonAnalytics(config);
62
+
63
+ // Memoize context value
64
+ const contextValue = useMemo<AnalyticsContextValue>(
65
+ () => ({
66
+ ...analytics,
67
+ config,
68
+ }),
69
+ [
70
+ analytics.isInitialized,
71
+ analytics.isGTMReady,
72
+ config.gtmContainerId,
73
+ config.trackClicks,
74
+ config.trackPageViews,
75
+ config.syncESIContext,
76
+ ],
77
+ );
78
+
79
+ return (
80
+ <AnalyticsContext.Provider value={contextValue}>
81
+ {children}
82
+ </AnalyticsContext.Provider>
83
+ );
84
+ }
85
+
86
+ // ============================================================================
87
+ // Hook to use Analytics Context
88
+ // ============================================================================
89
+
90
+ /**
91
+ * Use analytics context in a component
92
+ *
93
+ * @example
94
+ * ```tsx
95
+ * function MyComponent() {
96
+ * const { trackClick, trackInteraction } = useAnalytics();
97
+ *
98
+ * return (
99
+ * <button onClick={(e) => trackInteraction('custom_action', { value: 123 })}>
100
+ * Track Me
101
+ * </button>
102
+ * );
103
+ * }
104
+ * ```
105
+ */
106
+ export function useAnalytics(): AnalyticsContextValue {
107
+ const context = useContext(AnalyticsContext);
108
+
109
+ if (!context) {
110
+ throw new Error(
111
+ 'useAnalytics must be used within an AeonAnalyticsProvider. ' +
112
+ 'Wrap your app with <AeonAnalyticsProvider gtmContainerId="GTM-XXXXXX">.',
113
+ );
114
+ }
115
+
116
+ return context;
117
+ }
118
+
119
+ /**
120
+ * Optional analytics context (returns null if not in provider)
121
+ */
122
+ export function useAnalyticsOptional(): AnalyticsContextValue | null {
123
+ return useContext(AnalyticsContext);
124
+ }
125
+
126
+ // ============================================================================
127
+ // Higher-Order Component
128
+ // ============================================================================
129
+
130
+ /**
131
+ * HOC to inject analytics props into a component
132
+ */
133
+ export function withAnalytics<P extends object>(
134
+ Component: React.ComponentType<P & { analytics: AnalyticsContextValue }>,
135
+ ): React.FC<P> {
136
+ return function WrappedComponent(props: P) {
137
+ const analytics = useAnalytics();
138
+ return <Component {...props} analytics={analytics} />;
139
+ };
140
+ }
141
+
142
+ // ============================================================================
143
+ // Render Props Component
144
+ // ============================================================================
145
+
146
+ interface AnalyticsRenderProps {
147
+ children: (analytics: AnalyticsContextValue) => React.ReactNode;
148
+ }
149
+
150
+ /**
151
+ * Render props component for analytics
152
+ *
153
+ * @example
154
+ * ```tsx
155
+ * <Analytics>
156
+ * {({ trackInteraction }) => (
157
+ * <button onClick={() => trackInteraction('click', {})}>
158
+ * Click me
159
+ * </button>
160
+ * )}
161
+ * </Analytics>
162
+ * ```
163
+ */
164
+ export function Analytics({ children }: AnalyticsRenderProps): React.ReactNode {
165
+ const analytics = useAnalytics();
166
+ return children(analytics);
167
+ }
168
+
169
+ // ============================================================================
170
+ // Merkle Tree Provider
171
+ // ============================================================================
172
+
173
+ interface MerkleTreeProviderProps {
174
+ tree: MerkleTree;
175
+ children: React.ReactNode;
176
+ }
177
+
178
+ /**
179
+ * Provide Merkle tree for current page
180
+ *
181
+ * Use this when you have a Merkle tree from SSR/build time.
182
+ */
183
+ export function MerkleTreeProvider({
184
+ tree,
185
+ children,
186
+ }: MerkleTreeProviderProps): React.JSX.Element {
187
+ const analytics = useAnalyticsOptional();
188
+
189
+ // Set Merkle tree on mount
190
+ React.useEffect(() => {
191
+ if (analytics) {
192
+ analytics.setMerkleTree(tree);
193
+ } else {
194
+ // No provider, set directly on window
195
+ window.__AEON_MERKLE_TREE__ = tree;
196
+ }
197
+ }, [tree, analytics]);
198
+
199
+ return <>{children}</>;
200
+ }
201
+
202
+ // ============================================================================
203
+ // Track Component
204
+ // ============================================================================
205
+
206
+ interface TrackProps {
207
+ /** Tracking event name */
208
+ event: string;
209
+ /** Additional data to track */
210
+ data?: Record<string, unknown>;
211
+ /** Track on mount */
212
+ onMount?: boolean;
213
+ /** Track on click */
214
+ onClick?: boolean;
215
+ /** Track on visibility */
216
+ onVisible?: boolean;
217
+ /** Children to render */
218
+ children: React.ReactElement;
219
+ }
220
+
221
+ /**
222
+ * Wrapper component that automatically tracks events
223
+ *
224
+ * @example
225
+ * ```tsx
226
+ * <Track event="cta_view" onVisible data={{ variant: 'A' }}>
227
+ * <button>Sign Up</button>
228
+ * </Track>
229
+ * ```
230
+ */
231
+ export function Track({
232
+ event,
233
+ data = {},
234
+ onMount = false,
235
+ onClick = false,
236
+ onVisible = false,
237
+ children,
238
+ }: TrackProps): React.ReactElement {
239
+ const analytics = useAnalyticsOptional();
240
+ const ref = React.useRef<HTMLElement>(null);
241
+ const hasTrackedVisibility = React.useRef(false);
242
+
243
+ // Track on mount
244
+ React.useEffect(() => {
245
+ if (onMount && analytics) {
246
+ analytics.trackInteraction(event, { ...data, trigger: 'mount' });
247
+ }
248
+ }, [onMount, event]);
249
+
250
+ // Track on visibility
251
+ React.useEffect(() => {
252
+ if (!onVisible || !analytics || hasTrackedVisibility.current) {
253
+ return;
254
+ }
255
+
256
+ const element = ref.current;
257
+ if (!element) return;
258
+
259
+ const observer = new IntersectionObserver(
260
+ (entries) => {
261
+ for (const entry of entries) {
262
+ if (entry.isIntersecting && !hasTrackedVisibility.current) {
263
+ hasTrackedVisibility.current = true;
264
+ analytics.trackInteraction(
265
+ event,
266
+ { ...data, trigger: 'visible' },
267
+ element,
268
+ );
269
+ observer.disconnect();
270
+ }
271
+ }
272
+ },
273
+ { threshold: 0.5 },
274
+ );
275
+
276
+ observer.observe(element);
277
+
278
+ return () => observer.disconnect();
279
+ }, [onVisible, event, analytics]);
280
+
281
+ // Clone child with click handler
282
+ if (onClick && analytics) {
283
+ return React.cloneElement(children, {
284
+ ref,
285
+ onClick: (e: React.MouseEvent<HTMLElement>) => {
286
+ analytics.trackInteraction(
287
+ event,
288
+ { ...data, trigger: 'click' },
289
+ e.currentTarget,
290
+ );
291
+ // Call original onClick if exists
292
+ if (children.props.onClick) {
293
+ children.props.onClick(e);
294
+ }
295
+ },
296
+ });
297
+ }
298
+
299
+ return React.cloneElement(children, { ref });
300
+ }
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Aeon Analytics Types
3
+ *
4
+ * TypeScript interfaces for automatic click tracking, GTM integration,
5
+ * and Merkle tree-based node identification.
6
+ */
7
+
8
+ // ============================================================================
9
+ // GTM Configuration
10
+ // ============================================================================
11
+
12
+ export interface GTMConfig {
13
+ /** GTM Container ID (e.g., 'GTM-XXXXXX') */
14
+ containerId: string;
15
+
16
+ /** Defer script loading (default: true) */
17
+ defer?: boolean;
18
+
19
+ /** Custom dataLayer name (default: 'dataLayer') */
20
+ dataLayerName?: string;
21
+ }
22
+
23
+ // ============================================================================
24
+ // Analytics Configuration
25
+ // ============================================================================
26
+
27
+ export interface ClickTrackingOptions {
28
+ /** Debounce rapid clicks in milliseconds (default: 0) */
29
+ debounceMs?: number;
30
+
31
+ /** Max text length to capture (default: 100) */
32
+ maxTextLength?: number;
33
+
34
+ /** CSS selectors to exclude from tracking */
35
+ excludeSelectors?: string[];
36
+
37
+ /** Include click position data (default: true) */
38
+ includePosition?: boolean;
39
+
40
+ /** Include full tree path (default: true) */
41
+ includeTreePath?: boolean;
42
+ }
43
+
44
+ export interface AnalyticsConfig {
45
+ /** Required: GTM container ID */
46
+ gtmContainerId: string;
47
+
48
+ /** Enable click tracking (default: true) */
49
+ trackClicks?: boolean;
50
+
51
+ /** Enable page view tracking (default: true) */
52
+ trackPageViews?: boolean;
53
+
54
+ /** Sync ESI context to dataLayer (default: true) */
55
+ syncESIContext?: boolean;
56
+
57
+ /** Click tracking options */
58
+ clickOptions?: ClickTrackingOptions;
59
+
60
+ /** Custom dataLayer name (default: 'dataLayer') */
61
+ dataLayerName?: string;
62
+
63
+ /** Event name prefix (default: 'aeon') */
64
+ eventPrefix?: string;
65
+
66
+ /** Enable debug logging (default: false) */
67
+ debug?: boolean;
68
+ }
69
+
70
+ // ============================================================================
71
+ // Merkle Tree Types
72
+ // ============================================================================
73
+
74
+ export interface MerkleNode {
75
+ /** SHA-256 hash truncated to 12 characters */
76
+ hash: string;
77
+
78
+ /** Original node ID from ComponentTree */
79
+ originalId: string;
80
+
81
+ /** Component type name */
82
+ type: string;
83
+
84
+ /** Component props (sanitized for hashing) */
85
+ props: Record<string, unknown>;
86
+
87
+ /** Child Merkle hashes */
88
+ childHashes: string[];
89
+
90
+ /** Ancestry path from root (node types) */
91
+ path: string[];
92
+
93
+ /** Ancestry path hashes */
94
+ pathHashes: string[];
95
+
96
+ /** Depth in tree (0 = root) */
97
+ depth: number;
98
+ }
99
+
100
+ export interface MerkleTree {
101
+ /** Root hash of the entire tree */
102
+ rootHash: string;
103
+
104
+ /** Map of original node ID to MerkleNode */
105
+ nodes: Map<string, MerkleNode>;
106
+
107
+ /** Get MerkleNode by original ID */
108
+ getNode(id: string): MerkleNode | undefined;
109
+
110
+ /** Get MerkleNode by hash */
111
+ getNodeByHash(hash: string): MerkleNode | undefined;
112
+
113
+ /** Get all nodes at a depth level */
114
+ getNodesAtDepth(depth: number): MerkleNode[];
115
+ }
116
+
117
+ // ============================================================================
118
+ // DOM Attributes
119
+ // ============================================================================
120
+
121
+ /** Data attribute for Merkle hash */
122
+ export const MERKLE_ATTR = 'data-aeon-merkle';
123
+
124
+ /** Data attribute for tree path */
125
+ export const PATH_ATTR = 'data-aeon-path';
126
+
127
+ /** Data attribute for tree path hashes */
128
+ export const PATH_HASHES_ATTR = 'data-aeon-path-hashes';
129
+
130
+ /** Data attribute for node type */
131
+ export const TYPE_ATTR = 'data-aeon-type';
132
+
133
+ // ============================================================================
134
+ // ESI State Types (mirrored from runtime for standalone usage)
135
+ // ============================================================================
136
+
137
+ export type UserTier = 'free' | 'starter' | 'pro' | 'enterprise' | 'admin';
138
+ export type ConnectionType = 'slow-2g' | '2g' | '3g' | '4g' | 'fast';
139
+
140
+ export interface EmotionState {
141
+ primary: string;
142
+ valence: number;
143
+ arousal: number;
144
+ confidence?: number;
145
+ }
146
+
147
+ export interface ESIStateFeatures {
148
+ aiInference: boolean;
149
+ emotionTracking: boolean;
150
+ collaboration: boolean;
151
+ advancedInsights: boolean;
152
+ customThemes: boolean;
153
+ voiceSynthesis: boolean;
154
+ imageAnalysis: boolean;
155
+ }
156
+
157
+ export interface ESIState {
158
+ userTier: UserTier;
159
+ /** Admin flag - bypasses all tier restrictions */
160
+ isAdmin?: boolean;
161
+ emotionState?: EmotionState;
162
+ preferences: {
163
+ theme?: 'light' | 'dark' | 'auto';
164
+ reducedMotion: boolean;
165
+ language?: string;
166
+ };
167
+ sessionId?: string;
168
+ localHour: number;
169
+ timezone: string;
170
+ features: ESIStateFeatures;
171
+ userId?: string;
172
+ isNewSession: boolean;
173
+ recentPages: string[];
174
+ viewport: { width: number; height: number };
175
+ connection: ConnectionType;
176
+ }
177
+
178
+ // ============================================================================
179
+ // DataLayer Event Types
180
+ // ============================================================================
181
+
182
+ export interface AeonEventBase {
183
+ event: string;
184
+ aeon: {
185
+ version: string;
186
+ timestamp: number;
187
+ };
188
+ }
189
+
190
+ export interface ElementInfo {
191
+ tagName: string;
192
+ text: string;
193
+ ariaLabel?: string;
194
+ role?: string;
195
+ href?: string;
196
+ id?: string;
197
+ className?: string;
198
+ }
199
+
200
+ export interface PositionInfo {
201
+ x: number;
202
+ y: number;
203
+ viewportX: number;
204
+ viewportY: number;
205
+ }
206
+
207
+ export interface ContextEvent extends AeonEventBase {
208
+ event: 'aeon.context';
209
+ user: {
210
+ tier: UserTier;
211
+ id?: string;
212
+ sessionId?: string;
213
+ isNewSession: boolean;
214
+ };
215
+ emotion?: EmotionState;
216
+ preferences: {
217
+ theme?: 'light' | 'dark' | 'auto';
218
+ reducedMotion: boolean;
219
+ language?: string;
220
+ };
221
+ features: ESIStateFeatures;
222
+ device: {
223
+ viewport: { width: number; height: number };
224
+ connection: ConnectionType;
225
+ };
226
+ time: {
227
+ localHour: number;
228
+ timezone: string;
229
+ };
230
+ recentPages: string[];
231
+ }
232
+
233
+ export interface PageViewEvent extends AeonEventBase {
234
+ event: 'aeon.pageview';
235
+ page: {
236
+ path: string;
237
+ title: string;
238
+ merkleRoot: string;
239
+ };
240
+ user: {
241
+ tier: UserTier;
242
+ id?: string;
243
+ sessionId?: string;
244
+ isNewSession: boolean;
245
+ };
246
+ emotion?: EmotionState;
247
+ features: ESIStateFeatures;
248
+ device: {
249
+ viewport: { width: number; height: number };
250
+ connection: ConnectionType;
251
+ reducedMotion: boolean;
252
+ };
253
+ time: {
254
+ localHour: number;
255
+ timezone: string;
256
+ };
257
+ }
258
+
259
+ export interface ClickEvent extends AeonEventBase {
260
+ event: 'aeon.click';
261
+ click: {
262
+ merkleHash: string;
263
+ treePath: string[];
264
+ treePathHashes: string[];
265
+ element: ElementInfo;
266
+ position: PositionInfo;
267
+ };
268
+ context: Partial<ESIState>;
269
+ }
270
+
271
+ export type DataLayerEvent = ContextEvent | PageViewEvent | ClickEvent;
272
+
273
+ // ============================================================================
274
+ // Window Extensions
275
+ // ============================================================================
276
+
277
+ declare global {
278
+ interface Window {
279
+ __AEON_ESI_STATE__?: ESIState & {
280
+ update?: (partial: Partial<ESIState>) => void;
281
+ subscribe?: (listener: (state: ESIState) => void) => () => void;
282
+ };
283
+ dataLayer?: unknown[];
284
+ __AEON_MERKLE_TREE__?: MerkleTree;
285
+ __AEON_ANALYTICS_INITIALIZED__?: boolean;
286
+ }
287
+ }
288
+
289
+ // ============================================================================
290
+ // Component Tree Types (for build-time integration)
291
+ // ============================================================================
292
+
293
+ export interface ComponentNode {
294
+ id: string;
295
+ type: string;
296
+ props?: Record<string, unknown>;
297
+ children?: string[];
298
+ requiredTier?: UserTier;
299
+ relevanceSignals?: string[];
300
+ defaultHidden?: boolean;
301
+ }
302
+
303
+ export interface ComponentTree {
304
+ rootId: string;
305
+ nodes: Map<string, ComponentNode>;
306
+ getNode(id: string): ComponentNode | undefined;
307
+ getChildren(id: string): ComponentNode[];
308
+ }
309
+
310
+ // ============================================================================
311
+ // Serialized Types (for data attributes)
312
+ // ============================================================================
313
+
314
+ export interface SerializedMerkleInfo {
315
+ hash: string;
316
+ path: string[];
317
+ pathHashes: string[];
318
+ type: string;
319
+ depth: number;
320
+ }