@ersbeth/picoflow 0.2.4 → 1.0.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.
Files changed (248) hide show
  1. package/.cursor/plans/update-js-e795d61b.plan.md +567 -0
  2. package/.gitlab-ci.yml +24 -0
  3. package/.vscode/settings.json +3 -3
  4. package/CHANGELOG.md +51 -0
  5. package/IMPLEMENTATION_GUIDE.md +1578 -0
  6. package/README.md +9 -134
  7. package/biome.json +32 -32
  8. package/dist/picoflow.js +610 -436
  9. package/dist/types/advanced/array.d.ts +0 -6
  10. package/dist/types/advanced/array.d.ts.map +1 -1
  11. package/dist/types/advanced/index.d.ts +5 -5
  12. package/dist/types/advanced/index.d.ts.map +1 -1
  13. package/dist/types/advanced/map.d.ts +114 -23
  14. package/dist/types/advanced/map.d.ts.map +1 -1
  15. package/dist/types/advanced/resource.d.ts +51 -12
  16. package/dist/types/advanced/resource.d.ts.map +1 -1
  17. package/dist/types/advanced/resourceAsync.d.ts +28 -13
  18. package/dist/types/advanced/resourceAsync.d.ts.map +1 -1
  19. package/dist/types/advanced/stream.d.ts +74 -16
  20. package/dist/types/advanced/stream.d.ts.map +1 -1
  21. package/dist/types/advanced/streamAsync.d.ts +69 -15
  22. package/dist/types/advanced/streamAsync.d.ts.map +1 -1
  23. package/dist/types/basic/constant.d.ts +44 -16
  24. package/dist/types/basic/constant.d.ts.map +1 -1
  25. package/dist/types/basic/derivation.d.ts +73 -24
  26. package/dist/types/basic/derivation.d.ts.map +1 -1
  27. package/dist/types/basic/disposable.d.ts +65 -6
  28. package/dist/types/basic/disposable.d.ts.map +1 -1
  29. package/dist/types/basic/effect.d.ts +27 -16
  30. package/dist/types/basic/effect.d.ts.map +1 -1
  31. package/dist/types/basic/index.d.ts +7 -8
  32. package/dist/types/basic/index.d.ts.map +1 -1
  33. package/dist/types/basic/observable.d.ts +62 -13
  34. package/dist/types/basic/observable.d.ts.map +1 -1
  35. package/dist/types/basic/signal.d.ts +35 -6
  36. package/dist/types/basic/signal.d.ts.map +1 -1
  37. package/dist/types/basic/state.d.ts +25 -4
  38. package/dist/types/basic/state.d.ts.map +1 -1
  39. package/dist/types/basic/trackingContext.d.ts +33 -0
  40. package/dist/types/basic/trackingContext.d.ts.map +1 -0
  41. package/dist/types/creators.d.ts +271 -26
  42. package/dist/types/creators.d.ts.map +1 -1
  43. package/dist/types/index.d.ts +60 -7
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/solid/converters.d.ts +5 -5
  46. package/dist/types/solid/converters.d.ts.map +1 -1
  47. package/dist/types/solid/index.d.ts +2 -2
  48. package/dist/types/solid/index.d.ts.map +1 -1
  49. package/dist/types/solid/primitives.d.ts +96 -4
  50. package/dist/types/solid/primitives.d.ts.map +1 -1
  51. package/docs/.vitepress/config.mts +110 -0
  52. package/docs/api/classes/FlowArray.md +489 -0
  53. package/docs/api/classes/FlowConstant.md +350 -0
  54. package/docs/api/classes/FlowDerivation.md +334 -0
  55. package/docs/api/classes/FlowEffect.md +100 -0
  56. package/docs/api/classes/FlowMap.md +512 -0
  57. package/docs/api/classes/FlowObservable.md +306 -0
  58. package/docs/api/classes/FlowResource.md +380 -0
  59. package/docs/api/classes/FlowResourceAsync.md +362 -0
  60. package/docs/api/classes/FlowSignal.md +160 -0
  61. package/docs/api/classes/FlowState.md +368 -0
  62. package/docs/api/classes/FlowStream.md +367 -0
  63. package/docs/api/classes/FlowStreamAsync.md +364 -0
  64. package/docs/api/classes/SolidDerivation.md +75 -0
  65. package/docs/api/classes/SolidResource.md +91 -0
  66. package/docs/api/classes/SolidState.md +71 -0
  67. package/docs/api/classes/TrackingContext.md +33 -0
  68. package/docs/api/functions/array.md +58 -0
  69. package/docs/api/functions/constant.md +45 -0
  70. package/docs/api/functions/derivation.md +53 -0
  71. package/docs/api/functions/effect.md +49 -0
  72. package/docs/api/functions/from.md +220 -0
  73. package/docs/api/functions/isDisposable.md +49 -0
  74. package/docs/api/functions/map.md +57 -0
  75. package/docs/api/functions/resource.md +52 -0
  76. package/docs/api/functions/resourceAsync.md +50 -0
  77. package/docs/api/functions/signal.md +36 -0
  78. package/docs/api/functions/state.md +47 -0
  79. package/docs/api/functions/stream.md +53 -0
  80. package/docs/api/functions/streamAsync.md +50 -0
  81. package/docs/api/index.md +118 -0
  82. package/docs/api/interfaces/FlowDisposable.md +65 -0
  83. package/docs/api/interfaces/SolidObservable.md +19 -0
  84. package/docs/api/type-aliases/FlowArrayAction.md +49 -0
  85. package/docs/api/type-aliases/FlowStreamDisposer.md +15 -0
  86. package/docs/api/type-aliases/FlowStreamSetter.md +27 -0
  87. package/docs/api/type-aliases/FlowStreamUpdater.md +32 -0
  88. package/docs/api/type-aliases/NotPromise.md +18 -0
  89. package/docs/api/type-aliases/SolidGetter.md +17 -0
  90. package/docs/api/typedoc-sidebar.json +1 -0
  91. package/docs/examples/examples.md +2313 -0
  92. package/docs/examples/patterns.md +649 -0
  93. package/docs/guide/advanced/disposal.md +426 -0
  94. package/docs/guide/advanced/solidjs.md +221 -0
  95. package/docs/guide/advanced/upgrading.md +464 -0
  96. package/docs/guide/introduction/concepts.md +56 -0
  97. package/docs/guide/introduction/conventions.md +61 -0
  98. package/docs/guide/introduction/getting-started.md +134 -0
  99. package/docs/guide/introduction/lifecycle.md +371 -0
  100. package/docs/guide/primitives/array.md +400 -0
  101. package/docs/guide/primitives/constant.md +380 -0
  102. package/docs/guide/primitives/derivations.md +348 -0
  103. package/docs/guide/primitives/effects.md +458 -0
  104. package/docs/guide/primitives/map.md +387 -0
  105. package/docs/guide/primitives/overview.md +175 -0
  106. package/docs/guide/primitives/resources.md +858 -0
  107. package/docs/guide/primitives/signal.md +259 -0
  108. package/docs/guide/primitives/state.md +368 -0
  109. package/docs/guide/primitives/streams.md +931 -0
  110. package/docs/index.md +47 -0
  111. package/docs/public/logo.svg +1 -0
  112. package/package.json +57 -41
  113. package/src/advanced/array.ts +208 -210
  114. package/src/advanced/index.ts +7 -7
  115. package/src/advanced/map.ts +178 -68
  116. package/src/advanced/resource.ts +87 -43
  117. package/src/advanced/resourceAsync.ts +62 -42
  118. package/src/advanced/stream.ts +113 -50
  119. package/src/advanced/streamAsync.ts +120 -61
  120. package/src/basic/constant.ts +82 -49
  121. package/src/basic/derivation.ts +128 -84
  122. package/src/basic/disposable.ts +74 -15
  123. package/src/basic/effect.ts +85 -77
  124. package/src/basic/index.ts +7 -8
  125. package/src/basic/observable.ts +94 -36
  126. package/src/basic/signal.ts +133 -105
  127. package/src/basic/state.ts +46 -25
  128. package/src/basic/trackingContext.ts +45 -0
  129. package/src/creators.ts +297 -54
  130. package/src/index.ts +96 -43
  131. package/src/solid/converters.ts +186 -67
  132. package/src/solid/index.ts +8 -2
  133. package/src/solid/primitives.ts +167 -65
  134. package/test/array.test.ts +592 -612
  135. package/test/constant.test.ts +31 -33
  136. package/test/derivation.test.ts +531 -536
  137. package/test/effect.test.ts +21 -21
  138. package/test/map.test.ts +233 -137
  139. package/test/resource.test.ts +119 -121
  140. package/test/resourceAsync.test.ts +98 -100
  141. package/test/signal.test.ts +51 -55
  142. package/test/state.test.ts +186 -168
  143. package/test/stream.test.ts +189 -189
  144. package/test/streamAsync.test.ts +186 -186
  145. package/tsconfig.json +19 -18
  146. package/typedoc.json +37 -0
  147. package/vite.config.ts +23 -23
  148. package/vitest.config.ts +7 -7
  149. package/api/doc/index.md +0 -31
  150. package/api/doc/picoflow.array.md +0 -55
  151. package/api/doc/picoflow.constant.md +0 -55
  152. package/api/doc/picoflow.derivation.md +0 -55
  153. package/api/doc/picoflow.effect.md +0 -55
  154. package/api/doc/picoflow.flowarray._constructor_.md +0 -49
  155. package/api/doc/picoflow.flowarray._lastaction.md +0 -13
  156. package/api/doc/picoflow.flowarray.clear.md +0 -17
  157. package/api/doc/picoflow.flowarray.dispose.md +0 -55
  158. package/api/doc/picoflow.flowarray.get.md +0 -19
  159. package/api/doc/picoflow.flowarray.length.md +0 -13
  160. package/api/doc/picoflow.flowarray.md +0 -273
  161. package/api/doc/picoflow.flowarray.pop.md +0 -17
  162. package/api/doc/picoflow.flowarray.push.md +0 -53
  163. package/api/doc/picoflow.flowarray.set.md +0 -53
  164. package/api/doc/picoflow.flowarray.setitem.md +0 -69
  165. package/api/doc/picoflow.flowarray.shift.md +0 -17
  166. package/api/doc/picoflow.flowarray.splice.md +0 -85
  167. package/api/doc/picoflow.flowarray.unshift.md +0 -53
  168. package/api/doc/picoflow.flowarrayaction.md +0 -37
  169. package/api/doc/picoflow.flowconstant._constructor_.md +0 -49
  170. package/api/doc/picoflow.flowconstant.get.md +0 -25
  171. package/api/doc/picoflow.flowconstant.md +0 -88
  172. package/api/doc/picoflow.flowderivation._constructor_.md +0 -49
  173. package/api/doc/picoflow.flowderivation.get.md +0 -23
  174. package/api/doc/picoflow.flowderivation.md +0 -86
  175. package/api/doc/picoflow.flowdisposable.dispose.md +0 -55
  176. package/api/doc/picoflow.flowdisposable.md +0 -43
  177. package/api/doc/picoflow.floweffect._constructor_.md +0 -54
  178. package/api/doc/picoflow.floweffect.dispose.md +0 -21
  179. package/api/doc/picoflow.floweffect.disposed.md +0 -13
  180. package/api/doc/picoflow.floweffect.md +0 -131
  181. package/api/doc/picoflow.flowgetter.md +0 -15
  182. package/api/doc/picoflow.flowmap._lastdeleted.md +0 -21
  183. package/api/doc/picoflow.flowmap._lastset.md +0 -21
  184. package/api/doc/picoflow.flowmap.delete.md +0 -61
  185. package/api/doc/picoflow.flowmap.md +0 -133
  186. package/api/doc/picoflow.flowmap.setat.md +0 -77
  187. package/api/doc/picoflow.flowobservable.get.md +0 -19
  188. package/api/doc/picoflow.flowobservable.md +0 -68
  189. package/api/doc/picoflow.flowobservable.subscribe.md +0 -55
  190. package/api/doc/picoflow.flowresource._constructor_.md +0 -49
  191. package/api/doc/picoflow.flowresource.fetch.md +0 -27
  192. package/api/doc/picoflow.flowresource.get.md +0 -23
  193. package/api/doc/picoflow.flowresource.md +0 -100
  194. package/api/doc/picoflow.flowresourceasync._constructor_.md +0 -49
  195. package/api/doc/picoflow.flowresourceasync.fetch.md +0 -27
  196. package/api/doc/picoflow.flowresourceasync.get.md +0 -23
  197. package/api/doc/picoflow.flowresourceasync.md +0 -100
  198. package/api/doc/picoflow.flowsignal.dispose.md +0 -59
  199. package/api/doc/picoflow.flowsignal.disposed.md +0 -18
  200. package/api/doc/picoflow.flowsignal.md +0 -112
  201. package/api/doc/picoflow.flowsignal.trigger.md +0 -21
  202. package/api/doc/picoflow.flowstate.md +0 -52
  203. package/api/doc/picoflow.flowstate.set.md +0 -61
  204. package/api/doc/picoflow.flowstream._constructor_.md +0 -49
  205. package/api/doc/picoflow.flowstream.dispose.md +0 -21
  206. package/api/doc/picoflow.flowstream.get.md +0 -23
  207. package/api/doc/picoflow.flowstream.md +0 -100
  208. package/api/doc/picoflow.flowstreamasync._constructor_.md +0 -54
  209. package/api/doc/picoflow.flowstreamasync.dispose.md +0 -21
  210. package/api/doc/picoflow.flowstreamasync.get.md +0 -23
  211. package/api/doc/picoflow.flowstreamasync.md +0 -100
  212. package/api/doc/picoflow.flowstreamdisposer.md +0 -13
  213. package/api/doc/picoflow.flowstreamsetter.md +0 -13
  214. package/api/doc/picoflow.flowstreamupdater.md +0 -19
  215. package/api/doc/picoflow.flowwatcher.md +0 -15
  216. package/api/doc/picoflow.from.md +0 -55
  217. package/api/doc/picoflow.from_1.md +0 -55
  218. package/api/doc/picoflow.from_2.md +0 -55
  219. package/api/doc/picoflow.from_3.md +0 -55
  220. package/api/doc/picoflow.from_4.md +0 -55
  221. package/api/doc/picoflow.from_5.md +0 -55
  222. package/api/doc/picoflow.isdisposable.md +0 -55
  223. package/api/doc/picoflow.map.md +0 -59
  224. package/api/doc/picoflow.md +0 -544
  225. package/api/doc/picoflow.resource.md +0 -55
  226. package/api/doc/picoflow.resourceasync.md +0 -55
  227. package/api/doc/picoflow.signal.md +0 -19
  228. package/api/doc/picoflow.solidderivation._constructor_.md +0 -49
  229. package/api/doc/picoflow.solidderivation.get.md +0 -13
  230. package/api/doc/picoflow.solidderivation.md +0 -94
  231. package/api/doc/picoflow.solidgetter.md +0 -13
  232. package/api/doc/picoflow.solidobservable.get.md +0 -13
  233. package/api/doc/picoflow.solidobservable.md +0 -57
  234. package/api/doc/picoflow.solidresource._constructor_.md +0 -49
  235. package/api/doc/picoflow.solidresource.get.md +0 -13
  236. package/api/doc/picoflow.solidresource.latest.md +0 -13
  237. package/api/doc/picoflow.solidresource.md +0 -157
  238. package/api/doc/picoflow.solidresource.refetch.md +0 -13
  239. package/api/doc/picoflow.solidresource.state.md +0 -13
  240. package/api/doc/picoflow.solidstate._constructor_.md +0 -49
  241. package/api/doc/picoflow.solidstate.get.md +0 -13
  242. package/api/doc/picoflow.solidstate.md +0 -115
  243. package/api/doc/picoflow.solidstate.set.md +0 -13
  244. package/api/doc/picoflow.state.md +0 -55
  245. package/api/doc/picoflow.stream.md +0 -55
  246. package/api/doc/picoflow.streamasync.md +0 -55
  247. package/api/picoflow.public.api.md +0 -244
  248. package/api-extractor.json +0 -61
