march-hare 0.6.0 → 0.6.1

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
@@ -1,13 +1,19 @@
1
1
  <div align="center">
2
2
  <img src="/media/logo-v3.png" width="475" />
3
3
 
4
- [![Checks](https://github.com/Wildhoney/march-hare/actions/workflows/checks.yml/badge.svg)](https://github.com/Wildhoney/march-hare/actions/workflows/checks.yml)
4
+ <i>❝We're all <ins>mad</ins> here.❞</i>
5
+ <br />
6
+ <sub><strong>M</strong>odel,</sub>
7
+ <sub><strong>A</strong>ctions,</sub>
8
+ <sub><strong>D</strong>ata</sub>
9
+
10
+ [![Checks](https://github.com/Wildhoney/MarchHare/actions/workflows/checks.yml/badge.svg)](https://github.com/Wildhoney/MarchHare/actions/workflows/checks.yml)
5
11
 
6
12
  </div>
7
13
 
8
- Strongly typed React framework using generators and efficiently updated views alongside the publish-subscribe pattern.
14
+ > Strongly typed React framework using generators and efficiently updated views alongside the publish-subscribe pattern.
9
15
 
10
- **[View Live Demo →](https://wildhoney.github.io/march-hare/)**
16
+ > **[View Live Demo →](https://wildhoney.github.io/MarchHare/)**
11
17
 
12
18
  ## Contents
13
19
 
@@ -70,22 +76,33 @@ export default function Profile(): React.ReactElement {
70
76
  }
71
77
  ```
72
78
 
73
- When you need to do more than just assign the payload &ndash; such as making an API request &ndash; expand `useAction` to a full function. It can be synchronous, asynchronous, or even a generator:
79
+ When you need to do more than just assign the payload &ndash; such as making an API request &ndash; expand `useAction` to a full function. It can be synchronous, asynchronous, or even a generator. Remote data goes through `Resource` rather than a bare `fetch` &ndash; declare the resource at module scope and consume it via `useResource`:
80
+
81
+ ```ts
82
+ // resources.ts
83
+ import { Resource } from "march-hare";
84
+
85
+ export const user = Resource(() => ky.get(api.user()).json<User>());
86
+ ```
74
87
 
75
88
  ```tsx
89
+ const get = {
90
+ user: useResource(resource.user),
91
+ };
92
+
76
93
  actions.useAction(Actions.Name, async (context) => {
77
94
  context.actions.produce(
78
- (draft) =>
79
- void (draft.model.name = context.actions.annotate(null, Op.Update)),
95
+ ({ model }) =>
96
+ void (model.name = context.actions.annotate(model.name, Op.Update)),
80
97
  );
81
98
 
82
- const name = await fetch(api.user());
99
+ const data = await get.user();
83
100
 
84
- context.actions.produce((draft) => void (draft.model.name = name));
101
+ context.actions.produce(({ model }) => void (model.name = data.name));
85
102
  });
86
103
  ```
87
104
 
88
- Notice we're using `annotate` which you can read more about in the [Immertation documentation](https://github.com/Wildhoney/Immertation). Nevertheless once the request is finished we update the model again with the `name` fetched from the response and update our React component again.
105
+ Notice we're using `annotate` which you can read more about in the [Immertation documentation](https://github.com/Wildhoney/Immertation). Once the request is finished we update the model again with the name fetched from the response and re-render the React component. `Resource` caches the most recent successful payload and exposes typed params &ndash; the full API is covered [further down](#remote-data).
89
106
 
90
107
  If you need to access external reactive values (like props or `useState` from parent components) that always reflect the latest value even after `await` operations, pass a data callback to `useActions`:
91
108
 
@@ -95,9 +112,13 @@ const actions = useActions<Model, typeof Actions, { query: string }>(
95
112
  () => ({ query: props.query }),
96
113
  );
97
114
 
115
+ const get = {
116
+ search: useResource(resource.search),
117
+ };
118
+
98
119
  actions.useAction(Actions.Search, async (context) => {
99
- await fetch("/search");
100
- // context.data.query is always the latest value
120
+ await get.search({ query: context.data.query });
121
+ // context.data.query is always the latest value, even after await
101
122
  console.log(context.data.query);
102
123
  });
103
124
  ```
@@ -156,38 +177,50 @@ class Actions {
156
177
  ```
157
178
 
158
179
  ```tsx
180
+ const get = {
181
+ user: useResource(resource.user),
182
+ };
183
+
159
184
  actions.useAction(Actions.Profile, async (context) => {
160
185
  context.actions.produce(
161
- (draft) =>
162
- void (draft.model.name = context.actions.annotate(null, Op.Update)),
186
+ ({ model }) =>
187
+ void (model.name = context.actions.annotate(model.name, Op.Update)),
163
188
  );
164
189
 
165
- const name = await fetch(api.user());
190
+ const data = await get.user();
166
191
 
167
- context.actions.produce((draft) => void (draft.model.name = name));
192
+ context.actions.produce(({ model }) => void (model.name = data.name));
168
193
 
169
- context.actions.dispatch(Actions.Broadcast.Name, name);
194
+ context.actions.dispatch(Actions.Broadcast.Name, data.name);
170
195
  });
171
196
  ```
172
197
 
173
198
  Once we have the broadcast action, if we want to listen for it and perform another operation in our local component we can do that via `useAction`:
174
199
 
175
200
  ```tsx
201
+ const get = {
202
+ friends: useResource(resource.friends),
203
+ };
204
+
176
205
  actions.useAction(Actions.Broadcast.Name, async (context, name) => {
177
- const friends = await fetch(api.friends(name));
206
+ const data = await get.friends({ name });
178
207
 
179
- context.actions.produce((draft) => void (draft.model.friends = friends));
208
+ context.actions.produce(({ model }) => void (model.friends = data));
180
209
  });
181
210
  ```
182
211
 
183
212
  Both `read` and `peek` access the latest cached broadcast value without subscribing via `useAction`. The difference is that `read` waits for any pending annotations on the corresponding model field to settle before resolving, whereas `peek` returns the value immediately:
184
213
 
185
214
  ```tsx
215
+ const get = {
216
+ friends: useResource(resource.friends),
217
+ };
218
+
186
219
  actions.useAction(Actions.FetchFriends, async (context) => {
187
220
  const name = await context.actions.resolution(Actions.Broadcast.Name);
188
221
  if (!name) return;
189
- const friends = await fetch(api.friends(name));
190
- context.actions.produce(({ model }) => void (model.friends = friends));
222
+ const data = await get.friends({ name });
223
+ context.actions.produce(({ model }) => void (model.friends = data));
191
224
  });
192
225
  ```
193
226
 
@@ -233,62 +266,90 @@ function Dashboard() {
233
266
 
234
267
  Components that mount after a broadcast has already been dispatched automatically receive the cached value via their `useAction` handler. If you also fetch data in `Lifecycle.Mount()`, see the [mount deduplication recipe](./recipes/mount-broadcast-deduplication.md) to avoid duplicate requests.
235
268
 
236
- For remote data, declare a `Resource` at module scope &ndash; same shape as `Action` &ndash; and consume it via `actions.useResource` inside a component. Convention is to keep all resources in `resources.ts` and import them as a namespace:
269
+ <a id="remote-data"></a>
270
+
271
+ For remote data, declare a `Resource` at module scope and consume it via `useResource`. Every call fires its own request; the most recent successful response is cached in a module-level `WeakMap` keyed by the fetcher so `.if(...)` and `.else(...)` on the bound handle have something to read from. Convention is to keep all resources in `resources.ts` and import them as a namespace:
237
272
 
238
273
  ```ts
239
274
  // resources.ts
240
275
  import { Resource } from "march-hare";
241
276
 
242
- export const user = Resource("user", () => ky.get("/api/user").json<User>());
277
+ export const user = Resource(() => ky.get("/api/user").json<User>());
278
+
279
+ export const pay = Resource((signal, body: Body) =>
280
+ ky.post("/api/pay", { json: body, signal }).json<Receipt>(),
281
+ );
243
282
  ```
244
283
 
245
284
  ```tsx
246
285
  // actions.ts
247
- import * as marchHare from "march-hare";
286
+ import { useActions, useResource } from "march-hare";
248
287
  import * as resource from "./resources";
249
288
 
250
289
  export function useActions() {
251
- const actions = marchHare.useActions<Model, typeof Actions>(initialModel);
252
-
253
- const user = actions.useResource(resource.user);
290
+ // Bind the resources first so we can seed the initial model from the
291
+ // cache via `.else(fallback)` — if a previous mount populated the
292
+ // slot, the model starts with that value; otherwise the fallback.
293
+ // Bindings are grouped by HTTP verb so call sites advertise read vs.
294
+ // write at a glance.
295
+ const get = {
296
+ user: useResource(resource.user),
297
+ };
298
+ const post = {
299
+ pay: useResource(resource.pay),
300
+ };
301
+
302
+ const actions = useActions<Model, typeof Actions>({
303
+ user: get.user.else(null),
304
+ receipt: post.pay.else(null),
305
+ });
254
306
 
255
307
  actions.useAction(Actions.Mount, async (context) => {
256
- const data = await user.run.if({ over: { minutes: 5 } });
257
-
308
+ const data = await get.user.if(
309
+ { over: { minutes: 5 } },
310
+ context.task.controller.signal,
311
+ );
258
312
  context.actions.produce(({ model }) => void (model.user = data));
259
313
  });
260
314
 
315
+ actions.useAction(Actions.Submit, async (context, body) => {
316
+ const receipt = await post.pay(context.task.controller.signal, body);
317
+ context.actions.produce(({ model }) => void (model.receipt = receipt));
318
+ });
319
+
261
320
  return actions;
262
321
  }
263
322
  ```
264
323
 
265
- `actions.useResource(handle)` returns a frozen `{ run, data, at }` object. Every call to `run()` hits the network &ndash; concurrent calls share one in-flight request, but there is no memoised result. `data` and `at` are read-only snapshots of the most recent successful payload and a `Temporal.Instant` of when it resolved (both `null` until the first success). Coordination across components still happens at the broadcast layer; `data` is a diagnostic snapshot, not a reactive subscription. `Temporal` is read from the host runtime &ndash; bring a polyfill (e.g. [`@js-temporal/polyfill`](https://github.com/js-temporal/temporal-polyfill)) if your target environment does not yet expose it natively. `run.if({ over })` accepts a `Temporal.Duration`, a `DurationLike` object, or an ISO 8601 duration string.
324
+ `useResource(handle)` returns the fetch callable directly. The callable has two attached methods: `.if({ over })` skips the network when the cached payload is still fresh, and `.else(fallback)` reads the cached payload synchronously with a default. `Temporal` is read from the host runtime &ndash; bring a polyfill (e.g. [`@js-temporal/polyfill`](https://github.com/js-temporal/temporal-polyfill)) if your target environment does not yet expose it natively. `.if({ over })` accepts a `Temporal.Duration`, a `DurationLike` object, or an ISO 8601 duration string.
266
325
 
267
- `Resource` takes two arguments: a key and a fetcher. The fetcher receives the call-site `params` object as its only argument and returns a `Promise<T>`. There are no callbacks &ndash; no `onSuccess`, no `onError`, no injected `dispatch`. Side-effects after a run (broadcasting, analytics, model writes) live in the `useAction` handler that awaited `run()`, next to the rest of the flow:
326
+ `Resource` takes a single fetcher argument. The fetcher receives the call-site `params` object as its only argument and returns a `Promise<T>`. There are no callbacks &ndash; no `onSuccess`, no `onError`, no injected `dispatch`. Side-effects after a run (broadcasting, analytics, model writes) live in the `useAction` handler that awaited the call, next to the rest of the flow:
268
327
 
269
328
  ```ts
270
- export const user = Resource("user", () => ky.get("/api/user").json<User>());
329
+ export const user = Resource(() => ky.get("/api/user").json<User>());
271
330
 
272
331
  actions.useAction(Actions.Mount, async (context) => {
273
- const data = await user.run();
332
+ const data = await get.user();
274
333
  await context.actions.dispatch(Actions.Broadcast.UserUpdated, data);
275
334
  context.actions.produce(({ model }) => void (model.user = data));
276
335
  });
277
336
  ```
278
337
 
279
- `params` is the second generic on `Resource` and defaults to `{}`. Declare it when the fetcher needs call-time inputs &ndash; cursors, ids, query strings. `params` is a single object (not positional args), which keeps call sites self-documenting and lets in-flight dedup key cleanly per param shape:
338
+ `params` is the second generic on `Resource` and defaults to `{}`. Declare it when the fetcher needs call-time inputs &ndash; cursors, ids, query strings, request bodies. `params` is a single object (not positional args), which keeps call sites self-documenting:
280
339
 
281
340
  ```ts
282
341
  type Params = { cursor: string | null };
283
342
 
284
- export const feed = Resource<Page<Item>, Params>("feed", ({ cursor }) =>
343
+ export const feed = Resource((signal, { cursor }: Params) =>
285
344
  http
286
- .get("feed", { searchParams: { cursor: cursor ?? "" } })
345
+ .get("feed", { searchParams: { cursor: cursor ?? "" }, signal })
287
346
  .json<Page<Item>>(),
288
347
  );
289
348
 
290
- const feed = actions.useResource(resource.feed);
291
- const page = await feed.run({ cursor: context.model.cursor });
349
+ const get = {
350
+ feed: useResource(resource.feed),
351
+ };
352
+ const page = await get.feed({ cursor: context.model.cursor });
292
353
  ```
293
354
 
294
355
  A complete IntersectionObserver-driven infinite-scroll demo lives at [`src/example/transactions/`](./src/example/transactions/) &ndash; mock paginated API, scroll-triggered `LoadMore`, `pending()` guard, broadcast on success.
@@ -298,7 +359,7 @@ For typed failure routing, wrap the call in `try/catch` and use `instanceof` &nd
298
359
  ```ts
299
360
  actions.useAction(Actions.Mount, async (context) => {
300
361
  try {
301
- const data = await user.run();
362
+ const data = await get.user();
302
363
  context.actions.produce(({ model }) => void (model.user = data));
303
364
  } catch (error) {
304
365
  if (error instanceof RateLimitedError) {
@@ -314,6 +375,42 @@ actions.useAction(Actions.Mount, async (context) => {
314
375
 
315
376
  See the [Resource recipe](./recipes/use-resource.md) for the three-tier error handling model, parameterised resources, and limitations.
316
377
 
378
+ ### Persisting resources across reloads
379
+
380
+ `useResource`'s cache lives in a `WeakMap` that's reset on every page load. To keep the most recent successful payload around between sessions, pair it with `utils.store(...)` &ndash; a synchronous key/value wrapper around any backing store (`localStorage` on web, `MMKV` on React Native, etc.) that traffics in the same `Stored<T>` shape as the Resource cache.
381
+
382
+ ```ts
383
+ import { utils } from "march-hare";
384
+
385
+ export const store = utils.store({
386
+ get: (key) => localStorage.getItem(key),
387
+ set: (key, value) => localStorage.setItem(key, value),
388
+ remove: (key) => localStorage.removeItem(key),
389
+ });
390
+ ```
391
+
392
+ `get.cat.else(...)` is overloaded: pass a `Stored<T>` (from `store.get(key)`) and the bound handle seeds its own cache from it when empty &ndash; then chain `.else(null)` for the leaf fallback. `get.cat.snapshot()` produces the symmetric `Stored<T>` for writing back. After this single chain, `.if({ over })` short-circuits on the persisted timestamp on the _first_ mount after a reload, with no second method to call.
393
+
394
+ ```ts
395
+ const get = { cat: useResource(resource.cat) };
396
+ const actions = useActions<Model, typeof Actions>({
397
+ // First render reads cache → storage → null.
398
+ cat: get.cat.else(store.get(Snapshots.Cat)).else(null),
399
+ });
400
+
401
+ actions.useAction(Actions.Mount, async (context) => {
402
+ // Short-circuits when storage held a payload < 5 minutes old.
403
+ const fresh = await get.cat.if(
404
+ { over: { minutes: 5 } },
405
+ context.task.controller.signal,
406
+ );
407
+ store.set(Snapshots.Cat, get.cat.snapshot());
408
+ context.actions.produce(({ model }) => void (model.cat = fresh));
409
+ });
410
+ ```
411
+
412
+ See the [storage recipe](./recipes/storage.md) for backend adapters (React Native MMKV, browser extension `chrome.storage`), sign-out purge, and the `unset` sentinel that keeps "nothing stored" distinct from "a legitimately stored null".
413
+
317
414
  For targeted event delivery, use channeled actions. Define a channel type as the second generic argument and call the action with a channel object &ndash; handlers fire when the dispatch channel matches:
318
415
 
319
416
  ```tsx
@@ -387,7 +484,7 @@ See the [multicast recipe](./recipes/multicast-actions.md) for more details.
387
484
  For coordinating between async handlers without re-rendering the JSX tree, use the per-`<Boundary>` mode handle returned by `useMode()`. Thread it through the `useActions` data callback so it shows up as `context.data.mode` inside handlers, fully typed. Mode is **not** reactive &mdash; drive view state through the model, not mode.
388
485
 
389
486
  ```ts
390
- import * as marchHare from "march-hare";
487
+ import { useActions, useMode } from "march-hare";
391
488
 
392
489
  enum Mode {
393
490
  Idle,
@@ -395,14 +492,13 @@ enum Mode {
395
492
  }
396
493
 
397
494
  export function useActions() {
398
- const mode = marchHare.useMode<Mode>();
495
+ const mode = useMode<Mode>();
399
496
  // Spell the data shape as the third generic so `context.data.mode` keeps
400
497
  // its concrete type inside handlers.
401
- const actions = marchHare.useActions<
402
- Model,
403
- typeof Actions,
404
- { mode: typeof mode }
405
- >(model, () => ({ mode }));
498
+ const actions = useActions<Model, typeof Actions, { mode: typeof mode }>(
499
+ model,
500
+ () => ({ mode }),
501
+ );
406
502
 
407
503
  actions.useAction(Actions.SignOut, async (context) => {
408
504
  context.data.mode.update(Mode.SigningOut);
@@ -1,6 +1,6 @@
1
- import{G as e,A as t}from"@mobily/ts-belt";import{immerable as n,enablePatches as r,Immer as o}from"immer";import{jsx as s}from"react/jsx-runtime";import*as c from"react";const i=(e="")=>`march-hare.action/${e}`,a=(e="")=>`march-hare.action/broadcast/${e}`,u=(e="")=>`march-hare.action/multicast/${e}`,l=(e="")=>`march-hare.action.lifecycle/${e}`;class f{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")}function d(e){const t=/* @__PURE__ */Symbol(`march-hare.action.lifecycle/${e}`),n=function(e){return{[f.Action]:t,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(n,f.Action,{value:t,enumerable:!1}),Object.defineProperty(n,f.Payload,{value:void 0,enumerable:!1}),n}const p=Symbol(a("Fault"));class h{static Mount(){return d("Mount")}static Unmount(){return d("Unmount")}static Error(){return d("Error")}static Update(){return d("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,f.Action,{value:p,enumerable:!1}),Object.defineProperty(e,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,f.Broadcast,{value:!0,enumerable:!1}),e})()}var m=/* @__PURE__ */(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(m||{}),y=/* @__PURE__ */(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(y||{});const b=e=>"symbol"==typeof e;function v(t){return e.isString(t)||b(t)?t:(e.isObject(t)||e.isFunction(t))&&f.Action in t?t[f.Action]:t}function g(t){if(e.isString(t))return t.startsWith(a());if(b(t))return t.description?.startsWith(a())??!1;if(e.isObject(t)||e.isFunction(t)){if(f.Broadcast in t&&t[f.Broadcast])return!0;if(f.Action in t){const e=t[f.Action];return e.description?.startsWith(a())??!1}}return!1}function w(t){const n=v(t),r=e.isString(n)?n:n.description??"";return r.startsWith(i())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function O(t){return e.isObject(t)&&f.Channel in t&&"channel"in t}function j(e){const t=v(e),n=b(t)?t.description??"":t;return n.startsWith(l())&&n.slice(l().length)||null}function S(t){if(e.isString(t))return t.startsWith(u());if(b(t))return t.description?.startsWith(u())??!1;if(e.isObject(t)||e.isFunction(t)){if(f.Multicast in t&&t[f.Multicast])return!0;if(f.Action in t){const e=t[f.Action];return e.description?.startsWith(u())??!1}}return!1}const E=(e,t=m.Unicast)=>{const n=t===m.Broadcast?Symbol(a(e)):t===m.Multicast?Symbol(u(e)):Symbol(i(e)),r=function(e){return{[f.Action]:n,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(r,f.Action,{value:n,enumerable:!1}),Object.defineProperty(r,f.Payload,{value:void 0,enumerable:!1}),t===m.Broadcast&&Object.defineProperty(r,f.Broadcast,{value:!0,enumerable:!1}),t===m.Multicast&&Object.defineProperty(r,f.Multicast,{value:!0,enumerable:!1}),r};var P=/* @__PURE__ */(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Errored=2]="Errored",e))(P||{});class M extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}class C extends Error{name="TimeoutError";constructor(e="Timeout"){super(e)}}let x=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var k=/* @__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))(k||{}),A=/* @__PURE__ */(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(A||{}),_=/* @__PURE__ */(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(_||{});class R{[n]=!0;static keys=new Set(Object.values(_));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new R(this.value,this.operation);return n.property=e,n.process=t,n}}class N{static immer=(()=>{r();const e=new o;return e.setAutoFreeze(!1),e})();static tag="κ";static id=x}function U(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 L(t){if(e.isNullable(t)||F(t))return t;if(e.isArray(t))return t.map(e=>L(e));if(e.isObject(t)&&B(t)){const e=Object.entries(t).map(([e,t])=>[e,L(t)]);return{...Object.fromEntries(e),[N.tag]:t[N.tag]??N.id()}}return t}function T(e){if(Array.isArray(e))return e.filter(e=>N.tag in e).map(e=>e[N.tag]??"").join(",");const t=e[N.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function B(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function F(t){return e.isNullable(t)||e.isString(t)||e.isNumber(t)||e.isBoolean(t)||"symbol"==typeof t||"bigint"==typeof t}function W(t,n,r,o,s,c){return function i(a,u=n.path){if(a instanceof R){const n=U(r,u.join("."));if(Object.entries(a).filter(([e,t])=>!R.keys.has(e)&&t instanceof R).forEach(([e,t])=>i(t,u.concat(e))),F(a.value)){if(t===A.Hydrate)return a.value;const i=u.slice(0,-1),l=i.length>0?U(r,i.join(".")):r;return e.isNullable(l)||$(l,a,u.at(-1),o,s,c),n??a.value}if(t===A.Hydrate){const e=L(i(a.value,u));return $(e,a,null,o,s,c),e}const l=n??L(a.value);return $(l,a,null,o,s,c),e.isNullable(n)?l:(i(a.value,u),n)}if(e.isArray(a))return a.map((e,t)=>i(e,u.concat(t)));if(e.isObject(a)&&!B(a))return a;if(e.isObject(a)){const e=Object.entries(a).map(([e,t])=>[e,i(t,u.concat(e))]),n=Object.fromEntries(e);if(t===A.Hydrate){const e=L(n);return Object.entries(a).forEach(([t,n])=>{n instanceof R&&F(n.value)&&$(e,n,t,o,s,c)}),e}return n}return a}(n.value)}function $(e,t,n,r,o,s){const c=s(e),i=o.get(c)??[];o.set(c,[t.assign(n,r),...i])}class z{#e={};#t;#n=/* @__PURE__ */new Map;#r=/* @__PURE__ */new Set;#o=!1;constructor(e=T){this.#t=e}static pk(){return x()}static"κ"=z.pk;annotate(e,t){return new R(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(n,r,o,s,c){function i(s){const c=s.at(-1),i=U(n(),s),a=s.slice(0,-1),u=t.isNotEmpty(a)?U(n(),a):n();return[...e.isObject(i)||e.isArray(i)?r.get(o(i))?.filter(t=>e.isNullable(t.property))??[]:[],...e.isObject(u)?r.get(o(u))?.filter(e=>e.property===c)??[]:[]]}return function e(r){return new Proxy(()=>{},{get:(o,a)=>"pending"===a?()=>!t.isEmpty(i(r)):"remaining"===a?()=>t.length(i(r)):"box"===a?()=>({value:U(n(),r),inspect:e(r)}):"is"===a?e=>i(r).some(t=>0!==(t.operation&e)):"draft"===a?()=>t.head(i(r))?.value??U(n(),r):"settled"===a?()=>new Promise(e=>{if(t.isEmpty(i(r)))return e(U(n(),r));const o=()=>{t.isEmpty(i(r))&&(c(o),e(U(n(),r)))};s(o)}):e([...r,String(a)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(A.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(A.Produce,e)}#s(e,t){const n=/* @__PURE__ */Symbol("process"),[,r]=N.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>N.immer.applyPatches(t,[{...r,value:W(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=L(this.#e),this.#c(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const H=new z;function I(e,t=k.Update){return H.annotate(t,e)}function D(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var G,J={exports:{}};const V=/* @__PURE__ */D((G||(G=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 i=new o(r,s||e,c),a=n?n+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],i]:e._events[a].push(i):(e._events[a]=i,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function i(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=/* @__PURE__ */Object.create(null),(new r).__proto__||(n=!1)),i.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},i.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},i.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},i.prototype.emit=function(e,t,r,o,s,c){var i=n?n+e:e;if(!this._events[i])return!1;var a,u,l=this._events[i],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,a=new Array(f-1);u<f;u++)a[u-1]=arguments[u];l.fn.apply(l.context,a)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!a)for(d=1,a=new Array(f-1);d<f;d++)a[d-1]=arguments[d];l[u].fn.apply(l[u].context,a)}}return!0},i.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},i.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},i.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 i=this._events[s];if(i.fn)i.fn!==t||o&&!i.once||r&&i.context!==r||c(this,s);else{for(var a=0,u=[],l=i.length;a<l;a++)(i[a].fn!==t||o&&!i[a].once||r&&i[a].context!==r)&&u.push(i[a]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},i.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},i.prototype.off=i.prototype.removeListener,i.prototype.addListener=i.prototype.on,i.prefixed=n,i.EventEmitter=i,e.exports=i}(J)),J.exports));class q extends V{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 K=c.createContext(new q);function Q(){return c.useContext(K)}function X({children:e}){const t=c.useMemo(()=>new q,[]);/* @__PURE__ */
2
- return s(K.Provider,{value:t,children:e})}const Y=c.createContext(/* @__PURE__ */new Set);function Z({children:e}){const t=c.useMemo(()=>/* @__PURE__ */new Set,[]);/* @__PURE__ */
3
- return s(Y.Provider,{value:t,children:e})}const ee=c.createContext({current:null});function te(){const e=c.useContext(ee);return c.useMemo(()=>({read:()=>e.current,update(t){e.current=t}}),[e])}function ne({children:e}){const t=c.useRef(null);/* @__PURE__ */
1
+ import{G as e,A as t}from"@mobily/ts-belt";import{immerable as n,enablePatches as r,Immer as o}from"immer";import{jsx as s}from"react/jsx-runtime";import*as a from"react";const c=(e="")=>`march-hare.action/${e}`,i=(e="")=>`march-hare.action/broadcast/${e}`,u=(e="")=>`march-hare.action/multicast/${e}`,l=(e="")=>`march-hare.action.lifecycle/${e}`;class f{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")}function d(e){const t=/* @__PURE__ */Symbol(`march-hare.action.lifecycle/${e}`),n=function(e){return{[f.Action]:t,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(n,f.Action,{value:t,enumerable:!1}),Object.defineProperty(n,f.Payload,{value:void 0,enumerable:!1}),n}const p=Symbol(i("Fault"));class h{static Mount(){return d("Mount")}static Unmount(){return d("Unmount")}static Error(){return d("Error")}static Update(){return d("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,f.Action,{value:p,enumerable:!1}),Object.defineProperty(e,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,f.Broadcast,{value:!0,enumerable:!1}),e})()}var m=/* @__PURE__ */(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(m||{}),y=/* @__PURE__ */(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(y||{});const b=e=>"symbol"==typeof e;function v(t){return e.isString(t)||b(t)?t:(e.isObject(t)||e.isFunction(t))&&f.Action in t?t[f.Action]:t}function g(t){if(e.isString(t))return t.startsWith(i());if(b(t))return t.description?.startsWith(i())??!1;if(e.isObject(t)||e.isFunction(t)){if(f.Broadcast in t&&t[f.Broadcast])return!0;if(f.Action in t){const e=t[f.Action];return e.description?.startsWith(i())??!1}}return!1}function w(t){const n=v(t),r=e.isString(n)?n:n.description??"";return r.startsWith(c())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function O(t){return e.isObject(t)&&f.Channel in t&&"channel"in t}function S(e){const t=v(e),n=b(t)?t.description??"":t;return n.startsWith(l())&&n.slice(l().length)||null}function j(t){if(e.isString(t))return t.startsWith(u());if(b(t))return t.description?.startsWith(u())??!1;if(e.isObject(t)||e.isFunction(t)){if(f.Multicast in t&&t[f.Multicast])return!0;if(f.Action in t){const e=t[f.Action];return e.description?.startsWith(u())??!1}}return!1}const P=(e,t=m.Unicast)=>{const n=t===m.Broadcast?Symbol(i(e)):t===m.Multicast?Symbol(u(e)):Symbol(c(e)),r=function(e){return{[f.Action]:n,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(r,f.Action,{value:n,enumerable:!1}),Object.defineProperty(r,f.Payload,{value:void 0,enumerable:!1}),t===m.Broadcast&&Object.defineProperty(r,f.Broadcast,{value:!0,enumerable:!1}),t===m.Multicast&&Object.defineProperty(r,f.Multicast,{value:!0,enumerable:!1}),r};var E=/* @__PURE__ */(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Errored=2]="Errored",e))(E||{});class M extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}class C extends Error{name="TimeoutError";constructor(e="Timeout"){super(e)}}let x=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var k=/* @__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))(k||{}),A=/* @__PURE__ */(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(A||{}),_=/* @__PURE__ */(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(_||{});class N{[n]=!0;static keys=new Set(Object.values(_));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new N(this.value,this.operation);return n.property=e,n.process=t,n}}class R{static immer=(()=>{r();const e=new o;return e.setAutoFreeze(!1),e})();static tag="κ";static id=x}function U(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 L(t){if(e.isNullable(t)||F(t))return t;if(e.isArray(t))return t.map(e=>L(e));if(e.isObject(t)&&B(t)){const e=Object.entries(t).map(([e,t])=>[e,L(t)]);return{...Object.fromEntries(e),[R.tag]:t[R.tag]??R.id()}}return t}function T(e){if(Array.isArray(e))return e.filter(e=>R.tag in e).map(e=>e[R.tag]??"").join(",");const t=e[R.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function B(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function F(t){return e.isNullable(t)||e.isString(t)||e.isNumber(t)||e.isBoolean(t)||"symbol"==typeof t||"bigint"==typeof t}function W(t,n,r,o,s,a){return function c(i,u=n.path){if(i instanceof N){const n=U(r,u.join("."));if(Object.entries(i).filter(([e,t])=>!N.keys.has(e)&&t instanceof N).forEach(([e,t])=>c(t,u.concat(e))),F(i.value)){if(t===A.Hydrate)return i.value;const c=u.slice(0,-1),l=c.length>0?U(r,c.join(".")):r;return e.isNullable(l)||$(l,i,u.at(-1),o,s,a),n??i.value}if(t===A.Hydrate){const e=L(c(i.value,u));return $(e,i,null,o,s,a),e}const l=n??L(i.value);return $(l,i,null,o,s,a),e.isNullable(n)?l:(c(i.value,u),n)}if(e.isArray(i))return i.map((e,t)=>c(e,u.concat(t)));if(e.isObject(i)&&!B(i))return i;if(e.isObject(i)){const e=Object.entries(i).map(([e,t])=>[e,c(t,u.concat(e))]),n=Object.fromEntries(e);if(t===A.Hydrate){const e=L(n);return Object.entries(i).forEach(([t,n])=>{n instanceof N&&F(n.value)&&$(e,n,t,o,s,a)}),e}return n}return i}(n.value)}function $(e,t,n,r,o,s){const a=s(e),c=o.get(a)??[];o.set(a,[t.assign(n,r),...c])}class H{#e={};#t;#n=/* @__PURE__ */new Map;#r=/* @__PURE__ */new Set;#o=!1;constructor(e=T){this.#t=e}static pk(){return x()}static"κ"=H.pk;annotate(e,t){return new N(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(n,r,o,s,a){function c(s){const a=s.at(-1),c=U(n(),s),i=s.slice(0,-1),u=t.isNotEmpty(i)?U(n(),i):n();return[...e.isObject(c)||e.isArray(c)?r.get(o(c))?.filter(t=>e.isNullable(t.property))??[]:[],...e.isObject(u)?r.get(o(u))?.filter(e=>e.property===a)??[]:[]]}return function e(r){return new Proxy(()=>{},{get:(o,i)=>"pending"===i?()=>!t.isEmpty(c(r)):"remaining"===i?()=>t.length(c(r)):"box"===i?()=>({value:U(n(),r),inspect:e(r)}):"is"===i?e=>c(r).some(t=>0!==(t.operation&e)):"draft"===i?()=>t.head(c(r))?.value??U(n(),r):"settled"===i?()=>new Promise(e=>{if(t.isEmpty(c(r)))return e(U(n(),r));const o=()=>{t.isEmpty(c(r))&&(a(o),e(U(n(),r)))};s(o)}):e([...r,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(A.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(A.Produce,e)}#s(e,t){const n=/* @__PURE__ */Symbol("process"),[,r]=R.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>R.immer.applyPatches(t,[{...r,value:W(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=L(this.#e),this.#a(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#a()}#a(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const I=new H;function z(e,t=k.Update){return I.annotate(t,e)}function D(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var J,G={exports:{}};const V=/* @__PURE__ */D((J||(J=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,a){if("function"!=typeof r)throw new TypeError("The listener must be a function");var c=new o(r,s||e,a),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],c]:e._events[i].push(c):(e._events[i]=c,e._eventsCount++),e}function a(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function c(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=/* @__PURE__ */Object.create(null),(new r).__proto__||(n=!1)),c.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},c.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},c.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},c.prototype.emit=function(e,t,r,o,s,a){var c=n?n+e:e;if(!this._events[c])return!1;var i,u,l=this._events[c],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,a),!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},c.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},c.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},c.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return a(this,s),this;var c=this._events[s];if(c.fn)c.fn!==t||o&&!c.once||r&&c.context!==r||a(this,s);else{for(var i=0,u=[],l=c.length;i<l;i++)(c[i].fn!==t||o&&!c[i].once||r&&c[i].context!==r)&&u.push(c[i]);u.length?this._events[s]=1===u.length?u[0]:u:a(this,s)}return this},c.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&a(this,t):(this._events=new r,this._eventsCount=0),this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prefixed=n,c.EventEmitter=c,e.exports=c}(G)),G.exports));class q extends V{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 K=a.createContext(new q);function Q(){return a.useContext(K)}function X({children:e}){const t=a.useMemo(()=>new q,[]);/* @__PURE__ */
2
+ return s(K.Provider,{value:t,children:e})}const Y=a.createContext(/* @__PURE__ */new Set);function Z({children:e}){const t=a.useMemo(()=>/* @__PURE__ */new Set,[]);/* @__PURE__ */
3
+ return s(Y.Provider,{value:t,children:e})}const ee=a.createContext({current:null});function te(){const e=a.useContext(ee);return a.useMemo(()=>({read:()=>e.current,update(t){e.current=t}}),[e])}function ne({children:e}){const t=a.useRef(null);/* @__PURE__ */
4
4
  return s(ee.Provider,{value:t,children:e})}function re({children:e}){/* @__PURE__ */
5
- return s(X,{children:/* @__PURE__ */s(ne,{children:/* @__PURE__ */s(Z,{children:e})})})}const oe=c.createContext(null);function se(){return c.useContext(oe)}function ce(e,t){return e?.get(t)??null}function ie(e,t){const n=`Scoped${t.displayName||t.name||"Component"}`,r=v(e);return{[n](e){const n=se(),o=c.useMemo(()=>({action:r,emitter:new q}),[]),i=c.useMemo(()=>{const e=new Map(n??[]);return e.set(r,o),e},[n,o]);/* @__PURE__ */
6
- return s(oe.Provider,{value:i,children:/* @__PURE__ */s(t,{...e})})}}[n]}const ae=Symbol(((e="")=>`march-hare/replay${e}`)());function ue(e,t,...n){e instanceof q&&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(()=>{})}const le={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]})}};function fe(e,t){for(const n of e.keys())if(j(n)===t)return n;return null}function de(){const[,e]=c.useReducer(e=>e+1,0);return e}function pe(e){if(e instanceof Error){if("TimeoutError"===e.name)return P.Timedout;if("AbortError"===e.name)return P.Supplanted}return P.Errored}const he=c.createContext(/* @__PURE__ */new Map);function me({action:t,renderer:n}){const r=Q(),o=c.useContext(he),s=de(),i=c.useMemo(()=>{const e=o.get(t);if(e)return e;const n={state:new z,listeners:/* @__PURE__ */new Set};return o.set(t,n),n},[t,o]);c.useLayoutEffect(()=>{function e(e){i.state.hydrate({value:e}),i.listeners.forEach(e=>e())}return i.listeners.add(s),r.on(t,e),()=>{i.listeners.delete(s),r.off(t,e)}},[t,r,i]);const a=i.state.model?.value;return e.isNullable(a)?null:n(a,i.state.inspect.value)}function ye(...n){const r=e.isUndefined(n[0])||e.isFunction(n[0])?{}:n[0],o=e.isFunction(n[0])?n[0]:n[1]??(()=>({})),s=Q(),i=se(),a=c.useContext(Y),u=de(),l=c.useRef(!1),f=c.useRef(null),d=c.useRef(new z);l.current||(l.current=!0,f.current=d.current.hydrate(r));const[h,m]=c.useState(()=>d.current.model),b=function(e){const t=c.useRef(e);return c.useLayoutEffect(()=>{t.current=e},[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])}(o()),j=c.useMemo(()=>new V,[]),E=c.useRef({handlers:/* @__PURE__ */new Map});E.current.handlers=/* @__PURE__ */new Map;const P=function(){const e=c.useRef(/* @__PURE__ */new Set),t=c.useRef(/* @__PURE__ */new Set);return c.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),M=c.useRef(y.Mounting),C=c.useRef(/* @__PURE__ */new Set),x=c.useRef(0),A=c.useCallback((e,t,n)=>{const r=new AbortController,o={controller:r,action:e,payload:t};return a.add(o),C.current.add(o),{model:d.current.model,get phase(){return M.current},task:o,data:b,tasks:a,actions:{produce(e){if(r.signal.aborted)return;const t=d.current.produce(t=>{e({model:t,inspect:d.current.inspect})});m(d.current.model),n.processes.add(t),f.current&&(n.processes.add(f.current),f.current=null)},dispatch(e,t){if(r.signal.aborted)return Promise.resolve();const n=v(e),o=O(e)?e.channel:void 0;if(S(e)){const e=ce(i,n);return e?ue(e.emitter,n,t,o):Promise.resolve()}return ue(g(e)?s:j,n,t,o)},annotate:(e,t=k.Update)=>d.current.annotate(t,e),async resolution(e){if(r.signal.aborted)return null;const t=v(e),n=S(e)?ce(i,t)?.emitter??null:s;if(!n)return null;if(void 0===n.getCached(t))return null;const o=w(e),c="unknown"!==o?o[0].toLowerCase()+o.slice(1):null;if(c){const e=d.current.inspect[c];e?.pending?.()&&await new Promise((t,n)=>{if(r.signal.aborted)return void n(r.signal.reason);const o=()=>n(r.signal.reason);r.signal.addEventListener("abort",o,{once:!0}),e.settled().then(()=>{r.signal.removeEventListener("abort",o),t()})})}return n.getCached(t)??null},peek(e){if(r.signal.aborted)return null;const t=v(e),n=S(e)?ce(i,t)?.emitter??null:s;return n?n.getCached(t)??null:null}}}},[h]);c.useLayoutEffect(()=>{function t(t,n,r){return function(o,c){const i=r();if(c===ae&&e.isNotNullable(i))return;if(e.isNotNullable(c)&&c!==ae&&e.isNotNullable(i)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,i))return;const l={processes:/* @__PURE__ */new Set},f=Promise.withResolvers(),h=A(t,o,l);function m(e){const n=fe(E.current.handlers,"Error"),r=null!==n,o={reason:pe(e),error:(c=e,c instanceof Error?c:new Error(String(c))),action:w(t),handled:r,tasks:a};var c;s.fire(p,o),r&&n&&j.emit(n,o)}function y(){for(const e of a)if(e===h.task){a.delete(e),C.current.delete(e);break}l.processes.forEach(e=>d.current.prune(e)),l.processes.size>0&&u(),f.resolve()}let b;try{b=n(h,o)}catch(v){return m(v),void y()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(b))return Promise.resolve(b).catch(m).finally(y),f.promise;(async()=>{for await(const e of b);})().catch(m).finally(y)}}x.current++;const n=/* @__PURE__ */new Set;return E.current.handlers.forEach((e,r)=>{for(const{getChannel:o,handler:c}of e){const e=t(r,c,o);if(S(r)){if(i)for(const t of i.values()){const o=t.emitter;o.on(r,e),n.add(()=>o.off(r,e))}j.on(r,e),P.multicast.add(r),n.add(()=>j.off(r,e))}else g(r)?(s.on(r,e),j.on(r,e),P.broadcast.add(r),n.add(()=>{s.off(r,e),j.off(r,e)})):(j.on(r,e),n.add(()=>j.off(r,e)))}}),()=>{const e=++x.current,t=new Set(n);queueMicrotask(()=>{if(x.current!==e){for(const e of t)e();return}for(const e of C.current)e.controller.abort(),a.delete(e);C.current.clear(),M.current=y.Unmounting;const n=fe(E.current.handlers,"Unmount");n&&j.emit(n),M.current=y.Unmounted;for(const e of t)e()})}},[j]),function({unicast:n,broadcast:r,dispatchers:o,scope:s,phase:i,data:a,handlers:u}){const l=c.useRef(null);c.useLayoutEffect(()=>{if(i.current===y.Mounted)return;i.current=y.Mounting;const t=fe(u,"Mount");t&&n.emit(t),o.broadcast.forEach(t=>{const o=r.getCached(t);e.isNullable(o)||n.emit(t,o,ae)}),s&&o.multicast.forEach(t=>{for(const r of s.values()){const o=r.emitter.getCached(t);e.isNullable(o)||n.emit(t,o,ae)}}),i.current=y.Mounted},[]),c.useLayoutEffect(()=>{if(e.isNotNullable(l.current)){const e=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(l.current,a);if(t.isNotEmpty(Object.keys(e))){const t=fe(u,"Update");t&&n.emit(t,e)}}l.current=a},[a,n])}({unicast:j,broadcast:s,dispatchers:P,scope:i,phase:M,data:o(),handlers:E.current.handlers});const _=c.useMemo(()=>[h,{dispatch(e,t){const n=v(e),r=O(e)?e.channel:void 0;if(S(e)){const e=ce(i,n);return e?ue(e.emitter,n,t,r):Promise.resolve()}return ue(g(e)?s:j,n,t,r)},get inspect(){return d.current.inspect},stream:(e,t)=>c.createElement(me,{action:v(e),renderer:t})}],[h,j]);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),[]),i=c.useCallback(()=>O(o.current)?o.current.channel:void 0,[]),a=v(t),u=e.current.handlers.get(a)??/* @__PURE__ */new Set;0===u.size&&e.current.handlers.set(a,u),u.add({getChannel:i,handler:s})}(E,e,t)},_.useResource=e=>{const t=c.useMemo(()=>{const t=t=>e.run(t??{});return Object.assign(t,{if:(n,r)=>{const{data:o,at:s}=e;if(null!==s&&null!==o){const e=Temporal.Now.instant().since(s),t=Temporal.Duration.from(n.over);if(Temporal.Duration.compare(e,t)<=0)return Promise.resolve(o)}return t(r)}})},[e]);return c.useMemo(()=>Object.freeze({run:t,get data(){return e.data},get at(){return e.at}}),[e,t])},_}function be(e,t){const n=/* @__PURE__ */new Map;let r=null,o=null;return Object.freeze({key:e,run:e=>{const s=JSON.stringify(e),c=n.get(s);if(c)return c;const i=t(e).then(e=>(n.get(s)===i&&n.delete(s),r=e,o=Temporal.Now.instant(),e),e=>{throw n.get(s)===i&&n.delete(s),e});return n.set(s,i),i},get data(){return r},get at(){return o}})}function ve(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new M);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new M)},{once:!0})})}async function ge(e,t,n){if(t?.aborted)throw new M;for(;;){if(await n())return;await ve(e,t)}}function we(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:we,poll:ge,sleep:ve,"ζ":ve,"κ":we,"π":ge},Symbol.toStringTag,{value:"Module"}));export{M as AbortError,E as Action,re as Boundary,m as Distribution,h as Lifecycle,k as Op,k as Operation,P as Reason,be as Resource,z as State,C as TimeoutError,le as With,I as annotate,ye as useActions,te as useMode,Oe as utils,ie as withScope};
5
+ return s(X,{children:/* @__PURE__ */s(ne,{children:/* @__PURE__ */s(Z,{children:e})})})}const oe=a.createContext(null);function se(){return a.useContext(oe)}function ae(e,t){return e?.get(t)??null}function ce(e,t){const n=`Scoped${t.displayName||t.name||"Component"}`,r=v(e);return{[n](e){const n=se(),o=a.useMemo(()=>({action:r,emitter:new q}),[]),c=a.useMemo(()=>{const e=new Map(n??[]);return e.set(r,o),e},[n,o]);/* @__PURE__ */
6
+ return s(oe.Provider,{value:c,children:/* @__PURE__ */s(t,{...e})})}}[n]}const ie=Symbol(((e="")=>`march-hare/replay${e}`)());function ue(e,t,...n){e instanceof q&&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(()=>{})}const le={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]})}};function fe(e,t){for(const n of e.keys())if(S(n)===t)return n;return null}const de=/* @__PURE__ */Symbol("march-hare.unset");function pe(){const[,e]=a.useReducer(e=>e+1,0);return e}function he(){return{data:de,at:null,else:e=>e}}function me(e,t){return{data:e,at:t,else:t=>e}}function ye(e){if(e instanceof Error){if("TimeoutError"===e.name)return E.Timedout;if("AbortError"===e.name)return E.Supplanted}return E.Errored}const be=a.createContext(/* @__PURE__ */new Map);function ve({action:t,renderer:n}){const r=Q(),o=a.useContext(be),s=pe(),c=a.useMemo(()=>{const e=o.get(t);if(e)return e;const n={state:new H,listeners:/* @__PURE__ */new Set};return o.set(t,n),n},[t,o]);a.useLayoutEffect(()=>{function e(e){c.state.hydrate({value:e}),c.listeners.forEach(e=>e())}return c.listeners.add(s),r.on(t,e),()=>{c.listeners.delete(s),r.off(t,e)}},[t,r,c]);const i=c.state.model?.value;return e.isNullable(i)?null:n(i,c.state.inspect.value)}function ge(...n){const r=e.isUndefined(n[0])||e.isFunction(n[0])?{}:n[0],o=e.isFunction(n[0])?n[0]:n[1]??(()=>({})),s=Q(),c=se(),i=a.useContext(Y),u=pe(),l=a.useRef(!1),f=a.useRef(null),d=a.useRef(new H);l.current||(l.current=!0,f.current=d.current.hydrate(r));const[h,m]=a.useState(()=>d.current.model),b=function(e){const t=a.useRef(e);return a.useLayoutEffect(()=>{t.current=e},[e]),a.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(o()),S=a.useMemo(()=>new V,[]),P=a.useRef({handlers:/* @__PURE__ */new Map});P.current.handlers=/* @__PURE__ */new Map;const E=function(){const e=a.useRef(/* @__PURE__ */new Set),t=a.useRef(/* @__PURE__ */new Set);return a.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),M=a.useRef(y.Mounting),C=a.useRef(/* @__PURE__ */new Set),x=a.useRef(0),A=a.useCallback((e,t,n)=>{const r=new AbortController,o={controller:r,action:e,payload:t};return i.add(o),C.current.add(o),{model:d.current.model,get phase(){return M.current},task:o,data:b,tasks:i,actions:{produce(e){if(r.signal.aborted)return;const t=d.current.produce(t=>{e({model:t,inspect:d.current.inspect})});m(d.current.model),n.processes.add(t),f.current&&(n.processes.add(f.current),f.current=null)},dispatch(e,t){if(r.signal.aborted)return Promise.resolve();const n=v(e),o=O(e)?e.channel:void 0;if(j(e)){const e=ae(c,n);return e?ue(e.emitter,n,t,o):Promise.resolve()}return ue(g(e)?s:S,n,t,o)},annotate:(e,t=k.Update)=>d.current.annotate(t,e),async resolution(e){if(r.signal.aborted)return null;const t=v(e),n=j(e)?ae(c,t)?.emitter??null:s;if(!n)return null;if(void 0===n.getCached(t))return null;const o=w(e),a="unknown"!==o?o[0].toLowerCase()+o.slice(1):null;if(a){const e=d.current.inspect[a];e?.pending?.()&&await new Promise((t,n)=>{if(r.signal.aborted)return void n(r.signal.reason);const o=()=>n(r.signal.reason);r.signal.addEventListener("abort",o,{once:!0}),e.settled().then(()=>{r.signal.removeEventListener("abort",o),t()})})}return n.getCached(t)??null},peek(e){if(r.signal.aborted)return null;const t=v(e),n=j(e)?ae(c,t)?.emitter??null:s;return n?n.getCached(t)??null:null}}}},[h]);a.useLayoutEffect(()=>{function t(t,n,r){return function(o,a){const c=r();if(a===ie&&e.isNotNullable(c))return;if(e.isNotNullable(a)&&a!==ie&&e.isNotNullable(c)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(a,c))return;const l={processes:/* @__PURE__ */new Set},f=Promise.withResolvers(),h=A(t,o,l);function m(e){const n=fe(P.current.handlers,"Error"),r=null!==n,o={reason:ye(e),error:(a=e,a instanceof Error?a:new Error(String(a))),action:w(t),handled:r,tasks:i};var a;s.fire(p,o),r&&n&&S.emit(n,o)}function y(){for(const e of i)if(e===h.task){i.delete(e),C.current.delete(e);break}l.processes.forEach(e=>d.current.prune(e)),l.processes.size>0&&u(),f.resolve()}let b;try{b=n(h,o)}catch(v){return m(v),void y()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(b))return Promise.resolve(b).catch(m).finally(y),f.promise;(async()=>{for await(const e of b);})().catch(m).finally(y)}}x.current++;const n=/* @__PURE__ */new Set;return P.current.handlers.forEach((e,r)=>{for(const{getChannel:o,handler:a}of e){const e=t(r,a,o);if(j(r)){if(c)for(const t of c.values()){const o=t.emitter;o.on(r,e),n.add(()=>o.off(r,e))}S.on(r,e),E.multicast.add(r),n.add(()=>S.off(r,e))}else g(r)?(s.on(r,e),S.on(r,e),E.broadcast.add(r),n.add(()=>{s.off(r,e),S.off(r,e)})):(S.on(r,e),n.add(()=>S.off(r,e)))}}),()=>{const e=++x.current,t=new Set(n);queueMicrotask(()=>{if(x.current!==e){for(const e of t)e();return}for(const e of C.current)e.controller.abort(),i.delete(e);C.current.clear(),M.current=y.Unmounting;const n=fe(P.current.handlers,"Unmount");n&&S.emit(n),M.current=y.Unmounted;for(const e of t)e()})}},[S]),function({unicast:n,broadcast:r,dispatchers:o,scope:s,phase:c,data:i,handlers:u}){const l=a.useRef(null);a.useLayoutEffect(()=>{if(c.current===y.Mounted)return;c.current=y.Mounting;const t=fe(u,"Mount");t&&n.emit(t),o.broadcast.forEach(t=>{const o=r.getCached(t);e.isNullable(o)||n.emit(t,o,ie)}),s&&o.multicast.forEach(t=>{for(const r of s.values()){const o=r.emitter.getCached(t);e.isNullable(o)||n.emit(t,o,ie)}}),c.current=y.Mounted},[]),a.useLayoutEffect(()=>{if(e.isNotNullable(l.current)){const e=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(l.current,i);if(t.isNotEmpty(Object.keys(e))){const t=fe(u,"Update");t&&n.emit(t,e)}}l.current=i},[i,n])}({unicast:S,broadcast:s,dispatchers:E,scope:c,phase:M,data:o(),handlers:P.current.handlers});const _=a.useMemo(()=>[h,{dispatch(e,t){const n=v(e),r=O(e)?e.channel:void 0;if(j(e)){const e=ae(c,n);return e?ue(e.emitter,n,t,r):Promise.resolve()}return ue(g(e)?s:S,n,t,r)},get inspect(){return d.current.inspect},stream:(e,t)=>a.createElement(ve,{action:v(e),renderer:t})}],[h,S]);return _.useAction=(e,t)=>{!function(e,t,n){const r=a.useRef(n);a.useLayoutEffect(()=>{r.current=n});const o=a.useRef(t);a.useLayoutEffect(()=>{o.current=t});const s=a.useCallback((e,t)=>r.current(e,t),[]),c=a.useCallback(()=>O(o.current)?o.current.channel:void 0,[]),i=v(t),u=e.current.handlers.get(i)??/* @__PURE__ */new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:c,handler:s})}(P,e,t)},_}function we(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new M);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new M)},{once:!0})})}async function Oe(e,t,n){if(t?.aborted)throw new M;for(;;){if(await n())return;await we(e,t)}}function Se(e){return e?Boolean(e&&"symbol"!=typeof e):/* @__PURE__ */Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}function je(e){return{get(t){try{const n=e.get(t);if(null===n)return he();const r=JSON.parse(n);return me(r.data,Temporal.Instant.from(r.at))}catch{return he()}},set(t,n){if(n.data===de||null===n.at)return!1;try{return e.set(t,JSON.stringify({data:n.data,at:n.at.toString()})),!0}catch{return!1}},remove(t){e.remove(t)},clear(){e.clear()}}}const Pe=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,pk:Se,poll:Oe,sleep:we,store:je,unset:de,"ζ":we,"κ":Se,"π":Oe,"σ":je},Symbol.toStringTag,{value:"Module"})),Ee=/* @__PURE__ */new WeakMap;function Me(e){return{run:(t,n)=>e(t,n).then(t=>(Ee.set(e,{data:t,at:Temporal.Now.instant()}),t)),get data(){const t=Ee.get(e);return void 0===t?de:t.data},get at(){return Ee.get(e)?.at??null},seed(t,n){Ee.set(e,{data:t,at:n})}}}function Ce(e){return a.useMemo(()=>{const t=(t,n)=>e.run(t??void 0,n??{});return Object.defineProperties(t,{if:{value:(t,n,r)=>{const o=e.data,s=e.at;if(o!==de&&null!==s){const e=Temporal.Now.instant().since(s),n=Temporal.Duration.from(t.over);if(Temporal.Duration.compare(e,n)<=0)return Promise.resolve(o)}return e.run(n??void 0,r??{})},enumerable:!0},else:{value:function(n){if(null!==(r=n)&&"object"==typeof r&&"data"in r&&"at"in r&&"else"in r)return e.data===de&&n.data!==de&&null!==n.at&&e.seed(n.data,n.at),t;var r;const o=e.data;return o===de?n:o},enumerable:!0},snapshot:{value:()=>{const t=e.data,n=e.at;return t===de||null===n?he():me(t,n)},enumerable:!0},data:{get:()=>e.data,enumerable:!0},at:{get:()=>e.at,enumerable:!0}}),t},[e])}export{M as AbortError,P as Action,re as Boundary,m as Distribution,h as Lifecycle,k as Op,k as Operation,E as Reason,Me as Resource,H as State,C as TimeoutError,le as With,z as annotate,ge as useActions,te as useMode,Ce as useResource,Pe as utils,ce as withScope};
@@ -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(o),i=(e="")=>`march-hare.action/${e}`,a=(e="")=>`march-hare.action/broadcast/${e}`,u=(e="")=>`march-hare.action/multicast/${e}`,l=(e="")=>`march-hare.action.lifecycle/${e}`;class f{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")}function d(e){const t=Symbol(`march-hare.action.lifecycle/${e}`),n=function(e){return{[f.Action]:t,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(n,f.Action,{value:t,enumerable:!1}),Object.defineProperty(n,f.Payload,{value:void 0,enumerable:!1}),n}const p=Symbol(a("Fault"));class h{static Mount(){return d("Mount")}static Unmount(){return d("Unmount")}static Error(){return d("Error")}static Update(){return d("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,f.Action,{value:p,enumerable:!1}),Object.defineProperty(e,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,f.Broadcast,{value:!0,enumerable:!1}),e})()}var m=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(m||{}),b=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(b||{});const y=e=>"symbol"==typeof e;function v(e){return t.G.isString(e)||y(e)?e:(t.G.isObject(e)||t.G.isFunction(e))&&f.Action in e?e[f.Action]:e}function g(e){if(t.G.isString(e))return e.startsWith(a());if(y(e))return e.description?.startsWith(a())??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(f.Broadcast in e&&e[f.Broadcast])return!0;if(f.Action in e){const t=e[f.Action];return t.description?.startsWith(a())??!1}}return!1}function w(e){const n=v(e),r=t.G.isString(n)?n:n.description??"";return r.startsWith(i())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function j(e){return t.G.isObject(e)&&f.Channel in e&&"channel"in e}function O(e){const t=v(e),n=y(t)?t.description??"":t;return n.startsWith(l())&&n.slice(l().length)||null}function S(e){if(t.G.isString(e))return e.startsWith(u());if(y(e))return e.description?.startsWith(u())??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(f.Multicast in e&&e[f.Multicast])return!0;if(f.Action in e){const t=e[f.Action];return t.description?.startsWith(u())??!1}}return!1}var P=(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Errored=2]="Errored",e))(P||{});class x extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}class E extends Error{name="TimeoutError";constructor(e="Timeout"){super(e)}}let M=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var A=(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))(A||{}),C=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(C||{}),G=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(G||{});class k{[n.immerable]=!0;static keys=new Set(Object.values(G));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new k(this.value,this.operation);return n.property=e,n.process=t,n}}class _{static immer=(()=>{n.enablePatches();const e=new n.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=M}function R(e,t){const n="string"==typeof t?""===t?[]:t.split("."):t;let r=e;for(const o of n){if(null==r)return;r=r[o]}return r}function N(e){if(t.G.isNullable(e)||L(e))return e;if(t.G.isArray(e))return e.map(e=>N(e));if(t.G.isObject(e)&&T(e)){const t=Object.entries(e).map(([e,t])=>[e,N(t)]);return{...Object.fromEntries(t),[_.tag]:e[_.tag]??_.id()}}return e}function U(e){if(Array.isArray(e))return e.filter(e=>_.tag in e).map(e=>e[_.tag]??"").join(",");const t=e[_.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function T(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function L(e){return t.G.isNullable(e)||t.G.isString(e)||t.G.isNumber(e)||t.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function B(e,n,r,o,s,c){return function i(a,u=n.path){if(a instanceof k){const n=R(r,u.join("."));if(Object.entries(a).filter(([e,t])=>!k.keys.has(e)&&t instanceof k).forEach(([e,t])=>i(t,u.concat(e))),L(a.value)){if(e===C.Hydrate)return a.value;const i=u.slice(0,-1),l=i.length>0?R(r,i.join(".")):r;return t.G.isNullable(l)||F(l,a,u.at(-1),o,s,c),n??a.value}if(e===C.Hydrate){const e=N(i(a.value,u));return F(e,a,null,o,s,c),e}const l=n??N(a.value);return F(l,a,null,o,s,c),t.G.isNullable(n)?l:(i(a.value,u),n)}if(t.G.isArray(a))return a.map((e,t)=>i(e,u.concat(t)));if(t.G.isObject(a)&&!T(a))return a;if(t.G.isObject(a)){const t=Object.entries(a).map(([e,t])=>[e,i(t,u.concat(e))]),n=Object.fromEntries(t);if(e===C.Hydrate){const e=N(n);return Object.entries(a).forEach(([t,n])=>{n instanceof k&&L(n.value)&&F(e,n,t,o,s,c)}),e}return n}return a}(n.value)}function F(e,t,n,r,o,s){const c=s(e),i=o.get(c)??[];o.set(c,[t.assign(n,r),...i])}class W{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=U){this.#t=e}static pk(){return M()}static"κ"=W.pk;annotate(e,t){return new k(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,n,r,o,s){function c(o){const s=o.at(-1),c=R(e(),o),i=o.slice(0,-1),a=t.A.isNotEmpty(i)?R(e(),i):e();return[...t.G.isObject(c)||t.G.isArray(c)?n.get(r(c))?.filter(e=>t.G.isNullable(e.property))??[]:[],...t.G.isObject(a)?n.get(r(a))?.filter(e=>e.property===s)??[]:[]]}return function n(r){return new Proxy(()=>{},{get:(i,a)=>"pending"===a?()=>!t.A.isEmpty(c(r)):"remaining"===a?()=>t.A.length(c(r)):"box"===a?()=>({value:R(e(),r),inspect:n(r)}):"is"===a?e=>c(r).some(t=>0!==(t.operation&e)):"draft"===a?()=>t.A.head(c(r))?.value??R(e(),r):"settled"===a?()=>new Promise(n=>{if(t.A.isEmpty(c(r)))return n(R(e(),r));const i=()=>{t.A.isEmpty(c(r))&&(s(i),n(R(e(),r)))};o(i)}):n([...r,String(a)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(C.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(C.Produce,e)}#s(e,t){const n=Symbol("process"),[,r]=_.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>_.immer.applyPatches(t,[{...r,value:B(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=N(this.#e),this.#c(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.A.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const $=new W;function z(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H,I={exports:{}},D=(H||(H=1,function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function s(e,t,r,s,c){if("function"!=typeof r)throw new TypeError("The listener must be a function");var i=new o(r,s||e,c),a=n?n+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],i]:e._events[a].push(i):(e._events[a]=i,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function i(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),i.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},i.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},i.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},i.prototype.emit=function(e,t,r,o,s,c){var i=n?n+e:e;if(!this._events[i])return!1;var a,u,l=this._events[i],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,a=new Array(f-1);u<f;u++)a[u-1]=arguments[u];l.fn.apply(l.context,a)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!a)for(d=1,a=new Array(f-1);d<f;d++)a[d-1]=arguments[d];l[u].fn.apply(l[u].context,a)}}return!0},i.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},i.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},i.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 i=this._events[s];if(i.fn)i.fn!==t||o&&!i.once||r&&i.context!==r||c(this,s);else{for(var a=0,u=[],l=i.length;a<l;a++)(i[a].fn!==t||o&&!i[a].once||r&&i[a].context!==r)&&u.push(i[a]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},i.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},i.prototype.off=i.prototype.removeListener,i.prototype.addListener=i.prototype.on,i.prefixed=n,i.EventEmitter=i,e.exports=i}(I)),I.exports);const q=z(D);class J extends q{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 V=c.createContext(new J);function K(){return c.useContext(V)}function Q({children:e}){const t=c.useMemo(()=>new J,[]);return r.jsx(V.Provider,{value:t,children:e})}const X=c.createContext(new Set);function Y({children:e}){const t=c.useMemo(()=>new Set,[]);return r.jsx(X.Provider,{value:t,children:e})}const Z=c.createContext({current:null});function ee({children:e}){const t=c.useRef(null);return r.jsx(Z.Provider,{value:t,children:e})}const te=c.createContext(null);function ne(){return c.useContext(te)}function re(e,t){return e?.get(t)??null}const oe=Symbol(((e="")=>`march-hare/replay${e}`)());function se(e,t,...n){e instanceof J&&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 ce(e,t){for(const n of e.keys())if(O(n)===t)return n;return null}function ie(){const[,e]=c.useReducer(e=>e+1,0);return e}function ae(e){if(e instanceof Error){if("TimeoutError"===e.name)return P.Timedout;if("AbortError"===e.name)return P.Supplanted}return P.Errored}const ue=c.createContext(new Map);function le({action:e,renderer:n}){const r=K(),o=c.useContext(ue),s=ie(),i=c.useMemo(()=>{const t=o.get(e);if(t)return t;const n={state:new W,listeners:new Set};return o.set(e,n),n},[e,o]);c.useLayoutEffect(()=>{function t(e){i.state.hydrate({value:e}),i.listeners.forEach(e=>e())}return i.listeners.add(s),r.on(e,t),()=>{i.listeners.delete(s),r.off(e,t)}},[e,r,i]);const a=i.state.model?.value;return t.G.isNullable(a)?null:n(a,i.state.inspect.value)}function fe(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 de(e,t,n){if(t?.aborted)throw new x;for(;;){if(await n())return;await fe(e,t)}}function pe(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const he=Object.freeze(Object.defineProperty({__proto__:null,pk:pe,poll:de,sleep:fe,"ζ":fe,"κ":pe,"π":de},Symbol.toStringTag,{value:"Module"}));e.AbortError=x,e.Action=(e,t=m.Unicast)=>{const n=t===m.Broadcast?Symbol(a(e)):t===m.Multicast?Symbol(u(e)):Symbol(i(e)),r=function(e){return{[f.Action]:n,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(r,f.Action,{value:n,enumerable:!1}),Object.defineProperty(r,f.Payload,{value:void 0,enumerable:!1}),t===m.Broadcast&&Object.defineProperty(r,f.Broadcast,{value:!0,enumerable:!1}),t===m.Multicast&&Object.defineProperty(r,f.Multicast,{value:!0,enumerable:!1}),r},e.Boundary=function({children:e}){return r.jsx(Q,{children:r.jsx(ee,{children:r.jsx(Y,{children:e})})})},e.Distribution=m,e.Lifecycle=h,e.Op=A,e.Operation=A,e.Reason=P,e.Resource=function(e,t){const n=new Map;let r=null,o=null;return Object.freeze({key:e,run:e=>{const s=JSON.stringify(e),c=n.get(s);if(c)return c;const i=t(e).then(e=>(n.get(s)===i&&n.delete(s),r=e,o=Temporal.Now.instant(),e),e=>{throw n.get(s)===i&&n.delete(s),e});return n.set(s,i),i},get data(){return r},get at(){return o}})},e.State=W,e.TimeoutError=E,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=A.Update){return $.annotate(t,e)},e.useActions=function(...e){const n=t.G.isUndefined(e[0])||t.G.isFunction(e[0])?{}:e[0],r=t.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),o=K(),s=ne(),i=c.useContext(X),a=ie(),u=c.useRef(!1),l=c.useRef(null),f=c.useRef(new W);u.current||(u.current=!0,l.current=f.current.hydrate(n));const[d,h]=c.useState(()=>f.current.model),m=function(e){const t=c.useRef(e);return c.useLayoutEffect(()=>{t.current=e},[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])}(r()),y=c.useMemo(()=>new q,[]),O=c.useRef({handlers:new Map});O.current.handlers=new Map;const P=function(){const e=c.useRef(new Set),t=c.useRef(new Set);return c.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),x=c.useRef(b.Mounting),E=c.useRef(new Set),M=c.useRef(0),C=c.useCallback((e,t,n)=>{const r=new AbortController,c={controller:r,action:e,payload:t};return i.add(c),E.current.add(c),{model:f.current.model,get phase(){return x.current},task:c,data:m,tasks:i,actions:{produce(e){if(r.signal.aborted)return;const t=f.current.produce(t=>{e({model:t,inspect:f.current.inspect})});h(f.current.model),n.processes.add(t),l.current&&(n.processes.add(l.current),l.current=null)},dispatch(e,t){if(r.signal.aborted)return Promise.resolve();const n=v(e),c=j(e)?e.channel:void 0;if(S(e)){const e=re(s,n);return e?se(e.emitter,n,t,c):Promise.resolve()}return se(g(e)?o:y,n,t,c)},annotate:(e,t=A.Update)=>f.current.annotate(t,e),async resolution(e){if(r.signal.aborted)return null;const t=v(e),n=S(e)?re(s,t)?.emitter??null:o;if(!n)return null;if(void 0===n.getCached(t))return null;const c=w(e),i="unknown"!==c?c[0].toLowerCase()+c.slice(1):null;if(i){const e=f.current.inspect[i];e?.pending?.()&&await new Promise((t,n)=>{if(r.signal.aborted)return void n(r.signal.reason);const o=()=>n(r.signal.reason);r.signal.addEventListener("abort",o,{once:!0}),e.settled().then(()=>{r.signal.removeEventListener("abort",o),t()})})}return n.getCached(t)??null},peek(e){if(r.signal.aborted)return null;const t=v(e),n=S(e)?re(s,t)?.emitter??null:o;return n?n.getCached(t)??null:null}}}},[d]);c.useLayoutEffect(()=>{function e(e,n,r){return function(s,c){const u=r();if(c===oe&&t.G.isNotNullable(u))return;if(t.G.isNotNullable(c)&&c!==oe&&t.G.isNotNullable(u)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,u))return;const l={processes:new Set},d=Promise.withResolvers(),h=C(e,s,l);function m(t){const n=ce(O.current.handlers,"Error"),r=null!==n,s={reason:ae(t),error:(c=t,c instanceof Error?c:new Error(String(c))),action:w(e),handled:r,tasks:i};var c;o.fire(p,s),r&&n&&y.emit(n,s)}function b(){for(const e of i)if(e===h.task){i.delete(e),E.current.delete(e);break}l.processes.forEach(e=>f.current.prune(e)),l.processes.size>0&&a(),d.resolve()}let v;try{v=n(h,s)}catch(g){return m(g),void b()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(v))return Promise.resolve(v).catch(m).finally(b),d.promise;(async()=>{for await(const e of v);})().catch(m).finally(b)}}M.current++;const n=new Set;return O.current.handlers.forEach((t,r)=>{for(const{getChannel:c,handler:i}of t){const t=e(r,i,c);if(S(r)){if(s)for(const e of s.values()){const o=e.emitter;o.on(r,t),n.add(()=>o.off(r,t))}y.on(r,t),P.multicast.add(r),n.add(()=>y.off(r,t))}else g(r)?(o.on(r,t),y.on(r,t),P.broadcast.add(r),n.add(()=>{o.off(r,t),y.off(r,t)})):(y.on(r,t),n.add(()=>y.off(r,t)))}}),()=>{const e=++M.current,t=new Set(n);queueMicrotask(()=>{if(M.current!==e){for(const e of t)e();return}for(const e of E.current)e.controller.abort(),i.delete(e);E.current.clear(),x.current=b.Unmounting;const n=ce(O.current.handlers,"Unmount");n&&y.emit(n),x.current=b.Unmounted;for(const e of t)e()})}},[y]),function({unicast:e,broadcast:n,dispatchers:r,scope:o,phase:s,data:i,handlers:a}){const u=c.useRef(null);c.useLayoutEffect(()=>{if(s.current===b.Mounted)return;s.current=b.Mounting;const c=ce(a,"Mount");c&&e.emit(c),r.broadcast.forEach(r=>{const o=n.getCached(r);t.G.isNullable(o)||e.emit(r,o,oe)}),o&&r.multicast.forEach(n=>{for(const r of o.values()){const o=r.emitter.getCached(n);t.G.isNullable(o)||e.emit(n,o,oe)}}),s.current=b.Mounted},[]),c.useLayoutEffect(()=>{if(t.G.isNotNullable(u.current)){const n=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,i);if(t.A.isNotEmpty(Object.keys(n))){const t=ce(a,"Update");t&&e.emit(t,n)}}u.current=i},[i,e])}({unicast:y,broadcast:o,dispatchers:P,scope:s,phase:x,data:r(),handlers:O.current.handlers});const G=c.useMemo(()=>[d,{dispatch(e,t){const n=v(e),r=j(e)?e.channel:void 0;if(S(e)){const e=re(s,n);return e?se(e.emitter,n,t,r):Promise.resolve()}return se(g(e)?o:y,n,t,r)},get inspect(){return f.current.inspect},stream:(e,t)=>c.createElement(le,{action:v(e),renderer:t})}],[d,y]);return G.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),[]),i=c.useCallback(()=>j(o.current)?o.current.channel:void 0,[]),a=v(t),u=e.current.handlers.get(a)??new Set;0===u.size&&e.current.handlers.set(a,u),u.add({getChannel:i,handler:s})}(O,e,t)},G.useResource=e=>{const t=c.useMemo(()=>{const t=t=>e.run(t??{});return Object.assign(t,{if:(n,r)=>{const{data:o,at:s}=e;if(null!==s&&null!==o){const e=Temporal.Now.instant().since(s),t=Temporal.Duration.from(n.over);if(Temporal.Duration.compare(e,t)<=0)return Promise.resolve(o)}return t(r)}})},[e]);return c.useMemo(()=>Object.freeze({run:t,get data(){return e.data},get at(){return e.at}}),[e,t])},G},e.useMode=function(){const e=c.useContext(Z);return c.useMemo(()=>({read:()=>e.current,update(t){e.current=t}}),[e])},e.utils=he,e.withScope=function(e,t){const n=`Scoped${t.displayName||t.name||"Component"}`,o=v(e);return{[n](e){const n=ne(),s=c.useMemo(()=>({action:o,emitter:new J}),[]),i=c.useMemo(()=>{const e=new Map(n??[]);return e.set(o,s),e},[n,s]);return r.jsx(te.Provider,{value:i,children:r.jsx(t,{...e})})}}[n]},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("@mobily/ts-belt"),require("immer"),require("react/jsx-runtime"),require("react")):"function"==typeof define&&define.amd?define(["exports","@mobily/ts-belt","immer","react/jsx-runtime","react"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).MarchHare={},global.TsBelt,global.Immer,global.jsxRuntime,global.React);
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 a=s(o),c=(e="")=>`march-hare.action/${e}`,i=(e="")=>`march-hare.action/broadcast/${e}`,u=(e="")=>`march-hare.action/multicast/${e}`,l=(e="")=>`march-hare.action.lifecycle/${e}`;class f{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")}function d(e){const t=Symbol(`march-hare.action.lifecycle/${e}`),n=function(e){return{[f.Action]:t,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(n,f.Action,{value:t,enumerable:!1}),Object.defineProperty(n,f.Payload,{value:void 0,enumerable:!1}),n}const p=Symbol(i("Fault"));class h{static Mount(){return d("Mount")}static Unmount(){return d("Unmount")}static Error(){return d("Error")}static Update(){return d("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,f.Action,{value:p,enumerable:!1}),Object.defineProperty(e,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,f.Broadcast,{value:!0,enumerable:!1}),e})()}var m=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(m||{}),b=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(b||{});const y=e=>"symbol"==typeof e;function v(e){return t.G.isString(e)||y(e)?e:(t.G.isObject(e)||t.G.isFunction(e))&&f.Action in e?e[f.Action]:e}function g(e){if(t.G.isString(e))return e.startsWith(i());if(y(e))return e.description?.startsWith(i())??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(f.Broadcast in e&&e[f.Broadcast])return!0;if(f.Action in e){const t=e[f.Action];return t.description?.startsWith(i())??!1}}return!1}function w(e){const n=v(e),r=t.G.isString(n)?n:n.description??"";return r.startsWith(c())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function j(e){return t.G.isObject(e)&&f.Channel in e&&"channel"in e}function O(e){const t=v(e),n=y(t)?t.description??"":t;return n.startsWith(l())&&n.slice(l().length)||null}function S(e){if(t.G.isString(e))return e.startsWith(u());if(y(e))return e.description?.startsWith(u())??!1;if(t.G.isObject(e)||t.G.isFunction(e)){if(f.Multicast in e&&e[f.Multicast])return!0;if(f.Action in e){const t=e[f.Action];return t.description?.startsWith(u())??!1}}return!1}var P=(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Errored=2]="Errored",e))(P||{});class x extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}class E extends Error{name="TimeoutError";constructor(e="Timeout"){super(e)}}let M=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var A=(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))(A||{}),C=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(C||{}),G=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(G||{});class k{[n.immerable]=!0;static keys=new Set(Object.values(G));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new k(this.value,this.operation);return n.property=e,n.process=t,n}}class _{static immer=(()=>{n.enablePatches();const e=new n.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=M}function R(e,t){const n="string"==typeof t?""===t?[]:t.split("."):t;let r=e;for(const o of n){if(null==r)return;r=r[o]}return r}function N(e){if(t.G.isNullable(e)||L(e))return e;if(t.G.isArray(e))return e.map(e=>N(e));if(t.G.isObject(e)&&T(e)){const t=Object.entries(e).map(([e,t])=>[e,N(t)]);return{...Object.fromEntries(t),[_.tag]:e[_.tag]??_.id()}}return e}function U(e){if(Array.isArray(e))return e.filter(e=>_.tag in e).map(e=>e[_.tag]??"").join(",");const t=e[_.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function T(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function L(e){return t.G.isNullable(e)||t.G.isString(e)||t.G.isNumber(e)||t.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function B(e,n,r,o,s,a){return function c(i,u=n.path){if(i instanceof k){const n=R(r,u.join("."));if(Object.entries(i).filter(([e,t])=>!k.keys.has(e)&&t instanceof k).forEach(([e,t])=>c(t,u.concat(e))),L(i.value)){if(e===C.Hydrate)return i.value;const c=u.slice(0,-1),l=c.length>0?R(r,c.join(".")):r;return t.G.isNullable(l)||W(l,i,u.at(-1),o,s,a),n??i.value}if(e===C.Hydrate){const e=N(c(i.value,u));return W(e,i,null,o,s,a),e}const l=n??N(i.value);return W(l,i,null,o,s,a),t.G.isNullable(n)?l:(c(i.value,u),n)}if(t.G.isArray(i))return i.map((e,t)=>c(e,u.concat(t)));if(t.G.isObject(i)&&!T(i))return i;if(t.G.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,c(t,u.concat(e))]),n=Object.fromEntries(t);if(e===C.Hydrate){const e=N(n);return Object.entries(i).forEach(([t,n])=>{n instanceof k&&L(n.value)&&W(e,n,t,o,s,a)}),e}return n}return i}(n.value)}function W(e,t,n,r,o,s){const a=s(e),c=o.get(a)??[];o.set(a,[t.assign(n,r),...c])}class F{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=U){this.#t=e}static pk(){return M()}static"κ"=F.pk;annotate(e,t){return new k(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,n,r,o,s){function a(o){const s=o.at(-1),a=R(e(),o),c=o.slice(0,-1),i=t.A.isNotEmpty(c)?R(e(),c):e();return[...t.G.isObject(a)||t.G.isArray(a)?n.get(r(a))?.filter(e=>t.G.isNullable(e.property))??[]:[],...t.G.isObject(i)?n.get(r(i))?.filter(e=>e.property===s)??[]:[]]}return function n(r){return new Proxy(()=>{},{get:(c,i)=>"pending"===i?()=>!t.A.isEmpty(a(r)):"remaining"===i?()=>t.A.length(a(r)):"box"===i?()=>({value:R(e(),r),inspect:n(r)}):"is"===i?e=>a(r).some(t=>0!==(t.operation&e)):"draft"===i?()=>t.A.head(a(r))?.value??R(e(),r):"settled"===i?()=>new Promise(n=>{if(t.A.isEmpty(a(r)))return n(R(e(),r));const c=()=>{t.A.isEmpty(a(r))&&(s(c),n(R(e(),r)))};o(c)}):n([...r,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(C.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(C.Produce,e)}#s(e,t){const n=Symbol("process"),[,r]=_.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>_.immer.applyPatches(t,[{...r,value:B(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=N(this.#e),this.#a(),n}prune(e){this.#n.forEach((n,r)=>{const o=n.filter(t=>t.process!==e);t.A.isEmpty(o)?this.#n.delete(r):this.#n.set(r,o)}),this.#a()}#a(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const $=new F;function I(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H,z={exports:{}},D=(H||(H=1,function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function s(e,t,r,s,a){if("function"!=typeof r)throw new TypeError("The listener must be a function");var c=new o(r,s||e,a),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],c]:e._events[i].push(c):(e._events[i]=c,e._eventsCount++),e}function a(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function c(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),c.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},c.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},c.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},c.prototype.emit=function(e,t,r,o,s,a){var c=n?n+e:e;if(!this._events[c])return!1;var i,u,l=this._events[c],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,a),!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},c.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},c.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},c.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return a(this,s),this;var c=this._events[s];if(c.fn)c.fn!==t||o&&!c.once||r&&c.context!==r||a(this,s);else{for(var i=0,u=[],l=c.length;i<l;i++)(c[i].fn!==t||o&&!c[i].once||r&&c[i].context!==r)&&u.push(c[i]);u.length?this._events[s]=1===u.length?u[0]:u:a(this,s)}return this},c.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&a(this,t):(this._events=new r,this._eventsCount=0),this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prefixed=n,c.EventEmitter=c,e.exports=c}(z)),z.exports);const q=I(D);class J extends q{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 V=a.createContext(new J);function K(){return a.useContext(V)}function Q({children:e}){const t=a.useMemo(()=>new J,[]);return r.jsx(V.Provider,{value:t,children:e})}const X=a.createContext(new Set);function Y({children:e}){const t=a.useMemo(()=>new Set,[]);return r.jsx(X.Provider,{value:t,children:e})}const Z=a.createContext({current:null});function ee({children:e}){const t=a.useRef(null);return r.jsx(Z.Provider,{value:t,children:e})}const te=a.createContext(null);function ne(){return a.useContext(te)}function re(e,t){return e?.get(t)??null}const oe=Symbol(((e="")=>`march-hare/replay${e}`)());function se(e,t,...n){e instanceof J&&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 ae(e,t){for(const n of e.keys())if(O(n)===t)return n;return null}const ce=Symbol("march-hare.unset");function ie(){const[,e]=a.useReducer(e=>e+1,0);return e}function ue(){return{data:ce,at:null,else:e=>e}}function le(e,t){return{data:e,at:t,else:t=>e}}function fe(e){if(e instanceof Error){if("TimeoutError"===e.name)return P.Timedout;if("AbortError"===e.name)return P.Supplanted}return P.Errored}const de=a.createContext(new Map);function pe({action:e,renderer:n}){const r=K(),o=a.useContext(de),s=ie(),c=a.useMemo(()=>{const t=o.get(e);if(t)return t;const n={state:new F,listeners:new Set};return o.set(e,n),n},[e,o]);a.useLayoutEffect(()=>{function t(e){c.state.hydrate({value:e}),c.listeners.forEach(e=>e())}return c.listeners.add(s),r.on(e,t),()=>{c.listeners.delete(s),r.off(e,t)}},[e,r,c]);const i=c.state.model?.value;return t.G.isNullable(i)?null:n(i,c.state.inspect.value)}function he(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 me(e,t,n){if(t?.aborted)throw new x;for(;;){if(await n())return;await he(e,t)}}function be(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}function ye(e){return{get(t){try{const n=e.get(t);if(null===n)return ue();const r=JSON.parse(n);return le(r.data,Temporal.Instant.from(r.at))}catch{return ue()}},set(t,n){if(n.data===ce||null===n.at)return!1;try{return e.set(t,JSON.stringify({data:n.data,at:n.at.toString()})),!0}catch{return!1}},remove(t){e.remove(t)},clear(){e.clear()}}}const ve=Object.freeze(Object.defineProperty({__proto__:null,pk:be,poll:me,sleep:he,store:ye,unset:ce,"ζ":he,"κ":be,"π":me,"σ":ye},Symbol.toStringTag,{value:"Module"})),ge=new WeakMap;e.AbortError=x,e.Action=(e,t=m.Unicast)=>{const n=t===m.Broadcast?Symbol(i(e)):t===m.Multicast?Symbol(u(e)):Symbol(c(e)),r=function(e){return{[f.Action]:n,[f.Payload]:void 0,[f.Channel]:e,channel:e}};return Object.defineProperty(r,f.Action,{value:n,enumerable:!1}),Object.defineProperty(r,f.Payload,{value:void 0,enumerable:!1}),t===m.Broadcast&&Object.defineProperty(r,f.Broadcast,{value:!0,enumerable:!1}),t===m.Multicast&&Object.defineProperty(r,f.Multicast,{value:!0,enumerable:!1}),r},e.Boundary=function({children:e}){return r.jsx(Q,{children:r.jsx(ee,{children:r.jsx(Y,{children:e})})})},e.Distribution=m,e.Lifecycle=h,e.Op=A,e.Operation=A,e.Reason=P,e.Resource=function(e){return{run:(t,n)=>e(t,n).then(t=>(ge.set(e,{data:t,at:Temporal.Now.instant()}),t)),get data(){const t=ge.get(e);return void 0===t?ce:t.data},get at(){return ge.get(e)?.at??null},seed(t,n){ge.set(e,{data:t,at:n})}}},e.State=F,e.TimeoutError=E,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=A.Update){return $.annotate(t,e)},e.useActions=function(...e){const n=t.G.isUndefined(e[0])||t.G.isFunction(e[0])?{}:e[0],r=t.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),o=K(),s=ne(),c=a.useContext(X),i=ie(),u=a.useRef(!1),l=a.useRef(null),f=a.useRef(new F);u.current||(u.current=!0,l.current=f.current.hydrate(n));const[d,h]=a.useState(()=>f.current.model),m=function(e){const t=a.useRef(e);return a.useLayoutEffect(()=>{t.current=e},[e]),a.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(r()),y=a.useMemo(()=>new q,[]),O=a.useRef({handlers:new Map});O.current.handlers=new Map;const P=function(){const e=a.useRef(new Set),t=a.useRef(new Set);return a.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),x=a.useRef(b.Mounting),E=a.useRef(new Set),M=a.useRef(0),C=a.useCallback((e,t,n)=>{const r=new AbortController,a={controller:r,action:e,payload:t};return c.add(a),E.current.add(a),{model:f.current.model,get phase(){return x.current},task:a,data:m,tasks:c,actions:{produce(e){if(r.signal.aborted)return;const t=f.current.produce(t=>{e({model:t,inspect:f.current.inspect})});h(f.current.model),n.processes.add(t),l.current&&(n.processes.add(l.current),l.current=null)},dispatch(e,t){if(r.signal.aborted)return Promise.resolve();const n=v(e),a=j(e)?e.channel:void 0;if(S(e)){const e=re(s,n);return e?se(e.emitter,n,t,a):Promise.resolve()}return se(g(e)?o:y,n,t,a)},annotate:(e,t=A.Update)=>f.current.annotate(t,e),async resolution(e){if(r.signal.aborted)return null;const t=v(e),n=S(e)?re(s,t)?.emitter??null:o;if(!n)return null;if(void 0===n.getCached(t))return null;const a=w(e),c="unknown"!==a?a[0].toLowerCase()+a.slice(1):null;if(c){const e=f.current.inspect[c];e?.pending?.()&&await new Promise((t,n)=>{if(r.signal.aborted)return void n(r.signal.reason);const o=()=>n(r.signal.reason);r.signal.addEventListener("abort",o,{once:!0}),e.settled().then(()=>{r.signal.removeEventListener("abort",o),t()})})}return n.getCached(t)??null},peek(e){if(r.signal.aborted)return null;const t=v(e),n=S(e)?re(s,t)?.emitter??null:o;return n?n.getCached(t)??null:null}}}},[d]);a.useLayoutEffect(()=>{function e(e,n,r){return function(s,a){const u=r();if(a===oe&&t.G.isNotNullable(u))return;if(t.G.isNotNullable(a)&&a!==oe&&t.G.isNotNullable(u)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(a,u))return;const l={processes:new Set},d=Promise.withResolvers(),h=C(e,s,l);function m(t){const n=ae(O.current.handlers,"Error"),r=null!==n,s={reason:fe(t),error:(a=t,a instanceof Error?a:new Error(String(a))),action:w(e),handled:r,tasks:c};var a;o.fire(p,s),r&&n&&y.emit(n,s)}function b(){for(const e of c)if(e===h.task){c.delete(e),E.current.delete(e);break}l.processes.forEach(e=>f.current.prune(e)),l.processes.size>0&&i(),d.resolve()}let v;try{v=n(h,s)}catch(g){return m(g),void b()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(v))return Promise.resolve(v).catch(m).finally(b),d.promise;(async()=>{for await(const e of v);})().catch(m).finally(b)}}M.current++;const n=new Set;return O.current.handlers.forEach((t,r)=>{for(const{getChannel:a,handler:c}of t){const t=e(r,c,a);if(S(r)){if(s)for(const e of s.values()){const o=e.emitter;o.on(r,t),n.add(()=>o.off(r,t))}y.on(r,t),P.multicast.add(r),n.add(()=>y.off(r,t))}else g(r)?(o.on(r,t),y.on(r,t),P.broadcast.add(r),n.add(()=>{o.off(r,t),y.off(r,t)})):(y.on(r,t),n.add(()=>y.off(r,t)))}}),()=>{const e=++M.current,t=new Set(n);queueMicrotask(()=>{if(M.current!==e){for(const e of t)e();return}for(const e of E.current)e.controller.abort(),c.delete(e);E.current.clear(),x.current=b.Unmounting;const n=ae(O.current.handlers,"Unmount");n&&y.emit(n),x.current=b.Unmounted;for(const e of t)e()})}},[y]),function({unicast:e,broadcast:n,dispatchers:r,scope:o,phase:s,data:c,handlers:i}){const u=a.useRef(null);a.useLayoutEffect(()=>{if(s.current===b.Mounted)return;s.current=b.Mounting;const a=ae(i,"Mount");a&&e.emit(a),r.broadcast.forEach(r=>{const o=n.getCached(r);t.G.isNullable(o)||e.emit(r,o,oe)}),o&&r.multicast.forEach(n=>{for(const r of o.values()){const o=r.emitter.getCached(n);t.G.isNullable(o)||e.emit(n,o,oe)}}),s.current=b.Mounted},[]),a.useLayoutEffect(()=>{if(t.G.isNotNullable(u.current)){const n=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,c);if(t.A.isNotEmpty(Object.keys(n))){const t=ae(i,"Update");t&&e.emit(t,n)}}u.current=c},[c,e])}({unicast:y,broadcast:o,dispatchers:P,scope:s,phase:x,data:r(),handlers:O.current.handlers});const G=a.useMemo(()=>[d,{dispatch(e,t){const n=v(e),r=j(e)?e.channel:void 0;if(S(e)){const e=re(s,n);return e?se(e.emitter,n,t,r):Promise.resolve()}return se(g(e)?o:y,n,t,r)},get inspect(){return f.current.inspect},stream:(e,t)=>a.createElement(pe,{action:v(e),renderer:t})}],[d,y]);return G.useAction=(e,t)=>{!function(e,t,n){const r=a.useRef(n);a.useLayoutEffect(()=>{r.current=n});const o=a.useRef(t);a.useLayoutEffect(()=>{o.current=t});const s=a.useCallback((e,t)=>r.current(e,t),[]),c=a.useCallback(()=>j(o.current)?o.current.channel:void 0,[]),i=v(t),u=e.current.handlers.get(i)??new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:c,handler:s})}(O,e,t)},G},e.useMode=function(){const e=a.useContext(Z);return a.useMemo(()=>({read:()=>e.current,update(t){e.current=t}}),[e])},e.useResource=function(e){return a.useMemo(()=>{const t=(t,n)=>e.run(t??void 0,n??{});return Object.defineProperties(t,{if:{value:(t,n,r)=>{const o=e.data,s=e.at;if(o!==ce&&null!==s){const e=Temporal.Now.instant().since(s),n=Temporal.Duration.from(t.over);if(Temporal.Duration.compare(e,n)<=0)return Promise.resolve(o)}return e.run(n??void 0,r??{})},enumerable:!0},else:{value:function(n){if(null!==(r=n)&&"object"==typeof r&&"data"in r&&"at"in r&&"else"in r)return e.data===ce&&n.data!==ce&&null!==n.at&&e.seed(n.data,n.at),t;var r;const o=e.data;return o===ce?n:o},enumerable:!0},snapshot:{value:()=>{const t=e.data,n=e.at;return t===ce||null===n?ue():le(t,n)},enumerable:!0},data:{get:()=>e.data,enumerable:!0},at:{get:()=>e.at,enumerable:!0}}),t},[e])},e.utils=ve,e.withScope=function(e,t){const n=`Scoped${t.displayName||t.name||"Component"}`,o=v(e);return{[n](e){const n=ne(),s=a.useMemo(()=>({action:o,emitter:new J}),[]),c=a.useMemo(()=>{const e=new Map(n??[]);return e.set(o,s),e},[n,s]);return r.jsx(te.Provider,{value:c,children:r.jsx(t,{...e})})}}[n]},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("@mobily/ts-belt"),require("immer"),require("react/jsx-runtime"),require("react")):"function"==typeof define&&define.amd?define(["exports","@mobily/ts-belt","immer","react/jsx-runtime","react"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).MarchHare={},global.TsBelt,global.Immer,global.jsxRuntime,global.React);
@@ -8,9 +8,10 @@ export { withScope } from './boundary/components/scope/index.tsx';
8
8
  export { useMode } from './boundary/components/mode/index.tsx';
9
9
  export type { ModeHandle } from './boundary/components/mode/index.tsx';
10
10
  export { useActions, With } from './hooks/index.ts';
11
- export { Resource } from './resource/index.ts';
12
- export type { ResourceHandle, ResourceFetcher, BoundRun, IfOptions, } from './resource/index.ts';
11
+ export { Resource, useResource } from './resource/index.ts';
12
+ export type { ResourceHandle, ResourceFetcher, BoundResourceHandle, IfOptions, } from './resource/index.ts';
13
13
  export * as utils from './utils/index.ts';
14
+ export type { Stored, Unset, Adapter, Store } from './utils/index.ts';
14
15
  export type { Box } from 'immertation';
15
16
  export type { Fault } from './error/index.ts';
16
17
  export type { Pk, Task, Tasks, Handlers } from './types/index.ts';
@@ -1,99 +1,65 @@
1
+ import { ResourceFetcher, ResourceHandle, BoundResourceHandle } from './types.ts';
2
+ export type { IfOptions, ResourceFetcher, ResourceHandle, BoundResourceHandle, } from './types.ts';
1
3
  /**
2
- * Options accepted by `run.if(...)`.
4
+ * Defines a remote resource &mdash; declared at module scope and
5
+ * consumed via {@link useResource}.
3
6
  *
4
- * - `over` &ndash; a `Temporal.Duration`, a `DurationLike` object
5
- * (e.g. `{ minutes: 5 }`), or an ISO 8601 duration string (`"PT5M"`).
6
- * If the most recent successful run resolved longer ago than this
7
- * window, `run(...)` is called. Otherwise the cached data is returned
8
- * without hitting the network.
7
+ * The fetcher receives the optional `AbortSignal` first and the
8
+ * `params` object second (defaults to `{}`). Resources do **not**
9
+ * carry any callbacks &ndash; side-effects (broadcasting, logging,
10
+ * model updates) belong in the `useAction` handler that called
11
+ * `await handle(...)`.
12
+ *
13
+ * Every call fires its own request. The most recent successful
14
+ * payload is cached in a module-level `WeakMap` keyed by the fetcher,
15
+ * so `.if(...)` and `.else(...)` on the bound handle behave
16
+ * consistently across all components that share the same Resource.
9
17
  *
10
18
  * @example
11
19
  * ```ts
12
- * await user.run.if({ over: { minutes: 5 } });
13
- * await user.run.if({ over: "PT5M" });
14
- * await user.run.if({ over: Temporal.Duration.from({ minutes: 5 }) });
15
- * ```
16
- */
17
- export type IfOptions = {
18
- readonly over: Temporal.DurationLike;
19
- };
20
- /**
21
- * Fetcher signature accepted by {@link Resource}. Receives the
22
- * call-site `params` object and returns a `Promise` of the response.
23
- * Side-effects (dispatching broadcasts, analytics, etc.) belong in
24
- * the calling `useAction` handler, not inside the fetcher.
25
- */
26
- export type ResourceFetcher<T, P extends object = Record<never, never>> = (params: P) => Promise<T>;
27
- /**
28
- * Component-bound `run` callable returned by `actions.useResource`. It
29
- * is invokable like the underlying fetcher (`run(params)`) and also
30
- * carries an `if` method that triggers the network call only when the
31
- * cached data is older than the supplied freshness window.
20
+ * import { Resource } from "march-hare";
32
21
  *
33
- * The conditional specialisation collapses the call signature when
34
- * `P` is empty &mdash; `run()` instead of `run({})`.
35
- */
36
- export type BoundRun<T, P extends object> = [keyof P] extends [never] ? {
37
- (): Promise<T>;
38
- /**
39
- * Calls `run()` if the most recent successful run resolved longer
40
- * ago than `options.over`. Otherwise returns the cached data.
41
- */
42
- readonly if: (options: IfOptions) => Promise<T>;
43
- } : {
44
- (params: P): Promise<T>;
45
- /**
46
- * Calls `run(params)` if the most recent successful run resolved
47
- * longer ago than `options.over`. Otherwise returns the cached data.
48
- */
49
- readonly if: (options: IfOptions, params: P) => Promise<T>;
50
- };
51
- /**
52
- * Module-scope handle returned by {@link Resource}. Pass to
53
- * `actions.useResource(handle)` inside a component to obtain a
54
- * `{ run, data, at }` object.
22
+ * // `T` is inferred from the fetcher's return type.
23
+ * export const user = Resource((signal) =>
24
+ * ky.get("user", { signal }).json<User>(),
25
+ * );
26
+ *
27
+ * // Annotate `params` when destructuring so `P` is inferred.
28
+ * export const updateUser = Resource(
29
+ * (signal, { id, body }: { id: number; body: { name: string } }) =>
30
+ * ky.patch(`users/${id}`, { json: body, signal }).json<User>(),
31
+ * );
32
+ * ```
55
33
  */
56
- export type ResourceHandle<T, P extends object = Record<never, never>> = {
57
- readonly key: string;
58
- /** @internal */
59
- readonly run: (params: P) => Promise<T>;
60
- /** Most recent successful data across all param-sets, or `null`. */
61
- readonly data: T | null;
62
- /** Instant of the most recent successful run, or `null`. */
63
- readonly at: Temporal.Instant | null;
64
- };
34
+ export declare function Resource<T, P extends object = Record<never, never>>(fetcher: ResourceFetcher<T, P>): ResourceHandle<T, P>;
65
35
  /**
66
- * Defines a remote resource &mdash; declare at module scope and consume
67
- * via `actions.useResource(handle)`. Mirrors the {@link Action} factory
68
- * pattern: the declaration is a value, not a hook.
69
- *
70
- * The fetcher takes a single `params` argument (defaults to `{}`) and
71
- * returns a `Promise<T>`. Resources do **not** carry any callbacks
72
- * &ndash; any side-effects the caller wants on success or failure
73
- * (broadcasting, logging, model updates) belong in the `useAction`
74
- * handler that called `await user.run(...)`.
36
+ * Binds a module-scope {@link ResourceHandle} to the component, returning
37
+ * the fetch callable with `.if`, `.else`, `.snapshot`, `.data`, and `.at`
38
+ * attached. The hook is standalone &ndash; call it *before* `useActions`
39
+ * when you want to seed the initial model from the cache via
40
+ * `.else(fallback)`.
75
41
  *
76
- * `params` are typed via the second generic and forwarded to every
77
- * `run(params)` call site. In-flight dedup keys per params shape, so
78
- * `feed.run({ cursor: null })` and `feed.run({ cursor: "abc" })` execute
79
- * independently while two concurrent `feed.run({ cursor: "abc" })` calls
80
- * share one network request.
81
- *
82
- * Each call to `run()` always hits the network; `data` and `at`
83
- * are read-only snapshots of the most recent successful payload and
84
- * the instant it resolved &ndash; not a memoised result.
42
+ * Pass `context.task.controller.signal` as the first argument to thread
43
+ * cancellation from the surrounding action handler through to the
44
+ * fetcher. For parameterised resources, pass `null` as the first arg
45
+ * when you have params but no signal.
85
46
  *
86
47
  * @example
87
48
  * ```ts
88
- * import { Resource } from "march-hare";
89
- *
90
- * export const feed = Resource<Page<Item>, { cursor: string | null }>(
91
- * "feed",
92
- * ({ cursor }) =>
93
- * http
94
- * .get("feed", { searchParams: { cursor: cursor ?? "" } })
95
- * .json<Page<Item>>(),
49
+ * const cat = useResource(resources.cat);
50
+ * const actions = useActions<Model, typeof Actions, Data>(
51
+ * { cat: cat.else(store.get(Snapshots.Cat)).else(null) },
52
+ * () => ({ index, router }),
96
53
  * );
54
+ *
55
+ * actions.useAction(Actions.Mount, async (context) => {
56
+ * const fresh = await cat.if(
57
+ * { over: { minutes: 5 } },
58
+ * context.task.controller.signal,
59
+ * );
60
+ * store.set(Snapshots.Cat, cat.snapshot());
61
+ * context.actions.produce(({ model }) => void (model.cat = fresh));
62
+ * });
97
63
  * ```
98
64
  */
99
- export declare function Resource<T, P extends object = Record<never, never>>(key: string, fetcher: ResourceFetcher<T, P>): ResourceHandle<T, P>;
65
+ export declare function useResource<T, P extends object>(resource: ResourceHandle<T, P>): BoundResourceHandle<T, P>;
@@ -0,0 +1,150 @@
1
+ import { Stored, Unset } from '../utils/index.ts';
2
+ export type { Unset } from '../utils/index.ts';
3
+ /**
4
+ * Options accepted by `.if(...)` on a bound resource handle.
5
+ *
6
+ * - `over` &ndash; a `Temporal.Duration`, a `DurationLike` object
7
+ * (e.g. `{ minutes: 5 }`), or an ISO 8601 duration string (`"PT5M"`).
8
+ * If the most recent successful run resolved longer ago than this
9
+ * window, the underlying fetcher is called. Otherwise the cached
10
+ * data is returned without hitting the network.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * await user.if({ over: { minutes: 5 } });
15
+ * await user.if({ over: "PT5M" });
16
+ * await user.if({ over: Temporal.Duration.from({ minutes: 5 }) });
17
+ * ```
18
+ */
19
+ export type IfOptions = {
20
+ readonly over: Temporal.DurationLike;
21
+ };
22
+ /**
23
+ * Fetcher signature accepted by `Resource`. Receives the optional
24
+ * `AbortSignal` first (threaded from the action handler's
25
+ * `context.task.controller.signal`) and the call-site `params` second.
26
+ * Side-effects (dispatching broadcasts, analytics, etc.) belong in the
27
+ * calling `useAction` handler, not inside the fetcher.
28
+ */
29
+ export type ResourceFetcher<T, P extends object = Record<never, never>> = (signal: AbortSignal | undefined, params: P) => Promise<T>;
30
+ /**
31
+ * Module-scope handle returned by `Resource`. Pass to `useResource` to
32
+ * obtain the bound, component-scoped callable.
33
+ *
34
+ * Every call to the underlying fetcher fires its own request. The most
35
+ * recent successful response is cached in a module-level `WeakMap`
36
+ * keyed by the fetcher itself, so `.if(...)` and `.else(...)` on the
37
+ * bound handle have something to read from.
38
+ */
39
+ export type ResourceHandle<T, P extends object = Record<never, never>> = {
40
+ /** @internal */
41
+ readonly run: (signal: AbortSignal | undefined, params: P) => Promise<T>;
42
+ /**
43
+ * Most recent successfully-resolved payload, or the shared `unset`
44
+ * sentinel if no successful run has happened yet.
45
+ * @internal
46
+ */
47
+ readonly data: T | Unset;
48
+ /** @internal */
49
+ readonly at: Temporal.Instant | null;
50
+ /**
51
+ * Populates the cache slot with `data` and `at` without invoking the
52
+ * fetcher. Used by the bound handle's `.else(stored)` overload to
53
+ * hydrate the cache from a {@link Stored} fallback (typically the
54
+ * return value of `Store.get(key)` after a page reload).
55
+ * @internal
56
+ */
57
+ readonly seed: (data: T, at: Temporal.Instant) => void;
58
+ };
59
+ /**
60
+ * Component-bound handle returned by `useResource`. The handle is itself
61
+ * the fetch callable &mdash; `await user(signal?, params?)` triggers a
62
+ * request &mdash; with attached read accessors and methods:
63
+ *
64
+ * - `.if({ over }, signal?, params?)` &mdash; fetch only if the cached
65
+ * payload is older than the supplied freshness window; otherwise
66
+ * return the cached payload synchronously.
67
+ * - `.else(fallback)` &mdash; synchronous read of the cached payload,
68
+ * falling back to the supplied default when nothing has resolved
69
+ * successfully yet. Accepts either a value (terminal, returns
70
+ * `T | U`) or a {@link Stored} (chainable, seeds the cache from the
71
+ * Stored's data/at when the cache is empty and returns the same bound
72
+ * handle for further chaining).
73
+ * - `.snapshot()` &mdash; returns a {@link Stored} wrapping the current
74
+ * cache state, symmetric with `Store.get(key)`. Pass straight to
75
+ * `Store.set(key, ...)` to persist the latest successful payload.
76
+ * - `.data` and `.at` &mdash; the underlying cache fields. Reading
77
+ * `.snapshot()` is usually clearer.
78
+ *
79
+ * Call signature: `(signal?)` for resources with no params, or
80
+ * `(signal: AbortSignal | null, params: P)` for parameterised
81
+ * resources &mdash; pass `null` as the first argument when you have
82
+ * params but no signal to thread.
83
+ */
84
+ export type BoundResourceHandle<T, P extends object> = [keyof P] extends [never] ? {
85
+ (signal?: AbortSignal): Promise<T>;
86
+ /**
87
+ * Calls the underlying fetcher if the most recent successful run
88
+ * resolved longer ago than `options.over`. Otherwise returns the
89
+ * cached data without hitting the network.
90
+ */
91
+ readonly if: (options: IfOptions, signal?: AbortSignal) => Promise<T>;
92
+ /**
93
+ * Overloaded fallback accessor.
94
+ *
95
+ * - `(fallback: U)` terminal &mdash; returns the cached payload, or
96
+ * `fallback` when nothing has resolved yet. Cached `null` values
97
+ * are returned verbatim.
98
+ * - `(stored: Stored<T>)` chainable &mdash; if the cache is empty
99
+ * and the Stored carries data and a timestamp, seeds the cache
100
+ * from it before returning the same bound handle so further
101
+ * `.else(...)` calls compose. Used to hydrate the cache on first
102
+ * render after a page reload, allowing `.if({ over })` to
103
+ * short-circuit on the persisted timestamp.
104
+ */
105
+ readonly else: {
106
+ (stored: Stored<T>): BoundResourceHandle<T, P>;
107
+ <U>(fallback: U): T | U;
108
+ };
109
+ /**
110
+ * Snapshot of the current cache state in the shared {@link Stored}
111
+ * shape. Empty (`data === unset`, `at === null`) until a fetcher
112
+ * resolves; otherwise carries the most recent payload and the
113
+ * instant it resolved. Pass directly to `Store.set(key, ...)`.
114
+ */
115
+ readonly snapshot: () => Stored<T>;
116
+ /** Direct read of the cache payload. Prefer `.snapshot()`. */
117
+ readonly data: T | Unset;
118
+ /** Instant the cache was last populated, or `null` if empty. */
119
+ readonly at: Temporal.Instant | null;
120
+ } : {
121
+ (signal: AbortSignal | null, params: P): Promise<T>;
122
+ /**
123
+ * Calls the underlying fetcher if the most recent successful run
124
+ * resolved longer ago than `options.over`. Otherwise returns the
125
+ * cached data without hitting the network.
126
+ */
127
+ readonly if: (options: IfOptions, signal: AbortSignal | null, params: P) => Promise<T>;
128
+ /**
129
+ * Overloaded fallback accessor.
130
+ *
131
+ * - `(fallback: U)` terminal &mdash; returns the cached payload, or
132
+ * `fallback` when nothing has resolved yet.
133
+ * - `(stored: Stored<T>)` chainable &mdash; if the cache is empty
134
+ * and the Stored carries data and a timestamp, seeds the cache
135
+ * from it before returning the same bound handle.
136
+ */
137
+ readonly else: {
138
+ (stored: Stored<T>): BoundResourceHandle<T, P>;
139
+ <U>(fallback: U): T | U;
140
+ };
141
+ /**
142
+ * Snapshot of the current cache state in the shared {@link Stored}
143
+ * shape. Pass directly to `Store.set(key, ...)`.
144
+ */
145
+ readonly snapshot: () => Stored<T>;
146
+ /** Direct read of the cache payload. Prefer `.snapshot()`. */
147
+ readonly data: T | Unset;
148
+ /** Instant the cache was last populated, or `null` if empty. */
149
+ readonly at: Temporal.Instant | null;
150
+ };
@@ -0,0 +1,23 @@
1
+ import { unset } from '../utils/index.ts';
2
+ /**
3
+ * Module-level cache shared by every `Resource` declaration. Keyed by
4
+ * the fetcher function itself so each module-scope declaration gets a
5
+ * distinct slot &mdash; entries are garbage-collected when the fetcher
6
+ * reference is dropped.
7
+ *
8
+ * @internal
9
+ */
10
+ export declare const cache: WeakMap<object, {
11
+ data: unknown;
12
+ at: Temporal.Instant;
13
+ }>;
14
+ /**
15
+ * Re-export of the shared `unset` sentinel from {@link "../utils/index.ts"}.
16
+ * Kept under `config` for back-compatibility with existing imports in this
17
+ * module's siblings; new code should import `unset` directly from `utils`.
18
+ *
19
+ * @internal
20
+ */
21
+ export declare const config: {
22
+ readonly unset: typeof unset;
23
+ };
@@ -690,29 +690,4 @@ export type UseActions<M extends Model | void, AC extends Actions | void, D exte
690
690
  * ```
691
691
  */
692
692
  useAction<A extends ActionId | HandlerPayload | ChanneledAction>(action: A, handler: (context: HandlerContext<M, AC, D>, ...args: [Payload<A>] extends [never] ? [] : [payload: Payload<A>]) => void | Promise<void> | AsyncGenerator | Generator): void;
693
- /**
694
- * Connects a {@link Resource} declared at module scope to this component.
695
- * Returns a frozen `{ run, data, at }` object &ndash; `run` triggers a
696
- * fresh network call (concurrent calls share the in-flight promise),
697
- * while `data` and `at` are read-only snapshots of the most recent
698
- * successful payload and the instant it resolved.
699
- *
700
- * `data` and `at` are non-reactive &mdash; reading them does not
701
- * subscribe the component to updates. Drive UI from the model.
702
- *
703
- * @example
704
- * ```ts
705
- * const user = actions.useResource(resources.user);
706
- *
707
- * actions.useAction(Actions.Mount, async (context) => {
708
- * const data = await user.run();
709
- * context.actions.produce(({ model }) => { model.user = data; });
710
- * });
711
- * ```
712
- */
713
- useResource<T, P extends object>(resource: import('../resource/index.ts').ResourceHandle<T, P>): Readonly<{
714
- run: import('../resource/index.ts').BoundRun<T, P>;
715
- data: T | null;
716
- at: Temporal.Instant | null;
717
- }>;
718
693
  };
@@ -1,42 +1,92 @@
1
1
  import { Pk } from '../types/index.ts';
2
+ import { Adapter, Store } from './types.ts';
3
+ export { unset } from './utils.ts';
4
+ export type { Adapter, Encoded, Store, Stored, Unset } from './types.ts';
2
5
  /**
3
- * Returns a promise that resolves after the specified number of milliseconds.
4
- * The sleep will reject with an AbortError when the signal is aborted,
5
- * allowing cleanup of pending operations.
6
+ * Returns a promise that resolves after the specified number of
7
+ * milliseconds, or rejects with an {@link AbortError} when the signal is
8
+ * aborted. Use to inject a cancellable delay into an action handler.
6
9
  *
7
- * @param ms The number of milliseconds to sleep.
8
- * @param signal AbortSignal to cancel the sleep early.
9
- * @returns A promise that resolves after the delay or rejects if aborted.
10
+ * @param ms How long to wait before resolving.
11
+ * @param signal Optional {@link AbortSignal} that cancels the sleep early.
12
+ * Pass `context.task.controller.signal` to tie the wait to
13
+ * the lifetime of the current action.
14
+ * @returns A promise that resolves after `ms` milliseconds or rejects with
15
+ * an {@link AbortError} if `signal` aborts first.
10
16
  */
11
17
  export declare function sleep(ms: number, signal: AbortSignal | undefined): Promise<void>;
12
- /** Shorthand alias for {@link sleep}. */
13
- export declare const ζ: typeof sleep;
14
18
  /**
15
- * Repeatedly calls a function at a fixed interval until it returns `true` or
16
- * the signal is aborted. The function is invoked immediately on the first
17
- * iteration, then after each interval.
18
- *
19
- * @param ms The interval in milliseconds between invocations.
20
- * @param signal Optional AbortSignal to cancel polling early.
21
- * @param fn Callback invoked each iteration. Return `true` to stop polling.
22
- * @returns A promise that resolves when `fn` returns `true`, or rejects with
23
- * an AbortError if the signal is aborted.
19
+ * Repeatedly calls a function at a fixed interval until it returns `true`
20
+ * or the signal is aborted. The function is invoked immediately on the
21
+ * first iteration, then after each interval.
22
+ *
23
+ * @param ms Interval in milliseconds between invocations of `fn`.
24
+ * @param signal Optional {@link AbortSignal} that cancels polling early.
25
+ * Aborts propagate as an {@link AbortError} rejection.
26
+ * @param fn Predicate invoked each iteration. Return `true` to stop
27
+ * polling, `false` to schedule another invocation after `ms`.
28
+ * May be sync or async.
29
+ * @returns A promise that resolves when `fn` returns `true`, or rejects
30
+ * with an {@link AbortError} if `signal` aborts first.
24
31
  */
25
32
  export declare function poll(ms: number, signal: AbortSignal | undefined, fn: () => boolean | Promise<boolean>): Promise<void>;
26
- /** Shorthand alias for {@link poll}. */
27
- export declare const π: typeof poll;
28
33
  /**
29
34
  * Generates a unique primary key.
35
+ *
30
36
  * @returns A new unique symbol representing the primary key.
31
37
  */
32
38
  export declare function pk(): symbol;
33
39
  /**
34
- * Checks if the provided ID is a valid primary key.
35
- * A valid primary key is considered any value that is not a symbol.
36
- * @template T The type of the object.
40
+ * Checks if the provided ID is a valid primary key. A valid primary key
41
+ * is any value that is not a symbol.
42
+ *
43
+ * @template T The model type the key identifies.
37
44
  * @param id The primary key to validate.
38
- * @returns `true` if the ID is valid, `false` otherwise.
45
+ * @returns `true` if `id` is a non-symbol value, `false` otherwise.
39
46
  */
40
47
  export declare function pk<T>(id: Pk<T>): boolean;
48
+ /**
49
+ * Wraps a synchronous {@link Adapter} into a {@link Store} that traffics
50
+ * in {@link Stored} values. Storage entries serialise as
51
+ * {@link Encoded}`<T>` so the `Temporal.Instant` timestamp survives the
52
+ * string round-trip and `BoundResourceHandle.if({ over })` can
53
+ * short-circuit on the persisted timestamp after a reload.
54
+ *
55
+ * @param adapter Backend implementation providing raw string `get`/`set`/
56
+ * `remove`/`clear`. The Store layers JSON encoding and
57
+ * timestamp serialisation on top.
58
+ * @returns A {@link Store} bound to `adapter`. Reads return {@link Stored}
59
+ * envelopes; writes accept Stored envelopes and return `true`
60
+ * when the entry landed in the adapter.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const store = utils.store({
65
+ * get: (key) => localStorage.getItem(key),
66
+ * set: (key, value) => localStorage.setItem(key, value),
67
+ * remove: (key) => localStorage.removeItem(key),
68
+ * clear: () => localStorage.clear(),
69
+ * });
70
+ *
71
+ * // Read into a Resource fallback chain.
72
+ * { cat: get.cat.else(store.get(Snapshots.Cat)).else(null) }
73
+ *
74
+ * // Write the latest cached value back to storage.
75
+ * store.set(Snapshots.Cat, get.cat.snapshot());
76
+ *
77
+ * // Drop a snapshot on sign-out, cache invalidation, etc.
78
+ * store.remove(Snapshots.Cat);
79
+ *
80
+ * // Or wipe the whole backing store (scope is the adapter's call).
81
+ * store.clear();
82
+ * ```
83
+ */
84
+ export declare function store(adapter: Adapter): Store;
85
+ /** Shorthand alias for {@link sleep}. */
86
+ export declare const ζ: typeof sleep;
87
+ /** Shorthand alias for {@link poll}. */
88
+ export declare const π: typeof poll;
41
89
  /** Shorthand alias for {@link pk}. */
42
90
  export declare const κ: typeof pk;
91
+ /** Shorthand alias for {@link store}. */
92
+ export declare const σ: typeof store;
@@ -0,0 +1,101 @@
1
+ import { unset } from './utils.ts';
2
+ /** Nominal type of the {@link unset} sentinel. */
3
+ export type Unset = typeof unset;
4
+ /**
5
+ * On-disk JSON shape of a {@link Stored} envelope. The Store wrapper
6
+ * encodes a populated Stored as `{ data, at: at.toString() }` so the
7
+ * `Temporal.Instant` survives the string round-trip, and decodes via
8
+ * `Temporal.Instant.from(...)` on read. Adapters never see this shape
9
+ * directly — they shuttle the already-stringified JSON.
10
+ *
11
+ * @template T The payload type carried by the matching {@link Stored}.
12
+ */
13
+ export type Encoded<T> = {
14
+ readonly data: T;
15
+ readonly at: string;
16
+ };
17
+ /**
18
+ * Common shape for a possibly-present value with a timestamp. Produced by
19
+ * `BoundResourceHandle.snapshot()` (from the in-memory cache) and by
20
+ * `Store.get(key)` (from persistent storage). Both feed into the bound
21
+ * handle's overloaded `.else(...)`, which seeds the cache when given a
22
+ * Stored that carries data and a timestamp.
23
+ *
24
+ * @template T The payload type when present.
25
+ */
26
+ export type Stored<T> = {
27
+ /** The payload, or {@link unset} when nothing is recorded. */
28
+ readonly data: T | Unset;
29
+ /** When the payload was recorded, or `null` when nothing is recorded. */
30
+ readonly at: Temporal.Instant | null;
31
+ /**
32
+ * Returns {@link data} when present, otherwise the supplied fallback.
33
+ * Symmetric with `BoundResourceHandle.else(...)`'s terminal form.
34
+ */
35
+ readonly else: <U>(fallback: U) => T | U;
36
+ };
37
+ /**
38
+ * Adapter contract for synchronous key/value storage. Implement once per
39
+ * backend (localStorage, MMKV on React Native, chrome.storage with a sync
40
+ * facade, etc.) and pass to `store`. The adapter shuttles raw strings;
41
+ * JSON encoding and `Temporal.Instant` round-tripping happen inside the
42
+ * Store wrapper, so adapters stay trivial.
43
+ */
44
+ export type Adapter = {
45
+ /**
46
+ * Return the raw string stored under `key`, or `null` when no entry
47
+ * exists. The Store wrapper handles JSON parsing and `Temporal.Instant`
48
+ * round-tripping, so this stays a plain string getter. Treat any
49
+ * read-time error (decryption, IPC, etc.) as "not found" and return
50
+ * `null` — the Store falls through to its next fallback rather than
51
+ * crashing the render.
52
+ */
53
+ readonly get: (key: string) => string | null;
54
+ /**
55
+ * Persist the raw string `value` under `key`. The Store guarantees
56
+ * `value` is a JSON-encoded `{ data, at }` envelope produced by a
57
+ * resolved snapshot — never a placeholder. Throwing is fine on quota,
58
+ * private mode, sandboxed iframes, etc.; the Store catches and
59
+ * swallows so a write failure can't poison an already-resolved fetch.
60
+ */
61
+ readonly set: (key: string, value: string) => void;
62
+ /**
63
+ * Drop the entry at `key`. Idempotent — calling `remove` for a key
64
+ * that isn't present must not throw.
65
+ */
66
+ readonly remove: (key: string) => void;
67
+ /**
68
+ * Wipe every entry this adapter can see. On a shared backend such as
69
+ * `localStorage` this means the whole origin — third-party SDK state,
70
+ * dismissed banners, route hints, etc. all go with it. Adapter authors
71
+ * should either delegate to the backend's native clear (accepting that
72
+ * scope) or namespace by key prefix and remove only their own.
73
+ */
74
+ readonly clear: () => void;
75
+ };
76
+ /**
77
+ * Bound storage instance returned by `store`. Reads return a
78
+ * {@link Stored} handle so the result composes with the Resource bound
79
+ * handle's `.else(...)`; writes accept a Stored and short-circuit on the
80
+ * empty case to avoid persisting placeholder snapshots.
81
+ */
82
+ export type Store = Pick<Adapter, "remove" | "clear"> & {
83
+ /**
84
+ * Read the entry at `key` as a {@link Stored} envelope. Returns an
85
+ * empty Stored (`data: unset`, `at: null`) when nothing is recorded
86
+ * or when the persisted payload fails to parse — corrupted entries
87
+ * never reach the caller. The result composes directly with a
88
+ * Resource bound handle's `.else(...)` for seeding the cache after
89
+ * a reload.
90
+ */
91
+ readonly get: <T>(key: string) => Stored<T>;
92
+ /**
93
+ * Persist `value` under `key`. Returns `true` when the entry landed
94
+ * in the adapter, `false` otherwise. A `false` covers two distinct
95
+ * cases: the Stored had no payload yet (`data === unset` or
96
+ * `at === null`), or the adapter threw (quota, private mode, etc.).
97
+ * Callers that care about quota failures should branch on the
98
+ * return; callers writing on every dispatch can safely ignore it.
99
+ */
100
+ readonly set: <T>(key: string, value: Stored<T>) => boolean;
101
+ };
@@ -1,5 +1,36 @@
1
+ import { Stored } from './types.ts';
1
2
  /**
2
- * Returns a function to force a component re-render.
3
- * Useful when state is managed externally (e.g., refs) but the UI needs updating.
3
+ * Sentinel symbol marking "no value present yet". Shared by the Resource
4
+ * cache and by storage handles so callers can distinguish "nothing has been
5
+ * recorded" from "a legitimately stored null".
6
+ */
7
+ export declare const unset: unique symbol;
8
+ /**
9
+ * Returns a function to force a component re-render. Useful when state is
10
+ * managed externally (e.g., refs) but the UI needs updating.
11
+ *
12
+ * @returns A zero-arg callback that schedules a re-render of the host
13
+ * component when invoked.
4
14
  */
5
15
  export declare function useRerender(): () => void;
16
+ /**
17
+ * Constructs a {@link Stored} in the empty state. Internal helper shared
18
+ * by the storage layer and the Resource snapshot accessor.
19
+ *
20
+ * @template T The payload type the resulting Stored would carry if populated.
21
+ * @returns A Stored with `data` set to {@link unset} and `at` set to `null`.
22
+ * Its `.else(fallback)` returns the fallback unchanged.
23
+ * @internal
24
+ */
25
+ export declare function empty<T>(): Stored<T>;
26
+ /**
27
+ * Constructs a {@link Stored} wrapping a present payload and timestamp.
28
+ *
29
+ * @template T The payload type carried by the Stored.
30
+ * @param data The payload value to wrap.
31
+ * @param at The instant the payload was recorded — flows through to the
32
+ * Resource cache as the entry's `at` timestamp.
33
+ * @returns A Stored whose `.else(fallback)` returns `data` unchanged.
34
+ * @internal
35
+ */
36
+ export declare function present<T>(data: T, at: Temporal.Instant): Stored<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "march-hare",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "packageManager": "yarn@1.22.22",
@@ -30,7 +30,7 @@
30
30
  ],
31
31
  "scripts": {
32
32
  "build": "vite build",
33
- "build:example": "vite build --mode example --outDir dist-example --base /march-hare/",
33
+ "build:example": "vite build --mode example --outDir dist-example --base /MarchHare/ && mv dist-example/src/example/index.html dist-example/index.html && rm -rf dist-example/src",
34
34
  "dev": "vite",
35
35
  "preview": "vite preview",
36
36
  "release": "make checks",