diff --git a/packages/devtools-extension/README.MD b/packages/devtools-extension/README.MD
new file mode 100644
index 00000000..b2dd24d1
--- /dev/null
+++ b/packages/devtools-extension/README.MD
@@ -0,0 +1,31 @@
+This is the devtools for [react-async-states](https://github.com/incepter/react-async-states) package.
+
+It is still experimental and in alpha phase.
+
+Usage:
+```tsx
+import DevtoolsView from "async-states-devtools";
+
+// then embed anywhere in your tree:
+
+```
+or
+```tsx
+import {AutoConfiguredDevtools} from "async-states-devtools";
+
+// embed this devtools anywhere
+
+
+```
+or
+```tsx
+import {autoConfigureDevtools} from "async-states-devtools";
+
+// or just let magic happen by itself
+autoConfigureDevtools();
+```
+
+Note/issue: The devtools uses antd for now (will be removed), so your styles may
+clash if also using antd.
+
+Antd will be removed from the library asap.
diff --git a/packages/devtools-extension/package.json b/packages/devtools-extension/package.json
index 3dd45b13..8b9b0dca 100644
--- a/packages/devtools-extension/package.json
+++ b/packages/devtools-extension/package.json
@@ -1,11 +1,14 @@
{
"name": "async-states-devtools",
- "private": true,
"type": "module",
- "version": "0.0.1",
+ "version": "0.0.1-alpha-1",
"types": "dist/index",
"module": "dist/index.js",
"main": "dist/index.umd.cjs",
+ "files": [
+ "README.MD",
+ "dist"
+ ],
"scripts": {
"dev": "vite",
"preview": "vite preview",
diff --git a/packages/react-async-states/README.MD b/packages/react-async-states/README.MD
index 95acbce8..e6d45030 100644
--- a/packages/react-async-states/README.MD
+++ b/packages/react-async-states/README.MD
@@ -1,69 +1,280 @@
# React async states
## What is this ?
-This is a multi-paradigm library for decentralized state management in React.
-It aims to facilitate and automate working with [a]synchronous states while
-sharing them. It was designed to reduce the needed boilerplate to
-achieve great and effective results.
+This is a multi-paradigm library for state management.
+
+It aims to facilitate working with [a]synchronous states while sharing them.
+It was designed to reduce the needed boilerplate to achieve great and effective
+results.
+
+It introduces a new concept: the `producer` that is similar to reducer, async
+reducer or query from other libraries you might know, but with more power.
+
+This library provides utilities for low level state manipulation, and other
+libraries may appear just a small abstraction on top of it.
## Main features
-The features that make this library special are:
-
-- Easy to use and Minimal API (`useAsyncState`).
-- Tiny library with 0 dependencies, only react as a peer dependency.
-- Targets all react/javascript environments.
-- Cancellations friendly (`props.onAbort(cb)`)
-- Designed to support concurrency
-- Supports many forms on functions (async/await, promises, generators, reducers)
-- Run [side] effects either declaratively or imperatively.
-- Built-in `status` in the state (initial, pending, success, error and aborted).
-- Built-in `debounce` and `throttle`.
-- Cache support.
-- Events support.
-- Dynamic creation and sharing of states at runtime.
-- Share states inside and outside the provider without store.
-- Subscribe and react to `selected` portions of state while controlling
- when to re-render.
-- Fork the state to have same behavior with separate subscribers.
-- Lanes support to have several `grouped` states sharing the same cache.
-- Hoist states to provider on demand at runtime.
-- Automatic cleanup/reset on dependencies change (includes unmount).
-- React 18+ friendly (already supported through the `read()` API).
-- Powerful selectors.
-## Get started
+#### Multi-paradigm nature
+The library can work with the following modes:
-To get started using the library, please make sure to read [the docs](https://incepter.github.io/react-async-states/docs/intro).
-[The tutorial section](https://incepter.github.io/react-async-states/docs/tutorial/first-steps) is a good starting point to get your hands dirty.
+- `Imperative` and/or `declarative`
+- `Synchronous` and/or `Asynchronous`
+- Data fetching and/or any form of asynchrony
+- Inside and/or outside `React`
+- Inside and/or outside `React context provider`
+- With or without `Cache`
+- `Promises`, `async/await` and even `generators` or nothing at all
+- Allows abstractions on top of it
+- ...
+
+#### Easy to use and Minimal API (`useAsyncState`).
+The library has one main hook: `useAsyncState` which allows the creation,
+subscription and manipulation of the desired state.
+[Here is a sneak peek](https://incepter.github.io/react-async-states/docs/api/the-whole-api#useasyncstate)
+at this hook's full API.
+
+#### Tiny library with no dependencies and works in all environments
+The library has no dependencies and very small on size compared to all the power
+it gives, and it should target all environments (browser, node, native...).
+
+#### Synchronous and asynchronous; Imperative and declarative support
+The library adds the `status` property as part of the state, the possible values
+are: `initial`, `pending`, `success`, `error` and `aborted`.
+
+When your producer runs, it becomes asynchronous if the returned value is a
+`Thenable` object. But, you can control the `pending` status: eg, skip it
+totally if our promise resolves under `400ms`. Or skip it entirely if you want
+to perform some `fetch-then-render` patterns.
+
+The library allows you to perform declarative runs using `useAsyncState`
+hook configuration, while also providing a multiple imperative `run` functions
+with different signatures to answer your needs.
+
+#### Promises, async/await & generators support
+The `producer`, the core concept of the library can be of different forms (you
+can even omit it and manipulate the state directly, without a producer function):
+
+Either return a promise (thenable) to your state, use async/await syntax or go
+generators. All of these are supported by the library out of the box and
+no configuration is needed.
+
+```typescript
+useAsyncState();
+useAsyncState(function getSomeData() { return fetchMyData(); });
+useAsyncState(function* someGenerator() { yield fetchMyData(); });
+useAsyncState(async function getSomeData() { return await fetchMyData(); });
+```
+
+[Here is a sneak peek](https://incepter.github.io/react-async-states/docs/api/the-whole-api#producer) at the producer signature:
+
+#### Automatic and friendly cancellations
+The library was designed from the start to support cancellations in a standard
+way: an `onAbort` callback registration function that registers your callbacks,
+that are invoked once your run is cancelled (either decoratively or imperatively).
+
+In practice, we found ourselves writing the following, depending on context:
+```typescript
+onAbort((reason) => controller.abort(reason));
+onAbort(() => socket.disconnect());
+onAbort(() => worker.terminate());
+onAbort(() => clearInterval(id));
+onAbort(() => clearTimeout(id));
+```
+
+When your state loses all the subscriptions (and depending on the `resetStateOnDispose`)
+configuration, it will go back to its initial state and aborting any ongoing run.
+This behavior is opt-in, and it is not the default mode of the library.
+
+#### Events and callbacks support
+The library supports two forms of imperative notifications when state is updated:
+
+- Via `events` as a configuration of `useAsyncState`: This allows you to react
+to updates occurring in a share piece of state.
+- Via `runc` function: It allows having callbacks `per run`, not by subscription.
+
+```typescript
+import {useAsyncState} from "react-async-states";
+
+const {runc} = useAsyncState({
+ // ... config
+ events: {
+ change: [
+ newState => console.log('state changed'), // will be invoked every state change
+ {
+ status: 'success', // handler will be invoked only in success status
+ handler : (successState) => {},
+ }
+ ],
+ }
+})
+
+// or per run callbacks:
+runc({
+ args: myOptionalArgs,
+ onError : () => {},
+ onSuccess : () => {},
+ onAborted : () => {}, // not called when the abort status is bailed out
+ // no onPending callback.
+});
+```
+
+#### Dynamic creation and sharing of states at runtime
+Under the `AsyncStateProvider`, you can create and share state instances
+and access them by their `key` via the `hoistToProvider` option.
+
+You can even start listening to a state before it gets hoisted to the provider,
+and get notified once it gets added.
+
+#### Works with or without a provider
+The library can work without the provider and still share state via the
+`source` special object.
+
+#### Apply effects or runs: debounce, throttle...
+To avoid creating additional state pieces and third party utilities,
+the library has out-of-the box support for effects that can be applied to runs:
+such as `debounce`, and `throttle` and `delay`.
+This support allows you to create awesome user experience natively with the
+minimum CPU and RAM fingerprints, without additional libraries or managed
+variables. It just works in the core of the library. Of course, this requires
+you to be in an environment where `setTimeout` exists.
+
+```tsx
+import {useAsyncState, ProducerRunEffects} from "react-async-states";
+
+const {run} = useAsyncState({
+ producer: userSearchByUsername,
+ // debounce runs
+ runEffect: ProducerRunEffects.debounce,
+ runEffectDurationMs: 300,
+ // skip pending status if it answers less than 200ms
+ skipPendingDelayMs: 200,
+});
+
+
+ run(e.target.value)} /* ... */ />
+```
+
+#### On-demand cache support
+The library has a different cache support: it doesn't cache the value of you state,
+rather, it caches your producer runs when they succeed by hashing the run `args`
+and `payload`.
+
+Let's add cache support to the previous example:
+
+```tsx
+import {useAsyncState, ProducerRunEffects} from "react-async-states";
+
+// note that the whole configuration object does not depend on render
+// and can be moved to module level static object.
+const {run} = useAsyncState({
+ producer: userSearchByUsername,
+ // debounce runs
+ runEffect: ProducerRunEffects.debounce,
+ runEffectDurationMs: 300,
+ // skip pending status if it answers less than 200ms
+ skipPendingDelayMs: 200,
+
+ // cache config:
+ cacheConfig: {
+ enabled: true, // enable cache
+ // run cache hash is the username passed to the producer, this allows to
+ // have cached entries such as: `incepter` : { state: {data}}
+ hash: (args) => args[0],
+ getDeadline: (state) => state.data.maxAge || Infinity,
+ }
+});
+
+
+ run(e.target.value)} /* ... */ />
+```
+
+The library allows you also to `persist` and `load` cache, even asynchronously
+and then do something in the `onCacheLoad` event.
+
+#### Forks and lanes support
+Forking a state in the library means having a new state instance, with the same
+producer, and probably the same cache (configurable), while having a new isolated
+state with new subscribers.
+
+The library has two ways for forks
+- Normal forks: obtained by adding `fork: true` to `useAsyncState`, and these
+are standalone states.
+- Lanes: These are normal forks, but managed by their parent and share the same
+cache, they can be enumerated from their parent via `source.getAllLanes`,
+and removed by `source.removeLane`.
+
+```typescript
+import {useAsyncState, useSourceLane} from "react-async-states";
+
+const references = createSource("refs", referencesProducer, {
+ /* awesome config */
+});
+
+const {state} = useAsyncState({
+ source: references,
+ lane: 'cities',
+ lazy: false
+});
+const {state} = useAsyncState({source: references, lane: 'roles', lazy: false});
+// can be simplified to this:
+const {state} = useSourceLane(references, 'roles');
+
+// re-use a state with its producer called weather present in the provider
+const {state: weatherState} = useAsyncState({key: "weather", fork: true});
+
+```
+
+#### Powerful selectors
+
+The library has two ways to select data from states:
+- via `useAsyncState`: it supports a `selector` configuration can accept the
+current state and the whole cache (you can decide to just work with cache, if you want to!)
+- via `useSelector`: This hook allows you to select data from one or multiple
+pieces of states, it even allows combining `keys` and `source` object to select from them.
+It also can dynamically select states from the provider as they get hoisted.
+
+#### And many more
+
+The previous examples are just a few subset of the library's power, there are
+several other unique features like:
+
+- Cascade runs and cancellations
+- Run and wait for resolve
+- Producer states that emit updates after resolve (such as websockets)
+- Configurable state disposal and garbage collection
+- React 18 support, and no tearing even without `useSES`
+- StateBoundary and support for all three `render strategies`
+- post subscribe and change events
+- And many more..
+
+
+## Get started
The library is available as a package on NPM for use with a module bundler or in a Node application:
-```shell
+```bash
# NPM
npm install react-async-states
+```
+```bash
# YARN
yarn add react-async-states
```
+```bash
+# PNPM
+pnpm add react-async-states
+```
-## Use cases
-
-The library supports several paradigms, which allows it to support almost
-every use case you can think of.
-
-In a nutshell, the library can manage:
-- Synchronous and asynchronous states
-- Cancellations
-- State sharing
-- Selectors
-- Caching
-- Inside and outside provider
-- Run effects such as debounce and throttle
-- Events
+To get started using the library, please make sure to read [the docs](https://incepter.github.io/react-async-states/docs/intro).
+[The tutorial section](https://incepter.github.io/react-async-states/docs/tutorial/first-steps) is a good starting point to get your hands dirty.
-[This section of the docs](https://incepter.github.io/react-async-states/docs/use-cases/) tells more about this.
## Contribution
To contribute, please refer take a look at [the issues section](https://github.com/incepter/react-async-states/issues).
+
+
+By [@incepter](https://twitter.com/incepterr), with 💜
diff --git a/packages/react-async-states/package.json b/packages/react-async-states/package.json
index b1e26166..2c9fab8e 100644
--- a/packages/react-async-states/package.json
+++ b/packages/react-async-states/package.json
@@ -3,7 +3,7 @@
"license": "MIT",
"author": "incepter",
"sideEffects": false,
- "version": "1.0.0-rc-8",
+ "version": "1.0.0-rc-9",
"module": "dist/index",
"main": "dist/umd/index",
"types": "dist/src/index",
diff --git a/packages/ts-example/package.json b/packages/ts-example/package.json
index 9736df93..2420d7f9 100644
--- a/packages/ts-example/package.json
+++ b/packages/ts-example/package.json
@@ -16,7 +16,7 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "6.4.3",
- "react-async-states": "1.0.0-rc-8",
+ "react-async-states": "1.0.0-rc-9",
"ts-node": "10.9.1"
},
"devDependencies": {