@akashjs/runtime 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animate.d.cts +145 -0
- package/dist/animate.d.ts +145 -0
- package/dist/{chunk-V7VG23IO.cjs → chunk-3AL2DVPZ.cjs} +3 -3
- package/dist/{chunk-V7VG23IO.cjs.map → chunk-3AL2DVPZ.cjs.map} +1 -1
- package/dist/{chunk-CHF5LH56.cjs → chunk-6NX6JRSV.cjs} +3 -3
- package/dist/{chunk-CHF5LH56.cjs.map → chunk-6NX6JRSV.cjs.map} +1 -1
- package/dist/chunk-772SU4MG.js +2 -0
- package/dist/chunk-772SU4MG.js.map +1 -0
- package/dist/chunk-7LQZF3XA.cjs +2 -0
- package/dist/chunk-7LQZF3XA.cjs.map +1 -0
- package/dist/{chunk-DYJUCZXA.js → chunk-BT6HNBE7.js} +4 -4
- package/dist/chunk-BT6HNBE7.js.map +1 -0
- package/dist/{chunk-CGKMCVEZ.js → chunk-D6QQYZIC.js} +2 -2
- package/dist/{chunk-CGKMCVEZ.js.map → chunk-D6QQYZIC.js.map} +1 -1
- package/dist/{chunk-R3W5W647.cjs → chunk-H4SAK7A5.cjs} +2 -2
- package/dist/{chunk-R3W5W647.cjs.map → chunk-H4SAK7A5.cjs.map} +1 -1
- package/dist/{chunk-VFOAULHK.js → chunk-IM2VW4TK.js} +3 -3
- package/dist/{chunk-VFOAULHK.js.map → chunk-IM2VW4TK.js.map} +1 -1
- package/dist/chunk-NQVWTQ2I.cjs +5 -0
- package/dist/chunk-NQVWTQ2I.cjs.map +1 -0
- package/dist/{chunk-5EFX654I.cjs → chunk-NVZLEJXB.cjs} +2 -2
- package/dist/{chunk-5EFX654I.cjs.map → chunk-NVZLEJXB.cjs.map} +1 -1
- package/dist/{chunk-DPJ6RJ7A.js → chunk-ODDXU5DO.js} +2 -2
- package/dist/chunk-ODDXU5DO.js.map +1 -0
- package/dist/{chunk-EUKRTV4W.js → chunk-POLTPHUA.js} +3 -3
- package/dist/{chunk-EUKRTV4W.js.map → chunk-POLTPHUA.js.map} +1 -1
- package/dist/{chunk-4HAE7H7W.cjs → chunk-YIB4EKVI.cjs} +2 -2
- package/dist/chunk-YIB4EKVI.cjs.map +1 -0
- package/dist/{chunk-SRPWGLOQ.js → chunk-Z5LQV5ND.js} +2 -2
- package/dist/{chunk-SRPWGLOQ.js.map → chunk-Z5LQV5ND.js.map} +1 -1
- package/dist/component-C1WnFcRp.d.cts +59 -0
- package/dist/component-C1WnFcRp.d.ts +59 -0
- package/dist/context-2uQ6fuxu.d.cts +57 -0
- package/dist/context-2uQ6fuxu.d.ts +57 -0
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +65 -0
- package/dist/core.d.ts +65 -0
- package/dist/core.js +1 -1
- package/dist/index.cjs +8 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3218 -0
- package/dist/index.d.ts +3218 -0
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/machine.cjs +1 -1
- package/dist/machine.d.cts +87 -0
- package/dist/machine.d.ts +87 -0
- package/dist/machine.js +1 -1
- package/dist/offline.cjs +1 -1
- package/dist/offline.d.cts +73 -0
- package/dist/offline.d.ts +73 -0
- package/dist/offline.js +1 -1
- package/dist/pwa.cjs +1 -1
- package/dist/pwa.d.cts +80 -0
- package/dist/pwa.d.ts +80 -0
- package/dist/pwa.js +1 -1
- package/dist/signals-C7XfOHHR.d.cts +55 -0
- package/dist/signals-C7XfOHHR.d.ts +55 -0
- package/dist/ssr.cjs +1 -1
- package/dist/ssr.d.cts +78 -0
- package/dist/ssr.d.ts +78 -0
- package/dist/ssr.js +1 -1
- package/dist/store.cjs +1 -1
- package/dist/store.d.cts +88 -0
- package/dist/store.d.ts +88 -0
- package/dist/store.js +1 -1
- package/dist/sync.cjs +1 -1
- package/dist/sync.d.cts +128 -0
- package/dist/sync.d.ts +128 -0
- package/dist/sync.js +1 -1
- package/dist/test.cjs +2 -2
- package/dist/test.d.cts +109 -0
- package/dist/test.d.ts +109 -0
- package/dist/test.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4HAE7H7W.cjs.map +0 -1
- package/dist/chunk-DPJ6RJ7A.js.map +0 -1
- package/dist/chunk-DYJUCZXA.js.map +0 -1
- package/dist/chunk-P5GADKQS.cjs +0 -2
- package/dist/chunk-P5GADKQS.cjs.map +0 -1
- package/dist/chunk-Q5BER4ZB.js +0 -2
- package/dist/chunk-Q5BER4ZB.js.map +0 -1
- package/dist/chunk-QDCIW4YE.cjs +0 -5
- package/dist/chunk-QDCIW4YE.cjs.map +0 -1
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation module.
|
|
3
|
+
*
|
|
4
|
+
* State-based animations, stagger, group, sequence, keyframes,
|
|
5
|
+
* and spring physics. Goes far beyond CSS transitions.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const fadeIn = animate(el, { opacity: [0, 1] }, { duration: 300 });
|
|
9
|
+
* const staggered = animateStagger('.item', { opacity: [0, 1], y: [20, 0] }, { stagger: 50 });
|
|
10
|
+
* const spring = animateSpring(el, { scale: 1.2 }, { stiffness: 300, damping: 20 });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
interface AnimationOptions {
|
|
14
|
+
/** Duration in ms (default: 300) */
|
|
15
|
+
duration?: number;
|
|
16
|
+
/** Easing function or CSS easing string (default: 'ease') */
|
|
17
|
+
easing?: string;
|
|
18
|
+
/** Delay before animation starts in ms */
|
|
19
|
+
delay?: number;
|
|
20
|
+
/** Number of iterations (Infinity for loop) */
|
|
21
|
+
iterations?: number;
|
|
22
|
+
/** Direction: normal, reverse, alternate */
|
|
23
|
+
direction?: PlaybackDirection;
|
|
24
|
+
/** Fill mode */
|
|
25
|
+
fill?: FillMode;
|
|
26
|
+
/** Callback when animation completes */
|
|
27
|
+
onComplete?: () => void;
|
|
28
|
+
}
|
|
29
|
+
interface StaggerOptions extends AnimationOptions {
|
|
30
|
+
/** Delay between each element in ms */
|
|
31
|
+
stagger?: number;
|
|
32
|
+
/** Stagger from: 'start', 'center', 'end' */
|
|
33
|
+
from?: 'start' | 'center' | 'end';
|
|
34
|
+
}
|
|
35
|
+
interface SpringOptions {
|
|
36
|
+
/** Spring stiffness (default: 100) */
|
|
37
|
+
stiffness?: number;
|
|
38
|
+
/** Damping ratio (default: 10) */
|
|
39
|
+
damping?: number;
|
|
40
|
+
/** Mass (default: 1) */
|
|
41
|
+
mass?: number;
|
|
42
|
+
/** Velocity threshold to stop (default: 0.01) */
|
|
43
|
+
threshold?: number;
|
|
44
|
+
/** Callback when animation completes */
|
|
45
|
+
onComplete?: () => void;
|
|
46
|
+
}
|
|
47
|
+
interface AnimationControl {
|
|
48
|
+
/** Play the animation */
|
|
49
|
+
play(): void;
|
|
50
|
+
/** Pause the animation */
|
|
51
|
+
pause(): void;
|
|
52
|
+
/** Cancel the animation */
|
|
53
|
+
cancel(): void;
|
|
54
|
+
/** Reverse the animation */
|
|
55
|
+
reverse(): void;
|
|
56
|
+
/** Promise that resolves when animation completes */
|
|
57
|
+
finished: Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
type PropertyValue = number | string | [number | string, number | string];
|
|
60
|
+
/**
|
|
61
|
+
* Animate an element using the Web Animations API.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* const ctrl = animate(el, {
|
|
65
|
+
* opacity: [0, 1],
|
|
66
|
+
* transform: ['translateY(20px)', 'translateY(0)'],
|
|
67
|
+
* }, { duration: 300, easing: 'ease-out' });
|
|
68
|
+
*
|
|
69
|
+
* await ctrl.finished;
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function animate(el: HTMLElement, properties: Record<string, PropertyValue>, options?: AnimationOptions): AnimationControl;
|
|
73
|
+
/**
|
|
74
|
+
* Animate multiple elements with staggered timing.
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* animateStagger('.list-item', {
|
|
78
|
+
* opacity: [0, 1],
|
|
79
|
+
* y: [20, 0],
|
|
80
|
+
* }, { stagger: 50, duration: 300 });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function animateStagger(selector: string | HTMLElement[], properties: Record<string, PropertyValue>, options?: StaggerOptions): AnimationControl[];
|
|
84
|
+
/**
|
|
85
|
+
* Run animations in sequence, one after another.
|
|
86
|
+
*
|
|
87
|
+
* ```ts
|
|
88
|
+
* await animateSequence([
|
|
89
|
+
* [el1, { opacity: [0, 1] }, { duration: 200 }],
|
|
90
|
+
* [el2, { opacity: [0, 1] }, { duration: 200 }],
|
|
91
|
+
* ]);
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function animateSequence(steps: Array<[HTMLElement, Record<string, PropertyValue>, AnimationOptions?]>): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Run multiple animations in parallel, wait for all to complete.
|
|
97
|
+
*/
|
|
98
|
+
declare function animateGroup(steps: Array<[HTMLElement, Record<string, PropertyValue>, AnimationOptions?]>): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Animate with spring physics (no CSS easing — uses requestAnimationFrame).
|
|
101
|
+
*
|
|
102
|
+
* ```ts
|
|
103
|
+
* animateSpring(el, { scale: 1.2, rotate: 10 }, {
|
|
104
|
+
* stiffness: 300,
|
|
105
|
+
* damping: 20,
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
declare function animateSpring(el: HTMLElement, target: Record<string, number>, options?: SpringOptions): AnimationControl;
|
|
110
|
+
/**
|
|
111
|
+
* Define keyframes for multi-step animations.
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* const bounce = keyframes([
|
|
115
|
+
* { offset: 0, transform: 'translateY(0)' },
|
|
116
|
+
* { offset: 0.5, transform: 'translateY(-30px)' },
|
|
117
|
+
* { offset: 1, transform: 'translateY(0)' },
|
|
118
|
+
* ]);
|
|
119
|
+
*
|
|
120
|
+
* el.animate(bounce, { duration: 600 });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare function keyframes(frames: Keyframe[]): Keyframe[];
|
|
124
|
+
interface AnimationState {
|
|
125
|
+
[property: string]: string | number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Define state-based animations.
|
|
129
|
+
*
|
|
130
|
+
* ```ts
|
|
131
|
+
* const toggle = defineStates({
|
|
132
|
+
* open: { height: 'auto', opacity: 1 },
|
|
133
|
+
* closed: { height: 0, opacity: 0 },
|
|
134
|
+
* }, { duration: 300 });
|
|
135
|
+
*
|
|
136
|
+
* toggle.transitionTo(el, 'open');
|
|
137
|
+
* toggle.transitionTo(el, 'closed');
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function defineStates(states: Record<string, AnimationState>, defaultOptions?: AnimationOptions): {
|
|
141
|
+
states: Record<string, AnimationState>;
|
|
142
|
+
transitionTo(el: HTMLElement, stateName: string, options?: AnimationOptions): AnimationControl;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export { type AnimationControl, type AnimationOptions, type AnimationState, type SpringOptions, type StaggerOptions, animate, animateGroup, animateSequence, animateSpring, animateStagger, defineStates, keyframes };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation module.
|
|
3
|
+
*
|
|
4
|
+
* State-based animations, stagger, group, sequence, keyframes,
|
|
5
|
+
* and spring physics. Goes far beyond CSS transitions.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const fadeIn = animate(el, { opacity: [0, 1] }, { duration: 300 });
|
|
9
|
+
* const staggered = animateStagger('.item', { opacity: [0, 1], y: [20, 0] }, { stagger: 50 });
|
|
10
|
+
* const spring = animateSpring(el, { scale: 1.2 }, { stiffness: 300, damping: 20 });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
interface AnimationOptions {
|
|
14
|
+
/** Duration in ms (default: 300) */
|
|
15
|
+
duration?: number;
|
|
16
|
+
/** Easing function or CSS easing string (default: 'ease') */
|
|
17
|
+
easing?: string;
|
|
18
|
+
/** Delay before animation starts in ms */
|
|
19
|
+
delay?: number;
|
|
20
|
+
/** Number of iterations (Infinity for loop) */
|
|
21
|
+
iterations?: number;
|
|
22
|
+
/** Direction: normal, reverse, alternate */
|
|
23
|
+
direction?: PlaybackDirection;
|
|
24
|
+
/** Fill mode */
|
|
25
|
+
fill?: FillMode;
|
|
26
|
+
/** Callback when animation completes */
|
|
27
|
+
onComplete?: () => void;
|
|
28
|
+
}
|
|
29
|
+
interface StaggerOptions extends AnimationOptions {
|
|
30
|
+
/** Delay between each element in ms */
|
|
31
|
+
stagger?: number;
|
|
32
|
+
/** Stagger from: 'start', 'center', 'end' */
|
|
33
|
+
from?: 'start' | 'center' | 'end';
|
|
34
|
+
}
|
|
35
|
+
interface SpringOptions {
|
|
36
|
+
/** Spring stiffness (default: 100) */
|
|
37
|
+
stiffness?: number;
|
|
38
|
+
/** Damping ratio (default: 10) */
|
|
39
|
+
damping?: number;
|
|
40
|
+
/** Mass (default: 1) */
|
|
41
|
+
mass?: number;
|
|
42
|
+
/** Velocity threshold to stop (default: 0.01) */
|
|
43
|
+
threshold?: number;
|
|
44
|
+
/** Callback when animation completes */
|
|
45
|
+
onComplete?: () => void;
|
|
46
|
+
}
|
|
47
|
+
interface AnimationControl {
|
|
48
|
+
/** Play the animation */
|
|
49
|
+
play(): void;
|
|
50
|
+
/** Pause the animation */
|
|
51
|
+
pause(): void;
|
|
52
|
+
/** Cancel the animation */
|
|
53
|
+
cancel(): void;
|
|
54
|
+
/** Reverse the animation */
|
|
55
|
+
reverse(): void;
|
|
56
|
+
/** Promise that resolves when animation completes */
|
|
57
|
+
finished: Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
type PropertyValue = number | string | [number | string, number | string];
|
|
60
|
+
/**
|
|
61
|
+
* Animate an element using the Web Animations API.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* const ctrl = animate(el, {
|
|
65
|
+
* opacity: [0, 1],
|
|
66
|
+
* transform: ['translateY(20px)', 'translateY(0)'],
|
|
67
|
+
* }, { duration: 300, easing: 'ease-out' });
|
|
68
|
+
*
|
|
69
|
+
* await ctrl.finished;
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function animate(el: HTMLElement, properties: Record<string, PropertyValue>, options?: AnimationOptions): AnimationControl;
|
|
73
|
+
/**
|
|
74
|
+
* Animate multiple elements with staggered timing.
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* animateStagger('.list-item', {
|
|
78
|
+
* opacity: [0, 1],
|
|
79
|
+
* y: [20, 0],
|
|
80
|
+
* }, { stagger: 50, duration: 300 });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function animateStagger(selector: string | HTMLElement[], properties: Record<string, PropertyValue>, options?: StaggerOptions): AnimationControl[];
|
|
84
|
+
/**
|
|
85
|
+
* Run animations in sequence, one after another.
|
|
86
|
+
*
|
|
87
|
+
* ```ts
|
|
88
|
+
* await animateSequence([
|
|
89
|
+
* [el1, { opacity: [0, 1] }, { duration: 200 }],
|
|
90
|
+
* [el2, { opacity: [0, 1] }, { duration: 200 }],
|
|
91
|
+
* ]);
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function animateSequence(steps: Array<[HTMLElement, Record<string, PropertyValue>, AnimationOptions?]>): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Run multiple animations in parallel, wait for all to complete.
|
|
97
|
+
*/
|
|
98
|
+
declare function animateGroup(steps: Array<[HTMLElement, Record<string, PropertyValue>, AnimationOptions?]>): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Animate with spring physics (no CSS easing — uses requestAnimationFrame).
|
|
101
|
+
*
|
|
102
|
+
* ```ts
|
|
103
|
+
* animateSpring(el, { scale: 1.2, rotate: 10 }, {
|
|
104
|
+
* stiffness: 300,
|
|
105
|
+
* damping: 20,
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
declare function animateSpring(el: HTMLElement, target: Record<string, number>, options?: SpringOptions): AnimationControl;
|
|
110
|
+
/**
|
|
111
|
+
* Define keyframes for multi-step animations.
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* const bounce = keyframes([
|
|
115
|
+
* { offset: 0, transform: 'translateY(0)' },
|
|
116
|
+
* { offset: 0.5, transform: 'translateY(-30px)' },
|
|
117
|
+
* { offset: 1, transform: 'translateY(0)' },
|
|
118
|
+
* ]);
|
|
119
|
+
*
|
|
120
|
+
* el.animate(bounce, { duration: 600 });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare function keyframes(frames: Keyframe[]): Keyframe[];
|
|
124
|
+
interface AnimationState {
|
|
125
|
+
[property: string]: string | number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Define state-based animations.
|
|
129
|
+
*
|
|
130
|
+
* ```ts
|
|
131
|
+
* const toggle = defineStates({
|
|
132
|
+
* open: { height: 'auto', opacity: 1 },
|
|
133
|
+
* closed: { height: 0, opacity: 0 },
|
|
134
|
+
* }, { duration: 300 });
|
|
135
|
+
*
|
|
136
|
+
* toggle.transitionTo(el, 'open');
|
|
137
|
+
* toggle.transitionTo(el, 'closed');
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function defineStates(states: Record<string, AnimationState>, defaultOptions?: AnimationOptions): {
|
|
141
|
+
states: Record<string, AnimationState>;
|
|
142
|
+
transitionTo(el: HTMLElement, stateName: string, options?: AnimationOptions): AnimationControl;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export { type AnimationControl, type AnimationOptions, type AnimationState, type SpringOptions, type StaggerOptions, animate, animateGroup, animateSequence, animateSpring, animateStagger, defineStates, keyframes };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var f=new Set,l=new Set,b=false,d=0,
|
|
1
|
+
'use strict';var f=new Set,l=new Set,b=false,d=0,g=false,x=3,P=100;function v(){if(b)return;b=true;let e=new Map,n=false,t=0;for(;(f.size>0||l.size>0)&&t<P;){if(t++,f.size>0){let s=[...f].sort(C);f.clear();for(let r of s){let o=(e.get(r)??0)+1;if(e.set(r,o),o>x){n=true;continue}r.run();}}if(l.size>0){let s=[...l].sort(C);l.clear();for(let r of s){let o=(e.get(r)??0)+1;if(e.set(r,o),o>x){n=true;continue}r.run();}}if(n&&f.size===0&&l.size===0)break}(n||t>=P)&&(f.clear(),l.clear(),console.error("[AkashJS] Circular dependency detected between effects. Two or more effects are writing to each other's dependencies. The cycle has been broken after "+t+" iterations.")),b=false,g&&(g=false,(f.size>0||l.size>0)&&v());}function N(e){e.isRender?f.add(e):l.add(e),d===0&&!b?v():b&&(g=true);}function _(e){d++;try{e();}finally{d--,d===0&&v();}}function R(){d++;}function k(){d--,d===0&&v();}function C(e,n){return (e.depth??0)-(n.depth??0)}function M(){v();}var y=false,h=[],S=0;function B(){y=true,h=[],S=performance.now();}function K(){y=false;let e=performance.now();return {entries:[...h],totalDuration:e-S,startTime:S,endTime:e}}function T(){return y}function p(e,n,t){y&&h.push({type:e,name:n,duration:t,timestamp:performance.now()});}function z(e){let n=e.entries.filter(i=>i.type==="render"),t=e.entries.filter(i=>i.type==="effect"),s=e.entries.filter(i=>i.type==="signal-update"),r=e.entries.filter(i=>i.type==="computed"),o=i=>i.length>0?i.reduce((u,m)=>u+m.duration,0)/i.length:0,c=i=>i.length>0?i.reduce((u,m)=>m.duration>u.duration?m:u):null;return {totalRenders:n.length,totalEffects:t.length,totalSignalUpdates:s.length,totalComputedEvals:r.length,avgRenderTime:o(n),avgEffectTime:o(t),slowestRender:c(n),slowestEffect:c(t)}}function O(e,n){let t=performance.now(),s=n(),r=performance.now()-t;return p("render",e,r),{result:s,duration:r}}async function j(e,n){let t=performance.now(),s=await n(),r=performance.now()-t;return p("render",e,r),{result:s,duration:r}}function I(e){let n=0,t=0;return {start(){n=performance.now();},stop(){t=performance.now()-n,p("render",e,t);},get duration(){return t}}}function X(e){let n=z(e),t=`
|
|
2
2
|
Performance Profile
|
|
3
3
|
`;return t+=" "+"\u2500".repeat(50)+`
|
|
4
4
|
`,t+=` Duration: ${e.totalDuration.toFixed(1)} ms
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
`,n.slowestRender&&(t+=` Slowest render: ${n.slowestRender.name} (${n.slowestRender.duration.toFixed(2)} ms)
|
|
10
10
|
`),n.slowestEffect&&(t+=` Slowest effect: ${n.slowestEffect.name} (${n.slowestEffect.duration.toFixed(2)} ms)
|
|
11
11
|
`),t+=" "+"\u2500".repeat(50)+`
|
|
12
|
-
`,t}var F=typeof process>"u"||process.env?.NODE_ENV!=="production";var
|
|
13
|
-
//# sourceMappingURL=chunk-
|
|
12
|
+
`,t}var F=typeof process>"u"||process.env?.NODE_ENV!=="production";var a=null;function G(e,n){let t={value:e,subscribers:new Set,equals:n?.equals??Object.is},s=()=>(J(t),t.value);return s.set=r=>{F&&a&&a._tag==="computed"&&console.warn("[AkashJS] Writing to a signal inside computed() is not allowed. The write will be lost on the next evaluation."),!t.equals(t.value,r)&&(t.value=r,T()&&p("signal-update","signal.set",0),_(()=>{E(t);}));},s.update=r=>{s.set(r(t.value));},s.peek=()=>t.value,s}function Q(e,n){let t={_tag:"computed",fn:e,value:void 0,state:1,subscribers:new Set,sources:new Set,equals:n?.equals??Object.is};return ()=>(a&&(t.subscribers.add(a),"sources"in a&&a.sources.add(t)),t.state!==0&&q(t),t.value)}var w=new Set;function q(e,n=false){if(w.has(e))throw new Error("[AkashJS] Circular dependency detected between computed values.");w.add(e),R();for(let r of e.sources)r.subscribers.delete(e);e.sources.clear();let t=a;a=e;let s=T()?performance.now():0;try{let r=e.fn(),o=e.value===void 0,c=o||!e.equals(e.value,r);if(e.value=r,e.state=0,c&&!o)if(n){for(let i of [...e.subscribers])if(i._tag==="computed"){i.state=1;for(let u of [...i.subscribers])u._tag==="computed"&&(u.state=1);}}else E(e);}finally{s&&p("computed","computed",performance.now()-s),w.delete(e),a=t,k();}}function Y(e,n){let t={_tag:"effect",fn:e,cleanup:null,sources:new Set,disposed:false,isRender:n?.render??false,run(){D(t);}};return D(t),()=>{t.disposed=true,A(t);for(let s of t.sources)s.subscribers.delete(t);t.sources.clear();}}function D(e){if(e.disposed)return;if(e.sources.size>0){let r=false;for(let o of e.sources)if("_tag"in o&&o._tag==="computed"){o.state===1&&q(o,true);let c=e._lastSeen;if(c?.has(o)){let i=c.get(o);o.equals(i,o.value)||(r=true);}else r=true;}else r=true;if(!r)return}A(e);let n=new Set(e.sources);for(let r of e.sources)r.subscribers.delete(e);e.sources.clear();let t=a;a=e;let s=T()?performance.now():0;try{let r=e.fn();typeof r=="function"&&(e.cleanup=r);}catch(r){for(let o of n)o.subscribers.add(e),e.sources.add(o);console.error("[AkashJS] Error in effect (will retry on next signal change):",r);}finally{s&&p("effect","effect",performance.now()-s),a=t;let r=new Map;for(let o of e.sources)"_tag"in o&&o._tag==="computed"&&r.set(o,o.value);r.size>0&&(e._lastSeen=r);}}function A(e){if(e.cleanup){try{e.cleanup();}catch(n){console.error("[AkashJS] Error in effect cleanup (ignored):",n);}e.cleanup=null;}}function U(e){let n=a;a=null;try{return e()}finally{a=n;}}function Z(e,n,t){let s=Array.isArray(e),r=s?e:[e],o,c=true;return ()=>{let i=r.map(m=>m());if(c&&(c=false,o=i.slice(),t?.defer!==false))return;let u=o;return o=i.slice(),U(()=>n(s?i:i[0],u?s?u:u[0]:void 0))}}function J(e){a&&(e.subscribers.add(a),"sources"in a&&a.sources.add(e));}function E(e){let n=[...e.subscribers];for(let t of n)t._tag==="computed"?(t.state=1,E(t)):t._tag==="effect"&&N(t);}exports.a=_;exports.b=M;exports.c=B;exports.d=K;exports.e=T;exports.f=p;exports.g=z;exports.h=O;exports.i=j;exports.j=I;exports.k=X;exports.l=G;exports.m=Q;exports.n=Y;exports.o=U;exports.p=Z;//# sourceMappingURL=chunk-3AL2DVPZ.cjs.map
|
|
13
|
+
//# sourceMappingURL=chunk-3AL2DVPZ.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scheduler.ts","../src/perf.ts","../src/signals.ts"],"names":["pendingRender","pendingUser","flushing","batchDepth","reflushNeeded","MAX_EFFECT_RUNS","MAX_FLUSH_ITERATIONS","flush","runCounts","circularDetected","iterations","queue","byDepth","fx","count","scheduleEffect","batch","fn","enterBatch","exitBatch","a","b","flushSync","profiling","entries","profileStart","startProfiling","stopProfiling","endTime","isProfiling","recordPerfEntry","type","name","duration","getProfileSummary","profile","renders","e","effects","signalUpdates","computeds","avg","arr","s","slowest","measureSync","start","result","measureAsync","createTimer","startTime","dur","formatProfile","summary","out","__DEV__","currentSubscriber","signal","initialValue","options","node","read","trackSubscriber","value","notifySubscribers","computed","recompute","computingSet","skipEffectNotify","source","prevSubscriber","_t0","newValue","isFirst","changed","sub","sub2","effect","runEffect","cleanupEffect","anyChanged","cachedValues","lastSeen","prevSources","err","untrack","prev","on","deps","isArray","depArray","prevValues","values","d","subs"],"mappings":"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","file":"chunk-V7VG23IO.cjs","sourcesContent":["/**\n * Microtask-based effect scheduler with priority levels and deduplication.\n *\n * Render effects (DOM bindings) run before user effects to ensure\n * DOM is consistent before user-side effects execute.\n */\n\nexport interface ScheduledEffect {\n run(): void;\n isRender: boolean;\n /** Depth in the dependency graph (0 = root). Lower depth runs first. */\n depth?: number;\n}\n\nconst pendingRender = new Set<ScheduledEffect>();\nconst pendingUser = new Set<ScheduledEffect>();\nlet flushing = false;\nlet batchDepth = 0;\nlet flushScheduled = false;\nlet reflushNeeded = false;\n\nconst MAX_EFFECT_RUNS = 3;\nconst MAX_FLUSH_ITERATIONS = 100;\n\nfunction flush(): void {\n if (flushing) return;\n flushing = true;\n flushScheduled = false;\n\n // Fresh per-effect run counter for THIS flush — reset every time\n const runCounts = new Map<ScheduledEffect, number>();\n let circularDetected = false;\n\n // Process render effects first, then user effects.\n // Effects may enqueue more effects during flush, so loop until empty.\n let iterations = 0;\n while ((pendingRender.size > 0 || pendingUser.size > 0) && iterations < MAX_FLUSH_ITERATIONS) {\n iterations++;\n\n // Drain render effects (sorted by depth — parents before children)\n if (pendingRender.size > 0) {\n const queue = [...pendingRender].sort(byDepth);\n pendingRender.clear();\n for (const fx of queue) {\n const count = (runCounts.get(fx) ?? 0) + 1;\n runCounts.set(fx, count);\n if (count > MAX_EFFECT_RUNS) {\n circularDetected = true;\n continue; // skip this effect — it's in a cycle\n }\n fx.run();\n }\n }\n\n // Drain user effects (sorted by depth)\n if (pendingUser.size > 0) {\n const queue = [...pendingUser].sort(byDepth);\n pendingUser.clear();\n for (const fx of queue) {\n const count = (runCounts.get(fx) ?? 0) + 1;\n runCounts.set(fx, count);\n if (count > MAX_EFFECT_RUNS) {\n circularDetected = true;\n continue; // skip this effect — it's in a cycle\n }\n fx.run();\n }\n }\n\n // If all remaining effects were skipped due to cycle detection, break\n if (circularDetected && pendingRender.size === 0 && pendingUser.size === 0) {\n break;\n }\n }\n\n if (circularDetected || iterations >= MAX_FLUSH_ITERATIONS) {\n pendingRender.clear();\n pendingUser.clear();\n console.error(\n '[AkashJS] Circular dependency detected between effects. ' +\n 'Two or more effects are writing to each other\\'s dependencies. ' +\n 'The cycle has been broken after ' + iterations + ' iterations.'\n );\n }\n\n flushing = false;\n\n // If effects were scheduled during the tail end of this flush (after the\n // while loop's condition was last checked), re-flush them now.\n if (reflushNeeded) {\n reflushNeeded = false;\n if (pendingRender.size > 0 || pendingUser.size > 0) {\n flush();\n }\n }\n}\n\nexport function scheduleEffect(fx: ScheduledEffect): void {\n if (fx.isRender) {\n pendingRender.add(fx);\n } else {\n pendingUser.add(fx);\n }\n\n if (batchDepth === 0 && !flushing) {\n flush();\n } else if (flushing) {\n // Effects were added during a flush. The while loop may still pick them\n // up, but if it has already checked the queues and found them empty,\n // we need a re-flush after the current one completes.\n reflushNeeded = true;\n }\n}\n\n/**\n * Batch multiple signal writes — subscribers are notified only once\n * at the end of the batch.\n */\nexport function batch(fn: () => void): void {\n batchDepth++;\n try {\n fn();\n } finally {\n batchDepth--;\n if (batchDepth === 0) {\n flush();\n }\n }\n}\n\n/** Enter/exit batch depth — used by computed recompute to prevent mid-evaluation flush */\nexport function enterBatch(): void { batchDepth++; }\nexport function exitBatch(): void {\n batchDepth--;\n if (batchDepth === 0) flush();\n}\n\n/** Sort effects by depth (lower depth first = parents before children) */\nfunction byDepth(a: ScheduledEffect, b: ScheduledEffect): number {\n return (a.depth ?? 0) - (b.depth ?? 0);\n}\n\n/** Synchronously flush all pending effects. Useful for testing. */\nexport function flushSync(): void {\n flush();\n}\n","/**\n * Performance profiling utilities.\n *\n * Measure component render times, signal propagation, and\n * effect execution for performance debugging.\n *\n * ```ts\n * import { startProfiling, stopProfiling, getProfile } from '@akashjs/runtime';\n *\n * startProfiling();\n * // ... do stuff ...\n * stopProfiling();\n * console.table(getProfile().entries);\n * ```\n */\n\n// --- Types ---\n\nexport interface PerfEntry {\n type: 'render' | 'effect' | 'signal-update' | 'computed';\n name: string;\n duration: number;\n timestamp: number;\n}\n\nexport interface PerfProfile {\n entries: PerfEntry[];\n totalDuration: number;\n startTime: number;\n endTime: number;\n}\n\nexport interface PerfSummary {\n totalRenders: number;\n totalEffects: number;\n totalSignalUpdates: number;\n totalComputedEvals: number;\n avgRenderTime: number;\n avgEffectTime: number;\n slowestRender: PerfEntry | null;\n slowestEffect: PerfEntry | null;\n}\n\n// --- Profiling state ---\n\nlet profiling = false;\nlet entries: PerfEntry[] = [];\nlet profileStart = 0;\n\n// --- Public API ---\n\n/**\n * Start profiling. Clears previous data.\n */\nexport function startProfiling(): void {\n profiling = true;\n entries = [];\n profileStart = performance.now();\n}\n\n/**\n * Stop profiling.\n */\nexport function stopProfiling(): PerfProfile {\n profiling = false;\n const endTime = performance.now();\n\n return {\n entries: [...entries],\n totalDuration: endTime - profileStart,\n startTime: profileStart,\n endTime,\n };\n}\n\n/**\n * Check if profiling is active.\n */\nexport function isProfiling(): boolean {\n return profiling;\n}\n\n/**\n * Record a performance entry (called internally by the framework).\n */\nexport function recordPerfEntry(\n type: PerfEntry['type'],\n name: string,\n duration: number,\n): void {\n if (!profiling) return;\n entries.push({\n type,\n name,\n duration,\n timestamp: performance.now(),\n });\n}\n\n/**\n * Get a summary of the profiling data.\n */\nexport function getProfileSummary(profile: PerfProfile): PerfSummary {\n const renders = profile.entries.filter((e) => e.type === 'render');\n const effects = profile.entries.filter((e) => e.type === 'effect');\n const signalUpdates = profile.entries.filter((e) => e.type === 'signal-update');\n const computeds = profile.entries.filter((e) => e.type === 'computed');\n\n const avg = (arr: PerfEntry[]) =>\n arr.length > 0 ? arr.reduce((s, e) => s + e.duration, 0) / arr.length : 0;\n\n const slowest = (arr: PerfEntry[]) =>\n arr.length > 0 ? arr.reduce((s, e) => (e.duration > s.duration ? e : s)) : null;\n\n return {\n totalRenders: renders.length,\n totalEffects: effects.length,\n totalSignalUpdates: signalUpdates.length,\n totalComputedEvals: computeds.length,\n avgRenderTime: avg(renders),\n avgEffectTime: avg(effects),\n slowestRender: slowest(renders),\n slowestEffect: slowest(effects),\n };\n}\n\n// --- Measurement helpers ---\n\n/**\n * Measure the time to execute a function.\n *\n * ```ts\n * const { result, duration } = measureSync('my-operation', () => expensiveWork());\n * ```\n */\nexport function measureSync<T>(name: string, fn: () => T): { result: T; duration: number } {\n const start = performance.now();\n const result = fn();\n const duration = performance.now() - start;\n recordPerfEntry('render', name, duration);\n return { result, duration };\n}\n\n/**\n * Measure the time to execute an async function.\n */\nexport async function measureAsync<T>(\n name: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; duration: number }> {\n const start = performance.now();\n const result = await fn();\n const duration = performance.now() - start;\n recordPerfEntry('render', name, duration);\n return { result, duration };\n}\n\n/**\n * Create a named timer for manual start/stop measurement.\n *\n * ```ts\n * const timer = createTimer('data-fetch');\n * timer.start();\n * await fetch(...);\n * timer.stop(); // records the entry\n * timer.duration; // ms\n * ```\n */\nexport function createTimer(name: string) {\n let startTime = 0;\n let dur = 0;\n\n return {\n start() { startTime = performance.now(); },\n stop() {\n dur = performance.now() - startTime;\n recordPerfEntry('render', name, dur);\n },\n get duration() { return dur; },\n };\n}\n\n/**\n * Format a profile for console output.\n */\nexport function formatProfile(profile: PerfProfile): string {\n const summary = getProfileSummary(profile);\n let out = '\\n Performance Profile\\n';\n out += ' ' + '─'.repeat(50) + '\\n';\n out += ` Duration: ${profile.totalDuration.toFixed(1)} ms\\n`;\n out += ` Renders: ${summary.totalRenders} (avg ${summary.avgRenderTime.toFixed(2)} ms)\\n`;\n out += ` Effects: ${summary.totalEffects} (avg ${summary.avgEffectTime.toFixed(2)} ms)\\n`;\n out += ` Signal updates: ${summary.totalSignalUpdates}\\n`;\n out += ` Computed evals: ${summary.totalComputedEvals}\\n`;\n\n if (summary.slowestRender) {\n out += ` Slowest render: ${summary.slowestRender.name} (${summary.slowestRender.duration.toFixed(2)} ms)\\n`;\n }\n if (summary.slowestEffect) {\n out += ` Slowest effect: ${summary.slowestEffect.name} (${summary.slowestEffect.duration.toFixed(2)} ms)\\n`;\n }\n\n out += ' ' + '─'.repeat(50) + '\\n';\n return out;\n}\n","/**\n * Fine-grained reactivity system.\n *\n * Inspired by SolidJS/Preact Signals. Provides signal(), computed(),\n * effect(), and untrack() primitives with automatic dependency tracking\n * and glitch-free diamond dependency resolution.\n */\n\nimport { scheduleEffect, batch, enterBatch, exitBatch, type ScheduledEffect } from './scheduler.js';\nimport { recordPerfEntry, isProfiling } from './perf.js';\n\nconst __DEV__ = typeof process === 'undefined' || process.env?.NODE_ENV !== 'production';\n\n/** Depth counter to defer effect scheduling until all notifications complete (glitch-free) */\nlet notifyDepth = 0;\n\n// --- Tracking scope ---\n\ntype Subscriber = EffectNode | ComputedNode<unknown>;\n\nlet currentSubscriber: Subscriber | null = null;\n\n// --- Signal ---\n\nexport interface Signal<T> {\n /** Read the current value (tracks dependency if inside a reactive scope) */\n (): T;\n /** Set a new value */\n set(value: T): void;\n /** Update the value using the previous value */\n update(fn: (prev: T) => T): void;\n /** Read without tracking (no dependency registered) */\n peek(): T;\n}\n\nexport type ReadonlySignal<T> = () => T;\n\ninterface SignalNode<T> {\n value: T;\n subscribers: Set<Subscriber>;\n equals: (a: T, b: T) => boolean;\n}\n\nexport function signal<T>(\n initialValue: T,\n options?: { equals?: (a: T, b: T) => boolean },\n): Signal<T> {\n const node: SignalNode<T> = {\n value: initialValue,\n subscribers: new Set(),\n equals: options?.equals ?? Object.is,\n };\n\n const read = (): T => {\n trackSubscriber(node);\n return node.value;\n };\n\n read.set = (value: T): void => {\n if (__DEV__ && currentSubscriber && currentSubscriber._tag === 'computed') {\n console.warn('[AkashJS] Writing to a signal inside computed() is not allowed. The write will be lost on the next evaluation.');\n }\n if (node.equals(node.value, value)) return;\n node.value = value;\n if (isProfiling()) recordPerfEntry('signal-update', 'signal.set', 0);\n batch(() => { notifySubscribers(node); });\n };\n\n read.update = (fn: (prev: T) => T): void => {\n read.set(fn(node.value));\n };\n\n read.peek = (): T => node.value;\n\n return read;\n}\n\n// --- Computed ---\n\nconst enum ComputedState {\n Clean = 0,\n Dirty = 1,\n}\n\ninterface ComputedNode<T> {\n _tag: 'computed';\n fn: () => T;\n value: T | undefined;\n state: ComputedState;\n subscribers: Set<Subscriber>;\n sources: Set<SignalNode<unknown> | ComputedNode<unknown>>;\n equals: (a: T, b: T) => boolean;\n}\n\nexport function computed<T>(\n fn: () => T,\n options?: { equals?: (a: T, b: T) => boolean },\n): ReadonlySignal<T> {\n const node: ComputedNode<T> = {\n _tag: 'computed',\n fn,\n value: undefined,\n state: ComputedState.Dirty,\n subscribers: new Set(),\n sources: new Set(),\n equals: options?.equals ?? Object.is,\n };\n\n const read = (): T => {\n // Track this computed as a dependency of the current subscriber\n if (currentSubscriber) {\n node.subscribers.add(currentSubscriber);\n if ('sources' in currentSubscriber) {\n currentSubscriber.sources.add(node);\n }\n }\n\n if (node.state !== ComputedState.Clean) {\n recompute(node);\n }\n\n return node.value as T;\n };\n\n return read;\n}\n\nconst computingSet = new Set<ComputedNode<unknown>>();\n\n/**\n * @param skipEffectNotify - When true, don't schedule effects in notifySubscribers.\n * Used when recompute is called from runEffect's dirty check — the effect is\n * already being processed, re-scheduling it would trigger the circular run limit.\n */\nfunction recompute<T>(node: ComputedNode<T>, skipEffectNotify = false): void {\n // Detect circular computed dependencies — only if THIS node is already being computed\n if (computingSet.has(node as ComputedNode<unknown>)) {\n throw new Error('[AkashJS] Circular dependency detected between computed values.');\n }\n computingSet.add(node as ComputedNode<unknown>);\n\n // Prevent effects from flushing while computed is evaluating.\n // Without this, a computed that reads other dirty computeds can trigger\n // notifySubscribers → scheduleEffect → flush → re-enter recompute on\n // a node still in computingSet (false circular detection).\n enterBatch();\n\n // Clean up old source subscriptions\n for (const source of node.sources) {\n source.subscribers.delete(node);\n }\n node.sources.clear();\n\n const prevSubscriber = currentSubscriber;\n currentSubscriber = node;\n\n const _t0 = isProfiling() ? performance.now() : 0;\n try {\n const newValue = node.fn();\n const isFirst = node.value === undefined;\n const changed = isFirst || !node.equals(node.value, newValue);\n node.value = newValue;\n node.state = ComputedState.Clean;\n\n // Only propagate if value actually changed (skip first computation —\n // the effect that triggered the read is already running).\n if (changed && !isFirst) {\n if (skipEffectNotify) {\n // Only mark downstream computeds as dirty — don't schedule effects.\n // Effects are already handled by the runEffect that triggered this recompute.\n for (const sub of [...node.subscribers]) {\n if (sub._tag === 'computed') {\n sub.state = ComputedState.Dirty;\n // Recursively propagate to further computeds\n for (const sub2 of [...sub.subscribers]) {\n if (sub2._tag === 'computed') sub2.state = ComputedState.Dirty;\n }\n }\n }\n } else {\n notifySubscribers(node);\n }\n }\n } finally {\n if (_t0) recordPerfEntry('computed', 'computed', performance.now() - _t0);\n computingSet.delete(node as ComputedNode<unknown>);\n currentSubscriber = prevSubscriber;\n exitBatch();\n }\n}\n\n// --- Effect ---\n\ninterface EffectNode extends ScheduledEffect {\n _tag: 'effect';\n fn: () => void | (() => void);\n cleanup: (() => void) | null;\n sources: Set<SignalNode<unknown> | ComputedNode<unknown>>;\n disposed: boolean;\n isRender: boolean;\n}\n\nexport function effect(\n fn: () => void | (() => void),\n options?: { render?: boolean },\n): () => void {\n const node: EffectNode = {\n _tag: 'effect',\n fn,\n cleanup: null,\n sources: new Set(),\n disposed: false,\n isRender: options?.render ?? false,\n run() {\n runEffect(node);\n },\n };\n\n // Run immediately to establish dependencies\n runEffect(node);\n\n // Return dispose function\n return () => {\n node.disposed = true;\n cleanupEffect(node);\n for (const source of node.sources) {\n source.subscribers.delete(node);\n }\n node.sources.clear();\n };\n}\n\nfunction runEffect(node: EffectNode): void {\n if (node.disposed) return;\n\n // Before re-running, check if any dirty computed source actually changed.\n // Compare against per-effect cached values (not the shared source.value which\n // may have been updated by another effect's recompute already).\n if (node.sources.size > 0) {\n let anyChanged = false;\n for (const source of node.sources) {\n if ('_tag' in source && source._tag === 'computed') {\n if (source.state === ComputedState.Dirty) {\n recompute(source, true);\n }\n // Compare against this effect's last-seen value (not the shared source.value\n // which another effect's recompute may have already updated)\n const cachedValues = (node as any)._lastSeen as Map<unknown, unknown> | undefined;\n if (cachedValues?.has(source)) {\n const lastSeen = cachedValues.get(source);\n if (!source.equals(lastSeen as never, source.value as never)) {\n anyChanged = true;\n }\n } else {\n // No cached value — first dirty check after creation. Always run.\n anyChanged = true;\n }\n } else {\n // Plain signal source — if we got scheduled, something changed\n anyChanged = true;\n }\n }\n if (!anyChanged) return;\n }\n\n // Clean up previous run\n cleanupEffect(node);\n\n // Save old sources in case the effect throws — we need to re-subscribe\n const prevSources = new Set(node.sources);\n\n // Clean up old source subscriptions\n for (const source of node.sources) {\n source.subscribers.delete(node);\n }\n node.sources.clear();\n\n const prevSubscriber = currentSubscriber;\n currentSubscriber = node;\n const _t0 = isProfiling() ? performance.now() : 0;\n\n try {\n const result = node.fn();\n if (typeof result === 'function') {\n node.cleanup = result;\n }\n } catch (err) {\n // Re-subscribe to previous sources so the effect can recover on next change\n for (const source of prevSources) {\n source.subscribers.add(node);\n node.sources.add(source);\n }\n console.error('[AkashJS] Error in effect (will retry on next signal change):', err);\n } finally {\n if (_t0) recordPerfEntry('effect', 'effect', performance.now() - _t0);\n currentSubscriber = prevSubscriber;\n\n // Cache computed values so the next dirty check compares against THIS effect's\n // last-seen values, not the shared source.value (which another effect may update)\n const lastSeen = new Map();\n for (const source of node.sources) {\n if ('_tag' in source && source._tag === 'computed') {\n lastSeen.set(source, source.value);\n }\n }\n if (lastSeen.size > 0) (node as any)._lastSeen = lastSeen;\n }\n}\n\nfunction cleanupEffect(node: EffectNode): void {\n if (node.cleanup) {\n try {\n node.cleanup();\n } catch (err) {\n console.error('[AkashJS] Error in effect cleanup (ignored):', err);\n }\n node.cleanup = null;\n }\n}\n\n// --- Untrack ---\n\n/** Execute a function without tracking any signal reads */\nexport function untrack<T>(fn: () => T): T {\n const prev = currentSubscriber;\n currentSubscriber = null;\n try {\n return fn();\n } finally {\n currentSubscriber = prev;\n }\n}\n\n// --- on() helper ---\n\n/**\n * Create an effect callback that only tracks specific signals.\n * All other signal reads inside the callback are untracked.\n *\n * ```ts\n * effect(on(url, (currentUrl, prevUrl) => {\n * fetch(currentUrl, options()); // options() not tracked\n * }));\n *\n * effect(on([url, page], ([u, p], prev) => {\n * fetch(`${u}?page=${p}`);\n * }));\n * ```\n */\nexport function on<T>(\n dep: () => T,\n fn: (value: T, prev: T | undefined) => void | (() => void),\n options?: { defer?: boolean },\n): () => void | (() => void);\nexport function on<T extends readonly (() => unknown)[]>(\n deps: [...T],\n fn: (values: { [K in keyof T]: ReturnType<T[K]> }, prev: { [K in keyof T]: ReturnType<T[K]> } | undefined) => void | (() => void),\n options?: { defer?: boolean },\n): () => void | (() => void);\nexport function on(\n deps: (() => unknown) | (() => unknown)[],\n fn: (values: unknown, prev: unknown) => void | (() => void),\n options?: { defer?: boolean },\n): () => void | (() => void) {\n const isArray = Array.isArray(deps);\n const depArray = isArray ? deps : [deps];\n let prevValues: unknown[] | undefined;\n let isFirst = true;\n\n return () => {\n // Track only the specified deps\n const values = depArray.map(d => d());\n\n // Skip the initial effect run — only fire on actual changes\n // (pass { defer: false } to opt out and run immediately)\n if (isFirst) {\n isFirst = false;\n prevValues = values.slice();\n if (options?.defer !== false) return;\n }\n\n const prev = prevValues;\n prevValues = values.slice();\n\n // Run fn without tracking so reads inside don't create subscriptions\n return untrack(() => fn(\n isArray ? values : values[0],\n prev ? (isArray ? prev : prev[0]) : undefined,\n ));\n };\n}\n\n// --- Internal helpers ---\n\nfunction trackSubscriber(\n node: SignalNode<unknown> | ComputedNode<unknown>,\n): void {\n if (currentSubscriber) {\n node.subscribers.add(currentSubscriber);\n\n if ('sources' in currentSubscriber) {\n currentSubscriber.sources.add(node);\n }\n }\n}\n\nfunction notifySubscribers(\n node: SignalNode<unknown> | ComputedNode<unknown>,\n): void {\n // Snapshot subscribers before iterating. Effects that run synchronously\n // during flush() will delete and re-add themselves to the Set, and JS\n // Set iterators visit newly added entries — causing an infinite loop\n // without the snapshot.\n const subs = [...node.subscribers];\n for (const sub of subs) {\n if (sub._tag === 'computed') {\n // Mark dirty. The computed will re-evaluate lazily when read.\n sub.state = ComputedState.Dirty;\n // Propagate through the computed chain to reach effects.\n // The effects will re-read the computed, triggering recompute,\n // and only update DOM if the value actually changed.\n notifySubscribers(sub);\n } else if (sub._tag === 'effect') {\n scheduleEffect(sub);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/scheduler.ts","../src/perf.ts","../src/signals.ts"],"names":["pendingRender","pendingUser","flushing","batchDepth","reflushNeeded","MAX_EFFECT_RUNS","MAX_FLUSH_ITERATIONS","flush","runCounts","circularDetected","iterations","queue","byDepth","fx","count","scheduleEffect","batch","fn","enterBatch","exitBatch","a","b","flushSync","profiling","entries","profileStart","startProfiling","stopProfiling","endTime","isProfiling","recordPerfEntry","type","name","duration","getProfileSummary","profile","renders","e","effects","signalUpdates","computeds","avg","arr","s","slowest","measureSync","start","result","measureAsync","createTimer","startTime","dur","formatProfile","summary","out","__DEV__","currentSubscriber","signal","initialValue","options","node","read","trackSubscriber","value","notifySubscribers","computed","recompute","computingSet","skipEffectNotify","source","prevSubscriber","_t0","newValue","isFirst","changed","sub","sub2","effect","runEffect","cleanupEffect","anyChanged","cachedValues","lastSeen","prevSources","err","untrack","prev","on","deps","isArray","depArray","prevValues","values","d","subs"],"mappings":"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","file":"chunk-3AL2DVPZ.cjs","sourcesContent":["/**\n * Microtask-based effect scheduler with priority levels and deduplication.\n *\n * Render effects (DOM bindings) run before user effects to ensure\n * DOM is consistent before user-side effects execute.\n */\n\nexport interface ScheduledEffect {\n run(): void;\n isRender: boolean;\n /** Depth in the dependency graph (0 = root). Lower depth runs first. */\n depth?: number;\n}\n\nconst pendingRender = new Set<ScheduledEffect>();\nconst pendingUser = new Set<ScheduledEffect>();\nlet flushing = false;\nlet batchDepth = 0;\nlet flushScheduled = false;\nlet reflushNeeded = false;\n\nconst MAX_EFFECT_RUNS = 3;\nconst MAX_FLUSH_ITERATIONS = 100;\n\nfunction flush(): void {\n if (flushing) return;\n flushing = true;\n flushScheduled = false;\n\n // Fresh per-effect run counter for THIS flush — reset every time\n const runCounts = new Map<ScheduledEffect, number>();\n let circularDetected = false;\n\n // Process render effects first, then user effects.\n // Effects may enqueue more effects during flush, so loop until empty.\n let iterations = 0;\n while ((pendingRender.size > 0 || pendingUser.size > 0) && iterations < MAX_FLUSH_ITERATIONS) {\n iterations++;\n\n // Drain render effects (sorted by depth — parents before children)\n if (pendingRender.size > 0) {\n const queue = [...pendingRender].sort(byDepth);\n pendingRender.clear();\n for (const fx of queue) {\n const count = (runCounts.get(fx) ?? 0) + 1;\n runCounts.set(fx, count);\n if (count > MAX_EFFECT_RUNS) {\n circularDetected = true;\n continue; // skip this effect — it's in a cycle\n }\n fx.run();\n }\n }\n\n // Drain user effects (sorted by depth)\n if (pendingUser.size > 0) {\n const queue = [...pendingUser].sort(byDepth);\n pendingUser.clear();\n for (const fx of queue) {\n const count = (runCounts.get(fx) ?? 0) + 1;\n runCounts.set(fx, count);\n if (count > MAX_EFFECT_RUNS) {\n circularDetected = true;\n continue; // skip this effect — it's in a cycle\n }\n fx.run();\n }\n }\n\n // If all remaining effects were skipped due to cycle detection, break\n if (circularDetected && pendingRender.size === 0 && pendingUser.size === 0) {\n break;\n }\n }\n\n if (circularDetected || iterations >= MAX_FLUSH_ITERATIONS) {\n pendingRender.clear();\n pendingUser.clear();\n console.error(\n '[AkashJS] Circular dependency detected between effects. ' +\n 'Two or more effects are writing to each other\\'s dependencies. ' +\n 'The cycle has been broken after ' + iterations + ' iterations.'\n );\n }\n\n flushing = false;\n\n // If effects were scheduled during the tail end of this flush (after the\n // while loop's condition was last checked), re-flush them now.\n if (reflushNeeded) {\n reflushNeeded = false;\n if (pendingRender.size > 0 || pendingUser.size > 0) {\n flush();\n }\n }\n}\n\nexport function scheduleEffect(fx: ScheduledEffect): void {\n if (fx.isRender) {\n pendingRender.add(fx);\n } else {\n pendingUser.add(fx);\n }\n\n if (batchDepth === 0 && !flushing) {\n flush();\n } else if (flushing) {\n // Effects were added during a flush. The while loop may still pick them\n // up, but if it has already checked the queues and found them empty,\n // we need a re-flush after the current one completes.\n reflushNeeded = true;\n }\n}\n\n/**\n * Batch multiple signal writes — subscribers are notified only once\n * at the end of the batch.\n */\nexport function batch(fn: () => void): void {\n batchDepth++;\n try {\n fn();\n } finally {\n batchDepth--;\n if (batchDepth === 0) {\n flush();\n }\n }\n}\n\n/** Enter/exit batch depth — used by computed recompute to prevent mid-evaluation flush */\nexport function enterBatch(): void { batchDepth++; }\nexport function exitBatch(): void {\n batchDepth--;\n if (batchDepth === 0) flush();\n}\n\n/** Sort effects by depth (lower depth first = parents before children) */\nfunction byDepth(a: ScheduledEffect, b: ScheduledEffect): number {\n return (a.depth ?? 0) - (b.depth ?? 0);\n}\n\n/** Synchronously flush all pending effects. Useful for testing. */\nexport function flushSync(): void {\n flush();\n}\n","/**\n * Performance profiling utilities.\n *\n * Measure component render times, signal propagation, and\n * effect execution for performance debugging.\n *\n * ```ts\n * import { startProfiling, stopProfiling, getProfile } from '@akashjs/runtime';\n *\n * startProfiling();\n * // ... do stuff ...\n * stopProfiling();\n * console.table(getProfile().entries);\n * ```\n */\n\n// --- Types ---\n\nexport interface PerfEntry {\n type: 'render' | 'effect' | 'signal-update' | 'computed';\n name: string;\n duration: number;\n timestamp: number;\n}\n\nexport interface PerfProfile {\n entries: PerfEntry[];\n totalDuration: number;\n startTime: number;\n endTime: number;\n}\n\nexport interface PerfSummary {\n totalRenders: number;\n totalEffects: number;\n totalSignalUpdates: number;\n totalComputedEvals: number;\n avgRenderTime: number;\n avgEffectTime: number;\n slowestRender: PerfEntry | null;\n slowestEffect: PerfEntry | null;\n}\n\n// --- Profiling state ---\n\nlet profiling = false;\nlet entries: PerfEntry[] = [];\nlet profileStart = 0;\n\n// --- Public API ---\n\n/**\n * Start profiling. Clears previous data.\n */\nexport function startProfiling(): void {\n profiling = true;\n entries = [];\n profileStart = performance.now();\n}\n\n/**\n * Stop profiling.\n */\nexport function stopProfiling(): PerfProfile {\n profiling = false;\n const endTime = performance.now();\n\n return {\n entries: [...entries],\n totalDuration: endTime - profileStart,\n startTime: profileStart,\n endTime,\n };\n}\n\n/**\n * Check if profiling is active.\n */\nexport function isProfiling(): boolean {\n return profiling;\n}\n\n/**\n * Record a performance entry (called internally by the framework).\n */\nexport function recordPerfEntry(\n type: PerfEntry['type'],\n name: string,\n duration: number,\n): void {\n if (!profiling) return;\n entries.push({\n type,\n name,\n duration,\n timestamp: performance.now(),\n });\n}\n\n/**\n * Get a summary of the profiling data.\n */\nexport function getProfileSummary(profile: PerfProfile): PerfSummary {\n const renders = profile.entries.filter((e) => e.type === 'render');\n const effects = profile.entries.filter((e) => e.type === 'effect');\n const signalUpdates = profile.entries.filter((e) => e.type === 'signal-update');\n const computeds = profile.entries.filter((e) => e.type === 'computed');\n\n const avg = (arr: PerfEntry[]) =>\n arr.length > 0 ? arr.reduce((s, e) => s + e.duration, 0) / arr.length : 0;\n\n const slowest = (arr: PerfEntry[]) =>\n arr.length > 0 ? arr.reduce((s, e) => (e.duration > s.duration ? e : s)) : null;\n\n return {\n totalRenders: renders.length,\n totalEffects: effects.length,\n totalSignalUpdates: signalUpdates.length,\n totalComputedEvals: computeds.length,\n avgRenderTime: avg(renders),\n avgEffectTime: avg(effects),\n slowestRender: slowest(renders),\n slowestEffect: slowest(effects),\n };\n}\n\n// --- Measurement helpers ---\n\n/**\n * Measure the time to execute a function.\n *\n * ```ts\n * const { result, duration } = measureSync('my-operation', () => expensiveWork());\n * ```\n */\nexport function measureSync<T>(name: string, fn: () => T): { result: T; duration: number } {\n const start = performance.now();\n const result = fn();\n const duration = performance.now() - start;\n recordPerfEntry('render', name, duration);\n return { result, duration };\n}\n\n/**\n * Measure the time to execute an async function.\n */\nexport async function measureAsync<T>(\n name: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; duration: number }> {\n const start = performance.now();\n const result = await fn();\n const duration = performance.now() - start;\n recordPerfEntry('render', name, duration);\n return { result, duration };\n}\n\n/**\n * Create a named timer for manual start/stop measurement.\n *\n * ```ts\n * const timer = createTimer('data-fetch');\n * timer.start();\n * await fetch(...);\n * timer.stop(); // records the entry\n * timer.duration; // ms\n * ```\n */\nexport function createTimer(name: string) {\n let startTime = 0;\n let dur = 0;\n\n return {\n start() { startTime = performance.now(); },\n stop() {\n dur = performance.now() - startTime;\n recordPerfEntry('render', name, dur);\n },\n get duration() { return dur; },\n };\n}\n\n/**\n * Format a profile for console output.\n */\nexport function formatProfile(profile: PerfProfile): string {\n const summary = getProfileSummary(profile);\n let out = '\\n Performance Profile\\n';\n out += ' ' + '─'.repeat(50) + '\\n';\n out += ` Duration: ${profile.totalDuration.toFixed(1)} ms\\n`;\n out += ` Renders: ${summary.totalRenders} (avg ${summary.avgRenderTime.toFixed(2)} ms)\\n`;\n out += ` Effects: ${summary.totalEffects} (avg ${summary.avgEffectTime.toFixed(2)} ms)\\n`;\n out += ` Signal updates: ${summary.totalSignalUpdates}\\n`;\n out += ` Computed evals: ${summary.totalComputedEvals}\\n`;\n\n if (summary.slowestRender) {\n out += ` Slowest render: ${summary.slowestRender.name} (${summary.slowestRender.duration.toFixed(2)} ms)\\n`;\n }\n if (summary.slowestEffect) {\n out += ` Slowest effect: ${summary.slowestEffect.name} (${summary.slowestEffect.duration.toFixed(2)} ms)\\n`;\n }\n\n out += ' ' + '─'.repeat(50) + '\\n';\n return out;\n}\n","/**\n * Fine-grained reactivity system.\n *\n * Inspired by SolidJS/Preact Signals. Provides signal(), computed(),\n * effect(), and untrack() primitives with automatic dependency tracking\n * and glitch-free diamond dependency resolution.\n */\n\nimport { scheduleEffect, batch, enterBatch, exitBatch, type ScheduledEffect } from './scheduler.js';\nimport { recordPerfEntry, isProfiling } from './perf.js';\n\nconst __DEV__ = typeof process === 'undefined' || process.env?.NODE_ENV !== 'production';\n\n/** Depth counter to defer effect scheduling until all notifications complete (glitch-free) */\nlet notifyDepth = 0;\n\n// --- Tracking scope ---\n\ntype Subscriber = EffectNode | ComputedNode<any>;\n\nlet currentSubscriber: Subscriber | null = null;\n\n// --- Signal ---\n\nexport interface Signal<T> {\n /** Read the current value (tracks dependency if inside a reactive scope) */\n (): T;\n /** Set a new value */\n set(value: T): void;\n /** Update the value using the previous value */\n update(fn: (prev: T) => T): void;\n /** Read without tracking (no dependency registered) */\n peek(): T;\n}\n\nexport type ReadonlySignal<T> = () => T;\n\ninterface SignalNode<T> {\n value: T;\n subscribers: Set<Subscriber>;\n equals: (a: T, b: T) => boolean;\n}\n\nexport function signal<T>(\n initialValue: T,\n options?: { equals?: (a: T, b: T) => boolean },\n): Signal<T> {\n const node: SignalNode<T> = {\n value: initialValue,\n subscribers: new Set(),\n equals: options?.equals ?? Object.is,\n };\n\n const read = (): T => {\n trackSubscriber(node);\n return node.value;\n };\n\n read.set = (value: T): void => {\n if (__DEV__ && currentSubscriber && currentSubscriber._tag === 'computed') {\n console.warn('[AkashJS] Writing to a signal inside computed() is not allowed. The write will be lost on the next evaluation.');\n }\n if (node.equals(node.value, value)) return;\n node.value = value;\n if (isProfiling()) recordPerfEntry('signal-update', 'signal.set', 0);\n batch(() => { notifySubscribers(node); });\n };\n\n read.update = (fn: (prev: T) => T): void => {\n read.set(fn(node.value));\n };\n\n read.peek = (): T => node.value;\n\n return read;\n}\n\n// --- Computed ---\n\nconst enum ComputedState {\n Clean = 0,\n Dirty = 1,\n}\n\ninterface ComputedNode<T> {\n _tag: 'computed';\n fn: () => T;\n value: T | undefined;\n state: ComputedState;\n subscribers: Set<Subscriber>;\n sources: Set<SignalNode<any> | ComputedNode<any>>;\n equals: (a: T, b: T) => boolean;\n}\n\nexport function computed<T>(\n fn: () => T,\n options?: { equals?: (a: T, b: T) => boolean },\n): ReadonlySignal<T> {\n const node: ComputedNode<T> = {\n _tag: 'computed',\n fn,\n value: undefined,\n state: ComputedState.Dirty,\n subscribers: new Set(),\n sources: new Set(),\n equals: options?.equals ?? Object.is,\n };\n\n const read = (): T => {\n // Track this computed as a dependency of the current subscriber\n if (currentSubscriber) {\n node.subscribers.add(currentSubscriber);\n if ('sources' in currentSubscriber) {\n currentSubscriber.sources.add(node);\n }\n }\n\n if (node.state !== ComputedState.Clean) {\n recompute(node);\n }\n\n return node.value as T;\n };\n\n return read;\n}\n\nconst computingSet = new Set<ComputedNode<unknown>>();\n\n/**\n * @param skipEffectNotify - When true, don't schedule effects in notifySubscribers.\n * Used when recompute is called from runEffect's dirty check — the effect is\n * already being processed, re-scheduling it would trigger the circular run limit.\n */\nfunction recompute<T>(node: ComputedNode<T>, skipEffectNotify = false): void {\n // Detect circular computed dependencies — only if THIS node is already being computed\n if (computingSet.has(node as ComputedNode<unknown>)) {\n throw new Error('[AkashJS] Circular dependency detected between computed values.');\n }\n computingSet.add(node as ComputedNode<unknown>);\n\n // Prevent effects from flushing while computed is evaluating.\n // Without this, a computed that reads other dirty computeds can trigger\n // notifySubscribers → scheduleEffect → flush → re-enter recompute on\n // a node still in computingSet (false circular detection).\n enterBatch();\n\n // Clean up old source subscriptions\n for (const source of node.sources) {\n source.subscribers.delete(node);\n }\n node.sources.clear();\n\n const prevSubscriber = currentSubscriber;\n currentSubscriber = node;\n\n const _t0 = isProfiling() ? performance.now() : 0;\n try {\n const newValue = node.fn();\n const isFirst = node.value === undefined;\n const changed = isFirst || !node.equals(node.value as T, newValue);\n node.value = newValue;\n node.state = ComputedState.Clean;\n\n // Only propagate if value actually changed (skip first computation —\n // the effect that triggered the read is already running).\n if (changed && !isFirst) {\n if (skipEffectNotify) {\n // Only mark downstream computeds as dirty — don't schedule effects.\n // Effects are already handled by the runEffect that triggered this recompute.\n for (const sub of [...node.subscribers]) {\n if (sub._tag === 'computed') {\n sub.state = ComputedState.Dirty;\n // Recursively propagate to further computeds\n for (const sub2 of [...sub.subscribers]) {\n if (sub2._tag === 'computed') sub2.state = ComputedState.Dirty;\n }\n }\n }\n } else {\n notifySubscribers(node);\n }\n }\n } finally {\n if (_t0) recordPerfEntry('computed', 'computed', performance.now() - _t0);\n computingSet.delete(node as ComputedNode<unknown>);\n currentSubscriber = prevSubscriber;\n exitBatch();\n }\n}\n\n// --- Effect ---\n\ninterface EffectNode extends ScheduledEffect {\n _tag: 'effect';\n fn: () => void | (() => void);\n cleanup: (() => void) | null;\n sources: Set<SignalNode<any> | ComputedNode<any>>;\n disposed: boolean;\n isRender: boolean;\n}\n\nexport function effect(\n fn: () => void | (() => void),\n options?: { render?: boolean },\n): () => void {\n const node: EffectNode = {\n _tag: 'effect',\n fn,\n cleanup: null,\n sources: new Set(),\n disposed: false,\n isRender: options?.render ?? false,\n run() {\n runEffect(node);\n },\n };\n\n // Run immediately to establish dependencies\n runEffect(node);\n\n // Return dispose function\n return () => {\n node.disposed = true;\n cleanupEffect(node);\n for (const source of node.sources) {\n source.subscribers.delete(node);\n }\n node.sources.clear();\n };\n}\n\nfunction runEffect(node: EffectNode): void {\n if (node.disposed) return;\n\n // Before re-running, check if any dirty computed source actually changed.\n // Compare against per-effect cached values (not the shared source.value which\n // may have been updated by another effect's recompute already).\n if (node.sources.size > 0) {\n let anyChanged = false;\n for (const source of node.sources) {\n if ('_tag' in source && source._tag === 'computed') {\n if (source.state === ComputedState.Dirty) {\n recompute(source, true);\n }\n // Compare against this effect's last-seen value (not the shared source.value\n // which another effect's recompute may have already updated)\n const cachedValues = (node as any)._lastSeen as Map<unknown, unknown> | undefined;\n if (cachedValues?.has(source)) {\n const lastSeen = cachedValues.get(source);\n if (!source.equals(lastSeen as never, source.value as never)) {\n anyChanged = true;\n }\n } else {\n // No cached value — first dirty check after creation. Always run.\n anyChanged = true;\n }\n } else {\n // Plain signal source — if we got scheduled, something changed\n anyChanged = true;\n }\n }\n if (!anyChanged) return;\n }\n\n // Clean up previous run\n cleanupEffect(node);\n\n // Save old sources in case the effect throws — we need to re-subscribe\n const prevSources = new Set(node.sources);\n\n // Clean up old source subscriptions\n for (const source of node.sources) {\n source.subscribers.delete(node);\n }\n node.sources.clear();\n\n const prevSubscriber = currentSubscriber;\n currentSubscriber = node;\n const _t0 = isProfiling() ? performance.now() : 0;\n\n try {\n const result = node.fn();\n if (typeof result === 'function') {\n node.cleanup = result;\n }\n } catch (err) {\n // Re-subscribe to previous sources so the effect can recover on next change\n for (const source of prevSources) {\n source.subscribers.add(node);\n node.sources.add(source);\n }\n console.error('[AkashJS] Error in effect (will retry on next signal change):', err);\n } finally {\n if (_t0) recordPerfEntry('effect', 'effect', performance.now() - _t0);\n currentSubscriber = prevSubscriber;\n\n // Cache computed values so the next dirty check compares against THIS effect's\n // last-seen values, not the shared source.value (which another effect may update)\n const lastSeen = new Map();\n for (const source of node.sources) {\n if ('_tag' in source && source._tag === 'computed') {\n lastSeen.set(source, source.value);\n }\n }\n if (lastSeen.size > 0) (node as any)._lastSeen = lastSeen;\n }\n}\n\nfunction cleanupEffect(node: EffectNode): void {\n if (node.cleanup) {\n try {\n node.cleanup();\n } catch (err) {\n console.error('[AkashJS] Error in effect cleanup (ignored):', err);\n }\n node.cleanup = null;\n }\n}\n\n// --- Untrack ---\n\n/** Execute a function without tracking any signal reads */\nexport function untrack<T>(fn: () => T): T {\n const prev = currentSubscriber;\n currentSubscriber = null;\n try {\n return fn();\n } finally {\n currentSubscriber = prev;\n }\n}\n\n// --- on() helper ---\n\n/**\n * Create an effect callback that only tracks specific signals.\n * All other signal reads inside the callback are untracked.\n *\n * ```ts\n * effect(on(url, (currentUrl, prevUrl) => {\n * fetch(currentUrl, options()); // options() not tracked\n * }));\n *\n * effect(on([url, page], ([u, p], prev) => {\n * fetch(`${u}?page=${p}`);\n * }));\n * ```\n */\nexport function on<T>(\n dep: () => T,\n fn: (value: T, prev: T | undefined) => void | (() => void),\n options?: { defer?: boolean },\n): () => void | (() => void);\nexport function on<T extends readonly (() => unknown)[]>(\n deps: [...T],\n fn: (values: { [K in keyof T]: ReturnType<T[K]> }, prev: { [K in keyof T]: ReturnType<T[K]> } | undefined) => void | (() => void),\n options?: { defer?: boolean },\n): () => void | (() => void);\nexport function on(\n deps: (() => any) | (() => any)[],\n fn: (values: any, prev: any) => void | (() => void),\n options?: { defer?: boolean },\n): () => void | (() => void) {\n const isArray = Array.isArray(deps);\n const depArray = isArray ? deps : [deps];\n let prevValues: unknown[] | undefined;\n let isFirst = true;\n\n return () => {\n // Track only the specified deps\n const values = depArray.map(d => d());\n\n // Skip the initial effect run — only fire on actual changes\n // (pass { defer: false } to opt out and run immediately)\n if (isFirst) {\n isFirst = false;\n prevValues = values.slice();\n if (options?.defer !== false) return;\n }\n\n const prev = prevValues;\n prevValues = values.slice();\n\n // Run fn without tracking so reads inside don't create subscriptions\n return untrack(() => fn(\n isArray ? values : values[0],\n prev ? (isArray ? prev : prev[0]) : undefined,\n ));\n };\n}\n\n// --- Internal helpers ---\n\nfunction trackSubscriber(\n node: SignalNode<any> | ComputedNode<any>,\n): void {\n if (currentSubscriber) {\n node.subscribers.add(currentSubscriber);\n\n if ('sources' in currentSubscriber) {\n currentSubscriber.sources.add(node);\n }\n }\n}\n\nfunction notifySubscribers(\n node: SignalNode<any> | ComputedNode<any>,\n): void {\n // Snapshot subscribers before iterating. Effects that run synchronously\n // during flush() will delete and re-add themselves to the Set, and JS\n // Set iterators visit newly added entries — causing an infinite loop\n // without the snapshot.\n const subs = [...node.subscribers];\n for (const sub of subs) {\n if (sub._tag === 'computed') {\n // Mark dirty. The computed will re-evaluate lazily when read.\n sub.state = ComputedState.Dirty;\n // Propagate through the computed chain to reach effects.\n // The effects will re-read the computed, triggering recompute,\n // and only update DOM if the value actually changed.\n notifySubscribers(sub);\n } else if (sub._tag === 'effect') {\n scheduleEffect(sub);\n }\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunk3AL2DVPZ_cjs=require('./chunk-3AL2DVPZ.cjs');function f(r,e={}){let t=chunk3AL2DVPZ_cjs.l(false),a=chunk3AL2DVPZ_cjs.l(false),s=chunk3AL2DVPZ_cjs.l(!navigator.onLine),i=null;window.addEventListener("online",()=>s.set(false)),window.addEventListener("offline",()=>s.set(true));let u=new Promise((h,l)=>{if(!("serviceWorker"in navigator)){l(new Error("Service workers not supported"));return}navigator.serviceWorker.register(r,{scope:e.scope}).then(n=>{i=n,t.set(true),e.onReady?.(n),h(n),n.addEventListener("updatefound",()=>{let o=n.installing;o&&o.addEventListener("statechange",()=>{o.state==="installed"&&navigator.serviceWorker.controller&&(a.set(true),e.onUpdate?.(n),e.autoReload&&(o.postMessage({type:"SKIP_WAITING"}),window.location.reload()));});});}).catch(n=>{e.onError?.(n),l(n);});});return {registered:()=>t(),updateAvailable:()=>a(),offline:()=>s(),ready:u,async update(){i&&await i.update();},skipWaiting(){i?.waiting&&(i.waiting.postMessage({type:"SKIP_WAITING"}),window.location.reload());},async unregister(){return i?i.unregister():false}}}function v(r){let e=`// Auto-generated service worker by AkashJS
|
|
2
2
|
const CACHE_VERSION = 'v1';
|
|
3
3
|
|
|
4
4
|
self.addEventListener('install', (event) => {
|
|
@@ -28,5 +28,5 @@ self.addEventListener('fetch', (event) => {
|
|
|
28
28
|
fetch(event.request).catch(() => caches.match(event.request))
|
|
29
29
|
);
|
|
30
30
|
});
|
|
31
|
-
`,e}function p(r,e){switch(r){case "cache-first":return `caches.match(event.request).then(cached => cached || fetch(event.request).then(response => { const clone = response.clone(); caches.open('${e}').then(cache => cache.put(event.request, clone)); return response; }))`;case "network-first":return `fetch(event.request).then(response => { const clone = response.clone(); caches.open('${e}').then(cache => cache.put(event.request, clone)); return response; }).catch(() => caches.match(event.request))`;case "stale-while-revalidate":return `caches.match(event.request).then(cached => { const fetchPromise = fetch(event.request).then(response => { caches.open('${e}').then(cache => cache.put(event.request, response.clone())); return response; }); return cached || fetchPromise; })`;case "network-only":return "fetch(event.request)";case "cache-only":return "caches.match(event.request)"}}async function y(r,e){return await Notification.requestPermission()!=="granted"?null:await r.pushManager.subscribe({userVisibleOnly:true,applicationServerKey:d(e)})}function d(r){let e="=".repeat((4-r.length%4)%4),t=(r+e).replace(/-/g,"+").replace(/_/g,"/"),a=atob(t);return Uint8Array.from(a,s=>s.charCodeAt(0))}exports.a=f;exports.b=v;exports.c=y;//# sourceMappingURL=chunk-
|
|
32
|
-
//# sourceMappingURL=chunk-
|
|
31
|
+
`,e}function p(r,e){switch(r){case "cache-first":return `caches.match(event.request).then(cached => cached || fetch(event.request).then(response => { const clone = response.clone(); caches.open('${e}').then(cache => cache.put(event.request, clone)); return response; }))`;case "network-first":return `fetch(event.request).then(response => { const clone = response.clone(); caches.open('${e}').then(cache => cache.put(event.request, clone)); return response; }).catch(() => caches.match(event.request))`;case "stale-while-revalidate":return `caches.match(event.request).then(cached => { const fetchPromise = fetch(event.request).then(response => { caches.open('${e}').then(cache => cache.put(event.request, response.clone())); return response; }); return cached || fetchPromise; })`;case "network-only":return "fetch(event.request)";case "cache-only":return "caches.match(event.request)"}}async function y(r,e){return await Notification.requestPermission()!=="granted"?null:await r.pushManager.subscribe({userVisibleOnly:true,applicationServerKey:d(e)})}function d(r){let e="=".repeat((4-r.length%4)%4),t=(r+e).replace(/-/g,"+").replace(/_/g,"/"),a=atob(t);return Uint8Array.from(a,s=>s.charCodeAt(0))}exports.a=f;exports.b=v;exports.c=y;//# sourceMappingURL=chunk-6NX6JRSV.cjs.map
|
|
32
|
+
//# sourceMappingURL=chunk-6NX6JRSV.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pwa.ts"],"names":["registerServiceWorker","swUrl","options","registered","signal","updateAvailable","offline","registration","ready","resolve","reject","reg","newWorker","err","generateSWScript","routes","script","route","pattern","cacheName","generateStrategyCode","strategy","subscribePush","vapidPublicKey","urlBase64ToUint8Array","base64String","padding","base64","rawData","char"],"mappings":"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","file":"chunk-CHF5LH56.cjs","sourcesContent":["/**\n * PWA / Service Worker support.\n *\n * Register service workers, configure caching strategies,\n * handle updates, and manage push notifications.\n *\n * ```ts\n * const sw = registerServiceWorker('/sw.js', {\n * onUpdate: () => toast.info('New version available!'),\n * });\n * sw.ready; // Promise<ServiceWorkerRegistration>\n * sw.update(); // check for updates\n * ```\n */\n\nimport { signal } from './signals.js';\nimport type { ReadonlySignal } from './signals.js';\n\n// =========================================================================\n// Types\n// =========================================================================\n\nexport interface SWOptions {\n /** Callback when a new version is available */\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n /** Callback when the SW is ready */\n onReady?: (registration: ServiceWorkerRegistration) => void;\n /** Callback on registration error */\n onError?: (error: Error) => void;\n /** Auto-reload on update (default: false) */\n autoReload?: boolean;\n /** Scope of the service worker */\n scope?: string;\n}\n\nexport interface SWRegistration {\n /** Whether the SW is registered */\n registered: ReadonlySignal<boolean>;\n /** Whether an update is available */\n updateAvailable: ReadonlySignal<boolean>;\n /** Whether the app is running offline */\n offline: ReadonlySignal<boolean>;\n /** The raw SW registration (available after ready) */\n ready: Promise<ServiceWorkerRegistration>;\n /** Check for updates */\n update(): Promise<void>;\n /** Skip waiting and activate new SW */\n skipWaiting(): void;\n /** Unregister the service worker */\n unregister(): Promise<boolean>;\n}\n\n// =========================================================================\n// Service Worker registration\n// =========================================================================\n\n/**\n * Register a service worker with update detection.\n */\nexport function registerServiceWorker(\n swUrl: string,\n options: SWOptions = {},\n): SWRegistration {\n const registered = signal(false);\n const updateAvailable = signal(false);\n const offline = signal(!navigator.onLine);\n\n let registration: ServiceWorkerRegistration | null = null;\n\n // Track online/offline\n window.addEventListener('online', () => offline.set(false));\n window.addEventListener('offline', () => offline.set(true));\n\n const ready = new Promise<ServiceWorkerRegistration>((resolve, reject) => {\n if (!('serviceWorker' in navigator)) {\n reject(new Error('Service workers not supported'));\n return;\n }\n\n navigator.serviceWorker\n .register(swUrl, { scope: options.scope })\n .then((reg) => {\n registration = reg;\n registered.set(true);\n options.onReady?.(reg);\n resolve(reg);\n\n // Listen for updates\n reg.addEventListener('updatefound', () => {\n const newWorker = reg.installing;\n if (!newWorker) return;\n\n newWorker.addEventListener('statechange', () => {\n if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {\n updateAvailable.set(true);\n options.onUpdate?.(reg);\n\n if (options.autoReload) {\n newWorker.postMessage({ type: 'SKIP_WAITING' });\n window.location.reload();\n }\n }\n });\n });\n })\n .catch((err) => {\n options.onError?.(err);\n reject(err);\n });\n });\n\n return {\n registered: () => registered(),\n updateAvailable: () => updateAvailable(),\n offline: () => offline(),\n ready,\n async update() {\n if (registration) {\n await registration.update();\n }\n },\n skipWaiting() {\n if (registration?.waiting) {\n registration.waiting.postMessage({ type: 'SKIP_WAITING' });\n window.location.reload();\n }\n },\n async unregister() {\n if (registration) {\n return registration.unregister();\n }\n return false;\n },\n };\n}\n\n// =========================================================================\n// Caching strategies (for SW scripts)\n// =========================================================================\n\nexport type CacheStrategy = 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'network-only' | 'cache-only';\n\nexport interface CacheRoute {\n /** URL pattern to match (string or regex) */\n match: string | RegExp;\n /** Caching strategy */\n strategy: CacheStrategy;\n /** Cache name */\n cacheName?: string;\n /** Max entries in cache */\n maxEntries?: number;\n /** Max age in seconds */\n maxAgeSeconds?: number;\n}\n\n/**\n * Generate a service worker script from cache route configs.\n *\n * ```ts\n * const swScript = generateSWScript([\n * { match: /\\.(?:js|css)$/, strategy: 'cache-first', cacheName: 'assets' },\n * { match: '/api/', strategy: 'network-first', maxAgeSeconds: 300 },\n * { match: /\\.(?:png|jpg|svg)$/, strategy: 'cache-first', cacheName: 'images' },\n * ]);\n * ```\n */\nexport function generateSWScript(routes: CacheRoute[]): string {\n let script = `// Auto-generated service worker by AkashJS\nconst CACHE_VERSION = 'v1';\n\nself.addEventListener('install', (event) => {\n self.skipWaiting();\n});\n\nself.addEventListener('activate', (event) => {\n event.waitUntil(clients.claim());\n});\n\nself.addEventListener('message', (event) => {\n if (event.data?.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\nself.addEventListener('fetch', (event) => {\n const url = new URL(event.request.url);\n`;\n\n for (const route of routes) {\n const pattern = route.match instanceof RegExp\n ? route.match.toString()\n : `new RegExp(${JSON.stringify(route.match.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))})`;\n\n const cacheName = route.cacheName ?? 'akash-cache';\n\n script += `\n if (${pattern}.test(url.pathname)) {\n event.respondWith(${generateStrategyCode(route.strategy, cacheName)});\n return;\n }\n`;\n }\n\n script += `\n // Default: network-first\n event.respondWith(\n fetch(event.request).catch(() => caches.match(event.request))\n );\n});\n`;\n\n return script;\n}\n\nfunction generateStrategyCode(strategy: CacheStrategy, cacheName: string): string {\n switch (strategy) {\n case 'cache-first':\n return `caches.match(event.request).then(cached => cached || fetch(event.request).then(response => { const clone = response.clone(); caches.open('${cacheName}').then(cache => cache.put(event.request, clone)); return response; }))`;\n case 'network-first':\n return `fetch(event.request).then(response => { const clone = response.clone(); caches.open('${cacheName}').then(cache => cache.put(event.request, clone)); return response; }).catch(() => caches.match(event.request))`;\n case 'stale-while-revalidate':\n return `caches.match(event.request).then(cached => { const fetchPromise = fetch(event.request).then(response => { caches.open('${cacheName}').then(cache => cache.put(event.request, response.clone())); return response; }); return cached || fetchPromise; })`;\n case 'network-only':\n return `fetch(event.request)`;\n case 'cache-only':\n return `caches.match(event.request)`;\n }\n}\n\n// =========================================================================\n// Push notifications\n// =========================================================================\n\n/**\n * Request push notification permission and subscribe.\n */\nexport async function subscribePush(\n registration: ServiceWorkerRegistration,\n vapidPublicKey: string,\n): Promise<PushSubscription | null> {\n const permission = await Notification.requestPermission();\n if (permission !== 'granted') return null;\n\n const subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: urlBase64ToUint8Array(vapidPublicKey),\n });\n\n return subscription;\n}\n\nfunction urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n const rawData = atob(base64);\n return Uint8Array.from(rawData, (char) => char.charCodeAt(0));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/pwa.ts"],"names":["registerServiceWorker","swUrl","options","registered","signal","updateAvailable","offline","registration","ready","resolve","reject","reg","newWorker","err","generateSWScript","routes","script","route","pattern","cacheName","generateStrategyCode","strategy","subscribePush","vapidPublicKey","urlBase64ToUint8Array","base64String","padding","base64","rawData","char"],"mappings":"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","file":"chunk-6NX6JRSV.cjs","sourcesContent":["/**\n * PWA / Service Worker support.\n *\n * Register service workers, configure caching strategies,\n * handle updates, and manage push notifications.\n *\n * ```ts\n * const sw = registerServiceWorker('/sw.js', {\n * onUpdate: () => toast.info('New version available!'),\n * });\n * sw.ready; // Promise<ServiceWorkerRegistration>\n * sw.update(); // check for updates\n * ```\n */\n\nimport { signal } from './signals.js';\nimport type { ReadonlySignal } from './signals.js';\n\n// =========================================================================\n// Types\n// =========================================================================\n\nexport interface SWOptions {\n /** Callback when a new version is available */\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n /** Callback when the SW is ready */\n onReady?: (registration: ServiceWorkerRegistration) => void;\n /** Callback on registration error */\n onError?: (error: Error) => void;\n /** Auto-reload on update (default: false) */\n autoReload?: boolean;\n /** Scope of the service worker */\n scope?: string;\n}\n\nexport interface SWRegistration {\n /** Whether the SW is registered */\n registered: ReadonlySignal<boolean>;\n /** Whether an update is available */\n updateAvailable: ReadonlySignal<boolean>;\n /** Whether the app is running offline */\n offline: ReadonlySignal<boolean>;\n /** The raw SW registration (available after ready) */\n ready: Promise<ServiceWorkerRegistration>;\n /** Check for updates */\n update(): Promise<void>;\n /** Skip waiting and activate new SW */\n skipWaiting(): void;\n /** Unregister the service worker */\n unregister(): Promise<boolean>;\n}\n\n// =========================================================================\n// Service Worker registration\n// =========================================================================\n\n/**\n * Register a service worker with update detection.\n */\nexport function registerServiceWorker(\n swUrl: string,\n options: SWOptions = {},\n): SWRegistration {\n const registered = signal(false);\n const updateAvailable = signal(false);\n const offline = signal(!navigator.onLine);\n\n let registration: ServiceWorkerRegistration | null = null;\n\n // Track online/offline\n window.addEventListener('online', () => offline.set(false));\n window.addEventListener('offline', () => offline.set(true));\n\n const ready = new Promise<ServiceWorkerRegistration>((resolve, reject) => {\n if (!('serviceWorker' in navigator)) {\n reject(new Error('Service workers not supported'));\n return;\n }\n\n navigator.serviceWorker\n .register(swUrl, { scope: options.scope })\n .then((reg) => {\n registration = reg;\n registered.set(true);\n options.onReady?.(reg);\n resolve(reg);\n\n // Listen for updates\n reg.addEventListener('updatefound', () => {\n const newWorker = reg.installing;\n if (!newWorker) return;\n\n newWorker.addEventListener('statechange', () => {\n if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {\n updateAvailable.set(true);\n options.onUpdate?.(reg);\n\n if (options.autoReload) {\n newWorker.postMessage({ type: 'SKIP_WAITING' });\n window.location.reload();\n }\n }\n });\n });\n })\n .catch((err) => {\n options.onError?.(err);\n reject(err);\n });\n });\n\n return {\n registered: () => registered(),\n updateAvailable: () => updateAvailable(),\n offline: () => offline(),\n ready,\n async update() {\n if (registration) {\n await registration.update();\n }\n },\n skipWaiting() {\n if (registration?.waiting) {\n registration.waiting.postMessage({ type: 'SKIP_WAITING' });\n window.location.reload();\n }\n },\n async unregister() {\n if (registration) {\n return registration.unregister();\n }\n return false;\n },\n };\n}\n\n// =========================================================================\n// Caching strategies (for SW scripts)\n// =========================================================================\n\nexport type CacheStrategy = 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'network-only' | 'cache-only';\n\nexport interface CacheRoute {\n /** URL pattern to match (string or regex) */\n match: string | RegExp;\n /** Caching strategy */\n strategy: CacheStrategy;\n /** Cache name */\n cacheName?: string;\n /** Max entries in cache */\n maxEntries?: number;\n /** Max age in seconds */\n maxAgeSeconds?: number;\n}\n\n/**\n * Generate a service worker script from cache route configs.\n *\n * ```ts\n * const swScript = generateSWScript([\n * { match: /\\.(?:js|css)$/, strategy: 'cache-first', cacheName: 'assets' },\n * { match: '/api/', strategy: 'network-first', maxAgeSeconds: 300 },\n * { match: /\\.(?:png|jpg|svg)$/, strategy: 'cache-first', cacheName: 'images' },\n * ]);\n * ```\n */\nexport function generateSWScript(routes: CacheRoute[]): string {\n let script = `// Auto-generated service worker by AkashJS\nconst CACHE_VERSION = 'v1';\n\nself.addEventListener('install', (event) => {\n self.skipWaiting();\n});\n\nself.addEventListener('activate', (event) => {\n event.waitUntil(clients.claim());\n});\n\nself.addEventListener('message', (event) => {\n if (event.data?.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\nself.addEventListener('fetch', (event) => {\n const url = new URL(event.request.url);\n`;\n\n for (const route of routes) {\n const pattern = route.match instanceof RegExp\n ? route.match.toString()\n : `new RegExp(${JSON.stringify(route.match.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))})`;\n\n const cacheName = route.cacheName ?? 'akash-cache';\n\n script += `\n if (${pattern}.test(url.pathname)) {\n event.respondWith(${generateStrategyCode(route.strategy, cacheName)});\n return;\n }\n`;\n }\n\n script += `\n // Default: network-first\n event.respondWith(\n fetch(event.request).catch(() => caches.match(event.request))\n );\n});\n`;\n\n return script;\n}\n\nfunction generateStrategyCode(strategy: CacheStrategy, cacheName: string): string {\n switch (strategy) {\n case 'cache-first':\n return `caches.match(event.request).then(cached => cached || fetch(event.request).then(response => { const clone = response.clone(); caches.open('${cacheName}').then(cache => cache.put(event.request, clone)); return response; }))`;\n case 'network-first':\n return `fetch(event.request).then(response => { const clone = response.clone(); caches.open('${cacheName}').then(cache => cache.put(event.request, clone)); return response; }).catch(() => caches.match(event.request))`;\n case 'stale-while-revalidate':\n return `caches.match(event.request).then(cached => { const fetchPromise = fetch(event.request).then(response => { caches.open('${cacheName}').then(cache => cache.put(event.request, response.clone())); return response; }); return cached || fetchPromise; })`;\n case 'network-only':\n return `fetch(event.request)`;\n case 'cache-only':\n return `caches.match(event.request)`;\n }\n}\n\n// =========================================================================\n// Push notifications\n// =========================================================================\n\n/**\n * Request push notification permission and subscribe.\n */\nexport async function subscribePush(\n registration: ServiceWorkerRegistration,\n vapidPublicKey: string,\n): Promise<PushSubscription | null> {\n const permission = await Notification.requestPermission();\n if (permission !== 'granted') return null;\n\n const subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n applicationServerKey: urlBase64ToUint8Array(vapidPublicKey) as any,\n });\n\n return subscription;\n}\n\nfunction urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n const rawData = atob(base64);\n return Uint8Array.from(rawData, (char) => char.charCodeAt(0));\n}\n"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {l,m,n}from'./chunk-POLTPHUA.js';var k=[];function v(s){k.push(...s.plugins);}var g=new Map;function R(s,a){return ()=>{if(g.has(s))return g.get(s);let r=a.state(),o=A(s,r,a);return g.set(s,o),o}}function A(s,a,r){let o={},c=Object.keys(a);for(let t of c)o[t]=l(a[t]);let n$1={$id:s};for(let t of c)n$1[t]=o[t];if(r.getters)for(let[t,e]of Object.entries(r.getters))n$1[t]=m(()=>e.call(n$1,o));let y=[...k,...r.plugins??[]];if(r.actions)for(let[t,e]of Object.entries(r.actions))n$1[t]=(...i)=>{for(let f of y)f.onAction?.(n$1,t,i);return e.apply(n$1,i)};n$1.$reset=()=>{let t=r.state();for(let e of c)o[e].set(t[e]);},n$1.$patch=t=>{if(typeof t=="function")t(o);else for(let[e,i]of Object.entries(t))e in o&&o[e].set(i);},n$1.$snapshot=()=>{let t={};for(let e of c)t[e]=o[e]();return t};let l$1=new Set,S=null;n$1.$subscribe=t=>{if(l$1.add(t),!S){let e=true;S=n(()=>{for(let f of c)o[f]();if(e){e=false;return}let i=n$1.$snapshot();for(let f of l$1)f(i);});}return ()=>{l$1.delete(t),l$1.size===0&&S&&(S(),S=null);}};for(let t of y)t.init?.(n$1);return n$1}function x(){g.clear();}function b(){return Object.fromEntries(g)}export{v as a,R as b,x as c,b as d};//# sourceMappingURL=chunk-772SU4MG.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-772SU4MG.js.map
|