@ersbeth/picoflow 0.2.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +62 -25
  7. package/biome.json +32 -32
  8. package/dist/picoflow.js +557 -1099
  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 -20
  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
package/src/creators.ts CHANGED
@@ -1,152 +1,395 @@
1
1
  import {
2
- FlowMap,
3
- FlowResource,
4
- FlowResourceAsync,
5
- FlowStream,
6
- FlowStreamAsync,
2
+ FlowMap,
3
+ FlowResource,
4
+ FlowResourceAsync,
5
+ FlowStream,
6
+ FlowStreamAsync,
7
7
  } from "./advanced/";
8
8
  import { FlowArray } from "./advanced/array";
9
+ import type { TrackingContext } from "./basic/";
9
10
  import {
10
- FlowConstant,
11
- FlowDerivation,
12
- FlowEffect,
13
- FlowSignal,
14
- FlowState,
11
+ FlowConstant,
12
+ FlowDerivation,
13
+ FlowEffect,
14
+ FlowSignal,
15
+ FlowState,
15
16
  } from "./basic/";
16
- import type { FlowGetter, FlowWatcher } from "./basic/";
17
17
 
18
18
  /**
19
19
  * Creates a new reactive signal.
20
+ *
20
21
  * @returns A new instance of {@link FlowSignal}.
22
+ *
23
+ * @remarks
24
+ * A signal is the simplest reactive primitive - it doesn't hold a value, but can be triggered
25
+ * to notify dependent effects and derivations. Use signals when you need event-like notifications
26
+ * without associated data.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const $refresh = signal();
31
+ *
32
+ * effect((t) => {
33
+ * $refresh.watch(t);
34
+ * console.log('Refreshing...');
35
+ * });
36
+ *
37
+ * $refresh.trigger(); // Logs: "Refreshing..."
38
+ * ```
39
+ *
21
40
  * @public
22
41
  */
23
42
  export function signal(): FlowSignal {
24
- return new FlowSignal();
43
+ return new FlowSignal();
25
44
  }
26
45
 
27
46
  /**
28
47
  * Creates a new reactive constant.
29
- * @param value - The value or a function that returns the value.
48
+ *
49
+ * @typeParam T - The type of the constant value.
50
+ * @param value - The value or a function that returns the value (for lazy initialization).
30
51
  * @returns A new instance of {@link FlowConstant}.
52
+ *
53
+ * @remarks
54
+ * A constant is an immutable reactive value that never changes after initialization.
55
+ * It can be initialized eagerly (direct value) or lazily (function). Use constants for
56
+ * configuration, computed-once values, or expensive initialization that should only run once.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * // Eager initialization
61
+ * const $config = constant({ apiUrl: 'https://api.example.com' });
62
+ *
63
+ * // Lazy initialization
64
+ * const $computed = constant(() => expensiveCalculation());
65
+ * ```
66
+ *
31
67
  * @public
32
68
  */
33
69
  export function constant<T>(value: T | (() => T)): FlowConstant<T> {
34
- return new FlowConstant<T>(value);
70
+ return new FlowConstant<T>(value);
35
71
  }
36
72
 
37
73
  /**
38
- * Creates a new reactive state holding a value.
39
- * @typeparam T - The type of the state value.
40
- * @param value - The initial value for the state.
74
+ * Creates a new reactive state holding a mutable value.
75
+ *
76
+ * @typeParam T - The type of the state value.
77
+ * @param value - The initial value for the state, or a function returning the initial value.
41
78
  * @returns A new instance of {@link FlowState}.
79
+ *
80
+ * @remarks
81
+ * State is the most common reactive primitive - a mutable container that notifies dependents
82
+ * when its value changes. Use `set()` to update the value and `get(t)` or `pick()` to read it.
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const $count = state(0);
87
+ *
88
+ * effect((t) => {
89
+ * console.log($count.get(t));
90
+ * });
91
+ *
92
+ * $count.set(1); // Logs: 1
93
+ * $count.set(n => n + 1); // Logs: 2
94
+ * ```
95
+ *
42
96
  * @public
43
97
  */
44
98
  export function state<T>(value: T | (() => T)): FlowState<T> {
45
- return new FlowState(value);
99
+ return new FlowState(value);
46
100
  }
47
101
 