@@ -0,0 +1,464 @@
1
+ # Upgrading from v0.x
2
+
3
+ PicoFlow v1.0.0 introduces a new API based on an explicit tracking context instead of getter and watcher functions. This change brings several benefits:
4
+
5
+ 1. **More intuitive:** The method-based API (`$state.get(t)`) is more natural than `get($state)`
6
+ 2. **Better chaining:** Nested access is much more readable: `$a.get(t).b.get(t)` vs `get(get($a).b)`
7
+ 3. **Explicit control:** Clear distinction between reactive (`.get(t)`) and non-reactive (`.pick()`) reads
8
+ 4. **Simpler architecture:** Fewer internal abstractions make the library easier to understand and maintain
9
+ 5. **More flexible:** Fine-grained control over dependencies within a single effect
10
+
11
+ We believe this change makes PicoFlow better for both new and experienced users, and we're excited for you to try it!
12
+
13
+ ## Quick Start
14
+
15
+ The core change is simple:
16
+
17
+ **Before (v0.x):**
18
+ ```typescript
19
+ effect((get, watch) => {
20
+ const value = get($state);
21
+ watch($signal);
22
+ });
23
+ ```
24
+
25
+ **After (v1.0.0):**
26
+ ```typescript
27
+ effect((t) => {
28
+ const value = $state.get(t);
29
+ $signal.watch(t);
30
+ });
31
+ ```
32
+
33
+ ## Breaking Changes Summary
34
+
35
+ | v0.x | v1.0.0 | Notes |
36
+ |------|--------|-------|
37
+ | `effect((get, watch) => {})` | `effect((t) => {})` | Single tracking context parameter |
38
+ | `derivation((get, watch) => {})` | `derivation((t) => {})` | Single tracking context parameter |
39
+ | `get($observable)` | `$observable.get(t)` | Method-based API |
40
+ | `watch($signal)` | `$signal.watch(t)` | Method-based API |
41
+ | `FlowGetter` type | `TrackingContext` type | New type for tracking context |
42
+ | `FlowWatcher` type | `TrackingContext` type | New type for tracking context |
43
+ | N/A | `$observable.pick()` | New: non-reactive reads |
44
+
45
+ ## TypeScript Type Changes
46
+
47
+ If you've imported these types, update them:
48
+
49
+ **Before:**
50
+ ```typescript
51
+ import type { FlowGetter, FlowWatcher } from '@ersbeth/picoflow';
52
+
53
+ function myHelper(get: FlowGetter, watch: FlowWatcher) {
54
+ // ...
55
+ }
56
+ ```
57
+
58
+ **After:**
59
+ ```typescript
60
+ import type { TrackingContext } from '@ersbeth/picoflow';
61
+
62
+ function myHelper(t: TrackingContext) {
63
+ // ...
64
+ }
65
+ ```
66
+
67
+ ## Step-by-Step Migration
68
+
69
+ ### 1. Update PicoFlow
70
+
71
+ ```bash
72
+ npm install @ersbeth/picoflow@1.0.0
73
+ ```
74
+
75
+ ### 2. Replace Effect and Derivation Parameters
76
+
77
+ Find all `effect()` and `derivation()` calls in your codebase:
78
+
79
+ **Pattern to find:** `(get, watch) =>` or `(get) =>`
80
+ **Replace with:** `(t) =>`
81
+
82
+ ### 3. Update Observable Reads
83
+
84
+ Replace getter function calls with method calls:
85
+
86
+ **Pattern to find:** `get($observable)`
87
+ **Replace with:** `$observable.get(t)`
88
+
89
+ ### 4. Update Signal Watches
90
+
91
+ Replace watcher function calls with method calls:
92
+
93
+ **Pattern to find:** `watch($signal)`
94
+ **Replace with:** `$signal.watch(t)`
95
+
96
+ ### 5. Test Your Application
97
+
98
+ Run your tests and verify everything works as expected.
99
+
100
+ ## Common Migration Patterns
101
+
102
+ ### Pattern 1: Simple Effect with State
103
+
104
+ **Before:**
105
+ ```typescript
106
+ import { state, effect } from '@ersbeth/picoflow';
107
+
108
+ const $count = state(0);
109
+
110
+ const $effect = effect((get) => {
111
+ console.log('Count:', get($count));
112
+ });
113
+
114
+ $count.set(42);
115
+ ```
116
+
117
+ **After:**
118
+ ```typescript
119
+ import { state, effect } from '@ersbeth/picoflow';
120
+
121
+ const $count = state(0);
122
+
123
+ const $effect = effect((t) => {
124
+ console.log('Count:', $count.get(t));
125
+ });
126
+
127
+ $count.set(42);
128
+ ```
129
+
130
+ ### Pattern 2: Effect with Signal Watch
131
+
132
+ **Before:**
133
+ ```typescript
134
+ import { signal, effect } from '@ersbeth/picoflow';
135
+
136
+ const $signal = signal();
137
+
138
+ const $effect = effect((get, watch) => {
139
+ watch($signal);
140
+ console.log('Signal triggered!');
141
+ });
142
+
143
+ $signal.trigger();
144
+ ```
145
+
146
+ **After:**
147
+ ```typescript
148
+ import { signal, effect } from '@ersbeth/picoflow';
149
+
150
+ const $signal = signal();
151
+
152
+ const $effect = effect((t) => {
153
+ $signal.watch(t);
154
+ console.log('Signal triggered!');
155
+ });
156
+
157
+ $signal.trigger();
158
+ ```
159
+
160
+ ### Pattern 3: Derivations
161
+
162
+ **Before:**
163
+ ```typescript
164
+ import { state, derivation } from '@ersbeth/picoflow';
165
+
166
+ const $firstName = state('John');
167
+ const $lastName = state('Doe');
168
+
169
+ const $fullName = derivation((get) => {
170
+ return `${get($firstName)} ${get($lastName)}`;
171
+ });
172
+ ```
173
+
174
+ **After:**
175
+ ```typescript
176
+ import { state, derivation } from '@ersbeth/picoflow';
177
+
178
+ const $firstName = state('John');
179
+ const $lastName = state('Doe');
180
+
181
+ const $fullName = derivation((t) => {
182
+ return `${$firstName.get(t)} ${$lastName.get(t)}`;
183
+ });
184
+ ```
185
+
186
+ ### Pattern 4: Nested States (Chained Access)
187
+
188
+ This is where the new API really shines!
189
+
190
+ **Before:**
191
+ ```typescript
192
+ const $user = state({
193
+ profile: $profile,
194
+ settings: $settings
195
+ });
196
+
197
+ effect((get) => {
198
+ const name = get(get($user).profile).name;
199
+ console.log(name);
200
+ });
201
+ ```
202
+
203
+ **After:**
204
+ ```typescript
205
+ const $user = state({
206
+ profile: $profile,
207
+ settings: $settings
208
+ });
209
+
210
+ effect((t) => {
211
+ const name = $user.get(t).profile.get(t).name;
212
+ console.log(name);
213
+ });
214
+ ```
215
+
216
+ Much more readable!
217
+
218
+ ### Pattern 5: Non-Reactive Reads (NEW CAPABILITY!)
219
+
220
+ v1.0.0 introduces `pick()` for reading values without creating dependencies:
221
+
222
+ ```typescript
223
+ const $data = state({ count: 0 });
224
+ const $trigger = signal();
225
+
226
+ effect((t) => {
227
+ // Only react to $trigger, not to $data
228
+ $trigger.watch(t);
229
+ const snapshot = $data.pick(); // Non-reactive read!
230
+ console.log('Triggered, current data:', snapshot);
231
+ });
232
+ ```
233
+
234
+ You can also use `get(null)` for the same effect:
235
+ ```typescript
236
+ const snapshot = $data.get(null); // Equivalent to pick()
237
+ ```
238
+
239
+ ### Pattern 6: Arrays and Collections
240
+
241
+ **Before:**
242
+ ```typescript
243
+ import { array, effect } from '@ersbeth/picoflow';
244
+
245
+ const $items = array([1, 2, 3]);
246
+
247
+ effect((get) => {
248
+ const items = get($items);
249
+ console.log('Items:', items);
250
+ });
251
+
252
+ $items.push(4);
253
+ ```
254
+
255
+ **After:**
256
+ ```typescript
257
+ import { array, effect } from '@ersbeth/picoflow';
258
+
259
+ const $items = array([1, 2, 3]);
260
+
261
+ effect((t) => {
262
+ const items = $items.get(t);
263
+ console.log('Items:', items);
264
+ });
265
+
266
+ $items.push(4);
267
+ ```
268
+
269
+ ### Pattern 7: Reactive Maps
270
+
271
+ **Before:**
272
+ ```typescript
273
+ import { map, effect } from '@ersbeth/picoflow';
274
+
275
+ const $map = map({ foo: 'bar' });
276
+
277
+ effect((get) => {
278
+ const data = get($map);
279
+ console.log('Map:', data);
280
+ });
281
+
282
+ $map.setAt('key', 'value');
283
+ ```
284
+
285
+ **After:**
286
+ ```typescript
287
+ import { map, effect } from '@ersbeth/picoflow';
288
+
289
+ const $map = map({ foo: 'bar' });
290
+
291
+ effect((t) => {
292
+ const data = $map.get(t);
293
+ console.log('Map:', data);
294
+ });
295
+
296
+ $map.setAt('key', 'value');
297
+ ```
298
+
299
+ ### Pattern 8: Async Resources
300
+
301
+ **Before:**
302
+ ```typescript
303
+ import { resource, effect } from '@ersbeth/picoflow';
304
+
305
+ const $data = resource(fetchData, {});
306
+
307
+ effect((get) => {
308
+ const data = get($data);
309
+ console.log('Data loaded:', data);
310
+ });
311
+ ```
312
+
313
+ **After:**
314
+ ```typescript
315
+ import { resource, effect } from '@ersbeth/picoflow';
316
+
317
+ const $data = resource(fetchData, {});
318
+
319
+ effect((t) => {
320
+ const data = $data.get(t);
321
+ console.log('Data loaded:', data);
322
+ });
323
+ ```
324
+
325
+ ### Pattern 9: Streams
326
+
327
+ **Before:**
328
+ ```typescript
329
+ import { stream, effect } from '@ersbeth/picoflow';
330
+
331
+ const $messages = stream((set) => {
332
+ const ws = new WebSocket('ws://...');
333
+ ws.onmessage = (e) => set(e.data);
334
+ return () => ws.close();
335
+ });
336
+
337
+ effect((get) => {
338
+ console.log('Message:', get($messages));
339
+ });
340
+ ```
341
+
342
+ **After:**
343
+ ```typescript
344
+ import { stream, effect } from '@ersbeth/picoflow';
345
+
346
+ const $messages = stream((set) => {
347
+ const ws = new WebSocket('ws://...');
348
+ ws.onmessage = (e) => set(e.data);
349
+ return () => ws.close();
350
+ });
351
+
352
+ effect((t) => {
353
+ console.log('Message:', $messages.get(t));
354
+ });
355
+ ```
356
+
357
+ ### Pattern 10: SolidJS Integration
358
+
359
+ If you're using `picoflow/solid`:
360
+
361
+ **Before:**
362
+ ```typescript
363
+ import { from } from '@ersbeth/picoflow/solid';
364
+ import { state } from '@ersbeth/picoflow';
365
+
366
+ const $picoState = state(42);
367
+
368
+ // Convert to SolidJS signal
369
+ const solidSignal = from($picoState);
370
+
371
+ // Or with a getter function
372
+ const solidDerived = from((get) => {
373
+ return get($stateA) + get($stateB);
374
+ });
375
+ ```
376
+
377
+ **After:**
378
+ ```typescript
379
+ import { from } from '@ersbeth/picoflow/solid';
380
+ import { state } from '@ersbeth/picoflow';
381
+
382
+ const $picoState = state(42);
383
+
384
+ // Convert to SolidJS signal
385
+ const solidSignal = from($picoState);
386
+
387
+ // Or with a getter function
388
+ const solidDerived = from((t) => {
389
+ return $stateA.get(t) + $stateB.get(t);
390
+ });
391
+ ```
392
+
393
+ ## Advanced: Mixed Reactive and Non-Reactive Reads
394
+
395
+ One powerful new feature is the ability to mix reactive and non-reactive reads in the same effect:
396
+
397
+ ```typescript
398
+ const $config = state({ debug: true });
399
+ const $data = state({ value: 0 });
400
+
401
+ effect((t) => {
402
+ // Reactive: effect re-runs when $data changes
403
+ const data = $data.get(t);
404
+
405
+ // Non-reactive: effect does NOT re-run when $config changes
406
+ const config = $config.pick();
407
+
408
+ if (config.debug) {
409
+ console.log('Debug:', data);
410
+ }
411
+ });
412
+
413
+ // This triggers the effect:
414
+ $data.set({ value: 1 });
415
+
416
+ // This does NOT trigger the effect:
417
+ $config.set({ debug: false });
418
+ ```
419
+
420
+ This is useful for:
421
+ - Reading configuration that rarely changes
422
+ - Accessing reference data without creating dependencies
423
+ - Performance optimization by avoiding unnecessary re-runs
424
+
425
+ ## Troubleshooting
426
+
427
+ ### Error: "Cannot read property 'get' of undefined"
428
+
429
+ Make sure you're passing the tracking context to the `get()` method:
430
+
431
+ ```typescript
432
+ // ❌ Wrong
433
+ effect((t) => {
434
+ const value = $state.get(); // Missing parameter
435
+ });
436
+
437
+ // ✅ Correct
438
+ effect((t) => {
439
+ const value = $state.get(t);
440
+ });
441
+ ```
442
+
443
+ ### Error: "watch is not a function"
444
+
445
+ You're trying to use the old API. Update to the new method-based syntax:
446
+
447
+ ```typescript
448
+ // ❌ Wrong (old API)
449
+ effect((get, watch) => {
450
+ watch($signal);
451
+ });
452
+
453
+ // ✅ Correct (new API)
454
+ effect((t) => {
455
+ $signal.watch(t);
456
+ });
457
+ ```
458
+
459
+ ### My effect runs too often / too rarely
460
+
461
+ Check if you're using `.get(t)` vs `.pick()` correctly:
462
+ - Use `.get(t)` to create a reactive dependency
463
+ - Use `.pick()` or `.get(null)` for snapshot reads without dependencies
464
+
@@ -0,0 +1,56 @@
1
+ # Concepts
2
+
3
+ Understand the fundamentals of reactive programming and how it simplifies managing your application's state and behavior.
4
+
5
+ ## What is Reactive Programming?
6
+
7
+ Imagine a **spreadsheet** where you write `=A1 + B1` in cell C1. When you change A1 or B1, C1 automatically updates. That's reactive programming - values that automatically update when their dependencies change.
8
+
9
+ ## Imperative Approach
10
+
11
+ In traditional programming, you manually update everything:
12
+
13
+ ```typescript
14
+ // Imperative approach
15
+ let count = 0
16
+ let doubledCount = count * 2
17
+
18
+ function increment() {
19
+ count++
20
+ doubledCount = count * 2 // Must remember to update!
21
+ updateUI(count, doubledCount) // Must remember to update UI!
22
+ }
23
+ ```
24
+
25
+
26
+ ```mermaid
27
+ flowchart LR
28
+ A[count = 5] --> B[Manually update doubled]
29
+ B --> C[Manually update UI]
30
+ ```
31
+
32
+ ## Reactive Approach
33
+
34
+ With reactive programming, dependencies update automatically:
35
+
36
+ ```typescript
37
+ // Reactive approach with PicoFlow
38
+ const $count = state(0)
39
+ const $doubled = derivation((t) => $count.get(t) * 2)
40
+
41
+ effect((t) => {
42
+ updateUI($count.get(t), $doubled.get(t)) // Runs automatically!
43
+ })
44
+
45
+ function increment() {
46
+ $count.set(n => n + 1) // Everything else updates automatically!
47
+ }
48
+ ```
49
+
50
+ ```mermaid
51
+ flowchart LR
52
+ A2[$count.set 5] --> C2[$doubled updates]
53
+ C2 --> D2[UI effect runs]
54
+ ```
55
+
56
+ **The benefit:** You define relationships once, and they stay synchronized automatically!
@@ -0,0 +1,61 @@
1
+ # Conventions
2
+
3
+ PicoFlow follows simple, consistent conventions that make your reactive code easier to read and maintain. These conventions help you quickly identify reactive values and understand data flow at a glance.
4
+
5
+ ## The $ Prefix
6
+
7
+ You'll see variables prefixed with `$` throughout PicoFlow examples:
8
+
9
+ ```typescript
10
+ const $count = state(0)
11
+ const $double = derivation((t) => $count.get(t) * 2)
12
+ ```
13
+
14
+ This is a **naming convention** to make reactive values stand out. It helps you quickly identify:
15
+ - Which values are reactive
16
+ - Which values will cause re-executions when changed
17
+ - Where your state lives
18
+
19
+ Think of `$` as a visual marker: "This value is special - it's reactive!"
20
+
21
+ ### Examples
22
+
23
+ ```typescript
24
+ // Reactive values - use $ prefix
25
+ const $userName = state('Alice')
26
+ const $userAge = state(25)
27
+ const $isAdult = derivation((t) => $userAge.get(t) >= 18)
28
+
29
+ // Plain values - no $ prefix
30
+ const currentName = $userName.pick() // Snapshot of current value
31
+ const maxAge = 100 // Constant
32
+ ```
33
+
34
+ ## Benefits
35
+
36
+ **1. Visual Clarity**
37
+
38
+ ```typescript
39
+ // Clear distinction between reactive and non-reactive
40
+ function updateProfile(newName: string) {
41
+ $userName.set(newName) // $ = reactive, will trigger effects
42
+ const timestamp = Date.now() // no $ = plain value
43
+ }
44
+ ```
45
+
46
+ **2. Prevents Confusion**
47
+
48
+ ```typescript
49
+ // Easy to see what's reactive
50
+ effect((t) => {
51
+ const user = $currentUser.get(t) // $ = will re-run on change
52
+ const config = appConfig // no $ = static value
53
+
54
+ fetchUserData(user.id, config)
55
+ })
56
+ ```
57
+
58
+ **3. Code Review**
59
+
60
+ When reviewing code, the `$` prefix makes it immediately obvious which variables should be part of the reactive system and which should be regular JavaScript values.
61
+
@@ -0,0 +1,134 @@
1
+ # Getting Started
2
+
3
+ Welcome to PicoFlow! This guide will help you install PicoFlow and build your first reactive application in just a few minutes.
4
+
5
+ ## Why PicoFlow?
6
+
7
+ PicoFlow is a lightweight reactive library with a focus on **explicit control** and **simplicity**. Unlike some reactive libraries that track everything automatically, PicoFlow gives you precise control over what is reactive and what isn't.
8
+
9
+ ### Key Philosophy
10
+
11
+ 1. **Explicit Tracking** - You decide what to track with `.get(t)`
12
+ 2. **Fine-grained Control** - React to specific operations, not just "something changed"
13
+ 3. **No Magic** - Simple, predictable behavior
14
+ 4. **TypeScript First** - Full type safety and inference
15
+
16
+ ## Installation
17
+
18
+ Install PicoFlow using your preferred package manager:
19
+
20
+ ::: code-group
21
+
22
+ ```bash [pnpm]
23
+ pnpm add @ersbeth/picoflow
24
+ ```
25
+
26
+ ```bash [npm]
27
+ npm install @ersbeth/picoflow
28
+ ```
29
+
30
+ ```bash [yarn]
31
+ yarn add @ersbeth/picoflow
32
+ ```
33
+
34
+ :::
35
+
36
+ If you plan to use the SolidJS integration, install SolidJS as a peer dependency:
37
+
38
+ ::: code-group
39
+
40
+ ```bash [pnpm]
41
+ pnpm add solid-js
42
+ ```
43
+
44
+ ```bash [npm]
45
+ npm install solid-js
46
+ ```
47
+
48
+ ```bash [yarn]
49
+ yarn add solid-js
50
+ ```
51
+
52
+ :::
53
+
54
+ Import the primitives you need:
55
+
56
+ ```typescript
57
+ import { state, effect, derivation, signal } from '@ersbeth/picoflow'
58
+ ```
59
+
60
+ For SolidJS integration:
61
+
62
+ ```typescript
63
+ import { from } from '@ersbeth/picoflow/solid'
64
+ ```
65
+
66
+ ## Your First PicoFlow App
67
+
68
+ Let's build a simple counter with PicoFlow:
69
+
70
+ ```typescript
71
+ import { state, derivation, effect } from '@ersbeth/picoflow'
72
+
73
+ // Create reactive state (prefix with $ by convention)
74
+ const $count = state(0)
75
+
76
+ // Create a computed value
77
+ const $isEven = derivation((t) => {
78
+ return $count.get(t) % 2 === 0
79
+ })
80
+
81
+ // React to changes
82
+ effect((t) => {
83
+ const count = $count.get(t)
84
+ const even = $isEven.get(t)
85
+ console.log(`Count is ${count}, which is ${even ? 'even' : 'odd'}`)
86
+ })
87
+ // Logs "Count is 0, wich is even"
88
+
89
+ // Update the state
90
+ $count.set(1) // Logs: "Count is 1, which is odd"
91
+ $count.set(2) // Logs: "Count is 2, which is even"
92
+ $count.set(3) // Logs: "Count is 3, which is odd"
93
+ ```
94
+
95
+ ### What Just Happened?
96
+
97
+ 1. **State** (`$count`) - Holds a mutable value
98
+ 2. **Derivation** (`$isEven`) - Computes a value based on state
99
+ 3. **Effect** - Runs automatically when dependencies change
100
+ 4. **`.get(t)`** - Reads a value AND creates a dependency
101
+ 5. **`.set()`** - Updates state, triggering effects
102
+
103
+ ### Data Flow
104
+
105
+ Here's what happens when you call `$count.set(1)`:
106
+
107
+ ```mermaid
108
+ sequenceDiagram
109
+ participant User
110
+ participant $count
111
+ participant $isEven
112
+ participant Effect
113
+
114
+ User->>$count: set(1)
115
+ activate $count
116
+ Note over $count: Updates value<br/>0 → 1
117
+ $count->>$isEven: notify()
118
+ Note over $isEven: Marks as dirty<br/>(lazy recompute)
119
+ $count->>Effect: notify()
120
+ deactivate $count
121
+
122
+ activate Effect
123
+ Effect->>$count: get(t)
124
+ $count-->>Effect: 1
125
+ Effect->>$isEven: get(t)
126
+ activate $isEven
127
+ Note over $isEven: Recomputes because dirty
128
+ $isEven->>$count: get(t)
129
+ $count-->>$isEven: 1
130
+ $isEven-->>Effect: false
131
+ deactivate $isEven
132
+ Note over Effect: Logs: "Count is 1,<br/>which is odd"
133
+ deactivate Effect
134
+ ```