@ersbeth/picoflow 2.0.1 → 2.0.3

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 (154) hide show
  1. package/README.md +10 -0
  2. package/SKILL.md +106 -0
  3. package/dist/types/api/base/flowSubscribable.d.ts +3 -3
  4. package/dist/types/api/base/flowSubscribable.d.ts.map +1 -1
  5. package/package.json +5 -1
  6. package/.gitlab-ci.yml +0 -24
  7. package/.vscode/settings.json +0 -5
  8. package/CHANGELOG.md +0 -94
  9. package/biome.json +0 -47
  10. package/docs/.vitepress/config.mts +0 -145
  11. package/docs/api/functions/array.md +0 -35
  12. package/docs/api/functions/constant.md +0 -33
  13. package/docs/api/functions/constantAsync.md +0 -69
  14. package/docs/api/functions/derivation.md +0 -34
  15. package/docs/api/functions/derivationAsync.md +0 -34
  16. package/docs/api/functions/from.md +0 -129
  17. package/docs/api/functions/isDisposable.md +0 -27
  18. package/docs/api/functions/map.md +0 -36
  19. package/docs/api/functions/signal.md +0 -21
  20. package/docs/api/functions/state.md +0 -67
  21. package/docs/api/functions/stateAsync.md +0 -69
  22. package/docs/api/functions/subscribe.md +0 -40
  23. package/docs/api/functions/writableDerivation.md +0 -33
  24. package/docs/api/functions/writableDerivationAsync.md +0 -34
  25. package/docs/api/index.md +0 -61
  26. package/docs/api/interfaces/FlowArray.md +0 -439
  27. package/docs/api/interfaces/FlowConstant.md +0 -220
  28. package/docs/api/interfaces/FlowConstantAsync.md +0 -221
  29. package/docs/api/interfaces/FlowDerivation.md +0 -241
  30. package/docs/api/interfaces/FlowDerivationAsync.md +0 -242
  31. package/docs/api/interfaces/FlowDisposable.md +0 -59
  32. package/docs/api/interfaces/FlowEffect.md +0 -64
  33. package/docs/api/interfaces/FlowMap.md +0 -374
  34. package/docs/api/interfaces/FlowObservable.md +0 -155
  35. package/docs/api/interfaces/FlowSignal.md +0 -156
  36. package/docs/api/interfaces/FlowState.md +0 -269
  37. package/docs/api/interfaces/FlowStateAsync.md +0 -268
  38. package/docs/api/interfaces/FlowSubscribable.md +0 -55
  39. package/docs/api/interfaces/FlowTracker.md +0 -61
  40. package/docs/api/interfaces/FlowValue.md +0 -222
  41. package/docs/api/interfaces/FlowWritableDerivation.md +0 -292
  42. package/docs/api/interfaces/FlowWritableDerivationAsync.md +0 -293
  43. package/docs/api/type-aliases/DerivationFunction.md +0 -28
  44. package/docs/api/type-aliases/DerivationFunctionAsync.md +0 -28
  45. package/docs/api/type-aliases/FlowArrayAction.md +0 -60
  46. package/docs/api/type-aliases/FlowDataTracker.md +0 -33
  47. package/docs/api/type-aliases/FlowMapAction.md +0 -48
  48. package/docs/api/type-aliases/FlowOnDataListener.md +0 -33
  49. package/docs/api/type-aliases/FlowOnErrorListener.md +0 -27
  50. package/docs/api/type-aliases/FlowOnPendingListener.md +0 -21
  51. package/docs/api/type-aliases/FlowReadonly.md +0 -22
  52. package/docs/api/type-aliases/InitFunction.md +0 -21
  53. package/docs/api/type-aliases/InitFunctionAsync.md +0 -21
  54. package/docs/api/type-aliases/NotPromise.md +0 -21
  55. package/docs/api/type-aliases/UpdateFunction.md +0 -27
  56. package/docs/api/type-aliases/UpdateFunctionAsync.md +0 -27
  57. package/docs/api/typedoc-sidebar.json +0 -65
  58. package/docs/examples/examples.md +0 -2311
  59. package/docs/examples/patterns.md +0 -649
  60. package/docs/guide/advanced/architecture.md +0 -1234
  61. package/docs/guide/advanced/disposal.md +0 -426
  62. package/docs/guide/advanced/migration-v1.md +0 -464
  63. package/docs/guide/advanced/migration-v2.md +0 -204
  64. package/docs/guide/advanced/solidjs.md +0 -135
  65. package/docs/guide/introduction/concepts.md +0 -57
  66. package/docs/guide/introduction/conventions.md +0 -30
  67. package/docs/guide/introduction/getting-started.md +0 -139
  68. package/docs/guide/introduction/lifecycle.md +0 -368
  69. package/docs/guide/primitives/array.md +0 -286
  70. package/docs/guide/primitives/constant.md +0 -207
  71. package/docs/guide/primitives/derivations.md +0 -281
  72. package/docs/guide/primitives/effects.md +0 -372
  73. package/docs/guide/primitives/map.md +0 -265
  74. package/docs/guide/primitives/overview.md +0 -92
  75. package/docs/guide/primitives/signal.md +0 -222
  76. package/docs/guide/primitives/state.md +0 -272
  77. package/docs/index.md +0 -47
  78. package/docs/public/logo.svg +0 -1
  79. package/src/api/base/flowDisposable.ts +0 -44
  80. package/src/api/base/flowObservable.ts +0 -28
  81. package/src/api/base/flowSubscribable.ts +0 -87
  82. package/src/api/base/flowTracker.ts +0 -7
  83. package/src/api/base/index.ts +0 -4
  84. package/src/api/index.ts +0 -2
  85. package/src/api/nodes/async/flowConstantAsync.ts +0 -36
  86. package/src/api/nodes/async/flowDerivationAsync.ts +0 -42
  87. package/src/api/nodes/async/flowStateAsync.ts +0 -47
  88. package/src/api/nodes/async/flowWritableDerivationAsync.ts +0 -33
  89. package/src/api/nodes/async/index.ts +0 -4
  90. package/src/api/nodes/collections/flowArray.ts +0 -155
  91. package/src/api/nodes/collections/flowMap.ts +0 -115
  92. package/src/api/nodes/collections/index.ts +0 -2
  93. package/src/api/nodes/flowEffect.ts +0 -42
  94. package/src/api/nodes/flowSignal.ts +0 -28
  95. package/src/api/nodes/flowValue.ts +0 -37
  96. package/src/api/nodes/index.ts +0 -7
  97. package/src/api/nodes/sync/flowConstant.ts +0 -33
  98. package/src/api/nodes/sync/flowDerivation.ts +0 -41
  99. package/src/api/nodes/sync/flowState.ts +0 -45
  100. package/src/api/nodes/sync/flowWritableDerivation.ts +0 -31
  101. package/src/api/nodes/sync/index.ts +0 -4
  102. package/src/api/nodes/utils.ts +0 -24
  103. package/src/base/disposable.ts +0 -18
  104. package/src/base/executionStack.ts +0 -42
  105. package/src/base/index.ts +0 -5
  106. package/src/base/node.ts +0 -98
  107. package/src/base/observable.ts +0 -92
  108. package/src/base/observer.ts +0 -51
  109. package/src/converters/index.ts +0 -1
  110. package/src/converters/solid.ts +0 -109
  111. package/src/index.ts +0 -2
  112. package/src/nodes/arrayNode.ts +0 -180
  113. package/src/nodes/effectNode.ts +0 -58
  114. package/src/nodes/index.ts +0 -7
  115. package/src/nodes/mapNode.ts +0 -125
  116. package/src/nodes/signalNode.ts +0 -19
  117. package/src/nodes/valueAsyncNode.ts +0 -85
  118. package/src/nodes/valueNode.ts +0 -148
  119. package/src/nodes/valueSyncNode.ts +0 -125
  120. package/src/schedulers/asyncResolver.ts +0 -78
  121. package/src/schedulers/asyncScheduler.ts +0 -66
  122. package/src/schedulers/index.ts +0 -4
  123. package/src/schedulers/pendingError.ts +0 -13
  124. package/src/schedulers/scheduler.ts +0 -9
  125. package/src/schedulers/syncResolver.ts +0 -69
  126. package/src/schedulers/syncScheduler.ts +0 -55
  127. package/test/base/pendingError.test.ts +0 -67
  128. package/test/converters/solid.derivation.browser.test.tsx +0 -69
  129. package/test/converters/solid.node.test.ts +0 -654
  130. package/test/converters/solid.state.browser.test.tsx +0 -1592
  131. package/test/reactivity/flowSignal.test.ts +0 -226
  132. package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +0 -593
  133. package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +0 -317
  134. package/test/reactivity/nodes/async/flowConstantAsync.test.ts +0 -652
  135. package/test/reactivity/nodes/async/flowDerivation.test.ts +0 -898
  136. package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +0 -1716
  137. package/test/reactivity/nodes/async/flowStateAsync.test.ts +0 -708
  138. package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +0 -614
  139. package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +0 -1289
  140. package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +0 -961
  141. package/test/reactivity/nodes/collections/flowArray.states.test.ts +0 -1035
  142. package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +0 -960
  143. package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +0 -775
  144. package/test/reactivity/nodes/collections/flowMap.states.test.ts +0 -958
  145. package/test/reactivity/nodes/sync/flowConstant.test.ts +0 -377
  146. package/test/reactivity/nodes/sync/flowDerivation.test.ts +0 -896
  147. package/test/reactivity/nodes/sync/flowState.test.ts +0 -341
  148. package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +0 -603
  149. package/test/vitest.d.ts +0 -10
  150. package/tsconfig.json +0 -37
  151. package/typedoc.json +0 -37
  152. package/vite.config.ts +0 -31
  153. package/vitest.browser.config.ts +0 -21
  154. package/vitest.config.ts +0 -17
