@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,86 @@
1
+ import type { PresenceUser } from '@affectively/aeon-pages/react';
2
+
3
+ interface CursorProps {
4
+ user: PresenceUser;
5
+ }
6
+
7
+ // Generate a color from user ID
8
+ function userColor(userId: string): string {
9
+ const colors = [
10
+ '#ef4444', // red
11
+ '#f97316', // orange
12
+ '#eab308', // yellow
13
+ '#22c55e', // green
14
+ '#06b6d4', // cyan
15
+ '#3b82f6', // blue
16
+ '#336699', // steel blue
17
+ '#ec4899', // pink
18
+ ];
19
+ let hash = 0;
20
+ for (let i = 0; i < userId.length; i++) {
21
+ hash = (hash << 5) - hash + userId.charCodeAt(i);
22
+ hash = hash & hash;
23
+ }
24
+ return colors[Math.abs(hash) % colors.length];
25
+ }
26
+
27
+ export function Cursor({ user }: CursorProps) {
28
+ if (!user.cursor || user.status === 'offline') {
29
+ return null;
30
+ }
31
+
32
+ const color = userColor(user.userId);
33
+
34
+ return (
35
+ <div
36
+ style={{
37
+ position: 'fixed',
38
+ left: user.cursor.x,
39
+ top: user.cursor.y,
40
+ pointerEvents: 'none',
41
+ zIndex: 9999,
42
+ transition: 'left 0.1s ease-out, top 0.1s ease-out',
43
+ }}
44
+ >
45
+ {/* Cursor arrow */}
46
+ <svg
47
+ width="24"
48
+ height="24"
49
+ viewBox="0 0 24 24"
50
+ fill="none"
51
+ style={{ filter: 'drop-shadow(0 1px 2px rgba(0,0,0,0.3))' }}
52
+ >
53
+ <path
54
+ d="M5.5 3.21V20.8c0 .45.54.67.85.35l4.86-4.86a.5.5 0 0 1 .35-.15h6.87c.48 0 .72-.58.38-.92L5.92 2.53a.5.5 0 0 0-.42.68z"
55
+ fill={color}
56
+ stroke="white"
57
+ strokeWidth="1.5"
58
+ />
59
+ </svg>
60
+
61
+ {/* User label */}
62
+ <div
63
+ style={{
64
+ marginLeft: '16px',
65
+ marginTop: '-4px',
66
+ padding: '2px 8px',
67
+ backgroundColor: color,
68
+ color: 'white',
69
+ fontSize: '12px',
70
+ fontWeight: 500,
71
+ borderRadius: '4px',
72
+ whiteSpace: 'nowrap',
73
+ boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
74
+ }}
75
+ >
76
+ {user.role === 'assistant' ? '🤖 ' : ''}
77
+ {user.userId.slice(0, 8)}
78
+ {user.editing && (
79
+ <span style={{ marginLeft: '4px', opacity: 0.8 }}>editing</span>
80
+ )}
81
+ </div>
82
+ </div>
83
+ );
84
+ }
85
+
86
+ export default Cursor;
@@ -0,0 +1,103 @@
1
+ import { useOfflineStatus } from '@affectively/aeon-pages/react';
2
+
3
+ export function OfflineIndicator() {
4
+ const { isOffline, isSyncing, pendingOperations, lastSyncAt } =
5
+ useOfflineStatus();
6
+
7
+ if (!isOffline && !isSyncing && pendingOperations === 0) {
8
+ return null;
9
+ }
10
+
11
+ return (
12
+ <div className="fixed bottom-4 right-4 flex flex-col gap-2">
13
+ {/* Offline banner */}
14
+ {isOffline && (
15
+ <div className="flex items-center gap-2 bg-yellow-50 border border-yellow-200 rounded-lg px-4 py-2 shadow-lg">
16
+ <svg
17
+ className="w-5 h-5 text-yellow-500"
18
+ fill="none"
19
+ viewBox="0 0 24 24"
20
+ stroke="currentColor"
21
+ >
22
+ <path
23
+ strokeLinecap="round"
24
+ strokeLinejoin="round"
25
+ strokeWidth={2}
26
+ d="M18.364 5.636a9 9 0 010 12.728m0 0l-2.829-2.829m2.829 2.829L21 21M15.536 8.464a5 5 0 010 7.072m0 0l-2.829-2.829m-4.243 2.829a4.978 4.978 0 01-1.414-2.83m-1.414 5.658a9 9 0 01-2.167-9.238m7.824 2.167a1 1 0 111.414 1.414m-1.414-1.414L3 3"
27
+ />
28
+ </svg>
29
+ <div>
30
+ <p className="text-sm font-medium text-yellow-800">
31
+ You're offline
32
+ </p>
33
+ <p className="text-xs text-yellow-600">
34
+ Changes will sync when back online
35
+ </p>
36
+ </div>
37
+ </div>
38
+ )}
39
+
40
+ {/* Pending operations */}
41
+ {pendingOperations > 0 && (
42
+ <div className="flex items-center gap-2 bg-blue-50 border border-blue-200 rounded-lg px-4 py-2 shadow-lg">
43
+ <div className="w-5 h-5">
44
+ <svg
45
+ className="animate-spin text-blue-500"
46
+ fill="none"
47
+ viewBox="0 0 24 24"
48
+ >
49
+ <circle
50
+ className="opacity-25"
51
+ cx="12"
52
+ cy="12"
53
+ r="10"
54
+ stroke="currentColor"
55
+ strokeWidth="4"
56
+ />
57
+ <path
58
+ className="opacity-75"
59
+ fill="currentColor"
60
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
61
+ />
62
+ </svg>
63
+ </div>
64
+ <div>
65
+ <p className="text-sm font-medium text-blue-800">
66
+ {isSyncing ? 'Syncing...' : `${pendingOperations} pending`}
67
+ </p>
68
+ <p className="text-xs text-blue-600">
69
+ {pendingOperations}{' '}
70
+ {pendingOperations === 1 ? 'change' : 'changes'} to sync
71
+ </p>
72
+ </div>
73
+ </div>
74
+ )}
75
+
76
+ {/* Last sync time */}
77
+ {lastSyncAt && !isOffline && pendingOperations === 0 && (
78
+ <div className="text-xs text-gray-400 text-right">
79
+ Last synced: {formatRelativeTime(lastSyncAt)}
80
+ </div>
81
+ )}
82
+ </div>
83
+ );
84
+ }
85
+
86
+ function formatRelativeTime(isoString: string): string {
87
+ const date = new Date(isoString);
88
+ const now = new Date();
89
+ const diff = now.getTime() - date.getTime();
90
+
91
+ const seconds = Math.floor(diff / 1000);
92
+ const minutes = Math.floor(seconds / 60);
93
+ const hours = Math.floor(minutes / 60);
94
+
95
+ if (seconds < 10) return 'just now';
96
+ if (seconds < 60) return `${seconds}s ago`;
97
+ if (minutes < 60) return `${minutes}m ago`;
98
+ if (hours < 24) return `${hours}h ago`;
99
+
100
+ return date.toLocaleDateString();
101
+ }
102
+
103
+ export default OfflineIndicator;
@@ -0,0 +1,77 @@
1
+ import type { PresenceUser } from '@affectively/aeon-pages/react';
2
+
3
+ interface PresenceBarProps {
4
+ users: PresenceUser[];
5
+ }
6
+
7
+ export function PresenceBar({ users }: PresenceBarProps) {
8
+ const onlineUsers = users.filter((u) => u.status === 'online');
9
+ const awayUsers = users.filter((u) => u.status === 'away');
10
+
11
+ return (
12
+ <div className="fixed top-4 right-4 flex items-center gap-2 bg-white rounded-full px-4 py-2 shadow-lg border border-gray-200">
13
+ {/* Online indicator */}
14
+ <div className="flex items-center gap-1">
15
+ <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />
16
+ <span className="text-sm text-gray-600">
17
+ {onlineUsers.length} online
18
+ </span>
19
+ </div>
20
+
21
+ {awayUsers.length > 0 && (
22
+ <>
23
+ <div className="w-px h-4 bg-gray-200" />
24
+ <div className="flex items-center gap-1">
25
+ <div className="w-2 h-2 bg-yellow-500 rounded-full" />
26
+ <span className="text-sm text-gray-500">
27
+ {awayUsers.length} away
28
+ </span>
29
+ </div>
30
+ </>
31
+ )}
32
+
33
+ {/* User avatars */}
34
+ <div className="w-px h-4 bg-gray-200 ml-2" />
35
+ <div className="flex -space-x-2">
36
+ {users.slice(0, 5).map((user) => (
37
+ <UserAvatar key={user.userId} user={user} />
38
+ ))}
39
+ {users.length > 5 && (
40
+ <div className="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center text-xs text-gray-600 border-2 border-white">
41
+ +{users.length - 5}
42
+ </div>
43
+ )}
44
+ </div>
45
+ </div>
46
+ );
47
+ }
48
+
49
+ function UserAvatar({ user }: { user: PresenceUser }) {
50
+ const isAgent = user.role === 'assistant';
51
+ const statusColor =
52
+ user.status === 'online'
53
+ ? 'bg-green-500'
54
+ : user.status === 'away'
55
+ ? 'bg-yellow-500'
56
+ : 'bg-gray-400';
57
+
58
+ return (
59
+ <div
60
+ className="relative w-8 h-8 rounded-full border-2 border-white flex items-center justify-center text-xs font-medium"
61
+ style={{
62
+ backgroundColor: isAgent ? '#336699' : '#3b82f6',
63
+ color: 'white',
64
+ }}
65
+ title={`${user.userId.slice(0, 8)} (${user.role})`}
66
+ >
67
+ {isAgent ? '🤖' : user.userId.slice(0, 2).toUpperCase()}
68
+
69
+ {/* Status indicator */}
70
+ <div
71
+ className={`absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full ${statusColor} border border-white`}
72
+ />
73
+ </div>
74
+ );
75
+ }
76
+
77
+ export default PresenceBar;
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@affectively/aeon-pages-example-basic",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "aeon dev",
8
+ "build": "aeon build",
9
+ "start": "aeon start"
10
+ },
11
+ "dependencies": {
12
+ "@affectively/aeon-pages": "workspace:*",
13
+ "react": "^18.0.0",
14
+ "react-dom": "^18.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "typescript": "^5.7.0",
18
+ "@types/react": "^18.0.0"
19
+ }
20
+ }
@@ -0,0 +1,80 @@
1
+ 'use aeon';
2
+
3
+ import {
4
+ usePresence,
5
+ useAeonData,
6
+ useCursorTracking,
7
+ } from '@affectively/aeon-pages/react';
8
+ import { Cursor } from '../components/Cursor';
9
+ import { PresenceBar } from '../components/PresenceBar';
10
+ import { OfflineIndicator } from '../components/OfflineIndicator';
11
+
12
+ export default function HomePage() {
13
+ const { presence, localUser } = usePresence();
14
+ const [title, setTitle] = useAeonData<string>('title');
15
+ const [description, setDescription] = useAeonData<string>('description');
16
+
17
+ // Auto-track cursor movement
18
+ useCursorTracking(true);
19
+
20
+ // Filter out self from presence
21
+ const otherUsers = presence.filter((u) => u.userId !== localUser?.userId);
22
+
23
+ return (
24
+ <div className="min-h-screen bg-gray-50 p-8">
25
+ {/* Presence bar showing who's viewing */}
26
+ <PresenceBar users={presence} />
27
+
28
+ {/* Offline indicator */}
29
+ <OfflineIndicator />
30
+
31
+ {/* Main content - editable in place */}
32
+ <main className="max-w-4xl mx-auto mt-8">
33
+ <h1
34
+ contentEditable
35
+ suppressContentEditableWarning
36
+ onBlur={(e) => setTitle(e.currentTarget.textContent || '')}
37
+ className="text-4xl font-bold text-gray-900 outline-none focus:ring-2 focus:ring-blue-500 rounded px-2 py-1"
38
+ >
39
+ {title || 'Welcome to Aeon Pages'}
40
+ </h1>
41
+
42
+ <p
43
+ contentEditable
44
+ suppressContentEditableWarning
45
+ onBlur={(e) => setDescription(e.currentTarget.textContent || '')}
46
+ className="mt-4 text-xl text-gray-600 outline-none focus:ring-2 focus:ring-blue-500 rounded px-2 py-1"
47
+ >
48
+ {description || 'Click any text to edit. Changes sync in real-time.'}
49
+ </p>
50
+
51
+ <div className="mt-8 p-6 bg-white rounded-lg shadow">
52
+ <h2 className="text-2xl font-semibold text-gray-800">Features</h2>
53
+ <ul className="mt-4 space-y-2 text-gray-700">
54
+ <li>Real-time collaborative editing</li>
55
+ <li>See other editors cursors</li>
56
+ <li>Works offline, syncs when back online</li>
57
+ <li>Version history with rollback</li>
58
+ <li>~20KB runtime</li>
59
+ </ul>
60
+ </div>
61
+
62
+ <div className="mt-8 text-sm text-gray-500">
63
+ {otherUsers.length > 0 ? (
64
+ <p>
65
+ {otherUsers.length} other{' '}
66
+ {otherUsers.length === 1 ? 'person' : 'people'} viewing this page
67
+ </p>
68
+ ) : (
69
+ <p>You're the only one here</p>
70
+ )}
71
+ </div>
72
+ </main>
73
+
74
+ {/* Render other users' cursors */}
75
+ {otherUsers.map((user) => (
76
+ <Cursor key={user.userId} user={user} />
77
+ ))}
78
+ </div>
79
+ );
80
+ }
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "@affectively/aeon-pages",
3
+ "version": "1.3.0",
4
+ "description": "Collaborative page surface with CRDT-based flux state, Edge Side Inference, and zero-CLS rendering. Pages that think.",
5
+ "type": "module",
6
+ "workspaces": [
7
+ "packages/*"
8
+ ],
9
+ "main": "./packages/runtime/dist/index.js",
10
+ "types": "./packages/runtime/dist/index.d.ts",
11
+ "bin": {
12
+ "aeon": "packages/cli/dist/index.js"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "import": "./packages/runtime/dist/index.js",
17
+ "types": "./packages/runtime/dist/index.d.ts"
18
+ },
19
+ "./runtime": {
20
+ "import": "./packages/runtime/dist/index.js",
21
+ "types": "./packages/runtime/dist/index.d.ts"
22
+ },
23
+ "./react": {
24
+ "import": "./packages/react/dist/index.js",
25
+ "types": "./packages/react/dist/index.d.ts"
26
+ },
27
+ "./esi": {
28
+ "import": "./packages/runtime/dist/router/index.js",
29
+ "types": "./packages/runtime/dist/router/index.d.ts"
30
+ },
31
+ "./server": {
32
+ "import": "./packages/runtime/dist/server.js",
33
+ "types": "./packages/runtime/dist/server.d.ts"
34
+ },
35
+ "./auth": {
36
+ "import": "@affectively/auth",
37
+ "types": "@affectively/auth"
38
+ },
39
+ "./directives": {
40
+ "import": "./packages/directives/dist/use-aeon.js",
41
+ "types": "./packages/directives/dist/use-aeon.d.ts"
42
+ }
43
+ },
44
+ "scripts": {
45
+ "build": "bun run build:wasm && bun run build:ts",
46
+ "build:wasm": "cd packages/runtime-wasm && wasm-pack build --target web --out-dir ../runtime/wasm",
47
+ "build:ts": "bun run --filter='./packages/*' build",
48
+ "dev": "bun run packages/cli/src/dev.ts",
49
+ "test": "bun test",
50
+ "clean": "rm -rf packages/*/dist packages/runtime/wasm"
51
+ },
52
+ "dependencies": {
53
+ "@affectively/aeon": "^1.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "typescript": "^5.7.0",
57
+ "@types/bun": "latest",
58
+ "@types/react": "^18.0.0",
59
+ "wasm-pack": "^0.13.0"
60
+ },
61
+ "peerDependencies": {
62
+ "bun": ">=1.0.0",
63
+ "react": ">=18.0.0",
64
+ "@affectively/auth": ">=0.1.0"
65
+ },
66
+ "peerDependenciesMeta": {
67
+ "@affectively/auth": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "engines": {
72
+ "bun": ">=1.0.0"
73
+ },
74
+ "license": "MIT",
75
+ "repository": {
76
+ "type": "git",
77
+ "url": "git+https://github.com/affectively-ai/aeon-flux.git"
78
+ },
79
+ "keywords": [
80
+ "aeon",
81
+ "flux",
82
+ "crdt",
83
+ "framework",
84
+ "collaborative",
85
+ "cms",
86
+ "real-time",
87
+ "bun",
88
+ "cloudflare",
89
+ "d1",
90
+ "durable-objects",
91
+ "wasm",
92
+ "skeleton",
93
+ "zero-cls",
94
+ "performance"
95
+ ],
96
+ "author": "AFFECTIVELY",
97
+ "homepage": "https://github.com/affectively-ai/aeon-flux#readme",
98
+ "bugs": {
99
+ "url": "https://github.com/affectively-ai/aeon-flux/issues"
100
+ }
101
+ }