48
102
  /**
49
- * Creates a new reactive resource that asynchronously fetches its value.
50
- * @typeparam T - The type of the resource value.
103
+ * Creates a new reactive resource that asynchronously fetches its value, returning `T | undefined`.
104
+ *
105
+ * @typeParam T - The type of the resource value.
51
106
  * @param fn - An asynchronous function that fetches the resource value.
52
107
  * @returns A new instance of {@link FlowResource}.
108
+ *
109
+ * @remarks
110
+ * A resource manages async data fetching with reactive updates. Unlike {@link resourceAsync},
111
+ * this returns the resolved value directly (or `undefined` if not fetched yet), making it
112
+ * easier to work with in synchronous contexts. Call `fetch()` to trigger the async operation.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const $user = resource(() => fetch('/api/user').then(r => r.json()));
117
+ *
118
+ * // Trigger fetch
119
+ * await $user.fetch();
120
+ *
121
+ * // Use in effect
122
+ * effect((t) => {
123
+ * const user = $user.get(t);
124
+ * if (user) {
125
+ * console.log(user.name);
126
+ * }
127
+ * });
128
+ * ```
129
+ *
53
130
  * @public
54
131
  */
55
132
  export function resource<T>(fn: () => Promise<T>): FlowResource<T> {
56
- return new FlowResource(fn);
133
+ return new FlowResource(fn);
57
134
  }
58
135
 
59
136
  /**
60
- * Creates a new reactive asynchronous resource that fetches its value.
61
- * @typeparam T - The type of the resource value.
137
+ * Creates a new reactive asynchronous resource that always returns a Promise.
138
+ *
139
+ * @typeParam T - The type of the resource value.
62
140
  * @param fn - An asynchronous function that fetches the resource value.
63
141
  * @returns A new instance of {@link FlowResourceAsync}.
142
+ *
143
+ * @remarks
144
+ * An async resource manages async data fetching and always returns a Promise, making it
145
+ * ideal for async/await patterns. Unlike {@link resource}, the Promise is created lazily
146
+ * on first access and cached. Call `fetch()` to create a new Promise and trigger a refetch.
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const $data = resourceAsync(() => fetch('/api/data').then(r => r.json()));
151
+ *
152
+ * // Use with async/await
153
+ * effect(async (t) => {
154
+ * const data = await $data.get(t);
155
+ * console.log(data);
156
+ * });
157
+ *
158
+ * // Refetch
159
+ * await $data.fetch();
160
+ * ```
161
+ *
64
162
  * @public
65
163
  */
66
164
  export function resourceAsync<T>(fn: () => Promise<T>): FlowResourceAsync<T> {
67
- return new FlowResourceAsync(fn);
165
+ return new FlowResourceAsync(fn);
68
166
  }
69
167
 
70
168
  /**
71
- * Creates a new reactive stream.
72
- * @typeparam T - The type of the stream value.
169
+ * Creates a new reactive stream that bridges external event sources with PicoFlow's reactive system.
170
+ *
171
+ * @typeParam T - The type of the stream value.
73
172
  * @param updater - A function that receives a setter to update the stream's value.
74
173
  * It should return a disposer function to clean up resources.
75
174
  * @returns A new instance of {@link FlowStream}.
175
+ *
176
+ * @remarks
177
+ * Streams are ideal for integrating push-based data sources like WebSockets, DOM events,
178
+ * timers, or any event emitter. The updater sets up subscriptions and calls the setter
179
+ * when new data arrives. The returned disposer is called on cleanup.
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * // WebSocket stream
184
+ * const $messages = stream<string>((set) => {
185
+ * const ws = new WebSocket('ws://example.com');
186
+ * ws.onmessage = (e) => set(e.data);
187
+ * return () => ws.close();
188
+ * });
189
+ *
190
+ * // Timer stream
191
+ * const $tick = stream<number>((set) => {
192
+ * let count = 0;
193
+ * const id = setInterval(() => set(count++), 1000);
194
+ * return () => clearInterval(id);
195
+ * });
196
+ * ```
197
+ *
76
198
  * @public
77
199
  */
78
200
  export function stream<T>(
79
- updater: (set: (value: T) => void) => () => void,
201
+ updater: (set: (value: T) => void) => () => void,
80
202
  ): FlowStream<T> {
81
- return new FlowStream(updater);
203
+ return new FlowStream(updater);
82
204
  }
83
205
 