@@ -1,426 +0,0 @@
1
- # Disposal
2
-
3
- Memory management is crucial in long-running applications. PicoFlow provides explicit disposal mechanisms to prevent memory leaks and ensure resources are properly cleaned up.
4
-
5
- ## Why Disposal Matters
6
-
7
- All PicoFlow primitives are disposable. When you're done with them, you should clean them up:
8
-
9
- ```typescript
10
- const $count = state(0)
11
- const fx = effect((t) => {
12
- console.log($count.get(t))
13
- })
14
-
15
- // Later... clean up
16
- fx.dispose() // Effect stops running
17
- $count.dispose() // State is cleaned up
18
- ```
19
-
20
- **Why disposal matters:**
21
- - **Prevents memory leaks** - Unreferenced but undisposed primitives stay in memory
22
- - **Stops effects from running** - Effects continue executing until explicitly disposed
23
- - **Cleans up resources** - WebSocket connections, intervals, event listeners, etc.
24
- - **Important in long-running applications** - SPAs, dashboards, real-time apps
25
-
26
- ```mermaid
27
- flowchart LR
28
- A[Create primitive] --> B[Use in effects]
29
- B --> C[No longer needed]
30
- C --> D{Disposed?}
31
- D -->|Yes| E[Memory freed]
32
- D -->|No| F[Memory leak!]
33
-
34
- style E fill:#90EE90
35
- style F fill:#FFB6C6
36
- ```
37
-
38
- ## When to Dispose
39
-
40
- ### Component Cleanup
41
-
42
- In component-based architectures, dispose primitives when components unmount:
43
-
44
- ```typescript
45
- class TodoList {
46
- private $todos = state<Todo[]>([])
47
- private disposables: FlowDisposable[] = []
48
-
49
- constructor() {
50
- // Track all disposables
51
- this.disposables.push(
52
- effect((t) => {
53
- this.render($todos.get(t))
54
- })
55
- )
56
- }
57
-
58
- destroy() {
59
- // Clean up when component is destroyed
60
- this.disposables.forEach(d => d.dispose())
61
- this.$todos.dispose()
62
- }
63
- }
64
- ```
65
-
66
- ### Conditional Effects
67
-
68
- Dispose and recreate effects based on application state:
69
-
70
- ```typescript
71
- let currentEffect: FlowEffect | null = null
72
-
73
- function enableLogging(enable: boolean) {
74
- // Dispose previous effect
75
- currentEffect?.dispose()
76
-
77
- if (enable) {
78
- currentEffect = effect((t) => {
79
- console.log('Value:', $data.get(t))
80
- })
81
- }
82
- }
83
-
84
- // Toggle logging on/off
85
- enableLogging(true) // Effect starts
86
- enableLogging(false) // Effect disposed
87
- ```
88
-
89
- ### Resource Management
90
-
91
- Dispose primitives that manage external resources:
92
-
93
- ```typescript
94
- const $wsData = stream<string>((set) => {
95
- const ws = new WebSocket('ws://example.com')
96
- ws.onmessage = (e) => set(e.data)
97
-
98
- // Cleanup function called on disposal
99
- return () => ws.close()
100
- })
101
-
102
- // Use the stream
103
- effect((t) => {
104
- console.log('Message:', $wsData.get(t))
105
- })
106
-
107
- // Later... close the connection
108
- $wsData.dispose()
109
- ```
110
-
111
- ### Interval Cleanup
112
-
113
- ```typescript
114
- const $tick = stream<number>((set) => {
115
- let count = 0
116
- const interval = setInterval(() => {
117
- set(count++)
118
- }, 1000)
119
-
120
- // Cleanup: clear interval on disposal
121
- return () => clearInterval(interval)
122
- })
123
-
124
- // Later...
125
- $tick.dispose() // Interval cleared
126
- ```
127
-
128
- ## Automatic Cleanup
129
-
130
- Effects automatically clean up their dependencies when disposed:
131
-
132
- ```typescript
133
- const $a = state(1)
134
- const $b = state(2)
135
-
136
- const fx = effect((t) => {
137
- console.log($a.get(t) + $b.get(t))
138
- })
139
-
140
- fx.dispose()
141
-
142
- // These no longer trigger the effect
143
- $a.set(10) // No console log
144
- $b.set(20) // No console log
145
- ```
146
-
147
- When an effect is disposed:
148
- 1. It unregisters from all its dependencies
149
- 2. Future changes to those dependencies won't trigger it
150
- 3. The effect's memory is freed
151
-
152
- ## Best Practices
153
-
154
- ### 1. Always Dispose in Cleanup Hooks
155
-
156
- In any framework with lifecycle hooks, dispose in the cleanup phase:
157
-
158
- ```typescript
159
- // React
160
- useEffect(() => {
161
- const fx = effect((t) => {
162
- // ... effect code
163
- })
164
-
165
- return () => fx.dispose() // Cleanup
166
- }, [])
167
-
168
- // Vue
169
- onUnmounted(() => {
170
- fx.dispose()
171
- })
172
-
173
- // Svelte
174
- onDestroy(() => {
175
- fx.dispose()
176
- })
177
- ```
178
-
179
- ### 2. Group Related Disposables
180
-
181
- Use collections to manage multiple disposables:
182
-
183
- ```typescript
184
- class DataManager {
185
- private disposables = new Set<FlowDisposable>()
186
-
187
- track(disposable: FlowDisposable) {
188
- this.disposables.add(disposable)
189
- }
190
-
191
- cleanup() {
192
- this.disposables.forEach(d => d.dispose())
193
- this.disposables.clear()
194
- }
195
- }
196
-
197
- // Usage
198
- const manager = new DataManager()
199
- manager.track(effect((t) => { /* ... */ }))
200
- manager.track(effect((t) => { /* ... */ }))
201
- manager.track($someState)
202
-
203
- // Clean up everything
204
- manager.cleanup()
205
- ```
206
-
207
- ### 3. Dispose in Reverse Order of Creation
208
-
209
- Dispose dependents before dependencies:
210
-
211
- ```typescript
212
- const $data = state(0)
213
- const $derived = derivation((t) => $data.get(t) * 2)
214
- const fx = effect((t) => console.log($derived.get(t)))
215
-
216
- // Cleanup: dispose in reverse order
217
- fx.dispose() // Effect first (depends on $derived)
218
- $derived.dispose() // Derivation second (depends on $data)
219
- $data.dispose() // State last (no dependencies)
220
- ```
221
-
222
- **Why?** Disposing in reverse order prevents:
223
- - Accessing disposed dependencies
224
- - Unnecessary recomputations during cleanup
225
- - Race conditions during shutdown
226
-
227
- ### 4. Check Disposal State
228
-
229
- Use the `disposed` property to check if a primitive has been disposed:
230
-
231
- ```typescript
232
- const fx = effect((t) => {
233
- console.log($count.get(t))
234
- })
235
-
236
- console.log(fx.disposed) // false
237
-
238
- fx.dispose()
239
-
240
- console.log(fx.disposed) // true
241
- ```
242
-
243
- ### 5. Handle Disposal Errors
244
-
245
- Wrap disposal in try-catch for robust cleanup:
246
-
247
- ```typescript
248
- function cleanupResources(disposables: FlowDisposable[]) {
249
- const errors: Error[] = []
250
-
251
- for (const disposable of disposables) {
252
- try {
253
- disposable.dispose()
254
- } catch (error) {
255
- errors.push(error as Error)
256
- }
257
- }
258
-
259
- if (errors.length > 0) {
260
- console.error('Disposal errors:', errors)
261
- }
262
- }
263
- ```
264
-
265
- ## Common Pitfalls
266
-
267
- ### Pitfall 1: Not Disposing Effects
268
-
269
- ```typescript
270
- // ❌ Memory leak - effect never disposed
271
- function updateCounter() {
272
- effect((t) => {
273
- document.getElementById('count').textContent = $count.get(t)
274
- })
275
- }
276
-
277
- // Called 100 times = 100 effects running!
278
- for (let i = 0; i < 100; i++) {
279
- updateCounter()
280
- }
281
-
282
- // ✅ Proper cleanup
283
- function updateCounter(): () => void {
284
- const fx = effect((t) => {
285
- document.getElementById('count').textContent = $count.get(t)
286
- })
287
-
288
- return () => fx.dispose()
289
- }
290
-
291
- const cleanup = updateCounter()
292
- // Later...
293
- cleanup()
294
- ```
295
-
296
- ### Pitfall 2: Disposing Too Early
297
-
298
- ```typescript
299
- // ❌ Disposed too early
300
- const fx = effect((t) => {
301
- console.log($count.get(t))
302
- })
303
-
304
- fx.dispose() // Effect disposed immediately!
305
-
306
- $count.set(1) // No effect runs
307
-
308
- // ✅ Dispose at the right time
309
- const fx = effect((t) => {
310
- console.log($count.get(t))
311
- })
312
-
313
- // Use the effect...
314
- $count.set(1) // Effect runs
315
-
316
- // Now dispose when truly done
317
- fx.dispose()
318
- ```
319
-
320
- ### Pitfall 3: Forgetting Stream Cleanup
321
-
322
- ```typescript
323
- // ❌ WebSocket never closed
324
- function connectWebSocket() {
325
- const $ws = stream<string>((set) => {
326
- const socket = new WebSocket('ws://...')
327
- socket.onmessage = (e) => set(e.data)
328
- // Missing: return () => socket.close()
329
- })
330
- return $ws
331
- }
332
-
333
- // ✅ Proper cleanup
334
- function connectWebSocket() {
335
- const $ws = stream<string>((set) => {
336
- const socket = new WebSocket('ws://...')
337
- socket.onmessage = (e) => set(e.data)
338
-
339
- return () => socket.close() // Cleanup function
340
- })
341
- return $ws
342
- }
343
- ```
344
-
345
- ## Disposal Patterns
346
-
347
- ### Pattern 1: Disposable Builder
348
-
349
- ```typescript
350
- class DisposableBuilder {
351
- private disposables: FlowDisposable[] = []
352
-
353
- add<T extends FlowDisposable>(disposable: T): T {
354
- this.disposables.push(disposable)
355
- return disposable
356
- }
357
-
358
- disposeAll(): void {
359
- // Dispose in reverse order
360
- for (let i = this.disposables.length - 1; i >= 0; i--) {
361
- this.disposables[i].dispose()
362
- }
363
- this.disposables = []
364
- }
365
- }
366
-
367
- // Usage
368
- const builder = new DisposableBuilder()
369
- builder.add(effect((t) => { /* ... */ }))
370
- builder.add(effect((t) => { /* ... */ }))
371
- builder.disposeAll()
372
- ```
373
-
374
- ### Pattern 2: Scoped Disposables
375
-
376
- ```typescript
377
- function withDisposables<T>(
378
- fn: (track: <D extends FlowDisposable>(d: D) => D) => T
379
- ): T & { cleanup: () => void } {
380
- const disposables: FlowDisposable[] = []
381
-
382
- const track = <D extends FlowDisposable>(d: D): D => {
383
- disposables.push(d)
384
- return d
385
- }
386
-
387
- const result = fn(track) as T & { cleanup: () => void }
388
- result.cleanup = () => disposables.forEach(d => d.dispose())
389
-
390
- return result
391
- }
392
-
393
- // Usage
394
- const { cleanup } = withDisposables((track) => {
395
- const $count = track(state(0))
396
- const fx = track(effect((t) => console.log($count.get(t))))
397
- })
398
-
399
- // Clean up everything
400
- cleanup()
401
- ```
402
-
403
- ### Pattern 3: Auto-disposal on Condition
404
-
405
- ```typescript
406
- function createAutoDisposeEffect(
407
- condition: () => boolean,
408
- apply: (t: TrackingContext) => void
409
- ): FlowEffect {
410
- const fx = effect((t) => {
411
- if (!condition()) {
412
- fx.dispose()
413
- return
414
- }
415
- apply(t)
416
- })
417
- return fx
418
- }
419
-
420
- // Usage: effect auto-disposes when count > 10
421
- createAutoDisposeEffect(
422
- () => $count.pick() <= 10,
423
- (t) => console.log('Count:', $count.get(t))
424
- )
425
- ```
426
-