@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.
@@ -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":"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"}
@@ -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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"}
@@ -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"}