@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.
- package/CHANGELOG.md +112 -0
- package/README.md +625 -0
- package/examples/basic/aeon.config.ts +39 -0
- package/examples/basic/components/Cursor.tsx +86 -0
- package/examples/basic/components/OfflineIndicator.tsx +103 -0
- package/examples/basic/components/PresenceBar.tsx +77 -0
- package/examples/basic/package.json +20 -0
- package/examples/basic/pages/index.tsx +80 -0
- package/package.json +101 -0
- package/packages/analytics/README.md +309 -0
- package/packages/analytics/build.ts +35 -0
- package/packages/analytics/package.json +50 -0
- package/packages/analytics/src/click-tracker.ts +368 -0
- package/packages/analytics/src/context-bridge.ts +319 -0
- package/packages/analytics/src/data-layer.ts +302 -0
- package/packages/analytics/src/gtm-loader.ts +239 -0
- package/packages/analytics/src/index.ts +230 -0
- package/packages/analytics/src/merkle-tree.ts +489 -0
- package/packages/analytics/src/provider.tsx +300 -0
- package/packages/analytics/src/types.ts +320 -0
- package/packages/analytics/src/use-analytics.ts +296 -0
- package/packages/analytics/tsconfig.json +19 -0
- package/packages/benchmarks/src/benchmark.test.ts +691 -0
- package/packages/cli/dist/index.js +61899 -0
- package/packages/cli/package.json +43 -0
- package/packages/cli/src/commands/build.test.ts +682 -0
- package/packages/cli/src/commands/build.ts +890 -0
- package/packages/cli/src/commands/dev.ts +473 -0
- package/packages/cli/src/commands/init.ts +409 -0
- package/packages/cli/src/commands/start.ts +297 -0
- package/packages/cli/src/index.ts +105 -0
- package/packages/directives/src/use-aeon.ts +272 -0
- package/packages/mcp-server/package.json +51 -0
- package/packages/mcp-server/src/index.ts +178 -0
- package/packages/mcp-server/src/resources.ts +346 -0
- package/packages/mcp-server/src/tools/index.ts +36 -0
- package/packages/mcp-server/src/tools/navigation.ts +545 -0
- package/packages/mcp-server/tsconfig.json +21 -0
- package/packages/react/package.json +40 -0
- package/packages/react/src/Link.tsx +388 -0
- package/packages/react/src/components/InstallPrompt.tsx +286 -0
- package/packages/react/src/components/OfflineDiagnostics.tsx +677 -0
- package/packages/react/src/components/PushNotifications.tsx +453 -0
- package/packages/react/src/hooks/useAeonNavigation.ts +219 -0
- package/packages/react/src/hooks/useConflicts.ts +277 -0
- package/packages/react/src/hooks/useNetworkState.ts +209 -0
- package/packages/react/src/hooks/usePilotNavigation.ts +254 -0
- package/packages/react/src/hooks/useServiceWorker.ts +278 -0
- package/packages/react/src/hooks.ts +195 -0
- package/packages/react/src/index.ts +151 -0
- package/packages/react/src/provider.tsx +467 -0
- package/packages/react/tsconfig.json +19 -0
- package/packages/runtime/README.md +399 -0
- package/packages/runtime/build.ts +48 -0
- package/packages/runtime/package.json +71 -0
- package/packages/runtime/schema.sql +40 -0
- package/packages/runtime/src/api-routes.ts +465 -0
- package/packages/runtime/src/benchmark.ts +171 -0
- package/packages/runtime/src/cache.ts +479 -0
- package/packages/runtime/src/durable-object.ts +1341 -0
- package/packages/runtime/src/index.ts +360 -0
- package/packages/runtime/src/navigation.test.ts +421 -0
- package/packages/runtime/src/navigation.ts +422 -0
- package/packages/runtime/src/nextjs-adapter.ts +272 -0
- package/packages/runtime/src/offline/encrypted-queue.test.ts +607 -0
- package/packages/runtime/src/offline/encrypted-queue.ts +478 -0
- package/packages/runtime/src/offline/encryption.test.ts +412 -0
- package/packages/runtime/src/offline/encryption.ts +397 -0
- package/packages/runtime/src/offline/types.ts +465 -0
- package/packages/runtime/src/predictor.ts +371 -0
- package/packages/runtime/src/registry.ts +351 -0
- package/packages/runtime/src/router/context-extractor.ts +661 -0
- package/packages/runtime/src/router/esi-control-react.tsx +2053 -0
- package/packages/runtime/src/router/esi-control.ts +541 -0
- package/packages/runtime/src/router/esi-cyrano.ts +779 -0
- package/packages/runtime/src/router/esi-format-react.tsx +1744 -0
- package/packages/runtime/src/router/esi-react.tsx +1065 -0
- package/packages/runtime/src/router/esi-translate-observer.ts +476 -0
- package/packages/runtime/src/router/esi-translate-react.tsx +556 -0
- package/packages/runtime/src/router/esi-translate.ts +503 -0
- package/packages/runtime/src/router/esi.ts +666 -0
- package/packages/runtime/src/router/heuristic-adapter.test.ts +295 -0
- package/packages/runtime/src/router/heuristic-adapter.ts +557 -0
- package/packages/runtime/src/router/index.ts +298 -0
- package/packages/runtime/src/router/merkle-capability.ts +473 -0
- package/packages/runtime/src/router/speculation.ts +451 -0
- package/packages/runtime/src/router/types.ts +630 -0
- package/packages/runtime/src/router.test.ts +470 -0
- package/packages/runtime/src/router.ts +302 -0
- package/packages/runtime/src/server.ts +481 -0
- package/packages/runtime/src/service-worker-push.ts +319 -0
- package/packages/runtime/src/service-worker.ts +553 -0
- package/packages/runtime/src/skeleton-hydrate.ts +237 -0
- package/packages/runtime/src/speculation.test.ts +389 -0
- package/packages/runtime/src/speculation.ts +486 -0
- package/packages/runtime/src/storage.test.ts +1297 -0
- package/packages/runtime/src/storage.ts +1048 -0
- package/packages/runtime/src/sync/conflict-resolver.test.ts +528 -0
- package/packages/runtime/src/sync/conflict-resolver.ts +565 -0
- package/packages/runtime/src/sync/coordinator.test.ts +608 -0
- package/packages/runtime/src/sync/coordinator.ts +596 -0
- package/packages/runtime/src/tree-compiler.ts +295 -0
- package/packages/runtime/src/types.ts +728 -0
- package/packages/runtime/src/worker.ts +327 -0
- package/packages/runtime/tsconfig.json +20 -0
- package/packages/runtime/wasm/aeon_pages_runtime.d.ts +504 -0
- package/packages/runtime/wasm/aeon_pages_runtime.js +1657 -0
- package/packages/runtime/wasm/aeon_pages_runtime_bg.wasm +0 -0
- package/packages/runtime/wasm/aeon_pages_runtime_bg.wasm.d.ts +196 -0
- package/packages/runtime/wasm/package.json +21 -0
- package/packages/runtime/wrangler.toml +41 -0
- package/packages/runtime-wasm/Cargo.lock +436 -0
- package/packages/runtime-wasm/Cargo.toml +29 -0
- package/packages/runtime-wasm/pkg/aeon_pages_runtime.d.ts +480 -0
- package/packages/runtime-wasm/pkg/aeon_pages_runtime.js +1568 -0
- package/packages/runtime-wasm/pkg/aeon_pages_runtime_bg.wasm +0 -0
- package/packages/runtime-wasm/pkg/aeon_pages_runtime_bg.wasm.d.ts +192 -0
- package/packages/runtime-wasm/pkg/package.json +21 -0
- package/packages/runtime-wasm/src/hydrate.rs +352 -0
- package/packages/runtime-wasm/src/lib.rs +191 -0
- package/packages/runtime-wasm/src/render.rs +629 -0
- package/packages/runtime-wasm/src/router.rs +298 -0
- package/packages/runtime-wasm/src/skeleton.rs +430 -0
- 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
|
+
}
|