@nexus_js/runtime 0.6.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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/cache.d.ts +78 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +132 -0
- package/dist/cache.js.map +1 -0
- package/dist/dev-mode.d.ts +60 -0
- package/dist/dev-mode.d.ts.map +1 -0
- package/dist/dev-mode.js +89 -0
- package/dist/dev-mode.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/island.d.ts +29 -0
- package/dist/island.d.ts.map +1 -0
- package/dist/island.js +161 -0
- package/dist/island.js.map +1 -0
- package/dist/navigation.d.ts +97 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +390 -0
- package/dist/navigation.js.map +1 -0
- package/dist/optimistic.d.ts +67 -0
- package/dist/optimistic.d.ts.map +1 -0
- package/dist/optimistic.js +104 -0
- package/dist/optimistic.js.map +1 -0
- package/dist/prefetch-ai.d.ts +88 -0
- package/dist/prefetch-ai.d.ts.map +1 -0
- package/dist/prefetch-ai.js +277 -0
- package/dist/prefetch-ai.js.map +1 -0
- package/dist/runes.d.ts +61 -0
- package/dist/runes.d.ts.map +1 -0
- package/dist/runes.js +155 -0
- package/dist/runes.js.map +1 -0
- package/dist/store.d.ts +123 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +267 -0
- package/dist/store.js.map +1 -0
- package/dist/sync.d.ts +49 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +156 -0
- package/dist/sync.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nexus Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @nexus_js/runtime
|
|
2
|
+
|
|
3
|
+
Nexus Islands runtime — selective hydration with fine-grained reactivity.
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
All guides, API reference, and examples live on **[nexusjs.dev](https://nexusjs.dev)**.
|
|
8
|
+
|
|
9
|
+
## Links
|
|
10
|
+
|
|
11
|
+
- **Website:** [https://nexusjs.dev](https://nexusjs.dev)
|
|
12
|
+
- **Repository:** [github.com/bierfor/nexus](https://github.com/bierfor/nexus) (see `packages/runtime/`)
|
|
13
|
+
- **Issues:** [github.com/bierfor/nexus/issues](https://github.com/bierfor/nexus/issues)
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT © Nexus contributors
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Cache & Revalidation System.
|
|
3
|
+
*
|
|
4
|
+
* Server-side: Tags routes as cacheable, invalidates on demand.
|
|
5
|
+
* Client-side: Coordinates revalidation after Server Actions.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
*
|
|
9
|
+
* In a server block:
|
|
10
|
+
* const posts = await cache(() => db.post.findMany(), {
|
|
11
|
+
* tags: ['posts'],
|
|
12
|
+
* ttl: 60, // seconds
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* In a Server Action:
|
|
16
|
+
* async function createPost(formData) {
|
|
17
|
+
* "use server";
|
|
18
|
+
* await db.post.create({ ... });
|
|
19
|
+
* await revalidate(['posts']); // Purges cache tag 'posts'
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* After revalidation, any route that fetched with tag 'posts' gets
|
|
23
|
+
* re-rendered on the next request (stale-while-revalidate pattern).
|
|
24
|
+
*/
|
|
25
|
+
export interface CacheOptions {
|
|
26
|
+
/** Tags for targeted invalidation */
|
|
27
|
+
tags?: string[];
|
|
28
|
+
/** Time-to-live in seconds. 0 = no cache. Infinity = permanent. */
|
|
29
|
+
ttl?: number;
|
|
30
|
+
/** Stale-while-revalidate window in seconds */
|
|
31
|
+
swr?: number;
|
|
32
|
+
/** Key override (default: auto-generated from function source) */
|
|
33
|
+
key?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface CacheEntry<T> {
|
|
36
|
+
value: T;
|
|
37
|
+
expiresAt: number;
|
|
38
|
+
swrExpiresAt: number;
|
|
39
|
+
tags: Set<string>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Wraps an async data-fetching function with caching.
|
|
43
|
+
* Implements stale-while-revalidate for zero-latency serving.
|
|
44
|
+
*/
|
|
45
|
+
export declare function cache<T>(fn: () => Promise<T>, opts?: CacheOptions): Promise<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Invalidates all cache entries with the given tags.
|
|
48
|
+
* Call this after Server Actions that mutate data.
|
|
49
|
+
*/
|
|
50
|
+
export declare function revalidate(tags: string[]): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Invalidates a specific cache key (path-based).
|
|
53
|
+
*/
|
|
54
|
+
export declare function revalidatePath(path: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Returns cache statistics for diagnostics.
|
|
57
|
+
*/
|
|
58
|
+
export declare function cacheStats(): {
|
|
59
|
+
size: number;
|
|
60
|
+
tags: number;
|
|
61
|
+
entries: Array<{
|
|
62
|
+
key: string;
|
|
63
|
+
expiresIn: number;
|
|
64
|
+
tags: string[];
|
|
65
|
+
}>;
|
|
66
|
+
};
|
|
67
|
+
export interface CacheAdapter {
|
|
68
|
+
get: (key: string) => Promise<unknown | null>;
|
|
69
|
+
set: (key: string, value: unknown, ttlSeconds: number) => Promise<void>;
|
|
70
|
+
del: (keys: string[]) => Promise<void>;
|
|
71
|
+
tags: {
|
|
72
|
+
add: (tag: string, key: string) => Promise<void>;
|
|
73
|
+
keys: (tag: string) => Promise<string[]>;
|
|
74
|
+
clear: (tag: string) => Promise<void>;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export declare function setCacheAdapter(adapter: CacheAdapter): void;
|
|
78
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB;AAMD;;;GAGG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,CAAC,CAAC,CA0BZ;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACpE,CAWA;AAsDD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC9C,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,EAAE;QACJ,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACvC,CAAC;CACH;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAE3D"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Cache & Revalidation System.
|
|
3
|
+
*
|
|
4
|
+
* Server-side: Tags routes as cacheable, invalidates on demand.
|
|
5
|
+
* Client-side: Coordinates revalidation after Server Actions.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
*
|
|
9
|
+
* In a server block:
|
|
10
|
+
* const posts = await cache(() => db.post.findMany(), {
|
|
11
|
+
* tags: ['posts'],
|
|
12
|
+
* ttl: 60, // seconds
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* In a Server Action:
|
|
16
|
+
* async function createPost(formData) {
|
|
17
|
+
* "use server";
|
|
18
|
+
* await db.post.create({ ... });
|
|
19
|
+
* await revalidate(['posts']); // Purges cache tag 'posts'
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* After revalidation, any route that fetched with tag 'posts' gets
|
|
23
|
+
* re-rendered on the next request (stale-while-revalidate pattern).
|
|
24
|
+
*/
|
|
25
|
+
// ── In-memory cache (replace with Redis adapter in production) ─────────────
|
|
26
|
+
const memCache = new Map();
|
|
27
|
+
const tagIndex = new Map();
|
|
28
|
+
/**
|
|
29
|
+
* Wraps an async data-fetching function with caching.
|
|
30
|
+
* Implements stale-while-revalidate for zero-latency serving.
|
|
31
|
+
*/
|
|
32
|
+
export async function cache(fn, opts = {}) {
|
|
33
|
+
const key = opts.key ?? generateKey(fn);
|
|
34
|
+
const ttl = opts.ttl ?? 60;
|
|
35
|
+
const swr = opts.swr ?? ttl * 2;
|
|
36
|
+
const tags = opts.tags ?? [];
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
const existing = memCache.get(key);
|
|
39
|
+
if (existing) {
|
|
40
|
+
// Fresh hit
|
|
41
|
+
if (now < existing.expiresAt) {
|
|
42
|
+
return existing.value;
|
|
43
|
+
}
|
|
44
|
+
// Stale hit — serve stale, trigger background revalidation
|
|
45
|
+
if (now < existing.swrExpiresAt) {
|
|
46
|
+
revalidateInBackground(key, fn, ttl, swr, tags);
|
|
47
|
+
return existing.value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Cache miss or expired — fetch fresh
|
|
51
|
+
const value = await fn();
|
|
52
|
+
setCache(key, value, ttl, swr, tags);
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Invalidates all cache entries with the given tags.
|
|
57
|
+
* Call this after Server Actions that mutate data.
|
|
58
|
+
*/
|
|
59
|
+
export async function revalidate(tags) {
|
|
60
|
+
for (const tag of tags) {
|
|
61
|
+
const keys = tagIndex.get(tag);
|
|
62
|
+
if (!keys)
|
|
63
|
+
continue;
|
|
64
|
+
for (const key of keys) {
|
|
65
|
+
memCache.delete(key);
|
|
66
|
+
}
|
|
67
|
+
tagIndex.delete(tag);
|
|
68
|
+
}
|
|
69
|
+
console.log(`[Nexus Cache] Invalidated tags: ${tags.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Invalidates a specific cache key (path-based).
|
|
73
|
+
*/
|
|
74
|
+
export async function revalidatePath(path) {
|
|
75
|
+
const key = `path:${path}`;
|
|
76
|
+
memCache.delete(key);
|
|
77
|
+
console.log(`[Nexus Cache] Invalidated path: ${path}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns cache statistics for diagnostics.
|
|
81
|
+
*/
|
|
82
|
+
export function cacheStats() {
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
return {
|
|
85
|
+
size: memCache.size,
|
|
86
|
+
tags: tagIndex.size,
|
|
87
|
+
entries: [...memCache.entries()].map(([key, entry]) => ({
|
|
88
|
+
key,
|
|
89
|
+
expiresIn: Math.max(0, Math.floor((entry.expiresAt - now) / 1000)),
|
|
90
|
+
tags: [...entry.tags],
|
|
91
|
+
})),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
95
|
+
// Internals
|
|
96
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
97
|
+
function setCache(key, value, ttl, swr, tags) {
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
const entry = {
|
|
100
|
+
value,
|
|
101
|
+
expiresAt: now + ttl * 1000,
|
|
102
|
+
swrExpiresAt: now + swr * 1000,
|
|
103
|
+
tags: new Set(tags),
|
|
104
|
+
};
|
|
105
|
+
memCache.set(key, entry);
|
|
106
|
+
// Update tag index
|
|
107
|
+
for (const tag of tags) {
|
|
108
|
+
if (!tagIndex.has(tag))
|
|
109
|
+
tagIndex.set(tag, new Set());
|
|
110
|
+
tagIndex.get(tag).add(key);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function revalidateInBackground(key, fn, ttl, swr, tags) {
|
|
114
|
+
fn()
|
|
115
|
+
.then((value) => setCache(key, value, ttl, swr, tags))
|
|
116
|
+
.catch((err) => console.error(`[Nexus Cache] Background revalidation failed for "${key}":`, err));
|
|
117
|
+
}
|
|
118
|
+
function generateKey(fn) {
|
|
119
|
+
// Use function source as key (stable across hot reloads in dev)
|
|
120
|
+
const src = fn.toString();
|
|
121
|
+
let h = 0x811c9dc5;
|
|
122
|
+
for (let i = 0; i < src.length; i++) {
|
|
123
|
+
h ^= src.charCodeAt(i);
|
|
124
|
+
h = Math.imul(h, 0x01000193);
|
|
125
|
+
}
|
|
126
|
+
return `fn:${(h >>> 0).toString(16)}`;
|
|
127
|
+
}
|
|
128
|
+
let _adapter = null;
|
|
129
|
+
export function setCacheAdapter(adapter) {
|
|
130
|
+
_adapter = adapter;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Runtime Dev Mode — browser-side observability hooks.
|
|
3
|
+
*
|
|
4
|
+
* In dev mode, the renderer injects window.__NEXUS_DEV__ = true and
|
|
5
|
+
* window.__NEXUS_SERVER_LOGS__ into the HTML. This module provides
|
|
6
|
+
* type-safe wrappers that island code and Runes can call to log events
|
|
7
|
+
* into the browser DevTools console.
|
|
8
|
+
*
|
|
9
|
+
* All functions are no-ops in production (window.__NEXUS_DEV__ is falsy).
|
|
10
|
+
* Tree-shaking removes the import entirely in production builds.
|
|
11
|
+
*/
|
|
12
|
+
type ActionPhase = 'call' | 'optimistic' | 'success' | 'error' | 'cancelled';
|
|
13
|
+
/**
|
|
14
|
+
* Log an island hydration event.
|
|
15
|
+
* Called by the island loader after `component.mount()` completes.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Inside @nexus_js/runtime island.ts
|
|
19
|
+
* logIslandHydration('SearchBar', 'client:load', performance.now() - t0);
|
|
20
|
+
*/
|
|
21
|
+
export declare function logIslandHydration(componentName: string, strategy: string, durationMs: number): void;
|
|
22
|
+
/**
|
|
23
|
+
* Log a reactive $state change.
|
|
24
|
+
* Called by the dev-mode Runes proxy when a signal's value is written.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Inside $state() implementation (dev mode)
|
|
28
|
+
* logStateChange('hp', 100, 88, 'AttackButton');
|
|
29
|
+
*/
|
|
30
|
+
export declare function logStateChange(key: string, prev: unknown, next: unknown, source?: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Log an $optimistic state update before the server responds.
|
|
33
|
+
* Called by the $optimistic() rune when the pessimistic state is applied.
|
|
34
|
+
*/
|
|
35
|
+
export declare function logOptimisticUpdate(key: string, value: unknown): void;
|
|
36
|
+
/**
|
|
37
|
+
* Log a SPA navigation event (Nexus DOM Morphing).
|
|
38
|
+
* Called by the client router before and after morphing.
|
|
39
|
+
*/
|
|
40
|
+
export declare function logNavigation(to: string, morphKey?: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Log a Server Action lifecycle event.
|
|
43
|
+
* Called by the action client at each phase.
|
|
44
|
+
*
|
|
45
|
+
* @param name - Action name (e.g. 'capture_pokemon')
|
|
46
|
+
* @param phase - 'call' | 'optimistic' | 'success' | 'error' | 'cancelled'
|
|
47
|
+
* @param data - Optional payload (optimistic value, error message, etc.)
|
|
48
|
+
*/
|
|
49
|
+
export declare function logAction(name: string, phase: ActionPhase, data?: unknown): void;
|
|
50
|
+
/**
|
|
51
|
+
* Returns a dev-mode proxy for a $state signal.
|
|
52
|
+
* Wraps the signal so every `.set()` call emits a logStateChange() entry.
|
|
53
|
+
* In production, returns the original signal unmodified (zero overhead).
|
|
54
|
+
*/
|
|
55
|
+
export declare function devProxy<T>(signal: {
|
|
56
|
+
get: () => T;
|
|
57
|
+
set: (v: T) => void;
|
|
58
|
+
}, key: string, source?: string): typeof signal;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=dev-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-mode.d.ts","sourceRoot":"","sources":["../src/dev-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8BH,KAAK,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;AAU7E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,IAAI,CAGN;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGrE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAGjE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,EAClB,IAAI,CAAC,EAAE,OAAO,GACb,IAAI,CAGN;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;CAAE,EAC7C,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,MAAM,CAWf"}
|
package/dist/dev-mode.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Runtime Dev Mode — browser-side observability hooks.
|
|
3
|
+
*
|
|
4
|
+
* In dev mode, the renderer injects window.__NEXUS_DEV__ = true and
|
|
5
|
+
* window.__NEXUS_SERVER_LOGS__ into the HTML. This module provides
|
|
6
|
+
* type-safe wrappers that island code and Runes can call to log events
|
|
7
|
+
* into the browser DevTools console.
|
|
8
|
+
*
|
|
9
|
+
* All functions are no-ops in production (window.__NEXUS_DEV__ is falsy).
|
|
10
|
+
* Tree-shaking removes the import entirely in production builds.
|
|
11
|
+
*/
|
|
12
|
+
// ── Guard ─────────────────────────────────────────────────────────────────────
|
|
13
|
+
const isDev = () => typeof window !== 'undefined' && window.__NEXUS_DEV__ === true;
|
|
14
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Log an island hydration event.
|
|
17
|
+
* Called by the island loader after `component.mount()` completes.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Inside @nexus_js/runtime island.ts
|
|
21
|
+
* logIslandHydration('SearchBar', 'client:load', performance.now() - t0);
|
|
22
|
+
*/
|
|
23
|
+
export function logIslandHydration(componentName, strategy, durationMs) {
|
|
24
|
+
if (!isDev())
|
|
25
|
+
return;
|
|
26
|
+
window.__NEXUS_LOG_ISLAND__?.(componentName, strategy, durationMs);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Log a reactive $state change.
|
|
30
|
+
* Called by the dev-mode Runes proxy when a signal's value is written.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Inside $state() implementation (dev mode)
|
|
34
|
+
* logStateChange('hp', 100, 88, 'AttackButton');
|
|
35
|
+
*/
|
|
36
|
+
export function logStateChange(key, prev, next, source) {
|
|
37
|
+
if (!isDev())
|
|
38
|
+
return;
|
|
39
|
+
window.__NEXUS_LOG_STATE__?.(key, prev, next, source);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Log an $optimistic state update before the server responds.
|
|
43
|
+
* Called by the $optimistic() rune when the pessimistic state is applied.
|
|
44
|
+
*/
|
|
45
|
+
export function logOptimisticUpdate(key, value) {
|
|
46
|
+
if (!isDev())
|
|
47
|
+
return;
|
|
48
|
+
window.__NEXUS_LOG_OPTIMISTIC__?.(key, value);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Log a SPA navigation event (Nexus DOM Morphing).
|
|
52
|
+
* Called by the client router before and after morphing.
|
|
53
|
+
*/
|
|
54
|
+
export function logNavigation(to, morphKey) {
|
|
55
|
+
if (!isDev())
|
|
56
|
+
return;
|
|
57
|
+
window.__NEXUS_LOG_NAV__?.(to, morphKey);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Log a Server Action lifecycle event.
|
|
61
|
+
* Called by the action client at each phase.
|
|
62
|
+
*
|
|
63
|
+
* @param name - Action name (e.g. 'capture_pokemon')
|
|
64
|
+
* @param phase - 'call' | 'optimistic' | 'success' | 'error' | 'cancelled'
|
|
65
|
+
* @param data - Optional payload (optimistic value, error message, etc.)
|
|
66
|
+
*/
|
|
67
|
+
export function logAction(name, phase, data) {
|
|
68
|
+
if (!isDev())
|
|
69
|
+
return;
|
|
70
|
+
window.__NEXUS_LOG_ACTION__?.(name, phase, data);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns a dev-mode proxy for a $state signal.
|
|
74
|
+
* Wraps the signal so every `.set()` call emits a logStateChange() entry.
|
|
75
|
+
* In production, returns the original signal unmodified (zero overhead).
|
|
76
|
+
*/
|
|
77
|
+
export function devProxy(signal, key, source) {
|
|
78
|
+
if (!isDev())
|
|
79
|
+
return signal;
|
|
80
|
+
return {
|
|
81
|
+
get: () => signal.get(),
|
|
82
|
+
set: (next) => {
|
|
83
|
+
const prev = signal.get();
|
|
84
|
+
logStateChange(key, prev, next, source);
|
|
85
|
+
signal.set(next);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=dev-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-mode.js","sourceRoot":"","sources":["../src/dev-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkCH,iFAAiF;AACjF,MAAM,KAAK,GAAG,GAAY,EAAE,CAC1B,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,CAAC;AAEjE,iFAAiF;AAEjF;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAqB,EACrB,QAAgB,EAChB,UAAkB;IAElB,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO;IACrB,MAAM,CAAC,oBAAoB,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,IAAa,EACb,IAAa,EACb,MAAe;IAEf,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO;IACrB,MAAM,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,KAAc;IAC7D,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO;IACrB,MAAM,CAAC,wBAAwB,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU,EAAE,QAAiB;IACzD,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO;IACrB,MAAM,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,KAAkB,EAClB,IAAc;IAEd,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO;IACrB,MAAM,CAAC,oBAAoB,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CACtB,MAA6C,EAC7C,GAAW,EACX,MAAe;IAEf,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,MAAM,CAAC;IAE5B,OAAO;QACL,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE;QACvB,GAAG,EAAE,CAAC,IAAO,EAAE,EAAE;YACf,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;YAC1B,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YACxC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { $state, $derived, $effect, $props, batch } from './runes.js';
|
|
2
|
+
export { createIsland, hydrateAll } from './island.js';
|
|
3
|
+
export type { HydrationStrategy, IslandOptions, IslandInstance } from './island.js';
|
|
4
|
+
export { $optimistic, createOptimistic } from './optimistic.js';
|
|
5
|
+
export type { OptimisticUpdate } from './optimistic.js';
|
|
6
|
+
export { $sync } from './sync.js';
|
|
7
|
+
export type { SyncOptions, SyncedSignal, SyncPersistence } from './sync.js';
|
|
8
|
+
export { cache, revalidate, revalidatePath, cacheStats, setCacheAdapter } from './cache.js';
|
|
9
|
+
export type { CacheOptions, CacheAdapter } from './cache.js';
|
|
10
|
+
export { navigate, prefetch, initNavigation, navigation } from './navigation.js';
|
|
11
|
+
export type { NavigateOptions, NavigationState } from './navigation.js';
|
|
12
|
+
export { useStore, readStore, writeStore, snapshotStore, importStore, exportStore, clearStore, storeDebugInfo } from './store.js';
|
|
13
|
+
export type { StoreOptions, StoreEntry } from './store.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5F,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjF,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAClI,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { $state, $derived, $effect, $props, batch } from './runes.js';
|
|
2
|
+
export { createIsland, hydrateAll } from './island.js';
|
|
3
|
+
export { $optimistic, createOptimistic } from './optimistic.js';
|
|
4
|
+
export { $sync } from './sync.js';
|
|
5
|
+
export { cache, revalidate, revalidatePath, cacheStats, setCacheAdapter } from './cache.js';
|
|
6
|
+
export { navigate, prefetch, initNavigation, navigation } from './navigation.js';
|
|
7
|
+
export { useStore, readStore, writeStore, snapshotStore, importStore, exportStore, clearStore, storeDebugInfo } from './store.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE5F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEjF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/island.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Island Runtime — selective hydration engine.
|
|
3
|
+
* Activates interactive "islands" on an otherwise static HTML page.
|
|
4
|
+
*/
|
|
5
|
+
import { $state, $derived, $effect, batch } from './runes.js';
|
|
6
|
+
export { $state, $derived, $effect, batch };
|
|
7
|
+
export type HydrationStrategy = 'client:load' | 'client:idle' | 'client:visible' | 'client:media' | 'server:only';
|
|
8
|
+
export interface IslandOptions {
|
|
9
|
+
template: string;
|
|
10
|
+
strategy?: HydrationStrategy;
|
|
11
|
+
props?: Record<string, unknown>;
|
|
12
|
+
mediaQuery?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface IslandInstance {
|
|
15
|
+
el: Element;
|
|
16
|
+
destroy: () => void;
|
|
17
|
+
update: (props: Record<string, unknown>) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Core island hydration function.
|
|
21
|
+
* Called by the generated client module for each interactive island.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createIsland(el: Element, opts: IslandOptions): IslandInstance;
|
|
24
|
+
/**
|
|
25
|
+
* Scans the document for islands and hydrates them according to their strategy.
|
|
26
|
+
* Called once on page load by the Nexus bootstrap script.
|
|
27
|
+
*/
|
|
28
|
+
export declare function hydrateAll(): void;
|
|
29
|
+
//# sourceMappingURL=island.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island.d.ts","sourceRoot":"","sources":["../src/island.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAE5C,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAClD;AAKD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,OAAO,EACX,IAAI,EAAE,aAAa,GAClB,cAAc,CA0ChB;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAyBjC"}
|
package/dist/island.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Island Runtime — selective hydration engine.
|
|
3
|
+
* Activates interactive "islands" on an otherwise static HTML page.
|
|
4
|
+
*/
|
|
5
|
+
import { $state, $derived, $effect, batch } from './runes.js';
|
|
6
|
+
export { $state, $derived, $effect, batch };
|
|
7
|
+
/** Registry of all mounted islands on the page */
|
|
8
|
+
const islandRegistry = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* Core island hydration function.
|
|
11
|
+
* Called by the generated client module for each interactive island.
|
|
12
|
+
*/
|
|
13
|
+
export function createIsland(el, opts) {
|
|
14
|
+
const cleanups = [];
|
|
15
|
+
function hydrate() {
|
|
16
|
+
// Inject props as reactive signals
|
|
17
|
+
const propSignals = {};
|
|
18
|
+
for (const [key, val] of Object.entries(opts.props ?? {})) {
|
|
19
|
+
propSignals[key] = $state(val);
|
|
20
|
+
}
|
|
21
|
+
// Mark element as hydrated
|
|
22
|
+
el.setAttribute('data-nexus-hydrated', 'true');
|
|
23
|
+
// Attach event listeners from data attributes
|
|
24
|
+
attachEventListeners(el, propSignals, cleanups);
|
|
25
|
+
}
|
|
26
|
+
function destroy() {
|
|
27
|
+
for (const cleanup of cleanups)
|
|
28
|
+
cleanup();
|
|
29
|
+
el.removeAttribute('data-nexus-hydrated');
|
|
30
|
+
const id = el.getAttribute('data-nexus-island');
|
|
31
|
+
if (id)
|
|
32
|
+
islandRegistry.delete(id);
|
|
33
|
+
}
|
|
34
|
+
function update(newProps) {
|
|
35
|
+
batch(() => {
|
|
36
|
+
for (const [key, val] of Object.entries(newProps)) {
|
|
37
|
+
if (el.hasAttribute(`data-prop-${key}`)) {
|
|
38
|
+
el.setAttribute(`data-prop-${key}`, String(val));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
hydrate();
|
|
44
|
+
const instance = { el, destroy, update };
|
|
45
|
+
const islandId = el.getAttribute('data-nexus-island') ?? crypto.randomUUID();
|
|
46
|
+
el.setAttribute('data-nexus-island', islandId);
|
|
47
|
+
islandRegistry.set(islandId, instance);
|
|
48
|
+
return instance;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Scans the document for islands and hydrates them according to their strategy.
|
|
52
|
+
* Called once on page load by the Nexus bootstrap script.
|
|
53
|
+
*/
|
|
54
|
+
export function hydrateAll() {
|
|
55
|
+
const islands = document.querySelectorAll('[data-nexus-island]');
|
|
56
|
+
for (const el of islands) {
|
|
57
|
+
const strategy = (el.getAttribute('data-nexus-strategy') ??
|
|
58
|
+
'client:load');
|
|
59
|
+
switch (strategy) {
|
|
60
|
+
case 'client:load':
|
|
61
|
+
scheduleHydration(el, () => hydrateElement(el));
|
|
62
|
+
break;
|
|
63
|
+
case 'client:idle':
|
|
64
|
+
requestIdleCallback(() => hydrateElement(el), { timeout: 2000 });
|
|
65
|
+
break;
|
|
66
|
+
case 'client:visible':
|
|
67
|
+
hydrateOnVisible(el);
|
|
68
|
+
break;
|
|
69
|
+
case 'client:media':
|
|
70
|
+
hydrateOnMedia(el);
|
|
71
|
+
break;
|
|
72
|
+
case 'server:only':
|
|
73
|
+
// Never hydrate — server rendered HTML only
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function scheduleHydration(el, fn) {
|
|
79
|
+
// Use microtask to avoid blocking paint
|
|
80
|
+
queueMicrotask(fn);
|
|
81
|
+
}
|
|
82
|
+
async function hydrateElement(el) {
|
|
83
|
+
if (el.getAttribute('data-nexus-hydrated') === 'true')
|
|
84
|
+
return;
|
|
85
|
+
const componentPath = el.getAttribute('data-nexus-component');
|
|
86
|
+
if (!componentPath)
|
|
87
|
+
return;
|
|
88
|
+
try {
|
|
89
|
+
// Dynamic import of the island's client bundle
|
|
90
|
+
const mod = await import(/* @vite-ignore */ componentPath);
|
|
91
|
+
if (typeof mod.mount === 'function') {
|
|
92
|
+
const props = getPropsFromElement(el);
|
|
93
|
+
mod.mount(el, props);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
console.error(`[Nexus] Failed to hydrate island at ${componentPath}:`, err);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function hydrateOnVisible(el) {
|
|
101
|
+
const observer = new IntersectionObserver((entries) => {
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (entry.isIntersecting) {
|
|
104
|
+
observer.unobserve(el);
|
|
105
|
+
hydrateElement(el);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, { rootMargin: '50px' });
|
|
109
|
+
observer.observe(el);
|
|
110
|
+
}
|
|
111
|
+
function hydrateOnMedia(el) {
|
|
112
|
+
const query = el.getAttribute('data-nexus-media') ?? '';
|
|
113
|
+
const mq = window.matchMedia(query);
|
|
114
|
+
const check = () => {
|
|
115
|
+
if (mq.matches) {
|
|
116
|
+
mq.removeEventListener('change', check);
|
|
117
|
+
hydrateElement(el);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
check();
|
|
121
|
+
mq.addEventListener('change', check);
|
|
122
|
+
}
|
|
123
|
+
function getPropsFromElement(el) {
|
|
124
|
+
const props = {};
|
|
125
|
+
const raw = el.getAttribute('data-nexus-props');
|
|
126
|
+
if (raw) {
|
|
127
|
+
try {
|
|
128
|
+
Object.assign(props, JSON.parse(atob(raw)));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Invalid props encoding
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return props;
|
|
135
|
+
}
|
|
136
|
+
function attachEventListeners(el, _signals, cleanups) {
|
|
137
|
+
// Find all [data-on-*] attributes and attach listeners
|
|
138
|
+
for (const attr of el.attributes) {
|
|
139
|
+
if (!attr.name.startsWith('data-on-'))
|
|
140
|
+
continue;
|
|
141
|
+
const eventName = attr.name.slice('data-on-'.length);
|
|
142
|
+
const handlerName = attr.value;
|
|
143
|
+
const handler = (e) => {
|
|
144
|
+
const fn = window[handlerName];
|
|
145
|
+
if (typeof fn === 'function')
|
|
146
|
+
fn(e);
|
|
147
|
+
};
|
|
148
|
+
el.addEventListener(eventName, handler);
|
|
149
|
+
cleanups.push(() => el.removeEventListener(eventName, handler));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Bootstrap: auto-runs when the runtime script loads in the browser */
|
|
153
|
+
if (typeof document !== 'undefined') {
|
|
154
|
+
if (document.readyState === 'loading') {
|
|
155
|
+
document.addEventListener('DOMContentLoaded', hydrateAll);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
hydrateAll();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=island.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island.js","sourceRoot":"","sources":["../src/island.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAsB5C,kDAAkD;AAClD,MAAM,cAAc,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,EAAW,EACX,IAAmB;IAEnB,MAAM,QAAQ,GAAsB,EAAE,CAAC;IAEvC,SAAS,OAAO;QACd,mCAAmC;QACnC,MAAM,WAAW,GAAuC,EAAE,CAAC;QAC3D,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1D,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAED,2BAA2B;QAC3B,EAAE,CAAC,YAAY,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;QAE/C,8CAA8C;QAC9C,oBAAoB,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED,SAAS,OAAO;QACd,KAAK,MAAM,OAAO,IAAI,QAAQ;YAAE,OAAO,EAAE,CAAC;QAC1C,EAAE,CAAC,eAAe,CAAC,qBAAqB,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC;QAChD,IAAI,EAAE;YAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,SAAS,MAAM,CAAC,QAAiC;QAC/C,KAAK,CAAC,GAAG,EAAE;YACT,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClD,IAAI,EAAE,CAAC,YAAY,CAAC,aAAa,GAAG,EAAE,CAAC,EAAE,CAAC;oBACxC,EAAE,CAAC,YAAY,CAAC,aAAa,GAAG,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;IAEV,MAAM,QAAQ,GAAmB,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7E,EAAE,CAAC,YAAY,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;IAC/C,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEvC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;IAEjE,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,qBAAqB,CAAC;YACtD,aAAa,CAAsB,CAAC;QAEtC,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,aAAa;gBAChB,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChD,MAAM;YACR,KAAK,aAAa;gBAChB,mBAAmB,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjE,MAAM;YACR,KAAK,gBAAgB;gBACnB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACrB,MAAM;YACR,KAAK,cAAc;gBACjB,cAAc,CAAC,EAAE,CAAC,CAAC;gBACnB,MAAM;YACR,KAAK,aAAa;gBAChB,4CAA4C;gBAC5C,MAAM;QACV,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAW,EAAE,EAAc;IACpD,wCAAwC;IACxC,cAAc,CAAC,EAAE,CAAC,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,EAAW;IACvC,IAAI,EAAE,CAAC,YAAY,CAAC,qBAAqB,CAAC,KAAK,MAAM;QAAE,OAAO;IAE9D,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC;IAC9D,IAAI,CAAC,aAAa;QAAE,OAAO;IAE3B,IAAI,CAAC;QACH,+CAA+C;QAC/C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;QAC3D,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAC;YACtC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,aAAa,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAW;IACnC,MAAM,QAAQ,GAAG,IAAI,oBAAoB,CACvC,CAAC,OAAO,EAAE,EAAE;QACV,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;gBACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBACvB,cAAc,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC,EACD,EAAE,UAAU,EAAE,MAAM,EAAE,CACvB,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,cAAc,CAAC,EAAW;IACjC,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;YACf,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACxC,cAAc,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,EAAE,CAAC;IACR,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAW;IACtC,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;IAChD,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,oBAAoB,CAC3B,EAAW,EACX,QAA4C,EAC5C,QAA2B;IAE3B,uDAAuD;IACvD,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QAChD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC;QAE/B,MAAM,OAAO,GAAG,CAAC,CAAQ,EAAQ,EAAE;YACjC,MAAM,EAAE,GAAI,MAA6C,CAAC,WAAW,CAAC,CAAC;YACvE,IAAI,OAAO,EAAE,KAAK,UAAU;gBAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC;QAEF,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;IACpC,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACtC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;IAC5D,CAAC;SAAM,CAAC;QACN,UAAU,EAAE,CAAC;IACf,CAAC;AACH,CAAC"}
|