84
206
  /**
85
- * Creates a new reactive asynchronous stream.
86
- * @typeparam T - The type of the stream value.
207
+ * Creates a new reactive asynchronous stream that always returns a Promise.
208
+ *
209
+ * @typeParam T - The type of the stream value.
87
210
  * @param updater - A function that receives a setter to update the stream's value.
88
211
  * It should return a disposer function to clean up resources.
89
212
  * @returns A new instance of {@link FlowStreamAsync}.
213
+ *
214
+ * @remarks
215
+ * Async streams are ideal for push-based async data sources where you want to use async/await.
216
+ * Unlike {@link stream}, this always returns a Promise that resolves to the value. The initial
217
+ * Promise is created on construction and resolves when the setter is first called.
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * const $asyncMessages = streamAsync<string>((set) => {
222
+ * const ws = new WebSocket('ws://example.com');
223
+ * ws.onmessage = (e) => set(e.data);
224
+ * return () => ws.close();
225
+ * });
226
+ *
227
+ * effect(async (t) => {
228
+ * const message = await $asyncMessages.get(t);
229
+ * console.log('Received:', message);
230
+ * });
231
+ * ```
232
+ *
90
233
  * @public
91
234
  */
92
235
  export function streamAsync<T>(
93
- updater: (set: (value: T) => void) => () => void,
236
+ updater: (set: (value: T) => void) => () => void,
94
237
  ): FlowStreamAsync<T> {
95
- return new FlowStreamAsync(updater);
238
+ return new FlowStreamAsync(updater);
96
239
  }
97
240
 
98
241
  /**
99
242
  * Creates a new reactive derivation whose value is computed based on other reactive signals.
100
- * @typeparam T - The type of the derived value.
101
- * @param fn - A function that computes the derived value. It receives a getter and a watcher
102
- * function to access and register dependencies.
243
+ *
244
+ * @typeParam T - The type of the derived value.
245
+ * @param fn - A function that computes the derived value using a tracking context.
103
246
  * @returns A new instance of {@link FlowDerivation}.
247
+ *
248
+ * @remarks
249
+ * A derivation is a computed reactive value that automatically tracks its dependencies and
250
+ * recomputes when they change. The computation is lazy - it runs only when the value is
251
+ * accessed, not on construction. Use derivations to create derived state without manual
252
+ * dependency management.
253
+ *
254
+ * @example
255
+ * ```typescript
256
+ * const $firstName = state('John');
257
+ * const $lastName = state('Doe');
258
+ *
259
+ * const $fullName = derivation((t) => {
260
+ * return `${$firstName.get(t)} ${$lastName.get(t)}`;
261
+ * });
262
+ *
263
+ * effect((t) => {
264
+ * console.log($fullName.get(t)); // Logs: "John Doe"
265
+ * });
266
+ *
267
+ * $firstName.set('Jane'); // Logs: "Jane Doe"
268
+ * ```
269
+ *
104
270
  * @public
105
271
  */
106
272
  export function derivation<T>(
107
- fn: (get: FlowGetter, watch: FlowWatcher) => T,
273
+ fn: (t: TrackingContext) => T,
108
274
  ): FlowDerivation<T> {
109
- return new FlowDerivation(fn);
275
+ return new FlowDerivation(fn);
110
276
  }
111
277
 
112
278
  /**
113
279
  * Creates a new reactive effect that executes a side-effect function based on its dependencies.
114
- * @param fn - A function that performs side effects. It receives a getter and a watcher
115
- * function for tracking reactive dependencies.
280
+ *
281
+ * @param fn - A function that performs side effects using a tracking context.
116
282
  * @returns A new instance of {@link FlowEffect}.
283
+ *
284
+ * @remarks
285
+ * An effect is a reactive computation that runs immediately and re-runs whenever its tracked
286
+ * dependencies change. Use effects for side effects like logging, DOM updates, network requests,
287
+ * or any operation that should respond to reactive state changes.
288
+ *
289
+ * The effect executes immediately upon creation and provides a tracking context (`t`) that you
290
+ * use to explicitly mark dependencies via `observable.get(t)`. Use `observable.pick()` for
291
+ * reads that shouldn't trigger re-runs.
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * const $count = state(0);
296
+ *
297
+ * const fx = effect((t) => {
298
+ * console.log('Count is:', $count.get(t));
299
+ * });
300
+ *
301
+ * $count.set(1); // Logs: "Count is: 1"
302
+ * $count.set(2); // Logs: "Count is: 2"
303
+ *
304
+ * // Clean up when done
305
+ * fx.dispose();
306
+ * ```
307
+ *
117
308
  * @public
118
309
  */
