@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
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Optimistic UI — `$optimistic` rune.
|
|
3
|
+
*
|
|
4
|
+
* Updates the UI instantly before the server responds.
|
|
5
|
+
* Rolls back automatically if the server action fails.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const likes = $state(post.likes);
|
|
9
|
+
*
|
|
10
|
+
* function handleLike() {
|
|
11
|
+
* $optimistic(
|
|
12
|
+
* likes,
|
|
13
|
+
* () => likePost(post.id), // Server Action
|
|
14
|
+
* post.likes // rollback value
|
|
15
|
+
* );
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* What happens:
|
|
19
|
+
* 1. `likes.value` jumps to `likes.value + 1` immediately (UI updates)
|
|
20
|
+
* 2. Server Action runs in background
|
|
21
|
+
* 3a. Success → server value is confirmed (or replaced with server result)
|
|
22
|
+
* 3b. Failure → `likes.value` rolls back to `post.likes`
|
|
23
|
+
*/
|
|
24
|
+
import { $state } from './runes.js';
|
|
25
|
+
/**
|
|
26
|
+
* Wraps a server action with optimistic UI.
|
|
27
|
+
* The signal is updated immediately; rolls back on error.
|
|
28
|
+
*
|
|
29
|
+
* @param signal - A $state signal to update optimistically
|
|
30
|
+
* @param action - Async function that calls the server (returns new value or void)
|
|
31
|
+
* @param rollback - Value to restore if the action fails (defaults to current value)
|
|
32
|
+
*/
|
|
33
|
+
export async function $optimistic(signal, action, rollback) {
|
|
34
|
+
const savedValue = rollback ?? signal.value;
|
|
35
|
+
// Apply optimistic update immediately — UI reflects change before server
|
|
36
|
+
const optimisticResult = guessNextValue(signal.value);
|
|
37
|
+
if (optimisticResult !== undefined) {
|
|
38
|
+
signal.value = optimisticResult;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const serverResult = await action();
|
|
42
|
+
// Server returned a canonical value — use it
|
|
43
|
+
if (serverResult !== undefined && serverResult !== null) {
|
|
44
|
+
signal.value = serverResult;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
// Roll back to the saved value on any error
|
|
49
|
+
signal.value = savedValue;
|
|
50
|
+
console.warn('[Nexus $optimistic] Action failed, rolling back:', err);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a full optimistic action controller with pending/error state.
|
|
55
|
+
* More powerful than bare $optimistic — gives you loading indicators too.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const likeAction = createOptimistic(likes, () => likePost(post.id));
|
|
59
|
+
* <button onclick={likeAction.execute} disabled={likeAction.pending}>
|
|
60
|
+
* {likeAction.pending ? '...' : likes.value} likes
|
|
61
|
+
* </button>
|
|
62
|
+
*/
|
|
63
|
+
export function createOptimistic(signal, action, opts = {}) {
|
|
64
|
+
const pending = $state(false);
|
|
65
|
+
const error = $state(null);
|
|
66
|
+
const execute = async () => {
|
|
67
|
+
if (pending.value)
|
|
68
|
+
return; // Prevent double-submit
|
|
69
|
+
const savedValue = signal.value;
|
|
70
|
+
error.value = null;
|
|
71
|
+
pending.value = true;
|
|
72
|
+
// Apply optimistic update
|
|
73
|
+
if (opts.optimisticValue) {
|
|
74
|
+
signal.value = opts.optimisticValue(savedValue);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const result = await action(savedValue);
|
|
78
|
+
if (result !== undefined && result !== null) {
|
|
79
|
+
signal.value = result;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
signal.value = savedValue;
|
|
84
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
85
|
+
error.value = msg;
|
|
86
|
+
opts.onError?.(err);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
pending.value = false;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
return { execute, pending, error };
|
|
93
|
+
}
|
|
94
|
+
/** Heuristic: guess next value for common types (numbers, booleans, arrays) */
|
|
95
|
+
function guessNextValue(current) {
|
|
96
|
+
if (typeof current === 'number')
|
|
97
|
+
return (current + 1);
|
|
98
|
+
if (typeof current === 'boolean')
|
|
99
|
+
return (!current);
|
|
100
|
+
if (Array.isArray(current))
|
|
101
|
+
return [...current]; // shallow clone
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=optimistic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimistic.js","sourceRoot":"","sources":["../src/optimistic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,MAAM,EAAW,MAAM,YAAY,CAAC;AAW7C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAoB,EACpB,MAA+B,EAC/B,QAAY;IAEZ,MAAM,UAAU,GAAG,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC;IAE5C,yEAAyE;IACzE,MAAM,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,KAAK,GAAG,gBAAqB,CAAC;IACvC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,MAAM,EAAE,CAAC;QACpC,6CAA6C;QAC7C,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YACxD,MAAM,CAAC,KAAK,GAAG,YAAY,CAAC;QAC9B,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,4CAA4C;QAC5C,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,kDAAkD,EAAE,GAAG,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAoB,EACpB,MAAyC,EACzC,OAGI,EAAE;IAMN,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACxC,IAAI,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,wBAAwB;QAEnD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;QAChC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;QAErB,0BAA0B;QAC1B,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;YACxC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC5C,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC;YACxB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC;YAC1B,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC;YAClB,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACrC,CAAC;AAED,+EAA+E;AAC/E,SAAS,cAAc,CAAI,OAAU;IACnC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,CAAC,OAAO,GAAG,CAAC,CAAM,CAAC;IAC3D,IAAI,OAAO,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,OAAO,CAAM,CAAC;IACzD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,GAAG,OAAO,CAAM,CAAC,CAAC,gBAAgB;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus AI Prefetch — Network-Aware Predictive Prefetching.
|
|
3
|
+
*
|
|
4
|
+
* Philosophy: "Spend better, not more."
|
|
5
|
+
*
|
|
6
|
+
* Pipeline:
|
|
7
|
+
* 1. Network check (Network Information API)
|
|
8
|
+
* → Save-Data ON → kill switch, log reason, exit
|
|
9
|
+
* → effectiveType 2g/3g → skip, log reason, exit
|
|
10
|
+
* → budget exhausted → skip, log reason
|
|
11
|
+
* 2. Read server probability manifest (/nexus-prefetch-manifest.json)
|
|
12
|
+
* → Cached in sessionStorage, refreshed every 5min
|
|
13
|
+
* 3. Look up predictions for current route
|
|
14
|
+
* → Only prefetch if probability ≥ threshold (default 0.85)
|
|
15
|
+
* 4. Inject <link rel="prefetch"> for HTML only (Zero-JS prefetch)
|
|
16
|
+
* → Island JS is NOT prefetched until hover/focus
|
|
17
|
+
* 5. Track session budget — stop when exceeded
|
|
18
|
+
*/
|
|
19
|
+
export type PrefetchMode = 'aggressive' | 'smart' | 'conservative' | 'off';
|
|
20
|
+
export interface AIPrefetchConfig {
|
|
21
|
+
/** Prefetch strategy (default: 'smart') */
|
|
22
|
+
mode: PrefetchMode;
|
|
23
|
+
/** Confidence threshold 0–1 to trigger prefetch (default: 0.85) */
|
|
24
|
+
threshold: number;
|
|
25
|
+
/** Max bytes to prefetch per browser session (default: 500KB) */
|
|
26
|
+
budget: number;
|
|
27
|
+
/** Only prefetch on WiFi or 4G (default: true) */
|
|
28
|
+
wifiOnly: boolean;
|
|
29
|
+
/** Respect navigator.connection.saveData (default: true) */
|
|
30
|
+
respectSaveData: boolean;
|
|
31
|
+
/** URL of the server-generated probability manifest */
|
|
32
|
+
manifestUrl: string;
|
|
33
|
+
}
|
|
34
|
+
export interface PrefetchPrediction {
|
|
35
|
+
to: string;
|
|
36
|
+
probability: number;
|
|
37
|
+
/** Estimated bytes of the prefetched resource */
|
|
38
|
+
estimatedBytes?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface PrefetchManifest {
|
|
41
|
+
generated: number;
|
|
42
|
+
routes: Record<string, PrefetchPrediction[]>;
|
|
43
|
+
version: string;
|
|
44
|
+
}
|
|
45
|
+
export interface PrefetchDecision {
|
|
46
|
+
willPrefetch: boolean;
|
|
47
|
+
reason: SkipReason | null;
|
|
48
|
+
predictions: PrefetchPrediction[];
|
|
49
|
+
prefetched: string[];
|
|
50
|
+
}
|
|
51
|
+
export type SkipReason = 'mode-off' | 'save-data' | 'slow-connection' | 'budget-exhausted' | 'no-predictions' | 'low-confidence' | 'already-prefetched';
|
|
52
|
+
/**
|
|
53
|
+
* Run the AI prefetch engine for the current route.
|
|
54
|
+
* Call this after each navigation or on page load.
|
|
55
|
+
*
|
|
56
|
+
* @param currentPath - Current route pathname
|
|
57
|
+
* @param config - Optional config overrides (merged with defaults)
|
|
58
|
+
* @returns PrefetchDecision — what was prefetched and why (or why not)
|
|
59
|
+
*/
|
|
60
|
+
export declare function runAIPrefetch(currentPath: string, config?: Partial<AIPrefetchConfig>): Promise<PrefetchDecision>;
|
|
61
|
+
/**
|
|
62
|
+
* Record a navigation transition for the client-side Markov chain.
|
|
63
|
+
* Call this on every route change: recordNavigation('/pokemon/25', '/pokemon/26').
|
|
64
|
+
*/
|
|
65
|
+
export declare function recordNavigation(from: string, to: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* Build an in-browser probability manifest from observed navigation patterns.
|
|
68
|
+
* Useful for apps that can't generate a server-side manifest.
|
|
69
|
+
*/
|
|
70
|
+
export declare function buildClientManifest(minConfidence?: number): PrefetchManifest;
|
|
71
|
+
/**
|
|
72
|
+
* Creates a configured AI prefetch runner — use this in your nexus.config.ts.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // nexus.config.ts
|
|
76
|
+
* import { defineAIPrefetch } from '@nexus_js/runtime/prefetch-ai';
|
|
77
|
+
* export default defineNexusConfig({
|
|
78
|
+
* ai: defineAIPrefetch({
|
|
79
|
+
* mode: 'smart',
|
|
80
|
+
* budget: '500kb',
|
|
81
|
+
* wifiOnly: true,
|
|
82
|
+
* })
|
|
83
|
+
* });
|
|
84
|
+
*/
|
|
85
|
+
export declare function defineAIPrefetch(config?: Partial<AIPrefetchConfig> & {
|
|
86
|
+
budget?: string | number;
|
|
87
|
+
}): AIPrefetchConfig;
|
|
88
|
+
//# sourceMappingURL=prefetch-ai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch-ai.d.ts","sourceRoot":"","sources":["../src/prefetch-ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,cAAc,GAAG,KAAK,CAAC;AAE3E,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,IAAI,EAAa,YAAY,CAAC;IAC9B,mEAAmE;IACnE,SAAS,EAAQ,MAAM,CAAC;IACxB,iEAAiE;IACjE,MAAM,EAAW,MAAM,CAAC;IACxB,kDAAkD;IAClD,QAAQ,EAAS,OAAO,CAAC;IACzB,4DAA4D;IAC5D,eAAe,EAAE,OAAO,CAAC;IACzB,uDAAuD;IACvD,WAAW,EAAM,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAW,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAI,MAAM,CAAC;IACpB,MAAM,EAAO,MAAM,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAClD,OAAO,EAAM,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAQ,UAAU,GAAG,IAAI,CAAC;IAChC,WAAW,EAAG,kBAAkB,EAAE,CAAC;IACnC,UAAU,EAAI,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,kBAAkB,GAClB,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,CAAC;AA0HzB;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA4E3B;AAiBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAM/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,SAAM,GAAG,gBAAgB,CAczE;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAO,GAAG,gBAAgB,CAMxH"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus AI Prefetch — Network-Aware Predictive Prefetching.
|
|
3
|
+
*
|
|
4
|
+
* Philosophy: "Spend better, not more."
|
|
5
|
+
*
|
|
6
|
+
* Pipeline:
|
|
7
|
+
* 1. Network check (Network Information API)
|
|
8
|
+
* → Save-Data ON → kill switch, log reason, exit
|
|
9
|
+
* → effectiveType 2g/3g → skip, log reason, exit
|
|
10
|
+
* → budget exhausted → skip, log reason
|
|
11
|
+
* 2. Read server probability manifest (/nexus-prefetch-manifest.json)
|
|
12
|
+
* → Cached in sessionStorage, refreshed every 5min
|
|
13
|
+
* 3. Look up predictions for current route
|
|
14
|
+
* → Only prefetch if probability ≥ threshold (default 0.85)
|
|
15
|
+
* 4. Inject <link rel="prefetch"> for HTML only (Zero-JS prefetch)
|
|
16
|
+
* → Island JS is NOT prefetched until hover/focus
|
|
17
|
+
* 5. Track session budget — stop when exceeded
|
|
18
|
+
*/
|
|
19
|
+
// ── Internal state ─────────────────────────────────────────────────────────────
|
|
20
|
+
const SESSION_KEY_BUDGET = '__nexus_prefetch_budget__';
|
|
21
|
+
const SESSION_KEY_PREFETCHED = '__nexus_prefetched__';
|
|
22
|
+
const SESSION_KEY_MANIFEST = '__nexus_manifest__';
|
|
23
|
+
const MANIFEST_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
24
|
+
const DEFAULT_CONFIG = {
|
|
25
|
+
mode: 'smart',
|
|
26
|
+
threshold: 0.85,
|
|
27
|
+
budget: 500 * 1024, // 500KB
|
|
28
|
+
wifiOnly: true,
|
|
29
|
+
respectSaveData: true,
|
|
30
|
+
manifestUrl: '/nexus-prefetch-manifest.json',
|
|
31
|
+
};
|
|
32
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
33
|
+
function getConnection() {
|
|
34
|
+
const nav = navigator;
|
|
35
|
+
return nav.connection ?? nav.mozConnection ?? nav.webkitConnection ?? null;
|
|
36
|
+
}
|
|
37
|
+
function getEffectiveType() {
|
|
38
|
+
return getConnection()?.effectiveType ?? 'unknown';
|
|
39
|
+
}
|
|
40
|
+
function isSaveDataEnabled() {
|
|
41
|
+
return getConnection()?.saveData === true;
|
|
42
|
+
}
|
|
43
|
+
function isConnectionFast(wifiOnly) {
|
|
44
|
+
const type = getEffectiveType();
|
|
45
|
+
if (type === '4g')
|
|
46
|
+
return true;
|
|
47
|
+
if (type === '3g' && !wifiOnly)
|
|
48
|
+
return true;
|
|
49
|
+
if (type === '2g' || type === 'slow-2g')
|
|
50
|
+
return false;
|
|
51
|
+
// Unknown — assume ok (desktop, no Network API)
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function getBudgetUsed() {
|
|
55
|
+
return parseInt(sessionStorage.getItem(SESSION_KEY_BUDGET) ?? '0', 10);
|
|
56
|
+
}
|
|
57
|
+
function addBudgetUsed(bytes) {
|
|
58
|
+
sessionStorage.setItem(SESSION_KEY_BUDGET, String(getBudgetUsed() + bytes));
|
|
59
|
+
}
|
|
60
|
+
function getPrefetched() {
|
|
61
|
+
try {
|
|
62
|
+
return new Set(JSON.parse(sessionStorage.getItem(SESSION_KEY_PREFETCHED) ?? '[]'));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return new Set();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function markPrefetched(url) {
|
|
69
|
+
const set = getPrefetched();
|
|
70
|
+
set.add(url);
|
|
71
|
+
sessionStorage.setItem(SESSION_KEY_PREFETCHED, JSON.stringify([...set]));
|
|
72
|
+
}
|
|
73
|
+
function devLog(msg, data) {
|
|
74
|
+
if (typeof window === 'undefined')
|
|
75
|
+
return;
|
|
76
|
+
const isDev = window['__NEXUS_DEV__'];
|
|
77
|
+
if (!isDev)
|
|
78
|
+
return;
|
|
79
|
+
const args = [
|
|
80
|
+
`%c[Nexus] 🧠 AI%c ${msg}`,
|
|
81
|
+
'color:#7c3aed;font-weight:700',
|
|
82
|
+
'color:#64748b',
|
|
83
|
+
];
|
|
84
|
+
if (data !== undefined)
|
|
85
|
+
args.push(data);
|
|
86
|
+
console.log(...args);
|
|
87
|
+
}
|
|
88
|
+
// ── Manifest fetching ─────────────────────────────────────────────────────────
|
|
89
|
+
async function fetchManifest(url) {
|
|
90
|
+
try {
|
|
91
|
+
const cached = sessionStorage.getItem(SESSION_KEY_MANIFEST);
|
|
92
|
+
if (cached) {
|
|
93
|
+
const parsed = JSON.parse(cached);
|
|
94
|
+
if (Date.now() - parsed._cachedAt < MANIFEST_TTL_MS)
|
|
95
|
+
return parsed;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch { /* ignore */ }
|
|
99
|
+
try {
|
|
100
|
+
const res = await fetch(url, { priority: 'low' });
|
|
101
|
+
if (!res.ok)
|
|
102
|
+
return null;
|
|
103
|
+
const manifest = await res.json();
|
|
104
|
+
sessionStorage.setItem(SESSION_KEY_MANIFEST, JSON.stringify({ ...manifest, _cachedAt: Date.now() }));
|
|
105
|
+
return manifest;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// ── Zero-JS HTML prefetch ─────────────────────────────────────────────────────
|
|
112
|
+
function injectPrefetchLink(href) {
|
|
113
|
+
if (document.querySelector(`link[rel="prefetch"][href="${href}"]`))
|
|
114
|
+
return;
|
|
115
|
+
const link = document.createElement('link');
|
|
116
|
+
link.rel = 'prefetch';
|
|
117
|
+
link.href = href;
|
|
118
|
+
link.as = 'document';
|
|
119
|
+
document.head.appendChild(link);
|
|
120
|
+
}
|
|
121
|
+
// ── Main logic ────────────────────────────────────────────────────────────────
|
|
122
|
+
/**
|
|
123
|
+
* Run the AI prefetch engine for the current route.
|
|
124
|
+
* Call this after each navigation or on page load.
|
|
125
|
+
*
|
|
126
|
+
* @param currentPath - Current route pathname
|
|
127
|
+
* @param config - Optional config overrides (merged with defaults)
|
|
128
|
+
* @returns PrefetchDecision — what was prefetched and why (or why not)
|
|
129
|
+
*/
|
|
130
|
+
export async function runAIPrefetch(currentPath, config = {}) {
|
|
131
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
132
|
+
const noop = (reason) => ({
|
|
133
|
+
willPrefetch: false, reason, predictions: [], prefetched: [],
|
|
134
|
+
});
|
|
135
|
+
if (typeof window === 'undefined')
|
|
136
|
+
return noop('mode-off');
|
|
137
|
+
if (cfg.mode === 'off') {
|
|
138
|
+
devLog('Prefetch disabled (mode: off)');
|
|
139
|
+
return noop('mode-off');
|
|
140
|
+
}
|
|
141
|
+
// ── Network checks ──────────────────────────────────────────────────────────
|
|
142
|
+
if (cfg.respectSaveData && isSaveDataEnabled()) {
|
|
143
|
+
devLog('🚫 Save-Data mode detected — prefetch disabled. Saved ~0MB (by policy).');
|
|
144
|
+
return noop('save-data');
|
|
145
|
+
}
|
|
146
|
+
if (cfg.wifiOnly && !isConnectionFast(true)) {
|
|
147
|
+
const type = getEffectiveType();
|
|
148
|
+
devLog(`🚫 Slow connection (${type}) — prefetch skipped. Your data is safe.`);
|
|
149
|
+
return noop('slow-connection');
|
|
150
|
+
}
|
|
151
|
+
if (!isConnectionFast(cfg.wifiOnly)) {
|
|
152
|
+
devLog(`⚠️ Connection is ${getEffectiveType()} — conservative mode activated.`);
|
|
153
|
+
}
|
|
154
|
+
// ── Budget check ────────────────────────────────────────────────────────────
|
|
155
|
+
const budgetUsed = getBudgetUsed();
|
|
156
|
+
if (budgetUsed >= cfg.budget) {
|
|
157
|
+
const usedKB = (budgetUsed / 1024).toFixed(0);
|
|
158
|
+
const maxKB = (cfg.budget / 1024).toFixed(0);
|
|
159
|
+
devLog(`🚫 Session budget exhausted (${usedKB}KB / ${maxKB}KB) — no more prefetches.`);
|
|
160
|
+
return noop('budget-exhausted');
|
|
161
|
+
}
|
|
162
|
+
// ── Load manifest ───────────────────────────────────────────────────────────
|
|
163
|
+
const manifest = await fetchManifest(cfg.manifestUrl);
|
|
164
|
+
if (!manifest) {
|
|
165
|
+
devLog('ℹ️ No probability manifest found — skipping AI prefetch.');
|
|
166
|
+
return noop('no-predictions');
|
|
167
|
+
}
|
|
168
|
+
const predictions = (manifest.routes[currentPath] ?? [])
|
|
169
|
+
.filter((p) => p.probability >= cfg.threshold)
|
|
170
|
+
.sort((a, b) => b.probability - a.probability);
|
|
171
|
+
if (predictions.length === 0) {
|
|
172
|
+
devLog(`ℹ️ No high-confidence predictions for "${currentPath}".`);
|
|
173
|
+
return noop(manifest.routes[currentPath] ? 'low-confidence' : 'no-predictions');
|
|
174
|
+
}
|
|
175
|
+
// ── Prefetch ────────────────────────────────────────────────────────────────
|
|
176
|
+
const prefetched = [];
|
|
177
|
+
const alreadyPrefetched = getPrefetched();
|
|
178
|
+
for (const pred of predictions) {
|
|
179
|
+
if (alreadyPrefetched.has(pred.to))
|
|
180
|
+
continue;
|
|
181
|
+
const estBytes = pred.estimatedBytes ?? 8_000; // ~8KB default for a Nexus HTML page
|
|
182
|
+
if (getBudgetUsed() + estBytes > cfg.budget) {
|
|
183
|
+
devLog(`🛑 Budget would be exceeded by prefetching "${pred.to}" — stopping.`);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
injectPrefetchLink(pred.to);
|
|
187
|
+
markPrefetched(pred.to);
|
|
188
|
+
addBudgetUsed(estBytes);
|
|
189
|
+
const pct = Math.round(pred.probability * 100);
|
|
190
|
+
const estKB = (estBytes / 1024).toFixed(1);
|
|
191
|
+
devLog(`✅ Predicting next hop → ${pred.to} (${pct}% confidence) — prefetched ${estKB}KB HTML-only.`);
|
|
192
|
+
prefetched.push(pred.to);
|
|
193
|
+
}
|
|
194
|
+
const totalBudgetUsed = getBudgetUsed();
|
|
195
|
+
const remaining = cfg.budget - totalBudgetUsed;
|
|
196
|
+
devLog(`💾 Session budget: ${(totalBudgetUsed / 1024).toFixed(0)}KB used / ${(cfg.budget / 1024).toFixed(0)}KB max — ${(remaining / 1024).toFixed(0)}KB remaining.`);
|
|
197
|
+
return { willPrefetch: prefetched.length > 0, reason: null, predictions, prefetched };
|
|
198
|
+
}
|
|
199
|
+
// ── Markov-chain recorder (client-side training) ──────────────────────────────
|
|
200
|
+
const MARKOV_KEY = '__nexus_markov__';
|
|
201
|
+
function loadMarkov() {
|
|
202
|
+
try {
|
|
203
|
+
return JSON.parse(sessionStorage.getItem(MARKOV_KEY) ?? '{}');
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return {};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function saveMarkov(chain) {
|
|
210
|
+
try {
|
|
211
|
+
sessionStorage.setItem(MARKOV_KEY, JSON.stringify(chain));
|
|
212
|
+
}
|
|
213
|
+
catch { /* quota */ }
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Record a navigation transition for the client-side Markov chain.
|
|
217
|
+
* Call this on every route change: recordNavigation('/pokemon/25', '/pokemon/26').
|
|
218
|
+
*/
|
|
219
|
+
export function recordNavigation(from, to) {
|
|
220
|
+
if (typeof window === 'undefined')
|
|
221
|
+
return;
|
|
222
|
+
const chain = loadMarkov();
|
|
223
|
+
if (!chain[from])
|
|
224
|
+
chain[from] = {};
|
|
225
|
+
chain[from][to] = (chain[from][to] ?? 0) + 1;
|
|
226
|
+
saveMarkov(chain);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Build an in-browser probability manifest from observed navigation patterns.
|
|
230
|
+
* Useful for apps that can't generate a server-side manifest.
|
|
231
|
+
*/
|
|
232
|
+
export function buildClientManifest(minConfidence = 0.5) {
|
|
233
|
+
const chain = loadMarkov();
|
|
234
|
+
const routes = {};
|
|
235
|
+
for (const [from, targets] of Object.entries(chain)) {
|
|
236
|
+
const total = Object.values(targets).reduce((a, b) => a + b, 0);
|
|
237
|
+
routes[from] = Object.entries(targets)
|
|
238
|
+
.map(([to, count]) => ({ to, probability: count / total }))
|
|
239
|
+
.filter((p) => p.probability >= minConfidence)
|
|
240
|
+
.sort((a, b) => b.probability - a.probability)
|
|
241
|
+
.slice(0, 3); // top 3 predictions per route
|
|
242
|
+
}
|
|
243
|
+
return { generated: Date.now(), routes, version: 'client-1.0' };
|
|
244
|
+
}
|
|
245
|
+
// ── nexus.config.ts integration helper ───────────────────────────────────────
|
|
246
|
+
/**
|
|
247
|
+
* Creates a configured AI prefetch runner — use this in your nexus.config.ts.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* // nexus.config.ts
|
|
251
|
+
* import { defineAIPrefetch } from '@nexus_js/runtime/prefetch-ai';
|
|
252
|
+
* export default defineNexusConfig({
|
|
253
|
+
* ai: defineAIPrefetch({
|
|
254
|
+
* mode: 'smart',
|
|
255
|
+
* budget: '500kb',
|
|
256
|
+
* wifiOnly: true,
|
|
257
|
+
* })
|
|
258
|
+
* });
|
|
259
|
+
*/
|
|
260
|
+
export function defineAIPrefetch(config = {}) {
|
|
261
|
+
const budget = typeof config.budget === 'string'
|
|
262
|
+
? parseBudget(config.budget)
|
|
263
|
+
: (config.budget ?? DEFAULT_CONFIG.budget);
|
|
264
|
+
return { ...DEFAULT_CONFIG, ...config, budget };
|
|
265
|
+
}
|
|
266
|
+
function parseBudget(s) {
|
|
267
|
+
const m = /^(\d+(?:\.\d+)?)(kb|mb|b)?$/i.exec(s.trim());
|
|
268
|
+
if (!m)
|
|
269
|
+
return DEFAULT_CONFIG.budget;
|
|
270
|
+
const n = parseFloat(m[1] ?? '0');
|
|
271
|
+
switch (m[2]?.toLowerCase()) {
|
|
272
|
+
case 'mb': return n * 1024 * 1024;
|
|
273
|
+
case 'b': return n;
|
|
274
|
+
default: return n * 1024; // kb
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=prefetch-ai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch-ai.js","sourceRoot":"","sources":["../src/prefetch-ai.ts"],"names":[],"mappings":"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"}
|
package/dist/runes.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Runes — Fine-grained reactive primitives inspired by Svelte 5.
|
|
3
|
+
* Zero Virtual DOM. The runtime surgically updates only what changed.
|
|
4
|
+
*/
|
|
5
|
+
type Cleanup = () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Creates a reactive signal. Reading `.value` inside an `$effect` or
|
|
8
|
+
* `$derived` automatically creates a dependency subscription.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const count = $state(0);
|
|
12
|
+
* count.value++; // triggers all subscribers
|
|
13
|
+
*/
|
|
14
|
+
export declare function $state<T>(initial: T): {
|
|
15
|
+
value: T;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Creates a computed value that automatically updates when its dependencies
|
|
19
|
+
* change. Computed lazily — only recalculates when accessed after a change.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const count = $state(0);
|
|
23
|
+
* const doubled = $derived(() => count.value * 2);
|
|
24
|
+
* console.log(doubled.value); // 0
|
|
25
|
+
* count.value = 5;
|
|
26
|
+
* console.log(doubled.value); // 10
|
|
27
|
+
*/
|
|
28
|
+
export declare function $derived<T>(computation: () => T): {
|
|
29
|
+
readonly value: T;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Runs a side effect whenever its reactive dependencies change.
|
|
33
|
+
* Returns a cleanup function to stop tracking.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const count = $state(0);
|
|
37
|
+
* $effect(() => {
|
|
38
|
+
* document.title = `Count: ${count.value}`;
|
|
39
|
+
* });
|
|
40
|
+
*/
|
|
41
|
+
export declare function $effect(fn: () => Cleanup | void): Cleanup;
|
|
42
|
+
/**
|
|
43
|
+
* Declares component props with optional defaults.
|
|
44
|
+
* Props are reactive — parent changes flow down automatically.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const { name, age = 18 } = $props<{ name: string; age?: number }>();
|
|
48
|
+
*/
|
|
49
|
+
export declare function $props<T extends Record<string, unknown>>(defaults?: Partial<T>): T;
|
|
50
|
+
/**
|
|
51
|
+
* Batches multiple state updates into a single re-render pass.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* batch(() => {
|
|
55
|
+
* x.value = 1;
|
|
56
|
+
* y.value = 2; // only one re-render happens
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
export declare function batch(fn: () => void): void;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=runes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runes.d.ts","sourceRoot":"","sources":["../src/runes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,KAAK,OAAO,GAAG,MAAM,IAAI,CAAC;AAqB1B;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,CAyBlD;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAgBvE;AAID;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,OAAO,GAAG,IAAI,GAAG,OAAO,CA8BzD;AAID;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,QAAQ,GAAE,OAAO,CAAC,CAAC,CAAM,GACxB,CAAC,CAQH;AAOD;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAc1C"}
|