chizu 0.2.64 → 0.2.67
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 +32 -24
- package/dist/action/index.d.ts +2 -2
- package/dist/boundary/components/broadcast/types.d.ts +1 -1
- package/dist/boundary/components/broadcast/utils.d.ts +4 -4
- package/dist/boundary/components/consumer/components/partition/index.d.ts +4 -4
- package/dist/boundary/components/consumer/index.d.ts +1 -1
- package/dist/boundary/components/consumer/types.d.ts +4 -4
- package/dist/boundary/components/scope/index.d.ts +2 -3
- package/dist/boundary/components/scope/types.d.ts +4 -10
- package/dist/boundary/index.d.ts +1 -1
- package/dist/chizu.js +7 -8
- package/dist/chizu.umd.cjs +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/types.d.ts +26 -8
- package/dist/hooks/utils.d.ts +6 -15
- package/dist/types/index.d.ts +78 -95
- package/dist/utils/index.d.ts +18 -4
- package/package.json +26 -26
- package/dist/boundary/components/scope/partition.d.ts +0 -32
package/README.md
CHANGED
|
@@ -176,20 +176,7 @@ actions.useAction(Actions.Profile, async (context) => {
|
|
|
176
176
|
});
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
Once we have the broadcast action if we
|
|
180
|
-
|
|
181
|
-
```tsx
|
|
182
|
-
export default function Subscriptions(): React.ReactElement {
|
|
183
|
-
return (
|
|
184
|
-
<>
|
|
185
|
-
Manage your subscriptions for your{" "}
|
|
186
|
-
{actions.consume(Actions.Broadcast.Name, (name) => name.value)} account.
|
|
187
|
-
</>
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
However if we want to listen for it and perform another operation in our local component we can do that via `useAction`:
|
|
179
|
+
Once we have the broadcast action, if we want to listen for it and perform another operation in our local component we can do that via `useAction`:
|
|
193
180
|
|
|
194
181
|
```tsx
|
|
195
182
|
actions.useAction(Actions.Broadcast.Name, async (context, name) => {
|
|
@@ -201,11 +188,11 @@ actions.useAction(Actions.Broadcast.Name, async (context, name) => {
|
|
|
201
188
|
});
|
|
202
189
|
```
|
|
203
190
|
|
|
204
|
-
|
|
191
|
+
Both `read` and `peek` access the latest cached broadcast value without subscribing via `useAction`. The difference is that `read` waits for any pending annotations on the corresponding model field to settle before resolving, whereas `peek` returns the value immediately:
|
|
205
192
|
|
|
206
193
|
```tsx
|
|
207
194
|
actions.useAction(Actions.FetchFriends, async (context) => {
|
|
208
|
-
const name = await context.actions.
|
|
195
|
+
const name = await context.actions.read(Actions.Broadcast.Name);
|
|
209
196
|
if (!name) return;
|
|
210
197
|
const friends = await fetch(api.friends(name));
|
|
211
198
|
context.actions.produce(({ model }) => {
|
|
@@ -214,6 +201,34 @@ actions.useAction(Actions.FetchFriends, async (context) => {
|
|
|
214
201
|
});
|
|
215
202
|
```
|
|
216
203
|
|
|
204
|
+
`peek` is useful for guard checks or synchronous reads where you don't need to wait for settled state:
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
actions.useAction(Actions.Check, (context) => {
|
|
208
|
+
const name = context.actions.peek(Actions.Broadcast.Name);
|
|
209
|
+
if (!name) return;
|
|
210
|
+
console.log(name);
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
You can also render broadcast values declaratively in JSX with `actions.stream`. The renderer callback receives `(value, inspect)` and returns React nodes:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
function Dashboard() {
|
|
218
|
+
const [model, actions] = useDashboardActions();
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<div>
|
|
222
|
+
{actions.stream(Actions.Broadcast.User, (user, inspect) => (
|
|
223
|
+
<span>Welcome, {user.name}</span>
|
|
224
|
+
))}
|
|
225
|
+
</div>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Components that mount after a broadcast has already been dispatched automatically receive the cached value via their `useAction` handler. If you also fetch data in `Lifecycle.Mount`, see the [mount deduplication recipe](./recipes/mount-broadcast-deduplication.md) to avoid duplicate requests.
|
|
231
|
+
|
|
217
232
|
For targeted event delivery, use channeled actions. Define a channel type as the second generic argument and call the action with a channel object – handlers fire when the dispatch channel matches:
|
|
218
233
|
|
|
219
234
|
```tsx
|
|
@@ -284,16 +299,9 @@ function App() {
|
|
|
284
299
|
|
|
285
300
|
// Dispatch to all components within "TeamA" scope
|
|
286
301
|
actions.dispatch(Actions.Multicast.Update, 42, { scope: "TeamA" });
|
|
287
|
-
|
|
288
|
-
// Consume with scope
|
|
289
|
-
{
|
|
290
|
-
actions.consume(Actions.Multicast.Update, (box) => box.value, {
|
|
291
|
-
scope: "TeamA",
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
302
|
```
|
|
295
303
|
|
|
296
|
-
Unlike broadcast which reaches all components, multicast is scoped to the named boundary – perfect for isolated widget groups, form sections, or distinct UI regions.
|
|
304
|
+
Unlike broadcast which reaches all components, multicast is scoped to the named boundary – perfect for isolated widget groups, form sections, or distinct UI regions. Like broadcast, multicast caches dispatched values per scope – components that mount later automatically receive the cached value. See the [mount deduplication recipe](./recipes/mount-broadcast-deduplication.md) if you also fetch data in `Lifecycle.Mount`.
|
|
297
305
|
|
|
298
306
|
For components that always render inside a scope, use the `withScope` HOC to eliminate the manual `<Scope>` wrapper:
|
|
299
307
|
|
package/dist/action/index.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ type ActionFactory = {
|
|
|
51
51
|
* // Action with channel support for targeted dispatches
|
|
52
52
|
* static UserUpdated = Action<User, { UserId: number }>("UserUpdated");
|
|
53
53
|
*
|
|
54
|
-
* // Broadcast action - can be
|
|
54
|
+
* // Broadcast action - can be read across components
|
|
55
55
|
* static Counter = Action<number>("Counter", Distribution.Broadcast);
|
|
56
56
|
* }
|
|
57
57
|
*
|
|
@@ -60,7 +60,7 @@ type ActionFactory = {
|
|
|
60
60
|
* actions.dispatch(Actions.Increment, 5);
|
|
61
61
|
* actions.dispatch(Actions.UserUpdated, user); // broadcast to all
|
|
62
62
|
* actions.dispatch(Actions.UserUpdated({ UserId: 5 }), user); // channeled dispatch
|
|
63
|
-
* actions.
|
|
63
|
+
* actions.stream(Actions.Counter, (box) => box.value);
|
|
64
64
|
* ```
|
|
65
65
|
*/
|
|
66
66
|
export declare const Action: ActionFactory;
|
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
/**
|
|
4
4
|
* The broadcast context is a BroadcastEmitter used for distributed actions across components.
|
|
5
5
|
* Extends EventEmitter with a per-action value cache so late-mounting components can replay
|
|
6
|
-
* broadcast values even without a Partition (from `
|
|
6
|
+
* broadcast values even without a Partition (from `stream()`).
|
|
7
7
|
*/
|
|
8
8
|
export type BroadcastContext = BroadcastEmitter;
|
|
9
9
|
/**
|
|
@@ -3,10 +3,10 @@ import * as React from "react";
|
|
|
3
3
|
/**
|
|
4
4
|
* EventEmitter subclass that caches the latest payload per event.
|
|
5
5
|
*
|
|
6
|
-
* When a broadcast action is dispatched, the payload is
|
|
7
|
-
* late-mounting components can replay it via
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* When a broadcast or multicast action is dispatched, the payload is
|
|
7
|
+
* stored so that late-mounting components can replay it via
|
|
8
|
+
* {@link useLifecycles} and handlers can read it via
|
|
9
|
+
* `context.actions.read()`.
|
|
10
10
|
*/
|
|
11
11
|
export declare class BroadcastEmitter extends EventEmitter {
|
|
12
12
|
private cache;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Props } from './types.ts';
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
/**
|
|
4
|
-
* Renders output for the `
|
|
4
|
+
* Renders output for the `stream()` method by subscribing to distributed action events.
|
|
5
5
|
*
|
|
6
6
|
* This component manages a subscription to the broadcast emitter for distributed actions,
|
|
7
7
|
* storing the latest dispatched value in the Consumer context. When a new value arrives,
|
|
@@ -14,14 +14,14 @@ import * as React from "react";
|
|
|
14
14
|
* annotation tracking through the `inspect` proxy. When a payload containing annotated
|
|
15
15
|
* values is dispatched, the annotations are preserved and accessible via `inspect`.
|
|
16
16
|
*
|
|
17
|
-
* The renderer callback receives
|
|
17
|
+
* The renderer callback receives two arguments:
|
|
18
18
|
* - `value`: The latest dispatched payload
|
|
19
19
|
* - `inspect`: A proxy for checking annotation status (pending, is, draft, settled, etc.)
|
|
20
20
|
*
|
|
21
21
|
* @template T - The payload type for the action (must be an object type)
|
|
22
22
|
* @param props.action - The distributed action symbol to subscribe to
|
|
23
|
-
* @param props.renderer - Callback that receives
|
|
24
|
-
* @returns The result of calling renderer
|
|
23
|
+
* @param props.renderer - Callback that receives value and inspect, returns React nodes
|
|
24
|
+
* @returns The result of calling renderer, or null if no value exists
|
|
25
25
|
* @internal
|
|
26
26
|
*/
|
|
27
27
|
export declare function Partition<T extends object>({ action, renderer, }: Props<T>): React.ReactNode;
|
|
@@ -11,7 +11,7 @@ export type { ConsumerRenderer, Entry, ConsumerContext } from './types.ts';
|
|
|
11
11
|
*
|
|
12
12
|
* The Consumer stores the latest value for each distributed action, allowing components
|
|
13
13
|
* that mount later to access values that were dispatched before they mounted. This enables
|
|
14
|
-
* the `
|
|
14
|
+
* the `stream()` method to render the most recent value immediately.
|
|
15
15
|
*
|
|
16
16
|
* @param props.children - The children to render within the consumer context.
|
|
17
17
|
* @returns The children wrapped in a consumer context provider.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Inspect, State } from 'immertation';
|
|
2
2
|
import { ActionId } from '../tasks/types.ts';
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
/**
|
|
5
|
-
* Callback function for the
|
|
6
|
-
* Receives
|
|
5
|
+
* Callback function for the stream() method.
|
|
6
|
+
* Receives the dispatched value and an inspect proxy for annotation tracking.
|
|
7
7
|
*
|
|
8
8
|
* @template T - The payload type
|
|
9
9
|
*/
|
|
10
|
-
export type ConsumerRenderer<T> = (
|
|
10
|
+
export type ConsumerRenderer<T> = (value: T, inspect: Inspect<T>) => React.ReactNode;
|
|
11
11
|
/**
|
|
12
12
|
* Model for consumed values.
|
|
13
13
|
* Allows Immertation's State to manage the value with real inspect capabilities.
|
|
@@ -3,7 +3,6 @@ import { ComponentType, ReactNode } from 'react';
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
export { useScope, getScope } from './utils.ts';
|
|
5
5
|
export type { ScopeEntry, ScopeContext } from './types.ts';
|
|
6
|
-
export { MulticastPartition } from './partition.tsx';
|
|
7
6
|
/**
|
|
8
7
|
* Creates a named scope boundary for multicast actions.
|
|
9
8
|
*
|
|
@@ -16,8 +15,8 @@ export { MulticastPartition } from './partition.tsx';
|
|
|
16
15
|
* communication channel. When dispatching, the nearest ancestor scope
|
|
17
16
|
* with the matching name receives the event.
|
|
18
17
|
*
|
|
19
|
-
* Like Broadcast, multicast
|
|
20
|
-
*
|
|
18
|
+
* Like Broadcast, multicast caches the most recent dispatched value so that
|
|
19
|
+
* late-mounted components can read it via `context.actions.read()`.
|
|
21
20
|
*
|
|
22
21
|
* @param props.name - The unique name for this scope
|
|
23
22
|
* @param props.children - Components within the scope boundary
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Entry } from '../consumer/types.ts';
|
|
3
|
-
import { ActionId } from '../tasks/types.ts';
|
|
1
|
+
import { BroadcastEmitter } from '../broadcast/utils.ts';
|
|
4
2
|
import type * as React from "react";
|
|
5
3
|
/**
|
|
6
4
|
* Props for the Scope component.
|
|
@@ -13,17 +11,13 @@ export type Props = {
|
|
|
13
11
|
};
|
|
14
12
|
/**
|
|
15
13
|
* Represents a single scope in the ancestor chain.
|
|
16
|
-
* Each scope has its own
|
|
14
|
+
* Each scope has its own BroadcastEmitter for multicast events and caching.
|
|
17
15
|
*/
|
|
18
16
|
export type ScopeEntry = {
|
|
19
17
|
/** The name of this scope */
|
|
20
18
|
name: string;
|
|
21
|
-
/**
|
|
22
|
-
emitter:
|
|
23
|
-
/** Consumer store for late-mounting components (like Broadcast) */
|
|
24
|
-
store: Map<ActionId, Entry>;
|
|
25
|
-
/** Listeners for store changes (for consume() re-renders) */
|
|
26
|
-
listeners: Map<ActionId, Set<() => void>>;
|
|
19
|
+
/** BroadcastEmitter for multicast events within this scope (caches last payload per event) */
|
|
20
|
+
emitter: BroadcastEmitter;
|
|
27
21
|
};
|
|
28
22
|
/**
|
|
29
23
|
* The scope context is a flattened map of all ancestor scopes by name.
|
package/dist/boundary/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Props } from './types.ts';
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
/**
|
|
4
4
|
* Creates a unified context boundary for all Chizu features.
|
|
5
|
-
* Wraps children with Broadcaster,
|
|
5
|
+
* Wraps children with Broadcaster, Cache, and Tasks providers.
|
|
6
6
|
*
|
|
7
7
|
* Use this at the root of your application or to create isolated context boundaries
|
|
8
8
|
* for libraries that need their own Chizu context.
|
package/dist/chizu.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import{G as e,A as t}from"@mobily/ts-belt";import{jsx as n}from"react/jsx-runtime";import*as r from"react";import{createContext as o,useContext as c}from"react";import{immerable as i,enablePatches as s,Immer as a}from"immer";class u{static Payload=/* @__PURE__ */Symbol("chizu.brand/Payload");static Broadcast=/* @__PURE__ */Symbol("chizu.brand/Broadcast");static Multicast=/* @__PURE__ */Symbol("chizu.brand/Multicast");static Action=/* @__PURE__ */Symbol("chizu.brand/Action");static Channel=/* @__PURE__ */Symbol("chizu.brand/Channel");static Node=/* @__PURE__ */Symbol("chizu.action.lifecycle/Node");static Cache=/* @__PURE__ */Symbol("chizu.brand/Cache")}class l{static Mount=/* @__PURE__ */Symbol("chizu.action.lifecycle/Mount");static Unmount=/* @__PURE__ */Symbol("chizu.action.lifecycle/Unmount");static Error=/* @__PURE__ */Symbol("chizu.action.lifecycle/Error");static Update=/* @__PURE__ */Symbol("chizu.action.lifecycle/Update");static Node=(()=>{const e=u.Node,t=function(t){return{[u.Action]:e,[u.Payload]:void 0,[u.Channel]:t,channel:t}};return Object.defineProperty(t,u.Action,{value:e,enumerable:!1}),Object.defineProperty(t,u.Payload,{value:void 0,enumerable:!1}),t})()}var f=/* @__PURE__ */(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(f||{}),d=/* @__PURE__ */(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(d||{}),p=/* @__PURE__ */(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Disallowed=2]="Disallowed",e[e.Errored=3]="Errored",e[e.Unmounted=4]="Unmounted",e))(p||{});class h extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const m={actionPrefix:"chizu.action/",broadcastActionPrefix:"chizu.action/broadcast/",multicastActionPrefix:"chizu.action/multicast/",channelPrefix:"chizu.channel/",cachePrefix:"chizu.cache/"};function y(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new h);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new h)},{once:!0})})}function b(e){return e?Boolean(e&&"symbol"!=typeof e):/* @__PURE__ */Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const
|
|
2
|
-
return n(
|
|
3
|
-
return n(
|
|
4
|
-
return n(
|
|
5
|
-
return n(
|
|
6
|
-
return n(
|
|
7
|
-
return n(
|
|
8
|
-
return n(de.Provider,{value:i,children:t})}function be(e,t){const r=`Scoped${t.displayName||t.name||"Component"}`;return{[r]:r=>/* @__PURE__ */n(ye,{name:e,children:/* @__PURE__ */n(t,{...r})})}[r]}function ve(e){return(t,n)=>{t.actions.produce(t=>{t.model[e]=n})}}function ge(...n){const o=e.isUndefined(n[0])||e.isFunction(n[0])?{}:n[0],i=e.isFunction(n[0])?n[0]:n[1]??(()=>({})),s=ee(),a=pe(),f=re(),p=c(k),m=r.useContext(ue),y=r.useContext(se),b=oe(),v=r.useRef(!1),g=r.useRef(null),M=r.useRef(new I);v.current||(v.current=!0,g.current=M.current.hydrate(o));const[O,_]=r.useState(()=>M.current.model),N=function(e){const t=r.useRef(e);return r.useLayoutEffect(()=>{t.current=e},[e]),r.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(i()),R=r.useMemo(()=>new X,[]),U=r.useRef({handlers:/* @__PURE__ */new Map});U.current.handlers=/* @__PURE__ */new Map;const z=function(){const e=r.useRef(/* @__PURE__ */new Set),t=r.useRef(/* @__PURE__ */new Set);return r.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),L=r.useRef(d.Mounting),T=function(){const e=r.useRef({}),t=r.useRef(/* @__PURE__ */new Map),n=r.useRef(/* @__PURE__ */new Map);return r.useMemo(()=>({refs:e,pending:t,emitted:n}),[])}(),$=r.useRef(/* @__PURE__ */new Set),B=r.useRef(0),F=r.useCallback((e,t,n)=>{const r=new AbortController,o={controller:r,action:e,payload:t};return m.add(o),$.current.add(o),{model:M.current.model,get phase(){return L.current},task:o,data:N,tasks:m,nodes:T.refs.current,actions:{produce(e){if(r.signal.aborted)return;const t=M.current.produce(t=>e({model:t,inspect:M.current.inspect}));_(M.current.model),n.processes.add(t),g.current&&(n.processes.add(g.current),g.current=null)},dispatch(e,t,n){if(r.signal.aborted)return;const o=w(e),c=P(e)?e.channel:void 0;if(E(e)&&n?.scope){const e=he(a,n.scope);return void(e&&e.emitter.emit(o,t,c))}(S(e)?s:R).emit(o,t,c)},annotate:(e,t)=>M.current.annotate(e,t),async cacheable(e,t,n){if(r.signal.aborted)return{data:null};const o=A(e),c=y.get(o);if(c&&Date.now()<c.expiry)return{data:c.value};const i=function(e){return null!=e&&"object"==typeof e&&"TAG"in e?0===e.TAG?{ok:!0,value:e._0}:{ok:!1}:null==e?{ok:!1}:{ok:!0,value:e}}(await n());return i.ok?(y.set(o,{value:i.value,expiry:Date.now()+t}),{data:i.value}):{data:null}},invalidate(e){y.delete(A(e))},async consume(e,t){if(r.signal.aborted)return null;const n=w(e);let o;if(E(e)&&t?.scope){const e=he(a,t.scope);if(!e)return null;o=e.store.get(n)}else o=f.get(n);if(!o?.state.model?.value)return null;const c=o.state.inspect;return c.value.pending()&&await new Promise((e,t)=>{if(r.signal.aborted)return void t(new h);const n=()=>t(new h);r.signal.addEventListener("abort",n,{once:!0}),c.value.settled().then(()=>{r.signal.removeEventListener("abort",n),e()})}),o.state.model.value}}}},[O]);r.useLayoutEffect(()=>{function t(t,n,r){return async function(o,c){const i=r();if(e.isNotNullable(c)&&e.isNotNullable(i)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,i))return;const s={processes:/* @__PURE__ */new Set},a=Promise.withResolvers(),u=F(t,o,s);try{await n(u,o)}catch(f){const e=U.current.handlers.has(l.Error),n={reason:j(f),error:C(f),action:x(t),handled:e,tasks:m};p?.(n),e&&R.emit(l.Error,n)}finally{for(const e of m)if(e===u.task){m.delete(e),$.current.delete(e);break}s.processes.forEach(e=>M.current.prune(e)),s.processes.size>0&&b(),a.resolve()}}}B.current++;const n=/* @__PURE__ */new Set;return U.current.handlers.forEach((e,r)=>{for(const{getChannel:o,handler:c}of e){const e=t(r,c,o);if(E(r)){if(a)for(const t of a.values()){const o=t.emitter;o.on(r,e),n.add(()=>o.off(r,e))}R.on(r,e),z.multicast.add(r),n.add(()=>R.off(r,e))}else S(r)?(s.on(r,e),R.on(r,e),z.broadcast.add(r),n.add(()=>{s.off(r,e),R.off(r,e)})):(R.on(r,e),n.add(()=>R.off(r,e)))}}),()=>{const e=++B.current,t=new Set(n);queueMicrotask(()=>{if(B.current===e){for(const e of $.current)e.controller.abort(),m.delete(e);$.current.clear(),L.current=d.Unmounting,R.emit(l.Unmount),L.current=d.Unmounted;for(const e of t)e()}else for(const e of t)e()})}},[R]),r.useLayoutEffect(()=>{for(const[e,t]of T.pending.current)T.emitted.current.get(e)!==t&&(T.emitted.current.set(e,t),R.emit(u.Node,t,{Name:e}));T.pending.current.clear()}),function({unicast:n,broadcast:o,broadcastActions:c,phase:i,data:s}){const a=re(),u=r.useRef(null);r.useLayoutEffect(()=>{i.current===d.Mounting&&(n.emit(l.Mount),c.forEach(t=>{const r=a.get(t),c=r?.state.model?.value;if(!e.isNullable(c))return void n.emit(t,c);const i=o.getCached(t);e.isNullable(i)||n.emit(t,i)}),i.current=d.Mounted)},[]),r.useLayoutEffect(()=>{if(e.isNotNullable(u.current)){const e=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,s);t.isNotEmpty(Object.keys(e))&&n.emit(l.Update,e)}u.current=s},[s,n])}({unicast:R,broadcast:s,broadcastActions:z.broadcast,phase:L,data:i()});const W=r.useMemo(()=>[O,{dispatch(e,t,n){const r=w(e),o=P(e)?e.channel:void 0;if(E(e)&&n?.scope){const e=he(a,n.scope);return void(e&&e.emitter.emit(r,t,o))}(S(e)?s:R).emit(r,t,o)},consume:(e,t,n)=>E(e)&&n?.scope?r.createElement(me,{action:w(e),scopeName:n.scope,renderer:t}):r.createElement(ce,{action:w(e),renderer:t}),get inspect(){return M.current.inspect},get nodes(){return T.refs.current},node(e,t){T.refs.current[e]=t,T.pending.current.set(e,t)}}],[O,R]);return W.useAction=(e,t)=>{!function(e,t,n){const o=r.useRef(n);r.useLayoutEffect(()=>{o.current=n});const c=r.useRef(t);r.useLayoutEffect(()=>{c.current=t});const i=r.useCallback(async(e,t)=>{const n=o.current;if("GeneratorFunction"===n.constructor.name||"AsyncGeneratorFunction"===n.constructor.name){const r=n(e,t);for await(const e of r);}else await n(e,t)},[]),s=r.useCallback(()=>P(c.current)?c.current.channel:void 0,[]),a=w(t),u=e.current.handlers.get(a)??/* @__PURE__ */new Set;0===u.size&&e.current.handlers.set(a,u),u.add({getChannel:s,handler:i})}(U,e,t)},W}export{M as Action,fe as Boundary,f as Distribution,O as Entry,_ as Error,l as Lifecycle,R as Op,R as Operation,p as Reason,ye as Scope,I as State,ve as With,q as annotate,ge as useActions,v as utils,be as withScope};
|
|
1
|
+
import{G as e,A as t}from"@mobily/ts-belt";import{jsx as n}from"react/jsx-runtime";import*as r from"react";import{createContext as o,useContext as c}from"react";import{immerable as i,enablePatches as s,Immer as a}from"immer";class u{static Payload=/* @__PURE__ */Symbol("chizu.brand/Payload");static Broadcast=/* @__PURE__ */Symbol("chizu.brand/Broadcast");static Multicast=/* @__PURE__ */Symbol("chizu.brand/Multicast");static Action=/* @__PURE__ */Symbol("chizu.brand/Action");static Channel=/* @__PURE__ */Symbol("chizu.brand/Channel");static Node=/* @__PURE__ */Symbol("chizu.action.lifecycle/Node");static Cache=/* @__PURE__ */Symbol("chizu.brand/Cache")}class l{static Mount=/* @__PURE__ */Symbol("chizu.action.lifecycle/Mount");static Unmount=/* @__PURE__ */Symbol("chizu.action.lifecycle/Unmount");static Error=/* @__PURE__ */Symbol("chizu.action.lifecycle/Error");static Update=/* @__PURE__ */Symbol("chizu.action.lifecycle/Update");static Node=(()=>{const e=u.Node,t=function(t){return{[u.Action]:e,[u.Payload]:void 0,[u.Channel]:t,channel:t}};return Object.defineProperty(t,u.Action,{value:e,enumerable:!1}),Object.defineProperty(t,u.Payload,{value:void 0,enumerable:!1}),t})()}var f=/* @__PURE__ */(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(f||{}),d=/* @__PURE__ */(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(d||{}),p=/* @__PURE__ */(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Disallowed=2]="Disallowed",e[e.Errored=3]="Errored",e[e.Unmounted=4]="Unmounted",e))(p||{});class h extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const m={actionPrefix:"chizu.action/",broadcastActionPrefix:"chizu.action/broadcast/",multicastActionPrefix:"chizu.action/multicast/",channelPrefix:"chizu.channel/",cachePrefix:"chizu.cache/"};function y(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new h);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new h)},{once:!0})})}async function b(e,t,n){if(t?.aborted)throw new h;for(;;){if(await n())return;await y(e,t)}}function v(e){return e?Boolean(e&&"symbol"!=typeof e):/* @__PURE__ */Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const g=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,config:m,pk:v,poll:b,sleep:y,"ζ":y,"κ":v,"π":b},Symbol.toStringTag,{value:"Module"})),w=e=>"symbol"==typeof e;function x(t){return e.isString(t)||w(t)?t:(e.isObject(t)||e.isFunction(t))&&u.Action in t?t[u.Action]:t}function S(t){if(e.isString(t))return t.startsWith(m.broadcastActionPrefix);if(w(t))return t.description?.startsWith(m.broadcastActionPrefix)??!1;if(e.isObject(t)||e.isFunction(t)){if(u.Broadcast in t&&t[u.Broadcast])return!0;if(u.Action in t){const e=t[u.Action];return e.description?.startsWith(m.broadcastActionPrefix)??!1}}return!1}function P(t){const n=x(t),r=e.isString(n)?n:n.description??"";return r.startsWith(m.actionPrefix)&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function E(t){return e.isObject(t)&&u.Channel in t&&"channel"in t}function O(t){if(e.isString(t))return t.startsWith(m.multicastActionPrefix);if(w(t))return t.description?.startsWith(m.multicastActionPrefix)??!1;if(e.isObject(t)||e.isFunction(t)){if(u.Multicast in t&&t[u.Multicast])return!0;if(u.Action in t){const e=t[u.Action];return e.description?.startsWith(m.multicastActionPrefix)??!1}}return!1}const j=(e,t=f.Unicast)=>{const n=t===f.Broadcast?/* @__PURE__ */Symbol(`${m.broadcastActionPrefix}${e}`):t===f.Multicast?/* @__PURE__ */Symbol(`${m.multicastActionPrefix}${e}`):/* @__PURE__ */Symbol(`${m.actionPrefix}${e}`),r=function(e){return{[u.Action]:n,[u.Payload]:void 0,[u.Channel]:e,channel:e}};return Object.defineProperty(r,u.Action,{value:n,enumerable:!1}),Object.defineProperty(r,u.Payload,{value:void 0,enumerable:!1}),t===f.Broadcast&&Object.defineProperty(r,u.Broadcast,{value:!0,enumerable:!1}),t===f.Multicast&&Object.defineProperty(r,u.Multicast,{value:!0,enumerable:!1}),r};function A(){const e=/* @__PURE__ */Symbol("chizu.cache/Entry"),t=function(t){return{[u.Cache]:e,channel:t}};return Object.defineProperty(t,u.Cache,{value:e,enumerable:!1}),t}function C(e){const t=function(e){return e[u.Cache]}(e),n=function(e){return"channel"in e}(e)&&(r=e.channel)?[...Object.keys(r)].toSorted().map(e=>`${e}=${String(r[e])}`).join("&"):"";var r;return`${String(t)}:${n}`}function M(e){if(e instanceof Error){if("TimeoutError"===e.name)return p.Timedout;if("AbortError"===e.name)return p.Supplanted}return p.Errored}function k(e){return e instanceof Error?e:new Error(String(e))}const _=o(void 0);function R({handler:e,children:t}){/* @__PURE__ */
|
|
2
|
+
return n(_.Provider,{value:e,children:t})}let N=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var U=/* @__PURE__ */(e=>(e[e.Add=1]="Add",e[e.Remove=2]="Remove",e[e.Update=4]="Update",e[e.Move=8]="Move",e[e.Replace=16]="Replace",e[e.Sort=32]="Sort",e[e.Create=64]="Create",e[e.Fetch=128]="Fetch",e[e.Clone=256]="Clone",e[e.Archive=512]="Archive",e[e.Restore=1024]="Restore",e[e.Merge=2048]="Merge",e[e.Reorder=4096]="Reorder",e[e.Sync=8192]="Sync",e[e.Publish=16384]="Publish",e[e.Link=32768]="Link",e[e.Unlink=65536]="Unlink",e[e.Lock=131072]="Lock",e[e.Unlock=262144]="Unlock",e[e.Import=524288]="Import",e[e.Export=1048576]="Export",e[e.Transfer=2097152]="Transfer",e))(U||{}),z=/* @__PURE__ */(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(z||{}),L=/* @__PURE__ */(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(L||{});class T{[i]=!0;static keys=new Set(Object.values(L));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new T(this.value,this.operation);return n.property=e,n.process=t,n}}class ${static immer=(()=>{s();const e=new a;return e.setAutoFreeze(!1),e})();static tag="κ";static id=N}function B(e,t){const n="string"==typeof t?""===t?[]:t.split("."):t;let r=e;for(const o of n){if(null==r)return;r=r[o]}return r}function F(t){if(e.isNullable(t)||H(t))return t;if(e.isArray(t))return t.map(e=>F(e));if(e.isObject(t)&&D(t)){const e=Object.entries(t).map(([e,t])=>[e,F(t)]);return{...Object.fromEntries(e),[$.tag]:t[$.tag]??$.id()}}return t}function W(e){if(Array.isArray(e))return e.filter(e=>$.tag in e).map(e=>e[$.tag]??"").join(",");const t=e[$.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function D(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function H(t){return e.isNullable(t)||e.isString(t)||e.isNumber(t)||e.isBoolean(t)||"symbol"==typeof t||"bigint"==typeof t}function G(t,n,r,o,c,i){return function s(a,u=n.path){if(a instanceof T){const n=B(r,u.join("."));if(Object.entries(a).filter(([e,t])=>!T.keys.has(e)&&t instanceof T).forEach(([e,t])=>s(t,u.concat(e))),H(a.value)){if(t===z.Hydrate)return a.value;const s=u.slice(0,-1),l=s.length>0?B(r,s.join(".")):r;return e.isNullable(l)||I(l,a,u.at(-1),o,c,i),n??a.value}if(t===z.Hydrate){const e=F(s(a.value,u));return I(e,a,null,o,c,i),e}const l=n??F(a.value);return I(l,a,null,o,c,i),e.isNullable(n)?l:(s(a.value,u),n)}if(e.isArray(a))return a.map((e,t)=>s(e,u.concat(t)));if(e.isObject(a)&&!D(a))return a;if(e.isObject(a)){const e=Object.entries(a).map(([e,t])=>[e,s(t,u.concat(e))]),n=Object.fromEntries(e);if(t===z.Hydrate){const e=F(n);return Object.entries(a).forEach(([t,n])=>{n instanceof T&&H(n.value)&&I(e,n,t,o,c,i)}),e}return n}return a}(n.value)}function I(e,t,n,r,o,c){const i=c(e),s=o.get(i)??[];o.set(i,[t.assign(n,r),...s])}class V{#e={};#t;#n=/* @__PURE__ */new Map;#r=/* @__PURE__ */new Set;#o=!1;constructor(e=W){this.#t=e}static pk(){return N()}static"κ"=V.pk;annotate(e,t){return new T(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(n,r,o,c,i){function s(c){const i=c.at(-1),s=B(n(),c),a=c.slice(0,-1),u=t.isNotEmpty(a)?B(n(),a):n();return[...e.isObject(s)||e.isArray(s)?r.get(o(s))?.filter(t=>e.isNullable(t.property))??[]:[],...e.isObject(u)?r.get(o(u))?.filter(e=>e.property===i)??[]:[]]}return function e(r){return new Proxy(()=>{},{get:(o,a)=>"pending"===a?()=>!t.isEmpty(s(r)):"remaining"===a?()=>t.length(s(r)):"box"===a?()=>({value:B(n(),r),inspect:e(r)}):"is"===a?e=>s(r).some(t=>0!==(t.operation&e)):"draft"===a?()=>t.head(s(r))?.value??B(n(),r):"settled"===a?()=>new Promise(e=>{if(t.isEmpty(s(r)))return e(B(n(),r));const o=()=>{t.isEmpty(s(r))&&(i(o),e(B(n(),r)))};c(o)}):e([...r,String(a)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#c(z.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#c(z.Produce,e)}#c(e,t){const n=/* @__PURE__ */Symbol("process"),[,r]=$.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>$.immer.applyPatches(t,[{...r,value:G(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=F(this.#e),this.#i(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#i()}#i(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const q=new V;function J(e,t){return q.annotate(e,t)}function K(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Q,X={exports:{}};const Y=/* @__PURE__ */K((Q||(Q=1,function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function c(e,t,r,c,i){if("function"!=typeof r)throw new TypeError("The listener must be a function");var s=new o(r,c||e,i),a=n?n+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],s]:e._events[a].push(s):(e._events[a]=s,e._eventsCount++),e}function i(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function s(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=/* @__PURE__ */Object.create(null),(new r).__proto__||(n=!1)),s.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},s.prototype.listeners=function(e){var t=this._events[n?n+e:e];if(!t)return[];if(t.fn)return[t.fn];for(var r=0,o=t.length,c=new Array(o);r<o;r++)c[r]=t[r].fn;return c},s.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},s.prototype.emit=function(e,t,r,o,c,i){var s=n?n+e:e;if(!this._events[s])return!1;var a,u,l=this._events[s],f=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),f){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,r),!0;case 4:return l.fn.call(l.context,t,r,o),!0;case 5:return l.fn.call(l.context,t,r,o,c),!0;case 6:return l.fn.call(l.context,t,r,o,c,i),!0}for(u=1,a=new Array(f-1);u<f;u++)a[u-1]=arguments[u];l.fn.apply(l.context,a)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!a)for(d=1,a=new Array(f-1);d<f;d++)a[d-1]=arguments[d];l[u].fn.apply(l[u].context,a)}}return!0},s.prototype.on=function(e,t,n){return c(this,e,t,n,!1)},s.prototype.once=function(e,t,n){return c(this,e,t,n,!0)},s.prototype.removeListener=function(e,t,r,o){var c=n?n+e:e;if(!this._events[c])return this;if(!t)return i(this,c),this;var s=this._events[c];if(s.fn)s.fn!==t||o&&!s.once||r&&s.context!==r||i(this,c);else{for(var a=0,u=[],l=s.length;a<l;a++)(s[a].fn!==t||o&&!s[a].once||r&&s[a].context!==r)&&u.push(s[a]);u.length?this._events[c]=1===u.length?u[0]:u:i(this,c)}return this},s.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&i(this,t):(this._events=new r,this._eventsCount=0),this},s.prototype.off=s.prototype.removeListener,s.prototype.addListener=s.prototype.on,s.prefixed=n,s.EventEmitter=s,e.exports=s}(X)),X.exports));class Z extends Y{cache=/* @__PURE__ */new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}getCached(e){return this.cache.get(e)}}const ee=r.createContext(new Z);function te(){return r.useContext(ee)}function ne({children:e}){const t=r.useMemo(()=>new Z,[]);/* @__PURE__ */
|
|
3
|
+
return n(ee.Provider,{value:t,children:e})}const re=r.createContext(/* @__PURE__ */new Map);function oe({children:e}){const t=r.useMemo(()=>/* @__PURE__ */new Map,[]);/* @__PURE__ */
|
|
4
|
+
return n(re.Provider,{value:t,children:e})}const ce=r.createContext(/* @__PURE__ */new Set);function ie({children:e}){const t=r.useMemo(()=>/* @__PURE__ */new Set,[]);/* @__PURE__ */
|
|
5
|
+
return n(ce.Provider,{value:t,children:e})}function se({children:e}){/* @__PURE__ */
|
|
6
|
+
return n(ne,{children:/* @__PURE__ */n(oe,{children:/* @__PURE__ */n(ie,{children:e})})})}const ae=r.createContext(null);function ue(){return r.useContext(ae)}function le(e,t){return e?.get(t)??null}function fe({name:e,children:t}){const o=ue(),c=r.useMemo(()=>({name:e,emitter:new Z}),[]),i=r.useMemo(()=>{const t=new Map(o??[]);return t.set(e,c),t},[o,e,c]);/* @__PURE__ */
|
|
7
|
+
return n(ae.Provider,{value:i,children:t})}function de(e,t){const r=`Scoped${t.displayName||t.name||"Component"}`;return{[r]:r=>/* @__PURE__ */n(fe,{name:e,children:/* @__PURE__ */n(t,{...r})})}[r]}function pe(e){return(t,n)=>{t.actions.produce(t=>{t.model[e]=n})}}function he(){const[,e]=r.useReducer(e=>e+1,0);return e}const me=r.createContext(/* @__PURE__ */new Map);function ye({action:t,renderer:n}){const o=te(),c=r.useContext(me),i=he(),s=r.useMemo(()=>{const e=c.get(t);if(e)return e;const n={state:new V,listeners:/* @__PURE__ */new Set};return c.set(t,n),n},[t,c]);r.useLayoutEffect(()=>{function e(e){s.state.hydrate({value:e}),s.listeners.forEach(e=>e())}return s.listeners.add(i),o.on(t,e),()=>{s.listeners.delete(i),o.off(t,e)}},[t,o,s]);const a=s.state.model?.value;return e.isNullable(a)?null:n(a,s.state.inspect.value)}function be(...n){const o=e.isUndefined(n[0])||e.isFunction(n[0])?{}:n[0],i=e.isFunction(n[0])?n[0]:n[1]??(()=>({})),s=te(),a=ue(),f=c(_),p=r.useContext(ce),h=r.useContext(re),m=he(),y=r.useRef(!1),b=r.useRef(null),v=r.useRef(new V);y.current||(y.current=!0,b.current=v.current.hydrate(o));const[g,w]=r.useState(()=>v.current.model),j=function(e){const t=r.useRef(e);return r.useLayoutEffect(()=>{t.current=e},[e]),r.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(i()),A=r.useMemo(()=>new Y,[]),R=r.useRef({handlers:/* @__PURE__ */new Map});R.current.handlers=/* @__PURE__ */new Map;const N=function(){const e=r.useRef(/* @__PURE__ */new Set),t=r.useRef(/* @__PURE__ */new Set);return r.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),U=r.useRef(d.Mounting),z=function(){const e=r.useRef({}),t=r.useRef(/* @__PURE__ */new Map),n=r.useRef(/* @__PURE__ */new Map);return r.useMemo(()=>({refs:e,pending:t,emitted:n}),[])}(),L=r.useRef(/* @__PURE__ */new Set),T=r.useRef(0),$=r.useCallback((e,t,n)=>{const r=new AbortController,o={controller:r,action:e,payload:t};return p.add(o),L.current.add(o),{model:v.current.model,get phase(){return U.current},task:o,data:j,tasks:p,nodes:z.refs.current,actions:{produce(e){if(r.signal.aborted)return;const t=v.current.produce(t=>e({model:t,inspect:v.current.inspect}));w(v.current.model),n.processes.add(t),b.current&&(n.processes.add(b.current),b.current=null)},dispatch(e,t,n){if(r.signal.aborted)return;const o=x(e),c=E(e)?e.channel:void 0;if(O(e)&&n?.scope){const e=le(a,n.scope);return void(e&&e.emitter.emit(o,t,c))}(S(e)?s:A).emit(o,t,c)},annotate:(e,t)=>v.current.annotate(e,t),async cacheable(e,t,n){if(r.signal.aborted)return{data:null};const o=C(e),c=h.get(o);if(c&&Date.now()<c.expiry)return{data:c.value};const i=function(e){return null!=e&&"object"==typeof e&&"TAG"in e?0===e.TAG?{ok:!0,value:e._0}:{ok:!1}:null==e?{ok:!1}:{ok:!0,value:e}}(await n());return i.ok?(h.set(o,{value:i.value,expiry:Date.now()+t}),{data:i.value}):{data:null}},invalidate(e){h.delete(C(e))},async read(e,t){if(r.signal.aborted)return null;const n=x(e),o=O(e)&&t?.scope?le(a,t.scope)?.emitter??null:s;if(!o)return null;if(void 0===o.getCached(n))return null;const c=P(e),i="unknown"!==c?c[0].toLowerCase()+c.slice(1):null;if(i){const e=v.current.inspect[i];e?.pending?.()&&await new Promise((t,n)=>{if(r.signal.aborted)return void n(r.signal.reason);const o=()=>n(r.signal.reason);r.signal.addEventListener("abort",o,{once:!0}),e.settled().then(()=>{r.signal.removeEventListener("abort",o),t()})})}return o.getCached(n)??null},peek(e,t){if(r.signal.aborted)return null;const n=x(e),o=O(e)&&t?.scope?le(a,t.scope)?.emitter??null:s;return o?o.getCached(n)??null:null}}}},[g]);r.useLayoutEffect(()=>{function t(t,n,r){return async function(o,c){const i=r();if(e.isNotNullable(c)&&e.isNotNullable(i)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,i))return;const s={processes:/* @__PURE__ */new Set},a=Promise.withResolvers(),u=$(t,o,s);try{await n(u,o)}catch(d){const e=R.current.handlers.has(l.Error),n={reason:M(d),error:k(d),action:P(t),handled:e,tasks:p};f?.(n),e&&A.emit(l.Error,n)}finally{for(const e of p)if(e===u.task){p.delete(e),L.current.delete(e);break}s.processes.forEach(e=>v.current.prune(e)),s.processes.size>0&&m(),a.resolve()}}}T.current++;const n=/* @__PURE__ */new Set;return R.current.handlers.forEach((e,r)=>{for(const{getChannel:o,handler:c}of e){const e=t(r,c,o);if(O(r)){if(a)for(const t of a.values()){const o=t.emitter;o.on(r,e),n.add(()=>o.off(r,e))}A.on(r,e),N.multicast.add(r),n.add(()=>A.off(r,e))}else S(r)?(s.on(r,e),A.on(r,e),N.broadcast.add(r),n.add(()=>{s.off(r,e),A.off(r,e)})):(A.on(r,e),n.add(()=>A.off(r,e)))}}),()=>{const e=++T.current,t=new Set(n);queueMicrotask(()=>{if(T.current===e){for(const e of L.current)e.controller.abort(),p.delete(e);L.current.clear(),U.current=d.Unmounting,A.emit(l.Unmount),U.current=d.Unmounted;for(const e of t)e()}else for(const e of t)e()})}},[A]),r.useLayoutEffect(()=>{for(const[e,t]of z.pending.current)z.emitted.current.get(e)!==t&&(z.emitted.current.set(e,t),A.emit(u.Node,t,{Name:e}));z.pending.current.clear()}),function({unicast:n,broadcast:o,dispatchers:c,scope:i,phase:s,data:a}){const u=r.useRef(null);r.useLayoutEffect(()=>{s.current===d.Mounting&&(n.emit(l.Mount),c.broadcast.forEach(t=>{const r=o.getCached(t);e.isNullable(r)||n.emit(t,r)}),i&&c.multicast.forEach(t=>{for(const r of i.values()){const o=r.emitter.getCached(t);e.isNullable(o)||n.emit(t,o)}}),s.current=d.Mounted)},[]),r.useLayoutEffect(()=>{if(e.isNotNullable(u.current)){const e=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,a);t.isNotEmpty(Object.keys(e))&&n.emit(l.Update,e)}u.current=a},[a,n])}({unicast:A,broadcast:s,dispatchers:N,scope:a,phase:U,data:i()});const B=r.useMemo(()=>[g,{dispatch(e,t,n){const r=x(e),o=E(e)?e.channel:void 0;if(O(e)&&n?.scope){const e=le(a,n.scope);return void(e&&e.emitter.emit(r,t,o))}(S(e)?s:A).emit(r,t,o)},get inspect(){return v.current.inspect},get nodes(){return z.refs.current},node(e,t){z.refs.current[e]=t,z.pending.current.set(e,t)},stream:(e,t)=>r.createElement(ye,{action:x(e),renderer:t})}],[g,A]);return B.useAction=(e,t)=>{!function(e,t,n){const o=r.useRef(n);r.useLayoutEffect(()=>{o.current=n});const c=r.useRef(t);r.useLayoutEffect(()=>{c.current=t});const i=r.useCallback(async(e,t)=>{const n=o.current;if("GeneratorFunction"===n.constructor.name||"AsyncGeneratorFunction"===n.constructor.name){const r=n(e,t);for await(const e of r);}else await n(e,t)},[]),s=r.useCallback(()=>E(c.current)?c.current.channel:void 0,[]),a=x(t),u=e.current.handlers.get(a)??/* @__PURE__ */new Set;0===u.size&&e.current.handlers.set(a,u),u.add({getChannel:s,handler:i})}(R,e,t)},B}export{j as Action,se as Boundary,f as Distribution,A as Entry,R as Error,l as Lifecycle,U as Op,U as Operation,p as Reason,fe as Scope,V as State,pe as With,J as annotate,be as useActions,g as utils,de as withScope};
|
package/dist/chizu.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var global,factory;global=this,factory=function(e,t,n,r,o){"use strict";function c(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const n in e)if("default"!==n){const r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:()=>e[n]})}return t.default=e,Object.freeze(t)}const i=c(r);class s{static Payload=Symbol("chizu.brand/Payload");static Broadcast=Symbol("chizu.brand/Broadcast");static Multicast=Symbol("chizu.brand/Multicast");static Action=Symbol("chizu.brand/Action");static Channel=Symbol("chizu.brand/Channel");static Node=Symbol("chizu.action.lifecycle/Node");static Cache=Symbol("chizu.brand/Cache")}class a{static Mount=Symbol("chizu.action.lifecycle/Mount");static Unmount=Symbol("chizu.action.lifecycle/Unmount");static Error=Symbol("chizu.action.lifecycle/Error");static Update=Symbol("chizu.action.lifecycle/Update");static Node=(()=>{const e=s.Node,t=function(t){return{[s.Action]:e,[s.Payload]:void 0,[s.Channel]:t,channel:t}};return Object.defineProperty(t,s.Action,{value:e,enumerable:!1}),Object.defineProperty(t,s.Payload,{value:void 0,enumerable:!1}),t})()}var u=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(u||{}),l=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(l||{}),f=(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Disallowed=2]="Disallowed",e[e.Errored=3]="Errored",e[e.Unmounted=4]="Unmounted",e))(f||{});class d extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const p={actionPrefix:"chizu.action/",broadcastActionPrefix:"chizu.action/broadcast/",multicastActionPrefix:"chizu.action/multicast/",channelPrefix:"chizu.channel/",cachePrefix:"chizu.cache/"};function h(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new d);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new d)},{once:!0})})}function m(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const y=Object.freeze(Object.defineProperty({__proto__:null,config:p,pk:m,sleep:h,"ζ":h,"κ":m},Symbol.toStringTag,{value:"Module"})),b=e=>"symbol"==typeof e;function v(e){return t.G.isString(e)||b(e)?e:(t.G.isObject(e)||t.G.isFunction(e))&&s.Action in e?e[s.Action]:e}function g(e){if(t.G.isString(e))return e.startsWith(p.broadcastActionPrefix);if(b(e))return e.description?.startsWith(p.broadcastActionPrefix)??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(s.Broadcast in e&&e[s.Broadcast])return!0;if(s.Action in e){const t=e[s.Action];return t.description?.startsWith(p.broadcastActionPrefix)??!1}}return!1}function w(e){const n=v(e),r=t.G.isString(n)?n:n.description??"";return r.startsWith(p.actionPrefix)&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function x(e){return t.G.isObject(e)&&s.Channel in e&&"channel"in e}function j(e){if(t.G.isString(e))return e.startsWith(p.multicastActionPrefix);if(b(e))return e.description?.startsWith(p.multicastActionPrefix)??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(s.Multicast in e&&e[s.Multicast])return!0;if(s.Action in e){const t=e[s.Action];return t.description?.startsWith(p.multicastActionPrefix)??!1}}return!1}function S(e){const t=function(e){return e[s.Cache]}(e),n=function(e){return"channel"in e}(e)&&(r=e.channel)?[...Object.keys(r)].toSorted().map(e=>`${e}=${String(r[e])}`).join("&"):"";var r;return`${String(t)}:${n}`}function P(e){if(e instanceof Error){if("TimeoutError"===e.name)return f.Timedout;if("AbortError"===e.name)return f.Supplanted}return f.Errored}function A(e){return e instanceof Error?e:new Error(String(e))}const O=r.createContext(void 0);let E=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var M=(e=>(e[e.Add=1]="Add",e[e.Remove=2]="Remove",e[e.Update=4]="Update",e[e.Move=8]="Move",e[e.Replace=16]="Replace",e[e.Sort=32]="Sort",e[e.Create=64]="Create",e[e.Fetch=128]="Fetch",e[e.Clone=256]="Clone",e[e.Archive=512]="Archive",e[e.Restore=1024]="Restore",e[e.Merge=2048]="Merge",e[e.Reorder=4096]="Reorder",e[e.Sync=8192]="Sync",e[e.Publish=16384]="Publish",e[e.Link=32768]="Link",e[e.Unlink=65536]="Unlink",e[e.Lock=131072]="Lock",e[e.Unlock=262144]="Unlock",e[e.Import=524288]="Import",e[e.Export=1048576]="Export",e[e.Transfer=2097152]="Transfer",e))(M||{}),C=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(C||{}),G=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(G||{});class k{[o.immerable]=!0;static keys=new Set(Object.values(G));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new k(this.value,this.operation);return n.property=e,n.process=t,n}}class _{static immer=(()=>{o.enablePatches();const e=new o.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=E}function R(e,t){const n="string"==typeof t?""===t?[]:t.split("."):t;let r=e;for(const o of n){if(null==r)return;r=r[o]}return r}function N(e){if(t.G.isNullable(e)||L(e))return e;if(t.G.isArray(e))return e.map(e=>N(e));if(t.G.isObject(e)&&U(e)){const t=Object.entries(e).map(([e,t])=>[e,N(t)]);return{...Object.fromEntries(t),[_.tag]:e[_.tag]??_.id()}}return e}function z(e){if(Array.isArray(e))return e.filter(e=>_.tag in e).map(e=>e[_.tag]??"").join(",");const t=e[_.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function U(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function L(e){return t.G.isNullable(e)||t.G.isString(e)||t.G.isNumber(e)||t.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function T(e,n,r,o,c,i){return function s(a,u=n.path){if(a instanceof k){const n=R(r,u.join("."));if(Object.entries(a).filter(([e,t])=>!k.keys.has(e)&&t instanceof k).forEach(([e,t])=>s(t,u.concat(e))),L(a.value)){if(e===C.Hydrate)return a.value;const s=u.slice(0,-1),l=s.length>0?R(r,s.join(".")):r;return t.G.isNullable(l)||$(l,a,u.at(-1),o,c,i),n??a.value}if(e===C.Hydrate){const e=N(s(a.value,u));return $(e,a,null,o,c,i),e}const l=n??N(a.value);return $(l,a,null,o,c,i),t.G.isNullable(n)?l:(s(a.value,u),n)}if(t.G.isArray(a))return a.map((e,t)=>s(e,u.concat(t)));if(t.G.isObject(a)&&!U(a))return a;if(t.G.isObject(a)){const t=Object.entries(a).map(([e,t])=>[e,s(t,u.concat(e))]),n=Object.fromEntries(t);if(e===C.Hydrate){const e=N(n);return Object.entries(a).forEach(([t,n])=>{n instanceof k&&L(n.value)&&$(e,n,t,o,c,i)}),e}return n}return a}(n.value)}function $(e,t,n,r,o,c){const i=c(e),s=o.get(i)??[];o.set(i,[t.assign(n,r),...s])}class B{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=z){this.#t=e}static pk(){return E()}static"κ"=B.pk;annotate(e,t){return new k(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,n,r,o,c){function i(o){const c=o.at(-1),i=R(e(),o),s=o.slice(0,-1),a=t.A.isNotEmpty(s)?R(e(),s):e();return[...t.G.isObject(i)||t.G.isArray(i)?n.get(r(i))?.filter(e=>t.G.isNullable(e.property))??[]:[],...t.G.isObject(a)?n.get(r(a))?.filter(e=>e.property===c)??[]:[]]}return function n(r){return new Proxy(()=>{},{get:(s,a)=>"pending"===a?()=>!t.A.isEmpty(i(r)):"remaining"===a?()=>t.A.length(i(r)):"box"===a?()=>({value:R(e(),r),inspect:n(r)}):"is"===a?e=>i(r).some(t=>0!==(t.operation&e)):"draft"===a?()=>t.A.head(i(r))?.value??R(e(),r):"settled"===a?()=>new Promise(n=>{if(t.A.isEmpty(i(r)))return n(R(e(),r));const s=()=>{t.A.isEmpty(i(r))&&(c(s),n(R(e(),r)))};o(s)}):n([...r,String(a)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#c(C.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#c(C.Produce,e)}#c(e,t){const n=Symbol("process"),[,r]=_.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>_.immer.applyPatches(t,[{...r,value:T(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=N(this.#e),this.#i(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.A.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#i()}#i(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const F=new B;function W(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var D,H={exports:{}},I=(D||(D=1,function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function c(e,t,r,c,i){if("function"!=typeof r)throw new TypeError("The listener must be a function");var s=new o(r,c||e,i),a=n?n+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],s]:e._events[a].push(s):(e._events[a]=s,e._eventsCount++),e}function i(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function s(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),s.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},s.prototype.listeners=function(e){var t=this._events[n?n+e:e];if(!t)return[];if(t.fn)return[t.fn];for(var r=0,o=t.length,c=new Array(o);r<o;r++)c[r]=t[r].fn;return c},s.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},s.prototype.emit=function(e,t,r,o,c,i){var s=n?n+e:e;if(!this._events[s])return!1;var a,u,l=this._events[s],f=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),f){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,r),!0;case 4:return l.fn.call(l.context,t,r,o),!0;case 5:return l.fn.call(l.context,t,r,o,c),!0;case 6:return l.fn.call(l.context,t,r,o,c,i),!0}for(u=1,a=new Array(f-1);u<f;u++)a[u-1]=arguments[u];l.fn.apply(l.context,a)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!a)for(d=1,a=new Array(f-1);d<f;d++)a[d-1]=arguments[d];l[u].fn.apply(l[u].context,a)}}return!0},s.prototype.on=function(e,t,n){return c(this,e,t,n,!1)},s.prototype.once=function(e,t,n){return c(this,e,t,n,!0)},s.prototype.removeListener=function(e,t,r,o){var c=n?n+e:e;if(!this._events[c])return this;if(!t)return i(this,c),this;var s=this._events[c];if(s.fn)s.fn!==t||o&&!s.once||r&&s.context!==r||i(this,c);else{for(var a=0,u=[],l=s.length;a<l;a++)(s[a].fn!==t||o&&!s[a].once||r&&s[a].context!==r)&&u.push(s[a]);u.length?this._events[c]=1===u.length?u[0]:u:i(this,c)}return this},s.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&i(this,t):(this._events=new r,this._eventsCount=0),this},s.prototype.off=s.prototype.removeListener,s.prototype.addListener=s.prototype.on,s.prefixed=n,s.EventEmitter=s,e.exports=s}(H)),H.exports);const q=W(I);class V extends q{cache=new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}getCached(e){return this.cache.get(e)}}const J=i.createContext(new V);function K(){return i.useContext(J)}function Q({children:e}){const t=i.useMemo(()=>new V,[]);return n.jsx(J.Provider,{value:t,children:e})}const X=i.createContext(new Map);function Y(){return i.useContext(X)}function Z(){const[,e]=i.useReducer(e=>e+1,0);return e}function ee({action:e,renderer:n}){const r=K(),o=Y(),c=Z(),s=i.useMemo(()=>{const t=o.get(e);if(t)return t;const n={state:new B,listeners:new Set};return o.set(e,n),n},[e,o]);i.useLayoutEffect(()=>{function t(e){s.state.hydrate({value:e}),s.listeners.forEach(e=>e())}return s.listeners.add(c),r.on(e,t),()=>{s.listeners.delete(c),r.off(e,t)}},[e,r,s]);const a=s.state.model?.value;return t.G.isNullable(a)?null:n({value:a,inspect:s.state.inspect.value})}function te({children:e}){const t=i.useMemo(()=>new Map,[]);return n.jsx(X.Provider,{value:t,children:e})}const ne=i.createContext(new Map);function re({children:e}){const t=i.useMemo(()=>new Map,[]);return n.jsx(ne.Provider,{value:t,children:e})}const oe=i.createContext(new Set);function ce({children:e}){const t=i.useMemo(()=>new Set,[]);return n.jsx(oe.Provider,{value:t,children:e})}const ie=i.createContext(null);function se(){return i.useContext(ie)}function ae(e,t){return e?.get(t)??null}function ue({action:e,scopeName:n,renderer:r}){const o=se(),c=Z(),s=i.useMemo(()=>ae(o,n),[o,n]),a=i.useMemo(()=>s?function(e,t){const n=e.store.get(t);if(n)return n;const r={state:new B,listeners:new Set};return e.store.set(t,r),r}(s,e):null,[e,s]);if(i.useLayoutEffect(()=>{if(s&&a)return a.listeners.add(c),s.emitter.on(e,t),()=>{a.listeners.delete(c),s.emitter.off(e,t)};function t(e){a&&(a.state.hydrate({value:e}),a.listeners.forEach(e=>e()))}},[e,s,a,c]),!a)return null;const u=a.state.model?.value;return t.G.isNullable(u)?null:r({value:u,inspect:a.state.inspect.value})}function le({name:e,children:t}){const r=se(),o=i.useMemo(()=>({name:e,emitter:new q,store:new Map,listeners:new Map}),[]),c=i.useMemo(()=>{const t=new Map(r??[]);return t.set(e,o),t},[r,e,o]);return n.jsx(ie.Provider,{value:c,children:t})}e.Action=(e,t=u.Unicast)=>{const n=t===u.Broadcast?Symbol(`${p.broadcastActionPrefix}${e}`):t===u.Multicast?Symbol(`${p.multicastActionPrefix}${e}`):Symbol(`${p.actionPrefix}${e}`),r=function(e){return{[s.Action]:n,[s.Payload]:void 0,[s.Channel]:e,channel:e}};return Object.defineProperty(r,s.Action,{value:n,enumerable:!1}),Object.defineProperty(r,s.Payload,{value:void 0,enumerable:!1}),t===u.Broadcast&&Object.defineProperty(r,s.Broadcast,{value:!0,enumerable:!1}),t===u.Multicast&&Object.defineProperty(r,s.Multicast,{value:!0,enumerable:!1}),r},e.Boundary=function({children:e}){return n.jsx(Q,{children:n.jsx(te,{children:n.jsx(re,{children:n.jsx(ce,{children:e})})})})},e.Distribution=u,e.Entry=function(){const e=Symbol("chizu.cache/Entry"),t=function(t){return{[s.Cache]:e,channel:t}};return Object.defineProperty(t,s.Cache,{value:e,enumerable:!1}),t},e.Error=function({handler:e,children:t}){return n.jsx(O.Provider,{value:e,children:t})},e.Lifecycle=a,e.Op=M,e.Operation=M,e.Reason=f,e.Scope=le,e.State=B,e.With=function(e){return(t,n)=>{t.actions.produce(t=>{t.model[e]=n})}},e.annotate=function(e,t){return F.annotate(e,t)},e.useActions=function(...e){const n=t.G.isUndefined(e[0])||t.G.isFunction(e[0])?{}:e[0],o=t.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),c=K(),u=se(),f=Y(),p=r.useContext(O),h=i.useContext(oe),m=i.useContext(ne),y=Z(),b=i.useRef(!1),E=i.useRef(null),M=i.useRef(new B);b.current||(b.current=!0,E.current=M.current.hydrate(n));const[C,G]=i.useState(()=>M.current.model),k=function(e){const t=i.useRef(e);return i.useLayoutEffect(()=>{t.current=e},[e]),i.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(o()),_=i.useMemo(()=>new q,[]),R=i.useRef({handlers:new Map});R.current.handlers=new Map;const N=function(){const e=i.useRef(new Set),t=i.useRef(new Set);return i.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),z=i.useRef(l.Mounting),U=function(){const e=i.useRef({}),t=i.useRef(new Map),n=i.useRef(new Map);return i.useMemo(()=>({refs:e,pending:t,emitted:n}),[])}(),L=i.useRef(new Set),T=i.useRef(0),$=i.useCallback((e,t,n)=>{const r=new AbortController,o={controller:r,action:e,payload:t};return h.add(o),L.current.add(o),{model:M.current.model,get phase(){return z.current},task:o,data:k,tasks:h,nodes:U.refs.current,actions:{produce(e){if(r.signal.aborted)return;const t=M.current.produce(t=>e({model:t,inspect:M.current.inspect}));G(M.current.model),n.processes.add(t),E.current&&(n.processes.add(E.current),E.current=null)},dispatch(e,t,n){if(r.signal.aborted)return;const o=v(e),i=x(e)?e.channel:void 0;if(j(e)&&n?.scope){const e=ae(u,n.scope);return void(e&&e.emitter.emit(o,t,i))}(g(e)?c:_).emit(o,t,i)},annotate:(e,t)=>M.current.annotate(e,t),async cacheable(e,t,n){if(r.signal.aborted)return{data:null};const o=S(e),c=m.get(o);if(c&&Date.now()<c.expiry)return{data:c.value};const i=function(e){return null!=e&&"object"==typeof e&&"TAG"in e?0===e.TAG?{ok:!0,value:e._0}:{ok:!1}:null==e?{ok:!1}:{ok:!0,value:e}}(await n());return i.ok?(m.set(o,{value:i.value,expiry:Date.now()+t}),{data:i.value}):{data:null}},invalidate(e){m.delete(S(e))},async consume(e,t){if(r.signal.aborted)return null;const n=v(e);let o;if(j(e)&&t?.scope){const e=ae(u,t.scope);if(!e)return null;o=e.store.get(n)}else o=f.get(n);if(!o?.state.model?.value)return null;const c=o.state.inspect;return c.value.pending()&&await new Promise((e,t)=>{if(r.signal.aborted)return void t(new d);const n=()=>t(new d);r.signal.addEventListener("abort",n,{once:!0}),c.value.settled().then(()=>{r.signal.removeEventListener("abort",n),e()})}),o.state.model.value}}}},[C]);i.useLayoutEffect(()=>{function e(e,n,r){return async function(o,c){const i=r();if(t.G.isNotNullable(c)&&t.G.isNotNullable(i)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,i))return;const s={processes:new Set},u=Promise.withResolvers(),l=$(e,o,s);try{await n(l,o)}catch(f){const t=R.current.handlers.has(a.Error),n={reason:P(f),error:A(f),action:w(e),handled:t,tasks:h};p?.(n),t&&_.emit(a.Error,n)}finally{for(const e of h)if(e===l.task){h.delete(e),L.current.delete(e);break}s.processes.forEach(e=>M.current.prune(e)),s.processes.size>0&&y(),u.resolve()}}}T.current++;const n=new Set;return R.current.handlers.forEach((t,r)=>{for(const{getChannel:o,handler:i}of t){const t=e(r,i,o);if(j(r)){if(u)for(const e of u.values()){const o=e.emitter;o.on(r,t),n.add(()=>o.off(r,t))}_.on(r,t),N.multicast.add(r),n.add(()=>_.off(r,t))}else g(r)?(c.on(r,t),_.on(r,t),N.broadcast.add(r),n.add(()=>{c.off(r,t),_.off(r,t)})):(_.on(r,t),n.add(()=>_.off(r,t)))}}),()=>{const e=++T.current,t=new Set(n);queueMicrotask(()=>{if(T.current===e){for(const e of L.current)e.controller.abort(),h.delete(e);L.current.clear(),z.current=l.Unmounting,_.emit(a.Unmount),z.current=l.Unmounted;for(const e of t)e()}else for(const e of t)e()})}},[_]),i.useLayoutEffect(()=>{for(const[e,t]of U.pending.current)U.emitted.current.get(e)!==t&&(U.emitted.current.set(e,t),_.emit(s.Node,t,{Name:e}));U.pending.current.clear()}),function({unicast:e,broadcast:n,broadcastActions:r,phase:o,data:c}){const s=Y(),u=i.useRef(null);i.useLayoutEffect(()=>{o.current===l.Mounting&&(e.emit(a.Mount),r.forEach(r=>{const o=s.get(r),c=o?.state.model?.value;if(!t.G.isNullable(c))return void e.emit(r,c);const i=n.getCached(r);t.G.isNullable(i)||e.emit(r,i)}),o.current=l.Mounted)},[]),i.useLayoutEffect(()=>{if(t.G.isNotNullable(u.current)){const n=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,c);t.A.isNotEmpty(Object.keys(n))&&e.emit(a.Update,n)}u.current=c},[c,e])}({unicast:_,broadcast:c,broadcastActions:N.broadcast,phase:z,data:o()});const F=i.useMemo(()=>[C,{dispatch(e,t,n){const r=v(e),o=x(e)?e.channel:void 0;if(j(e)&&n?.scope){const e=ae(u,n.scope);return void(e&&e.emitter.emit(r,t,o))}(g(e)?c:_).emit(r,t,o)},consume:(e,t,n)=>j(e)&&n?.scope?i.createElement(ue,{action:v(e),scopeName:n.scope,renderer:t}):i.createElement(ee,{action:v(e),renderer:t}),get inspect(){return M.current.inspect},get nodes(){return U.refs.current},node(e,t){U.refs.current[e]=t,U.pending.current.set(e,t)}}],[C,_]);return F.useAction=(e,t)=>{!function(e,t,n){const r=i.useRef(n);i.useLayoutEffect(()=>{r.current=n});const o=i.useRef(t);i.useLayoutEffect(()=>{o.current=t});const c=i.useCallback(async(e,t)=>{const n=r.current;if("GeneratorFunction"===n.constructor.name||"AsyncGeneratorFunction"===n.constructor.name){const r=n(e,t);for await(const e of r);}else await n(e,t)},[]),s=i.useCallback(()=>x(o.current)?o.current.channel:void 0,[]),a=v(t),u=e.current.handlers.get(a)??new Set;0===u.size&&e.current.handlers.set(a,u),u.add({getChannel:s,handler:c})}(R,e,t)},F},e.utils=y,e.withScope=function(e,t){const r=`Scoped${t.displayName||t.name||"Component"}`;return{[r]:r=>n.jsx(le,{name:e,children:n.jsx(t,{...r})})}[r]},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("@mobily/ts-belt"),require("react/jsx-runtime"),require("react"),require("immer")):"function"==typeof define&&define.amd?define(["exports","@mobily/ts-belt","react/jsx-runtime","react","immer"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).Chizu={},global.TsBelt,global.jsxRuntime,global.React,global.Immer);
|
|
1
|
+
var global,factory;global=this,factory=function(e,t,n,r,o){"use strict";function c(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const n in e)if("default"!==n){const r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:()=>e[n]})}return t.default=e,Object.freeze(t)}const i=c(r);class s{static Payload=Symbol("chizu.brand/Payload");static Broadcast=Symbol("chizu.brand/Broadcast");static Multicast=Symbol("chizu.brand/Multicast");static Action=Symbol("chizu.brand/Action");static Channel=Symbol("chizu.brand/Channel");static Node=Symbol("chizu.action.lifecycle/Node");static Cache=Symbol("chizu.brand/Cache")}class a{static Mount=Symbol("chizu.action.lifecycle/Mount");static Unmount=Symbol("chizu.action.lifecycle/Unmount");static Error=Symbol("chizu.action.lifecycle/Error");static Update=Symbol("chizu.action.lifecycle/Update");static Node=(()=>{const e=s.Node,t=function(t){return{[s.Action]:e,[s.Payload]:void 0,[s.Channel]:t,channel:t}};return Object.defineProperty(t,s.Action,{value:e,enumerable:!1}),Object.defineProperty(t,s.Payload,{value:void 0,enumerable:!1}),t})()}var u=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(u||{}),l=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(l||{}),f=(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Disallowed=2]="Disallowed",e[e.Errored=3]="Errored",e[e.Unmounted=4]="Unmounted",e))(f||{});class d extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const p={actionPrefix:"chizu.action/",broadcastActionPrefix:"chizu.action/broadcast/",multicastActionPrefix:"chizu.action/multicast/",channelPrefix:"chizu.channel/",cachePrefix:"chizu.cache/"};function h(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new d);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new d)},{once:!0})})}async function m(e,t,n){if(t?.aborted)throw new d;for(;;){if(await n())return;await h(e,t)}}function y(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const b=Object.freeze(Object.defineProperty({__proto__:null,config:p,pk:y,poll:m,sleep:h,"ζ":h,"κ":y,"π":m},Symbol.toStringTag,{value:"Module"})),v=e=>"symbol"==typeof e;function g(e){return t.G.isString(e)||v(e)?e:(t.G.isObject(e)||t.G.isFunction(e))&&s.Action in e?e[s.Action]:e}function w(e){if(t.G.isString(e))return e.startsWith(p.broadcastActionPrefix);if(v(e))return e.description?.startsWith(p.broadcastActionPrefix)??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(s.Broadcast in e&&e[s.Broadcast])return!0;if(s.Action in e){const t=e[s.Action];return t.description?.startsWith(p.broadcastActionPrefix)??!1}}return!1}function x(e){const n=g(e),r=t.G.isString(n)?n:n.description??"";return r.startsWith(p.actionPrefix)&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function j(e){return t.G.isObject(e)&&s.Channel in e&&"channel"in e}function S(e){if(t.G.isString(e))return e.startsWith(p.multicastActionPrefix);if(v(e))return e.description?.startsWith(p.multicastActionPrefix)??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(s.Multicast in e&&e[s.Multicast])return!0;if(s.Action in e){const t=e[s.Action];return t.description?.startsWith(p.multicastActionPrefix)??!1}}return!1}function P(e){const t=function(e){return e[s.Cache]}(e),n=function(e){return"channel"in e}(e)&&(r=e.channel)?[...Object.keys(r)].toSorted().map(e=>`${e}=${String(r[e])}`).join("&"):"";var r;return`${String(t)}:${n}`}function A(e){if(e instanceof Error){if("TimeoutError"===e.name)return f.Timedout;if("AbortError"===e.name)return f.Supplanted}return f.Errored}function O(e){return e instanceof Error?e:new Error(String(e))}const E=r.createContext(void 0);let C=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var M=(e=>(e[e.Add=1]="Add",e[e.Remove=2]="Remove",e[e.Update=4]="Update",e[e.Move=8]="Move",e[e.Replace=16]="Replace",e[e.Sort=32]="Sort",e[e.Create=64]="Create",e[e.Fetch=128]="Fetch",e[e.Clone=256]="Clone",e[e.Archive=512]="Archive",e[e.Restore=1024]="Restore",e[e.Merge=2048]="Merge",e[e.Reorder=4096]="Reorder",e[e.Sync=8192]="Sync",e[e.Publish=16384]="Publish",e[e.Link=32768]="Link",e[e.Unlink=65536]="Unlink",e[e.Lock=131072]="Lock",e[e.Unlock=262144]="Unlock",e[e.Import=524288]="Import",e[e.Export=1048576]="Export",e[e.Transfer=2097152]="Transfer",e))(M||{}),k=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(k||{}),G=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(G||{});class _{[o.immerable]=!0;static keys=new Set(Object.values(G));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new _(this.value,this.operation);return n.property=e,n.process=t,n}}class R{static immer=(()=>{o.enablePatches();const e=new o.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=C}function N(e,t){const n="string"==typeof t?""===t?[]:t.split("."):t;let r=e;for(const o of n){if(null==r)return;r=r[o]}return r}function z(e){if(t.G.isNullable(e)||T(e))return e;if(t.G.isArray(e))return e.map(e=>z(e));if(t.G.isObject(e)&&L(e)){const t=Object.entries(e).map(([e,t])=>[e,z(t)]);return{...Object.fromEntries(t),[R.tag]:e[R.tag]??R.id()}}return e}function U(e){if(Array.isArray(e))return e.filter(e=>R.tag in e).map(e=>e[R.tag]??"").join(",");const t=e[R.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function L(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function T(e){return t.G.isNullable(e)||t.G.isString(e)||t.G.isNumber(e)||t.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function $(e,n,r,o,c,i){return function s(a,u=n.path){if(a instanceof _){const n=N(r,u.join("."));if(Object.entries(a).filter(([e,t])=>!_.keys.has(e)&&t instanceof _).forEach(([e,t])=>s(t,u.concat(e))),T(a.value)){if(e===k.Hydrate)return a.value;const s=u.slice(0,-1),l=s.length>0?N(r,s.join(".")):r;return t.G.isNullable(l)||B(l,a,u.at(-1),o,c,i),n??a.value}if(e===k.Hydrate){const e=z(s(a.value,u));return B(e,a,null,o,c,i),e}const l=n??z(a.value);return B(l,a,null,o,c,i),t.G.isNullable(n)?l:(s(a.value,u),n)}if(t.G.isArray(a))return a.map((e,t)=>s(e,u.concat(t)));if(t.G.isObject(a)&&!L(a))return a;if(t.G.isObject(a)){const t=Object.entries(a).map(([e,t])=>[e,s(t,u.concat(e))]),n=Object.fromEntries(t);if(e===k.Hydrate){const e=z(n);return Object.entries(a).forEach(([t,n])=>{n instanceof _&&T(n.value)&&B(e,n,t,o,c,i)}),e}return n}return a}(n.value)}function B(e,t,n,r,o,c){const i=c(e),s=o.get(i)??[];o.set(i,[t.assign(n,r),...s])}class F{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=U){this.#t=e}static pk(){return C()}static"κ"=F.pk;annotate(e,t){return new _(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,n,r,o,c){function i(o){const c=o.at(-1),i=N(e(),o),s=o.slice(0,-1),a=t.A.isNotEmpty(s)?N(e(),s):e();return[...t.G.isObject(i)||t.G.isArray(i)?n.get(r(i))?.filter(e=>t.G.isNullable(e.property))??[]:[],...t.G.isObject(a)?n.get(r(a))?.filter(e=>e.property===c)??[]:[]]}return function n(r){return new Proxy(()=>{},{get:(s,a)=>"pending"===a?()=>!t.A.isEmpty(i(r)):"remaining"===a?()=>t.A.length(i(r)):"box"===a?()=>({value:N(e(),r),inspect:n(r)}):"is"===a?e=>i(r).some(t=>0!==(t.operation&e)):"draft"===a?()=>t.A.head(i(r))?.value??N(e(),r):"settled"===a?()=>new Promise(n=>{if(t.A.isEmpty(i(r)))return n(N(e(),r));const s=()=>{t.A.isEmpty(i(r))&&(c(s),n(N(e(),r)))};o(s)}):n([...r,String(a)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#c(k.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#c(k.Produce,e)}#c(e,t){const n=Symbol("process"),[,r]=R.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>R.immer.applyPatches(t,[{...r,value:$(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=z(this.#e),this.#i(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.A.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#i()}#i(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const W=new F;function D(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H,I={exports:{}},q=(H||(H=1,function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function c(e,t,r,c,i){if("function"!=typeof r)throw new TypeError("The listener must be a function");var s=new o(r,c||e,i),a=n?n+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],s]:e._events[a].push(s):(e._events[a]=s,e._eventsCount++),e}function i(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function s(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),s.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},s.prototype.listeners=function(e){var t=this._events[n?n+e:e];if(!t)return[];if(t.fn)return[t.fn];for(var r=0,o=t.length,c=new Array(o);r<o;r++)c[r]=t[r].fn;return c},s.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},s.prototype.emit=function(e,t,r,o,c,i){var s=n?n+e:e;if(!this._events[s])return!1;var a,u,l=this._events[s],f=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),f){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,r),!0;case 4:return l.fn.call(l.context,t,r,o),!0;case 5:return l.fn.call(l.context,t,r,o,c),!0;case 6:return l.fn.call(l.context,t,r,o,c,i),!0}for(u=1,a=new Array(f-1);u<f;u++)a[u-1]=arguments[u];l.fn.apply(l.context,a)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!a)for(d=1,a=new Array(f-1);d<f;d++)a[d-1]=arguments[d];l[u].fn.apply(l[u].context,a)}}return!0},s.prototype.on=function(e,t,n){return c(this,e,t,n,!1)},s.prototype.once=function(e,t,n){return c(this,e,t,n,!0)},s.prototype.removeListener=function(e,t,r,o){var c=n?n+e:e;if(!this._events[c])return this;if(!t)return i(this,c),this;var s=this._events[c];if(s.fn)s.fn!==t||o&&!s.once||r&&s.context!==r||i(this,c);else{for(var a=0,u=[],l=s.length;a<l;a++)(s[a].fn!==t||o&&!s[a].once||r&&s[a].context!==r)&&u.push(s[a]);u.length?this._events[c]=1===u.length?u[0]:u:i(this,c)}return this},s.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&i(this,t):(this._events=new r,this._eventsCount=0),this},s.prototype.off=s.prototype.removeListener,s.prototype.addListener=s.prototype.on,s.prefixed=n,s.EventEmitter=s,e.exports=s}(I)),I.exports);const V=D(q);class J extends V{cache=new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}getCached(e){return this.cache.get(e)}}const K=i.createContext(new J);function Q(){return i.useContext(K)}function X({children:e}){const t=i.useMemo(()=>new J,[]);return n.jsx(K.Provider,{value:t,children:e})}const Y=i.createContext(new Map);function Z({children:e}){const t=i.useMemo(()=>new Map,[]);return n.jsx(Y.Provider,{value:t,children:e})}const ee=i.createContext(new Set);function te({children:e}){const t=i.useMemo(()=>new Set,[]);return n.jsx(ee.Provider,{value:t,children:e})}const ne=i.createContext(null);function re(){return i.useContext(ne)}function oe(e,t){return e?.get(t)??null}function ce({name:e,children:t}){const r=re(),o=i.useMemo(()=>({name:e,emitter:new J}),[]),c=i.useMemo(()=>{const t=new Map(r??[]);return t.set(e,o),t},[r,e,o]);return n.jsx(ne.Provider,{value:c,children:t})}function ie(){const[,e]=i.useReducer(e=>e+1,0);return e}const se=i.createContext(new Map);function ae({action:e,renderer:n}){const r=Q(),o=i.useContext(se),c=ie(),s=i.useMemo(()=>{const t=o.get(e);if(t)return t;const n={state:new F,listeners:new Set};return o.set(e,n),n},[e,o]);i.useLayoutEffect(()=>{function t(e){s.state.hydrate({value:e}),s.listeners.forEach(e=>e())}return s.listeners.add(c),r.on(e,t),()=>{s.listeners.delete(c),r.off(e,t)}},[e,r,s]);const a=s.state.model?.value;return t.G.isNullable(a)?null:n(a,s.state.inspect.value)}e.Action=(e,t=u.Unicast)=>{const n=t===u.Broadcast?Symbol(`${p.broadcastActionPrefix}${e}`):t===u.Multicast?Symbol(`${p.multicastActionPrefix}${e}`):Symbol(`${p.actionPrefix}${e}`),r=function(e){return{[s.Action]:n,[s.Payload]:void 0,[s.Channel]:e,channel:e}};return Object.defineProperty(r,s.Action,{value:n,enumerable:!1}),Object.defineProperty(r,s.Payload,{value:void 0,enumerable:!1}),t===u.Broadcast&&Object.defineProperty(r,s.Broadcast,{value:!0,enumerable:!1}),t===u.Multicast&&Object.defineProperty(r,s.Multicast,{value:!0,enumerable:!1}),r},e.Boundary=function({children:e}){return n.jsx(X,{children:n.jsx(Z,{children:n.jsx(te,{children:e})})})},e.Distribution=u,e.Entry=function(){const e=Symbol("chizu.cache/Entry"),t=function(t){return{[s.Cache]:e,channel:t}};return Object.defineProperty(t,s.Cache,{value:e,enumerable:!1}),t},e.Error=function({handler:e,children:t}){return n.jsx(E.Provider,{value:e,children:t})},e.Lifecycle=a,e.Op=M,e.Operation=M,e.Reason=f,e.Scope=ce,e.State=F,e.With=function(e){return(t,n)=>{t.actions.produce(t=>{t.model[e]=n})}},e.annotate=function(e,t){return W.annotate(e,t)},e.useActions=function(...e){const n=t.G.isUndefined(e[0])||t.G.isFunction(e[0])?{}:e[0],o=t.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),c=Q(),u=re(),f=r.useContext(E),d=i.useContext(ee),p=i.useContext(Y),h=ie(),m=i.useRef(!1),y=i.useRef(null),b=i.useRef(new F);m.current||(m.current=!0,y.current=b.current.hydrate(n));const[v,C]=i.useState(()=>b.current.model),M=function(e){const t=i.useRef(e);return i.useLayoutEffect(()=>{t.current=e},[e]),i.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(o()),k=i.useMemo(()=>new V,[]),G=i.useRef({handlers:new Map});G.current.handlers=new Map;const _=function(){const e=i.useRef(new Set),t=i.useRef(new Set);return i.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),R=i.useRef(l.Mounting),N=function(){const e=i.useRef({}),t=i.useRef(new Map),n=i.useRef(new Map);return i.useMemo(()=>({refs:e,pending:t,emitted:n}),[])}(),z=i.useRef(new Set),U=i.useRef(0),L=i.useCallback((e,t,n)=>{const r=new AbortController,o={controller:r,action:e,payload:t};return d.add(o),z.current.add(o),{model:b.current.model,get phase(){return R.current},task:o,data:M,tasks:d,nodes:N.refs.current,actions:{produce(e){if(r.signal.aborted)return;const t=b.current.produce(t=>e({model:t,inspect:b.current.inspect}));C(b.current.model),n.processes.add(t),y.current&&(n.processes.add(y.current),y.current=null)},dispatch(e,t,n){if(r.signal.aborted)return;const o=g(e),i=j(e)?e.channel:void 0;if(S(e)&&n?.scope){const e=oe(u,n.scope);return void(e&&e.emitter.emit(o,t,i))}(w(e)?c:k).emit(o,t,i)},annotate:(e,t)=>b.current.annotate(e,t),async cacheable(e,t,n){if(r.signal.aborted)return{data:null};const o=P(e),c=p.get(o);if(c&&Date.now()<c.expiry)return{data:c.value};const i=function(e){return null!=e&&"object"==typeof e&&"TAG"in e?0===e.TAG?{ok:!0,value:e._0}:{ok:!1}:null==e?{ok:!1}:{ok:!0,value:e}}(await n());return i.ok?(p.set(o,{value:i.value,expiry:Date.now()+t}),{data:i.value}):{data:null}},invalidate(e){p.delete(P(e))},async read(e,t){if(r.signal.aborted)return null;const n=g(e),o=S(e)&&t?.scope?oe(u,t.scope)?.emitter??null:c;if(!o)return null;if(void 0===o.getCached(n))return null;const i=x(e),s="unknown"!==i?i[0].toLowerCase()+i.slice(1):null;if(s){const e=b.current.inspect[s];e?.pending?.()&&await new Promise((t,n)=>{if(r.signal.aborted)return void n(r.signal.reason);const o=()=>n(r.signal.reason);r.signal.addEventListener("abort",o,{once:!0}),e.settled().then(()=>{r.signal.removeEventListener("abort",o),t()})})}return o.getCached(n)??null},peek(e,t){if(r.signal.aborted)return null;const n=g(e),o=S(e)&&t?.scope?oe(u,t.scope)?.emitter??null:c;return o?o.getCached(n)??null:null}}}},[v]);i.useLayoutEffect(()=>{function e(e,n,r){return async function(o,c){const i=r();if(t.G.isNotNullable(c)&&t.G.isNotNullable(i)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,i))return;const s={processes:new Set},u=Promise.withResolvers(),l=L(e,o,s);try{await n(l,o)}catch(p){const t=G.current.handlers.has(a.Error),n={reason:A(p),error:O(p),action:x(e),handled:t,tasks:d};f?.(n),t&&k.emit(a.Error,n)}finally{for(const e of d)if(e===l.task){d.delete(e),z.current.delete(e);break}s.processes.forEach(e=>b.current.prune(e)),s.processes.size>0&&h(),u.resolve()}}}U.current++;const n=new Set;return G.current.handlers.forEach((t,r)=>{for(const{getChannel:o,handler:i}of t){const t=e(r,i,o);if(S(r)){if(u)for(const e of u.values()){const o=e.emitter;o.on(r,t),n.add(()=>o.off(r,t))}k.on(r,t),_.multicast.add(r),n.add(()=>k.off(r,t))}else w(r)?(c.on(r,t),k.on(r,t),_.broadcast.add(r),n.add(()=>{c.off(r,t),k.off(r,t)})):(k.on(r,t),n.add(()=>k.off(r,t)))}}),()=>{const e=++U.current,t=new Set(n);queueMicrotask(()=>{if(U.current===e){for(const e of z.current)e.controller.abort(),d.delete(e);z.current.clear(),R.current=l.Unmounting,k.emit(a.Unmount),R.current=l.Unmounted;for(const e of t)e()}else for(const e of t)e()})}},[k]),i.useLayoutEffect(()=>{for(const[e,t]of N.pending.current)N.emitted.current.get(e)!==t&&(N.emitted.current.set(e,t),k.emit(s.Node,t,{Name:e}));N.pending.current.clear()}),function({unicast:e,broadcast:n,dispatchers:r,scope:o,phase:c,data:s}){const u=i.useRef(null);i.useLayoutEffect(()=>{c.current===l.Mounting&&(e.emit(a.Mount),r.broadcast.forEach(r=>{const o=n.getCached(r);t.G.isNullable(o)||e.emit(r,o)}),o&&r.multicast.forEach(n=>{for(const r of o.values()){const o=r.emitter.getCached(n);t.G.isNullable(o)||e.emit(n,o)}}),c.current=l.Mounted)},[]),i.useLayoutEffect(()=>{if(t.G.isNotNullable(u.current)){const n=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,s);t.A.isNotEmpty(Object.keys(n))&&e.emit(a.Update,n)}u.current=s},[s,e])}({unicast:k,broadcast:c,dispatchers:_,scope:u,phase:R,data:o()});const T=i.useMemo(()=>[v,{dispatch(e,t,n){const r=g(e),o=j(e)?e.channel:void 0;if(S(e)&&n?.scope){const e=oe(u,n.scope);return void(e&&e.emitter.emit(r,t,o))}(w(e)?c:k).emit(r,t,o)},get inspect(){return b.current.inspect},get nodes(){return N.refs.current},node(e,t){N.refs.current[e]=t,N.pending.current.set(e,t)},stream:(e,t)=>i.createElement(ae,{action:g(e),renderer:t})}],[v,k]);return T.useAction=(e,t)=>{!function(e,t,n){const r=i.useRef(n);i.useLayoutEffect(()=>{r.current=n});const o=i.useRef(t);i.useLayoutEffect(()=>{o.current=t});const c=i.useCallback(async(e,t)=>{const n=r.current;if("GeneratorFunction"===n.constructor.name||"AsyncGeneratorFunction"===n.constructor.name){const r=n(e,t);for await(const e of r);}else await n(e,t)},[]),s=i.useCallback(()=>j(o.current)?o.current.channel:void 0,[]),a=g(t),u=e.current.handlers.get(a)??new Set;0===u.size&&e.current.handlers.set(a,u),u.add({getChannel:s,handler:c})}(G,e,t)},T},e.utils=b,e.withScope=function(e,t){const r=`Scoped${t.displayName||t.name||"Component"}`;return{[r]:r=>n.jsx(ce,{name:e,children:n.jsx(t,{...r})})}[r]},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("@mobily/ts-belt"),require("react/jsx-runtime"),require("react"),require("immer")):"function"==typeof define&&define.amd?define(["exports","@mobily/ts-belt","react/jsx-runtime","react","immer"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).Chizu={},global.TsBelt,global.jsxRuntime,global.React,global.Immer);
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { With } from './utils.ts';
|
|
|
10
10
|
*
|
|
11
11
|
* The hook returns a result containing:
|
|
12
12
|
* 1. The current model state
|
|
13
|
-
* 2. An actions object with `dispatch`, `
|
|
13
|
+
* 2. An actions object with `dispatch`, `inspect`, and `useAction`
|
|
14
14
|
*
|
|
15
15
|
* The `inspect` property provides access to Immertation's annotation system,
|
|
16
16
|
* allowing you to check for pending operations on model properties.
|
package/dist/hooks/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { default as EventEmitter } from 'eventemitter3';
|
|
|
2
2
|
import { RefObject } from 'react';
|
|
3
3
|
import { Model, HandlerContext, Actions, Props, Tasks, ActionId, Phase, Filter, Nodes } from '../types/index.ts';
|
|
4
4
|
import { BroadcastEmitter } from '../boundary/components/broadcast/utils.ts';
|
|
5
|
+
import { ScopeContext } from '../boundary/components/scope/types.ts';
|
|
5
6
|
/**
|
|
6
7
|
* Return type for the useNodes hook.
|
|
7
8
|
* Contains refs for captured nodes, pending captures, and last emitted nodes.
|
|
@@ -23,17 +24,17 @@ export type References<M extends Model | void> = {
|
|
|
23
24
|
* Receives the reactive context and payload, returning void or a promise/generator.
|
|
24
25
|
*
|
|
25
26
|
* @template M - The model type
|
|
26
|
-
* @template
|
|
27
|
+
* @template A - The actions class type
|
|
27
28
|
* @template D - The data props type
|
|
28
29
|
*/
|
|
29
|
-
export type Handler<M extends Model | void = Model,
|
|
30
|
+
export type Handler<M extends Model | void = Model, A extends Actions | void = Actions, D extends Props = Props> = (context: HandlerContext<M, A, D>, payload: unknown) => void | Promise<void> | AsyncGenerator | Generator;
|
|
30
31
|
/**
|
|
31
32
|
* Entry for an action handler with a reactive channel getter.
|
|
32
33
|
* When getChannel returns undefined, the handler fires for all dispatches.
|
|
33
34
|
* When getChannel returns a channel, dispatches must match.
|
|
34
35
|
*/
|
|
35
|
-
export type HandlerEntry<M extends Model | void = Model,
|
|
36
|
-
handler: Handler<M,
|
|
36
|
+
export type HandlerEntry<M extends Model | void = Model, A extends Actions | void = Actions, D extends Props = Props> = {
|
|
37
|
+
handler: Handler<M, A, D>;
|
|
37
38
|
getChannel: () => Filter | undefined;
|
|
38
39
|
};
|
|
39
40
|
/**
|
|
@@ -41,12 +42,12 @@ export type HandlerEntry<M extends Model | void = Model, AC extends Actions | vo
|
|
|
41
42
|
* Maps action IDs to sets of handler entries (with optional channels).
|
|
42
43
|
*
|
|
43
44
|
* @template M - The model type
|
|
44
|
-
* @template
|
|
45
|
+
* @template A - The actions class type
|
|
45
46
|
* @template D - The data props type
|
|
46
47
|
*/
|
|
47
|
-
export type Scope<M extends Model | void = Model,
|
|
48
|
+
export type Scope<M extends Model | void = Model, A extends Actions | void = Actions, D extends Props = Props> = {
|
|
48
49
|
/** All handlers for each action, with optional channels */
|
|
49
|
-
handlers: Map<ActionId, Set<HandlerEntry<M,
|
|
50
|
+
handlers: Map<ActionId, Set<HandlerEntry<M, A, D>>>;
|
|
50
51
|
};
|
|
51
52
|
/**
|
|
52
53
|
* Function type for the data snapshot passed to useActions.
|
|
@@ -55,14 +56,31 @@ export type Scope<M extends Model | void = Model, AC extends Actions | void = Ac
|
|
|
55
56
|
* @template D - The data props type
|
|
56
57
|
*/
|
|
57
58
|
export type Data<D extends Props = Props> = () => D;
|
|
59
|
+
/**
|
|
60
|
+
* Return type for useDispatchers hook.
|
|
61
|
+
*/
|
|
62
|
+
export type Dispatchers = {
|
|
63
|
+
/** Set of registered broadcast action IDs */
|
|
64
|
+
broadcast: Set<ActionId>;
|
|
65
|
+
/** Set of registered multicast action IDs */
|
|
66
|
+
multicast: Set<ActionId>;
|
|
67
|
+
};
|
|
58
68
|
/**
|
|
59
69
|
* Configuration for {@link useLifecycles}.
|
|
60
70
|
*/
|
|
61
71
|
export type LifecycleConfig = {
|
|
72
|
+
/** Component-local event emitter for unicast action dispatch */
|
|
62
73
|
unicast: EventEmitter;
|
|
74
|
+
/** Shared broadcast emitter with cached values for cross-component events */
|
|
63
75
|
broadcast: BroadcastEmitter;
|
|
76
|
+
/** Global set of all in-flight tasks across components */
|
|
64
77
|
tasks: Tasks;
|
|
65
|
-
|
|
78
|
+
/** Tracked broadcast and multicast action sets for cached replay on mount */
|
|
79
|
+
dispatchers: Dispatchers;
|
|
80
|
+
/** Scope context for multicast cached replay (null when outside any scope) */
|
|
81
|
+
scope: ScopeContext;
|
|
82
|
+
/** Mutable ref tracking the component's current lifecycle phase */
|
|
66
83
|
phase: RefObject<Phase>;
|
|
84
|
+
/** Current snapshot of reactive data props for change detection */
|
|
67
85
|
data: Props;
|
|
68
86
|
};
|
package/dist/hooks/utils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
2
|
import { Props, Model, Actions, Filter, ActionId, HandlerPayload, ChanneledAction, HandlerContext } from '../types/index.ts';
|
|
3
|
-
import { LifecycleConfig, References, Scope } from './types.ts';
|
|
3
|
+
import { Dispatchers, LifecycleConfig, References, Scope } from './types.ts';
|
|
4
4
|
import { isChanneledAction, getActionSymbol } from '../action/index.ts';
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
/**
|
|
@@ -24,7 +24,7 @@ export declare function isGenerator(result: unknown): result is Generator | Asyn
|
|
|
24
24
|
* - Mounting → (cached broadcast action values emitted here) → Mounted
|
|
25
25
|
* - Mounted → Unmounting → Unmounted
|
|
26
26
|
*/
|
|
27
|
-
export declare function useLifecycles({ unicast, broadcast,
|
|
27
|
+
export declare function useLifecycles({ unicast, broadcast, dispatchers, scope, phase, data, }: LifecycleConfig): void;
|
|
28
28
|
/**
|
|
29
29
|
* Creates a data proxy for a given object, returning a memoized version.
|
|
30
30
|
* The proxy provides stable access to the object's properties,
|
|
@@ -68,17 +68,8 @@ export declare function useData<P extends Props>(props: P): P;
|
|
|
68
68
|
* actions.useAction(Actions.Visitor, With("name")); // Country -> string ✗
|
|
69
69
|
* ```
|
|
70
70
|
*/
|
|
71
|
-
export declare function With<K extends string>(key: K): <M extends Model,
|
|
71
|
+
export declare function With<K extends string>(key: K): <M extends Model, A extends Actions | void, D extends Props, P extends K extends keyof M ? M[K] : never>(context: HandlerContext<M, A, D>, payload: P) => void;
|
|
72
72
|
export { isChanneledAction, getActionSymbol };
|
|
73
|
-
/**
|
|
74
|
-
* Return type for useActionSets hook.
|
|
75
|
-
*/
|
|
76
|
-
export type ActionSets = {
|
|
77
|
-
/** Set of registered broadcast action IDs */
|
|
78
|
-
broadcast: Set<ActionId>;
|
|
79
|
-
/** Set of registered multicast action IDs */
|
|
80
|
-
multicast: Set<ActionId>;
|
|
81
|
-
};
|
|
82
73
|
/**
|
|
83
74
|
* Manages sets of broadcast and multicast action IDs.
|
|
84
75
|
*
|
|
@@ -91,7 +82,7 @@ export type ActionSets = {
|
|
|
91
82
|
*
|
|
92
83
|
* @example
|
|
93
84
|
* ```ts
|
|
94
|
-
* const actions =
|
|
85
|
+
* const actions = useDispatchers();
|
|
95
86
|
*
|
|
96
87
|
* // Register a broadcast action
|
|
97
88
|
* actions.broadcast.add(getActionSymbol(MyBroadcastAction));
|
|
@@ -104,7 +95,7 @@ export type ActionSets = {
|
|
|
104
95
|
*
|
|
105
96
|
* @internal
|
|
106
97
|
*/
|
|
107
|
-
export declare function
|
|
98
|
+
export declare function useDispatchers(): Dispatchers;
|
|
108
99
|
/**
|
|
109
100
|
* Registers an action handler within a component's scope.
|
|
110
101
|
*
|
|
@@ -139,7 +130,7 @@ export declare function useActionSets(): ActionSets;
|
|
|
139
130
|
*
|
|
140
131
|
* @internal
|
|
141
132
|
*/
|
|
142
|
-
export declare function useRegisterHandler<M extends Model | void,
|
|
133
|
+
export declare function useRegisterHandler<M extends Model | void, A extends Actions | void, D extends Props>(scope: React.RefObject<Scope<M, A, D>>, action: ActionId | HandlerPayload | ChanneledAction, handler: (context: HandlerContext<M, A, D>, payload: unknown) => void | Promise<void> | AsyncGenerator | Generator): void;
|
|
143
134
|
/**
|
|
144
135
|
* Manages captured DOM nodes for a model type.
|
|
145
136
|
* Returns refs for nodes, pending captures, and last emitted nodes.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { Operation, Process, Inspect, Box } from 'immertation';
|
|
2
2
|
import { ActionId, Task, Tasks } from '../boundary/components/tasks/types.ts';
|
|
3
|
-
import { ConsumerRenderer } from '../boundary/components/consumer/index.tsx';
|
|
4
3
|
import { Option } from '@mobily/ts-belt/Option';
|
|
5
4
|
import { Result as TsBeltResult } from '@mobily/ts-belt/Result';
|
|
6
|
-
import
|
|
5
|
+
import * as React from "react";
|
|
7
6
|
export type { ActionId, Box, Task, Tasks };
|
|
8
|
-
export type { ConsumerRenderer };
|
|
9
7
|
/**
|
|
10
8
|
* Type for objects with a Brand.Action symbol property.
|
|
11
9
|
* Used for type-safe access to the action symbol.
|
|
@@ -148,7 +146,7 @@ export declare class Lifecycle {
|
|
|
148
146
|
* - **Unicast** – Action is scoped to the component that defines it and cannot be
|
|
149
147
|
* consumed by other components. This is the default behaviour.
|
|
150
148
|
* - **Broadcast** – Action is distributed to all mounted components that have defined
|
|
151
|
-
* a handler for it.
|
|
149
|
+
* a handler for it. Values are cached for late-mounting components.
|
|
152
150
|
*
|
|
153
151
|
* @example
|
|
154
152
|
* ```ts
|
|
@@ -261,24 +259,21 @@ export type ChanneledAction<P = unknown, C = unknown> = {
|
|
|
261
259
|
};
|
|
262
260
|
/**
|
|
263
261
|
* Branded type for broadcast action objects created with `Action()` and `Distribution.Broadcast`.
|
|
264
|
-
* Broadcast actions are sent to all mounted components
|
|
262
|
+
* Broadcast actions are sent to all mounted components. Values are cached so that
|
|
263
|
+
* late-mounting components receive the most recent payload.
|
|
265
264
|
*
|
|
266
265
|
* This type extends `HandlerPayload<P, C>` with an additional brand to enforce at compile-time
|
|
267
|
-
* that only broadcast actions can be passed to `
|
|
268
|
-
* a local action will result in a TypeScript error.
|
|
266
|
+
* that only broadcast actions can be passed to `context.actions.read()`.
|
|
269
267
|
*
|
|
270
268
|
* @template P - The payload type for the action
|
|
271
269
|
* @template C - The channel type for channeled dispatches (defaults to never)
|
|
272
270
|
*
|
|
273
271
|
* @example
|
|
274
272
|
* ```ts
|
|
275
|
-
* // This compiles - SignedOut is a broadcast action
|
|
276
273
|
* const SignedOut = Action<User>("SignedOut", Distribution.Broadcast);
|
|
277
|
-
* actions.consume(SignedOut, (box) => <div>{box.value.name}</div>);
|
|
278
274
|
*
|
|
279
|
-
* //
|
|
280
|
-
* const
|
|
281
|
-
* actions.consume(Increment, ...); // Type error!
|
|
275
|
+
* // Read the latest value inside a handler
|
|
276
|
+
* const user = await context.actions.read(SignedOut);
|
|
282
277
|
* ```
|
|
283
278
|
*/
|
|
284
279
|
export type BroadcastPayload<P = unknown, C extends Filter = never> = HandlerPayload<P, C> & {
|
|
@@ -342,7 +337,9 @@ export type MulticastOptions = {
|
|
|
342
337
|
*
|
|
343
338
|
* @template A - The action type (HandlerPayload or ChanneledAction)
|
|
344
339
|
*/
|
|
345
|
-
export type Payload<A> = A extends
|
|
340
|
+
export type Payload<A> = A extends {
|
|
341
|
+
readonly [Brand.Payload]: infer P;
|
|
342
|
+
} ? P : never;
|
|
346
343
|
/**
|
|
347
344
|
* Filter object for channeled actions.
|
|
348
345
|
* Must be an object where each value is a non-nullable primitive.
|
|
@@ -590,24 +587,20 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
590
587
|
*/
|
|
591
588
|
invalidate(entry: CacheId<unknown> | ChanneledCacheId<unknown>): void;
|
|
592
589
|
/**
|
|
593
|
-
* Reads the latest broadcast or multicast value
|
|
594
|
-
*
|
|
595
|
-
* Returns the raw value `T` or `null` if no value has been dispatched.
|
|
596
|
-
* If the value has pending annotations, awaits `settled()` before returning.
|
|
597
|
-
* Respects the task's abort signal — returns `null` if the task is aborted
|
|
598
|
-
* while waiting.
|
|
590
|
+
* Reads the latest broadcast or multicast value, waiting for annotations to settle.
|
|
599
591
|
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
592
|
+
* If a value has already been dispatched it resolves immediately.
|
|
593
|
+
* Otherwise it waits until the next dispatch of the action.
|
|
594
|
+
* Resolves with `null` if the task is aborted before a value arrives.
|
|
602
595
|
*
|
|
603
596
|
* @param action - The broadcast or multicast action to read.
|
|
604
597
|
* @param options - For multicast actions, must include `{ scope: "ScopeName" }`.
|
|
605
|
-
* @returns The
|
|
598
|
+
* @returns The dispatched value, or `null` if aborted.
|
|
606
599
|
*
|
|
607
600
|
* @example
|
|
608
601
|
* ```ts
|
|
609
602
|
* actions.useAction(Actions.FetchPosts, async (context) => {
|
|
610
|
-
* const user = await context.actions.
|
|
603
|
+
* const user = await context.actions.read(Actions.Broadcast.User);
|
|
611
604
|
* if (!user) return;
|
|
612
605
|
* const posts = await fetchPosts(user.id, {
|
|
613
606
|
* signal: context.task.controller.signal,
|
|
@@ -616,8 +609,28 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
616
609
|
* });
|
|
617
610
|
* ```
|
|
618
611
|
*/
|
|
619
|
-
|
|
620
|
-
|
|
612
|
+
read<T>(action: BroadcastPayload<T>): Promise<T | null>;
|
|
613
|
+
read<T>(action: MulticastPayload<T>, options: MulticastOptions): Promise<T | null>;
|
|
614
|
+
/**
|
|
615
|
+
* Returns the latest broadcast or multicast value immediately without
|
|
616
|
+
* waiting for annotations to settle. Use this when you need the current
|
|
617
|
+
* cached value and do not need to wait for pending operations to complete.
|
|
618
|
+
*
|
|
619
|
+
* @param action - The broadcast or multicast action to peek at.
|
|
620
|
+
* @param options - For multicast actions, must include `{ scope: "ScopeName" }`.
|
|
621
|
+
* @returns The cached value, or `null` if no value has been dispatched.
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* ```ts
|
|
625
|
+
* actions.useAction(Actions.Check, (context) => {
|
|
626
|
+
* const user = context.actions.peek(Actions.Broadcast.User);
|
|
627
|
+
* if (!user) return;
|
|
628
|
+
* console.log(user.name);
|
|
629
|
+
* });
|
|
630
|
+
* ```
|
|
631
|
+
*/
|
|
632
|
+
peek<T>(action: BroadcastPayload<T>): T | null;
|
|
633
|
+
peek<T>(action: MulticastPayload<T>, options: MulticastOptions): T | null;
|
|
621
634
|
};
|
|
622
635
|
};
|
|
623
636
|
/**
|
|
@@ -625,7 +638,7 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
625
638
|
*
|
|
626
639
|
* A tuple containing:
|
|
627
640
|
* 1. The current model state of type M
|
|
628
|
-
* 2. An actions object with dispatch
|
|
641
|
+
* 2. An actions object with dispatch and inspect capabilities
|
|
629
642
|
*
|
|
630
643
|
* @template M - The model type representing the component's state
|
|
631
644
|
* @template AC - The actions class containing action definitions
|
|
@@ -640,9 +653,6 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
640
653
|
* // Dispatch actions
|
|
641
654
|
* actions.dispatch(Actions.Increment, 5);
|
|
642
655
|
*
|
|
643
|
-
* // Consume action values declaratively
|
|
644
|
-
* {actions.consume(Actions.Data, (box) => box.value.name)}
|
|
645
|
-
*
|
|
646
656
|
* // Check pending state
|
|
647
657
|
* actions.inspect.count.pending();
|
|
648
658
|
* ```
|
|
@@ -658,39 +668,22 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
658
668
|
*
|
|
659
669
|
* @see {@link Handlers} for the recommended HKT pattern
|
|
660
670
|
*/
|
|
661
|
-
export type Handler<M extends Model | void, AC extends Actions | void, K extends keyof AC & string, D extends Props = Props> = (context: HandlerContext<M, AC, D>, payload: Payload<AC[K] & HandlerPayload<unknown>>) => void | Promise<void> | AsyncGenerator | Generator;
|
|
662
|
-
/**
|
|
663
|
-
* Resolves the action value at a (possibly dot-notated) path within an actions object.
|
|
664
|
-
* For a simple key like `"SetName"`, returns `AC["SetName"]`.
|
|
665
|
-
* For a dotted key like `"Broadcast.PaymentSent"`, recursively resolves to
|
|
666
|
-
* `AC["Broadcast"]["PaymentSent"]`.
|
|
667
|
-
*
|
|
668
|
-
* @template AC - The actions object to traverse
|
|
669
|
-
* @template K - The key path (may contain dots)
|
|
670
|
-
*/
|
|
671
|
-
type DeepAction<AC, K extends string> = K extends `${infer Head}.${infer Tail}` ? Head extends keyof AC ? DeepAction<AC[Head], Tail> : never : K extends keyof AC ? AC[K] : never;
|
|
671
|
+
export type Handler<M extends Model | void, AC extends Actions | void, K extends keyof AC & string, D extends Props = Props> = (context: HandlerContext<M, AC, D>, ...args: [Payload<AC[K] & HandlerPayload<unknown>>] extends [never] ? [] : [payload: Payload<AC[K] & HandlerPayload<unknown>>]) => void | Promise<void> | AsyncGenerator | Generator;
|
|
672
672
|
/**
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
*
|
|
676
|
-
*
|
|
677
|
-
* Nested namespaces like `Broadcast = { PaymentSent, PaymentLink }` produce
|
|
678
|
-
* `"Broadcast.PaymentSent" | "Broadcast.PaymentLink"`.
|
|
679
|
-
*
|
|
680
|
-
* @template AC - The actions object to flatten
|
|
681
|
-
* @template Prefix - Accumulated prefix for recursion (defaults to never)
|
|
673
|
+
* String keys of `AC` excluding inherited `prototype` from class constructors.
|
|
674
|
+
* When action containers are classes (`typeof MyActions`), TypeScript includes
|
|
675
|
+
* `"prototype"` in `keyof`. Excluding it prevents `prototype` from appearing
|
|
676
|
+
* as a handler key and avoids recursion into Function internals.
|
|
682
677
|
*/
|
|
683
|
-
type
|
|
684
|
-
[K in keyof AC & string]: keyof AC[K] & string extends never ? [Prefix] extends [never] ? K : `${Prefix}.${K}` : FlattenKeys<AC[K], [Prefix] extends [never] ? K : `${Prefix}.${K}`>;
|
|
685
|
-
}[keyof AC & string];
|
|
678
|
+
type OwnKeys<AC> = Exclude<keyof AC & string, "prototype">;
|
|
686
679
|
/**
|
|
687
|
-
*
|
|
688
|
-
* Creates a mapped type where each action key maps to its fully-typed handler.
|
|
680
|
+
* Recursive mapped type for action handlers that mirrors the action class hierarchy.
|
|
689
681
|
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
682
|
+
* For leaf actions (values with no own string keys, i.e. `HandlerPayload`), produces
|
|
683
|
+
* a handler function signature. For namespace objects (containing nested actions),
|
|
684
|
+
* produces a nested `Handlers` object.
|
|
692
685
|
*
|
|
693
|
-
*
|
|
686
|
+
* Access handlers using bracket notation matching the action structure:
|
|
694
687
|
*
|
|
695
688
|
* @template M - The model type
|
|
696
689
|
* @template AC - The actions class type
|
|
@@ -712,15 +705,15 @@ type FlattenKeys<AC, Prefix extends string = never> = {
|
|
|
712
705
|
*
|
|
713
706
|
* type H = Handlers<Model, typeof Actions>;
|
|
714
707
|
*
|
|
715
|
-
* // Flat actions
|
|
708
|
+
* // Flat actions
|
|
716
709
|
* export const handleSetName: H["SetName"] = (context, name) => { ... };
|
|
717
710
|
*
|
|
718
|
-
* // Nested actions use
|
|
719
|
-
* export const handlePaymentSent: H["Broadcast
|
|
711
|
+
* // Nested actions use chained bracket notation
|
|
712
|
+
* export const handlePaymentSent: H["Broadcast"]["PaymentSent"] = (context) => { ... };
|
|
720
713
|
* ```
|
|
721
714
|
*/
|
|
722
715
|
export type Handlers<M extends Model | void, AC extends Actions | void, D extends Props = Props> = {
|
|
723
|
-
[K in
|
|
716
|
+
[K in OwnKeys<AC>]: OwnKeys<AC[K]> extends never ? (context: HandlerContext<M, AC, D>, ...args: [Payload<AC[K] & HandlerPayload<unknown>>] extends [never] ? [] : [payload: Payload<AC[K] & HandlerPayload<unknown>>]) => void | Promise<void> | AsyncGenerator | Generator : Handlers<M, AC[K] & Actions, D>;
|
|
724
717
|
};
|
|
725
718
|
export type UseActions<M extends Model | void, AC extends Actions | void, D extends Props = Props> = [
|
|
726
719
|
Readonly<M>,
|
|
@@ -741,39 +734,6 @@ export type UseActions<M extends Model | void, AC extends Actions | void, D exte
|
|
|
741
734
|
dispatch<P>(action: BroadcastPayload<P>, payload?: P, options?: MulticastOptions): void;
|
|
742
735
|
dispatch<P>(action: MulticastPayload<P>, payload: P, options: MulticastOptions): void;
|
|
743
736
|
dispatch<P, C extends Filter>(action: ChanneledAction<P, C>, payload?: P, options?: MulticastOptions): void;
|
|
744
|
-
/**
|
|
745
|
-
* Subscribes to a distributed or multicast action's values and renders based on the callback.
|
|
746
|
-
* The callback receives a Box with `value` (the payload) and `inspect` (for annotation status).
|
|
747
|
-
* On mount, displays the most recent value from the Consumer/Scope store if available.
|
|
748
|
-
*
|
|
749
|
-
* Supports three usage patterns:
|
|
750
|
-
* 1. Consuming broadcast actions from the local actions class (with autocomplete)
|
|
751
|
-
* 2. Consuming any broadcast action from external modules
|
|
752
|
-
* 3. Consuming multicast actions with a scope name
|
|
753
|
-
*
|
|
754
|
-
* @param action - The distributed or multicast action to consume
|
|
755
|
-
* @param renderer - Render function receiving the Box
|
|
756
|
-
* @param options - For multicast actions, must include `{ scope: "ScopeName" }`
|
|
757
|
-
* @returns React element rendered by the callback
|
|
758
|
-
*
|
|
759
|
-
* @example
|
|
760
|
-
* ```tsx
|
|
761
|
-
* // Local broadcast action (from same actions class)
|
|
762
|
-
* {actions.consume(Actions.Visitor, (visitor) =>
|
|
763
|
-
* visitor.inspect.pending() ? "Loading..." : visitor.value.name
|
|
764
|
-
* )}
|
|
765
|
-
*
|
|
766
|
-
* // External broadcast action
|
|
767
|
-
* {actions.consume(SharedActions.Counter, (counter) => counter.value)}
|
|
768
|
-
*
|
|
769
|
-
* // Multicast action with scope
|
|
770
|
-
* {actions.consume(Actions.Multicast.Update, (update) => update.value, { scope: "MyScope" })}
|
|
771
|
-
* ```
|
|
772
|
-
*/
|
|
773
|
-
consume<T>(action: BroadcastPayload<T>, renderer: ConsumerRenderer<T>): React.ReactNode;
|
|
774
|
-
consume<T>(action: MulticastPayload<T>, renderer: ConsumerRenderer<T>, options: MulticastOptions): React.ReactNode;
|
|
775
|
-
consume<K extends keyof AC>(action: AC[K] & BroadcastPayload<unknown>, renderer: ConsumerRenderer<Payload<AC[K]>>): React.ReactNode;
|
|
776
|
-
consume<K extends keyof AC>(action: AC[K] & MulticastPayload<unknown>, renderer: ConsumerRenderer<Payload<AC[K]>>, options: MulticastOptions): React.ReactNode;
|
|
777
737
|
inspect: Inspect<M>;
|
|
778
738
|
/**
|
|
779
739
|
* Captured DOM nodes registered via `node()`.
|
|
@@ -821,6 +781,29 @@ export type UseActions<M extends Model | void, AC extends Actions | void, D exte
|
|
|
821
781
|
* ```
|
|
822
782
|
*/
|
|
823
783
|
node<K extends keyof Nodes<M>>(name: K, node: Nodes<M>[K] | null): void;
|
|
784
|
+
/**
|
|
785
|
+
* Streams broadcast values declaratively in JSX using a render-prop pattern.
|
|
786
|
+
*
|
|
787
|
+
* Subscribes to the given broadcast action and re-renders when a new value
|
|
788
|
+
* is dispatched. Returns `null` until the first dispatch. The renderer
|
|
789
|
+
* receives the value and an inspect proxy for annotation tracking.
|
|
790
|
+
*
|
|
791
|
+
* @param action - The broadcast action to subscribe to.
|
|
792
|
+
* @param renderer - Callback that receives value and inspect, returns React nodes.
|
|
793
|
+
* @returns React nodes from the renderer, or null if no value has been dispatched.
|
|
794
|
+
*
|
|
795
|
+
* @example
|
|
796
|
+
* ```tsx
|
|
797
|
+
* return (
|
|
798
|
+
* <div>
|
|
799
|
+
* {actions.stream(Actions.Broadcast.User, (user, inspect) => (
|
|
800
|
+
* <span>{user.name}</span>
|
|
801
|
+
* ))}
|
|
802
|
+
* </div>
|
|
803
|
+
* );
|
|
804
|
+
* ```
|
|
805
|
+
*/
|
|
806
|
+
stream<T extends object>(action: BroadcastPayload<T>, renderer: (value: T, inspect: Inspect<T>) => React.ReactNode): React.ReactNode;
|
|
824
807
|
}
|
|
825
808
|
] & {
|
|
826
809
|
/**
|
|
@@ -849,5 +832,5 @@ export type UseActions<M extends Model | void, AC extends Actions | void, D exte
|
|
|
849
832
|
* });
|
|
850
833
|
* ```
|
|
851
834
|
*/
|
|
852
|
-
useAction<A extends ActionId | HandlerPayload | ChanneledAction>(action: A, handler: (context: HandlerContext<M, AC, D>, payload: Payload<A>) => void | Promise<void> | AsyncGenerator | Generator): void;
|
|
835
|
+
useAction<A extends ActionId | HandlerPayload | ChanneledAction>(action: A, handler: (context: HandlerContext<M, AC, D>, ...args: [Payload<A>] extends [never] ? [] : [payload: Payload<A>]) => void | Promise<void> | AsyncGenerator | Generator): void;
|
|
853
836
|
};
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -16,16 +16,30 @@ export declare const config: {
|
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* Returns a promise that resolves after the specified number of milliseconds.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* The sleep will reject with an AbortError when the signal is aborted,
|
|
20
|
+
* allowing cleanup of pending operations.
|
|
21
21
|
*
|
|
22
22
|
* @param ms The number of milliseconds to sleep.
|
|
23
|
-
* @param signal
|
|
23
|
+
* @param signal AbortSignal to cancel the sleep early.
|
|
24
24
|
* @returns A promise that resolves after the delay or rejects if aborted.
|
|
25
25
|
*/
|
|
26
|
-
export declare function sleep(ms: number, signal
|
|
26
|
+
export declare function sleep(ms: number, signal: AbortSignal | undefined): Promise<void>;
|
|
27
27
|
/** Shorthand alias for {@link sleep}. */
|
|
28
28
|
export declare const ζ: typeof sleep;
|
|
29
|
+
/**
|
|
30
|
+
* Repeatedly calls a function at a fixed interval until it returns `true` or
|
|
31
|
+
* the signal is aborted. The function is invoked immediately on the first
|
|
32
|
+
* iteration, then after each interval.
|
|
33
|
+
*
|
|
34
|
+
* @param ms The interval in milliseconds between invocations.
|
|
35
|
+
* @param signal Optional AbortSignal to cancel polling early.
|
|
36
|
+
* @param fn Callback invoked each iteration. Return `true` to stop polling.
|
|
37
|
+
* @returns A promise that resolves when `fn` returns `true`, or rejects with
|
|
38
|
+
* an AbortError if the signal is aborted.
|
|
39
|
+
*/
|
|
40
|
+
export declare function poll(ms: number, signal: AbortSignal | undefined, fn: () => boolean | Promise<boolean>): Promise<void>;
|
|
41
|
+
/** Shorthand alias for {@link poll}. */
|
|
42
|
+
export declare const π: typeof poll;
|
|
29
43
|
/**
|
|
30
44
|
* Generates a unique primary key.
|
|
31
45
|
* @returns A new unique symbol representing the primary key.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chizu",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.67",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"packageManager": "yarn@1.22.22",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"eventemitter3": "^5.0.
|
|
17
|
+
"eventemitter3": "^5.0.4",
|
|
18
18
|
"immertation": "^0.1.26"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
@@ -34,62 +34,62 @@
|
|
|
34
34
|
"prepare": "husky"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@babel/plugin-proposal-decorators": "^7.
|
|
38
|
-
"@babel/preset-env": "^7.
|
|
37
|
+
"@babel/plugin-proposal-decorators": "^7.29.0",
|
|
38
|
+
"@babel/preset-env": "^7.29.0",
|
|
39
39
|
"@babel/preset-react": "^7.28.5",
|
|
40
40
|
"@babel/preset-typescript": "^7.28.5",
|
|
41
41
|
"@emotion/css": "^11.13.5",
|
|
42
|
-
"@eslint/js": "^9.39.
|
|
43
|
-
"@faker-js/faker": "^10.
|
|
42
|
+
"@eslint/js": "^9.39.3",
|
|
43
|
+
"@faker-js/faker": "^10.3.0",
|
|
44
44
|
"@jest/globals": "^30.2.0",
|
|
45
45
|
"@mobily/ts-belt": "4.0.0-rc.5",
|
|
46
|
-
"@playwright/test": "^1.
|
|
46
|
+
"@playwright/test": "^1.58.2",
|
|
47
47
|
"@testing-library/dom": "^10.4.1",
|
|
48
48
|
"@testing-library/jest-dom": "^6.9.1",
|
|
49
|
-
"@testing-library/react": "^16.3.
|
|
49
|
+
"@testing-library/react": "^16.3.2",
|
|
50
50
|
"@types/lodash": "^4.17.23",
|
|
51
51
|
"@types/ramda": "^0.31.1",
|
|
52
|
-
"@types/react": "^19.2.
|
|
52
|
+
"@types/react": "^19.2.14",
|
|
53
53
|
"@types/react-dom": "^19.2.3",
|
|
54
54
|
"@types/traverse": "^0.6.37",
|
|
55
|
-
"@vitejs/plugin-react": "^5.1.
|
|
56
|
-
"antd": "^6.
|
|
55
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
56
|
+
"antd": "^6.3.0",
|
|
57
57
|
"commit-and-tag-version": "^12.6.1",
|
|
58
58
|
"dayjs": "^1.11.19",
|
|
59
|
-
"dexie": "^4.
|
|
60
|
-
"eslint": "^9.39.
|
|
59
|
+
"dexie": "^4.3.0",
|
|
60
|
+
"eslint": "^9.39.3",
|
|
61
61
|
"eslint-plugin-fp": "^2.3.0",
|
|
62
62
|
"eslint-plugin-import": "^2.32.0",
|
|
63
63
|
"eslint-plugin-react": "^7.37.5",
|
|
64
64
|
"fslint": "^1.1.0",
|
|
65
65
|
"get-port-cli": "^3.0.0",
|
|
66
|
-
"globals": "^17.
|
|
67
|
-
"happy-dom": "^20.
|
|
66
|
+
"globals": "^17.3.0",
|
|
67
|
+
"happy-dom": "^20.6.1",
|
|
68
68
|
"husky": "^9.1.7",
|
|
69
|
-
"immer": "^11.1.
|
|
69
|
+
"immer": "^11.1.4",
|
|
70
70
|
"jest": "^30.2.0",
|
|
71
71
|
"jest-environment-jsdom": "^30.2.0",
|
|
72
|
-
"jsdom": "^
|
|
72
|
+
"jsdom": "^28.1.0",
|
|
73
73
|
"lodash": "^4.17.23",
|
|
74
|
-
"lucide-react": "^0.
|
|
74
|
+
"lucide-react": "^0.564.0",
|
|
75
75
|
"madge": "^8.0.0",
|
|
76
|
-
"prettier": "^3.
|
|
76
|
+
"prettier": "^3.8.1",
|
|
77
77
|
"ramda": "^0.32.0",
|
|
78
|
-
"react": "^19.2.
|
|
79
|
-
"react-dom": "^19.2.
|
|
78
|
+
"react": "^19.2.4",
|
|
79
|
+
"react-dom": "^19.2.4",
|
|
80
80
|
"react-flip-numbers": "^3.0.9",
|
|
81
|
-
"react-router-dom": "^7.
|
|
82
|
-
"react-test-renderer": "^19.2.
|
|
81
|
+
"react-router-dom": "^7.13.0",
|
|
82
|
+
"react-test-renderer": "^19.2.4",
|
|
83
83
|
"rollup-plugin-visualizer": "^6.0.5",
|
|
84
84
|
"terser": "^5.46.0",
|
|
85
85
|
"traverse": "^0.6.11",
|
|
86
86
|
"ts-jest": "^29.4.6",
|
|
87
87
|
"ts-node": "^10.9.2",
|
|
88
88
|
"typescript": "^5.9.3",
|
|
89
|
-
"typescript-eslint": "^8.
|
|
89
|
+
"typescript-eslint": "^8.55.0",
|
|
90
90
|
"vite": "^7.3.1",
|
|
91
91
|
"vite-plugin-dts": "^4.5.4",
|
|
92
|
-
"vitest": "^4.0.
|
|
93
|
-
"wait-on": "^9.0.
|
|
92
|
+
"vitest": "^4.0.18",
|
|
93
|
+
"wait-on": "^9.0.4"
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { ConsumerRenderer } from '../consumer/types.ts';
|
|
2
|
-
import { ActionId } from '../tasks/types.ts';
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
/**
|
|
5
|
-
* Props for the MulticastPartition component.
|
|
6
|
-
*/
|
|
7
|
-
export type Props<T> = {
|
|
8
|
-
/** The multicast action symbol to subscribe to */
|
|
9
|
-
action: ActionId;
|
|
10
|
-
/** The scope name to subscribe to */
|
|
11
|
-
scopeName: string;
|
|
12
|
-
/** Callback that receives a Box and returns React nodes */
|
|
13
|
-
renderer: ConsumerRenderer<T>;
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Renders output for multicast `consume()` by subscribing to scope action events.
|
|
17
|
-
*
|
|
18
|
-
* Similar to the broadcast Partition component, but subscribes to a named scope's
|
|
19
|
-
* EventEmitter instead of the global broadcast emitter.
|
|
20
|
-
*
|
|
21
|
-
* On mount, if a value was previously dispatched for this action within the scope,
|
|
22
|
-
* it renders immediately with that cached value. If no value exists yet, it renders
|
|
23
|
-
* `null` until the first dispatch.
|
|
24
|
-
*
|
|
25
|
-
* @template T - The payload type for the action
|
|
26
|
-
* @param props.action - The multicast action symbol to subscribe to
|
|
27
|
-
* @param props.scopeName - The scope name to subscribe to
|
|
28
|
-
* @param props.renderer - Callback that receives a Box and returns React nodes
|
|
29
|
-
* @returns The result of calling renderer with the Box, or null if no value/scope exists
|
|
30
|
-
* @internal
|
|
31
|
-
*/
|
|
32
|
-
export declare function MulticastPartition<T extends object>({ action, scopeName, renderer, }: Props<T>): React.ReactNode;
|