@affectively/aeon-pages-runtime 0.1.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/dist/cache.d.ts +94 -0
- package/dist/durable-object.d.ts +79 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +9497 -0
- package/dist/navigation.d.ts +124 -0
- package/dist/predictor.d.ts +121 -0
- package/dist/registry.d.ts +79 -0
- package/dist/router/context-extractor.d.ts +31 -0
- package/dist/router/esi-control-react.d.ts +248 -0
- package/dist/router/esi-control.d.ts +161 -0
- package/dist/router/esi-react.d.ts +198 -0
- package/dist/router/esi.d.ts +44 -0
- package/dist/router/heuristic-adapter.d.ts +57 -0
- package/dist/router/index.d.ts +24 -0
- package/dist/router/index.js +3515 -0
- package/dist/router/speculation.d.ts +91 -0
- package/dist/router/types.d.ts +305 -0
- package/dist/router.d.ts +56 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.js +8065 -0
- package/dist/service-worker.d.ts +12 -0
- package/dist/storage.d.ts +354 -0
- package/dist/types.d.ts +161 -0
- package/package.json +63 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aeon Service Worker - Total Preload Strategy
|
|
3
|
+
*
|
|
4
|
+
* The Aeon architecture is recursive:
|
|
5
|
+
* - This service worker caches the ENTIRE site as an Aeon
|
|
6
|
+
* - Each page session is an Aeon entity within the site Aeon
|
|
7
|
+
* - Federation would cache multiple sites as Aeons of Aeons
|
|
8
|
+
*
|
|
9
|
+
* With 8.4KB framework + ~2-5KB per page session, we can preload EVERYTHING.
|
|
10
|
+
* A site with 100 pages = ~315KB total (smaller than one hero image!)
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aeon Flux Storage Adapters
|
|
3
|
+
*
|
|
4
|
+
* Pluggable backend storage for routes and page content.
|
|
5
|
+
*
|
|
6
|
+
* Supported backends:
|
|
7
|
+
* - Dash (recommended for AFFECTIVELY ecosystem)
|
|
8
|
+
* - File system (default, development)
|
|
9
|
+
* - Cloudflare D1 (production, distributed)
|
|
10
|
+
* - Cloudflare Durable Objects (strong consistency)
|
|
11
|
+
* - Hybrid (D1 + Durable Objects)
|
|
12
|
+
* - Custom adapters
|
|
13
|
+
*/
|
|
14
|
+
import type { RouteDefinition, PageSession, SerializedComponent } from './types';
|
|
15
|
+
/**
|
|
16
|
+
* Storage adapter interface - implement this for custom backends
|
|
17
|
+
*/
|
|
18
|
+
export interface StorageAdapter {
|
|
19
|
+
/** Adapter name for logging */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Initialize the storage (create tables, etc.) */
|
|
22
|
+
init(): Promise<void>;
|
|
23
|
+
/** Get a route by path */
|
|
24
|
+
getRoute(path: string): Promise<RouteDefinition | null>;
|
|
25
|
+
/** Get all routes */
|
|
26
|
+
getAllRoutes(): Promise<RouteDefinition[]>;
|
|
27
|
+
/** Save a route */
|
|
28
|
+
saveRoute(route: RouteDefinition): Promise<void>;
|
|
29
|
+
/** Delete a route */
|
|
30
|
+
deleteRoute(path: string): Promise<void>;
|
|
31
|
+
/** Get a page session */
|
|
32
|
+
getSession(sessionId: string): Promise<PageSession | null>;
|
|
33
|
+
/** Save a page session */
|
|
34
|
+
saveSession(session: PageSession): Promise<void>;
|
|
35
|
+
/** Get component tree for a session */
|
|
36
|
+
getTree(sessionId: string): Promise<SerializedComponent | null>;
|
|
37
|
+
/** Save component tree for a session */
|
|
38
|
+
saveTree(sessionId: string, tree: SerializedComponent): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* File system storage adapter (default for development)
|
|
42
|
+
*/
|
|
43
|
+
export declare class FileStorageAdapter implements StorageAdapter {
|
|
44
|
+
name: string;
|
|
45
|
+
private pagesDir;
|
|
46
|
+
private dataDir;
|
|
47
|
+
constructor(options: {
|
|
48
|
+
pagesDir: string;
|
|
49
|
+
dataDir?: string;
|
|
50
|
+
});
|
|
51
|
+
init(): Promise<void>;
|
|
52
|
+
getRoute(path: string): Promise<RouteDefinition | null>;
|
|
53
|
+
getAllRoutes(): Promise<RouteDefinition[]>;
|
|
54
|
+
saveRoute(route: RouteDefinition): Promise<void>;
|
|
55
|
+
deleteRoute(path: string): Promise<void>;
|
|
56
|
+
getSession(sessionId: string): Promise<PageSession | null>;
|
|
57
|
+
saveSession(session: PageSession): Promise<void>;
|
|
58
|
+
getTree(sessionId: string): Promise<SerializedComponent | null>;
|
|
59
|
+
saveTree(sessionId: string, tree: SerializedComponent): Promise<void>;
|
|
60
|
+
private pathToKey;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Cloudflare D1 storage adapter (production, distributed)
|
|
64
|
+
*/
|
|
65
|
+
export declare class D1StorageAdapter implements StorageAdapter {
|
|
66
|
+
name: string;
|
|
67
|
+
private db;
|
|
68
|
+
constructor(db: D1Database);
|
|
69
|
+
init(): Promise<void>;
|
|
70
|
+
getRoute(path: string): Promise<RouteDefinition | null>;
|
|
71
|
+
getAllRoutes(): Promise<RouteDefinition[]>;
|
|
72
|
+
saveRoute(route: RouteDefinition): Promise<void>;
|
|
73
|
+
deleteRoute(path: string): Promise<void>;
|
|
74
|
+
getSession(sessionId: string): Promise<PageSession | null>;
|
|
75
|
+
saveSession(session: PageSession): Promise<void>;
|
|
76
|
+
getTree(sessionId: string): Promise<SerializedComponent | null>;
|
|
77
|
+
saveTree(sessionId: string, tree: SerializedComponent): Promise<void>;
|
|
78
|
+
private routeToSessionId;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Cloudflare D1 database interface (matches Cloudflare Workers API)
|
|
82
|
+
*/
|
|
83
|
+
interface D1Database {
|
|
84
|
+
prepare(query: string): D1PreparedStatement;
|
|
85
|
+
exec(query: string): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
interface D1PreparedStatement {
|
|
88
|
+
bind(...values: unknown[]): D1PreparedStatement;
|
|
89
|
+
first(): Promise<Record<string, unknown> | null>;
|
|
90
|
+
all(): Promise<{
|
|
91
|
+
results: Record<string, unknown>[];
|
|
92
|
+
}>;
|
|
93
|
+
run(): Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
interface DurableObjectId {
|
|
96
|
+
toString(): string;
|
|
97
|
+
equals(other: DurableObjectId): boolean;
|
|
98
|
+
}
|
|
99
|
+
interface DurableObjectNamespace {
|
|
100
|
+
get(id: DurableObjectId): DurableObjectStub;
|
|
101
|
+
idFromName(name: string): DurableObjectId;
|
|
102
|
+
idFromString(id: string): DurableObjectId;
|
|
103
|
+
newUniqueId(): DurableObjectId;
|
|
104
|
+
}
|
|
105
|
+
interface DurableObjectStub {
|
|
106
|
+
id: DurableObjectId;
|
|
107
|
+
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Cloudflare Durable Objects storage adapter (strong consistency)
|
|
111
|
+
*
|
|
112
|
+
* Each Aeon session maps to a Durable Object instance, providing:
|
|
113
|
+
* - Strong consistency for real-time collaborative editing
|
|
114
|
+
* - Automatic coalescing of WebSocket connections
|
|
115
|
+
* - Sub-millisecond latency within the same colo
|
|
116
|
+
*
|
|
117
|
+
* Use in combination with D1 for read replicas and historical data.
|
|
118
|
+
*/
|
|
119
|
+
export declare class DurableObjectStorageAdapter implements StorageAdapter {
|
|
120
|
+
name: string;
|
|
121
|
+
private namespace;
|
|
122
|
+
private routeCache;
|
|
123
|
+
constructor(namespace: DurableObjectNamespace);
|
|
124
|
+
init(): Promise<void>;
|
|
125
|
+
getRoute(path: string): Promise<RouteDefinition | null>;
|
|
126
|
+
getAllRoutes(): Promise<RouteDefinition[]>;
|
|
127
|
+
saveRoute(route: RouteDefinition): Promise<void>;
|
|
128
|
+
deleteRoute(path: string): Promise<void>;
|
|
129
|
+
getSession(sessionId: string): Promise<PageSession | null>;
|
|
130
|
+
saveSession(session: PageSession): Promise<void>;
|
|
131
|
+
getTree(sessionId: string): Promise<SerializedComponent | null>;
|
|
132
|
+
saveTree(sessionId: string, tree: SerializedComponent): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Get a direct stub for WebSocket connections
|
|
135
|
+
* This allows real-time collaboration via Durable Object WebSockets
|
|
136
|
+
*/
|
|
137
|
+
getSessionStub(sessionId: string): DurableObjectStub;
|
|
138
|
+
private routeToSessionId;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Hybrid storage adapter (D1 + Durable Objects)
|
|
142
|
+
*
|
|
143
|
+
* Combines the best of both:
|
|
144
|
+
* - Durable Objects for real-time collaborative editing (strong consistency)
|
|
145
|
+
* - D1 for read replicas and historical snapshots (eventual consistency)
|
|
146
|
+
*
|
|
147
|
+
* Write path: Durable Object → async propagate to D1
|
|
148
|
+
* Read path: Durable Object (real-time) or D1 (historical)
|
|
149
|
+
*/
|
|
150
|
+
export declare class HybridStorageAdapter implements StorageAdapter {
|
|
151
|
+
name: string;
|
|
152
|
+
private do;
|
|
153
|
+
private d1;
|
|
154
|
+
constructor(options: {
|
|
155
|
+
namespace: DurableObjectNamespace;
|
|
156
|
+
db: D1Database;
|
|
157
|
+
});
|
|
158
|
+
init(): Promise<void>;
|
|
159
|
+
getRoute(path: string): Promise<RouteDefinition | null>;
|
|
160
|
+
getAllRoutes(): Promise<RouteDefinition[]>;
|
|
161
|
+
saveRoute(route: RouteDefinition): Promise<void>;
|
|
162
|
+
deleteRoute(path: string): Promise<void>;
|
|
163
|
+
getSession(sessionId: string): Promise<PageSession | null>;
|
|
164
|
+
saveSession(session: PageSession): Promise<void>;
|
|
165
|
+
getTree(sessionId: string): Promise<SerializedComponent | null>;
|
|
166
|
+
saveTree(sessionId: string, tree: SerializedComponent): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Get historical snapshots from D1
|
|
169
|
+
*/
|
|
170
|
+
getHistoricalSession(sessionId: string): Promise<PageSession | null>;
|
|
171
|
+
/**
|
|
172
|
+
* Get direct Durable Object stub for WebSocket connections
|
|
173
|
+
*/
|
|
174
|
+
getSessionStub(sessionId: string): DurableObjectStub;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Dash client interface
|
|
178
|
+
*
|
|
179
|
+
* Dash is AFFECTIVELY's real-time sync system built on Aeon.
|
|
180
|
+
* It provides:
|
|
181
|
+
* - Real-time subscriptions via WebSocket
|
|
182
|
+
* - Automatic conflict resolution (CRDT-based)
|
|
183
|
+
* - Offline-first with sync on reconnect
|
|
184
|
+
* - Cross-platform (web, mobile, edge)
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* import { createDashClient } from '@affectively/dash';
|
|
189
|
+
*
|
|
190
|
+
* const dash = createDashClient({
|
|
191
|
+
* endpoint: 'wss://dash.affectively.com',
|
|
192
|
+
* auth: { token: 'your-auth-token' },
|
|
193
|
+
* });
|
|
194
|
+
*
|
|
195
|
+
* const storage = new DashStorageAdapter(dash);
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
interface DashClient {
|
|
199
|
+
/** Connect to Dash server */
|
|
200
|
+
connect(): Promise<void>;
|
|
201
|
+
/** Disconnect from Dash server */
|
|
202
|
+
disconnect(): Promise<void>;
|
|
203
|
+
/** Check connection status */
|
|
204
|
+
isConnected(): boolean;
|
|
205
|
+
/** Get a document by collection and id */
|
|
206
|
+
get<T>(collection: string, id: string): Promise<T | null>;
|
|
207
|
+
/** Query documents in a collection */
|
|
208
|
+
query<T>(collection: string, filter?: DashFilter): Promise<T[]>;
|
|
209
|
+
/** Set/update a document */
|
|
210
|
+
set<T>(collection: string, id: string, data: T): Promise<void>;
|
|
211
|
+
/** Delete a document */
|
|
212
|
+
delete(collection: string, id: string): Promise<void>;
|
|
213
|
+
/** Subscribe to real-time updates */
|
|
214
|
+
subscribe<T>(collection: string, filter: DashFilter | undefined, callback: (changes: DashChange<T>[]) => void): DashSubscription;
|
|
215
|
+
/** Batch operations */
|
|
216
|
+
batch(operations: DashOperation[]): Promise<void>;
|
|
217
|
+
}
|
|
218
|
+
interface DashFilter {
|
|
219
|
+
where?: Array<{
|
|
220
|
+
field: string;
|
|
221
|
+
op: '==' | '!=' | '<' | '<=' | '>' | '>=' | 'in' | 'contains';
|
|
222
|
+
value: unknown;
|
|
223
|
+
}>;
|
|
224
|
+
orderBy?: {
|
|
225
|
+
field: string;
|
|
226
|
+
direction: 'asc' | 'desc';
|
|
227
|
+
};
|
|
228
|
+
limit?: number;
|
|
229
|
+
offset?: number;
|
|
230
|
+
}
|
|
231
|
+
interface DashChange<T> {
|
|
232
|
+
type: 'added' | 'modified' | 'removed';
|
|
233
|
+
id: string;
|
|
234
|
+
data: T | null;
|
|
235
|
+
previousData?: T;
|
|
236
|
+
}
|
|
237
|
+
interface DashSubscription {
|
|
238
|
+
unsubscribe(): void;
|
|
239
|
+
}
|
|
240
|
+
interface DashOperation {
|
|
241
|
+
type: 'set' | 'delete';
|
|
242
|
+
collection: string;
|
|
243
|
+
id: string;
|
|
244
|
+
data?: unknown;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Dash storage adapter
|
|
248
|
+
*
|
|
249
|
+
* Uses AFFECTIVELY's Dash real-time sync system as the backend.
|
|
250
|
+
* This is the recommended adapter for the AFFECTIVELY ecosystem
|
|
251
|
+
* as it integrates seamlessly with other Dash-powered features.
|
|
252
|
+
*
|
|
253
|
+
* Features:
|
|
254
|
+
* - Real-time sync across all connected clients
|
|
255
|
+
* - CRDT-based conflict resolution (no data loss)
|
|
256
|
+
* - Offline-first with automatic sync on reconnect
|
|
257
|
+
* - Presence tracking built-in
|
|
258
|
+
* - Works with existing Dash infrastructure
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* import { createDashClient } from '@affectively/dash';
|
|
263
|
+
* import { DashStorageAdapter } from '@affectively/aeon-flux';
|
|
264
|
+
*
|
|
265
|
+
* const dash = createDashClient({
|
|
266
|
+
* endpoint: process.env.DASH_ENDPOINT,
|
|
267
|
+
* auth: { token: await getAuthToken() },
|
|
268
|
+
* });
|
|
269
|
+
*
|
|
270
|
+
* const storage = new DashStorageAdapter(dash, {
|
|
271
|
+
* routesCollection: 'aeon-routes',
|
|
272
|
+
* sessionsCollection: 'aeon-sessions',
|
|
273
|
+
* presenceCollection: 'aeon-presence',
|
|
274
|
+
* });
|
|
275
|
+
*
|
|
276
|
+
* // Use with Aeon Flux server
|
|
277
|
+
* const server = await createAeonServer({
|
|
278
|
+
* storage,
|
|
279
|
+
* // ...
|
|
280
|
+
* });
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
export declare class DashStorageAdapter implements StorageAdapter {
|
|
284
|
+
name: string;
|
|
285
|
+
private client;
|
|
286
|
+
private collections;
|
|
287
|
+
private subscriptions;
|
|
288
|
+
constructor(client: DashClient, options?: {
|
|
289
|
+
routesCollection?: string;
|
|
290
|
+
sessionsCollection?: string;
|
|
291
|
+
presenceCollection?: string;
|
|
292
|
+
});
|
|
293
|
+
init(): Promise<void>;
|
|
294
|
+
getRoute(path: string): Promise<RouteDefinition | null>;
|
|
295
|
+
getAllRoutes(): Promise<RouteDefinition[]>;
|
|
296
|
+
saveRoute(route: RouteDefinition): Promise<void>;
|
|
297
|
+
deleteRoute(path: string): Promise<void>;
|
|
298
|
+
getSession(sessionId: string): Promise<PageSession | null>;
|
|
299
|
+
saveSession(session: PageSession): Promise<void>;
|
|
300
|
+
getTree(sessionId: string): Promise<SerializedComponent | null>;
|
|
301
|
+
saveTree(sessionId: string, tree: SerializedComponent): Promise<void>;
|
|
302
|
+
/**
|
|
303
|
+
* Subscribe to real-time route changes
|
|
304
|
+
*/
|
|
305
|
+
subscribeToRoutes(callback: (changes: DashChange<RouteDefinition>[]) => void): DashSubscription;
|
|
306
|
+
/**
|
|
307
|
+
* Subscribe to real-time session changes
|
|
308
|
+
*/
|
|
309
|
+
subscribeToSession(sessionId: string, callback: (changes: DashChange<PageSession>[]) => void): DashSubscription;
|
|
310
|
+
/**
|
|
311
|
+
* Subscribe to presence updates for a session
|
|
312
|
+
*/
|
|
313
|
+
subscribeToPresence(sessionId: string, callback: (changes: DashChange<PresenceRecord>[]) => void): DashSubscription;
|
|
314
|
+
/**
|
|
315
|
+
* Update presence for current user
|
|
316
|
+
*/
|
|
317
|
+
updatePresence(sessionId: string, userId: string, presence: Partial<PresenceRecord>): Promise<void>;
|
|
318
|
+
/**
|
|
319
|
+
* Clean up subscriptions
|
|
320
|
+
*/
|
|
321
|
+
destroy(): void;
|
|
322
|
+
private pathToId;
|
|
323
|
+
private routeToSessionId;
|
|
324
|
+
}
|
|
325
|
+
interface PresenceRecord {
|
|
326
|
+
sessionId: string;
|
|
327
|
+
userId: string;
|
|
328
|
+
role: 'user' | 'assistant' | 'monitor' | 'admin';
|
|
329
|
+
cursor?: {
|
|
330
|
+
x: number;
|
|
331
|
+
y: number;
|
|
332
|
+
};
|
|
333
|
+
editing?: string;
|
|
334
|
+
status: 'online' | 'away' | 'offline';
|
|
335
|
+
lastActivity: string;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Create a storage adapter based on configuration
|
|
339
|
+
*/
|
|
340
|
+
export declare function createStorageAdapter(config: {
|
|
341
|
+
type: 'file' | 'd1' | 'durable-object' | 'hybrid' | 'dash' | 'custom';
|
|
342
|
+
pagesDir?: string;
|
|
343
|
+
dataDir?: string;
|
|
344
|
+
d1?: D1Database;
|
|
345
|
+
durableObjectNamespace?: DurableObjectNamespace;
|
|
346
|
+
dash?: DashClient;
|
|
347
|
+
dashCollections?: {
|
|
348
|
+
routes?: string;
|
|
349
|
+
sessions?: string;
|
|
350
|
+
presence?: string;
|
|
351
|
+
};
|
|
352
|
+
custom?: StorageAdapter;
|
|
353
|
+
}): StorageAdapter;
|
|
354
|
+
export {};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aeon Pages Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
export interface AeonConfig {
|
|
5
|
+
/** Directory containing pages (default: './pages') */
|
|
6
|
+
pagesDir: string;
|
|
7
|
+
/** Directory containing components (default: './components') */
|
|
8
|
+
componentsDir?: string;
|
|
9
|
+
/** Runtime target: 'bun' or 'cloudflare' */
|
|
10
|
+
runtime: 'bun' | 'cloudflare';
|
|
11
|
+
/** Server port (default: 3000) */
|
|
12
|
+
port?: number;
|
|
13
|
+
/** Aeon-specific configuration */
|
|
14
|
+
aeon?: AeonOptions;
|
|
15
|
+
/** Component configuration */
|
|
16
|
+
components?: ComponentOptions;
|
|
17
|
+
/** Next.js compatibility mode */
|
|
18
|
+
nextCompat?: boolean;
|
|
19
|
+
/** Build output configuration */
|
|
20
|
+
output?: OutputOptions;
|
|
21
|
+
}
|
|
22
|
+
export interface AeonOptions {
|
|
23
|
+
/** Distributed sync configuration */
|
|
24
|
+
sync?: SyncOptions;
|
|
25
|
+
/** Schema versioning configuration */
|
|
26
|
+
versioning?: VersioningOptions;
|
|
27
|
+
/** Presence tracking configuration */
|
|
28
|
+
presence?: PresenceOptions;
|
|
29
|
+
/** Offline support configuration */
|
|
30
|
+
offline?: OfflineOptions;
|
|
31
|
+
/** Allow dynamic route creation for unclaimed paths */
|
|
32
|
+
dynamicRoutes?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface SyncOptions {
|
|
35
|
+
/** Sync mode: 'distributed' for multi-node, 'local' for single-node */
|
|
36
|
+
mode: 'distributed' | 'local';
|
|
37
|
+
/** Number of replicas for distributed mode */
|
|
38
|
+
replicationFactor?: number;
|
|
39
|
+
/** Consistency level for reads/writes */
|
|
40
|
+
consistencyLevel?: 'strong' | 'eventual' | 'read-after-write';
|
|
41
|
+
}
|
|
42
|
+
export interface VersioningOptions {
|
|
43
|
+
/** Enable schema versioning */
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
/** Automatically run migrations */
|
|
46
|
+
autoMigrate?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface PresenceOptions {
|
|
49
|
+
/** Enable presence tracking */
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
/** Track cursor positions */
|
|
52
|
+
cursorTracking?: boolean;
|
|
53
|
+
/** Inactivity timeout in milliseconds */
|
|
54
|
+
inactivityTimeout?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface OfflineOptions {
|
|
57
|
+
/** Enable offline support */
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/** Maximum operations to queue offline */
|
|
60
|
+
maxQueueSize?: number;
|
|
61
|
+
}
|
|
62
|
+
export interface ComponentOptions {
|
|
63
|
+
/** Auto-discover components from componentsDir */
|
|
64
|
+
autoDiscover?: boolean;
|
|
65
|
+
/** Explicit list of components to include */
|
|
66
|
+
include?: string[];
|
|
67
|
+
/** Components to exclude from auto-discovery */
|
|
68
|
+
exclude?: string[];
|
|
69
|
+
}
|
|
70
|
+
export interface OutputOptions {
|
|
71
|
+
/** Output directory for built assets */
|
|
72
|
+
dir?: string;
|
|
73
|
+
}
|
|
74
|
+
/** Route definition */
|
|
75
|
+
export interface RouteDefinition {
|
|
76
|
+
/** Pattern like "/blog/[slug]" */
|
|
77
|
+
pattern: string;
|
|
78
|
+
/** Session ID template */
|
|
79
|
+
sessionId: string;
|
|
80
|
+
/** Component ID */
|
|
81
|
+
componentId: string;
|
|
82
|
+
/** Layout wrapper */
|
|
83
|
+
layout?: string;
|
|
84
|
+
/** Whether this route uses 'use aeon' */
|
|
85
|
+
isAeon: boolean;
|
|
86
|
+
}
|
|
87
|
+
/** Route match result */
|
|
88
|
+
export interface RouteMatch {
|
|
89
|
+
/** The matched route */
|
|
90
|
+
route: RouteDefinition;
|
|
91
|
+
/** Extracted parameters */
|
|
92
|
+
params: Record<string, string>;
|
|
93
|
+
/** Resolved session ID */
|
|
94
|
+
sessionId: string;
|
|
95
|
+
/** Component ID shorthand */
|
|
96
|
+
componentId: string;
|
|
97
|
+
/** Is this an Aeon page? */
|
|
98
|
+
isAeon: boolean;
|
|
99
|
+
}
|
|
100
|
+
/** Route metadata for registry */
|
|
101
|
+
export interface RouteMetadata {
|
|
102
|
+
createdAt: string;
|
|
103
|
+
createdBy: string;
|
|
104
|
+
updatedAt?: string;
|
|
105
|
+
updatedBy?: string;
|
|
106
|
+
}
|
|
107
|
+
/** Route operation for sync */
|
|
108
|
+
export interface RouteOperation {
|
|
109
|
+
type: 'route-add' | 'route-update' | 'route-remove';
|
|
110
|
+
path: string;
|
|
111
|
+
component?: string;
|
|
112
|
+
metadata?: RouteMetadata;
|
|
113
|
+
timestamp: string;
|
|
114
|
+
nodeId: string;
|
|
115
|
+
}
|
|
116
|
+
/** Serialized component tree */
|
|
117
|
+
export interface SerializedComponent {
|
|
118
|
+
type: string;
|
|
119
|
+
props?: Record<string, unknown>;
|
|
120
|
+
children?: (SerializedComponent | string)[];
|
|
121
|
+
}
|
|
122
|
+
/** Page session stored in Aeon */
|
|
123
|
+
export interface PageSession {
|
|
124
|
+
/** Route this session serves */
|
|
125
|
+
route: string;
|
|
126
|
+
/** Current component state */
|
|
127
|
+
tree: SerializedComponent;
|
|
128
|
+
/** Page data */
|
|
129
|
+
data: Record<string, unknown>;
|
|
130
|
+
/** Schema version */
|
|
131
|
+
schema: {
|
|
132
|
+
version: string;
|
|
133
|
+
};
|
|
134
|
+
/** Active presence info */
|
|
135
|
+
presence: PresenceInfo[];
|
|
136
|
+
}
|
|
137
|
+
/** Presence info for a user/agent */
|
|
138
|
+
export interface PresenceInfo {
|
|
139
|
+
/** User or agent ID */
|
|
140
|
+
userId: string;
|
|
141
|
+
/** User or agent role */
|
|
142
|
+
role: 'user' | 'assistant' | 'monitor' | 'admin';
|
|
143
|
+
/** Cursor position */
|
|
144
|
+
cursor?: {
|
|
145
|
+
x: number;
|
|
146
|
+
y: number;
|
|
147
|
+
};
|
|
148
|
+
/** Currently editing element path */
|
|
149
|
+
editing?: string;
|
|
150
|
+
/** Online/away/offline status */
|
|
151
|
+
status: 'online' | 'away' | 'offline';
|
|
152
|
+
/** Last activity timestamp */
|
|
153
|
+
lastActivity: string;
|
|
154
|
+
}
|
|
155
|
+
/** UCAN capability for Aeon pages */
|
|
156
|
+
export interface AeonCapability {
|
|
157
|
+
can: 'aeon:read' | 'aeon:write' | 'aeon:admin' | 'aeon:*';
|
|
158
|
+
with: string;
|
|
159
|
+
}
|
|
160
|
+
/** Alias for PresenceInfo - used by react package */
|
|
161
|
+
export type PresenceUser = PresenceInfo;
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@affectively/aeon-pages-runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Bun/Cloudflare runtime for @affectively/aeon-pages",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./server": {
|
|
14
|
+
"import": "./dist/server.js",
|
|
15
|
+
"types": "./dist/server.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./router": {
|
|
18
|
+
"import": "./dist/router/index.js",
|
|
19
|
+
"types": "./dist/router/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun build ./src/index.ts ./src/server.ts ./src/router/index.ts --outdir ./dist --target bun && tsc --declaration --emitDeclarationOnly",
|
|
24
|
+
"dev": "bun --watch ./src/index.ts",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"prepublishOnly": "bun run build"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"bun": ">=1.0.0",
|
|
34
|
+
"react": ">=18.0.0",
|
|
35
|
+
"zod": ">=3.0.0",
|
|
36
|
+
"@affectively/aeon": ">=0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependenciesMeta": {
|
|
39
|
+
"@affectively/aeon": {
|
|
40
|
+
"optional": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"typescript": "^5.7.0",
|
|
45
|
+
"@types/bun": "latest",
|
|
46
|
+
"@types/react": "^19.0.0",
|
|
47
|
+
"react": "^19.0.0",
|
|
48
|
+
"zod": "^3.24.0"
|
|
49
|
+
},
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/affectively/aeon-pages"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"aeon",
|
|
57
|
+
"pages",
|
|
58
|
+
"framework",
|
|
59
|
+
"collaborative",
|
|
60
|
+
"bun",
|
|
61
|
+
"cloudflare"
|
|
62
|
+
]
|
|
63
|
+
}
|