@ersbeth/picoflow 2.0.2 → 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.
- package/README.md +10 -0
- package/SKILL.md +106 -0
- package/package.json +5 -1
- package/.gitlab-ci.yml +0 -24
- package/.vscode/settings.json +0 -5
- package/CHANGELOG.md +0 -94
- package/biome.json +0 -47
- package/docs/.vitepress/config.mts +0 -145
- package/docs/api/functions/array.md +0 -35
- package/docs/api/functions/constant.md +0 -33
- package/docs/api/functions/constantAsync.md +0 -69
- package/docs/api/functions/derivation.md +0 -34
- package/docs/api/functions/derivationAsync.md +0 -34
- package/docs/api/functions/from.md +0 -129
- package/docs/api/functions/isDisposable.md +0 -27
- package/docs/api/functions/map.md +0 -36
- package/docs/api/functions/signal.md +0 -21
- package/docs/api/functions/state.md +0 -67
- package/docs/api/functions/stateAsync.md +0 -69
- package/docs/api/functions/subscribe.md +0 -40
- package/docs/api/functions/writableDerivation.md +0 -33
- package/docs/api/functions/writableDerivationAsync.md +0 -34
- package/docs/api/index.md +0 -61
- package/docs/api/interfaces/FlowArray.md +0 -439
- package/docs/api/interfaces/FlowConstant.md +0 -220
- package/docs/api/interfaces/FlowConstantAsync.md +0 -221
- package/docs/api/interfaces/FlowDerivation.md +0 -241
- package/docs/api/interfaces/FlowDerivationAsync.md +0 -242
- package/docs/api/interfaces/FlowDisposable.md +0 -59
- package/docs/api/interfaces/FlowEffect.md +0 -64
- package/docs/api/interfaces/FlowMap.md +0 -374
- package/docs/api/interfaces/FlowObservable.md +0 -155
- package/docs/api/interfaces/FlowSignal.md +0 -156
- package/docs/api/interfaces/FlowState.md +0 -269
- package/docs/api/interfaces/FlowStateAsync.md +0 -268
- package/docs/api/interfaces/FlowSubscribable.md +0 -55
- package/docs/api/interfaces/FlowTracker.md +0 -61
- package/docs/api/interfaces/FlowValue.md +0 -222
- package/docs/api/interfaces/FlowWritableDerivation.md +0 -292
- package/docs/api/interfaces/FlowWritableDerivationAsync.md +0 -293
- package/docs/api/type-aliases/DerivationFunction.md +0 -28
- package/docs/api/type-aliases/DerivationFunctionAsync.md +0 -28
- package/docs/api/type-aliases/FlowArrayAction.md +0 -60
- package/docs/api/type-aliases/FlowDataTracker.md +0 -33
- package/docs/api/type-aliases/FlowMapAction.md +0 -48
- package/docs/api/type-aliases/FlowOnDataListener.md +0 -33
- package/docs/api/type-aliases/FlowOnErrorListener.md +0 -27
- package/docs/api/type-aliases/FlowOnPendingListener.md +0 -21
- package/docs/api/type-aliases/FlowReadonly.md +0 -22
- package/docs/api/type-aliases/InitFunction.md +0 -21
- package/docs/api/type-aliases/InitFunctionAsync.md +0 -21
- package/docs/api/type-aliases/NotPromise.md +0 -21
- package/docs/api/type-aliases/UpdateFunction.md +0 -27
- package/docs/api/type-aliases/UpdateFunctionAsync.md +0 -27
- package/docs/api/typedoc-sidebar.json +0 -65
- package/docs/examples/examples.md +0 -2311
- package/docs/examples/patterns.md +0 -649
- package/docs/guide/advanced/architecture.md +0 -1234
- package/docs/guide/advanced/disposal.md +0 -426
- package/docs/guide/advanced/migration-v1.md +0 -464
- package/docs/guide/advanced/migration-v2.md +0 -204
- package/docs/guide/advanced/solidjs.md +0 -135
- package/docs/guide/introduction/concepts.md +0 -57
- package/docs/guide/introduction/conventions.md +0 -30
- package/docs/guide/introduction/getting-started.md +0 -139
- package/docs/guide/introduction/lifecycle.md +0 -368
- package/docs/guide/primitives/array.md +0 -286
- package/docs/guide/primitives/constant.md +0 -207
- package/docs/guide/primitives/derivations.md +0 -281
- package/docs/guide/primitives/effects.md +0 -372
- package/docs/guide/primitives/map.md +0 -265
- package/docs/guide/primitives/overview.md +0 -92
- package/docs/guide/primitives/signal.md +0 -222
- package/docs/guide/primitives/state.md +0 -272
- package/docs/index.md +0 -47
- package/docs/public/logo.svg +0 -1
- package/src/api/base/flowDisposable.ts +0 -44
- package/src/api/base/flowObservable.ts +0 -28
- package/src/api/base/flowSubscribable.ts +0 -87
- package/src/api/base/flowTracker.ts +0 -7
- package/src/api/base/index.ts +0 -4
- package/src/api/index.ts +0 -2
- package/src/api/nodes/async/flowConstantAsync.ts +0 -36
- package/src/api/nodes/async/flowDerivationAsync.ts +0 -42
- package/src/api/nodes/async/flowStateAsync.ts +0 -47
- package/src/api/nodes/async/flowWritableDerivationAsync.ts +0 -33
- package/src/api/nodes/async/index.ts +0 -4
- package/src/api/nodes/collections/flowArray.ts +0 -155
- package/src/api/nodes/collections/flowMap.ts +0 -115
- package/src/api/nodes/collections/index.ts +0 -2
- package/src/api/nodes/flowEffect.ts +0 -42
- package/src/api/nodes/flowSignal.ts +0 -28
- package/src/api/nodes/flowValue.ts +0 -37
- package/src/api/nodes/index.ts +0 -7
- package/src/api/nodes/sync/flowConstant.ts +0 -33
- package/src/api/nodes/sync/flowDerivation.ts +0 -41
- package/src/api/nodes/sync/flowState.ts +0 -45
- package/src/api/nodes/sync/flowWritableDerivation.ts +0 -31
- package/src/api/nodes/sync/index.ts +0 -4
- package/src/api/nodes/utils.ts +0 -24
- package/src/base/disposable.ts +0 -18
- package/src/base/executionStack.ts +0 -42
- package/src/base/index.ts +0 -5
- package/src/base/node.ts +0 -98
- package/src/base/observable.ts +0 -92
- package/src/base/observer.ts +0 -51
- package/src/converters/index.ts +0 -1
- package/src/converters/solid.ts +0 -109
- package/src/index.ts +0 -2
- package/src/nodes/arrayNode.ts +0 -180
- package/src/nodes/effectNode.ts +0 -58
- package/src/nodes/index.ts +0 -7
- package/src/nodes/mapNode.ts +0 -125
- package/src/nodes/signalNode.ts +0 -19
- package/src/nodes/valueAsyncNode.ts +0 -85
- package/src/nodes/valueNode.ts +0 -148
- package/src/nodes/valueSyncNode.ts +0 -125
- package/src/schedulers/asyncResolver.ts +0 -78
- package/src/schedulers/asyncScheduler.ts +0 -66
- package/src/schedulers/index.ts +0 -4
- package/src/schedulers/pendingError.ts +0 -13
- package/src/schedulers/scheduler.ts +0 -9
- package/src/schedulers/syncResolver.ts +0 -69
- package/src/schedulers/syncScheduler.ts +0 -55
- package/test/base/pendingError.test.ts +0 -67
- package/test/converters/solid.derivation.browser.test.tsx +0 -69
- package/test/converters/solid.node.test.ts +0 -654
- package/test/converters/solid.state.browser.test.tsx +0 -1592
- package/test/reactivity/flowSignal.test.ts +0 -226
- package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +0 -593
- package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +0 -317
- package/test/reactivity/nodes/async/flowConstantAsync.test.ts +0 -652
- package/test/reactivity/nodes/async/flowDerivation.test.ts +0 -898
- package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +0 -1716
- package/test/reactivity/nodes/async/flowStateAsync.test.ts +0 -708
- package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +0 -614
- package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +0 -1289
- package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +0 -961
- package/test/reactivity/nodes/collections/flowArray.states.test.ts +0 -1035
- package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +0 -960
- package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +0 -775
- package/test/reactivity/nodes/collections/flowMap.states.test.ts +0 -958
- package/test/reactivity/nodes/sync/flowConstant.test.ts +0 -377
- package/test/reactivity/nodes/sync/flowDerivation.test.ts +0 -896
- package/test/reactivity/nodes/sync/flowState.test.ts +0 -341
- package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +0 -603
- package/test/vitest.d.ts +0 -10
- package/tsconfig.json +0 -37
- package/typedoc.json +0 -37
- package/vite.config.ts +0 -31
- package/vitest.browser.config.ts +0 -21
- package/vitest.config.ts +0 -17
package/README.md
CHANGED
|
@@ -21,6 +21,16 @@ yarn add @ersbeth/picoflow
|
|
|
21
21
|
|
|
22
22
|
For comprehensive guides and API documentation, visit the [official website](https://ersbeth-web.gitlab.io/picoflow/)
|
|
23
23
|
|
|
24
|
+
## AI Coding Agents
|
|
25
|
+
|
|
26
|
+
Picoflow ships a [`SKILL.md`](SKILL.md) with the npm package, matching the exact version you have
|
|
27
|
+
installed. If you use an agent skill tool (e.g. [`npx skills`](https://github.com/vercel-labs/skills)),
|
|
28
|
+
install it straight from `node_modules` after installing the package:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx skills add ./node_modules/@ersbeth/picoflow
|
|
32
|
+
```
|
|
33
|
+
|
|
24
34
|
## License
|
|
25
35
|
|
|
26
36
|
This project is licensed under the [MIT License](LICENSE).
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: picoflow
|
|
3
|
+
description: Use when writing, reviewing, or debugging TypeScript code that uses @ersbeth/picoflow's reactive primitives (signal, state, constant, derivation, writableDerivation, array, map, subscribe). Covers the explicit tracking model (get(t) vs pick()), disposal, and the mistakes that silently break reactivity.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PicoFlow
|
|
7
|
+
|
|
8
|
+
PicoFlow is a reactive dataflow library with **explicit tracking** — there is no automatic dependency
|
|
9
|
+
detection like in Vue, MobX or Solid. Follow the rules below whenever you write or review code that
|
|
10
|
+
imports from `@ersbeth/picoflow`.
|
|
11
|
+
|
|
12
|
+
## The core rule: `.get(t)` vs `.pick()`
|
|
13
|
+
|
|
14
|
+
Every primitive is read one of two ways:
|
|
15
|
+
|
|
16
|
+
- **`.get(t)`** — tracked read. `t` is a `FlowTracker`, only available inside a `derivation()` callback
|
|
17
|
+
or a `subscribe()` data function. Registers the caller as a dependent.
|
|
18
|
+
- **`.pick()`** — untracked async read (`Promise<T>`). Use outside reactive contexts (event handlers,
|
|
19
|
+
one-off reads) when you don't want to react to future changes.
|
|
20
|
+
|
|
21
|
+
Never call `.get(t)` outside a derivation/subscribe callback — `t` isn't available there. Never use
|
|
22
|
+
`.pick()` inside a derivation/subscribe when you actually want reactivity — it silently creates no
|
|
23
|
+
dependency, which is a common source of "why doesn't this update" bugs.
|
|
24
|
+
|
|
25
|
+
Reactive values are named with a `$` prefix (`$count`, `$user`) by convention — keep this when writing
|
|
26
|
+
new code in a PicoFlow codebase, and use it to tell reactive values apart from plain ones at a glance.
|
|
27
|
+
|
|
28
|
+
## Choosing a primitive
|
|
29
|
+
|
|
30
|
+
| Need | Use | Not |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Event with no payload (trigger a refresh, coordinate actions) | `signal()` | `state()` for a flag no one reads |
|
|
33
|
+
| Mutable value that changes over time | `state(value)` | `constant` (if it truly never changes) |
|
|
34
|
+
| Expensive one-time computation, never changes | `constant(() => ...)` — **always a function**, computed lazily on first access | a plain top-level `const` if nothing reactive reads it |
|
|
35
|
+
| Pure computed value from other primitives | `derivation((t) => ...)` | putting side effects in it — use `subscribe` |
|
|
36
|
+
| A derivation that occasionally needs manual override | `writableDerivation((t) => ...)` | — |
|
|
37
|
+
| List with fine-grained mutation tracking | `array(initial?)` | `state(someArray)` if you need per-operation tracking |
|
|
38
|
+
| Key-value store with fine-grained mutation tracking | `map(initial?)` | `state(someMap)` if you need per-operation tracking |
|
|
39
|
+
| Running side effects (DOM, network, storage, logging) in reaction to changes | `.subscribe()` (single primitive) or `subscribe()` (multiple) | `derivation` — derivations must stay pure |
|
|
40
|
+
|
|
41
|
+
Async variants exist for state/constant/derivation/writableDerivation (`stateAsync`, `constantAsync`,
|
|
42
|
+
`derivationAsync`, `writableDerivationAsync`) — same rules, the held value is a `Promise<T>`, and reads
|
|
43
|
+
of a still-pending value are handled automatically (surfaced via `subscribe()`'s optional `onPending`
|
|
44
|
+
callback) rather than needing manual `await`/try-catch inside a derivation.
|
|
45
|
+
|
|
46
|
+
## Mistakes to catch when reviewing PicoFlow code
|
|
47
|
+
|
|
48
|
+
- **Side effects inside `derivation()`** (logging, API calls, mutating outside state) — derivations must
|
|
49
|
+
be pure; move the side effect into a `subscribe()`.
|
|
50
|
+
- **Mutating a collection returned by `.get(t)`/`.pick()` in place**, e.g. `items.push(x)` on a picked
|
|
51
|
+
array, or `user.name = 'x'` on a picked object, then relying on it to update — this changes nothing
|
|
52
|
+
observable. Always produce a new array/object (`items.map(...)`, `{ ...user, name: 'x' }`), or use the
|
|
53
|
+
primitive's own mutation methods (`$array.push(x)`, `$map.update(k, v)`).
|
|
54
|
+
- **`constant(value)` with a direct value instead of a function** — constants always take an initializer
|
|
55
|
+
function (`constant(() => value)`), enforcing lazy evaluation. A direct value is a v1 pattern (see below).
|
|
56
|
+
- **Not disposing subscriptions/primitives** (`.dispose()`) when they're no longer needed — every
|
|
57
|
+
`subscribe()`/`.subscribe()` call keeps running until disposed; forgetting this in code that creates
|
|
58
|
+
subscriptions repeatedly (e.g. once per component instance, once per request) is a memory leak.
|
|
59
|
+
- **Creating a subscription inside another subscription's callback** — it re-creates one on every run
|
|
60
|
+
and leaks. Combine into a single `subscribe()` whose data function reads all the needed primitives.
|
|
61
|
+
- **A `subscribe()`/`.subscribe()` callback that calls `.set()` on a primitive it also reads** — infinite
|
|
62
|
+
loop.
|
|
63
|
+
- **Using `add()`/`update()` on `array`/`map` without checking preconditions** — `array.update(index, x)`
|
|
64
|
+
throws if the index is out of bounds; `map.add(key, x)` throws if the key exists; `map.update(key, x)`
|
|
65
|
+
throws if it doesn't. Check first (`.pick()`) or branch on it, don't assume.
|
|
66
|
+
- **Tracking the whole `array`/`map` (`.subscribe()`/`.get(t)`) when only specific operations matter** —
|
|
67
|
+
prefer `$collection.$lastAction.subscribe(...)` (a discriminated union with a `type` field) to react
|
|
68
|
+
only to the mutation kind you care about, instead of re-running on every change.
|
|
69
|
+
|
|
70
|
+
## Recognizing pre-v2 (deprecated) API usage
|
|
71
|
+
|
|
72
|
+
If existing code uses any of these, it predates PicoFlow v2 — flag it and suggest migrating (full guide:
|
|
73
|
+
https://ersbeth-web.gitlab.io/picoflow/guide/advanced/migration-v2.html):
|
|
74
|
+
|
|
75
|
+
- `effect((t) => ...)` — removed. Replace with `.subscribe()` (single primitive) or `subscribe()` (multiple).
|
|
76
|
+
- `$map.$lastAdded` / `$lastUpdated` / `$lastDeleted` — replaced by a single `$map.$lastAction` signal
|
|
77
|
+
with a `type` discriminant.
|
|
78
|
+
- `$array.setItem(index, value)` — renamed to `$array.update(index, value)`.
|
|
79
|
+
- `constant(value)` with a direct (non-function) value.
|
|
80
|
+
|
|
81
|
+
## Minimal example (the shape most PicoFlow code follows)
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { state, derivation, subscribe } from '@ersbeth/picoflow'
|
|
85
|
+
|
|
86
|
+
const $count = state(0)
|
|
87
|
+
const $isEven = derivation((t) => $count.get(t) % 2 === 0)
|
|
88
|
+
|
|
89
|
+
const effect = subscribe(
|
|
90
|
+
(t) => ({ count: $count.get(t), even: $isEven.get(t) }),
|
|
91
|
+
(data) => console.log(`Count is ${data.count}, which is ${data.even ? 'even' : 'odd'}`),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
$count.set((n) => n + 1) // atomic updater form, prefer it when the new value depends on the current one
|
|
95
|
+
|
|
96
|
+
// when done:
|
|
97
|
+
effect.dispose()
|
|
98
|
+
$count.dispose()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Further reference
|
|
102
|
+
|
|
103
|
+
This file covers the rules needed to write and review correct PicoFlow code. For the full generated API
|
|
104
|
+
reference (every method, accessor, inherited member) or the guide with longer walkthroughs, see
|
|
105
|
+
https://ersbeth-web.gitlab.io/picoflow/ (or its condensed single-file form at
|
|
106
|
+
https://ersbeth-web.gitlab.io/picoflow/llms-full.txt).
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ersbeth/picoflow",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Minimal Dataflow library for TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"SKILL.md"
|
|
9
|
+
],
|
|
6
10
|
"exports": {
|
|
7
11
|
"types": "./dist/types/index.d.ts",
|
|
8
12
|
"default": "./dist/picoflow.js"
|
package/.gitlab-ci.yml
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
image: node:20
|
|
2
|
-
|
|
3
|
-
cache:
|
|
4
|
-
paths:
|
|
5
|
-
- node_modules/
|
|
6
|
-
- .pnpm-store/
|
|
7
|
-
|
|
8
|
-
variables:
|
|
9
|
-
PNPM_VERSION: 8
|
|
10
|
-
|
|
11
|
-
before_script:
|
|
12
|
-
- npm install -g pnpm@${PNPM_VERSION}
|
|
13
|
-
- pnpm install
|
|
14
|
-
|
|
15
|
-
pages:
|
|
16
|
-
stage: deploy
|
|
17
|
-
script:
|
|
18
|
-
- pnpm docs:build
|
|
19
|
-
- cp -r docs/.vitepress/dist public
|
|
20
|
-
artifacts:
|
|
21
|
-
paths:
|
|
22
|
-
- public
|
|
23
|
-
rules:
|
|
24
|
-
- if: $CI_COMMIT_BRANCH == "main"
|
package/.vscode/settings.json
DELETED
package/CHANGELOG.md
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [Unreleased]
|
|
9
|
-
|
|
10
|
-
## [2.0.0] - 2026-01-11
|
|
11
|
-
|
|
12
|
-
### 🚨 BREAKING CHANGES
|
|
13
|
-
|
|
14
|
-
This is a major API refinement focusing on consistency, performance, and clarity. **This release is not backward compatible with v1.x.**
|
|
15
|
-
|
|
16
|
-
**Migration required:** Please see the [Migration Guide](docs/guide/advanced/migration-v2.md) for detailed migration instructions. Most projects can be migrated in 30-60 minutes.
|
|
17
|
-
|
|
18
|
-
### Changed
|
|
19
|
-
|
|
20
|
-
- **`effect()` API removed:** The global `effect()` function has been replaced with `subscribe()` and `.subscribe()` methods for better consistency and clarity
|
|
21
|
-
- Single primitive subscriptions: use `$primitive.subscribe((value) => { ... })`
|
|
22
|
-
- Multiple dependencies: use `subscribe((t) => ({ ... }), (data) => { ... })`
|
|
23
|
-
- **FlowMap fine-grained tracking simplified:** Replaced three separate signals (`$lastAdded`, `$lastUpdated`, `$lastDeleted`) with a single unified `$lastAction` signal
|
|
24
|
-
- Actions now use a discriminated union type with `type` field
|
|
25
|
-
- Action properties renamed for clarity: `value` → `addedValue`, `setValue`, `removedValue`
|
|
26
|
-
- Added `set` and `clear` action types
|
|
27
|
-
- **FlowArray method renamed:** `setItem()` → `update()` for consistency with FlowMap
|
|
28
|
-
- **Constant initialization:** Constants now always require a function initializer `constant(() => value)`, enforcing lazy evaluation
|
|
29
|
-
- **Improved type naming:** Internal `TrackingContext` is now properly exported as `FlowTracker` interface
|
|
30
|
-
|
|
31
|
-
### Added
|
|
32
|
-
|
|
33
|
-
- **`subscribe()` function:** New global function for creating side effects with multiple dependencies
|
|
34
|
-
- **`.subscribe()` method:** Convenient method on primitives for single-value subscriptions
|
|
35
|
-
- **`FlowEffect` interface:** Return type for all subscription operations, providing consistent disposal pattern
|
|
36
|
-
- **Enhanced FlowMap actions:** Added `set` and `clear` action types to `$lastAction` for complete operation tracking
|
|
37
|
-
|
|
38
|
-
### Removed
|
|
39
|
-
|
|
40
|
-
- **`effect()` function:** Replaced by `subscribe()` and `.subscribe()` methods
|
|
41
|
-
- **FlowMap separate signals:** `$lastAdded`, `$lastUpdated`, `$lastDeleted` replaced by unified `$lastAction`
|
|
42
|
-
- **FlowArray `setItem()` method:** Renamed to `update()`
|
|
43
|
-
|
|
44
|
-
### Benefits
|
|
45
|
-
|
|
46
|
-
- **Clearer API:** Distinction between primitives and side effects (subscriptions) is more explicit
|
|
47
|
-
- **Better performance:** Single `$lastAction` signal reduces overhead in collection tracking
|
|
48
|
-
- **More consistent:** Unified naming across FlowArray and FlowMap operations
|
|
49
|
-
- **Simpler mental model:** `subscribe()` clearly indicates side effects vs pure derivations
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## [1.0.0] - 2025-11-29
|
|
54
|
-
|
|
55
|
-
### 🚨 BREAKING CHANGES
|
|
56
|
-
|
|
57
|
-
This is a major rewrite of PicoFlow's API. The library now uses an explicit tracking context instead of getter/watcher functions. **This release is not backward compatible with v0.x.**
|
|
58
|
-
|
|
59
|
-
**Migration required:** Please see [UPGRADING.md](UPGRADING.md) for detailed migration instructions. Most projects can be migrated in 15-30 minutes.
|
|
60
|
-
|
|
61
|
-
### Changed
|
|
62
|
-
|
|
63
|
-
- **Complete API overhaul:** Effects and derivations now receive a `TrackingContext` parameter (`t`) instead of separate `get` and `watch` functions
|
|
64
|
-
- **New method-based API:** Observables use `.get(t)` for reactive reads instead of `get(observable)`
|
|
65
|
-
- **Signals use `.watch(t)`:** Signal tracking now uses `$signal.watch(t)` instead of `watch($signal)`
|
|
66
|
-
- **Chained syntax:** Enable natural chaining like `$parent.get(t).child.get(t)` instead of nested `get(get($parent).child)`
|
|
67
|
-
- **Simpler architecture:** Removed internal methods (`_watch`, `_watchFrom`, `_getFrom`) in favor of direct method overrides
|
|
68
|
-
|
|
69
|
-
### Added
|
|
70
|
-
|
|
71
|
-
- **`TrackingContext` class:** New explicit tracking context for reactive computations
|
|
72
|
-
- **`pick()` method:** Read observable values without creating dependencies - `$state.pick()` is equivalent to `$state.get(null)`
|
|
73
|
-
- **Explicit control:** Granular control over what is tracked vs. untracked in the same reactive scope
|
|
74
|
-
- **Mixed reactive/non-reactive reads:** Use `.get(t)` for reactive dependencies and `.pick()` for snapshot reads in the same effect
|
|
75
|
-
|
|
76
|
-
### Removed
|
|
77
|
-
|
|
78
|
-
- **`FlowGetter` type:** Replaced by `TrackingContext` parameter
|
|
79
|
-
- **`FlowWatcher` type:** Replaced by `TrackingContext` parameter
|
|
80
|
-
- **Implicit getter/watcher functions:** No longer passed to effects and derivations
|
|
81
|
-
|
|
82
|
-
### Benefits
|
|
83
|
-
|
|
84
|
-
- **More readable:** Code is more explicit about what creates dependencies
|
|
85
|
-
- **Better chaining:** Natural fluent API for nested observables
|
|
86
|
-
- **Simpler codebase:** Cleaner internal architecture with fewer abstractions
|
|
87
|
-
- **More flexible:** Fine-grained control over reactive tracking per read operation
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## [0.2.4] - Previous Release
|
|
92
|
-
|
|
93
|
-
(Version 0.x releases used the getter/watcher API)
|
|
94
|
-
|
package/biome.json
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
|
|
3
|
-
"vcs": {
|
|
4
|
-
"enabled": true,
|
|
5
|
-
"clientKind": "git",
|
|
6
|
-
"useIgnoreFile": true
|
|
7
|
-
},
|
|
8
|
-
"files": {
|
|
9
|
-
"includes": ["**", "!!**/dist"]
|
|
10
|
-
},
|
|
11
|
-
"formatter": {
|
|
12
|
-
"enabled": true,
|
|
13
|
-
"indentStyle": "space",
|
|
14
|
-
"indentWidth": 4,
|
|
15
|
-
"lineWidth": 120
|
|
16
|
-
},
|
|
17
|
-
"linter": {
|
|
18
|
-
"enabled": true,
|
|
19
|
-
"rules": {
|
|
20
|
-
"recommended": true,
|
|
21
|
-
"complexity": {
|
|
22
|
-
"noStaticOnlyClass": "off"
|
|
23
|
-
},
|
|
24
|
-
"nursery": {
|
|
25
|
-
"useExhaustiveSwitchCases": "error",
|
|
26
|
-
"noFloatingPromises": "error",
|
|
27
|
-
"noMisusedPromises": "error"
|
|
28
|
-
},
|
|
29
|
-
"suspicious": {
|
|
30
|
-
"useAwait": "error"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"javascript": {
|
|
35
|
-
"formatter": {
|
|
36
|
-
"quoteStyle": "double"
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"assist": {
|
|
40
|
-
"enabled": true,
|
|
41
|
-
"actions": {
|
|
42
|
-
"source": {
|
|
43
|
-
"organizeImports": "on"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vitepress";
|
|
2
|
-
import { withMermaid } from "vitepress-plugin-mermaid";
|
|
3
|
-
import typedocSidebar from "../api/typedoc-sidebar.json";
|
|
4
|
-
|
|
5
|
-
export default withMermaid(
|
|
6
|
-
defineConfig({
|
|
7
|
-
title: "PicoFlow",
|
|
8
|
-
description: "Lightweight reactive dataflow library for TypeScript",
|
|
9
|
-
base: "/picoflow/",
|
|
10
|
-
|
|
11
|
-
mermaid: {},
|
|
12
|
-
|
|
13
|
-
head: [["link", { rel: "icon", type: "image/svg+xml", href: "/logo.svg" }]],
|
|
14
|
-
|
|
15
|
-
themeConfig: {
|
|
16
|
-
logo: "/logo.svg",
|
|
17
|
-
|
|
18
|
-
nav: [
|
|
19
|
-
{ text: "Guide", link: "/guide/introduction/getting-started" },
|
|
20
|
-
// { text: "Examples", link: "/examples/patterns" },
|
|
21
|
-
{ text: "API Reference", link: "/api/" },
|
|
22
|
-
],
|
|
23
|
-
|
|
24
|
-
sidebar: {
|
|
25
|
-
"/guide/": [
|
|
26
|
-
{
|
|
27
|
-
text: "Introduction",
|
|
28
|
-
items: [
|
|
29
|
-
{
|
|
30
|
-
text: "Getting Started",
|
|
31
|
-
link: "/guide/introduction/getting-started",
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
text: "Conventions",
|
|
35
|
-
link: "/guide/introduction/conventions",
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
text: "Concepts",
|
|
39
|
-
link: "/guide/introduction/concepts",
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
text: "Primitives",
|
|
45
|
-
items: [
|
|
46
|
-
{
|
|
47
|
-
text: "Overview",
|
|
48
|
-
link: "/guide/primitives/overview",
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
text: "Signals",
|
|
52
|
-
link: "/guide/primitives/signal",
|
|
53
|
-
},
|
|
54
|
-
{ text: "Constants", link: "/guide/primitives/constant" },
|
|
55
|
-
|
|
56
|
-
{ text: "States", link: "/guide/primitives/state" },
|
|
57
|
-
{
|
|
58
|
-
text: "Derivations",
|
|
59
|
-
link: "/guide/primitives/derivations",
|
|
60
|
-
},
|
|
61
|
-
{ text: "Maps", link: "/guide/primitives/map" },
|
|
62
|
-
{ text: "Arrays", link: "/guide/primitives/array" },
|
|
63
|
-
{
|
|
64
|
-
text: "Side Effects",
|
|
65
|
-
link: "/guide/primitives/effects",
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
text: "Advanced",
|
|
71
|
-
items: [
|
|
72
|
-
{
|
|
73
|
-
text: "Use with SolidJS",
|
|
74
|
-
link: "/guide/advanced/solidjs",
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
text: "Upgrade to v2",
|
|
78
|
-
link: "/guide/advanced/migration-v2",
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
text: "Upgrade to v1",
|
|
82
|
-
link: "/guide/advanced/migration-v1",
|
|
83
|
-
},
|
|
84
|
-
// {
|
|
85
|
-
// text: "Lifecycle",
|
|
86
|
-
// link: "/guide/introduction/lifecycle",
|
|
87
|
-
// },
|
|
88
|
-
// {
|
|
89
|
-
// text: "Disposal",
|
|
90
|
-
// link: "/guide/advanced/disposal",
|
|
91
|
-
// },
|
|
92
|
-
// {
|
|
93
|
-
// text: "Architecture",
|
|
94
|
-
// link: "/guide/advanced/architecture",
|
|
95
|
-
// },
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
|
|
100
|
-
// "/examples/": [
|
|
101
|
-
// {
|
|
102
|
-
// text: "Examples",
|
|
103
|
-
// items: [
|
|
104
|
-
// {
|
|
105
|
-
// text: "Common Patterns",
|
|
106
|
-
// link: "/examples/patterns",
|
|
107
|
-
// },
|
|
108
|
-
// {
|
|
109
|
-
// text: "Code Examples",
|
|
110
|
-
// link: "/examples/examples",
|
|
111
|
-
// },
|
|
112
|
-
// ],
|
|
113
|
-
// },
|
|
114
|
-
// ],
|
|
115
|
-
|
|
116
|
-
"/api/": [
|
|
117
|
-
{
|
|
118
|
-
text: "API Reference",
|
|
119
|
-
items: typedocSidebar,
|
|
120
|
-
},
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
socialLinks: [
|
|
125
|
-
{
|
|
126
|
-
icon: "gitlab",
|
|
127
|
-
link: "https://gitlab.com/ersbeth-web/picoflow",
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
|
|
131
|
-
search: {
|
|
132
|
-
provider: "local",
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
editLink: {
|
|
136
|
-
pattern: "https://gitlab.com/ersbeth-web/picoflow/-/edit/main/docs/:path",
|
|
137
|
-
text: "Edit this page on GitLab",
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
footer: {
|
|
141
|
-
copyright: "Copyright ©2025 <a href='https://gitlab.com/ersbeth/'>Ersbeth</a>",
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
}),
|
|
145
|
-
);
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
[@ersbeth/picoflow](/api/index.md) / array
|
|
2
|
-
|
|
3
|
-
# Function: array()
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
function array<T>(initial?): FlowArray<T>;
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Defined in: [api/nodes/collections/flowArray.ts:153](https://gitlab.com/ersbeth-web/picoflow/-/blob/4e864254f0eac72524c3be40b9e41d799a16e020/src/api/nodes/collections/flowArray.ts#L153)
|
|
10
|
-
|
|
11
|
-
Creates a reactive array with mutation methods and fine-grained action tracking.
|
|
12
|
-
|
|
13
|
-
The array starts with the provided initial items (or empty if none provided). All mutation methods
|
|
14
|
-
(push, pop, splice, etc.) notify dependents and emit detailed action information to `$lastAction`.
|
|
15
|
-
Use the array itself for coarse-grained reactivity, or subscribe to `$lastAction` for fine-grained
|
|
16
|
-
reactivity to specific mutation types. Useful for reactive lists, collections, or any data that
|
|
17
|
-
needs array-like operations with automatic change propagation.
|
|
18
|
-
|
|
19
|
-
## Type Parameters
|
|
20
|
-
|
|
21
|
-
| Type Parameter |
|
|
22
|
-
| ------ |
|
|
23
|
-
| `T` |
|
|
24
|
-
|
|
25
|
-
## Parameters
|
|
26
|
-
|
|
27
|
-
| Parameter | Type | Description |
|
|
28
|
-
| ------ | ------ | ------ |
|
|
29
|
-
| `initial?` | `T`[] | Optional initial array of items |
|
|
30
|
-
|
|
31
|
-
## Returns
|
|
32
|
-
|
|
33
|
-
[`FlowArray`](/api/interfaces/FlowArray.md)\<`T`\>
|
|
34
|
-
|
|
35
|
-
A FlowArray with reactive mutation methods
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
[@ersbeth/picoflow](/api/index.md) / constant
|
|
2
|
-
|
|
3
|
-
# Function: constant()
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
function constant<T>(initializer): FlowConstant<T>;
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Defined in: [api/nodes/sync/flowConstant.ts:31](https://gitlab.com/ersbeth-web/picoflow/-/blob/4e864254f0eac72524c3be40b9e41d799a16e020/src/api/nodes/sync/flowConstant.ts#L31)
|
|
10
|
-
|
|
11
|
-
Creates a constant reactive value that initializes lazily and never recomputes.
|
|
12
|
-
|
|
13
|
-
The initializer function runs once on first access, and the result is cached permanently.
|
|
14
|
-
Unlike state or derivations, constants never react to changes - they represent immutable values
|
|
15
|
-
in the reactive graph. Useful for expensive one-time computations or static configuration.
|
|
16
|
-
|
|
17
|
-
## Type Parameters
|
|
18
|
-
|
|
19
|
-
| Type Parameter |
|
|
20
|
-
| ------ |
|
|
21
|
-
| `T` |
|
|
22
|
-
|
|
23
|
-
## Parameters
|
|
24
|
-
|
|
25
|
-
| Parameter | Type | Description |
|
|
26
|
-
| ------ | ------ | ------ |
|
|
27
|
-
| `initializer` | [`InitFunction`](/api/type-aliases/InitFunction.md)\<`T`\> | Function that computes the constant value on first access |
|
|
28
|
-
|
|
29
|
-
## Returns
|
|
30
|
-
|
|
31
|
-
[`FlowConstant`](/api/interfaces/FlowConstant.md)\<`T`\>
|
|
32
|
-
|
|
33
|
-
A FlowConstant that provides read-only access to the cached value
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
[@ersbeth/picoflow](/api/index.md) / constantAsync
|
|
2
|
-
|
|
3
|
-
# Function: constantAsync()
|
|
4
|
-
|
|
5
|
-
## Call Signature
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
function constantAsync<T>(value): FlowConstantAsync<T>;
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Defined in: [api/nodes/async/flowConstantAsync.ts:32](https://gitlab.com/ersbeth-web/picoflow/-/blob/4e864254f0eac72524c3be40b9e41d799a16e020/src/api/nodes/async/flowConstantAsync.ts#L32)
|
|
12
|
-
|
|
13
|
-
Creates a constant reactive value from a promise or async initializer that resolves once and never recomputes.
|
|
14
|
-
|
|
15
|
-
The promise or async initializer executes once on first access, and the resolved value is cached permanently.
|
|
16
|
-
While the promise is pending, any reactive computation that accesses the value will receive PendingError and
|
|
17
|
-
automatically retry once the promise resolves. Use for one-time async operations that don't depend on other
|
|
18
|
-
reactive values, such as loading configuration or fetching initial data.
|
|
19
|
-
|
|
20
|
-
### Type Parameters
|
|
21
|
-
|
|
22
|
-
| Type Parameter |
|
|
23
|
-
| ------ |
|
|
24
|
-
| `T` |
|
|
25
|
-
|
|
26
|
-
### Parameters
|
|
27
|
-
|
|
28
|
-
| Parameter | Type | Description |
|
|
29
|
-
| ------ | ------ | ------ |
|
|
30
|
-
| `value` | `Promise`\<`T`\> | Promise to resolve, or async function that returns a promise on first access |
|
|
31
|
-
|
|
32
|
-
### Returns
|
|
33
|
-
|
|
34
|
-
[`FlowConstantAsync`](/api/interfaces/FlowConstantAsync.md)\<`T`\>
|
|
35
|
-
|
|
36
|
-
A FlowConstantAsync that provides read-only access to the resolved value
|
|
37
|
-
|
|
38
|
-
## Call Signature
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
function constantAsync<T>(initializer): FlowConstantAsync<T>;
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Defined in: [api/nodes/async/flowConstantAsync.ts:33](https://gitlab.com/ersbeth-web/picoflow/-/blob/4e864254f0eac72524c3be40b9e41d799a16e020/src/api/nodes/async/flowConstantAsync.ts#L33)
|
|
45
|
-
|
|
46
|
-
Creates a constant reactive value from a promise or async initializer that resolves once and never recomputes.
|
|
47
|
-
|
|
48
|
-
The promise or async initializer executes once on first access, and the resolved value is cached permanently.
|
|
49
|
-
While the promise is pending, any reactive computation that accesses the value will receive PendingError and
|
|
50
|
-
automatically retry once the promise resolves. Use for one-time async operations that don't depend on other
|
|
51
|
-
reactive values, such as loading configuration or fetching initial data.
|
|
52
|
-
|
|
53
|
-
### Type Parameters
|
|
54
|
-
|
|
55
|
-
| Type Parameter |
|
|
56
|
-
| ------ |
|
|
57
|
-
| `T` |
|
|
58
|
-
|
|
59
|
-
### Parameters
|
|
60
|
-
|
|
61
|
-
| Parameter | Type |
|
|
62
|
-
| ------ | ------ |
|
|
63
|
-
| `initializer` | [`InitFunctionAsync`](/api/type-aliases/InitFunctionAsync.md)\<`T`\> |
|
|
64
|
-
|
|
65
|
-
### Returns
|
|
66
|
-
|
|
67
|
-
[`FlowConstantAsync`](/api/interfaces/FlowConstantAsync.md)\<`T`\>
|
|
68
|
-
|
|
69
|
-
A FlowConstantAsync that provides read-only access to the resolved value
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
[@ersbeth/picoflow](/api/index.md) / derivation
|
|
2
|
-
|
|
3
|
-
# Function: derivation()
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
function derivation<T>(compute): FlowDerivation<T>;
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Defined in: [api/nodes/sync/flowDerivation.ts:39](https://gitlab.com/ersbeth-web/picoflow/-/blob/4e864254f0eac72524c3be40b9e41d799a16e020/src/api/nodes/sync/flowDerivation.ts#L39)
|
|
10
|
-
|
|
11
|
-
Creates a derived reactive value that automatically recomputes when dependencies change.
|
|
12
|
-
|
|
13
|
-
The compute function runs when any tracked dependency changes, and the result is cached until the next change.
|
|
14
|
-
Access reactive values within the compute function to establish dependencies automatically. The derivation
|
|
15
|
-
computes lazily on first access and then reactively thereafter. Use for derived data that should stay
|
|
16
|
-
synchronized with source state.
|
|
17
|
-
|
|
18
|
-
## Type Parameters
|
|
19
|
-
|
|
20
|
-
| Type Parameter |
|
|
21
|
-
| ------ |
|
|
22
|
-
| `T` |
|
|
23
|
-
|
|
24
|
-
## Parameters
|
|
25
|
-
|
|
26
|
-
| Parameter | Type | Description |
|
|
27
|
-
| ------ | ------ | ------ |
|
|
28
|
-
| `compute` | [`DerivationFunction`](/api/type-aliases/DerivationFunction.md)\<`T`\> | Function that accesses dependencies and computes the derived value |
|
|
29
|
-
|
|
30
|
-
## Returns
|
|
31
|
-
|
|
32
|
-
[`FlowDerivation`](/api/interfaces/FlowDerivation.md)\<`T`\>
|
|
33
|
-
|
|
34
|
-
A FlowDerivation that provides read-only access to the computed value
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
[@ersbeth/picoflow](/api/index.md) / derivationAsync
|
|
2
|
-
|
|
3
|
-
# Function: derivationAsync()
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
function derivationAsync<T>(compute): FlowDerivationAsync<T>;
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Defined in: [api/nodes/async/flowDerivationAsync.ts:40](https://gitlab.com/ersbeth-web/picoflow/-/blob/4e864254f0eac72524c3be40b9e41d799a16e020/src/api/nodes/async/flowDerivationAsync.ts#L40)
|
|
10
|
-
|
|
11
|
-
Creates an async derived value that automatically recomputes when dependencies change.
|
|
12
|
-
|
|
13
|
-
The async compute function tracks dependencies and returns a promise. When any tracked dependency changes,
|
|
14
|
-
the function runs again and returns a new promise. The resolved value is cached until the next change.
|
|
15
|
-
While the promise is pending, reactive computations that access this value receive PendingError and automatically
|
|
16
|
-
retry once resolved. Use for derived data from async sources like filtered API results or computed database queries.
|
|
17
|
-
|
|
18
|
-
## Type Parameters
|
|
19
|
-
|
|
20
|
-
| Type Parameter |
|
|
21
|
-
| ------ |
|
|
22
|
-
| `T` |
|
|
23
|
-
|
|
24
|
-
## Parameters
|
|
25
|
-
|
|
26
|
-
| Parameter | Type | Description |
|
|
27
|
-
| ------ | ------ | ------ |
|
|
28
|
-
| `compute` | [`DerivationFunctionAsync`](/api/type-aliases/DerivationFunctionAsync.md)\<`T`\> | Async function that accesses dependencies and returns a promise of the derived value |
|
|
29
|
-
|
|
30
|
-
## Returns
|
|
31
|
-
|
|
32
|
-
[`FlowDerivationAsync`](/api/interfaces/FlowDerivationAsync.md)\<`T`\>
|
|
33
|
-
|
|
34
|
-
A FlowDerivationAsync that provides read-only access to the resolved computed value
|