march-hare 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,6 +47,7 @@ For advanced topics, see the [recipes directory](./recipes/).
47
47
  - Declarative lifecycle hooks without `useEffect`.
48
48
  - Centralised error handling via the global `Lifecycle.Fault` broadcast.
49
49
  - View-side reactivity for the per-`<app.Boundary>` Env via the global `Lifecycle.Env` broadcast.
50
+ - Observability hook via `<app.Boundary tap={...}>` &ndash; fires for every handler dispatch and its terminal (`success` or `error`). See the [tap recipe](./recipes/tap.md).
50
51
  - React Native compatible &ndash; uses [eventemitter3](https://github.com/primus/eventemitter3) for cross-platform pub/sub.
51
52
 
52
53
  ## Getting started
@@ -148,7 +149,7 @@ function useActions() {
148
149
  void (model.name = context.actions.annotate(model.name, Op.Update)),
149
150
  );
150
151
 
151
- // Auto-threads context.task.controller and the Env snapshot.
152
+ // Auto-threads context.task.controller and the live Env handle.
152
153
  const user = await context.actions.resource(resource.user());
153
154
 
154
155
  context.actions.produce(({ model }) => void (model.name = user.name));
@@ -392,7 +393,7 @@ Components that mount after a broadcast has already been dispatched automaticall
392
393
 
393
394
  ## Remote data with `Resource`
394
395
 
395
- For remote data, declare an `app.Resource` at module scope. `resource.user(params)` is the unified call form &mdash; it returns the sync cache read (`User | null`) and primes a slot that `context.actions.resource(resource.user(params))` consumes for the fetch path (with auto-threaded abort controller and Env snapshot). Every successful fetch caches the response in a module-level slot keyed by the fetcher and the stringified params, so different param-sets are independent. Keep all resources in `resources.ts` and pull the whole module in as a namespace (`import * as resource from "./resources"`):
396
+ For remote data, declare an `app.Resource` at module scope. `resource.user(params)` is the unified call form &mdash; it returns the sync cache read (`User | null`) and primes a slot that `context.actions.resource(resource.user(params))` consumes for the fetch path (with auto-threaded abort controller and a live handle to the per-`<Boundary>` Env). Every successful fetch caches the response in a module-level slot keyed by the fetcher and the stringified params, so different param-sets are independent. Keep all resources in `resources.ts` and pull the whole module in as a namespace (`import * as resource from "./resources"`):
396
397
 
397
398
  ```ts
398
399
  // resources.ts
@@ -706,7 +707,7 @@ See the [multicast recipe](./recipes/multicast-actions.md) for more details.
706
707
 
707
708
  ## Global data
708
709
 
709
- For coordinating between async handlers and threading ambient values (session tokens, locale, feature flags, current operational mode) without re-rendering the JSX tree on every dot read, use the per-`<app.Boundary>` `Env`. Declare your env shape inline on `App({ env })`, read via dot notation (`env.session`, `context.env.locale`), and write via `context.actions.produce(({ env }) => { ... })` &mdash; the same Immer-style recipe used for the model. Every `app.Resource` fetcher also receives a snapshot of the Env on its args object. When the view side needs to react to Env changes, subscribe to the global `Lifecycle.Env` broadcast &mdash; `actions.useAction(Lifecycle.Env, handler)` for handler-level work and `actions.stream(Lifecycle.Env, (env) => ...)` for JSX. Both seed from the initial Env on mount.
710
+ For coordinating between async handlers and threading ambient values (session tokens, locale, feature flags, current operational mode) without re-rendering the JSX tree on every dot read, use the per-`<app.Boundary>` `Env`. Declare your env shape inline on `App({ env })`, read via dot notation (`env.session`, `context.env.locale`), and write via `context.actions.produce(({ env }) => { ... })` &mdash; the same Immer-style recipe used for the model. Every `app.Resource` fetcher also receives a live read-only handle to the Env on its args object &mdash; the same `Proxy` as `context.env`, so dot reads stay fresh across `await` boundaries inside the fetcher. When the view side needs to react to Env changes, subscribe to the global `Lifecycle.Env` broadcast &mdash; `actions.useAction(Lifecycle.Env, handler)` for handler-level work and `actions.stream(Lifecycle.Env, (env) => ...)` for JSX. Both seed from the initial Env on mount.
710
711
 
711
712
  ```ts
712
713
  // app.ts
@@ -790,10 +791,10 @@ Multiple `App` instances can coexist in the same tree &mdash; each `<app.Boundar
790
791
 
791
792
  ## Toggling boolean state
792
793
 
793
- Toggling boolean UI state &ndash; modals, sidebars, drawers &ndash; is one of the most common patterns. Bind a unicast action to a boolean field on the model with `With.Invert`:
794
+ Toggling boolean UI state &ndash; modals, sidebars, drawers &ndash; is one of the most common patterns. Bind a unicast action to a boolean field on the model with `context.with.invert`:
794
795
 
795
796
  ```tsx
796
- import { Action, With } from "march-hare";
797
+ import { Action } from "march-hare";
797
798
  import { app } from "./app";
798
799
 
799
800
  type Model = {
@@ -815,8 +816,11 @@ function useActions() {
815
816
  const context = app.useContext<Model, typeof Actions>();
816
817
  const actions = context.useActions(model);
817
818
 
818
- actions.useAction(Actions.TogglePaymentDialog, With.Invert("paymentDialog"));
819
- actions.useAction(Actions.ToggleSidebar, With.Invert("sidebar"));
819
+ actions.useAction(
820
+ Actions.TogglePaymentDialog,
821
+ context.with.invert("paymentDialog"),
822
+ );
823
+ actions.useAction(Actions.ToggleSidebar, context.with.invert("sidebar"));
820
824
 
821
825
  return actions;
822
826
  }
@@ -835,4 +839,9 @@ export default function Shell(): React.ReactElement {
835
839
  }
836
840
  ```
837
841
 
838
- `With.Invert` only compiles when the named property is a boolean on the model. `With.Update("name")` works the same way for arbitrary fields, and the payload type must match `model[name]`.
842
+ `context.with.invert` only compiles when the leaf at the path is a boolean on the model; sibling helpers cover other common shapes:
843
+
844
+ - `context.with.update(key)` &mdash; binds the dispatched payload to a model leaf; the payload type must match `Get<Model, key>`.
845
+ - `context.with.always(key, value)` &mdash; pins the leaf to a fixed value, ignoring any dispatched payload. Handy for Open/Close, Show/Hide pairs where each action pins the same field to a known value.
846
+
847
+ All three accept lodash-style dotted paths (`"a.b.c"`) and array indices (`"items.0.name"`); keys autocomplete from the model declared on `useContext<Model, …>()`. The top-level `With.Update` / `With.Invert` / `With.Always` import is kept for call sites that don't have a typed `context` in scope.
@@ -20,7 +20,7 @@ import { Model, Props, Actions, UseActions } from '../types/index';
20
20
  * @template M The model type representing the component's state.
21
21
  * @template AC The actions class containing action definitions.
22
22
  * @template D The data type for reactive external values.
23
- * @param initialModel The initial model state.
23
+ * @param model The initial model state.
24
24
  * @param getData Optional function that returns reactive values as data.
25
25
  * Values returned are accessible via `context.data` in action handlers,
26
26
  * always reflecting the latest values even after await operations.
@@ -39,8 +39,8 @@ import { Model, Props, Actions, UseActions } from '../types/index';
39
39
  * Model,
40
40
  * typeof Actions,
41
41
  * { query: string }
42
- * >(initialModel, () => ({ query: props.query }));
42
+ * >(model, () => ({ query: props.query }));
43
43
  * ```
44
44
  */
45
45
  export declare function useActions<M extends void = void, A extends Actions | void = void, D extends Props = Props>(getData?: Data<D>): UseActions<M, A, D>;
46
- export declare function useActions<M extends Model, A extends Actions | void = void, D extends Props = Props>(initialModel: M, getData?: Data<D>): UseActions<M, A, D>;
46
+ export declare function useActions<M extends Model, A extends Actions | void = void, D extends Props = Props>(model: M, getData?: Data<D>): UseActions<M, A, D>;
@@ -2,6 +2,7 @@ import { Env } from '../boundary/components/env/index';
2
2
  import { Actions, Model, Props } from '../types/index';
3
3
  import { Scope } from '../scope/index';
4
4
  import { AppContextHandle, AppResource } from './types';
5
+ import { Tap } from '../boundary/components/tap/types';
5
6
  import * as React from "react";
6
7
  export type { AppArgs, AppContextHandle, AppFetcher, AppResource, } from './types';
7
8
  /**
@@ -10,15 +11,20 @@ export type { AppArgs, AppContextHandle, AppFetcher, AppResource, } from './type
10
11
  */
11
12
  export type App<S extends object> = {
12
13
  /**
13
- * Boundary component for this App. Wraps the subtree with the initial
14
- * `env` value passed to {@link App}.
14
+ * Boundary component for this App. By default, wraps the subtree with
15
+ * the `env` and `tap` passed to {@link App}; either can be overridden
16
+ * at the call site via the corresponding prop, which is useful when a
17
+ * single `App` definition is rendered against different envs in tests
18
+ * or storybooks.
15
19
  */
16
20
  readonly Boundary: React.FC<{
21
+ env?: S;
22
+ tap?: Tap;
17
23
  children: React.ReactNode;
18
24
  }>;
19
25
  /**
20
26
  * Hook returning a stable `Context` handle. The handle's
21
- * `context.useActions(initialModel?, getData?)` materialises the
27
+ * `context.useActions(model?, getData?)` materialises the
22
28
  * component's `[model, actions, data]` tuple. Every handler's
23
29
  * `context.env` is typed as `S`.
24
30
  */
@@ -62,17 +68,30 @@ export type App<S extends object> = {
62
68
  * Each `<app.Boundary>` instance owns its own Env, so different `App`s
63
69
  * can coexist in the same tree with completely independent shapes.
64
70
  *
71
+ * Pass `tap` to subscribe to every action handler's dispatch / settle /
72
+ * error inside the boundary &mdash; useful for analytics, audit logging,
73
+ * Sentry breadcrumbs. See `recipes/tap.md`. Both `env` and `tap` can
74
+ * also be supplied as props on `<app.Boundary>`, where they override the
75
+ * defaults set at `App()` time (handy for test renders and storybooks).
76
+ *
65
77
  * @example
66
78
  * ```tsx
67
- * import { App } from "march-hare";
79
+ * import { App, type Tapped } from "march-hare";
68
80
  *
69
81
  * type Session = { accessToken: string };
70
82
  *
83
+ * function tap(event: Tapped) {
84
+ * if (event.type === "error") {
85
+ * Sentry.captureException(event.error, { tags: { action: event.action } });
86
+ * }
87
+ * }
88
+ *
71
89
  * export const app = App({
72
90
  * env: {
73
91
  * session: null as Session | null,
74
92
  * operating: "idle" as "idle" | "signing-out",
75
93
  * },
94
+ * tap,
76
95
  * });
77
96
  *
78
97
  * // Root render.
@@ -108,5 +127,6 @@ export type App<S extends object> = {
108
127
  * ```
109
128
  */
110
129
  export declare function App<S extends object = Env>(config?: {
111
- env: S;
130
+ env?: S;
131
+ tap?: Tap;
112
132
  }): App<S>;
@@ -2,6 +2,8 @@ import { Args, ResourceHandle } from '../resource/types';
2
2
  import { Cache } from '../cache/index';
3
3
  import { Actions, Context, Model, Props, UseActions } from '../types/index';
4
4
  import { Data } from '../actions/types';
5
+ import { Env } from '../boundary/components/env/index';
6
+ import { WithHandle } from '../with/index';
5
7
  /**
6
8
  * Args object passed to an `app.Resource` fetcher. Same shape as the
7
9
  * base `Resource` fetcher's args but with `env` typed as `S`.
@@ -25,25 +27,56 @@ export type AppResource<S> = {
25
27
  readonly Cachable: <T, P extends object = Record<never, never>>(cache: Cache, fetcher: AppFetcher<S, T, P>) => ResourceHandle<T, P>;
26
28
  };
27
29
  /**
28
- * Phantom marker so consumers of the App's hooks see `env: S` typing
29
- * at the type-system level; at runtime the value is the same proxy as
30
- * the loose `Env` type.
31
- *
32
- * @internal
30
+ * Tuple shape returned by `context.useActions(...)` on an App-bound
31
+ * Context. Re-exports the base {@link UseActions} with the App's `S`
32
+ * threaded through every `HandlerContext` and produce draft.
33
33
  */
34
- type EnvView<S> = {
35
- readonly __appEnv?: S;
36
- };
37
- type AppActionsResult<M, AC, D, S> = UseActions<M extends Model | void ? M : void, AC extends Actions | void ? AC : void, D extends Props ? D : Props> & EnvView<S>;
38
- type AppUseActions<M, AC, D, S> = M extends void ? (getData?: Data<D & Props>) => AppActionsResult<M, AC, D, S> : (initialModel: M, getData?: Data<D & Props>) => AppActionsResult<M, AC, D, S>;
34
+ type AppActionsResult<M, AC, D, S> = UseActions<M extends Model | void ? M : void, AC extends Actions | void ? AC : void, D extends Props ? D : Props, S extends Env ? S : Env>;
35
+ /**
36
+ * `useActions(...)` signature on the App-bound Context. Has two forms:
37
+ * void-model components omit the model argument entirely; everyone else
38
+ * passes their initial model as the first argument and an optional data
39
+ * callback as the second.
40
+ */
41
+ type AppUseActions<M, AC, D, S> = M extends void ? (getData?: Data<D & Props>) => AppActionsResult<M, AC, D, S> : (model: M, getData?: Data<D & Props>) => AppActionsResult<M, AC, D, S>;
39
42
  /**
40
43
  * `Context` handle returned by `app.useContext()`. Mirrors the base
41
- * {@link Context} but with the Env-typed slots overridden to `S`.
44
+ * {@link Context} but threads the App's Env shape `S` through every
45
+ * handler's `context.env` and produce draft.
46
+ *
47
+ * @template M The model type for the component's state, or `void`.
48
+ * @template AC The actions class containing this component's action
49
+ * definitions, or `void` for actions-only consumers.
50
+ * @template D The reactive data type returned from the `useActions(...)`
51
+ * data callback.
52
+ * @template S The App's Env shape, supplied at `App({env})` time.
42
53
  */
43
54
  export type AppContextHandle<M, AC, D, S> = {
55
+ /**
56
+ * Stable dispatch surface available before `useActions(...)` runs.
57
+ * Exposes only `dispatch(action, payload?)` &mdash; useful when an
58
+ * external imperative library needs a dispatch callback at construction
59
+ * time. Inside handlers, prefer `context.actions.dispatch` for the same
60
+ * call.
61
+ */
44
62
  readonly actions: {
45
63
  dispatch: Context<M extends Model | void ? M : void, AC extends Actions | void ? AC : void, D extends Props ? D : Props>["actions"]["dispatch"];
46
64
  };
65
+ /**
66
+ * Typed bag of handler factories bound to `M`. Methods accept
67
+ * lodash-style dotted paths and array indices; keys autocomplete from
68
+ * the model declared on `app.useContext<Model, …>()`. See
69
+ * {@link WithHandle}.
70
+ */
71
+ readonly with: WithHandle<M extends Model | void ? M : void>;
72
+ /**
73
+ * Materialises the component-local model and reactive data, returning
74
+ * the `[model, actions, data]` tuple with `useAction`, `dispatch`,
75
+ * `inspect`, and `stream` attached. Pass the initial model as the first
76
+ * argument (unless `M` is `void`) and an optional data callback as the
77
+ * second &mdash; the callback re-runs every render so handlers reading
78
+ * `context.data` always see fresh values across `await` boundaries.
79
+ */
47
80
  readonly useActions: AppUseActions<M, AC, D, S>;
48
81
  };
49
82
  export {};
@@ -0,0 +1,36 @@
1
+ import { Props } from './types';
2
+ import * as React from "react";
3
+ export { useTap } from './utils';
4
+ export type { Tap, Tapped, Invocation, Failure, Mutations, Snapshot, } from './types';
5
+ /**
6
+ * Internal provider that wires a {@link Tap} observer into the React
7
+ * context consumed by `useActions` during dispatch. Rendered by the
8
+ * top-level `<Boundary>` (and indirectly by `<app.Boundary>`); not
9
+ * exposed on the public surface &mdash; consumers should pass the
10
+ * callback via the `tap` prop of either boundary instead of mounting
11
+ * this provider directly.
12
+ *
13
+ * The supplied `tap` callback is held in a `useRef` and indirected
14
+ * through a stable `useMemo` wrapper. The ref is synchronised inside a
15
+ * `useLayoutEffect` &mdash; React's sanctioned write-after-commit
16
+ * window &mdash; so the provider stays compatible with Concurrent
17
+ * rendering, where the render function may be invoked more than once
18
+ * per commit and direct mutation during render would race the
19
+ * scheduler.
20
+ *
21
+ * Keeping the context value referentially constant for the lifetime of
22
+ * the boundary means callers may pass inline arrow functions without
23
+ * invalidating the dispatch pipeline on every render &mdash; the
24
+ * latest callback is read at fire time, not at provider-render time.
25
+ * When `tap` is `undefined`, the wrapper short-circuits via optional
26
+ * chaining: no allocation per event beyond the wrapper call itself.
27
+ *
28
+ * @param props.tap Observer to receive lifecycle events for every action
29
+ * handler dispatched inside the boundary. See {@link Tap}.
30
+ * @param props.children Subtree that should observe the supplied tap.
31
+ * @returns Children rendered inside the tap context provider.
32
+ *
33
+ * @see {@link Tap} &mdash; the observer signature.
34
+ * @see {@link Tapped} &mdash; the discriminated union of event shapes.
35
+ */
36
+ export declare function Tappable({ tap, children }: Props): React.ReactNode;
@@ -0,0 +1,150 @@
1
+ import { Reason } from '../../../error/types';
2
+ import { Task } from '../tasks/types';
3
+ import type * as React from "react";
4
+ /**
5
+ * Identity of a handler invocation: the action being handled and the
6
+ * payload supplied at dispatch. Appears on every {@link Tapped} event
7
+ * as `event.action`, alongside the `stage` / `result` discriminators.
8
+ */
9
+ export type Invocation = {
10
+ /** Human-readable name of the action being handled. */
11
+ readonly name: string;
12
+ /** Payload supplied at dispatch (typed `unknown`; cast at the call site). */
13
+ readonly payload: unknown;
14
+ };
15
+ /**
16
+ * Failure fields layered onto the `details` sub-object of the
17
+ * `end:error` variant of {@link Tapped}. Groups the thrown error with
18
+ * the {@link Reason} the dispatch pipeline classified it as &mdash;
19
+ * consumers branching on `Aborted` vs. `Errored` read both off the
20
+ * same place. The error variant's `details` is `Failure` merged with
21
+ * the common end-of-handler shape (`{ mutations }`), so a helper that
22
+ * takes a `Failure` accepts the error-variant `details` directly.
23
+ */
24
+ export type Failure = {
25
+ /** The Error instance thrown by the handler (or the abort cause). */
26
+ readonly error: Error;
27
+ /** Library classification of the failure: `Aborted` or `Errored`. */
28
+ readonly reason: Reason;
29
+ };
30
+ /**
31
+ * Reference snapshot for a single mutation surface (model or env)
32
+ * captured at handler start and end. The library compares references
33
+ * &mdash; Immer / Immertation produce a new reference iff a `produce`
34
+ * call actually committed a change, so reference inequality is a
35
+ * precise "did something change" signal with no deep-diff cost.
36
+ *
37
+ * Consumers diff `before` against `after` themselves (using the
38
+ * library's `changes` helper, a third-party diff lib, or a custom
39
+ * walk) when they need the per-field delta.
40
+ */
41
+ export type Snapshot<T> = {
42
+ readonly before: T;
43
+ readonly after: T;
44
+ };
45
+ /**
46
+ * Per-handler summary of which mutation surfaces changed during the
47
+ * invocation. `null` on a surface means "reference unchanged" &mdash;
48
+ * the handler did not commit any `produce` call that touched that
49
+ * surface. A non-null value carries the before/after references.
50
+ *
51
+ * Values are typed `unknown` at this seam because the library doesn't
52
+ * know the model or env shape; cast inside the tap callback at the
53
+ * boundary where you know your `App`'s typed shape.
54
+ *
55
+ * Note on nested dispatches: if a handler awaits a sibling dispatch
56
+ * that itself mutates the same surface, the outer handler's
57
+ * `mutations` reflects the net change observed across its lifetime
58
+ * &mdash; including downstream effects. This is usually what you want
59
+ * for tracing; if you need to attribute changes to the originating
60
+ * handler precisely, branch on the `action` field as well.
61
+ */
62
+ export type Mutations = {
63
+ readonly model: Snapshot<unknown> | null;
64
+ readonly env: Snapshot<unknown> | null;
65
+ };
66
+ /**
67
+ * Lifecycle event published by the tap. One pair of events is emitted
68
+ * per handler invocation, not per dispatch &mdash; a broadcast that
69
+ * reaches five subscribers produces five `start` events plus one `end`
70
+ * event per subscriber.
71
+ *
72
+ * The shape is a two-level discrimination:
73
+ *
74
+ * - **`stage`** &mdash; `"start"` (handler just began) or `"end"`
75
+ * (handler completed).
76
+ * - **`result`** &mdash; on `end` only, `"success"` or `"error"`
77
+ * describing the outcome. Mutually exclusive: the same handler
78
+ * invocation never produces both a success and an error.
79
+ *
80
+ * Per handler, exactly one of these two pairs is emitted:
81
+ * - **Succeeded:** `stage: "start"` &rarr; `stage: "end", result: "success"`.
82
+ * - **Failed:** `stage: "start"` &rarr; `stage: "end", result: "error"`.
83
+ *
84
+ * The {@link Invocation} identity (`action`, `payload`) and the
85
+ * discriminators (`stage`, `result`) sit at the top level so consumers
86
+ * can route and label events without diving into `details`. Everything
87
+ * else &mdash; the task handle, timing, mutation summary, failure
88
+ * info &mdash; lives on the `details` sub-object.
89
+ *
90
+ * `start` events carry just the {@link Task} in `details`;
91
+ * `end:success` adds `elapsed` and {@link Mutations}; `end:error`
92
+ * adds those plus the {@link Failure} fields.
93
+ *
94
+ * `elapsed` is measured in milliseconds against `performance.now()`,
95
+ * captured the moment the `end` event fires.
96
+ */
97
+ export type Tapped = {
98
+ /** Action being handled: `{ name, payload }`. */
99
+ readonly action: Invocation;
100
+ } & ({
101
+ readonly stage: "start";
102
+ readonly details: {
103
+ readonly task: Task;
104
+ };
105
+ } | {
106
+ readonly stage: "end";
107
+ readonly result: "success";
108
+ readonly details: {
109
+ readonly task: Task;
110
+ readonly elapsed: number;
111
+ readonly mutations: Mutations;
112
+ };
113
+ } | {
114
+ readonly stage: "end";
115
+ readonly result: "error";
116
+ readonly details: Failure & {
117
+ readonly task: Task;
118
+ readonly elapsed: number;
119
+ readonly mutations: Mutations;
120
+ };
121
+ });
122
+ /**
123
+ * Observer callback invoked for every action handler lifecycle event
124
+ * inside the surrounding `<Boundary>`. Synchronous &mdash; do not
125
+ * perform expensive or async work here; defer to a queue, ring buffer,
126
+ * or external transport if the receiver is slow.
127
+ *
128
+ * Tap is intended for cross-cutting observability concerns: analytics,
129
+ * audit logging, browser-extension devtools, Sentry breadcrumbs,
130
+ * replay traces for bug reports. Use {@link Lifecycle.Fault} for
131
+ * in-band error recovery; the two are independent.
132
+ */
133
+ export type Tap = (event: Tapped) => void;
134
+ /**
135
+ * Props accepted by the internal {@link Tappable} provider. The provider
136
+ * stores the supplied `tap` callback behind a ref so a parent re-render
137
+ * that changes the callback identity does not invalidate the React
138
+ * context value &mdash; every dispatch reads the latest callback at
139
+ * fire time.
140
+ */
141
+ export type Props = {
142
+ /**
143
+ * Observer invoked for every action handler lifecycle event inside
144
+ * the surrounding `<Boundary>`. Omit (or pass `undefined`) to
145
+ * disable observation &mdash; the dispatch path then pays only the
146
+ * cost of a single function call per handler invocation.
147
+ */
148
+ tap?: Tap;
149
+ children: React.ReactNode;
150
+ };
@@ -0,0 +1,14 @@
1
+ import { Tap } from './types';
2
+ import * as React from "react";
3
+ /**
4
+ * React context carrying the active {@link Tap} observer for the
5
+ * surrounding `<Boundary>`. Defaults to a no-op so `useTap()` callers
6
+ * never need to null-check.
7
+ */
8
+ export declare const Context: React.Context<Tap>;
9
+ /**
10
+ * Hook returning the active tap observer. Always returns a callable
11
+ * &mdash; if no `<Boundary tap={...}>` is mounted above, calls are
12
+ * silent no-ops with no allocation cost beyond the function call itself.
13
+ */
14
+ export declare function useTap(): Tap;
@@ -18,4 +18,4 @@ import * as React from "react";
18
18
  * </Boundary>
19
19
  * ```
20
20
  */
21
- export declare function Boundary({ env, children }: Props): React.ReactNode;
21
+ export declare function Boundary({ env, tap, children }: Props): React.ReactNode;
@@ -1,12 +1,54 @@
1
1
  import { Env } from './components/env/types';
2
+ import { Tap } from './components/tap/types';
2
3
  import type * as React from "react";
4
+ /**
5
+ * Props accepted by the bare `<Boundary>` provider.
6
+ *
7
+ * Most applications declare these once via {@link App} and let the
8
+ * generated `<app.Boundary>` thread them through &mdash; the bare
9
+ * Boundary is exposed for advanced use (custom wrappers, isolated test
10
+ * renders) where the loose {@link Env} record type is sufficient and
11
+ * the typed `app.useContext` / `app.useEnv` surface isn't needed.
12
+ *
13
+ * All fields are optional. Omit them all and the Boundary still wraps
14
+ * its subtree with the Broadcaster, Env, Tasks, and Tap providers
15
+ * required by every March Hare hook &mdash; just with a default empty
16
+ * env and a no-op tap.
17
+ */
3
18
  export type Props = {
4
19
  /**
5
20
  * Initial value of the per-Boundary {@link Env}. Prefer `App({ env })`
6
- * &mdash; it infers the Env shape and threads it through `app.useContext`,
7
- * `app.useEnv`, and `app.Resource`. Pass `env` directly here only for
8
- * advanced cases where the loose {@link Env} record type is sufficient.
21
+ * &mdash; it infers the Env shape `S` and threads it through
22
+ * `app.useContext`, `app.useEnv`, and `app.Resource`, so handler
23
+ * `context.env` is typed accordingly. Pass `env` directly here only
24
+ * for advanced cases where the loose record type is sufficient.
25
+ *
26
+ * The value is captured on mount; subsequent prop updates do not
27
+ * replace the live env. Mutations during the boundary's lifetime
28
+ * flow through `context.actions.produce(({ env }) => { ... })`.
9
29
  */
10
30
  env?: Env;
31
+ /**
32
+ * Observer invoked for every action handler lifecycle event inside
33
+ * this Boundary. One event fires per handler invocation, not per
34
+ * dispatch &mdash; a broadcast that reaches five subscribers
35
+ * produces five `dispatch` events, five `settle` events, and an
36
+ * `error` event for any of the five that throws.
37
+ *
38
+ * The callback is synchronous: it blocks the dispatch path until it
39
+ * returns. Defer slow work (network transports, file IO) to a queue
40
+ * or idle callback rather than running it inline.
41
+ *
42
+ * Typical uses: analytics histograms, audit-log ring buffers,
43
+ * Sentry breadcrumbs, replay traces for bug reports. For in-band
44
+ * error recovery use {@link Lifecycle.Fault} instead &mdash; the two
45
+ * channels are independent. See `recipes/tap.md`.
46
+ */
47
+ tap?: Tap;
48
+ /**
49
+ * Subtree that should receive the boundary's broadcast, env, tasks,
50
+ * and tap providers. Every March Hare hook called inside this
51
+ * subtree resolves against this boundary's context.
52
+ */
11
53
  children: React.ReactNode;
12
54
  };
@@ -6,15 +6,17 @@ import { Actions, Context as ContextHandle, Model, Props } from '../types/index'
6
6
  * dispatch callback at construction time, while the value that library
7
7
  * returns must flow back into the controller's data callback.
8
8
  *
9
- * The handle exposes `dispatch(action, payload?)` and a `useActions(...)`
9
+ * The handle exposes `dispatch(action, payload?)`, a `useActions(...)`
10
10
  * method that materialises the component-local model and reactive data
11
11
  * &mdash; the M and D pair of `useContext<M, AC, D>` &mdash; and
12
12
  * returns the `[model, actions, data]` tuple with `useAction`, `dispatch`,
13
- * `inspect`, and `stream` attached. The first invocation of
14
- * `context.actions.dispatch(...)` must come from an event handler &mdash; not
15
- * synchronously during render &mdash; because the underlying dispatch
16
- * target is wired up when `context.useActions(...)` runs in the same
17
- * render pass.
13
+ * `inspect`, and `stream` attached, plus `with` &mdash; a bag of handler
14
+ * factories (`update`/`invert`/`always`) typed against the declared model
15
+ * and accepting lodash-style dotted paths and array indices. The first
16
+ * invocation of `context.actions.dispatch(...)` must come from an event
17
+ * handler &mdash; not synchronously during render &mdash; because the
18
+ * underlying dispatch target is wired up when `context.useActions(...)`
19
+ * runs in the same render pass.
18
20
  *
19
21
  * @template M The model type representing the component's state.
20
22
  * @template AC The actions class containing action definitions.
package/dist/index.d.ts CHANGED
@@ -13,3 +13,4 @@ export type { Fault } from './error/index';
13
13
  export type { Adapter } from './cache/index';
14
14
  export type { Box } from 'immertation';
15
15
  export type { Pk, Task, Tasks, Maybe, Handler, Handlers, } from './types/index';
16
+ export type { Tap, Tapped, Invocation, Failure, Mutations, Snapshot, } from './boundary/components/tap/types';
@@ -1,7 +1,8 @@
1
1
  import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{G as n,A as r}from"@mobily/ts-belt";import{immerable as o,enablePatches as s,Immer as c,produce as a}from"immer";function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var u,l={exports:{}};const f=/* @__PURE__ */i((u||(u=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 s(e,t,r,s,c){if("function"!=typeof r)throw new TypeError("The listener must be a function");var a=new o(r,s||e,c),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],a]:e._events[i].push(a):(e._events[i]=a,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function a(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=/* @__PURE__ */Object.create(null),(new r).__proto__||(n=!1)),a.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},a.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,s=new Array(o);r<o;r++)s[r]=t[r].fn;return s},a.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},a.prototype.emit=function(e,t,r,o,s,c){var a=n?n+e:e;if(!this._events[a])return!1;var i,u,l=this._events[a],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,s),!0;case 6:return l.fn.call(l.context,t,r,o,s,c),!0}for(u=1,i=new Array(f-1);u<f;u++)i[u-1]=arguments[u];l.fn.apply(l.context,i)}else{var d,h=l.length;for(u=0;u<h;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(!i)for(d=1,i=new Array(f-1);d<f;d++)i[d-1]=arguments[d];l[u].fn.apply(l[u].context,i)}}return!0},a.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},a.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},a.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return c(this,s),this;var a=this._events[s];if(a.fn)a.fn!==t||o&&!a.once||r&&a.context!==r||c(this,s);else{for(var i=0,u=[],l=a.length;i<l;i++)(a[i].fn!==t||o&&!a[i].once||r&&a[i].context!==r)&&u.push(a[i]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},a.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&c(this,t):(this._events=new r,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=n,a.EventEmitter=a,e.exports=a}(l)),l.exports));class d extends f{cache=/* @__PURE__ */new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}setCache(e,t){this.cache.set(e,t)}getCached(e){return this.cache.get(e)}fire(e,...t){return super.emit(e,...t)}}const h=t.createContext(new d);function p(){return t.useContext(h)}function m({children:n}){const r=t.useMemo(()=>new d,[]);/* @__PURE__ */
2
2
  return e(h.Provider,{value:r,children:n})}const b=t.createContext(/* @__PURE__ */new Set);function y({children:n}){const r=t.useMemo(()=>/* @__PURE__ */new Set,[]);/* @__PURE__ */
3
- return e(b.Provider,{value:r,children:n})}const v=t.createContext({current:{}});function g(){const e=t.useContext(v);return t.useMemo(()=>new Proxy({},{get:(t,n)=>Reflect.get(e.current,n),has:(t,n)=>n in e.current,ownKeys:()=>Reflect.ownKeys(e.current),getOwnPropertyDescriptor(t,r){const o=Object.getOwnPropertyDescriptor(e.current,r);if(!n.isUndefined(o))return{...o,configurable:!0}},set(){throw new TypeError("Env is read-only outside `context.actions.produce`. Mutate via produce(({ env }) => { env.x = ... }) instead.")}}),[e])}const w=(e="")=>`march-hare.action/${e}`,O=(e="")=>`march-hare.action/broadcast/${e}`,P=(e="")=>`march-hare.action/multicast/${e}`,j=(e="")=>`march-hare.action.lifecycle/${e}`;class S{static Payload=/* @__PURE__ */Symbol("march-hare.brand/Payload");static Broadcast=/* @__PURE__ */Symbol("march-hare.brand/Broadcast");static Multicast=/* @__PURE__ */Symbol("march-hare.brand/Multicast");static Action=/* @__PURE__ */Symbol("march-hare.brand/Action");static Channel=/* @__PURE__ */Symbol("march-hare.brand/Channel");static Name=/* @__PURE__ */Symbol("march-hare.brand/Name")}function x(e){const t=/* @__PURE__ */Symbol(`march-hare.action.lifecycle/${e}`),n=function(n){return{[S.Action]:t,[S.Payload]:void 0,[S.Channel]:n,[S.Name]:e,channel:n}};return Object.defineProperty(n,S.Action,{value:t,enumerable:!1}),Object.defineProperty(n,S.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(n,S.Name,{value:e,enumerable:!1}),n}const E=Symbol(O("Fault")),C=Symbol(O("Env"));class N{static Mount(){return x("Mount")}static Unmount(){return x("Unmount")}static Error(){return x("Error")}static Update(){return x("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,S.Action,{value:E,enumerable:!1}),Object.defineProperty(e,S.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,S.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,S.Name,{value:"Fault",enumerable:!1}),e})();static Env=(()=>{const e={};return Object.defineProperty(e,S.Action,{value:C,enumerable:!1}),Object.defineProperty(e,S.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,S.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,S.Name,{value:"Env",enumerable:!1}),e})()}var M=/* @__PURE__ */(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(M||{}),k=/* @__PURE__ */(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(k||{});function A({initial:r,children:o}){const s=t.useRef(r),c=p();return n.isUndefined(c.getCached(C))&&c.setCache(C,s.current),/* @__PURE__ */e(v.Provider,{value:s,children:o})}const _=t.createContext(/* @__PURE__ */new WeakMap);function U({children:n}){const r=t.useMemo(()=>/* @__PURE__ */new WeakMap,[]);/* @__PURE__ */
4
- return e(_.Provider,{value:r,children:n})}function R({env:t,children:n}){/* @__PURE__ */
5
- return e(m,{children:/* @__PURE__ */e(A,{initial:t??{},children:/* @__PURE__ */e(y,{children:/* @__PURE__ */e(U,{children:n})})})})}const L=e=>"symbol"==typeof e;function T(e){return n.isString(e)||L(e)?e:(n.isObject(e)||n.isFunction(e))&&S.Action in e?e[S.Action]:e}function W(e){if(n.isString(e))return e.startsWith(O());if(L(e))return e.description?.startsWith(O())??!1;if(n.isObject(e)||n.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(O())??!1}}return!1}function $(e){const t=T(e),r=n.isString(t)?t:t.description??"";return r.startsWith(w())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function B(e){return n.isObject(e)&&S.Channel in e&&"channel"in e}function F(e){const t=T(e),n=L(t)?t.description??"":t;return n.startsWith(j())&&n.slice(j().length)||null}function D(e){if(n.isString(e))return e.startsWith(P());if(L(e))return e.description?.startsWith(P())??!1;if(n.isObject(e)||n.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())??!1}}return!1}const H=(e="",t=M.Unicast)=>{const n=t===M.Broadcast?Symbol(O(e)):t===M.Multicast?Symbol(P(e)):Symbol(w(e)),r=function(t){return{[S.Action]:n,[S.Payload]:void 0,[S.Channel]:t,[S.Name]:e,channel:t}};return Object.defineProperty(r,S.Action,{value:n,enumerable:!1}),Object.defineProperty(r,S.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(r,S.Name,{value:e,enumerable:!1}),t===M.Broadcast&&Object.defineProperty(r,S.Broadcast,{value:!0,enumerable:!1}),t===M.Multicast&&Object.defineProperty(r,S.Multicast,{value:!0,enumerable:!1}),r},I=Symbol(((e="")=>`march-hare/replay${e}`)());function J(e,t,...n){e instanceof d&&e.setCache(t,n[0]);const r=e.listeners(t);return 0===r.length?Promise.resolve():Promise.all(r.map(e=>Promise.resolve(e(...n)))).then(()=>{})}function z(e,t){for(const n of e.keys())if(F(n)===t)return n;return null}const q=/* @__PURE__ */Symbol("march-hare.unset");function G(){const[,e]=t.useReducer(e=>e+1,0);return e}function K(){return{data:q,at:null,else:e=>e}}function V(e,t){return{data:e,at:t,else:t=>e}}var Q=/* @__PURE__ */(e=>(e[e.Aborted=0]="Aborted",e[e.Errored=1]="Errored",e))(Q||{});class X extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}function Y(e){return e instanceof Error?e:new Error(String(e))}const Z=t.createContext(null);function ee(e){const t=/* @__PURE__ */new Map,r=e??{get:e=>t.get(e)??null,set:(e,n)=>{t.set(e,n)},remove:e=>{t.delete(e)},clear:()=>{t.clear()}};return{get(e){try{const t=r.get(e);if(n.isNull(t))return K();const o=JSON.parse(t);return V(o.data,Temporal.Instant.from(o.at))}catch{return K()}},set(e,t){if(t.data===q||n.isNull(t.at))return!1;try{return r.set(e,JSON.stringify({data:t.data,at:t.at.toString()})),!0}catch{return!1}},remove(e){r.remove(e)},clear(){r.clear()}}}function te(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new X);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new X)},{once:!0})})}async function ne(e,t,n){if(t?.aborted)throw new X;for(;;){if(await n())return;await te(e,t)}}function re(e){return e?Boolean(e&&"symbol"!=typeof e):/* @__PURE__ */Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const oe=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,pk:re,poll:ne,sleep:te,unset:q,"ζ":te,"κ":re,"π":ne},Symbol.toStringTag,{value:"Module"})),se=/* @__PURE__ */new WeakMap;function ce(e){return JSON.stringify(e)}let ae=null;function ie(){if(n.isNull(ae))throw new Error("context.actions.resource(...) and context.actions.resource.set(...) must be called with a fresh resource invocation, e.g. context.actions.resource(resource.cat({ id: 5 })).");const e=ae;return ae=null,e}function ue(e,t){const r=e=>{const r=t.get(ce(e));return r.data===q||n.isNull(r.at)?{data:q,at:null}:{data:r.data,at:r.at}},o=(n,r,o,s)=>e({env:n,controller:r,params:o,dispatch:s}).then(e=>(t.set(ce(o),V(e,Temporal.Now.instant())),e)),s=(e,n,r)=>{t.set(ce(e),V(n,r))};return function(e){const t=e??{};ae={run:o,read:r,seed:s,params:t},queueMicrotask(()=>{n.isNotNullable(ae)&&ae.params===t&&(ae=null)});const{data:c}=r(t);return c===q?null:c}}function le(e){return ue(e,function(e){let t=se.get(e);return n.isUndefined(t)&&(t=ee(),se.set(e,t)),t}(e))}(le||(le={})).Cachable=function(e,t){return ue(t,e)};const fe=/* @__PURE__ */Symbol("march-hare.coalesce/default");function de(e,t){return new Promise((n,r)=>{if(t.aborted)return void r(t.reason);const o=()=>r(t.reason);t.addEventListener("abort",o,{once:!0}),e.then(e=>{t.removeEventListener("abort",o),n(e)},e=>{t.removeEventListener("abort",o),r(e)})})}let he=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var pe=/* @__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))(pe||{}),me=/* @__PURE__ */(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(me||{}),be=/* @__PURE__ */(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(be||{});class ye{[o]=!0;static keys=new Set(Object.values(be));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new ye(this.value,this.operation);return n.property=e,n.process=t,n}}class ve{static immer=(()=>{s();const e=new c;return e.setAutoFreeze(!1),e})();static tag="κ";static id=he}function ge(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 we(e){if(n.isNullable(e)||je(e))return e;if(n.isArray(e))return e.map(e=>we(e));if(n.isObject(e)&&Pe(e)){const t=Object.entries(e).map(([e,t])=>[e,we(t)]);return{...Object.fromEntries(t),[ve.tag]:e[ve.tag]??ve.id()}}return e}function Oe(e){if(Array.isArray(e))return e.filter(e=>ve.tag in e).map(e=>e[ve.tag]??"").join(",");const t=e[ve.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function Pe(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function je(e){return n.isNullable(e)||n.isString(e)||n.isNumber(e)||n.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function Se(e,t,r,o,s,c){return function a(i,u=t.path){if(i instanceof ye){const t=ge(r,u.join("."));if(Object.entries(i).filter(([e,t])=>!ye.keys.has(e)&&t instanceof ye).forEach(([e,t])=>a(t,u.concat(e))),je(i.value)){if(e===me.Hydrate)return i.value;const a=u.slice(0,-1),l=a.length>0?ge(r,a.join(".")):r;return n.isNullable(l)||xe(l,i,u.at(-1),o,s,c),t??i.value}if(e===me.Hydrate){const e=we(a(i.value,u));return xe(e,i,null,o,s,c),e}const l=t??we(i.value);return xe(l,i,null,o,s,c),n.isNullable(t)?l:(a(i.value,u),t)}if(n.isArray(i))return i.map((e,t)=>a(e,u.concat(t)));if(n.isObject(i)&&!Pe(i))return i;if(n.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,a(t,u.concat(e))]),n=Object.fromEntries(t);if(e===me.Hydrate){const e=we(n);return Object.entries(i).forEach(([t,n])=>{n instanceof ye&&je(n.value)&&xe(e,n,t,o,s,c)}),e}return n}return i}(t.value)}function xe(e,t,n,r,o,s){const c=s(e),a=o.get(c)??[];o.set(c,[t.assign(n,r),...a])}class Ee{#e={};#t;#n=/* @__PURE__ */new Map;#r=/* @__PURE__ */new Set;#o=!1;constructor(e=Oe){this.#t=e}static pk(){return he()}static"κ"=Ee.pk;annotate(e,t){return new ye(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,t,o,s,c){function a(s){const c=s.at(-1),a=ge(e(),s),i=s.slice(0,-1),u=r.isNotEmpty(i)?ge(e(),i):e();return[...n.isObject(a)||n.isArray(a)?t.get(o(a))?.filter(e=>n.isNullable(e.property))??[]:[],...n.isObject(u)?t.get(o(u))?.filter(e=>e.property===c)??[]:[]]}return function t(n){return new Proxy(()=>{},{get:(o,i)=>"pending"===i?()=>!r.isEmpty(a(n)):"remaining"===i?()=>r.length(a(n)):"box"===i?()=>({value:ge(e(),n),inspect:t(n)}):"is"===i?e=>a(n).some(t=>0!==(t.operation&e)):"draft"===i?()=>r.head(a(n))?.value??ge(e(),n):"settled"===i?()=>new Promise(t=>{if(r.isEmpty(a(n)))return t(ge(e(),n));const o=()=>{r.isEmpty(a(n))&&(c(o),t(ge(e(),n)))};s(o)}):t([...n,String(i)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(me.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(me.Produce,e)}#s(e,t){const n=/* @__PURE__ */Symbol("process"),[,r]=ve.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>ve.immer.applyPatches(t,[{...r,value:Se(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=we(this.#e),this.#c(),n}prune(e){this.#n.forEach((t,n)=>{const o=t.filter(t=>t.process!==e);r.isEmpty(o)?this.#n.delete(n):this.#n.set(n,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const Ce=t.createContext(/* @__PURE__ */new Map);function Ne({action:e,renderer:r}){const o=p(),s=t.useContext(Ce),c=G(),a=t.useMemo(()=>{const t=s.get(e);if(t)return t;const r=new Ee,c=o.getCached(e);n.isNotNullable(c)&&r.hydrate({value:c});const a={state:r,listeners:/* @__PURE__ */new Set};return s.set(e,a),a},[e,o,s]);t.useLayoutEffect(()=>{function t(e){a.state.hydrate({value:e}),a.listeners.forEach(e=>e())}return a.listeners.add(c),o.on(e,t),()=>{a.listeners.delete(c),o.off(e,t)}},[e,o,a]);const i=a.state.model?.value;return n.isNullable(i)?null:r(i,a.state.inspect.value)}function Me(){const e=t.useRef(null);return t.useMemo(()=>({actions:{dispatch:function(t,n){const r=e.current;if(!r)throw new Error("march-hare: useContext handle dispatched before its paired context.useActions(...) ran. Call context.actions.dispatch from event handlers, not synchronously during render.");return r(t,n)}},useActions:function(...o){const s=function(...e){const o=n.isUndefined(e[0])||n.isFunction(e[0])?{}:e[0],s=n.isFunction(e[0])?e[0]:e[1]??(()=>({})),c=p(),i=t.useContext(Z),u=t.useContext(b),l=g(),d=t.useContext(v),h=t.useContext(_),m=G(),y=t.useRef(!1),w=t.useRef(null),O=t.useRef(new Ee);y.current||(y.current=!0,w.current=O.current.hydrate(o));const[P,j]=t.useState(()=>O.current.model),S=function(e){const n=t.useRef(e);return n.current=e,t.useMemo(()=>{return t=n,Object.keys(e).reduce((e,n)=>(Object.defineProperty(e,n,{get:()=>t.current[n],enumerable:!0}),e),{});var t},[e])}(s()),x=t.useMemo(()=>new f,[]),N=t.useRef({handlers:/* @__PURE__ */new Map});N.current.handlers=/* @__PURE__ */new Map;const M=function(){const e=t.useRef(/* @__PURE__ */new Set),n=t.useRef(/* @__PURE__ */new Set);return t.useMemo(()=>({broadcast:e.current,multicast:n.current}),[])}(),A=t.useRef(k.Mounting),U=t.useRef(/* @__PURE__ */new Set),R=t.useRef(0),L=t.useCallback((e,t,r)=>{const o=new AbortController,s={controller:o,action:e,payload:t};return u.add(s),U.current.add(s),{model:O.current.model,get phase(){return A.current},task:s,data:S,tasks:u,env:l,actions:{produce(e){if(o.signal.aborted)return;const t=d.current,n=O.current.produce(t=>{d.current=a(d.current,n=>{e({model:t,inspect:O.current.inspect,env:n})})});j(O.current.model),d.current!==t&&c.emit(C,d.current),r.processes.add(n),w.current&&(r.processes.add(w.current),w.current=null)},dispatch(e,t){if(o.signal.aborted)return Promise.resolve();const n=T(e),r=B(e)?e.channel:void 0;return D(e)?i?J(i.emitter,n,t,r):Promise.resolve():J(W(e)?c:x,n,t,r)},annotate:(e,t=pe.Update)=>O.current.annotate(t,e),get inspect(){return O.current.inspect},resource:Object.assign(function(e){const t=ie(),r=(e,t)=>{if(o.signal.aborted)return Promise.resolve();const n=e,r=T(n);return D(n)?i?J(i.emitter,r,t,void 0):Promise.resolve():W(n)?J(c,r,t,void 0):Promise.resolve()},s={exceedsWindow:null,coalesceToken:void 0},a={then:(e,c)=>(()=>{if(n.isNotNullable(s.exceedsWindow)){const{data:e,at:r}=t.read(t.params);if(e!==q&&n.isNotNullable(r)){const t=Temporal.Now.instant().since(r),n=Temporal.Duration.from(s.exceedsWindow);if(Temporal.Duration.compare(t,n)<=0)return Promise.resolve(e)}}if(n.isUndefined(s.coalesceToken))return t.run(d.current,o,t.params,r);let e=h.get(t.run);n.isUndefined(e)&&(e=/* @__PURE__ */new Map,h.set(t.run,e));const c=e,a=`${JSON.stringify(t.params)}|${function(e){switch(typeof e){case"string":return`s:${e}`;case"number":return`n:${e}`;case"bigint":return`i:${e.toString()}`;case"boolean":return`b:${e}`;case"symbol":return`y:${e.description??String(e)}`;default:return`o:${JSON.stringify(e)}`}}(s.coalesceToken)}`,i=c.get(a);if(i)return de(i,o.signal);const u=new AbortController,l=t.run(d.current,u,t.params,r).finally(()=>{c.delete(a)});return c.set(a,l),de(l,o.signal)})().then(e,c),exceeds:e=>(s.exceedsWindow=e,a),coalesce:e=>(s.coalesceToken=e??fe,a)};return a},{set:(e,t)=>{const n=ie();n.seed(n.params,t,Temporal.Now.instant())}}),async final(e){if(o.signal.aborted)return null;const t=T(e),r=D(e)?i?.emitter??null:c;if(!r)return null;const s=r.getCached(t);if(n.isUndefined(s))return null;const a=O.current.inspect;return a.pending()&&await new Promise((e,t)=>{if(o.signal.aborted)return void t(o.signal.reason);const n=()=>t(o.signal.reason);o.signal.addEventListener("abort",n,{once:!0}),a.settled().then(()=>{o.signal.removeEventListener("abort",n),e()})}),r.getCached(t)??null},peek(e){if(o.signal.aborted)return null;const t=T(e),n=D(e)?i?.emitter??null:c;return n?n.getCached(t)??null:null}}}},[P]);t.useLayoutEffect(()=>{function e(e,t,r){return function(o,s){const a=r();if(s===I&&n.isNotNullable(a))return;if(n.isNotNullable(s)&&s!==I&&n.isNotNullable(a)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(s,a))return;const i={processes:/* @__PURE__ */new Set},l=Promise.withResolvers(),f=L(e,o,i);function d(t){const r=z(N.current.handlers,"Error"),o=n.isNotNullable(r),s={reason:(a=t,a instanceof Error&&"AbortError"===a.name?Q.Aborted:Q.Errored),error:Y(t),action:$(e),handled:o,tasks:u};var a;c.fire(E,s),o&&r&&x.emit(r,s)}function h(){for(const e of u)if(e===f.task){u.delete(e),U.current.delete(e);break}i.processes.forEach(e=>O.current.prune(e)),i.processes.size>0&&m(),l.resolve()}let p;try{p=t(f,o)}catch(b){return d(b),void h()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(p))return Promise.resolve(p).catch(d).finally(h),l.promise;(async()=>{for await(const e of p);})().catch(d).finally(h)}}R.current++;const t=/* @__PURE__ */new Set;return N.current.handlers.forEach((n,r)=>{for(const{getChannel:o,handler:s}of n){const n=e(r,s,o);if(D(r)){if(i){const e=i.emitter;e.on(r,n),t.add(()=>e.off(r,n))}x.on(r,n),M.multicast.add(r),t.add(()=>x.off(r,n))}else W(r)?(c.on(r,n),x.on(r,n),M.broadcast.add(r),t.add(()=>{c.off(r,n),x.off(r,n)})):(x.on(r,n),t.add(()=>x.off(r,n)))}}),()=>{const e=++R.current,n=new Set(t);queueMicrotask(()=>{if(R.current!==e){for(const e of n)e();return}for(const e of U.current)e.controller.abort(),u.delete(e);U.current.clear(),A.current=k.Unmounting;const t=z(N.current.handlers,"Unmount");t&&x.emit(t),A.current=k.Unmounted;for(const e of n)e()})}},[x]),function({unicast:e,broadcast:o,dispatchers:s,scope:c,phase:a,data:i,handlers:u}){const l=t.useRef(null);t.useLayoutEffect(()=>{if(a.current===k.Mounted)return;a.current=k.Mounting;const t=z(u,"Mount");t&&e.emit(t),s.broadcast.forEach(t=>{const r=o.getCached(t);n.isNullable(r)||e.emit(t,r,I)}),c&&s.multicast.forEach(t=>{const r=c.emitter.getCached(t);n.isNullable(r)||e.emit(t,r,I)}),a.current=k.Mounted},[]),t.useLayoutEffect(()=>{if(n.isNotNullable(l.current)){const t=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(l.current,i);if(r.isNotEmpty(Object.keys(t))){const n=z(u,"Update");n&&e.emit(n,t)}}l.current=i},[i,e])}({unicast:x,broadcast:c,dispatchers:M,scope:i,phase:A,data:s(),handlers:N.current.handlers});const F=t.useMemo(()=>({dispatch(e,t){const n=T(e),r=B(e)?e.channel:void 0;return D(e)?i?J(i.emitter,n,t,r):Promise.resolve():J(W(e)?c:x,n,t,r)},get inspect(){return O.current.inspect},stream:(e,n)=>t.createElement(Ne,{action:T(e),renderer:n})}),[P,x]),H=t.useMemo(()=>[P,F,S],[P,F,S]);return H.useAction=(e,n)=>{!function(e,n,r){const o=t.useRef(r);t.useLayoutEffect(()=>{o.current=r});const s=t.useRef(n);t.useLayoutEffect(()=>{s.current=n});const c=t.useCallback((e,t)=>o.current(e,t),[]),a=t.useCallback(()=>B(s.current)?s.current.channel:void 0,[]),i=T(n),u=e.current.handlers.get(i)??/* @__PURE__ */new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:a,handler:c})}(N,e,n)},H.dispatch=H[1].dispatch,H}(...o);return e.current=s.dispatch,s}}),[])}function ke(n){return{Boundary:function({children:t}){/* @__PURE__ */
6
- return e(R,{env:n?.env,children:t})},useContext:function(){return Me()},useEnv:function(){return g()},Resource:Object.assign(function(e){return le(e)},{Cachable:(e,t)=>le.Cachable(e,t)}),Scope:()=>({Boundary:function({children:n}){const r=t.useMemo(()=>({id:/* @__PURE__ */Symbol("march-hare.scope/instance"),emitter:new d}),[]);/* @__PURE__ */
7
- return e(Z.Provider,{value:r,children:n})},useContext:function(){return Me()},useEnv:function(){return g()},Resource:Object.assign(function(e){return le(e)},{Cachable:(e,t)=>le.Cachable(e,t)})})}}const Ae={Update:e=>(t,n)=>{t.actions.produce(t=>{t.model[e]=n})},Invert:e=>t=>{t.actions.produce(t=>{t.model[e]=!t.model[e]})}},_e=new Ee;function Ue(e,t=pe.Update){return _e.annotate(t,e)}export{X as Aborted,H as Action,ke as App,R as Boundary,ee as Cache,M as Distribution,N as Lifecycle,pe as Op,pe as Operation,Q as Reason,le as Resource,Ee as State,Ae as With,Ue as annotate,oe as utils};
3
+ return e(b.Provider,{value:r,children:n})}const v=t.createContext({current:{}});function g(){const e=t.useContext(v);return t.useMemo(()=>new Proxy({},{get:(t,n)=>Reflect.get(e.current,n),has:(t,n)=>n in e.current,ownKeys:()=>Reflect.ownKeys(e.current),getOwnPropertyDescriptor(t,r){const o=Object.getOwnPropertyDescriptor(e.current,r);if(!n.isUndefined(o))return{...o,configurable:!0}},set(){throw new TypeError("Env is read-only outside `context.actions.produce`. Mutate via produce(({ env }) => { env.x = ... }) instead.")}}),[e])}const w=(e="")=>`march-hare.action/${e}`,O=(e="")=>`march-hare.action/broadcast/${e}`,P=(e="")=>`march-hare.action/multicast/${e}`,j=(e="")=>`march-hare.action.lifecycle/${e}`;class x{static Payload=/* @__PURE__ */Symbol("march-hare.brand/Payload");static Broadcast=/* @__PURE__ */Symbol("march-hare.brand/Broadcast");static Multicast=/* @__PURE__ */Symbol("march-hare.brand/Multicast");static Action=/* @__PURE__ */Symbol("march-hare.brand/Action");static Channel=/* @__PURE__ */Symbol("march-hare.brand/Channel");static Name=/* @__PURE__ */Symbol("march-hare.brand/Name")}function S(e){const t=/* @__PURE__ */Symbol(`march-hare.action.lifecycle/${e}`),n=function(n){return{[x.Action]:t,[x.Payload]:void 0,[x.Channel]:n,[x.Name]:e,channel:n}};return Object.defineProperty(n,x.Action,{value:t,enumerable:!1}),Object.defineProperty(n,x.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(n,x.Name,{value:e,enumerable:!1}),n}const E=Symbol(O("Fault")),C=Symbol(O("Env"));class k{static Mount(){return S("Mount")}static Unmount(){return S("Unmount")}static Error(){return S("Error")}static Update(){return S("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,x.Action,{value:E,enumerable:!1}),Object.defineProperty(e,x.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,x.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,x.Name,{value:"Fault",enumerable:!1}),e})();static Env=(()=>{const e={};return Object.defineProperty(e,x.Action,{value:C,enumerable:!1}),Object.defineProperty(e,x.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,x.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,x.Name,{value:"Env",enumerable:!1}),e})()}var N=/* @__PURE__ */(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(N||{}),M=/* @__PURE__ */(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(M||{});function A({initial:r,children:o}){const s=t.useRef(r),c=p();return n.isUndefined(c.getCached(C))&&c.setCache(C,s.current),/* @__PURE__ */e(v.Provider,{value:s,children:o})}const _=t.createContext(/* @__PURE__ */new WeakMap);function R({children:n}){const r=t.useMemo(()=>/* @__PURE__ */new WeakMap,[]);/* @__PURE__ */
4
+ return e(_.Provider,{value:r,children:n})}const U=t.createContext(()=>{});function L({tap:n,children:r}){const o=t.useRef(n);t.useLayoutEffect(()=>{o.current=n},[n]);const s=t.useMemo(()=>e=>o.current?.(e),[]);/* @__PURE__ */
5
+ return e(U.Provider,{value:s,children:r})}function T({env:t,tap:n,children:r}){/* @__PURE__ */
6
+ return e(m,{children:/* @__PURE__ */e(A,{initial:t??{},children:/* @__PURE__ */e(y,{children:/* @__PURE__ */e(L,{tap:n,children:/* @__PURE__ */e(R,{children:r})})})})})}const W=e=>"symbol"==typeof e;function $(e){return n.isString(e)||W(e)?e:(n.isObject(e)||n.isFunction(e))&&x.Action in e?e[x.Action]:e}function B(e){if(n.isString(e))return e.startsWith(O());if(W(e))return e.description?.startsWith(O())??!1;if(n.isObject(e)||n.isFunction(e)){if(x.Broadcast in e&&e[x.Broadcast])return!0;if(x.Action in e){const t=e[x.Action];return t.description?.startsWith(O())??!1}}return!1}function F(e){return n.isObject(e)&&x.Channel in e&&"channel"in e}function D(e){const t=$(e),n=W(t)?t.description??"":t;return n.startsWith(j())&&n.slice(j().length)||null}function H(e){if(n.isString(e))return e.startsWith(P());if(W(e))return e.description?.startsWith(P())??!1;if(n.isObject(e)||n.isFunction(e)){if(x.Multicast in e&&e[x.Multicast])return!0;if(x.Action in e){const t=e[x.Action];return t.description?.startsWith(P())??!1}}return!1}const I=(e="",t=N.Unicast)=>{const n=t===N.Broadcast?Symbol(O(e)):t===N.Multicast?Symbol(P(e)):Symbol(w(e)),r=function(t){return{[x.Action]:n,[x.Payload]:void 0,[x.Channel]:t,[x.Name]:e,channel:t}};return Object.defineProperty(r,x.Action,{value:n,enumerable:!1}),Object.defineProperty(r,x.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(r,x.Name,{value:e,enumerable:!1}),t===N.Broadcast&&Object.defineProperty(r,x.Broadcast,{value:!0,enumerable:!1}),t===N.Multicast&&Object.defineProperty(r,x.Multicast,{value:!0,enumerable:!1}),r},J=Symbol(((e="")=>`march-hare/replay${e}`)());function z(e,t,...n){e instanceof d&&e.setCache(t,n[0]);const r=e.listeners(t);return 0===r.length?Promise.resolve():Promise.all(r.map(e=>Promise.resolve(e(...n)))).then(()=>{})}function q(e,t){for(const n of e.keys())if(D(n)===t)return n;return null}const G=/* @__PURE__ */Symbol("march-hare.unset");function K(){const[,e]=t.useReducer(e=>e+1,0);return e}function V(){return{data:G,at:null,else:e=>e}}function Q(e,t){return{data:e,at:t,else:t=>e}}var X=/* @__PURE__ */(e=>(e[e.Aborted=0]="Aborted",e[e.Errored=1]="Errored",e))(X||{});class Y extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const Z=t.createContext(null);function ee(e){const t=/* @__PURE__ */new Map,r=e??{get:e=>t.get(e)??null,set:(e,n)=>{t.set(e,n)},remove:e=>{t.delete(e)},clear:()=>{t.clear()}};return{get(e){try{const t=r.get(e);if(n.isNull(t))return V();const o=JSON.parse(t);return Q(o.data,Temporal.Instant.from(o.at))}catch{return V()}},set(e,t){if(t.data===G||n.isNull(t.at))return!1;try{return r.set(e,JSON.stringify({data:t.data,at:t.at.toString()})),!0}catch{return!1}},remove(e){r.remove(e)},clear(){r.clear()}}}function te(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new Y);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new Y)},{once:!0})})}async function ne(e,t,n){if(t?.aborted)throw new Y;for(;;){if(await n())return;await te(e,t)}}function re(e){return e?Boolean(e&&"symbol"!=typeof e):/* @__PURE__ */Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const oe=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,pk:re,poll:ne,sleep:te,unset:G,"ζ":te,"κ":re,"π":ne},Symbol.toStringTag,{value:"Module"})),se=/* @__PURE__ */new WeakMap;function ce(e){return JSON.stringify(e)}let ae=null;function ie(){if(n.isNull(ae))throw new Error("context.actions.resource(...) and context.actions.resource.set(...) must be called with a fresh resource invocation, e.g. context.actions.resource(resource.cat({ id: 5 })).");const e=ae;return ae=null,e}function ue(e,t){const r=e=>{const r=t.get(ce(e));return r.data===G||n.isNull(r.at)?{data:G,at:null}:{data:r.data,at:r.at}},o=(n,r,o,s)=>e({env:n,controller:r,params:o,dispatch:s}).then(e=>(t.set(ce(o),Q(e,Temporal.Now.instant())),e)),s=(e,n,r)=>{t.set(ce(e),Q(n,r))};return function(e){const t=e??{};ae={run:o,read:r,seed:s,params:t},queueMicrotask(()=>{n.isNotNullable(ae)&&ae.params===t&&(ae=null)});const{data:c}=r(t);return c===G?null:c}}function le(e){return ue(e,function(e){let t=se.get(e);return n.isUndefined(t)&&(t=ee(),se.set(e,t)),t}(e))}(le||(le={})).Cachable=function(e,t){return ue(t,e)};const fe=/* @__PURE__ */Symbol("march-hare.coalesce/default");function de(e,t){return new Promise((n,r)=>{if(t.aborted)return void r(t.reason);const o=()=>r(t.reason);t.addEventListener("abort",o,{once:!0}),e.then(e=>{t.removeEventListener("abort",o),n(e)},e=>{t.removeEventListener("abort",o),r(e)})})}let he=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var pe=/* @__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))(pe||{}),me=/* @__PURE__ */(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(me||{}),be=/* @__PURE__ */(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(be||{});class ye{[o]=!0;static keys=new Set(Object.values(be));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new ye(this.value,this.operation);return n.property=e,n.process=t,n}}class ve{static immer=(()=>{s();const e=new c;return e.setAutoFreeze(!1),e})();static tag="κ";static id=he}function ge(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 we(e){if(n.isNullable(e)||je(e))return e;if(n.isArray(e))return e.map(e=>we(e));if(n.isObject(e)&&Pe(e)){const t=Object.entries(e).map(([e,t])=>[e,we(t)]);return{...Object.fromEntries(t),[ve.tag]:e[ve.tag]??ve.id()}}return e}function Oe(e){if(Array.isArray(e))return e.filter(e=>ve.tag in e).map(e=>e[ve.tag]??"").join(",");const t=e[ve.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function Pe(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function je(e){return n.isNullable(e)||n.isString(e)||n.isNumber(e)||n.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function xe(e,t,r,o,s,c){return function a(i,u=t.path){if(i instanceof ye){const t=ge(r,u.join("."));if(Object.entries(i).filter(([e,t])=>!ye.keys.has(e)&&t instanceof ye).forEach(([e,t])=>a(t,u.concat(e))),je(i.value)){if(e===me.Hydrate)return i.value;const a=u.slice(0,-1),l=a.length>0?ge(r,a.join(".")):r;return n.isNullable(l)||Se(l,i,u.at(-1),o,s,c),t??i.value}if(e===me.Hydrate){const e=we(a(i.value,u));return Se(e,i,null,o,s,c),e}const l=t??we(i.value);return Se(l,i,null,o,s,c),n.isNullable(t)?l:(a(i.value,u),t)}if(n.isArray(i))return i.map((e,t)=>a(e,u.concat(t)));if(n.isObject(i)&&!Pe(i))return i;if(n.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,a(t,u.concat(e))]),n=Object.fromEntries(t);if(e===me.Hydrate){const e=we(n);return Object.entries(i).forEach(([t,n])=>{n instanceof ye&&je(n.value)&&Se(e,n,t,o,s,c)}),e}return n}return i}(t.value)}function Se(e,t,n,r,o,s){const c=s(e),a=o.get(c)??[];o.set(c,[t.assign(n,r),...a])}class Ee{#e={};#t;#n=/* @__PURE__ */new Map;#r=/* @__PURE__ */new Set;#o=!1;constructor(e=Oe){this.#t=e}static pk(){return he()}static"κ"=Ee.pk;annotate(e,t){return new ye(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,t,o,s,c){function a(s){const c=s.at(-1),a=ge(e(),s),i=s.slice(0,-1),u=r.isNotEmpty(i)?ge(e(),i):e();return[...n.isObject(a)||n.isArray(a)?t.get(o(a))?.filter(e=>n.isNullable(e.property))??[]:[],...n.isObject(u)?t.get(o(u))?.filter(e=>e.property===c)??[]:[]]}return function t(n){return new Proxy(()=>{},{get:(o,i)=>"pending"===i?()=>!r.isEmpty(a(n)):"remaining"===i?()=>r.length(a(n)):"box"===i?()=>({value:ge(e(),n),inspect:t(n)}):"is"===i?e=>a(n).some(t=>0!==(t.operation&e)):"draft"===i?()=>r.head(a(n))?.value??ge(e(),n):"settled"===i?()=>new Promise(t=>{if(r.isEmpty(a(n)))return t(ge(e(),n));const o=()=>{r.isEmpty(a(n))&&(c(o),t(ge(e(),n)))};s(o)}):t([...n,String(i)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(me.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(me.Produce,e)}#s(e,t){const n=/* @__PURE__ */Symbol("process"),[,r]=ve.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>ve.immer.applyPatches(t,[{...r,value:xe(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=we(this.#e),this.#c(),n}prune(e){this.#n.forEach((t,n)=>{const o=t.filter(t=>t.process!==e);r.isEmpty(o)?this.#n.delete(n):this.#n.set(n,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const Ce=t.createContext(/* @__PURE__ */new Map);function ke({action:e,renderer:r}){const o=p(),s=t.useContext(Ce),c=K(),a=t.useMemo(()=>{const t=s.get(e);if(t)return t;const r=new Ee,c=o.getCached(e);n.isNotNullable(c)&&r.hydrate({value:c});const a={state:r,listeners:/* @__PURE__ */new Set};return s.set(e,a),a},[e,o,s]);t.useLayoutEffect(()=>{function t(e){a.state.hydrate({value:e}),a.listeners.forEach(e=>e())}return a.listeners.add(c),o.on(e,t),()=>{a.listeners.delete(c),o.off(e,t)}},[e,o,a]);const i=a.state.model?.value;return n.isNullable(i)?null:r(i,a.state.inspect.value)}function Ne(e,t){const n=t.split(".");let r=e;for(let o=0;o<n.length-1;o++)r=r[n[o]];return{cursor:r,key:n[n.length-1]}}function Me(e,t,n){const{cursor:r,key:o}=Ne(e,t);r[o]=n}function Ae(e){return(t,n)=>{t.actions.produce(t=>{Me(t.model,e,n)})}}function _e(e){return t=>{t.actions.produce(t=>{!function(e,t){const{cursor:n,key:r}=Ne(e,t);n[r]=!n[r]}(t.model,e)})}}function Re(e,t){return n=>{n.actions.produce(n=>{Me(n.model,e,t)})}}const Ue={Update:e=>Ae(e),Invert:e=>_e(e),Always:(e,t)=>Re(e,t)};function Le(){const e=t.useRef(null);return t.useMemo(()=>({actions:{dispatch:function(t,n){const r=e.current;if(!r)throw new Error("march-hare: useContext handle dispatched before its paired context.useActions(...) ran. Call context.actions.dispatch from event handlers, not synchronously during render.");return r(t,n)}},useActions:function(...o){const s=function(...e){const o=n.isUndefined(e[0])||n.isFunction(e[0])?{}:e[0],s=n.isFunction(e[0])?e[0]:e[1]??(()=>({})),c=p(),i=t.useContext(Z),u=t.useContext(b),l=g(),d=t.useContext(v),h=t.useContext(_),m=t.useContext(U),y=K(),O=t.useRef(!1),P=t.useRef(null),j=t.useRef(new Ee);O.current||(O.current=!0,P.current=j.current.hydrate(o));const[x,S]=t.useState(()=>j.current.model),k=function(e){const n=t.useRef(e);return n.current=e,t.useMemo(()=>{return t=n,Object.keys(e).reduce((e,n)=>(Object.defineProperty(e,n,{get:()=>t.current[n],enumerable:!0}),e),{});var t},[e])}(s()),N=t.useMemo(()=>new f,[]),A=t.useRef({handlers:/* @__PURE__ */new Map});A.current.handlers=/* @__PURE__ */new Map;const R=function(){const e=t.useRef(/* @__PURE__ */new Set),n=t.useRef(/* @__PURE__ */new Set);return t.useMemo(()=>({broadcast:e.current,multicast:n.current}),[])}(),L=t.useRef(M.Mounting),T=t.useRef(/* @__PURE__ */new Set),W=t.useRef(0),D=t.useCallback((e,t,r)=>{const o=new AbortController,s={controller:o,action:e,payload:t};return u.add(s),T.current.add(s),{model:j.current.model,get phase(){return L.current},task:s,data:k,tasks:u,env:l,actions:{produce(e){if(o.signal.aborted)return;const t=d.current,n=j.current.produce(t=>{d.current=a(d.current,n=>{e({model:t,inspect:j.current.inspect,env:n})})});S(j.current.model),d.current!==t&&c.emit(C,d.current),r.processes.add(n),P.current&&(r.processes.add(P.current),P.current=null)},dispatch(e,t){if(o.signal.aborted)return Promise.resolve();const n=$(e),r=F(e)?e.channel:void 0;return H(e)?i?z(i.emitter,n,t,r):Promise.resolve():z(B(e)?c:N,n,t,r)},annotate:(e,t=pe.Update)=>j.current.annotate(t,e),get inspect(){return j.current.inspect},resource:Object.assign(function(e){const t=ie(),r=(e,t)=>{if(o.signal.aborted)return Promise.resolve();const n=e,r=$(n);return H(n)?i?z(i.emitter,r,t,void 0):Promise.resolve():B(n)?z(c,r,t,void 0):Promise.resolve()},s={exceedsWindow:null,coalesceToken:void 0},a={then:(e,c)=>(()=>{if(n.isNotNullable(s.exceedsWindow)){const{data:e,at:r}=t.read(t.params);if(e!==G&&n.isNotNullable(r)){const t=Temporal.Now.instant().since(r),n=Temporal.Duration.from(s.exceedsWindow);if(Temporal.Duration.compare(t,n)<=0)return Promise.resolve(e)}}if(n.isUndefined(s.coalesceToken))return t.run(l,o,t.params,r);let e=h.get(t.run);n.isUndefined(e)&&(e=/* @__PURE__ */new Map,h.set(t.run,e));const c=e,a=`${JSON.stringify(t.params)}|${function(e){switch(typeof e){case"string":return`s:${e}`;case"number":return`n:${e}`;case"bigint":return`i:${e.toString()}`;case"boolean":return`b:${e}`;case"symbol":return`y:${e.description??String(e)}`;default:return`o:${JSON.stringify(e)}`}}(s.coalesceToken)}`,i=c.get(a);if(i)return de(i,o.signal);const u=new AbortController,f=t.run(l,u,t.params,r).finally(()=>{c.delete(a)});return c.set(a,f),de(f,o.signal)})().then(e,c),exceeds:e=>(s.exceedsWindow=e,a),coalesce:e=>(s.coalesceToken=e??fe,a)};return a},{set:(e,t)=>{const n=ie();n.seed(n.params,t,Temporal.Now.instant())}}),async final(e){if(o.signal.aborted)return null;const t=$(e),r=H(e)?i?.emitter??null:c;if(!r)return null;const s=r.getCached(t);if(n.isUndefined(s))return null;const a=j.current.inspect;return a.pending()&&await new Promise((e,t)=>{if(o.signal.aborted)return void t(o.signal.reason);const n=()=>t(o.signal.reason);o.signal.addEventListener("abort",n,{once:!0}),a.settled().then(()=>{o.signal.removeEventListener("abort",n),e()})}),r.getCached(t)??null},peek(e){if(o.signal.aborted)return null;const t=$(e),n=H(e)?i?.emitter??null:c;return n?n.getCached(t)??null:null}}}},[x]);t.useLayoutEffect(()=>{function e(e,t,r){return function(o,s){const a=r();if(s===J&&n.isNotNullable(a))return;if(n.isNotNullable(s)&&s!==J&&n.isNotNullable(a)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(s,a))return;const i={processes:/* @__PURE__ */new Set},l=Promise.withResolvers(),f=D(e,o,i),h=function(e){const t=$(e),r=n.isString(t)?t:t.description??"";return r.startsWith(w())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}(e),p=performance.now(),b=j.current.model,v=d.current;let g,O=!1;function P(){const e=j.current.model,t=d.current;return{model:b===e?null:{before:b,after:e},env:v===t?null:{before:v,after:t}}}function x(e){O=!0;const t=q(A.current.handlers,"Error"),r=n.isNotNullable(t),s=function(e){return e instanceof Error&&"AbortError"===e.name?X.Aborted:X.Errored}(e),a=function(e){return e instanceof Error?e:new Error(String(e))}(e),i={reason:s,error:a,action:h,handled:r,tasks:u};c.fire(E,i),r&&t&&N.emit(t,i),m({stage:"end",result:"error",action:{name:h,payload:o},details:{task:f.task,elapsed:performance.now()-p,mutations:P(),error:a,reason:s}})}function S(){for(const e of u)if(e===f.task){u.delete(e),T.current.delete(e);break}i.processes.forEach(e=>j.current.prune(e)),i.processes.size>0&&y(),O||m({stage:"end",result:"success",action:{name:h,payload:o},details:{task:f.task,elapsed:performance.now()-p,mutations:P()}}),l.resolve()}m({stage:"start",action:{name:h,payload:o},details:{task:f.task}});try{g=t(f,o)}catch(C){return x(C),S(),l.promise}return function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(g)?((async()=>{for await(const e of g);})().catch(x).finally(S),l.promise):(Promise.resolve(g).catch(x).finally(S),l.promise)}}W.current++;const t=/* @__PURE__ */new Set;return A.current.handlers.forEach((n,r)=>{for(const{getChannel:o,handler:s}of n){const n=e(r,s,o);if(H(r)){if(i){const e=i.emitter;e.on(r,n),t.add(()=>e.off(r,n))}N.on(r,n),R.multicast.add(r),t.add(()=>N.off(r,n))}else B(r)?(c.on(r,n),N.on(r,n),R.broadcast.add(r),t.add(()=>{c.off(r,n),N.off(r,n)})):(N.on(r,n),t.add(()=>N.off(r,n)))}}),()=>{const e=++W.current,n=new Set(t);queueMicrotask(()=>{if(W.current!==e){for(const e of n)e();return}for(const e of T.current)e.controller.abort(),u.delete(e);T.current.clear(),L.current=M.Unmounting;const t=q(A.current.handlers,"Unmount");t&&N.emit(t),L.current=M.Unmounted;for(const e of n)e()})}},[N]),function({unicast:e,broadcast:o,dispatchers:s,scope:c,phase:a,data:i,handlers:u}){const l=t.useRef(null);t.useLayoutEffect(()=>{if(a.current===M.Mounted)return;a.current=M.Mounting;const t=q(u,"Mount");t&&e.emit(t),s.broadcast.forEach(t=>{const r=o.getCached(t);n.isNullable(r)||e.emit(t,r,J)}),c&&s.multicast.forEach(t=>{const r=c.emitter.getCached(t);n.isNullable(r)||e.emit(t,r,J)}),a.current=M.Mounted},[]),t.useLayoutEffect(()=>{if(n.isNotNullable(l.current)){const t=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(l.current,i);if(r.isNotEmpty(Object.keys(t))){const n=q(u,"Update");n&&e.emit(n,t)}}l.current=i},[i,e])}({unicast:N,broadcast:c,dispatchers:R,scope:i,phase:L,data:s(),handlers:A.current.handlers});const I=t.useMemo(()=>({dispatch(e,t){const n=$(e),r=F(e)?e.channel:void 0;return H(e)?i?z(i.emitter,n,t,r):Promise.resolve():z(B(e)?c:N,n,t,r)},get inspect(){return j.current.inspect},stream:(e,n)=>t.createElement(ke,{action:$(e),renderer:n})}),[x,N]),V=t.useMemo(()=>[x,I,k],[x,I,k]);return V.useAction=(e,n)=>{!function(e,n,r){const o=t.useRef(r);t.useLayoutEffect(()=>{o.current=r});const s=t.useRef(n);t.useLayoutEffect(()=>{s.current=n});const c=t.useCallback((e,t)=>o.current(e,t),[]),a=t.useCallback(()=>F(s.current)?s.current.channel:void 0,[]),i=$(n),u=e.current.handlers.get(i)??/* @__PURE__ */new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:a,handler:c})}(A,e,n)},V.dispatch=V[1].dispatch,V}(...o);return e.current=s.dispatch,s},with:{update:e=>Ae(e),invert:e=>_e(e),always:(e,t)=>Re(e,t)}}),[])}function Te(n){return{Boundary:function({env:t,tap:r,children:o}){/* @__PURE__ */
7
+ return e(T,{env:t??n?.env,tap:r??n?.tap,children:o})},useContext:function(){return Le()},useEnv:function(){return g()},Resource:Object.assign(function(e){return le(e)},{Cachable:(e,t)=>le.Cachable(e,t)}),Scope:()=>({Boundary:function({children:n}){const r=t.useMemo(()=>({id:/* @__PURE__ */Symbol("march-hare.scope/instance"),emitter:new d}),[]);/* @__PURE__ */
8
+ return e(Z.Provider,{value:r,children:n})},useContext:function(){return Le()},useEnv:function(){return g()},Resource:Object.assign(function(e){return le(e)},{Cachable:(e,t)=>le.Cachable(e,t)})})}}const We=new Ee;function $e(e,t=pe.Update){return We.annotate(t,e)}export{Y as Aborted,I as Action,Te as App,T as Boundary,ee as Cache,N as Distribution,k as Lifecycle,pe as Op,pe as Operation,X as Reason,le as Resource,Ee as State,Ue as With,$e as annotate,oe as utils};
@@ -1 +1 @@
1
- var global,factory;global=this,factory=function(e,t,n,r,o){"use strict";function s(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 c=s(n);function a(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var i,u={exports:{}},l=(i||(i=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 s(e,t,r,s,c){if("function"!=typeof r)throw new TypeError("The listener must be a function");var a=new o(r,s||e,c),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],a]:e._events[i].push(a):(e._events[i]=a,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function a(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),a.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},a.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,s=new Array(o);r<o;r++)s[r]=t[r].fn;return s},a.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},a.prototype.emit=function(e,t,r,o,s,c){var a=n?n+e:e;if(!this._events[a])return!1;var i,u,l=this._events[a],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,s),!0;case 6:return l.fn.call(l.context,t,r,o,s,c),!0}for(u=1,i=new Array(f-1);u<f;u++)i[u-1]=arguments[u];l.fn.apply(l.context,i)}else{var d,h=l.length;for(u=0;u<h;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(!i)for(d=1,i=new Array(f-1);d<f;d++)i[d-1]=arguments[d];l[u].fn.apply(l[u].context,i)}}return!0},a.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},a.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},a.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return c(this,s),this;var a=this._events[s];if(a.fn)a.fn!==t||o&&!a.once||r&&a.context!==r||c(this,s);else{for(var i=0,u=[],l=a.length;i<l;i++)(a[i].fn!==t||o&&!a[i].once||r&&a[i].context!==r)&&u.push(a[i]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},a.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&c(this,t):(this._events=new r,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=n,a.EventEmitter=a,e.exports=a}(u)),u.exports);const f=a(l);class d extends f{cache=new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}setCache(e,t){this.cache.set(e,t)}getCached(e){return this.cache.get(e)}fire(e,...t){return super.emit(e,...t)}}const h=c.createContext(new d);function p(){return c.useContext(h)}function m({children:e}){const n=c.useMemo(()=>new d,[]);return t.jsx(h.Provider,{value:n,children:e})}const b=c.createContext(new Set);function y({children:e}){const n=c.useMemo(()=>new Set,[]);return t.jsx(b.Provider,{value:n,children:e})}const v=c.createContext({current:{}});function g(){const e=c.useContext(v);return c.useMemo(()=>new Proxy({},{get:(t,n)=>Reflect.get(e.current,n),has:(t,n)=>n in e.current,ownKeys:()=>Reflect.ownKeys(e.current),getOwnPropertyDescriptor(t,n){const o=Object.getOwnPropertyDescriptor(e.current,n);if(!r.G.isUndefined(o))return{...o,configurable:!0}},set(){throw new TypeError("Env is read-only outside `context.actions.produce`. Mutate via produce(({ env }) => { env.x = ... }) instead.")}}),[e])}const w=(e="")=>`march-hare.action/${e}`,j=(e="")=>`march-hare.action/broadcast/${e}`,O=(e="")=>`march-hare.action/multicast/${e}`,x=(e="")=>`march-hare.action.lifecycle/${e}`;class P{static Payload=Symbol("march-hare.brand/Payload");static Broadcast=Symbol("march-hare.brand/Broadcast");static Multicast=Symbol("march-hare.brand/Multicast");static Action=Symbol("march-hare.brand/Action");static Channel=Symbol("march-hare.brand/Channel");static Name=Symbol("march-hare.brand/Name")}function S(e){const t=Symbol(`march-hare.action.lifecycle/${e}`),n=function(n){return{[P.Action]:t,[P.Payload]:void 0,[P.Channel]:n,[P.Name]:e,channel:n}};return Object.defineProperty(n,P.Action,{value:t,enumerable:!1}),Object.defineProperty(n,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(n,P.Name,{value:e,enumerable:!1}),n}const E=Symbol(j("Fault")),C=Symbol(j("Env"));class G{static Mount(){return S("Mount")}static Unmount(){return S("Unmount")}static Error(){return S("Error")}static Update(){return S("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,P.Action,{value:E,enumerable:!1}),Object.defineProperty(e,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,P.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,P.Name,{value:"Fault",enumerable:!1}),e})();static Env=(()=>{const e={};return Object.defineProperty(e,P.Action,{value:C,enumerable:!1}),Object.defineProperty(e,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,P.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,P.Name,{value:"Env",enumerable:!1}),e})()}var A=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(A||{}),M=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(M||{});function N({initial:e,children:n}){const o=c.useRef(e),s=p();return r.G.isUndefined(s.getCached(C))&&s.setCache(C,o.current),t.jsx(v.Provider,{value:o,children:n})}const k=c.createContext(new WeakMap);function R({children:e}){const n=c.useMemo(()=>new WeakMap,[]);return t.jsx(k.Provider,{value:n,children:e})}function _({env:e,children:n}){return t.jsx(m,{children:t.jsx(N,{initial:e??{},children:t.jsx(y,{children:t.jsx(R,{children:n})})})})}const U=e=>"symbol"==typeof e;function L(e){return r.G.isString(e)||U(e)?e:(r.G.isObject(e)||r.G.isFunction(e))&&P.Action in e?e[P.Action]:e}function T(e){if(r.G.isString(e))return e.startsWith(j());if(U(e))return e.description?.startsWith(j())??!1;if(r.G.isObject(e)||r.G.isFunction(e)){if(P.Broadcast in e&&e[P.Broadcast])return!0;if(P.Action in e){const t=e[P.Action];return t.description?.startsWith(j())??!1}}return!1}function W(e){const t=L(e),n=r.G.isString(t)?t:t.description??"";return n.startsWith(w())&&n.slice(n.lastIndexOf("/")+1)||"unknown"}function B(e){return r.G.isObject(e)&&P.Channel in e&&"channel"in e}function $(e){const t=L(e),n=U(t)?t.description??"":t;return n.startsWith(x())&&n.slice(x().length)||null}function F(e){if(r.G.isString(e))return e.startsWith(O());if(U(e))return e.description?.startsWith(O())??!1;if(r.G.isObject(e)||r.G.isFunction(e)){if(P.Multicast in e&&e[P.Multicast])return!0;if(P.Action in e){const t=e[P.Action];return t.description?.startsWith(O())??!1}}return!1}const D=Symbol(((e="")=>`march-hare/replay${e}`)());function I(e,t,...n){e instanceof d&&e.setCache(t,n[0]);const r=e.listeners(t);return 0===r.length?Promise.resolve():Promise.all(r.map(e=>Promise.resolve(e(...n)))).then(()=>{})}function H(e,t){for(const n of e.keys())if($(n)===t)return n;return null}const q=Symbol("march-hare.unset");function z(){const[,e]=c.useReducer(e=>e+1,0);return e}function J(){return{data:q,at:null,else:e=>e}}function K(e,t){return{data:e,at:t,else:t=>e}}var V=(e=>(e[e.Aborted=0]="Aborted",e[e.Errored=1]="Errored",e))(V||{});class Q extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}function X(e){return e instanceof Error?e:new Error(String(e))}const Y=c.createContext(null);function Z(e){const t=new Map,n=e??{get:e=>t.get(e)??null,set:(e,n)=>{t.set(e,n)},remove:e=>{t.delete(e)},clear:()=>{t.clear()}};return{get(e){try{const t=n.get(e);if(r.G.isNull(t))return J();const o=JSON.parse(t);return K(o.data,Temporal.Instant.from(o.at))}catch{return J()}},set(e,t){if(t.data===q||r.G.isNull(t.at))return!1;try{return n.set(e,JSON.stringify({data:t.data,at:t.at.toString()})),!0}catch{return!1}},remove(e){n.remove(e)},clear(){n.clear()}}}function ee(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new Q);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new Q)},{once:!0})})}async function te(e,t,n){if(t?.aborted)throw new Q;for(;;){if(await n())return;await ee(e,t)}}function ne(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const re=Object.freeze(Object.defineProperty({__proto__:null,pk:ne,poll:te,sleep:ee,unset:q,"ζ":ee,"κ":ne,"π":te},Symbol.toStringTag,{value:"Module"})),oe=new WeakMap;function se(e){return JSON.stringify(e)}let ce=null;function ae(){if(r.G.isNull(ce))throw new Error("context.actions.resource(...) and context.actions.resource.set(...) must be called with a fresh resource invocation, e.g. context.actions.resource(resource.cat({ id: 5 })).");const e=ce;return ce=null,e}function ie(e,t){const n=e=>{const n=t.get(se(e));return n.data===q||r.G.isNull(n.at)?{data:q,at:null}:{data:n.data,at:n.at}},o=(n,r,o,s)=>e({env:n,controller:r,params:o,dispatch:s}).then(e=>(t.set(se(o),K(e,Temporal.Now.instant())),e)),s=(e,n,r)=>{t.set(se(e),K(n,r))};return function(e){const t=e??{};ce={run:o,read:n,seed:s,params:t},queueMicrotask(()=>{r.G.isNotNullable(ce)&&ce.params===t&&(ce=null)});const{data:c}=n(t);return c===q?null:c}}function ue(e){return ie(e,function(e){let t=oe.get(e);return r.G.isUndefined(t)&&(t=Z(),oe.set(e,t)),t}(e))}(ue||(ue={})).Cachable=function(e,t){return ie(t,e)};const le=Symbol("march-hare.coalesce/default");function fe(e,t){return new Promise((n,r)=>{if(t.aborted)return void r(t.reason);const o=()=>r(t.reason);t.addEventListener("abort",o,{once:!0}),e.then(e=>{t.removeEventListener("abort",o),n(e)},e=>{t.removeEventListener("abort",o),r(e)})})}let de=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var he=(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))(he||{}),pe=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(pe||{}),me=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(me||{});class be{[o.immerable]=!0;static keys=new Set(Object.values(me));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new be(this.value,this.operation);return n.property=e,n.process=t,n}}class ye{static immer=(()=>{o.enablePatches();const e=new o.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=de}function ve(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 ge(e){if(r.G.isNullable(e)||Oe(e))return e;if(r.G.isArray(e))return e.map(e=>ge(e));if(r.G.isObject(e)&&je(e)){const t=Object.entries(e).map(([e,t])=>[e,ge(t)]);return{...Object.fromEntries(t),[ye.tag]:e[ye.tag]??ye.id()}}return e}function we(e){if(Array.isArray(e))return e.filter(e=>ye.tag in e).map(e=>e[ye.tag]??"").join(",");const t=e[ye.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function je(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function Oe(e){return r.G.isNullable(e)||r.G.isString(e)||r.G.isNumber(e)||r.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function xe(e,t,n,o,s,c){return function a(i,u=t.path){if(i instanceof be){const t=ve(n,u.join("."));if(Object.entries(i).filter(([e,t])=>!be.keys.has(e)&&t instanceof be).forEach(([e,t])=>a(t,u.concat(e))),Oe(i.value)){if(e===pe.Hydrate)return i.value;const a=u.slice(0,-1),l=a.length>0?ve(n,a.join(".")):n;return r.G.isNullable(l)||Pe(l,i,u.at(-1),o,s,c),t??i.value}if(e===pe.Hydrate){const e=ge(a(i.value,u));return Pe(e,i,null,o,s,c),e}const l=t??ge(i.value);return Pe(l,i,null,o,s,c),r.G.isNullable(t)?l:(a(i.value,u),t)}if(r.G.isArray(i))return i.map((e,t)=>a(e,u.concat(t)));if(r.G.isObject(i)&&!je(i))return i;if(r.G.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,a(t,u.concat(e))]),n=Object.fromEntries(t);if(e===pe.Hydrate){const e=ge(n);return Object.entries(i).forEach(([t,n])=>{n instanceof be&&Oe(n.value)&&Pe(e,n,t,o,s,c)}),e}return n}return i}(t.value)}function Pe(e,t,n,r,o,s){const c=s(e),a=o.get(c)??[];o.set(c,[t.assign(n,r),...a])}class Se{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=we){this.#t=e}static pk(){return de()}static"κ"=Se.pk;annotate(e,t){return new be(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,t,n,o,s){function c(o){const s=o.at(-1),c=ve(e(),o),a=o.slice(0,-1),i=r.A.isNotEmpty(a)?ve(e(),a):e();return[...r.G.isObject(c)||r.G.isArray(c)?t.get(n(c))?.filter(e=>r.G.isNullable(e.property))??[]:[],...r.G.isObject(i)?t.get(n(i))?.filter(e=>e.property===s)??[]:[]]}return function t(n){return new Proxy(()=>{},{get:(a,i)=>"pending"===i?()=>!r.A.isEmpty(c(n)):"remaining"===i?()=>r.A.length(c(n)):"box"===i?()=>({value:ve(e(),n),inspect:t(n)}):"is"===i?e=>c(n).some(t=>0!==(t.operation&e)):"draft"===i?()=>r.A.head(c(n))?.value??ve(e(),n):"settled"===i?()=>new Promise(t=>{if(r.A.isEmpty(c(n)))return t(ve(e(),n));const a=()=>{r.A.isEmpty(c(n))&&(s(a),t(ve(e(),n)))};o(a)}):t([...n,String(i)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(pe.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(pe.Produce,e)}#s(e,t){const n=Symbol("process"),[,r]=ye.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>ye.immer.applyPatches(t,[{...r,value:xe(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=ge(this.#e),this.#c(),n}prune(e){this.#n.forEach((t,n)=>{const o=t.filter(t=>t.process!==e);r.A.isEmpty(o)?this.#n.delete(n):this.#n.set(n,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const Ee=c.createContext(new Map);function Ce({action:e,renderer:t}){const n=p(),o=c.useContext(Ee),s=z(),a=c.useMemo(()=>{const t=o.get(e);if(t)return t;const s=new Se,c=n.getCached(e);r.G.isNotNullable(c)&&s.hydrate({value:c});const a={state:s,listeners:new Set};return o.set(e,a),a},[e,n,o]);c.useLayoutEffect(()=>{function t(e){a.state.hydrate({value:e}),a.listeners.forEach(e=>e())}return a.listeners.add(s),n.on(e,t),()=>{a.listeners.delete(s),n.off(e,t)}},[e,n,a]);const i=a.state.model?.value;return r.G.isNullable(i)?null:t(i,a.state.inspect.value)}function Ge(){const e=c.useRef(null);return c.useMemo(()=>({actions:{dispatch:function(t,n){const r=e.current;if(!r)throw new Error("march-hare: useContext handle dispatched before its paired context.useActions(...) ran. Call context.actions.dispatch from event handlers, not synchronously during render.");return r(t,n)}},useActions:function(...t){const n=function(...e){const t=r.G.isUndefined(e[0])||r.G.isFunction(e[0])?{}:e[0],n=r.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),s=p(),a=c.useContext(Y),i=c.useContext(b),u=g(),l=c.useContext(v),d=c.useContext(k),h=z(),m=c.useRef(!1),y=c.useRef(null),w=c.useRef(new Se);m.current||(m.current=!0,y.current=w.current.hydrate(t));const[j,O]=c.useState(()=>w.current.model),x=function(e){const t=c.useRef(e);return t.current=e,c.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(n()),P=c.useMemo(()=>new f,[]),S=c.useRef({handlers:new Map});S.current.handlers=new Map;const G=function(){const e=c.useRef(new Set),t=c.useRef(new Set);return c.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),A=c.useRef(M.Mounting),N=c.useRef(new Set),R=c.useRef(0),_=c.useCallback((e,t,n)=>{const c=new AbortController,f={controller:c,action:e,payload:t};return i.add(f),N.current.add(f),{model:w.current.model,get phase(){return A.current},task:f,data:x,tasks:i,env:u,actions:{produce(e){if(c.signal.aborted)return;const t=l.current,r=w.current.produce(t=>{l.current=o.produce(l.current,n=>{e({model:t,inspect:w.current.inspect,env:n})})});O(w.current.model),l.current!==t&&s.emit(C,l.current),n.processes.add(r),y.current&&(n.processes.add(y.current),y.current=null)},dispatch(e,t){if(c.signal.aborted)return Promise.resolve();const n=L(e),r=B(e)?e.channel:void 0;return F(e)?a?I(a.emitter,n,t,r):Promise.resolve():I(T(e)?s:P,n,t,r)},annotate:(e,t=he.Update)=>w.current.annotate(t,e),get inspect(){return w.current.inspect},resource:Object.assign(function(e){const t=ae(),n=(e,t)=>{if(c.signal.aborted)return Promise.resolve();const n=e,r=L(n);return F(n)?a?I(a.emitter,r,t,void 0):Promise.resolve():T(n)?I(s,r,t,void 0):Promise.resolve()},o={exceedsWindow:null,coalesceToken:void 0},i={then:(e,s)=>(()=>{if(r.G.isNotNullable(o.exceedsWindow)){const{data:e,at:n}=t.read(t.params);if(e!==q&&r.G.isNotNullable(n)){const t=Temporal.Now.instant().since(n),r=Temporal.Duration.from(o.exceedsWindow);if(Temporal.Duration.compare(t,r)<=0)return Promise.resolve(e)}}if(r.G.isUndefined(o.coalesceToken))return t.run(l.current,c,t.params,n);let e=d.get(t.run);r.G.isUndefined(e)&&(e=new Map,d.set(t.run,e));const s=e,a=`${JSON.stringify(t.params)}|${function(e){switch(typeof e){case"string":return`s:${e}`;case"number":return`n:${e}`;case"bigint":return`i:${e.toString()}`;case"boolean":return`b:${e}`;case"symbol":return`y:${e.description??String(e)}`;default:return`o:${JSON.stringify(e)}`}}(o.coalesceToken)}`,i=s.get(a);if(i)return fe(i,c.signal);const u=new AbortController,f=t.run(l.current,u,t.params,n).finally(()=>{s.delete(a)});return s.set(a,f),fe(f,c.signal)})().then(e,s),exceeds:e=>(o.exceedsWindow=e,i),coalesce:e=>(o.coalesceToken=e??le,i)};return i},{set:(e,t)=>{const n=ae();n.seed(n.params,t,Temporal.Now.instant())}}),async final(e){if(c.signal.aborted)return null;const t=L(e),n=F(e)?a?.emitter??null:s;if(!n)return null;const o=n.getCached(t);if(r.G.isUndefined(o))return null;const i=w.current.inspect;return i.pending()&&await new Promise((e,t)=>{if(c.signal.aborted)return void t(c.signal.reason);const n=()=>t(c.signal.reason);c.signal.addEventListener("abort",n,{once:!0}),i.settled().then(()=>{c.signal.removeEventListener("abort",n),e()})}),n.getCached(t)??null},peek(e){if(c.signal.aborted)return null;const t=L(e),n=F(e)?a?.emitter??null:s;return n?n.getCached(t)??null:null}}}},[j]);c.useLayoutEffect(()=>{function e(e,t,n){return function(o,c){const a=n();if(c===D&&r.G.isNotNullable(a))return;if(r.G.isNotNullable(c)&&c!==D&&r.G.isNotNullable(a)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,a))return;const u={processes:new Set},l=Promise.withResolvers(),f=_(e,o,u);function d(t){const n=H(S.current.handlers,"Error"),o=r.G.isNotNullable(n),c={reason:(a=t,a instanceof Error&&"AbortError"===a.name?V.Aborted:V.Errored),error:X(t),action:W(e),handled:o,tasks:i};var a;s.fire(E,c),o&&n&&P.emit(n,c)}function p(){for(const e of i)if(e===f.task){i.delete(e),N.current.delete(e);break}u.processes.forEach(e=>w.current.prune(e)),u.processes.size>0&&h(),l.resolve()}let m;try{m=t(f,o)}catch(b){return d(b),void p()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(m))return Promise.resolve(m).catch(d).finally(p),l.promise;(async()=>{for await(const e of m);})().catch(d).finally(p)}}R.current++;const t=new Set;return S.current.handlers.forEach((n,r)=>{for(const{getChannel:o,handler:c}of n){const n=e(r,c,o);if(F(r)){if(a){const e=a.emitter;e.on(r,n),t.add(()=>e.off(r,n))}P.on(r,n),G.multicast.add(r),t.add(()=>P.off(r,n))}else T(r)?(s.on(r,n),P.on(r,n),G.broadcast.add(r),t.add(()=>{s.off(r,n),P.off(r,n)})):(P.on(r,n),t.add(()=>P.off(r,n)))}}),()=>{const e=++R.current,n=new Set(t);queueMicrotask(()=>{if(R.current!==e){for(const e of n)e();return}for(const e of N.current)e.controller.abort(),i.delete(e);N.current.clear(),A.current=M.Unmounting;const t=H(S.current.handlers,"Unmount");t&&P.emit(t),A.current=M.Unmounted;for(const e of n)e()})}},[P]),function({unicast:e,broadcast:t,dispatchers:n,scope:o,phase:s,data:a,handlers:i}){const u=c.useRef(null);c.useLayoutEffect(()=>{if(s.current===M.Mounted)return;s.current=M.Mounting;const c=H(i,"Mount");c&&e.emit(c),n.broadcast.forEach(n=>{const o=t.getCached(n);r.G.isNullable(o)||e.emit(n,o,D)}),o&&n.multicast.forEach(t=>{const n=o.emitter.getCached(t);r.G.isNullable(n)||e.emit(t,n,D)}),s.current=M.Mounted},[]),c.useLayoutEffect(()=>{if(r.G.isNotNullable(u.current)){const t=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,a);if(r.A.isNotEmpty(Object.keys(t))){const n=H(i,"Update");n&&e.emit(n,t)}}u.current=a},[a,e])}({unicast:P,broadcast:s,dispatchers:G,scope:a,phase:A,data:n(),handlers:S.current.handlers});const U=c.useMemo(()=>({dispatch(e,t){const n=L(e),r=B(e)?e.channel:void 0;return F(e)?a?I(a.emitter,n,t,r):Promise.resolve():I(T(e)?s:P,n,t,r)},get inspect(){return w.current.inspect},stream:(e,t)=>c.createElement(Ce,{action:L(e),renderer:t})}),[j,P]),$=c.useMemo(()=>[j,U,x],[j,U,x]);return $.useAction=(e,t)=>{!function(e,t,n){const r=c.useRef(n);c.useLayoutEffect(()=>{r.current=n});const o=c.useRef(t);c.useLayoutEffect(()=>{o.current=t});const s=c.useCallback((e,t)=>r.current(e,t),[]),a=c.useCallback(()=>B(o.current)?o.current.channel:void 0,[]),i=L(t),u=e.current.handlers.get(i)??new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:a,handler:s})}(S,e,t)},$.dispatch=$[1].dispatch,$}(...t);return e.current=n.dispatch,n}}),[])}const Ae=new Se;e.Aborted=Q,e.Action=(e="",t=A.Unicast)=>{const n=t===A.Broadcast?Symbol(j(e)):t===A.Multicast?Symbol(O(e)):Symbol(w(e)),r=function(t){return{[P.Action]:n,[P.Payload]:void 0,[P.Channel]:t,[P.Name]:e,channel:t}};return Object.defineProperty(r,P.Action,{value:n,enumerable:!1}),Object.defineProperty(r,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(r,P.Name,{value:e,enumerable:!1}),t===A.Broadcast&&Object.defineProperty(r,P.Broadcast,{value:!0,enumerable:!1}),t===A.Multicast&&Object.defineProperty(r,P.Multicast,{value:!0,enumerable:!1}),r},e.App=function(e){return{Boundary:function({children:n}){return t.jsx(_,{env:e?.env,children:n})},useContext:function(){return Ge()},useEnv:function(){return g()},Resource:Object.assign(function(e){return ue(e)},{Cachable:(e,t)=>ue.Cachable(e,t)}),Scope:()=>({Boundary:function({children:e}){const n=c.useMemo(()=>({id:Symbol("march-hare.scope/instance"),emitter:new d}),[]);return t.jsx(Y.Provider,{value:n,children:e})},useContext:function(){return Ge()},useEnv:function(){return g()},Resource:Object.assign(function(e){return ue(e)},{Cachable:(e,t)=>ue.Cachable(e,t)})})}},e.Boundary=_,e.Cache=Z,e.Distribution=A,e.Lifecycle=G,e.Op=he,e.Operation=he,e.Reason=V,e.Resource=ue,e.State=Se,e.With={Update:e=>(t,n)=>{t.actions.produce(t=>{t.model[e]=n})},Invert:e=>t=>{t.actions.produce(t=>{t.model[e]=!t.model[e]})}},e.annotate=function(e,t=he.Update){return Ae.annotate(t,e)},e.utils=re,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("react/jsx-runtime"),require("react"),require("@mobily/ts-belt"),require("immer")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react","@mobily/ts-belt","immer"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).MarchHare={},global.jsxRuntime,global.React,global.TsBelt,global.Immer);
1
+ var global,factory;global=this,factory=function(e,t,n,r,o){"use strict";function s(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 c=s(n);function a(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var i,u={exports:{}},l=(i||(i=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 s(e,t,r,s,c){if("function"!=typeof r)throw new TypeError("The listener must be a function");var a=new o(r,s||e,c),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],a]:e._events[i].push(a):(e._events[i]=a,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function a(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),a.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},a.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,s=new Array(o);r<o;r++)s[r]=t[r].fn;return s},a.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},a.prototype.emit=function(e,t,r,o,s,c){var a=n?n+e:e;if(!this._events[a])return!1;var i,u,l=this._events[a],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,s),!0;case 6:return l.fn.call(l.context,t,r,o,s,c),!0}for(u=1,i=new Array(f-1);u<f;u++)i[u-1]=arguments[u];l.fn.apply(l.context,i)}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(!i)for(d=1,i=new Array(f-1);d<f;d++)i[d-1]=arguments[d];l[u].fn.apply(l[u].context,i)}}return!0},a.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},a.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},a.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return c(this,s),this;var a=this._events[s];if(a.fn)a.fn!==t||o&&!a.once||r&&a.context!==r||c(this,s);else{for(var i=0,u=[],l=a.length;i<l;i++)(a[i].fn!==t||o&&!a[i].once||r&&a[i].context!==r)&&u.push(a[i]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},a.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&c(this,t):(this._events=new r,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=n,a.EventEmitter=a,e.exports=a}(u)),u.exports);const f=a(l);class d extends f{cache=new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}setCache(e,t){this.cache.set(e,t)}getCached(e){return this.cache.get(e)}fire(e,...t){return super.emit(e,...t)}}const p=c.createContext(new d);function h(){return c.useContext(p)}function m({children:e}){const n=c.useMemo(()=>new d,[]);return t.jsx(p.Provider,{value:n,children:e})}const b=c.createContext(new Set);function y({children:e}){const n=c.useMemo(()=>new Set,[]);return t.jsx(b.Provider,{value:n,children:e})}const v=c.createContext({current:{}});function g(){const e=c.useContext(v);return c.useMemo(()=>new Proxy({},{get:(t,n)=>Reflect.get(e.current,n),has:(t,n)=>n in e.current,ownKeys:()=>Reflect.ownKeys(e.current),getOwnPropertyDescriptor(t,n){const o=Object.getOwnPropertyDescriptor(e.current,n);if(!r.G.isUndefined(o))return{...o,configurable:!0}},set(){throw new TypeError("Env is read-only outside `context.actions.produce`. Mutate via produce(({ env }) => { env.x = ... }) instead.")}}),[e])}const w=(e="")=>`march-hare.action/${e}`,j=(e="")=>`march-hare.action/broadcast/${e}`,x=(e="")=>`march-hare.action/multicast/${e}`,O=(e="")=>`march-hare.action.lifecycle/${e}`;class P{static Payload=Symbol("march-hare.brand/Payload");static Broadcast=Symbol("march-hare.brand/Broadcast");static Multicast=Symbol("march-hare.brand/Multicast");static Action=Symbol("march-hare.brand/Action");static Channel=Symbol("march-hare.brand/Channel");static Name=Symbol("march-hare.brand/Name")}function S(e){const t=Symbol(`march-hare.action.lifecycle/${e}`),n=function(n){return{[P.Action]:t,[P.Payload]:void 0,[P.Channel]:n,[P.Name]:e,channel:n}};return Object.defineProperty(n,P.Action,{value:t,enumerable:!1}),Object.defineProperty(n,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(n,P.Name,{value:e,enumerable:!1}),n}const C=Symbol(j("Fault")),E=Symbol(j("Env"));class G{static Mount(){return S("Mount")}static Unmount(){return S("Unmount")}static Error(){return S("Error")}static Update(){return S("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,P.Action,{value:C,enumerable:!1}),Object.defineProperty(e,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,P.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,P.Name,{value:"Fault",enumerable:!1}),e})();static Env=(()=>{const e={};return Object.defineProperty(e,P.Action,{value:E,enumerable:!1}),Object.defineProperty(e,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,P.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,P.Name,{value:"Env",enumerable:!1}),e})()}var A=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(A||{}),M=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(M||{});function k({initial:e,children:n}){const o=c.useRef(e),s=h();return r.G.isUndefined(s.getCached(E))&&s.setCache(E,o.current),t.jsx(v.Provider,{value:o,children:n})}const N=c.createContext(new WeakMap);function R({children:e}){const n=c.useMemo(()=>new WeakMap,[]);return t.jsx(N.Provider,{value:n,children:e})}const _=c.createContext(()=>{});function U({tap:e,children:n}){const r=c.useRef(e);c.useLayoutEffect(()=>{r.current=e},[e]);const o=c.useMemo(()=>e=>r.current?.(e),[]);return t.jsx(_.Provider,{value:o,children:n})}function L({env:e,tap:n,children:r}){return t.jsx(m,{children:t.jsx(k,{initial:e??{},children:t.jsx(y,{children:t.jsx(U,{tap:n,children:t.jsx(R,{children:r})})})})})}const T=e=>"symbol"==typeof e;function W(e){return r.G.isString(e)||T(e)?e:(r.G.isObject(e)||r.G.isFunction(e))&&P.Action in e?e[P.Action]:e}function B(e){if(r.G.isString(e))return e.startsWith(j());if(T(e))return e.description?.startsWith(j())??!1;if(r.G.isObject(e)||r.G.isFunction(e)){if(P.Broadcast in e&&e[P.Broadcast])return!0;if(P.Action in e){const t=e[P.Action];return t.description?.startsWith(j())??!1}}return!1}function $(e){return r.G.isObject(e)&&P.Channel in e&&"channel"in e}function F(e){const t=W(e),n=T(t)?t.description??"":t;return n.startsWith(O())&&n.slice(O().length)||null}function D(e){if(r.G.isString(e))return e.startsWith(x());if(T(e))return e.description?.startsWith(x())??!1;if(r.G.isObject(e)||r.G.isFunction(e)){if(P.Multicast in e&&e[P.Multicast])return!0;if(P.Action in e){const t=e[P.Action];return t.description?.startsWith(x())??!1}}return!1}const I=Symbol(((e="")=>`march-hare/replay${e}`)());function H(e,t,...n){e instanceof d&&e.setCache(t,n[0]);const r=e.listeners(t);return 0===r.length?Promise.resolve():Promise.all(r.map(e=>Promise.resolve(e(...n)))).then(()=>{})}function q(e,t){for(const n of e.keys())if(F(n)===t)return n;return null}const z=Symbol("march-hare.unset");function J(){const[,e]=c.useReducer(e=>e+1,0);return e}function K(){return{data:z,at:null,else:e=>e}}function V(e,t){return{data:e,at:t,else:t=>e}}var Q=(e=>(e[e.Aborted=0]="Aborted",e[e.Errored=1]="Errored",e))(Q||{});class X extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const Y=c.createContext(null);function Z(e){const t=new Map,n=e??{get:e=>t.get(e)??null,set:(e,n)=>{t.set(e,n)},remove:e=>{t.delete(e)},clear:()=>{t.clear()}};return{get(e){try{const t=n.get(e);if(r.G.isNull(t))return K();const o=JSON.parse(t);return V(o.data,Temporal.Instant.from(o.at))}catch{return K()}},set(e,t){if(t.data===z||r.G.isNull(t.at))return!1;try{return n.set(e,JSON.stringify({data:t.data,at:t.at.toString()})),!0}catch{return!1}},remove(e){n.remove(e)},clear(){n.clear()}}}function ee(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new X);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new X)},{once:!0})})}async function te(e,t,n){if(t?.aborted)throw new X;for(;;){if(await n())return;await ee(e,t)}}function ne(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const re=Object.freeze(Object.defineProperty({__proto__:null,pk:ne,poll:te,sleep:ee,unset:z,"ζ":ee,"κ":ne,"π":te},Symbol.toStringTag,{value:"Module"})),oe=new WeakMap;function se(e){return JSON.stringify(e)}let ce=null;function ae(){if(r.G.isNull(ce))throw new Error("context.actions.resource(...) and context.actions.resource.set(...) must be called with a fresh resource invocation, e.g. context.actions.resource(resource.cat({ id: 5 })).");const e=ce;return ce=null,e}function ie(e,t){const n=e=>{const n=t.get(se(e));return n.data===z||r.G.isNull(n.at)?{data:z,at:null}:{data:n.data,at:n.at}},o=(n,r,o,s)=>e({env:n,controller:r,params:o,dispatch:s}).then(e=>(t.set(se(o),V(e,Temporal.Now.instant())),e)),s=(e,n,r)=>{t.set(se(e),V(n,r))};return function(e){const t=e??{};ce={run:o,read:n,seed:s,params:t},queueMicrotask(()=>{r.G.isNotNullable(ce)&&ce.params===t&&(ce=null)});const{data:c}=n(t);return c===z?null:c}}function ue(e){return ie(e,function(e){let t=oe.get(e);return r.G.isUndefined(t)&&(t=Z(),oe.set(e,t)),t}(e))}(ue||(ue={})).Cachable=function(e,t){return ie(t,e)};const le=Symbol("march-hare.coalesce/default");function fe(e,t){return new Promise((n,r)=>{if(t.aborted)return void r(t.reason);const o=()=>r(t.reason);t.addEventListener("abort",o,{once:!0}),e.then(e=>{t.removeEventListener("abort",o),n(e)},e=>{t.removeEventListener("abort",o),r(e)})})}let de=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var pe=(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))(pe||{}),he=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(he||{}),me=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(me||{});class be{[o.immerable]=!0;static keys=new Set(Object.values(me));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new be(this.value,this.operation);return n.property=e,n.process=t,n}}class ye{static immer=(()=>{o.enablePatches();const e=new o.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=de}function ve(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 ge(e){if(r.G.isNullable(e)||xe(e))return e;if(r.G.isArray(e))return e.map(e=>ge(e));if(r.G.isObject(e)&&je(e)){const t=Object.entries(e).map(([e,t])=>[e,ge(t)]);return{...Object.fromEntries(t),[ye.tag]:e[ye.tag]??ye.id()}}return e}function we(e){if(Array.isArray(e))return e.filter(e=>ye.tag in e).map(e=>e[ye.tag]??"").join(",");const t=e[ye.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function je(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function xe(e){return r.G.isNullable(e)||r.G.isString(e)||r.G.isNumber(e)||r.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function Oe(e,t,n,o,s,c){return function a(i,u=t.path){if(i instanceof be){const t=ve(n,u.join("."));if(Object.entries(i).filter(([e,t])=>!be.keys.has(e)&&t instanceof be).forEach(([e,t])=>a(t,u.concat(e))),xe(i.value)){if(e===he.Hydrate)return i.value;const a=u.slice(0,-1),l=a.length>0?ve(n,a.join(".")):n;return r.G.isNullable(l)||Pe(l,i,u.at(-1),o,s,c),t??i.value}if(e===he.Hydrate){const e=ge(a(i.value,u));return Pe(e,i,null,o,s,c),e}const l=t??ge(i.value);return Pe(l,i,null,o,s,c),r.G.isNullable(t)?l:(a(i.value,u),t)}if(r.G.isArray(i))return i.map((e,t)=>a(e,u.concat(t)));if(r.G.isObject(i)&&!je(i))return i;if(r.G.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,a(t,u.concat(e))]),n=Object.fromEntries(t);if(e===he.Hydrate){const e=ge(n);return Object.entries(i).forEach(([t,n])=>{n instanceof be&&xe(n.value)&&Pe(e,n,t,o,s,c)}),e}return n}return i}(t.value)}function Pe(e,t,n,r,o,s){const c=s(e),a=o.get(c)??[];o.set(c,[t.assign(n,r),...a])}class Se{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=we){this.#t=e}static pk(){return de()}static"κ"=Se.pk;annotate(e,t){return new be(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,t,n,o,s){function c(o){const s=o.at(-1),c=ve(e(),o),a=o.slice(0,-1),i=r.A.isNotEmpty(a)?ve(e(),a):e();return[...r.G.isObject(c)||r.G.isArray(c)?t.get(n(c))?.filter(e=>r.G.isNullable(e.property))??[]:[],...r.G.isObject(i)?t.get(n(i))?.filter(e=>e.property===s)??[]:[]]}return function t(n){return new Proxy(()=>{},{get:(a,i)=>"pending"===i?()=>!r.A.isEmpty(c(n)):"remaining"===i?()=>r.A.length(c(n)):"box"===i?()=>({value:ve(e(),n),inspect:t(n)}):"is"===i?e=>c(n).some(t=>0!==(t.operation&e)):"draft"===i?()=>r.A.head(c(n))?.value??ve(e(),n):"settled"===i?()=>new Promise(t=>{if(r.A.isEmpty(c(n)))return t(ve(e(),n));const a=()=>{r.A.isEmpty(c(n))&&(s(a),t(ve(e(),n)))};o(a)}):t([...n,String(i)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(he.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(he.Produce,e)}#s(e,t){const n=Symbol("process"),[,r]=ye.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>ye.immer.applyPatches(t,[{...r,value:Oe(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=ge(this.#e),this.#c(),n}prune(e){this.#n.forEach((t,n)=>{const o=t.filter(t=>t.process!==e);r.A.isEmpty(o)?this.#n.delete(n):this.#n.set(n,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const Ce=c.createContext(new Map);function Ee({action:e,renderer:t}){const n=h(),o=c.useContext(Ce),s=J(),a=c.useMemo(()=>{const t=o.get(e);if(t)return t;const s=new Se,c=n.getCached(e);r.G.isNotNullable(c)&&s.hydrate({value:c});const a={state:s,listeners:new Set};return o.set(e,a),a},[e,n,o]);c.useLayoutEffect(()=>{function t(e){a.state.hydrate({value:e}),a.listeners.forEach(e=>e())}return a.listeners.add(s),n.on(e,t),()=>{a.listeners.delete(s),n.off(e,t)}},[e,n,a]);const i=a.state.model?.value;return r.G.isNullable(i)?null:t(i,a.state.inspect.value)}function Ge(e,t){const n=t.split(".");let r=e;for(let o=0;o<n.length-1;o++)r=r[n[o]];return{cursor:r,key:n[n.length-1]}}function Ae(e,t,n){const{cursor:r,key:o}=Ge(e,t);r[o]=n}function Me(e){return(t,n)=>{t.actions.produce(t=>{Ae(t.model,e,n)})}}function ke(e){return t=>{t.actions.produce(t=>{!function(e,t){const{cursor:n,key:r}=Ge(e,t);n[r]=!n[r]}(t.model,e)})}}function Ne(e,t){return n=>{n.actions.produce(n=>{Ae(n.model,e,t)})}}const Re={Update:e=>Me(e),Invert:e=>ke(e),Always:(e,t)=>Ne(e,t)};function _e(){const e=c.useRef(null);return c.useMemo(()=>({actions:{dispatch:function(t,n){const r=e.current;if(!r)throw new Error("march-hare: useContext handle dispatched before its paired context.useActions(...) ran. Call context.actions.dispatch from event handlers, not synchronously during render.");return r(t,n)}},useActions:function(...t){const n=function(...e){const t=r.G.isUndefined(e[0])||r.G.isFunction(e[0])?{}:e[0],n=r.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),s=h(),a=c.useContext(Y),i=c.useContext(b),u=g(),l=c.useContext(v),d=c.useContext(N),p=c.useContext(_),m=J(),y=c.useRef(!1),j=c.useRef(null),x=c.useRef(new Se);y.current||(y.current=!0,j.current=x.current.hydrate(t));const[O,P]=c.useState(()=>x.current.model),S=function(e){const t=c.useRef(e);return t.current=e,c.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(n()),G=c.useMemo(()=>new f,[]),A=c.useRef({handlers:new Map});A.current.handlers=new Map;const k=function(){const e=c.useRef(new Set),t=c.useRef(new Set);return c.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),R=c.useRef(M.Mounting),U=c.useRef(new Set),L=c.useRef(0),T=c.useCallback((e,t,n)=>{const c=new AbortController,f={controller:c,action:e,payload:t};return i.add(f),U.current.add(f),{model:x.current.model,get phase(){return R.current},task:f,data:S,tasks:i,env:u,actions:{produce(e){if(c.signal.aborted)return;const t=l.current,r=x.current.produce(t=>{l.current=o.produce(l.current,n=>{e({model:t,inspect:x.current.inspect,env:n})})});P(x.current.model),l.current!==t&&s.emit(E,l.current),n.processes.add(r),j.current&&(n.processes.add(j.current),j.current=null)},dispatch(e,t){if(c.signal.aborted)return Promise.resolve();const n=W(e),r=$(e)?e.channel:void 0;return D(e)?a?H(a.emitter,n,t,r):Promise.resolve():H(B(e)?s:G,n,t,r)},annotate:(e,t=pe.Update)=>x.current.annotate(t,e),get inspect(){return x.current.inspect},resource:Object.assign(function(e){const t=ae(),n=(e,t)=>{if(c.signal.aborted)return Promise.resolve();const n=e,r=W(n);return D(n)?a?H(a.emitter,r,t,void 0):Promise.resolve():B(n)?H(s,r,t,void 0):Promise.resolve()},o={exceedsWindow:null,coalesceToken:void 0},i={then:(e,s)=>(()=>{if(r.G.isNotNullable(o.exceedsWindow)){const{data:e,at:n}=t.read(t.params);if(e!==z&&r.G.isNotNullable(n)){const t=Temporal.Now.instant().since(n),r=Temporal.Duration.from(o.exceedsWindow);if(Temporal.Duration.compare(t,r)<=0)return Promise.resolve(e)}}if(r.G.isUndefined(o.coalesceToken))return t.run(u,c,t.params,n);let e=d.get(t.run);r.G.isUndefined(e)&&(e=new Map,d.set(t.run,e));const s=e,a=`${JSON.stringify(t.params)}|${function(e){switch(typeof e){case"string":return`s:${e}`;case"number":return`n:${e}`;case"bigint":return`i:${e.toString()}`;case"boolean":return`b:${e}`;case"symbol":return`y:${e.description??String(e)}`;default:return`o:${JSON.stringify(e)}`}}(o.coalesceToken)}`,i=s.get(a);if(i)return fe(i,c.signal);const l=new AbortController,f=t.run(u,l,t.params,n).finally(()=>{s.delete(a)});return s.set(a,f),fe(f,c.signal)})().then(e,s),exceeds:e=>(o.exceedsWindow=e,i),coalesce:e=>(o.coalesceToken=e??le,i)};return i},{set:(e,t)=>{const n=ae();n.seed(n.params,t,Temporal.Now.instant())}}),async final(e){if(c.signal.aborted)return null;const t=W(e),n=D(e)?a?.emitter??null:s;if(!n)return null;const o=n.getCached(t);if(r.G.isUndefined(o))return null;const i=x.current.inspect;return i.pending()&&await new Promise((e,t)=>{if(c.signal.aborted)return void t(c.signal.reason);const n=()=>t(c.signal.reason);c.signal.addEventListener("abort",n,{once:!0}),i.settled().then(()=>{c.signal.removeEventListener("abort",n),e()})}),n.getCached(t)??null},peek(e){if(c.signal.aborted)return null;const t=W(e),n=D(e)?a?.emitter??null:s;return n?n.getCached(t)??null:null}}}},[O]);c.useLayoutEffect(()=>{function e(e,t,n){return function(o,c){const a=n();if(c===I&&r.G.isNotNullable(a))return;if(r.G.isNotNullable(c)&&c!==I&&r.G.isNotNullable(a)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,a))return;const u={processes:new Set},f=Promise.withResolvers(),d=T(e,o,u),h=function(e){const t=W(e),n=r.G.isString(t)?t:t.description??"";return n.startsWith(w())&&n.slice(n.lastIndexOf("/")+1)||"unknown"}(e),b=performance.now(),y=x.current.model,v=l.current;let g,j=!1;function O(){const e=x.current.model,t=l.current;return{model:y===e?null:{before:y,after:e},env:v===t?null:{before:v,after:t}}}function P(e){j=!0;const t=q(A.current.handlers,"Error"),n=r.G.isNotNullable(t),c=function(e){return e instanceof Error&&"AbortError"===e.name?Q.Aborted:Q.Errored}(e),a=function(e){return e instanceof Error?e:new Error(String(e))}(e),u={reason:c,error:a,action:h,handled:n,tasks:i};s.fire(C,u),n&&t&&G.emit(t,u),p({stage:"end",result:"error",action:{name:h,payload:o},details:{task:d.task,elapsed:performance.now()-b,mutations:O(),error:a,reason:c}})}function S(){for(const e of i)if(e===d.task){i.delete(e),U.current.delete(e);break}u.processes.forEach(e=>x.current.prune(e)),u.processes.size>0&&m(),j||p({stage:"end",result:"success",action:{name:h,payload:o},details:{task:d.task,elapsed:performance.now()-b,mutations:O()}}),f.resolve()}p({stage:"start",action:{name:h,payload:o},details:{task:d.task}});try{g=t(d,o)}catch(E){return P(E),S(),f.promise}return function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(g)?((async()=>{for await(const e of g);})().catch(P).finally(S),f.promise):(Promise.resolve(g).catch(P).finally(S),f.promise)}}L.current++;const t=new Set;return A.current.handlers.forEach((n,r)=>{for(const{getChannel:o,handler:c}of n){const n=e(r,c,o);if(D(r)){if(a){const e=a.emitter;e.on(r,n),t.add(()=>e.off(r,n))}G.on(r,n),k.multicast.add(r),t.add(()=>G.off(r,n))}else B(r)?(s.on(r,n),G.on(r,n),k.broadcast.add(r),t.add(()=>{s.off(r,n),G.off(r,n)})):(G.on(r,n),t.add(()=>G.off(r,n)))}}),()=>{const e=++L.current,n=new Set(t);queueMicrotask(()=>{if(L.current!==e){for(const e of n)e();return}for(const e of U.current)e.controller.abort(),i.delete(e);U.current.clear(),R.current=M.Unmounting;const t=q(A.current.handlers,"Unmount");t&&G.emit(t),R.current=M.Unmounted;for(const e of n)e()})}},[G]),function({unicast:e,broadcast:t,dispatchers:n,scope:o,phase:s,data:a,handlers:i}){const u=c.useRef(null);c.useLayoutEffect(()=>{if(s.current===M.Mounted)return;s.current=M.Mounting;const c=q(i,"Mount");c&&e.emit(c),n.broadcast.forEach(n=>{const o=t.getCached(n);r.G.isNullable(o)||e.emit(n,o,I)}),o&&n.multicast.forEach(t=>{const n=o.emitter.getCached(t);r.G.isNullable(n)||e.emit(t,n,I)}),s.current=M.Mounted},[]),c.useLayoutEffect(()=>{if(r.G.isNotNullable(u.current)){const t=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,a);if(r.A.isNotEmpty(Object.keys(t))){const n=q(i,"Update");n&&e.emit(n,t)}}u.current=a},[a,e])}({unicast:G,broadcast:s,dispatchers:k,scope:a,phase:R,data:n(),handlers:A.current.handlers});const F=c.useMemo(()=>({dispatch(e,t){const n=W(e),r=$(e)?e.channel:void 0;return D(e)?a?H(a.emitter,n,t,r):Promise.resolve():H(B(e)?s:G,n,t,r)},get inspect(){return x.current.inspect},stream:(e,t)=>c.createElement(Ee,{action:W(e),renderer:t})}),[O,G]),K=c.useMemo(()=>[O,F,S],[O,F,S]);return K.useAction=(e,t)=>{!function(e,t,n){const r=c.useRef(n);c.useLayoutEffect(()=>{r.current=n});const o=c.useRef(t);c.useLayoutEffect(()=>{o.current=t});const s=c.useCallback((e,t)=>r.current(e,t),[]),a=c.useCallback(()=>$(o.current)?o.current.channel:void 0,[]),i=W(t),u=e.current.handlers.get(i)??new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:a,handler:s})}(A,e,t)},K.dispatch=K[1].dispatch,K}(...t);return e.current=n.dispatch,n},with:{update:e=>Me(e),invert:e=>ke(e),always:(e,t)=>Ne(e,t)}}),[])}const Ue=new Se;e.Aborted=X,e.Action=(e="",t=A.Unicast)=>{const n=t===A.Broadcast?Symbol(j(e)):t===A.Multicast?Symbol(x(e)):Symbol(w(e)),r=function(t){return{[P.Action]:n,[P.Payload]:void 0,[P.Channel]:t,[P.Name]:e,channel:t}};return Object.defineProperty(r,P.Action,{value:n,enumerable:!1}),Object.defineProperty(r,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(r,P.Name,{value:e,enumerable:!1}),t===A.Broadcast&&Object.defineProperty(r,P.Broadcast,{value:!0,enumerable:!1}),t===A.Multicast&&Object.defineProperty(r,P.Multicast,{value:!0,enumerable:!1}),r},e.App=function(e){return{Boundary:function({env:n,tap:r,children:o}){return t.jsx(L,{env:n??e?.env,tap:r??e?.tap,children:o})},useContext:function(){return _e()},useEnv:function(){return g()},Resource:Object.assign(function(e){return ue(e)},{Cachable:(e,t)=>ue.Cachable(e,t)}),Scope:()=>({Boundary:function({children:e}){const n=c.useMemo(()=>({id:Symbol("march-hare.scope/instance"),emitter:new d}),[]);return t.jsx(Y.Provider,{value:n,children:e})},useContext:function(){return _e()},useEnv:function(){return g()},Resource:Object.assign(function(e){return ue(e)},{Cachable:(e,t)=>ue.Cachable(e,t)})})}},e.Boundary=L,e.Cache=Z,e.Distribution=A,e.Lifecycle=G,e.Op=pe,e.Operation=pe,e.Reason=Q,e.Resource=ue,e.State=Se,e.With=Re,e.annotate=function(e,t=pe.Update){return Ue.annotate(t,e)},e.utils=re,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("react/jsx-runtime"),require("react"),require("@mobily/ts-belt"),require("immer")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react","@mobily/ts-belt","immer"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).MarchHare={},global.jsxRuntime,global.React,global.TsBelt,global.Immer);
@@ -19,8 +19,11 @@ export declare function consumePending(): PendingCall;
19
19
  *
20
20
  * The fetcher receives a single `context` argument carrying `env`,
21
21
  * `controller`, `params`, and a broadcast/multicast-only `dispatch`.
22
- * Every successful fetch writes through to a per-resource in-memory
23
- * cache; pair with {@link Resource.Cachable} to persist across reloads.
22
+ * `env` is a live handle &mdash; dot reads inside the fetcher
23
+ * always see the latest per-`<Boundary>` Env, even after `await`
24
+ * boundaries. Every successful fetch writes through to a per-resource
25
+ * in-memory cache; pair with {@link Resource.Cachable} to persist
26
+ * across reloads.
24
27
  *
25
28
  * Concurrent calls fire fresh requests by default. Opt in to in-flight
26
29
  * sharing per call via `.coalesce(key)` on the thenable returned from
@@ -13,8 +13,11 @@ export type Dispatch = {
13
13
  /**
14
14
  * `context` object passed to every {@link Fetcher}.
15
15
  *
16
- * - `env` &mdash; snapshot of the per-`<Boundary>` Env at the
17
- * moment the fetcher is invoked.
16
+ * - `env` &mdash; live read-only handle to the per-`<Boundary>` Env.
17
+ * Dot reads always reflect the latest value, even across `await`
18
+ * boundaries inside the fetcher &mdash; the handle is a `Proxy`
19
+ * that delegates property access to the live ref, identical to
20
+ * the `context.env` exposed to action handlers.
18
21
  * - `controller` &mdash; the `AbortController` auto-threaded from the
19
22
  * calling handler's `context.task.controller`. Pass
20
23
  * `controller.signal` to `fetch`/`ky`/`EventSource`, or call
@@ -33,7 +36,7 @@ export type Args<P extends object = Record<never, never>> = {
33
36
  };
34
37
  /**
35
38
  * Fetcher signature accepted by `Resource`. Receives a single `context`
36
- * argument carrying the Env snapshot, the abort controller, params,
39
+ * argument carrying a live Env handle, the abort controller, params,
37
40
  * and a broadcast/multicast-only `dispatch`.
38
41
  */
39
42
  export type Fetcher<T, P extends object = Record<never, never>> = (context: Args<P>) => Promise<T>;
@@ -20,7 +20,7 @@ export declare function defaultCache(fetcher: object): Cache;
20
20
  /**
21
21
  * Stable string key derived from the call-site `params`. Two calls with
22
22
  * the same logical params (same key order, same primitive values) hit
23
- * the same slot. JSON.stringify is sufficient for the Chizu params
23
+ * the same slot. JSON.stringify is sufficient for the March Hare params
24
24
  * convention (primitive-leaf objects); callers who need order-stable
25
25
  * keying should normalise the object before passing it in.
26
26
  *
@@ -3,6 +3,7 @@ import { ActionId, Task, Tasks } from '../boundary/components/tasks/types';
3
3
  import { Fault } from '../error/types';
4
4
  import { Env } from '../boundary/components/env/index';
5
5
  import { Coalesce } from '../resource/types';
6
+ import { WithHandle } from '../with/index';
6
7
  import * as React from "react";
7
8
  /**
8
9
  * Chainable handle returned from `context.actions.resource(invocation)`.
@@ -482,16 +483,19 @@ export type Filter = Record<string, string | number | bigint | boolean | symbol>
482
483
  */
483
484
  export type ActionOrChanneled<A extends HandlerPayload = HandlerPayload> = A | ChanneledAction;
484
485
  /**
485
- * Checks if a function type returns a Promise.
486
- * @internal
487
- */
488
- type IsAsync<F> = F extends (...args: unknown[]) => Promise<unknown> ? true : false;
489
- /**
490
- * Type guard that produces a compile-time error if an async function is passed.
491
- * Used to enforce synchronous callbacks in `produce()`.
486
+ * Type guard that produces a compile-time error if an async function is
487
+ * passed. Used to enforce synchronous callbacks in `produce()`.
488
+ *
489
+ * The `[F]` tuple wrapping prevents distribution over function unions, and
490
+ * checking the actual signature (`(...args: never[]) => Promise<unknown>`)
491
+ * sidesteps TypeScript's lenient `Promise<void>`→`void` assignability that
492
+ * would otherwise let an async recipe satisfy a `(draft) => void`
493
+ * constraint. Async F collapses the argument type to `never`, which no
494
+ * function value can satisfy.
495
+ *
492
496
  * @internal
493
497
  */
494
- type AssertSync<F> = IsAsync<F> extends true ? "Error: async functions are not allowed in produce" : F;
498
+ type AssertSync<F> = [F] extends [(...args: never[]) => Promise<unknown>] ? never : F;
495
499
  /**
496
500
  * Base type for data props passed to useActions.
497
501
  * Represents any object that can be captured as reactive data.
@@ -509,17 +513,17 @@ export type Actions = object;
509
513
  export type Result = {
510
514
  processes: Set<Process>;
511
515
  };
512
- export type HandlerContext<M extends Model | void, AC extends Actions | void, D extends Props = Props> = {
516
+ export type HandlerContext<M extends Model | void, AC extends Actions | void, D extends Props = Props, S extends Env = Env> = {
513
517
  readonly model: DeepReadonly<M>;
514
518
  readonly phase: Phase;
515
519
  readonly task: Task;
516
520
  readonly data: DeepReadonly<D>;
517
521
  readonly tasks: ReadonlySet<Task>;
518
- readonly env: DeepReadonly<Env>;
522
+ readonly env: Readonly<S>;
519
523
  readonly actions: {
520
524
  produce<F extends (draft: {
521
525
  model: M;
522
- env: Env;
526
+ env: S;
523
527
  readonly inspect: Readonly<Inspect<M>>;
524
528
  }) => void>(ƒ: F & AssertSync<F>): void;
525
529
  dispatch(action: NoPayloadActions<Dispatchable<AC>>): Promise<void>;
@@ -550,7 +554,7 @@ export type HandlerContext<M extends Model | void, AC extends Actions | void, D
550
554
  * @example
551
555
  * ```tsx
552
556
  * const [model, actions, data] = useActions<Model, typeof Actions, Data>(
553
- * initialModel,
557
+ * model,
554
558
  * () => ({ user, theme }),
555
559
  * );
556
560
  *
@@ -578,7 +582,7 @@ export type HandlerContext<M extends Model | void, AC extends Actions | void, D
578
582
  *
579
583
  * @see {@link Handlers} for the recommended HKT pattern
580
584
  */
581
- 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;
585
+ export type Handler<M extends Model | void, AC extends Actions | void, K extends keyof AC & string, D extends Props = Props, S extends Env = Env> = (context: HandlerContext<M, AC, D, S>, ...args: [Payload<AC[K] & HandlerPayload<unknown>>] extends [never] ? [] : [payload: Payload<AC[K] & HandlerPayload<unknown>>]) => void | Promise<void> | AsyncGenerator | Generator;
582
586
  /**
583
587
  * String keys of `AC` excluding inherited `prototype` from class constructors.
584
588
  * When action containers are classes (`typeof MyActions`), TypeScript includes
@@ -667,10 +671,10 @@ export type WithPayloadActions<U> = Exclude<U, {
667
671
  * export const handlePaymentSent: H["Broadcast"]["PaymentSent"] = (context) => { ... };
668
672
  * ```
669
673
  */
670
- export type Handlers<M extends Model | void, AC extends Actions | void, D extends Props = Props, RootAC extends Actions | void = AC> = {
671
- [K in OwnKeys<AC>]: OwnKeys<AC[K]> extends never ? (context: HandlerContext<M, RootAC, 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, RootAC>;
674
+ export type Handlers<M extends Model | void, AC extends Actions | void, D extends Props = Props, RootAC extends Actions | void = AC, S extends Env = Env> = {
675
+ [K in OwnKeys<AC>]: OwnKeys<AC[K]> extends never ? (context: HandlerContext<M, RootAC, D, S>, ...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, RootAC, S>;
672
676
  };
673
- export type UseActions<M extends Model | void, AC extends Actions | void, D extends Props = Props> = [
677
+ export type UseActions<M extends Model | void, AC extends Actions | void, D extends Props = Props, S extends Env = Env> = [
674
678
  Readonly<M>,
675
679
  {
676
680
  /**
@@ -703,6 +707,7 @@ export type UseActions<M extends Model | void, AC extends Actions | void, D exte
703
707
  * );
704
708
  * ```
705
709
  */
710
+ stream(action: typeof Lifecycle.Env, renderer: (value: Readonly<S>, inspect: Inspect<S>) => React.ReactNode): React.ReactNode;
706
711
  stream<T extends object>(action: BroadcastPayload<T>, renderer: (value: T, inspect: Inspect<T>) => React.ReactNode): React.ReactNode;
707
712
  },
708
713
  DeepReadonly<D>
@@ -743,8 +748,9 @@ export type UseActions<M extends Model | void, AC extends Actions | void, D exte
743
748
  * });
744
749
  * ```
745
750
  */
746
- useAction(action: NoPayloadActions<Subscribable<AC>>, handler: (context: HandlerContext<M, AC, D>) => void | Promise<void> | AsyncGenerator | Generator): void;
747
- useAction<A extends WithPayloadActions<Subscribable<AC>>>(action: A, handler: (context: HandlerContext<M, AC, D>, payload: Payload<A>) => void | Promise<void> | AsyncGenerator | Generator): void;
751
+ useAction(action: NoPayloadActions<Subscribable<AC>>, handler: (context: HandlerContext<M, AC, D, S>) => void | Promise<void> | AsyncGenerator | Generator): void;
752
+ useAction(action: typeof Lifecycle.Env, handler: (context: HandlerContext<M, AC, D, S>, env: Readonly<S>) => void | Promise<void> | AsyncGenerator | Generator): void;
753
+ useAction<A extends WithPayloadActions<Subscribable<AC>>>(action: A, handler: (context: HandlerContext<M, AC, D, S>, payload: Payload<A>) => void | Promise<void> | AsyncGenerator | Generator): void;
748
754
  };
749
755
  /**
750
756
  * Stable, typed dispatch function for the actions class `AC`. Same call
@@ -767,10 +773,16 @@ export type Dispatch<AC extends Actions | void> = {
767
773
  * `React.Context` &mdash; it's the March Hare action surface returned by
768
774
  * the `useContext` hook of this library.
769
775
  */
770
- export type Context<M extends Model | void, AC extends Actions | void, D extends Props = Props> = {
776
+ export type Context<M extends Model | void, AC extends Actions | void, D extends Props = Props, S extends Env = Env> = {
771
777
  readonly actions: {
772
778
  dispatch: Dispatch<AC>;
773
779
  };
774
- useActions(getData?: () => D): UseActions<M, AC, D>;
775
- useActions(initialModel: M extends void ? never : M, getData?: () => D): UseActions<M, AC, D>;
780
+ /**
781
+ * Typed bag of handler factories bound to `M`. Methods accept lodash-style
782
+ * dotted paths with array indices (e.g. `"a.b.c"`, `"items.0.id"`) and
783
+ * autocomplete from the model. See {@link WithHandle}.
784
+ */
785
+ readonly with: WithHandle<M>;
786
+ useActions(getData?: () => D): UseActions<M, AC, D, S>;
787
+ useActions(model: M extends void ? never : M, getData?: () => D): UseActions<M, AC, D, S>;
776
788
  };
@@ -1,40 +1,111 @@
1
1
  import { Actions, HandlerContext, Model, Props } from '../types/index';
2
+ import { Env } from '../boundary/components/env/index';
3
+ type Primitive = string | number | bigint | boolean | symbol | null | undefined;
4
+ type Depth = [never, 0, 1, 2, 3, 4, 5];
2
5
  /**
3
- * Handler factories that wire an action directly to a model field.
6
+ * Lodash-style dotted paths reachable from `T`. Yields `"a"`, `"a.b"`,
7
+ * `"items.0"`, `"items.0.name"`, etc. Recursion is capped at depth 5 to
8
+ * keep the type-checker tractable on deeply nested models.
4
9
  *
5
- * - {@link With.Update} assigns the dispatched payload to `model[key]`.
6
- * - {@link With.Invert} flips a boolean field on `model[key]`.
10
+ * @template T The object type to enumerate paths from.
11
+ * @template D Recursion budget (internal).
12
+ */
13
+ export type Paths<T, D extends number = 5> = [D] extends [never] ? never : T extends Primitive ? never : T extends ReadonlyArray<infer U> ? `${number}` | (U extends Primitive ? never : `${number}.${Paths<U, Depth[D]>}`) : T extends object ? {
14
+ [K in Extract<keyof T, string>]: T[K] extends Primitive ? K : K | `${K}.${Paths<T[K], Depth[D]>}`;
15
+ }[Extract<keyof T, string>] : never;
16
+ /**
17
+ * Subset of {@link Paths} whose leaf type is `boolean`. Used by
18
+ * `context.with.invert` (and the legacy {@link With.Invert}) to restrict the
19
+ * key to togglable fields only.
20
+ *
21
+ * @template T The object type to enumerate boolean leaves from.
22
+ * @template D Recursion budget (internal).
23
+ */
24
+ export type BooleanPaths<T, D extends number = 5> = [D] extends [never] ? never : T extends Primitive ? never : T extends ReadonlyArray<infer U> ? (U extends boolean ? `${number}` : never) | (U extends Primitive ? never : `${number}.${BooleanPaths<U, Depth[D]>}`) : T extends object ? {
25
+ [K in Extract<keyof T, string>]: T[K] extends boolean ? K : T[K] extends Primitive ? never : `${K}.${BooleanPaths<T[K], Depth[D]>}`;
26
+ }[Extract<keyof T, string>] : never;
27
+ /**
28
+ * Resolves the leaf type at a dotted path on `T`. `Get<{a:{b:number}},"a.b">`
29
+ * is `number`; `Get<{items: string[]},"items.0">` is `string`.
7
30
  *
8
- * Both are typed so the call site fails to compile when `key` is missing or
9
- * has an incompatible type.
31
+ * @template T The object type to walk.
32
+ * @template P The dotted path string.
33
+ */
34
+ export type Get<T, P extends string> = P extends `${infer Head}.${infer Tail}` ? T extends ReadonlyArray<infer U> ? Head extends `${number}` ? Get<U, Tail> : never : Head extends keyof T ? Get<T[Head], Tail> : never : T extends ReadonlyArray<infer U> ? P extends `${number}` ? U : never : P extends keyof T ? T[P] : never;
35
+ /**
36
+ * Returned by `context.with` &mdash; a typed bag of handler factories
37
+ * bound to the model `M` declared in `useContext<M, …>()`. Methods accept
38
+ * lodash-style dotted paths (`"a.b.c"`) with array indices (`"items.0.id"`).
39
+ *
40
+ * - `update(key)` &mdash; assigns the dispatched payload to `model[key]`.
41
+ * - `invert(key)` &mdash; flips a boolean leaf at `model[key]`.
42
+ * - `always(key, value)` &mdash; assigns a fixed `value` to `model[key]`,
43
+ * ignoring any dispatched payload.
44
+ *
45
+ * @template M The model type to bind keys against.
46
+ */
47
+ export type WithHandle<M> = M extends Model ? {
48
+ update<K extends Paths<M>>(key: K): <A extends Actions | void, D extends Props, S extends Env = Env>(context: HandlerContext<M, A, D, S>, payload: Get<M, K>) => void;
49
+ invert<K extends BooleanPaths<M>>(key: K): <A extends Actions | void, D extends Props, S extends Env = Env>(context: HandlerContext<M, A, D, S>) => void;
50
+ always<K extends Paths<M>>(key: K, value: Get<M, K>): <A extends Actions | void, D extends Props, S extends Env = Env>(context: HandlerContext<M, A, D, S>) => void;
51
+ } : Record<string, never>;
52
+ /**
53
+ * Builds the {@link WithHandle} object returned via `context.with`. The
54
+ * runtime is identical for any model &mdash; only the call-site types differ.
55
+ *
56
+ * @internal
57
+ */
58
+ export declare function bindWith<M extends Model | void>(): WithHandle<M>;
59
+ /**
60
+ * Handler factories that wire an action directly to a model field. Prefer
61
+ * `context.with` from `useContext<Model>()` for first-class autocompletion
62
+ * over dotted paths; this top-level form is kept for callers that don't have
63
+ * a typed `context` in scope.
64
+ *
65
+ * - {@link With.Update} assigns the dispatched payload to a model path.
66
+ * - {@link With.Invert} flips a boolean leaf at a model path.
67
+ * - {@link With.Always} assigns a fixed value to a model path, ignoring any
68
+ * dispatched payload.
69
+ *
70
+ * Keys may be lodash-style dotted paths (`"a.b.c"`) and support array
71
+ * indices (`"items.0.name"`). The model type is inferred at handler-bind
72
+ * time; an invalid path or mismatched payload fails to compile when the
73
+ * handler is registered with `useAction`.
10
74
  *
11
75
  * @example
12
76
  * ```ts
13
77
  * import { With } from "march-hare";
14
78
  *
15
- * type Model = { name: string; sidebar: boolean };
16
- *
17
- * class Actions {
18
- * static SetName = Action<string>("SetName");
19
- * static ToggleSidebar = Action("ToggleSidebar");
20
- * }
79
+ * type Model = {
80
+ * name: string;
81
+ * sidebar: boolean;
82
+ * nested: { open: boolean };
83
+ * items: { id: number }[];
84
+ * };
21
85
  *
22
86
  * actions.useAction(Actions.SetName, With.Update("name"));
87
+ * actions.useAction(Actions.SetFirstId, With.Update("items.0.id"));
23
88
  * actions.useAction(Actions.ToggleSidebar, With.Invert("sidebar"));
89
+ * actions.useAction(Actions.ToggleNested, With.Invert("nested.open"));
90
+ * actions.useAction(Actions.Open, With.Always("nested.open", true));
24
91
  * ```
25
92
  */
26
93
  export declare const With: {
27
94
  /**
28
- * Returns a handler that assigns the action payload to `model[key]`.
29
- *
30
- * Type-checks at the call site: the payload type must be assignable to
31
- * the model property's type, and the key must exist on the model.
95
+ * Returns a handler that assigns the action payload to the model leaf at
96
+ * the given lodash-style path. The payload type must match `Get<M, K>`,
97
+ * and the path must exist on the model.
98
+ */
99
+ Update<K extends string>(key: K): <M extends Model, A extends Actions | void, D extends Props, P extends K extends Paths<M> ? Get<M, K> : never, S extends Env = Env>(context: HandlerContext<M, A, D, S>, payload: P) => void;
100
+ /**
101
+ * Returns a handler that inverts a boolean leaf at the given lodash-style
102
+ * path. The leaf must be a `boolean` on the model.
32
103
  */
33
- Update<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;
104
+ Invert<K extends string>(key: K): <M extends Model, A extends Actions | void, D extends Props, S extends Env = Env>(context: K extends BooleanPaths<M> ? HandlerContext<M, A, D, S> : never) => void;
34
105
  /**
35
- * Returns a handler that inverts a boolean field on the model.
36
- *
37
- * Type-checks at the call site: `model[key]` must be a boolean.
106
+ * Returns a handler that assigns a fixed `value` to the model leaf at the
107
+ * given lodash-style path. The dispatched payload (if any) is ignored.
38
108
  */
39
- Invert<K extends string>(key: K): <M extends Model & Record<K, boolean>, A extends Actions | void, D extends Props>(context: HandlerContext<M, A, D>) => void;
109
+ Always<K extends string, V>(key: K, value: V): <M extends Model, A extends Actions | void, D extends Props, S extends Env = Env>(context: K extends Paths<M> ? V extends Get<M, K> ? HandlerContext<M, A, D, S> : never : never) => void;
40
110
  };
111
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "march-hare",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "packageManager": "yarn@1.22.22",