119
- export function effect(
120
- fn: (get: FlowGetter, watch: FlowWatcher) => void,
121
- ): FlowEffect {
122
- return new FlowEffect(fn);
310
+ export function effect(fn: (t: TrackingContext) => void): FlowEffect {
311
+ return new FlowEffect(fn);
123
312
  }
124
313
 
125
314
  /**
126
- * Creates a new reactive map state.
127
- * @typeparam K - The type of the keys.
128
- * @typeparam V - The type of the values.
315
+ * Creates a new reactive map state with fine-grained tracking of operations.
316
+ *
317
+ * @typeParam K - The type of the keys.
318
+ * @typeParam V - The type of the values.
129
319
  * @param initial - An optional record of key-value pairs to initialize the map.
130
320
  * @returns A new instance of {@link FlowMap}.
321
+ *
131
322
  * @remarks
132
- * The initial record is converted to a native Map before being used.
323
+ * A reactive map wraps a native JavaScript Map and provides multiple levels of reactivity:
324
+ * tracking the entire map, tracking individual set operations, and tracking individual
325
+ * delete operations. The initial record (if provided) is converted to a native Map.
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * const $users = map<string, User>({
330
+ * 'user1': { name: 'John', age: 30 }
331
+ * });
332
+ *
333
+ * // Track the whole map
334
+ * effect((t) => {
335
+ * console.log('Users:', $users.get(t).size);
336
+ * });
337
+ *
338
+ * // Track additions
339
+ * effect((t) => {
340
+ * const { key, value } = $users.$lastSet.get(t);
341
+ * if (key) console.log(`Added: ${key}`);
342
+ * });
343
+ *
344
+ * $users.setAt('user2', { name: 'Jane', age: 25 });
345
+ * ```
346
+ *
133
347
  * @public
134
348
  */
135
349
  export function map<K extends string | number | symbol, V>(
136
- initial?: Record<K, V>,
350
+ initial?: Record<K, V>,
137
351
  ): FlowMap<K, V> {
138
- return new FlowMap<K, V>(
139
- new Map<K, V>(initial ? (Object.entries(initial) as [K, V][]) : []),
140
- );
352
+ return new FlowMap<K, V>(
353
+ new Map<K, V>(initial ? (Object.entries(initial) as [K, V][]) : []),
354
+ );
141
355
  }
142
356
 
143
357
  /**
144
- * Creates a new reactive array.
145
- * @typeparam T - The type of the array elements.
358
+ * Creates a new reactive array with mutation methods and fine-grained action tracking.
359
+ *
360
+ * @typeParam T - The type of the array elements.
146
361
  * @param initial - An optional array of initial values.
147
362
  * @returns A new instance of {@link FlowArray}.
363
+ *
364
+ * @remarks
365
+ * A reactive array provides array-like mutation methods (push, pop, shift, unshift, splice)
366
+ * and tracks the last operation performed via `$lastAction`. This enables both whole-array
367
+ * reactivity and fine-grained tracking of specific mutations.
368
+ *
369
+ * The array automatically disposes disposable items when they are removed (if they implement
370
+ * the FlowDisposable interface).
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * const $items = array([1, 2, 3]);
375
+ *
376
+ * // Track the whole array
377
+ * effect((t) => {
378
+ * console.log('Items:', $items.get(t));
379
+ * });
380
+ *
381
+ * // Track the last action
382
+ * effect((t) => {
383
+ * const action = $items.$lastAction.get(t);
384
+ * console.log('Action:', action.type);
385
+ * });
386
+ *
387
+ * $items.push(4); // Logs action: "push"
388
+ * $items.pop(); // Logs action: "pop"
389
+ * ```
390
+ *
148
391
  * @public
149
392
  */
150
393
  export function array<T>(initial?: T[]): FlowArray<T> {
151
- return new FlowArray<T>(initial);
394
+ return new FlowArray<T>(initial);
152
395
  }
package/src/index.ts CHANGED
@@ -1,56 +1,109 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * PicoFlow is a lightweight reactive dataflow library that provides a set of
5
- * reactive primitives such as signals, state, resources, streams, derivations,
6
- * effects, and reactive maps.
4
+ * # PicoFlow
7
5
  *
6
+ * PicoFlow is a lightweight reactive dataflow library that provides a comprehensive set of
7
+ * reactive primitives for building reactive applications with explicit dependency tracking.
8
+ *
9
+ * ## Core Concepts
10
+ *
11
+ * **Reactive Primitives:**
12
+ * - {@link FlowSignal}: Event-like notifications without values
13
+ * - {@link FlowState}: Mutable reactive values
14
+ * - {@link FlowConstant}: Immutable reactive values (computed once)
15
+ * - {@link FlowDerivation}: Computed values that track dependencies
16
+ * - {@link FlowEffect}: Side effects that run when dependencies change
17
+ *
18
+ * **Advanced Primitives:**
19
+ * - {@link FlowArray}: Reactive arrays with mutation tracking
20
+ * - {@link FlowMap}: Reactive maps with operation tracking
21
+ * - {@link FlowResource}: Async data fetching returning `T | undefined`
22
+ * - {@link FlowResourceAsync}: Async data fetching returning `Promise<T>`
23
+ * - {@link FlowStream}: Event streams from external sources
24
+ * - {@link FlowStreamAsync}: Async event streams returning Promises
25
+ *
26
+ * **Tracking Context:**
27
+ * - {@link TrackingContext}: The core mechanism for explicit dependency tracking
28
+ * - Use `observable.get(t)` to read with tracking
29
+ * - Use `observable.pick()` to read without tracking
30
+ * - Use `signal.watch(t)` to track signals without values
31
+ *
32
+ * ## Key Features
33
+ *
34
+ * - **Explicit tracking**: Full control over what triggers re-execution via TrackingContext
35
+ * - **Lazy evaluation**: Derivations compute only when accessed
36
+ * - **Fine-grained reactivity**: Track specific operations on collections
37
+ * - **Resource management**: Automatic cleanup with dispose patterns
38
+ * - **SolidJS integration**: Seamless bridge to SolidJS primitives
39
+ *
40
+ * ## Basic Usage
41
+ *
42
+ * ```typescript
43
+ * import { state, effect, derivation } from 'picoflow';
44
+ *
45
+ * // Create reactive state
46
+ * const $count = state(0);
47
+ *
48
+ * // Create derived value
49
+ * const $double = derivation((t) => $count.get(t) * 2);
50
+ *
51
+ * // Create effect
52
+ * effect((t) => {
53
+ * console.log('Count:', $count.get(t), 'Double:', $double.get(t));
54
+ * });
55
+ *
56
+ * // Update state
57
+ * $count.set(1); // Logs: "Count: 1 Double: 2"
58
+ * ```
59
+ *
60
+ * @see {@link https://github.com/yourusername/picoflow | GitHub Repository}
8
61
  */
62
+
9
63
  export {
10
- signal,
11
- state,
12
- constant,
13
- resource,
14
- stream,
15
- derivation,
16
- effect,
17
- map,
18
- array,
19
- streamAsync,
20
- resourceAsync,
21
- } from "./creators";
64
+ FlowArray,
65
+ type FlowArrayAction,
66
+ FlowMap,
67
+ FlowResource,
68
+ FlowResourceAsync,
69
+ FlowStream,
70
+ FlowStreamAsync,
71
+ type FlowStreamDisposer,
72
+ type FlowStreamSetter,
73
+ type FlowStreamUpdater,
74
+ } from "./advanced/";
22
75
 
23
76
  export {
24
- isDisposable,
25
- FlowDerivation,
26
- FlowEffect,
27
- FlowObservable,
28
- FlowSignal,
29
- FlowState,
30
- FlowConstant,
31
- type FlowGetter,
32
- type FlowWatcher,
33
- type FlowDisposable,
77
+ FlowConstant,
78
+ FlowDerivation,
79
+ type FlowDisposable,
80
+ FlowEffect,
81
+ FlowObservable,
82
+ FlowSignal,
83
+ FlowState,
84
+ isDisposable,
85
+ TrackingContext,
34
86
  } from "./basic/";
35
-
36
87
  export {
37
- FlowResource,
38
- FlowMap,
39
- FlowResourceAsync,
40
- FlowStreamAsync,
41
- FlowStream,
42
- FlowArray,
43
- type FlowStreamDisposer,
44
- type FlowStreamSetter,
45
- type FlowStreamUpdater,
46
- type FlowArrayAction,
47
- } from "./advanced/";
88
+ array,
89
+ constant,
90
+ derivation,
91
+ effect,
92
+ map,
93
+ resource,
94
+ resourceAsync,
95
+ signal,
96
+ state,
97
+ stream,
98
+ streamAsync,
99
+ } from "./creators";
48
100
 
49
101
  export {
50
- from,
51
- SolidState,
52
- SolidResource,
53
- SolidDerivation,
54
- type SolidObservable,
55
- type SolidGetter,
102
+ from,
103
+ type NotPromise,
104
+ SolidDerivation,
105
+ type SolidGetter,
106
+ type SolidObservable,
107
+ SolidResource,
108
+ SolidState,
56
109
  } from "./solid/";